@rosen-bridge/abstract-extractor 0.1.5 → 0.2.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/CHANGELOG.md +6 -0
- package/dist/ergo/initializable/AbstractInitializable.d.ts +0 -6
- package/dist/ergo/initializable/AbstractInitializable.d.ts.map +1 -1
- package/dist/ergo/initializable/AbstractInitializable.js +3 -1
- package/dist/ergo/initializable/InitializableByAddress.d.ts +0 -7
- package/dist/ergo/initializable/InitializableByAddress.d.ts.map +1 -1
- package/dist/ergo/initializable/InitializableByAddress.js +1 -9
- package/dist/ergo/initializable/InitializableByToken.d.ts +0 -7
- package/dist/ergo/initializable/InitializableByToken.d.ts.map +1 -1
- package/dist/ergo/initializable/InitializableByToken.js +1 -9
- package/dist/ergo/interfaces.d.ts +4 -0
- package/dist/ergo/interfaces.d.ts.map +1 -1
- package/dist/ergo/interfaces.js +1 -1
- package/dist/ergo/network/AbstractNetwork.d.ts +0 -6
- package/dist/ergo/network/AbstractNetwork.d.ts.map +1 -1
- package/dist/ergo/network/AbstractNetwork.js +1 -1
- package/dist/ergo/network/ExplorerNetwork.d.ts +6 -3
- package/dist/ergo/network/ExplorerNetwork.d.ts.map +1 -1
- package/dist/ergo/network/ExplorerNetwork.js +16 -8
- package/dist/ergo/network/NodeNetwork.d.ts +7 -4
- package/dist/ergo/network/NodeNetwork.d.ts.map +1 -1
- package/dist/ergo/network/NodeNetwork.js +21 -14
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/lib/ergo/initializable/AbstractInitializable.ts +2 -7
- package/lib/ergo/initializable/InitializableByAddress.ts +0 -10
- package/lib/ergo/initializable/InitializableByToken.ts +0 -10
- package/lib/ergo/interfaces.ts +4 -0
- package/lib/ergo/network/AbstractNetwork.ts +1 -7
- package/lib/ergo/network/ExplorerNetwork.ts +23 -7
- package/lib/ergo/network/NodeNetwork.ts +25 -13
- package/package.json +2 -2
- package/tests/initializable/AbstractInitializable.spec.ts +3 -0
- package/tests/initializable/testData.ts +1 -0
- package/tests/network/ExplorerNetwork.spec.ts +31 -0
- package/tests/network/NodeNetwork.spec.ts +37 -0
- package/tests/network/testData.ts +1232 -0
- package/tsconfig.build.tsbuildinfo +1 -1
|
@@ -34,13 +34,6 @@ export abstract class AbstractInitializableErgoExtractor<
|
|
|
34
34
|
limit: number
|
|
35
35
|
) => Promise<{ boxes: ErgoBox[]; hasNextBatch: boolean }>;
|
|
36
36
|
|
|
37
|
-
/**
|
|
38
|
-
* return block information of specified tx
|
|
39
|
-
* @param txId
|
|
40
|
-
* @return block info
|
|
41
|
-
*/
|
|
42
|
-
abstract getTxBlock: (txId: string) => Promise<BlockInfo>;
|
|
43
|
-
|
|
44
37
|
/**
|
|
45
38
|
* return all related data below the initial height (including the init height)
|
|
46
39
|
* @param initialHeight
|
|
@@ -75,6 +68,8 @@ export abstract class AbstractInitializableErgoExtractor<
|
|
|
75
68
|
...data,
|
|
76
69
|
spendBlock: spent ? box.spentBlockId : undefined,
|
|
77
70
|
spendHeight: spent ? box.spentHeight : undefined,
|
|
71
|
+
spendTxId: spent ? box.spentTransactionId : undefined,
|
|
72
|
+
spendIndex: spent ? box.spentIndex : undefined,
|
|
78
73
|
} as ExtractedData;
|
|
79
74
|
this.logger.debug(
|
|
80
75
|
`Extracted data ${JsonBigInt.stringify(extractedData)} from box ${
|
|
@@ -2,7 +2,6 @@ import { AbstractLogger } from '@rosen-bridge/abstract-logger';
|
|
|
2
2
|
|
|
3
3
|
import { ErgoExtractedData, ErgoNetworkType, ErgoBox } from '../interfaces';
|
|
4
4
|
import { AbstractInitializableErgoExtractor } from './AbstractInitializable';
|
|
5
|
-
import { BlockInfo } from '../../interfaces';
|
|
6
5
|
import { ExplorerNetwork } from '../network/ExplorerNetwork';
|
|
7
6
|
import { NodeNetwork } from '../network/NodeNetwork';
|
|
8
7
|
import { AbstractNetwork } from '../network/AbstractNetwork';
|
|
@@ -41,13 +40,4 @@ export abstract class AbstractInitializableByAddressErgoExtractor<
|
|
|
41
40
|
): Promise<{ boxes: ErgoBox[]; hasNextBatch: boolean }> => {
|
|
42
41
|
return this.network.getBoxesByAddress(this.address, offset, limit);
|
|
43
42
|
};
|
|
44
|
-
|
|
45
|
-
/**
|
|
46
|
-
* return block information from the specified network source
|
|
47
|
-
* @param txId
|
|
48
|
-
* @return block info
|
|
49
|
-
*/
|
|
50
|
-
getTxBlock = (txId: string): Promise<BlockInfo> => {
|
|
51
|
-
return this.network.getTxBlock(txId);
|
|
52
|
-
};
|
|
53
43
|
}
|
|
@@ -2,7 +2,6 @@ import { AbstractLogger } from '@rosen-bridge/abstract-logger';
|
|
|
2
2
|
|
|
3
3
|
import { ErgoExtractedData, ErgoNetworkType, ErgoBox } from '../interfaces';
|
|
4
4
|
import { AbstractInitializableErgoExtractor } from './AbstractInitializable';
|
|
5
|
-
import { BlockInfo } from '../../interfaces';
|
|
6
5
|
import { ExplorerNetwork } from '../network/ExplorerNetwork';
|
|
7
6
|
import { NodeNetwork } from '../network/NodeNetwork';
|
|
8
7
|
import { AbstractNetwork } from '../network/AbstractNetwork';
|
|
@@ -41,13 +40,4 @@ export abstract class AbstractInitializableByTokenErgoExtractor<
|
|
|
41
40
|
): Promise<{ boxes: ErgoBox[]; hasNextBatch: boolean }> => {
|
|
42
41
|
return this.network.getBoxesByTokenId(this.tokenId, offset, limit);
|
|
43
42
|
};
|
|
44
|
-
|
|
45
|
-
/**
|
|
46
|
-
* return block information from the specified network source
|
|
47
|
-
* @param txId
|
|
48
|
-
* @return block info
|
|
49
|
-
*/
|
|
50
|
-
getTxBlock = (txId: string): Promise<BlockInfo> => {
|
|
51
|
-
return this.network.getTxBlock(txId);
|
|
52
|
-
};
|
|
53
43
|
}
|
package/lib/ergo/interfaces.ts
CHANGED
|
@@ -41,6 +41,8 @@ export interface ErgoBox extends OutputBox {
|
|
|
41
41
|
inclusionHeight: number;
|
|
42
42
|
spentBlockId?: string;
|
|
43
43
|
spentHeight?: number;
|
|
44
|
+
spentTransactionId?: string;
|
|
45
|
+
spentIndex?: number;
|
|
44
46
|
}
|
|
45
47
|
|
|
46
48
|
export type Transaction = {
|
|
@@ -63,4 +65,6 @@ export interface ErgoExtractedData {
|
|
|
63
65
|
blockId: string;
|
|
64
66
|
spendBlock?: string;
|
|
65
67
|
spendHeight?: number;
|
|
68
|
+
spendTxId?: string;
|
|
69
|
+
spendIndex?: number;
|
|
66
70
|
}
|
|
@@ -1,12 +1,6 @@
|
|
|
1
|
-
import { BlockInfo } from '../../interfaces';
|
|
2
1
|
import { ErgoBox } from '../interfaces';
|
|
3
|
-
export abstract class AbstractNetwork {
|
|
4
|
-
/**
|
|
5
|
-
* return block information of specified tx
|
|
6
|
-
* @param txId
|
|
7
|
-
*/
|
|
8
|
-
abstract getTxBlock: (txId: string) => Promise<BlockInfo>;
|
|
9
2
|
|
|
3
|
+
export abstract class AbstractNetwork {
|
|
10
4
|
/**
|
|
11
5
|
* return related boxes by specified address with limit offset
|
|
12
6
|
* @param address
|
|
@@ -4,6 +4,7 @@ import { BlockInfo } from '../../interfaces';
|
|
|
4
4
|
import { ErgoBox } from '../interfaces';
|
|
5
5
|
import { AbstractNetwork } from './AbstractNetwork';
|
|
6
6
|
import { V1 } from '@rosen-clients/ergo-explorer';
|
|
7
|
+
import { mapValues, pick } from 'lodash-es';
|
|
7
8
|
|
|
8
9
|
export class ExplorerNetwork extends AbstractNetwork {
|
|
9
10
|
private api;
|
|
@@ -14,14 +15,24 @@ export class ExplorerNetwork extends AbstractNetwork {
|
|
|
14
15
|
}
|
|
15
16
|
|
|
16
17
|
/**
|
|
17
|
-
* return
|
|
18
|
-
* @param
|
|
18
|
+
* return spending information of a specified box by having spendTxId
|
|
19
|
+
* @param boxId
|
|
20
|
+
* @param spendTxId
|
|
19
21
|
*/
|
|
20
|
-
|
|
21
|
-
|
|
22
|
+
getSpendingInfo = async (
|
|
23
|
+
boxId: string,
|
|
24
|
+
spendTxId: string
|
|
25
|
+
): Promise<BlockInfo & { spendIndex: number }> => {
|
|
26
|
+
const tx = await this.api.v1.getApiV1TransactionsP1(spendTxId);
|
|
27
|
+
const spendIndex = tx.inputs?.findIndex((box) => box.boxId === boxId);
|
|
28
|
+
if (spendIndex == undefined)
|
|
29
|
+
throw Error(
|
|
30
|
+
`Impossible behavior, the box [${boxId}] should have been spent in tx [${spendTxId}]`
|
|
31
|
+
);
|
|
22
32
|
return {
|
|
23
33
|
hash: tx.blockId,
|
|
24
34
|
height: tx.inclusionHeight,
|
|
35
|
+
spendIndex,
|
|
25
36
|
};
|
|
26
37
|
};
|
|
27
38
|
|
|
@@ -32,7 +43,7 @@ export class ExplorerNetwork extends AbstractNetwork {
|
|
|
32
43
|
*/
|
|
33
44
|
convertBox = async (box: V1.OutputInfo): Promise<ErgoBox> => {
|
|
34
45
|
const spendInfo = box.spentTransactionId
|
|
35
|
-
? await this.
|
|
46
|
+
? await this.getSpendingInfo(box.boxId, box.spentTransactionId)
|
|
36
47
|
: undefined;
|
|
37
48
|
return {
|
|
38
49
|
blockId: box.blockId,
|
|
@@ -43,10 +54,15 @@ export class ExplorerNetwork extends AbstractNetwork {
|
|
|
43
54
|
index: box.index,
|
|
44
55
|
transactionId: box.transactionId,
|
|
45
56
|
value: box.value,
|
|
46
|
-
additionalRegisters:
|
|
47
|
-
|
|
57
|
+
additionalRegisters: mapValues(
|
|
58
|
+
box.additionalRegisters,
|
|
59
|
+
'serializedValue'
|
|
60
|
+
),
|
|
61
|
+
assets: box.assets?.map((asset) => pick(asset, ['tokenId', 'amount'])),
|
|
48
62
|
spentHeight: spendInfo?.height,
|
|
49
63
|
spentBlockId: spendInfo?.hash,
|
|
64
|
+
spentTransactionId: box.spentTransactionId,
|
|
65
|
+
spentIndex: spendInfo?.spendIndex,
|
|
50
66
|
};
|
|
51
67
|
};
|
|
52
68
|
|
|
@@ -19,10 +19,10 @@ export class NodeNetwork extends AbstractNetwork {
|
|
|
19
19
|
* @param box
|
|
20
20
|
* @returns ErgoBox
|
|
21
21
|
*/
|
|
22
|
-
|
|
23
|
-
const tx = await this.
|
|
22
|
+
convertBox = async (box: IndexedErgoBox): Promise<ErgoBox> => {
|
|
23
|
+
const tx = await await this.api.getTxById(box.transactionId!);
|
|
24
24
|
const spendInfo = box.spentTransactionId
|
|
25
|
-
? await this.
|
|
25
|
+
? await this.getSpendingInfo(box.boxId!, box.spentTransactionId)
|
|
26
26
|
: undefined;
|
|
27
27
|
return {
|
|
28
28
|
transactionId: box.transactionId || '',
|
|
@@ -30,25 +30,37 @@ export class NodeNetwork extends AbstractNetwork {
|
|
|
30
30
|
value: box.value || 0n,
|
|
31
31
|
ergoTree: box.ergoTree || '',
|
|
32
32
|
creationHeight: box.creationHeight || 0,
|
|
33
|
-
inclusionHeight: tx.
|
|
33
|
+
inclusionHeight: tx.inclusionHeight,
|
|
34
34
|
assets: box.assets || [],
|
|
35
35
|
additionalRegisters: box.additionalRegisters,
|
|
36
36
|
boxId: box.boxId || '',
|
|
37
|
-
blockId: tx.
|
|
38
|
-
spentBlockId: spendInfo?.hash
|
|
39
|
-
spentHeight: spendInfo?.height
|
|
37
|
+
blockId: tx.blockId,
|
|
38
|
+
spentBlockId: spendInfo?.hash,
|
|
39
|
+
spentHeight: spendInfo?.height,
|
|
40
|
+
spentTransactionId: box.spentTransactionId,
|
|
41
|
+
spentIndex: spendInfo?.spendIndex,
|
|
40
42
|
};
|
|
41
43
|
};
|
|
42
44
|
|
|
43
45
|
/**
|
|
44
|
-
* return
|
|
45
|
-
* @param
|
|
46
|
+
* return spending information of a specified box by having spendTxId
|
|
47
|
+
* @param boxId
|
|
48
|
+
* @param spendTxId
|
|
46
49
|
*/
|
|
47
|
-
|
|
48
|
-
|
|
50
|
+
getSpendingInfo = async (
|
|
51
|
+
boxId: string,
|
|
52
|
+
spendTxId: string
|
|
53
|
+
): Promise<BlockInfo & { spendIndex: number }> => {
|
|
54
|
+
const tx = await this.api.getTxById(spendTxId);
|
|
55
|
+
const spendIndex = tx.inputs?.findIndex((box) => box.boxId == boxId);
|
|
56
|
+
if (spendIndex == undefined)
|
|
57
|
+
throw Error(
|
|
58
|
+
`Impossible behavior, the box [${boxId}] should have been spent in tx [${spendTxId}]`
|
|
59
|
+
);
|
|
49
60
|
return {
|
|
50
61
|
hash: tx.blockId,
|
|
51
62
|
height: tx.inclusionHeight,
|
|
63
|
+
spendIndex,
|
|
52
64
|
};
|
|
53
65
|
};
|
|
54
66
|
|
|
@@ -72,7 +84,7 @@ export class NodeNetwork extends AbstractNetwork {
|
|
|
72
84
|
if (!boxes)
|
|
73
85
|
throw new Error('Ergo node BoxesByAddress api expected to have items');
|
|
74
86
|
const ergoBoxes = await Promise.all(
|
|
75
|
-
boxes.map(async (box) => await this.
|
|
87
|
+
boxes.map(async (box) => await this.convertBox(box))
|
|
76
88
|
);
|
|
77
89
|
return { boxes: ergoBoxes, hasNextBatch: boxes.length > 0 };
|
|
78
90
|
};
|
|
@@ -96,7 +108,7 @@ export class NodeNetwork extends AbstractNetwork {
|
|
|
96
108
|
if (!boxes.items)
|
|
97
109
|
throw new Error('Ergo node BoxesByTokenId api expected to have items');
|
|
98
110
|
const ergoBoxes = await Promise.all(
|
|
99
|
-
boxes.items.map(async (box) => await this.
|
|
111
|
+
boxes.items.map(async (box) => await this.convertBox(box))
|
|
100
112
|
);
|
|
101
113
|
return { boxes: ergoBoxes, hasNextBatch: boxes.items.length > 0 };
|
|
102
114
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rosen-bridge/abstract-extractor",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "Rosen Bridge extractor interfaces to work with scanner",
|
|
5
5
|
"repository": "",
|
|
6
6
|
"license": "GPL-3.0",
|
|
@@ -35,7 +35,7 @@
|
|
|
35
35
|
},
|
|
36
36
|
"dependencies": {
|
|
37
37
|
"@rosen-bridge/abstract-logger": "^1.0.0",
|
|
38
|
-
"@rosen-clients/ergo-explorer": "^1.1.
|
|
38
|
+
"@rosen-clients/ergo-explorer": "^1.1.2",
|
|
39
39
|
"@rosen-clients/ergo-node": "^1.1.1",
|
|
40
40
|
"lodash-es": "^4.17.21"
|
|
41
41
|
}
|
|
@@ -111,6 +111,9 @@ describe('AbstractInitializableErgoExtractorAction', () => {
|
|
|
111
111
|
spendBlock:
|
|
112
112
|
'9239ebca7b3b10701895e491a2213da4e07a37abc413d05434a5fab04993a19d',
|
|
113
113
|
spendHeight: 1252680,
|
|
114
|
+
spendTxId:
|
|
115
|
+
'b08fa920a6907d0e76eb0ad754439f1a26fa112b39f4de489620e4e6241930b7',
|
|
116
|
+
spendIndex: 1,
|
|
114
117
|
},
|
|
115
118
|
],
|
|
116
119
|
hasNextBatch: true,
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { describe, expect, it, vitest } from 'vitest';
|
|
2
|
+
import ergoExplorerClientFactory from '@rosen-clients/ergo-explorer';
|
|
3
|
+
|
|
4
|
+
import { ExplorerNetwork } from '../../lib';
|
|
5
|
+
import { convertedBox, explorerBox, explorerTxInfo } from './testData';
|
|
6
|
+
|
|
7
|
+
vitest.mock('@rosen-clients/ergo-explorer');
|
|
8
|
+
|
|
9
|
+
describe('ExplorerNetwork', () => {
|
|
10
|
+
describe('convertBox', () => {
|
|
11
|
+
/**
|
|
12
|
+
* @target covertBox should properly convert explorer api box to ergo box
|
|
13
|
+
* @dependencies
|
|
14
|
+
* @scenario
|
|
15
|
+
* - mock getApiV1TransactionsP1 to return spending transaction
|
|
16
|
+
* - run test (call `covertBox`)
|
|
17
|
+
* @expected
|
|
18
|
+
* - to convert box properly
|
|
19
|
+
*/
|
|
20
|
+
it('should properly convert explorer api box to ergo box', async () => {
|
|
21
|
+
vitest.mocked(ergoExplorerClientFactory).mockReturnValue({
|
|
22
|
+
v1: {
|
|
23
|
+
getApiV1TransactionsP1: async () => explorerTxInfo,
|
|
24
|
+
},
|
|
25
|
+
} as unknown as ReturnType<typeof ergoExplorerClientFactory>);
|
|
26
|
+
const explorerNetwork = new ExplorerNetwork('explorer_url');
|
|
27
|
+
const ergoBox = await explorerNetwork.convertBox(explorerBox);
|
|
28
|
+
expect(ergoBox).toEqual(convertedBox);
|
|
29
|
+
});
|
|
30
|
+
});
|
|
31
|
+
});
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { describe, expect, it, vitest } from 'vitest';
|
|
2
|
+
import ergoNodeClientFactory from '@rosen-clients/ergo-node';
|
|
3
|
+
|
|
4
|
+
import { NodeNetwork } from '../../lib';
|
|
5
|
+
import {
|
|
6
|
+
convertedBox,
|
|
7
|
+
nodeBox,
|
|
8
|
+
nodeSpendingTxInfo,
|
|
9
|
+
nodeCreationTxInfo,
|
|
10
|
+
} from './testData';
|
|
11
|
+
|
|
12
|
+
vitest.mock('@rosen-clients/ergo-node');
|
|
13
|
+
|
|
14
|
+
describe('NodeNetwork', () => {
|
|
15
|
+
describe('convertBox', () => {
|
|
16
|
+
/**
|
|
17
|
+
* @target covertBox should properly convert node api box to ergo box
|
|
18
|
+
* @dependencies
|
|
19
|
+
* @scenario
|
|
20
|
+
* - mock getTxById to return creation and spending transaction
|
|
21
|
+
* - run test (call `covertBox`)
|
|
22
|
+
* @expected
|
|
23
|
+
* - to convert box properly
|
|
24
|
+
*/
|
|
25
|
+
it('should properly convert node api box to ergo box', async () => {
|
|
26
|
+
vitest.mocked(ergoNodeClientFactory).mockReturnValue({
|
|
27
|
+
getTxById: async (txId: string) => {
|
|
28
|
+
if (txId == nodeSpendingTxInfo.id) return nodeSpendingTxInfo;
|
|
29
|
+
else return nodeCreationTxInfo;
|
|
30
|
+
},
|
|
31
|
+
} as unknown as ReturnType<typeof ergoNodeClientFactory>);
|
|
32
|
+
const nodeNetwork = new NodeNetwork('node_url');
|
|
33
|
+
const ergoBox = await nodeNetwork.convertBox(nodeBox);
|
|
34
|
+
expect(ergoBox).toEqual(convertedBox);
|
|
35
|
+
});
|
|
36
|
+
});
|
|
37
|
+
});
|