@my-packages-changeit/ergo-scanner 1.1.3

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/CHANGELOG.md ADDED
@@ -0,0 +1,126 @@
1
+ # @rosen-bridge/ergo-scanner
2
+
3
+ ## 1.1.3
4
+
5
+ ### Patch Changes
6
+
7
+ - Update dependencies
8
+ - @rosen-bridge/abstract-scanner@2.0.3
9
+
10
+ ## 1.1.2
11
+
12
+ ### Patch Changes
13
+
14
+ - Update dependencies
15
+ - @rosen-bridge/abstract-scanner@2.0.2
16
+ - @rosen-clients/ergo-explorer@2.1.3
17
+ - @rosen-clients/ergo-node@3.1.3
18
+
19
+ ## 1.1.1
20
+
21
+ ### Patch Changes
22
+
23
+ - Update dependencies
24
+ - @rosen-bridge/abstract-scanner@2.0.1
25
+
26
+ ## 1.1.0
27
+
28
+ ### Minor Changes
29
+
30
+ - Add heightGap config into scanners config
31
+
32
+ ### Patch Changes
33
+
34
+ - Update dependencies
35
+ - @rosen-bridge/abstract-scanner@2.0.0
36
+ - @rosen-bridge/scanner-interfaces@1.0.0
37
+
38
+ ## 1.0.4
39
+
40
+ ### Patch Changes
41
+
42
+ - Update dependencies
43
+ - @rosen-bridge/abstract-scanner@1.0.4
44
+
45
+ ## 1.0.3
46
+
47
+ ### Patch Changes
48
+
49
+ - Update dependencies
50
+ - @rosen-bridge/abstract-scanner@1.0.3
51
+ - @rosen-clients/ergo-explorer@2.1.2
52
+ - @rosen-clients/ergo-node@3.1.2
53
+
54
+ ## 1.0.2
55
+
56
+ ### Patch Changes
57
+
58
+ - @rosen-bridge/abstract-scanner@1.0.2
59
+
60
+ ## 1.0.1
61
+
62
+ ### Patch Changes
63
+
64
+ - Add `spendingProof` to input box interface
65
+ - Update dependencies
66
+ - @rosen-bridge/scanner-interfaces@0.2.2
67
+ - @rosen-bridge/abstract-scanner@1.0.1
68
+
69
+ ## 1.0.0
70
+
71
+ ### Major Changes
72
+
73
+ - Update AbstractExtractor interface; use `BlockInfo` in `processTransactions` and rename `initializeBoxes` to `initializeData`
74
+
75
+ ### Patch Changes
76
+
77
+ - Update dependencies
78
+ - @rosen-bridge/abstract-logger@4.0.0
79
+ - @rosen-bridge/abstract-scanner@1.0.0
80
+
81
+ ## 0.1.4
82
+
83
+ ### Patch Changes
84
+
85
+ - Update dependencies
86
+ - @rosen-bridge/abstract-scanner@0.2.3
87
+
88
+ ## 0.1.3
89
+
90
+ ### Patch Changes
91
+
92
+ - Update dependencies
93
+ - @rosen-bridge/abstract-scanner@0.2.2
94
+
95
+ ## 0.1.2
96
+
97
+ ### Patch Changes
98
+
99
+ - Fix package-lock and move typescript and types/node into root
100
+ - Update eslint and plugins:
101
+ - Apply new rules such as sort imports and file name
102
+ - Update dependencies
103
+ - @rosen-bridge/extended-typeorm@1.0.1
104
+ - @rosen-clients/rate-limited-axios@1.1.0
105
+ - @rosen-bridge/rosen-extractor@10.1.1
106
+ - @rosen-bridge/tokens@4.0.1
107
+ - @rosen-bridge/abstract-logger@3.0.1
108
+ - @rosen-bridge/json-bigint@1.1.0
109
+ - @rosen-clients/ergo-explorer@2.1.0
110
+ - @rosen-clients/ergo-node@3.1.0
111
+ - @rosen-bridge/scanner-interfaces@0.2.1
112
+ - @rosen-bridge/abstract-scanner@0.2.1
113
+
114
+ ## 0.1.1
115
+
116
+ ### Patch Changes
117
+
118
+ - Update dependencies
119
+ - @rosen-bridge/abstract-scanner@0.2.0
120
+ - @rosen-clients/ergo-node@3.0.0
121
+ - @rosen-clients/ergo-explorer@2.0.0
122
+
123
+ ## 0.1.0
124
+
125
+ - This package was **extracted** from `@rosen-bridge/scanner`.
126
+ You can follow the previous history in the old package’s changelog. The last changelog update is available [here](https://github.com/rosen-bridge/scanner/blob/d4a5539b01c523b101104470b03ff7023a10b70b/packages/scanner/CHANGELOG.md).
package/README.md ADDED
@@ -0,0 +1,38 @@
1
+ # @rosen-bridge/ergo-scanner
2
+
3
+ ## Table of contents
4
+
5
+ - [Introduction](#introduction)
6
+ - [Installation](#installation)
7
+
8
+ ## Introduction
9
+
10
+ An ergo blockchain scanner based on Node or Explorer API.
11
+
12
+ ## Installation
13
+
14
+ npm:
15
+
16
+ ```sh
17
+ npm i @rosen-bridge/ergo-scanner
18
+ ```
19
+
20
+ yarn:
21
+
22
+ ```sh
23
+ yarn add @rosen-bridge/ergo-scanner
24
+ ```
25
+
26
+ ### Usage
27
+
28
+ Ergo Scanner:
29
+
30
+ ```javascript
31
+ const ergoScannerConfig = {
32
+ nodeUrl: <node_url>,
33
+ timeout: <node_timeout>,
34
+ initialHeight: <ergo_initial_height>,
35
+ dataSource: dataSource,
36
+ }
37
+ scanner = new ErgoScanner(ergoScannerConfig);
38
+ ```
@@ -0,0 +1,7 @@
1
+ import { GeneralScanner, ScannerConfig } from '@rosen-bridge/abstract-scanner';
2
+ import { Transaction } from '@rosen-bridge/scanner-interfaces';
3
+ declare class ErgoScanner extends GeneralScanner<Transaction> {
4
+ constructor(config: ScannerConfig<Transaction>);
5
+ }
6
+ export { ErgoScanner };
7
+ //# sourceMappingURL=ergoScanner.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ergoScanner.d.ts","sourceRoot":"","sources":["../lib/ergoScanner.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,gCAAgC,CAAC;AAC/E,OAAO,EAAE,WAAW,EAAE,MAAM,kCAAkC,CAAC;AAE/D,cAAM,WAAY,SAAQ,cAAc,CAAC,WAAW,CAAC;gBACvC,MAAM,EAAE,aAAa,CAAC,WAAW,CAAC;CAY/C;AACD,OAAO,EAAE,WAAW,EAAE,CAAC"}
@@ -0,0 +1,8 @@
1
+ import { GeneralScanner } from '@rosen-bridge/abstract-scanner';
2
+ class ErgoScanner extends GeneralScanner {
3
+ constructor(config) {
4
+ super('ergo', config.dataSource, config.initialHeight, config.network, config.blockRetrieveGap, config.logger, config.suffix, config.heightGap);
5
+ }
6
+ }
7
+ export { ErgoScanner };
8
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZXJnb1NjYW5uZXIuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9saWIvZXJnb1NjYW5uZXIudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLGNBQWMsRUFBaUIsTUFBTSxnQ0FBZ0MsQ0FBQztBQUcvRSxNQUFNLFdBQVksU0FBUSxjQUEyQjtJQUNuRCxZQUFZLE1BQWtDO1FBQzVDLEtBQUssQ0FDSCxNQUFNLEVBQ04sTUFBTSxDQUFDLFVBQVUsRUFDakIsTUFBTSxDQUFDLGFBQWEsRUFDcEIsTUFBTSxDQUFDLE9BQU8sRUFDZCxNQUFNLENBQUMsZ0JBQWdCLEVBQ3ZCLE1BQU0sQ0FBQyxNQUFNLEVBQ2IsTUFBTSxDQUFDLE1BQU0sRUFDYixNQUFNLENBQUMsU0FBUyxDQUNqQixDQUFDO0lBQ0osQ0FBQztDQUNGO0FBQ0QsT0FBTyxFQUFFLFdBQVcsRUFBRSxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgR2VuZXJhbFNjYW5uZXIsIFNjYW5uZXJDb25maWcgfSBmcm9tICdAcm9zZW4tYnJpZGdlL2Fic3RyYWN0LXNjYW5uZXInO1xuaW1wb3J0IHsgVHJhbnNhY3Rpb24gfSBmcm9tICdAcm9zZW4tYnJpZGdlL3NjYW5uZXItaW50ZXJmYWNlcyc7XG5cbmNsYXNzIEVyZ29TY2FubmVyIGV4dGVuZHMgR2VuZXJhbFNjYW5uZXI8VHJhbnNhY3Rpb24+IHtcbiAgY29uc3RydWN0b3IoY29uZmlnOiBTY2FubmVyQ29uZmlnPFRyYW5zYWN0aW9uPikge1xuICAgIHN1cGVyKFxuICAgICAgJ2VyZ28nLFxuICAgICAgY29uZmlnLmRhdGFTb3VyY2UsXG4gICAgICBjb25maWcuaW5pdGlhbEhlaWdodCxcbiAgICAgIGNvbmZpZy5uZXR3b3JrLFxuICAgICAgY29uZmlnLmJsb2NrUmV0cmlldmVHYXAsXG4gICAgICBjb25maWcubG9nZ2VyLFxuICAgICAgY29uZmlnLnN1ZmZpeCxcbiAgICAgIGNvbmZpZy5oZWlnaHRHYXAsXG4gICAgKTtcbiAgfVxufVxuZXhwb3J0IHsgRXJnb1NjYW5uZXIgfTtcbiJdfQ==
@@ -0,0 +1,4 @@
1
+ export * from './ergoScanner';
2
+ export * from './network/ergoNodeNetwork';
3
+ export * from './network/ergoExplorerNetwork';
4
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../lib/index.ts"],"names":[],"mappings":"AAAA,cAAc,eAAe,CAAC;AAC9B,cAAc,2BAA2B,CAAC;AAC1C,cAAc,+BAA+B,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,4 @@
1
+ export * from './ergoScanner';
2
+ export * from './network/ergoNodeNetwork';
3
+ export * from './network/ergoExplorerNetwork';
4
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9saWIvaW5kZXgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsY0FBYyxlQUFlLENBQUM7QUFDOUIsY0FBYywyQkFBMkIsQ0FBQztBQUMxQyxjQUFjLCtCQUErQixDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiZXhwb3J0ICogZnJvbSAnLi9lcmdvU2Nhbm5lcic7XG5leHBvcnQgKiBmcm9tICcuL25ldHdvcmsvZXJnb05vZGVOZXR3b3JrJztcbmV4cG9ydCAqIGZyb20gJy4vbmV0d29yay9lcmdvRXhwbG9yZXJOZXR3b3JrJztcbiJdfQ==
@@ -0,0 +1,25 @@
1
+ import { AbstractNetworkConnector, Block, Transaction } from '@rosen-bridge/scanner-interfaces';
2
+ export declare class ErgoExplorerNetwork extends AbstractNetworkConnector<Transaction> {
3
+ private client;
4
+ constructor(explorerUrl: string);
5
+ /**
6
+ * get block at height.
7
+ * @param height
8
+ */
9
+ getBlockAtHeight: (height: number) => Promise<Block>;
10
+ /**
11
+ * convert Explorer transaction to scanner transaction type
12
+ * @param tx
13
+ */
14
+ private convertToTransaction;
15
+ /**
16
+ * get list of all block transactions
17
+ * @param blockHash
18
+ */
19
+ getBlockTxs: (blockHash: string) => Promise<Array<Transaction>>;
20
+ /**
21
+ * get current height of blockchain
22
+ */
23
+ getCurrentHeight: () => Promise<number>;
24
+ }
25
+ //# sourceMappingURL=ergoExplorerNetwork.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ergoExplorerNetwork.d.ts","sourceRoot":"","sources":["../../lib/network/ergoExplorerNetwork.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,wBAAwB,EACxB,KAAK,EACL,WAAW,EACZ,MAAM,kCAAkC,CAAC;AAG1C,qBAAa,mBAAoB,SAAQ,wBAAwB,CAAC,WAAW,CAAC;IAC5E,OAAO,CAAC,MAAM,CAA+C;gBAEjD,WAAW,EAAE,MAAM;IAK/B;;;OAGG;IACH,gBAAgB,GAAU,QAAQ,MAAM,KAAG,OAAO,CAAC,KAAK,CAAC,CASvD;IAEF;;;OAGG;IACH,OAAO,CAAC,oBAAoB,CAyB1B;IAEF;;;OAGG;IACH,WAAW,GAAU,WAAW,MAAM,KAAG,OAAO,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC,CAIlE;IAEF;;OAEG;IACH,gBAAgB,QAAa,OAAO,CAAC,MAAM,CAAC,CAG1C;CACH"}
@@ -0,0 +1,67 @@
1
+ import { AbstractNetworkConnector, } from '@rosen-bridge/scanner-interfaces';
2
+ import ergoExplorerClientFactory from '@rosen-clients/ergo-explorer';
3
+ export class ErgoExplorerNetwork extends AbstractNetworkConnector {
4
+ client;
5
+ constructor(explorerUrl) {
6
+ super();
7
+ this.client = ergoExplorerClientFactory(explorerUrl);
8
+ }
9
+ /**
10
+ * get block at height.
11
+ * @param height
12
+ */
13
+ getBlockAtHeight = async (height) => {
14
+ const blockIds = await this.client.v0.getApiV0BlocksAtP1(height);
15
+ const blockSummary = await this.client.v1.getApiV1BlocksP1(blockIds[0]);
16
+ return {
17
+ parentHash: blockSummary.block.header.parentId,
18
+ height: blockSummary.block.header.height,
19
+ timestamp: Number(blockSummary.block.header.timestamp / 1000n),
20
+ hash: blockSummary.block.header.id,
21
+ };
22
+ };
23
+ /**
24
+ * convert Explorer transaction to scanner transaction type
25
+ * @param tx
26
+ */
27
+ convertToTransaction = (tx) => {
28
+ return {
29
+ id: tx.id,
30
+ dataInputs: tx.dataInputs?.map((dataInput) => ({
31
+ boxId: dataInput.id,
32
+ })) ?? [],
33
+ // TODO: Add input extension to explorer local/ergo/rosen-bridge/scanner/-/issues/156
34
+ inputs: tx.inputs?.map((input) => ({
35
+ boxId: input.id,
36
+ spendingProof: input.spendingProof,
37
+ })) ?? [],
38
+ outputs: tx.outputs?.map((output) => ({
39
+ boxId: output.id,
40
+ transactionId: output.txId,
41
+ additionalRegisters: output.additionalRegisters,
42
+ assets: output.assets || [],
43
+ ergoTree: output.ergoTree,
44
+ creationHeight: output.creationHeight,
45
+ index: output.index,
46
+ value: output.value,
47
+ })) ?? [],
48
+ };
49
+ };
50
+ /**
51
+ * get list of all block transactions
52
+ * @param blockHash
53
+ */
54
+ getBlockTxs = async (blockHash) => {
55
+ const block = await this.client.v1.getApiV1BlocksP1(blockHash);
56
+ const transactions = block.block.blockTransactions || [];
57
+ return transactions.map(this.convertToTransaction);
58
+ };
59
+ /**
60
+ * get current height of blockchain
61
+ */
62
+ getCurrentHeight = async () => {
63
+ const networkState = await this.client.v1.getApiV1Networkstate();
64
+ return Number(networkState.height);
65
+ };
66
+ }
67
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZXJnb0V4cGxvcmVyTmV0d29yay5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL2xpYi9uZXR3b3JrL2VyZ29FeHBsb3Jlck5ldHdvcmsudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUNMLHdCQUF3QixHQUd6QixNQUFNLGtDQUFrQyxDQUFDO0FBQzFDLE9BQU8seUJBQWlDLE1BQU0sOEJBQThCLENBQUM7QUFFN0UsTUFBTSxPQUFPLG1CQUFvQixTQUFRLHdCQUFxQztJQUNwRSxNQUFNLENBQStDO0lBRTdELFlBQVksV0FBbUI7UUFDN0IsS0FBSyxFQUFFLENBQUM7UUFDUixJQUFJLENBQUMsTUFBTSxHQUFHLHlCQUF5QixDQUFDLFdBQVcsQ0FBQyxDQUFDO0lBQ3ZELENBQUM7SUFFRDs7O09BR0c7SUFDSCxnQkFBZ0IsR0FBRyxLQUFLLEVBQUUsTUFBYyxFQUFrQixFQUFFO1FBQzFELE1BQU0sUUFBUSxHQUFHLE1BQU0sSUFBSSxDQUFDLE1BQU0sQ0FBQyxFQUFFLENBQUMsa0JBQWtCLENBQUMsTUFBTSxDQUFDLENBQUM7UUFDakUsTUFBTSxZQUFZLEdBQUcsTUFBTSxJQUFJLENBQUMsTUFBTSxDQUFDLEVBQUUsQ0FBQyxnQkFBZ0IsQ0FBQyxRQUFRLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQztRQUN4RSxPQUFPO1lBQ0wsVUFBVSxFQUFFLFlBQVksQ0FBQyxLQUFLLENBQUMsTUFBTSxDQUFDLFFBQVE7WUFDOUMsTUFBTSxFQUFFLFlBQVksQ0FBQyxLQUFLLENBQUMsTUFBTSxDQUFDLE1BQU07WUFDeEMsU0FBUyxFQUFFLE1BQU0sQ0FBQyxZQUFZLENBQUMsS0FBSyxDQUFDLE1BQU0sQ0FBQyxTQUFTLEdBQUcsS0FBSyxDQUFDO1lBQzlELElBQUksRUFBRSxZQUFZLENBQUMsS0FBSyxDQUFDLE1BQU0sQ0FBQyxFQUFFO1NBQ25DLENBQUM7SUFDSixDQUFDLENBQUM7SUFFRjs7O09BR0c7SUFDSyxvQkFBb0IsR0FBRyxDQUFDLEVBQXVCLEVBQWUsRUFBRTtRQUN0RSxPQUFPO1lBQ0wsRUFBRSxFQUFFLEVBQUUsQ0FBQyxFQUFFO1lBQ1QsVUFBVSxFQUNSLEVBQUUsQ0FBQyxVQUFVLEVBQUUsR0FBRyxDQUFDLENBQUMsU0FBUyxFQUFFLEVBQUUsQ0FBQyxDQUFDO2dCQUNqQyxLQUFLLEVBQUUsU0FBUyxDQUFDLEVBQUU7YUFDcEIsQ0FBQyxDQUFDLElBQUksRUFBRTtZQUNYLHFGQUFxRjtZQUNyRixNQUFNLEVBQ0osRUFBRSxDQUFDLE1BQU0sRUFBRSxHQUFHLENBQUMsQ0FBQyxLQUFLLEVBQUUsRUFBRSxDQUFDLENBQUM7Z0JBQ3pCLEtBQUssRUFBRSxLQUFLLENBQUMsRUFBRTtnQkFDZixhQUFhLEVBQUUsS0FBSyxDQUFDLGFBQWE7YUFDbkMsQ0FBQyxDQUFDLElBQUksRUFBRTtZQUNYLE9BQU8sRUFDTCxFQUFFLENBQUMsT0FBTyxFQUFFLEdBQUcsQ0FBQyxDQUFDLE1BQU0sRUFBRSxFQUFFLENBQUMsQ0FBQztnQkFDM0IsS0FBSyxFQUFFLE1BQU0sQ0FBQyxFQUFFO2dCQUNoQixhQUFhLEVBQUUsTUFBTSxDQUFDLElBQUk7Z0JBQzFCLG1CQUFtQixFQUFFLE1BQU0sQ0FBQyxtQkFBbUI7Z0JBQy9DLE1BQU0sRUFBRSxNQUFNLENBQUMsTUFBTSxJQUFJLEVBQUU7Z0JBQzNCLFFBQVEsRUFBRSxNQUFNLENBQUMsUUFBUTtnQkFDekIsY0FBYyxFQUFFLE1BQU0sQ0FBQyxjQUFjO2dCQUNyQyxLQUFLLEVBQUUsTUFBTSxDQUFDLEtBQUs7Z0JBQ25CLEtBQUssRUFBRSxNQUFNLENBQUMsS0FBSzthQUNwQixDQUFDLENBQUMsSUFBSSxFQUFFO1NBQ1osQ0FBQztJQUNKLENBQUMsQ0FBQztJQUVGOzs7T0FHRztJQUNILFdBQVcsR0FBRyxLQUFLLEVBQUUsU0FBaUIsRUFBK0IsRUFBRTtRQUNyRSxNQUFNLEtBQUssR0FBRyxNQUFNLElBQUksQ0FBQyxNQUFNLENBQUMsRUFBRSxDQUFDLGdCQUFnQixDQUFDLFNBQVMsQ0FBQyxDQUFDO1FBQy9ELE1BQU0sWUFBWSxHQUFHLEtBQUssQ0FBQyxLQUFLLENBQUMsaUJBQWlCLElBQUksRUFBRSxDQUFDO1FBQ3pELE9BQU8sWUFBWSxDQUFDLEdBQUcsQ0FBQyxJQUFJLENBQUMsb0JBQW9CLENBQUMsQ0FBQztJQUNyRCxDQUFDLENBQUM7SUFFRjs7T0FFRztJQUNILGdCQUFnQixHQUFHLEtBQUssSUFBcUIsRUFBRTtRQUM3QyxNQUFNLFlBQVksR0FBRyxNQUFNLElBQUksQ0FBQyxNQUFNLENBQUMsRUFBRSxDQUFDLG9CQUFvQixFQUFFLENBQUM7UUFDakUsT0FBTyxNQUFNLENBQUMsWUFBWSxDQUFDLE1BQU0sQ0FBQyxDQUFDO0lBQ3JDLENBQUMsQ0FBQztDQUNIIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHtcbiAgQWJzdHJhY3ROZXR3b3JrQ29ubmVjdG9yLFxuICBCbG9jayxcbiAgVHJhbnNhY3Rpb24sXG59IGZyb20gJ0Byb3Nlbi1icmlkZ2Uvc2Nhbm5lci1pbnRlcmZhY2VzJztcbmltcG9ydCBlcmdvRXhwbG9yZXJDbGllbnRGYWN0b3J5LCB7IFYxIH0gZnJvbSAnQHJvc2VuLWNsaWVudHMvZXJnby1leHBsb3Jlcic7XG5cbmV4cG9ydCBjbGFzcyBFcmdvRXhwbG9yZXJOZXR3b3JrIGV4dGVuZHMgQWJzdHJhY3ROZXR3b3JrQ29ubmVjdG9yPFRyYW5zYWN0aW9uPiB7XG4gIHByaXZhdGUgY2xpZW50OiBSZXR1cm5UeXBlPHR5cGVvZiBlcmdvRXhwbG9yZXJDbGllbnRGYWN0b3J5PjtcblxuICBjb25zdHJ1Y3RvcihleHBsb3JlclVybDogc3RyaW5nKSB7XG4gICAgc3VwZXIoKTtcbiAgICB0aGlzLmNsaWVudCA9IGVyZ29FeHBsb3JlckNsaWVudEZhY3RvcnkoZXhwbG9yZXJVcmwpO1xuICB9XG5cbiAgLyoqXG4gICAqIGdldCBibG9jayBhdCBoZWlnaHQuXG4gICAqIEBwYXJhbSBoZWlnaHRcbiAgICovXG4gIGdldEJsb2NrQXRIZWlnaHQgPSBhc3luYyAoaGVpZ2h0OiBudW1iZXIpOiBQcm9taXNlPEJsb2NrPiA9PiB7XG4gICAgY29uc3QgYmxvY2tJZHMgPSBhd2FpdCB0aGlzLmNsaWVudC52MC5nZXRBcGlWMEJsb2Nrc0F0UDEoaGVpZ2h0KTtcbiAgICBjb25zdCBibG9ja1N1bW1hcnkgPSBhd2FpdCB0aGlzLmNsaWVudC52MS5nZXRBcGlWMUJsb2Nrc1AxKGJsb2NrSWRzWzBdKTtcbiAgICByZXR1cm4ge1xuICAgICAgcGFyZW50SGFzaDogYmxvY2tTdW1tYXJ5LmJsb2NrLmhlYWRlci5wYXJlbnRJZCxcbiAgICAgIGhlaWdodDogYmxvY2tTdW1tYXJ5LmJsb2NrLmhlYWRlci5oZWlnaHQsXG4gICAgICB0aW1lc3RhbXA6IE51bWJlcihibG9ja1N1bW1hcnkuYmxvY2suaGVhZGVyLnRpbWVzdGFtcCAvIDEwMDBuKSxcbiAgICAgIGhhc2g6IGJsb2NrU3VtbWFyeS5ibG9jay5oZWFkZXIuaWQsXG4gICAgfTtcbiAgfTtcblxuICAvKipcbiAgICogY29udmVydCBFeHBsb3JlciB0cmFuc2FjdGlvbiB0byBzY2FubmVyIHRyYW5zYWN0aW9uIHR5cGVcbiAgICogQHBhcmFtIHR4XG4gICAqL1xuICBwcml2YXRlIGNvbnZlcnRUb1RyYW5zYWN0aW9uID0gKHR4OiBWMS5UcmFuc2FjdGlvbkluZm8xKTogVHJhbnNhY3Rpb24gPT4ge1xuICAgIHJldHVybiB7XG4gICAgICBpZDogdHguaWQsXG4gICAgICBkYXRhSW5wdXRzOlxuICAgICAgICB0eC5kYXRhSW5wdXRzPy5tYXAoKGRhdGFJbnB1dCkgPT4gKHtcbiAgICAgICAgICBib3hJZDogZGF0YUlucHV0LmlkLFxuICAgICAgICB9KSkgPz8gW10sXG4gICAgICAvLyBUT0RPOiBBZGQgaW5wdXQgZXh0ZW5zaW9uIHRvIGV4cGxvcmVyIGxvY2FsL2VyZ28vcm9zZW4tYnJpZGdlL3NjYW5uZXIvLS9pc3N1ZXMvMTU2XG4gICAgICBpbnB1dHM6XG4gICAgICAgIHR4LmlucHV0cz8ubWFwKChpbnB1dCkgPT4gKHtcbiAgICAgICAgICBib3hJZDogaW5wdXQuaWQsXG4gICAgICAgICAgc3BlbmRpbmdQcm9vZjogaW5wdXQuc3BlbmRpbmdQcm9vZixcbiAgICAgICAgfSkpID8/IFtdLFxuICAgICAgb3V0cHV0czpcbiAgICAgICAgdHgub3V0cHV0cz8ubWFwKChvdXRwdXQpID0+ICh7XG4gICAgICAgICAgYm94SWQ6IG91dHB1dC5pZCxcbiAgICAgICAgICB0cmFuc2FjdGlvbklkOiBvdXRwdXQudHhJZCxcbiAgICAgICAgICBhZGRpdGlvbmFsUmVnaXN0ZXJzOiBvdXRwdXQuYWRkaXRpb25hbFJlZ2lzdGVycyxcbiAgICAgICAgICBhc3NldHM6IG91dHB1dC5hc3NldHMgfHwgW10sXG4gICAgICAgICAgZXJnb1RyZWU6IG91dHB1dC5lcmdvVHJlZSxcbiAgICAgICAgICBjcmVhdGlvbkhlaWdodDogb3V0cHV0LmNyZWF0aW9uSGVpZ2h0LFxuICAgICAgICAgIGluZGV4OiBvdXRwdXQuaW5kZXgsXG4gICAgICAgICAgdmFsdWU6IG91dHB1dC52YWx1ZSxcbiAgICAgICAgfSkpID8/IFtdLFxuICAgIH07XG4gIH07XG5cbiAgLyoqXG4gICAqIGdldCBsaXN0IG9mIGFsbCBibG9jayB0cmFuc2FjdGlvbnNcbiAgICogQHBhcmFtIGJsb2NrSGFzaFxuICAgKi9cbiAgZ2V0QmxvY2tUeHMgPSBhc3luYyAoYmxvY2tIYXNoOiBzdHJpbmcpOiBQcm9taXNlPEFycmF5PFRyYW5zYWN0aW9uPj4gPT4ge1xuICAgIGNvbnN0IGJsb2NrID0gYXdhaXQgdGhpcy5jbGllbnQudjEuZ2V0QXBpVjFCbG9ja3NQMShibG9ja0hhc2gpO1xuICAgIGNvbnN0IHRyYW5zYWN0aW9ucyA9IGJsb2NrLmJsb2NrLmJsb2NrVHJhbnNhY3Rpb25zIHx8IFtdO1xuICAgIHJldHVybiB0cmFuc2FjdGlvbnMubWFwKHRoaXMuY29udmVydFRvVHJhbnNhY3Rpb24pO1xuICB9O1xuXG4gIC8qKlxuICAgKiBnZXQgY3VycmVudCBoZWlnaHQgb2YgYmxvY2tjaGFpblxuICAgKi9cbiAgZ2V0Q3VycmVudEhlaWdodCA9IGFzeW5jICgpOiBQcm9taXNlPG51bWJlcj4gPT4ge1xuICAgIGNvbnN0IG5ldHdvcmtTdGF0ZSA9IGF3YWl0IHRoaXMuY2xpZW50LnYxLmdldEFwaVYxTmV0d29ya3N0YXRlKCk7XG4gICAgcmV0dXJuIE51bWJlcihuZXR3b3JrU3RhdGUuaGVpZ2h0KTtcbiAgfTtcbn1cbiJdfQ==
@@ -0,0 +1,25 @@
1
+ import { AbstractNetworkConnector, Block, Transaction } from '@rosen-bridge/scanner-interfaces';
2
+ export declare class ErgoNodeNetwork extends AbstractNetworkConnector<Transaction> {
3
+ private client;
4
+ constructor(nodeUrl: string);
5
+ /**
6
+ * get block at height.
7
+ * @param height
8
+ */
9
+ getBlockAtHeight: (height: number) => Promise<Block>;
10
+ /**
11
+ * convert Node transaction to scanner transaction type
12
+ * @param tx
13
+ */
14
+ private convertNodeTransactionToTransaction;
15
+ /**
16
+ * get list of all block transactions
17
+ * @param blockHash
18
+ */
19
+ getBlockTxs: (blockHash: string) => Promise<Array<Transaction>>;
20
+ /**
21
+ * get current height of blockchain
22
+ */
23
+ getCurrentHeight: () => Promise<number>;
24
+ }
25
+ //# sourceMappingURL=ergoNodeNetwork.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ergoNodeNetwork.d.ts","sourceRoot":"","sources":["../../lib/network/ergoNodeNetwork.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,wBAAwB,EACxB,KAAK,EACL,WAAW,EACZ,MAAM,kCAAkC,CAAC;AAK1C,qBAAa,eAAgB,SAAQ,wBAAwB,CAAC,WAAW,CAAC;IACxE,OAAO,CAAC,MAAM,CAA2C;gBAC7C,OAAO,EAAE,MAAM;IAK3B;;;OAGG;IACH,gBAAgB,GAAU,QAAQ,MAAM,KAAG,OAAO,CAAC,KAAK,CAAC,CAYvD;IAEF;;;OAGG;IACH,OAAO,CAAC,mCAAmC,CAsBzC;IAEF;;;OAGG;IACH,WAAW,GAAU,WAAW,MAAM,KAAG,OAAO,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC,CAMlE;IAEF;;OAEG;IACH,gBAAgB,QAAa,OAAO,CAAC,MAAM,CAAC,CAG1C;CACH"}
@@ -0,0 +1,67 @@
1
+ import { AbstractNetworkConnector, } from '@rosen-bridge/scanner-interfaces';
2
+ import ergoNodeClientFactory from '@rosen-clients/ergo-node';
3
+ export class ErgoNodeNetwork extends AbstractNetworkConnector {
4
+ client;
5
+ constructor(nodeUrl) {
6
+ super();
7
+ this.client = ergoNodeClientFactory(nodeUrl);
8
+ }
9
+ /**
10
+ * get block at height.
11
+ * @param height
12
+ */
13
+ getBlockAtHeight = async (height) => {
14
+ const blocks = await this.client.getChainSlice({
15
+ fromHeight: height,
16
+ toHeight: height,
17
+ });
18
+ const block = blocks[0];
19
+ return {
20
+ hash: block.id,
21
+ height: block.height,
22
+ parentHash: block.parentId,
23
+ timestamp: Number(block.timestamp / 1000n),
24
+ };
25
+ };
26
+ /**
27
+ * convert Node transaction to scanner transaction type
28
+ * @param tx
29
+ */
30
+ convertNodeTransactionToTransaction = (tx) => {
31
+ return {
32
+ id: tx.id || '',
33
+ outputs: tx.outputs.map((output) => ({
34
+ transactionId: output.transactionId || '',
35
+ index: output.index || 0,
36
+ value: output.value || 0n,
37
+ ergoTree: output.ergoTree || '',
38
+ creationHeight: output.creationHeight || 0,
39
+ assets: output.assets || [],
40
+ additionalRegisters: output.additionalRegisters,
41
+ boxId: output.boxId || '',
42
+ })),
43
+ inputs: tx.inputs.map((input) => ({
44
+ boxId: input.boxId,
45
+ spendingProof: input.spendingProof.proofBytes,
46
+ extension: input.spendingProof.extension,
47
+ })),
48
+ dataInputs: tx.dataInputs,
49
+ };
50
+ };
51
+ /**
52
+ * get list of all block transactions
53
+ * @param blockHash
54
+ */
55
+ getBlockTxs = async (blockHash) => {
56
+ const blockTransaction = await this.client.getBlockTransactionsById(blockHash);
57
+ return blockTransaction.transactions.map(this.convertNodeTransactionToTransaction);
58
+ };
59
+ /**
60
+ * get current height of blockchain
61
+ */
62
+ getCurrentHeight = async () => {
63
+ const info = await this.client.getNodeInfo();
64
+ return info.fullHeight || 0;
65
+ };
66
+ }
67
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZXJnb05vZGVOZXR3b3JrLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vbGliL25ldHdvcmsvZXJnb05vZGVOZXR3b3JrLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFDTCx3QkFBd0IsR0FHekIsTUFBTSxrQ0FBa0MsQ0FBQztBQUMxQyxPQUFPLHFCQUVOLE1BQU0sMEJBQTBCLENBQUM7QUFFbEMsTUFBTSxPQUFPLGVBQWdCLFNBQVEsd0JBQXFDO0lBQ2hFLE1BQU0sQ0FBMkM7SUFDekQsWUFBWSxPQUFlO1FBQ3pCLEtBQUssRUFBRSxDQUFDO1FBQ1IsSUFBSSxDQUFDLE1BQU0sR0FBRyxxQkFBcUIsQ0FBQyxPQUFPLENBQUMsQ0FBQztJQUMvQyxDQUFDO0lBRUQ7OztPQUdHO0lBQ0gsZ0JBQWdCLEdBQUcsS0FBSyxFQUFFLE1BQWMsRUFBa0IsRUFBRTtRQUMxRCxNQUFNLE1BQU0sR0FBRyxNQUFNLElBQUksQ0FBQyxNQUFNLENBQUMsYUFBYSxDQUFDO1lBQzdDLFVBQVUsRUFBRSxNQUFNO1lBQ2xCLFFBQVEsRUFBRSxNQUFNO1NBQ2pCLENBQUMsQ0FBQztRQUNILE1BQU0sS0FBSyxHQUFHLE1BQU0sQ0FBQyxDQUFDLENBQUMsQ0FBQztRQUN4QixPQUFPO1lBQ0wsSUFBSSxFQUFFLEtBQUssQ0FBQyxFQUFFO1lBQ2QsTUFBTSxFQUFFLEtBQUssQ0FBQyxNQUFNO1lBQ3BCLFVBQVUsRUFBRSxLQUFLLENBQUMsUUFBUTtZQUMxQixTQUFTLEVBQUUsTUFBTSxDQUFDLEtBQUssQ0FBQyxTQUFTLEdBQUcsS0FBSyxDQUFDO1NBQzNDLENBQUM7SUFDSixDQUFDLENBQUM7SUFFRjs7O09BR0c7SUFDSyxtQ0FBbUMsR0FBRyxDQUM1QyxFQUFtQixFQUNOLEVBQUU7UUFDZixPQUFPO1lBQ0wsRUFBRSxFQUFFLEVBQUUsQ0FBQyxFQUFFLElBQUksRUFBRTtZQUNmLE9BQU8sRUFBRSxFQUFFLENBQUMsT0FBTyxDQUFDLEdBQUcsQ0FBQyxDQUFDLE1BQU0sRUFBRSxFQUFFLENBQUMsQ0FBQztnQkFDbkMsYUFBYSxFQUFFLE1BQU0sQ0FBQyxhQUFhLElBQUksRUFBRTtnQkFDekMsS0FBSyxFQUFFLE1BQU0sQ0FBQyxLQUFLLElBQUksQ0FBQztnQkFDeEIsS0FBSyxFQUFFLE1BQU0sQ0FBQyxLQUFLLElBQUksRUFBRTtnQkFDekIsUUFBUSxFQUFFLE1BQU0sQ0FBQyxRQUFRLElBQUksRUFBRTtnQkFDL0IsY0FBYyxFQUFFLE1BQU0sQ0FBQyxjQUFjLElBQUksQ0FBQztnQkFDMUMsTUFBTSxFQUFFLE1BQU0sQ0FBQyxNQUFNLElBQUksRUFBRTtnQkFDM0IsbUJBQW1CLEVBQUUsTUFBTSxDQUFDLG1CQUFtQjtnQkFDL0MsS0FBSyxFQUFFLE1BQU0sQ0FBQyxLQUFLLElBQUksRUFBRTthQUMxQixDQUFDLENBQUM7WUFDSCxNQUFNLEVBQUUsRUFBRSxDQUFDLE1BQU0sQ0FBQyxHQUFHLENBQUMsQ0FBQyxLQUFLLEVBQUUsRUFBRSxDQUFDLENBQUM7Z0JBQ2hDLEtBQUssRUFBRSxLQUFLLENBQUMsS0FBSztnQkFDbEIsYUFBYSxFQUFFLEtBQUssQ0FBQyxhQUFhLENBQUMsVUFBVTtnQkFDN0MsU0FBUyxFQUFFLEtBQUssQ0FBQyxhQUFhLENBQUMsU0FBUzthQUN6QyxDQUFDLENBQUM7WUFDSCxVQUFVLEVBQUUsRUFBRSxDQUFDLFVBQVU7U0FDMUIsQ0FBQztJQUNKLENBQUMsQ0FBQztJQUVGOzs7T0FHRztJQUNILFdBQVcsR0FBRyxLQUFLLEVBQUUsU0FBaUIsRUFBK0IsRUFBRTtRQUNyRSxNQUFNLGdCQUFnQixHQUNwQixNQUFNLElBQUksQ0FBQyxNQUFNLENBQUMsd0JBQXdCLENBQUMsU0FBUyxDQUFDLENBQUM7UUFDeEQsT0FBTyxnQkFBZ0IsQ0FBQyxZQUFZLENBQUMsR0FBRyxDQUN0QyxJQUFJLENBQUMsbUNBQW1DLENBQ3pDLENBQUM7SUFDSixDQUFDLENBQUM7SUFFRjs7T0FFRztJQUNILGdCQUFnQixHQUFHLEtBQUssSUFBcUIsRUFBRTtRQUM3QyxNQUFNLElBQUksR0FBRyxNQUFNLElBQUksQ0FBQyxNQUFNLENBQUMsV0FBVyxFQUFFLENBQUM7UUFDN0MsT0FBTyxJQUFJLENBQUMsVUFBVSxJQUFJLENBQUMsQ0FBQztJQUM5QixDQUFDLENBQUM7Q0FDSCIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7XG4gIEFic3RyYWN0TmV0d29ya0Nvbm5lY3RvcixcbiAgQmxvY2ssXG4gIFRyYW5zYWN0aW9uLFxufSBmcm9tICdAcm9zZW4tYnJpZGdlL3NjYW5uZXItaW50ZXJmYWNlcyc7XG5pbXBvcnQgZXJnb05vZGVDbGllbnRGYWN0b3J5LCB7XG4gIEVyZ29UcmFuc2FjdGlvbixcbn0gZnJvbSAnQHJvc2VuLWNsaWVudHMvZXJnby1ub2RlJztcblxuZXhwb3J0IGNsYXNzIEVyZ29Ob2RlTmV0d29yayBleHRlbmRzIEFic3RyYWN0TmV0d29ya0Nvbm5lY3RvcjxUcmFuc2FjdGlvbj4ge1xuICBwcml2YXRlIGNsaWVudDogUmV0dXJuVHlwZTx0eXBlb2YgZXJnb05vZGVDbGllbnRGYWN0b3J5PjtcbiAgY29uc3RydWN0b3Iobm9kZVVybDogc3RyaW5nKSB7XG4gICAgc3VwZXIoKTtcbiAgICB0aGlzLmNsaWVudCA9IGVyZ29Ob2RlQ2xpZW50RmFjdG9yeShub2RlVXJsKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBnZXQgYmxvY2sgYXQgaGVpZ2h0LlxuICAgKiBAcGFyYW0gaGVpZ2h0XG4gICAqL1xuICBnZXRCbG9ja0F0SGVpZ2h0ID0gYXN5bmMgKGhlaWdodDogbnVtYmVyKTogUHJvbWlzZTxCbG9jaz4gPT4ge1xuICAgIGNvbnN0IGJsb2NrcyA9IGF3YWl0IHRoaXMuY2xpZW50LmdldENoYWluU2xpY2Uoe1xuICAgICAgZnJvbUhlaWdodDogaGVpZ2h0LFxuICAgICAgdG9IZWlnaHQ6IGhlaWdodCxcbiAgICB9KTtcbiAgICBjb25zdCBibG9jayA9IGJsb2Nrc1swXTtcbiAgICByZXR1cm4ge1xuICAgICAgaGFzaDogYmxvY2suaWQsXG4gICAgICBoZWlnaHQ6IGJsb2NrLmhlaWdodCxcbiAgICAgIHBhcmVudEhhc2g6IGJsb2NrLnBhcmVudElkLFxuICAgICAgdGltZXN0YW1wOiBOdW1iZXIoYmxvY2sudGltZXN0YW1wIC8gMTAwMG4pLFxuICAgIH07XG4gIH07XG5cbiAgLyoqXG4gICAqIGNvbnZlcnQgTm9kZSB0cmFuc2FjdGlvbiB0byBzY2FubmVyIHRyYW5zYWN0aW9uIHR5cGVcbiAgICogQHBhcmFtIHR4XG4gICAqL1xuICBwcml2YXRlIGNvbnZlcnROb2RlVHJhbnNhY3Rpb25Ub1RyYW5zYWN0aW9uID0gKFxuICAgIHR4OiBFcmdvVHJhbnNhY3Rpb24sXG4gICk6IFRyYW5zYWN0aW9uID0+IHtcbiAgICByZXR1cm4ge1xuICAgICAgaWQ6IHR4LmlkIHx8ICcnLFxuICAgICAgb3V0cHV0czogdHgub3V0cHV0cy5tYXAoKG91dHB1dCkgPT4gKHtcbiAgICAgICAgdHJhbnNhY3Rpb25JZDogb3V0cHV0LnRyYW5zYWN0aW9uSWQgfHwgJycsXG4gICAgICAgIGluZGV4OiBvdXRwdXQuaW5kZXggfHwgMCxcbiAgICAgICAgdmFsdWU6IG91dHB1dC52YWx1ZSB8fCAwbixcbiAgICAgICAgZXJnb1RyZWU6IG91dHB1dC5lcmdvVHJlZSB8fCAnJyxcbiAgICAgICAgY3JlYXRpb25IZWlnaHQ6IG91dHB1dC5jcmVhdGlvbkhlaWdodCB8fCAwLFxuICAgICAgICBhc3NldHM6IG91dHB1dC5hc3NldHMgfHwgW10sXG4gICAgICAgIGFkZGl0aW9uYWxSZWdpc3RlcnM6IG91dHB1dC5hZGRpdGlvbmFsUmVnaXN0ZXJzLFxuICAgICAgICBib3hJZDogb3V0cHV0LmJveElkIHx8ICcnLFxuICAgICAgfSkpLFxuICAgICAgaW5wdXRzOiB0eC5pbnB1dHMubWFwKChpbnB1dCkgPT4gKHtcbiAgICAgICAgYm94SWQ6IGlucHV0LmJveElkLFxuICAgICAgICBzcGVuZGluZ1Byb29mOiBpbnB1dC5zcGVuZGluZ1Byb29mLnByb29mQnl0ZXMsXG4gICAgICAgIGV4dGVuc2lvbjogaW5wdXQuc3BlbmRpbmdQcm9vZi5leHRlbnNpb24sXG4gICAgICB9KSksXG4gICAgICBkYXRhSW5wdXRzOiB0eC5kYXRhSW5wdXRzLFxuICAgIH07XG4gIH07XG5cbiAgLyoqXG4gICAqIGdldCBsaXN0IG9mIGFsbCBibG9jayB0cmFuc2FjdGlvbnNcbiAgICogQHBhcmFtIGJsb2NrSGFzaFxuICAgKi9cbiAgZ2V0QmxvY2tUeHMgPSBhc3luYyAoYmxvY2tIYXNoOiBzdHJpbmcpOiBQcm9taXNlPEFycmF5PFRyYW5zYWN0aW9uPj4gPT4ge1xuICAgIGNvbnN0IGJsb2NrVHJhbnNhY3Rpb24gPVxuICAgICAgYXdhaXQgdGhpcy5jbGllbnQuZ2V0QmxvY2tUcmFuc2FjdGlvbnNCeUlkKGJsb2NrSGFzaCk7XG4gICAgcmV0dXJuIGJsb2NrVHJhbnNhY3Rpb24udHJhbnNhY3Rpb25zLm1hcChcbiAgICAgIHRoaXMuY29udmVydE5vZGVUcmFuc2FjdGlvblRvVHJhbnNhY3Rpb24sXG4gICAgKTtcbiAgfTtcblxuICAvKipcbiAgICogZ2V0IGN1cnJlbnQgaGVpZ2h0IG9mIGJsb2NrY2hhaW5cbiAgICovXG4gIGdldEN1cnJlbnRIZWlnaHQgPSBhc3luYyAoKTogUHJvbWlzZTxudW1iZXI+ID0+IHtcbiAgICBjb25zdCBpbmZvID0gYXdhaXQgdGhpcy5jbGllbnQuZ2V0Tm9kZUluZm8oKTtcbiAgICByZXR1cm4gaW5mby5mdWxsSGVpZ2h0IHx8IDA7XG4gIH07XG59XG4iXX0=