@subql/node-starknet 0.0.2-7 → 0.0.2-9
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/dist/.tsbuildinfo +1 -1
- package/dist/indexer/blockDispatcher/block-dispatcher.service.js.map +1 -1
- package/dist/indexer/dictionary/v1/starknetDictionaryV1.d.ts +0 -1
- package/dist/indexer/dictionary/v1/starknetDictionaryV1.js +26 -47
- package/dist/indexer/dictionary/v1/starknetDictionaryV1.js.map +1 -1
- package/dist/indexer/dictionary/v1/starknetDictionaryV1.spec.d.ts +1 -0
- package/dist/indexer/dictionary/v1/starknetDictionaryV1.spec.js +189 -0
- package/dist/indexer/dictionary/v1/starknetDictionaryV1.spec.js.map +1 -0
- package/dist/indexer/fetch.service.js +1 -1
- package/dist/indexer/fetch.service.js.map +1 -1
- package/dist/indexer/project.service.js +1 -1
- package/dist/indexer/project.service.js.map +1 -1
- package/dist/indexer/types.js +5 -2
- package/dist/indexer/types.js.map +1 -1
- package/dist/indexer/unfinalizedBlocks.service.d.ts +0 -2
- package/dist/indexer/unfinalizedBlocks.service.js +0 -2
- package/dist/indexer/unfinalizedBlocks.service.js.map +1 -1
- package/dist/starknet/api.service.starknet.test.js +0 -4
- package/dist/starknet/api.service.starknet.test.js.map +1 -1
- package/dist/starknet/api.starknet.d.ts +7 -9
- package/dist/starknet/api.starknet.js +52 -90
- package/dist/starknet/api.starknet.js.map +1 -1
- package/dist/starknet/api.starknet.test.js +12 -5
- package/dist/starknet/api.starknet.test.js.map +1 -1
- package/dist/starknet/block.starknet.js +20 -12
- package/dist/starknet/block.starknet.js.map +1 -1
- package/dist/starknet/block.starknet.test.js +36 -1
- package/dist/starknet/block.starknet.test.js.map +1 -1
- package/dist/starknet/finalized.block.starknet.d.ts +21 -0
- package/dist/starknet/finalized.block.starknet.js +93 -0
- package/dist/starknet/finalized.block.starknet.js.map +1 -0
- package/dist/starknet/finalized.block.starknet.spec.d.ts +1 -0
- package/dist/starknet/finalized.block.starknet.spec.js +94 -0
- package/dist/starknet/finalized.block.starknet.spec.js.map +1 -0
- package/dist/starknet/utils.starknet.d.ts +40 -7
- package/dist/starknet/utils.starknet.js +50 -21
- package/dist/starknet/utils.starknet.js.map +1 -1
- package/dist/utils/project.js.map +1 -1
- package/package.json +4 -4
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { EventEmitter2 } from '@nestjs/event-emitter';
|
|
2
|
-
import { BlockWithTxs, SPEC } from '@starknet-io/types-js';
|
|
3
2
|
import { IBlock } from '@subql/node-core';
|
|
4
|
-
import { ApiWrapper, StarknetBlock, StarknetRuntimeDatasource, IStarknetEndpointConfig, LightStarknetBlock,
|
|
5
|
-
import { RpcProvider,
|
|
3
|
+
import { ApiWrapper, StarknetBlock, StarknetRuntimeDatasource, IStarknetEndpointConfig, LightStarknetBlock, StarknetResult, StarknetTransaction, StarknetLog, StarknetContractCall } from '@subql/types-starknet';
|
|
4
|
+
import { RpcProvider, Abi } from 'starknet';
|
|
5
|
+
import { SPEC } from 'starknet-types-07';
|
|
6
6
|
import SafeStarknetProvider from './safe-api';
|
|
7
7
|
export declare class StarknetApi implements ApiWrapper {
|
|
8
8
|
private endpoint;
|
|
@@ -14,6 +14,7 @@ export declare class StarknetApi implements ApiWrapper {
|
|
|
14
14
|
private contractInterfaces;
|
|
15
15
|
private chainId?;
|
|
16
16
|
private specVersion?;
|
|
17
|
+
private finalizedBlockService;
|
|
17
18
|
private _supportsFinalization;
|
|
18
19
|
get supportsFinalization(): boolean;
|
|
19
20
|
/**
|
|
@@ -26,19 +27,16 @@ export declare class StarknetApi implements ApiWrapper {
|
|
|
26
27
|
private getGenesisBlock;
|
|
27
28
|
/***
|
|
28
29
|
* Get the latest block (with its header)
|
|
29
|
-
* we will try to get the latest block, if it is rejected, we will get the latest accepted block
|
|
30
30
|
* @returns {Promise<BLOCK_HEADER>}
|
|
31
31
|
*/
|
|
32
|
-
getFinalizedBlock(): Promise<SPEC.
|
|
32
|
+
getFinalizedBlock(): Promise<SPEC.BLOCK_WITH_RECEIPTS>;
|
|
33
33
|
getFinalizedBlockHeight(): Promise<number>;
|
|
34
|
+
getBestBlockHeight(): Promise<number>;
|
|
34
35
|
getChainId(): string;
|
|
35
36
|
getGenesisHash(): string;
|
|
36
37
|
getSpecVersion(): string;
|
|
37
|
-
getBlockByHeightOrHash(heightOrHash: number | string): Promise<
|
|
38
|
-
private getBlockPromise;
|
|
39
|
-
getTransactionReceipt(transactionHash: string): Promise<TransactionReceipt>;
|
|
38
|
+
getBlockByHeightOrHash(heightOrHash: number | string): Promise<SPEC.BLOCK_WITH_RECEIPTS>;
|
|
40
39
|
fetchBlock(blockNumber: number): Promise<IBlock<StarknetBlock>>;
|
|
41
|
-
fetchBlockLogs(blockNumber: number): Promise<StarknetLogRaw[]>;
|
|
42
40
|
private fetchLightBlock;
|
|
43
41
|
fetchBlocks(bufferBlocks: number[]): Promise<IBlock<StarknetBlock>[]>;
|
|
44
42
|
fetchBlocksLight(bufferBlocks: number[]): Promise<IBlock<LightStarknetBlock>[]>;
|
|
@@ -10,12 +10,12 @@ const assert_1 = __importDefault(require("assert"));
|
|
|
10
10
|
const fs_1 = __importDefault(require("fs"));
|
|
11
11
|
const node_core_1 = require("@subql/node-core");
|
|
12
12
|
const starknet_1 = require("starknet");
|
|
13
|
+
const finalized_block_starknet_1 = require("./finalized.block.starknet");
|
|
13
14
|
const safe_api_1 = __importDefault(require("./safe-api"));
|
|
14
15
|
const utils_starknet_1 = require("./utils.starknet");
|
|
15
16
|
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
16
17
|
const { version: packageVersion } = require('../../package.json');
|
|
17
18
|
const logger = (0, node_core_1.getLogger)('api.starknet');
|
|
18
|
-
const DEFAULT_EVENT_CHUNK_SIZE = 1000;
|
|
19
19
|
async function loadAssets(ds) {
|
|
20
20
|
if (!ds.assets) {
|
|
21
21
|
return {};
|
|
@@ -42,6 +42,7 @@ class StarknetApi {
|
|
|
42
42
|
contractInterfaces = {};
|
|
43
43
|
chainId;
|
|
44
44
|
specVersion;
|
|
45
|
+
finalizedBlockService;
|
|
45
46
|
// Starknet POS
|
|
46
47
|
_supportsFinalization = true;
|
|
47
48
|
get supportsFinalization() {
|
|
@@ -58,23 +59,22 @@ class StarknetApi {
|
|
|
58
59
|
const { hostname, protocol, searchParams } = new URL(endpoint);
|
|
59
60
|
const protocolStr = protocol.replace(':', '');
|
|
60
61
|
logger.info(`Api host: ${hostname}, method: ${protocolStr}`);
|
|
61
|
-
if (protocolStr
|
|
62
|
-
const connection = {
|
|
63
|
-
nodeUrl: this.endpoint,
|
|
64
|
-
headers: {
|
|
65
|
-
'User-Agent': `Subquery-Node ${packageVersion}`,
|
|
66
|
-
...config?.headers,
|
|
67
|
-
},
|
|
68
|
-
batch: this.config?.batchSize ?? false,
|
|
69
|
-
};
|
|
70
|
-
searchParams.forEach((value, name, searchParams) => {
|
|
71
|
-
connection.headers[name] = value;
|
|
72
|
-
});
|
|
73
|
-
this.client = new starknet_1.RpcProvider(connection);
|
|
74
|
-
}
|
|
75
|
-
else {
|
|
62
|
+
if (protocolStr !== 'https' && protocolStr !== 'http') {
|
|
76
63
|
throw new Error(`Unsupported protocol: ${protocol}`);
|
|
77
64
|
}
|
|
65
|
+
const connection = {
|
|
66
|
+
nodeUrl: this.endpoint,
|
|
67
|
+
headers: {
|
|
68
|
+
'User-Agent': `Subquery-Node ${packageVersion}`,
|
|
69
|
+
...config?.headers,
|
|
70
|
+
},
|
|
71
|
+
batch: this.config?.batchSize ?? false,
|
|
72
|
+
};
|
|
73
|
+
searchParams.forEach((value, name) => {
|
|
74
|
+
connection.headers[name] = value;
|
|
75
|
+
});
|
|
76
|
+
this.client = new starknet_1.RpcProvider(connection);
|
|
77
|
+
this.finalizedBlockService = new finalized_block_starknet_1.FinalizedBlockService(this.getBlockByHeightOrHash.bind(this), logger);
|
|
78
78
|
}
|
|
79
79
|
get genesisBlock() {
|
|
80
80
|
if (!this._genesisBlock) {
|
|
@@ -111,22 +111,16 @@ class StarknetApi {
|
|
|
111
111
|
}
|
|
112
112
|
/***
|
|
113
113
|
* Get the latest block (with its header)
|
|
114
|
-
* we will try to get the latest block, if it is rejected, we will get the latest accepted block
|
|
115
114
|
* @returns {Promise<BLOCK_HEADER>}
|
|
116
115
|
*/
|
|
117
116
|
async getFinalizedBlock() {
|
|
118
|
-
const
|
|
119
|
-
|
|
120
|
-
await this.getFinalizedBlockHeight(),
|
|
121
|
-
]);
|
|
122
|
-
// @ts-ignore
|
|
123
|
-
let b = latestBlock;
|
|
124
|
-
if (latestBlock.status === 'REJECTED') {
|
|
125
|
-
b = (await this.getBlockByHeightOrHash(latestAccepted));
|
|
126
|
-
}
|
|
127
|
-
return b;
|
|
117
|
+
const block = await this.finalizedBlockService.getFinalizedBlock();
|
|
118
|
+
return block;
|
|
128
119
|
}
|
|
129
120
|
async getFinalizedBlockHeight() {
|
|
121
|
+
return (await this.getFinalizedBlock()).block_number;
|
|
122
|
+
}
|
|
123
|
+
async getBestBlockHeight() {
|
|
130
124
|
return (await this.client.getBlockLatestAccepted()).block_number;
|
|
131
125
|
}
|
|
132
126
|
getChainId() {
|
|
@@ -141,35 +135,32 @@ class StarknetApi {
|
|
|
141
135
|
return this.specVersion;
|
|
142
136
|
}
|
|
143
137
|
async getBlockByHeightOrHash(heightOrHash) {
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
async getBlockPromise(num, includeTx = true) {
|
|
148
|
-
const rawBlock = includeTx
|
|
149
|
-
? await this.client.getBlockWithTxs(num)
|
|
150
|
-
: await this.client.getBlockWithTxHashes(num);
|
|
151
|
-
if (!rawBlock) {
|
|
152
|
-
throw new Error(`Failed to fetch block ${num}`);
|
|
138
|
+
const block = await this.client.getBlockWithReceipts(heightOrHash);
|
|
139
|
+
if (!(0, utils_starknet_1.isFinalizedBlock)(block)) {
|
|
140
|
+
throw `Block ${block} is not a fulfilled block, its parent is ${block.parent_hash}`;
|
|
153
141
|
}
|
|
154
|
-
const block = (0, utils_starknet_1.formatBlock)(rawBlock);
|
|
155
142
|
return block;
|
|
156
143
|
}
|
|
157
|
-
async getTransactionReceipt(transactionHash) {
|
|
158
|
-
const receipt = await this.client.getTransactionReceipt(transactionHash);
|
|
159
|
-
return (0, utils_starknet_1.formatReceipt)(receipt);
|
|
160
|
-
}
|
|
161
144
|
async fetchBlock(blockNumber) {
|
|
162
145
|
try {
|
|
163
|
-
const
|
|
164
|
-
const
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
146
|
+
const rawBlock = await this.getBlockByHeightOrHash(blockNumber);
|
|
147
|
+
const formattedBlock = (0, utils_starknet_1.formatBlock)(rawBlock);
|
|
148
|
+
const formattedTransactions = rawBlock.transactions.map((tx, index) => {
|
|
149
|
+
const formattedTransaction = (0, utils_starknet_1.formatTransaction)(tx, formattedBlock, index);
|
|
150
|
+
return {
|
|
151
|
+
...formattedTransaction,
|
|
152
|
+
logs: tx.receipt.events.map((l, logIndex) => (0, utils_starknet_1.formatLog)(l, logIndex, formattedTransaction, formattedBlock)),
|
|
153
|
+
};
|
|
154
|
+
});
|
|
155
|
+
const logs = formattedTransactions.flatMap((tx) => tx.logs.map((l) => ({
|
|
156
|
+
...l,
|
|
157
|
+
transaction: tx,
|
|
158
|
+
})));
|
|
159
|
+
const block = {
|
|
160
|
+
...formattedBlock,
|
|
161
|
+
transactions: formattedTransactions,
|
|
162
|
+
logs,
|
|
163
|
+
};
|
|
173
164
|
this.eventEmitter.emit('fetchBlock');
|
|
174
165
|
return (0, utils_starknet_1.formatBlockUtil)(block);
|
|
175
166
|
}
|
|
@@ -177,47 +168,18 @@ class StarknetApi {
|
|
|
177
168
|
throw this.handleError(e);
|
|
178
169
|
}
|
|
179
170
|
}
|
|
180
|
-
// This follow method from official document https://starknetjs.com/docs/guides/events
|
|
181
|
-
async fetchBlockLogs(blockNumber) {
|
|
182
|
-
let continuationToken = '0';
|
|
183
|
-
let chunkNum = 1;
|
|
184
|
-
const allEvents = [];
|
|
185
|
-
while (continuationToken) {
|
|
186
|
-
let eventsRes;
|
|
187
|
-
try {
|
|
188
|
-
eventsRes = await this.client.getEvents({
|
|
189
|
-
from_block: {
|
|
190
|
-
block_number: blockNumber,
|
|
191
|
-
},
|
|
192
|
-
to_block: {
|
|
193
|
-
block_number: blockNumber,
|
|
194
|
-
},
|
|
195
|
-
chunk_size: DEFAULT_EVENT_CHUNK_SIZE,
|
|
196
|
-
continuation_token: continuationToken === '0' ? undefined : continuationToken,
|
|
197
|
-
});
|
|
198
|
-
}
|
|
199
|
-
catch (e) {
|
|
200
|
-
if (!eventsRes) {
|
|
201
|
-
throw new Error(`Fetch block ${blockNumber} events failed, ${e.message}`);
|
|
202
|
-
}
|
|
203
|
-
else {
|
|
204
|
-
throw e;
|
|
205
|
-
}
|
|
206
|
-
}
|
|
207
|
-
const nbEvents = eventsRes.events.length;
|
|
208
|
-
continuationToken = eventsRes.continuation_token;
|
|
209
|
-
for (let i = 0; i < nbEvents; i++) {
|
|
210
|
-
const event = eventsRes.events[i];
|
|
211
|
-
allEvents.push(event);
|
|
212
|
-
}
|
|
213
|
-
chunkNum++;
|
|
214
|
-
}
|
|
215
|
-
return allEvents;
|
|
216
|
-
}
|
|
217
171
|
async fetchLightBlock(blockNumber) {
|
|
218
|
-
const block = await this.
|
|
172
|
+
const block = (await this.client.getBlockWithTxHashes(blockNumber));
|
|
219
173
|
const lightBlock = {
|
|
220
174
|
...block,
|
|
175
|
+
blockHash: block.block_hash,
|
|
176
|
+
blockNumber: block.block_number,
|
|
177
|
+
parentHash: block.parent_hash,
|
|
178
|
+
newRoot: block.new_root,
|
|
179
|
+
sequencerAddress: block.sequencer_address,
|
|
180
|
+
l1GasPrice: block.l1_gas_price,
|
|
181
|
+
starknetVersion: block.starknet_version,
|
|
182
|
+
logs: [],
|
|
221
183
|
};
|
|
222
184
|
return (0, utils_starknet_1.formatBlockUtil)(lightBlock);
|
|
223
185
|
}
|
|
@@ -225,7 +187,7 @@ class StarknetApi {
|
|
|
225
187
|
return Promise.all(bufferBlocks.map(async (num) => this.fetchBlock(num)));
|
|
226
188
|
}
|
|
227
189
|
async fetchBlocksLight(bufferBlocks) {
|
|
228
|
-
return Promise.all(bufferBlocks.map(async (num) => this.
|
|
190
|
+
return Promise.all(bufferBlocks.map(async (num) => this.fetchLightBlock(num)));
|
|
229
191
|
}
|
|
230
192
|
get api() {
|
|
231
193
|
return this.client;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"api.starknet.js","sourceRoot":"","sources":["../../src/starknet/api.starknet.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright 2020-2024 SubQuery Pte Ltd authors & contributors\n// SPDX-License-Identifier: GPL-3.0\n\nimport assert from 'assert';\nimport fs from 'fs';\nimport http from 'http';\nimport https from 'https';\nimport { EventEmitter2 } from '@nestjs/event-emitter';\nimport { BlockWithTxs, SPEC } from '@starknet-io/types-js';\nimport { getLogger, IBlock, timeout } from '@subql/node-core';\nimport {\n ApiWrapper,\n StarknetBlock,\n StarknetRuntimeDatasource,\n IStarknetEndpointConfig,\n LightStarknetBlock,\n StarknetLogRaw,\n StarknetResult,\n StarknetTransaction,\n StarknetLog,\n StarknetContractCall,\n} from '@subql/types-starknet';\nimport {\n AbiInterfaces,\n ProviderInterface,\n RpcProvider,\n RpcProviderOptions,\n TransactionReceipt,\n events,\n CallData,\n Abi,\n AbiEntry,\n FunctionAbi,\n} from 'starknet';\nimport SafeStarknetProvider from './safe-api';\nimport {\n hexEq,\n encodeSelectorToHex,\n fetchAbiFromContractAddress,\n formatBlock,\n formatBlockUtil,\n formatLog,\n formatReceipt,\n formatTransaction,\n reverseToRawLog,\n} from './utils.starknet';\n\n// eslint-disable-next-line @typescript-eslint/no-var-requires\nconst { version: packageVersion } = require('../../package.json');\n\nconst logger = getLogger('api.starknet');\n\nconst DEFAULT_EVENT_CHUNK_SIZE = 1000;\n\nasync function loadAssets(\n ds: StarknetRuntimeDatasource,\n): Promise<Record<string, string>> {\n if (!ds.assets) {\n return {};\n }\n const res: Record<string, string> = {};\n\n for (const [name, { file }] of ds.assets.entries()) {\n try {\n res[name] = await fs.promises.readFile(file, { encoding: 'utf8' });\n } catch (e) {\n throw new Error(`Failed to load datasource asset ${file}`);\n }\n }\n\n return res;\n}\n\nexport class StarknetApi implements ApiWrapper {\n private client: RpcProvider;\n\n // This is used within the sandbox when HTTP is used\n private nonBatchClient?: SafeStarknetProvider;\n private _genesisBlock?: Record<string, any>;\n private contractInterfaces: Record<string, Abi> = {};\n private chainId?: string;\n private specVersion?: string;\n\n // Starknet POS\n private _supportsFinalization = true;\n\n get supportsFinalization(): boolean {\n return this._supportsFinalization;\n }\n\n /**\n * @param {string} endpoint - The endpoint of the RPC provider\n * @param {object} eventEmitter - Used to monitor the number of RPC requests\n */\n constructor(\n private endpoint: string,\n private eventEmitter: EventEmitter2,\n private config?: IStarknetEndpointConfig,\n ) {\n const { hostname, protocol, searchParams } = new URL(endpoint);\n\n const protocolStr = protocol.replace(':', '');\n\n logger.info(`Api host: ${hostname}, method: ${protocolStr}`);\n if (protocolStr === 'https' || protocolStr === 'http') {\n const connection: RpcProviderOptions | ProviderInterface = {\n nodeUrl: this.endpoint,\n headers: {\n 'User-Agent': `Subquery-Node ${packageVersion}`,\n ...config?.headers,\n },\n batch: this.config?.batchSize ?? false,\n };\n searchParams.forEach((value, name, searchParams) => {\n (connection.headers as any)[name] = value;\n });\n this.client = new RpcProvider(connection);\n } else {\n throw new Error(`Unsupported protocol: ${protocol}`);\n }\n }\n\n private get genesisBlock(): Record<string, any> {\n if (!this._genesisBlock) {\n throw new Error('Genesis block is not available');\n }\n return this._genesisBlock;\n }\n\n async init(): Promise<void> {\n try {\n this._genesisBlock = await this.getGenesisBlock();\n this.chainId = await this.client.getChainId();\n this.specVersion = await this.client.getSpecVersion();\n } catch (e) {\n if ((e as Error).message.startsWith('Invalid response')) {\n if (!this.nonBatchClient) {\n throw new Error('No suitable client found');\n }\n\n logger.warn(\n `The RPC Node at ${this.endpoint} cannot process batch requests. ` +\n `Switching to non-batch mode for subsequent requests. Please consider checking if batch processing is supported on the RPC node.`,\n );\n\n return this.init();\n }\n\n throw e;\n }\n }\n\n private async getGenesisBlock(): Promise<BlockWithTxs> {\n const block = await this.client.getBlockWithTxs(1);\n if (block === null) {\n throw new Error(`Getting genesis block returned null from block 1`);\n }\n // @ts-ignore\n // TODO, @starknet-io/types-js is not align with starknet rpc types, follow this ticket https://github.com/starknet-io/types-js/issues/31\n return block;\n }\n\n /***\n * Get the latest block (with its header)\n * we will try to get the latest block, if it is rejected, we will get the latest accepted block\n * @returns {Promise<BLOCK_HEADER>}\n */\n async getFinalizedBlock(): Promise<SPEC.BLOCK_HEADER> {\n const [latestBlock, latestAccepted] = await Promise.all([\n this.client.getBlock('latest'),\n await this.getFinalizedBlockHeight(),\n ]);\n // @ts-ignore\n let b: SPEC.BLOCK_HEADER = latestBlock;\n if (latestBlock.status === 'REJECTED') {\n b = (await this.getBlockByHeightOrHash(\n latestAccepted,\n )) as SPEC.BLOCK_WITH_TXS;\n }\n return b;\n }\n\n async getFinalizedBlockHeight(): Promise<number> {\n return (await this.client.getBlockLatestAccepted()).block_number;\n }\n\n getChainId(): string {\n assert(this.chainId, 'Api has not been initialised');\n return this.chainId;\n }\n\n getGenesisHash(): string {\n return this.genesisBlock.block_hash;\n }\n\n getSpecVersion(): string {\n assert(this.specVersion, 'Api has not been initialised');\n return this.specVersion;\n }\n\n async getBlockByHeightOrHash(\n heightOrHash: number | string,\n ): Promise<BlockWithTxs> {\n // @ts-ignore\n return this.client.getBlockWithTxs(heightOrHash);\n }\n\n private async getBlockPromise(num: number, includeTx = true): Promise<any> {\n const rawBlock = includeTx\n ? await this.client.getBlockWithTxs(num)\n : await this.client.getBlockWithTxHashes(num);\n\n if (!rawBlock) {\n throw new Error(`Failed to fetch block ${num}`);\n }\n\n const block = formatBlock(rawBlock);\n\n return block;\n }\n\n async getTransactionReceipt(\n transactionHash: string,\n ): Promise<TransactionReceipt> {\n const receipt = await this.client.getTransactionReceipt(transactionHash);\n return formatReceipt(receipt);\n }\n\n async fetchBlock(blockNumber: number): Promise<IBlock<StarknetBlock>> {\n try {\n const block: StarknetBlock = await this.getBlockPromise(\n blockNumber,\n true,\n );\n const logsRaw = await this.fetchBlockLogs(blockNumber);\n\n block.logs = logsRaw.map((l) => formatLog(l, block));\n // Cast as Tx still raw here\n block.transactions = (block.transactions as Record<string, any>).map(\n (tx, index) => ({\n // Format done\n ...formatTransaction(tx, block, index),\n receipt: () =>\n this.getTransactionReceipt(tx.transaction_hash).then((r) =>\n formatReceipt(r),\n ),\n logs: block.logs.filter(\n (l) => l.transactionHash === tx.transaction_hash,\n ),\n }),\n );\n\n this.eventEmitter.emit('fetchBlock');\n return formatBlockUtil(block);\n } catch (e: any) {\n throw this.handleError(e);\n }\n }\n\n // This follow method from official document https://starknetjs.com/docs/guides/events\n async fetchBlockLogs(blockNumber: number): Promise<StarknetLogRaw[]> {\n let continuationToken: string | undefined = '0';\n let chunkNum = 1;\n const allEvents: StarknetLogRaw[] = [];\n\n while (continuationToken) {\n let eventsRes;\n try {\n eventsRes = await this.client.getEvents({\n from_block: {\n block_number: blockNumber,\n },\n to_block: {\n block_number: blockNumber,\n },\n chunk_size: DEFAULT_EVENT_CHUNK_SIZE,\n continuation_token:\n continuationToken === '0' ? undefined : continuationToken,\n });\n } catch (e: any) {\n if (!eventsRes) {\n throw new Error(\n `Fetch block ${blockNumber} events failed, ${e.message}`,\n );\n } else {\n throw e;\n }\n }\n const nbEvents = eventsRes.events.length;\n continuationToken = eventsRes.continuation_token;\n for (let i = 0; i < nbEvents; i++) {\n const event = eventsRes.events[i];\n allEvents.push(event);\n }\n chunkNum++;\n }\n return allEvents;\n }\n\n private async fetchLightBlock(\n blockNumber: number,\n ): Promise<IBlock<LightStarknetBlock>> {\n const block = await this.getBlockPromise(blockNumber, false);\n const lightBlock: LightStarknetBlock = {\n ...block,\n };\n return formatBlockUtil<LightStarknetBlock>(lightBlock);\n }\n\n async fetchBlocks(bufferBlocks: number[]): Promise<IBlock<StarknetBlock>[]> {\n return Promise.all(bufferBlocks.map(async (num) => this.fetchBlock(num)));\n }\n\n async fetchBlocksLight(\n bufferBlocks: number[],\n ): Promise<IBlock<LightStarknetBlock>[]> {\n return Promise.all(bufferBlocks.map(async (num) => this.fetchBlock(num)));\n }\n\n get api(): RpcProvider {\n return this.client;\n }\n\n private buildInterface(abiName: string, assets: Record<string, string>): Abi {\n if (!assets[abiName]) {\n throw new Error(`ABI named \"${abiName}\" not referenced in assets`);\n }\n\n // This assumes that all datasources have a different abi name or they are the same abi\n if (!this.contractInterfaces[abiName]) {\n // Constructing the interface validates the ABI\n try {\n const abiObj = JSON.parse(assets[abiName]);\n\n this.contractInterfaces[abiName] = abiObj;\n } catch (e: any) {\n logger.error(`Unable to parse ABI: ${e.message}`);\n throw new Error('ABI is invalid');\n }\n }\n\n return this.contractInterfaces[abiName];\n }\n\n async parseLog<T extends StarknetResult = StarknetResult>(\n log: StarknetLog,\n ds: StarknetRuntimeDatasource,\n ): Promise<StarknetLog | StarknetLog<T>> {\n try {\n if (!ds?.options?.abi) {\n logger.warn('No ABI provided for datasource');\n return log;\n }\n const emittedEvent = reverseToRawLog(log);\n const assets = await loadAssets(ds);\n const iAbi = this.buildInterface(ds.options.abi, assets);\n const abiEvents = events.getAbiEvents(iAbi);\n const abiStructs = CallData.getAbiStruct(iAbi);\n const abiEnums = CallData.getAbiEnum(iAbi);\n const [parsed] = events.parseEvents(\n [emittedEvent],\n abiEvents,\n abiStructs,\n abiEnums,\n );\n log.args = parsed as T;\n return log;\n } catch (e: any) {\n logger.warn(`Failed to parse log data: ${e.message}`);\n return log;\n }\n }\n\n async parseTransaction<T extends StarknetResult = StarknetResult>(\n transaction: StarknetTransaction,\n ds: StarknetRuntimeDatasource,\n ): Promise<StarknetTransaction> {\n try {\n const assets = await loadAssets(ds);\n // If decoded calls not exist, try to parse first\n if (!transaction.decodedCalls) {\n transaction.decodedCalls = transaction.parseCallData();\n }\n if (transaction.decodedCalls && transaction.decodedCalls.length > 0) {\n await this.handleDecodedCallsArgs(transaction.decodedCalls, ds, assets);\n } else {\n logger.warn(\n `No decoded calls found in transaction, will skip decode call data for this transaction ${transaction.hash}`,\n );\n }\n transaction.logs =\n transaction.logs &&\n ((await Promise.all(\n transaction.logs.map(async (log) => this.parseLog(log, ds)),\n )) as Array<StarknetLog | StarknetLog<T>>);\n\n return transaction;\n } catch (e: any) {\n logger.warn(`Failed to parse transaction data: ${e.message}`);\n return transaction;\n }\n }\n\n private async handleDecodedCallsArgs(\n decodedCalls: StarknetContractCall[],\n ds: StarknetRuntimeDatasource,\n assets: Record<string, string>,\n ): Promise<void> {\n await Promise.all(\n decodedCalls.map(async (call) => {\n let iAbi: Abi;\n try {\n if (\n ds.options?.address &&\n hexEq(ds.options.address, call.to) &&\n ds.options.abi\n ) {\n iAbi = this.buildInterface(ds.options.abi, assets);\n } else {\n //We could register this abi in memory improve performance, maybe just record with address instead of abi name here\n if (!this.contractInterfaces[call.to]) {\n iAbi = await fetchAbiFromContractAddress(this.client, call.to);\n } else {\n iAbi = this.contractInterfaces[call.to];\n }\n }\n call.decodedArgs = StarknetApi.DecodeCallDataWithAbi(iAbi, call);\n } catch (e: any) {\n logger.warn(\n `Could not decode call data with contract address ${call.to}: ${e.message}`,\n );\n }\n }),\n );\n }\n\n static DecodeCallDataWithAbi(iAbi: Abi, call: StarknetContractCall): any {\n const callData = new CallData(iAbi);\n const { inputs } = callData.parser\n .getLegacyFormat()\n .find(\n (abiItem: AbiEntry) =>\n encodeSelectorToHex(abiItem.name) === call.selector,\n ) as FunctionAbi;\n const inputsTypes = inputs.map((inp: any) => {\n return inp.type as string;\n });\n const res = callData.decodeParameters(inputsTypes, call.calldata);\n const result = inputs.reduce((acc, item, index) => {\n acc[item.name] = res[index];\n return acc;\n }, {});\n return result;\n }\n\n // eslint-disable-next-line @typescript-eslint/require-await\n async connect(): Promise<void> {\n logger.error('Starknet API connect is not implemented');\n throw new Error('Not implemented');\n }\n\n //TODO\n async disconnect(): Promise<void> {\n return Promise.resolve();\n }\n\n handleError(e: Error): Error {\n if ((e as any)?.status === 429) {\n const { hostname } = new URL(this.endpoint);\n return new Error(`Rate Limited at endpoint: ${hostname}`);\n }\n\n return e;\n }\n\n getSafeApi(height: number) {\n return new SafeStarknetProvider(this.client, height);\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"api.starknet.js","sourceRoot":"","sources":["../../src/starknet/api.starknet.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright 2020-2024 SubQuery Pte Ltd authors & contributors\n// SPDX-License-Identifier: GPL-3.0\n\nimport assert from 'assert';\nimport fs from 'fs';\nimport { EventEmitter2 } from '@nestjs/event-emitter';\nimport { BlockWithTxs } from '@starknet-io/types-js';\nimport { getLogger, IBlock } from '@subql/node-core';\nimport {\n ApiWrapper,\n StarknetBlock,\n StarknetRuntimeDatasource,\n IStarknetEndpointConfig,\n LightStarknetBlock,\n StarknetResult,\n StarknetTransaction,\n StarknetLog,\n StarknetContractCall,\n} from '@subql/types-starknet';\nimport {\n ProviderInterface,\n RpcProvider,\n RpcProviderOptions,\n events,\n CallData,\n Abi,\n AbiEntry,\n FunctionAbi,\n} from 'starknet';\nimport { SPEC } from 'starknet-types-07';\nimport { FinalizedBlockService } from './finalized.block.starknet';\nimport SafeStarknetProvider from './safe-api';\nimport {\n hexEq,\n encodeSelectorToHex,\n fetchAbiFromContractAddress,\n formatBlock,\n formatBlockUtil,\n formatLog,\n formatTransaction,\n reverseToRawLog,\n isFinalizedBlock,\n} from './utils.starknet';\n\n// eslint-disable-next-line @typescript-eslint/no-var-requires\nconst { version: packageVersion } = require('../../package.json');\n\nconst logger = getLogger('api.starknet');\n\nasync function loadAssets(\n ds: StarknetRuntimeDatasource,\n): Promise<Record<string, string>> {\n if (!ds.assets) {\n return {};\n }\n const res: Record<string, string> = {};\n\n for (const [name, { file }] of ds.assets.entries()) {\n try {\n res[name] = await fs.promises.readFile(file, { encoding: 'utf8' });\n } catch (e) {\n throw new Error(`Failed to load datasource asset ${file}`);\n }\n }\n\n return res;\n}\n\nexport class StarknetApi implements ApiWrapper {\n private client: RpcProvider;\n\n // This is used within the sandbox when HTTP is used\n private nonBatchClient?: SafeStarknetProvider;\n private _genesisBlock?: Record<string, any>;\n private contractInterfaces: Record<string, Abi> = {};\n private chainId?: string;\n private specVersion?: string;\n private finalizedBlockService: FinalizedBlockService;\n\n // Starknet POS\n private _supportsFinalization = true;\n\n get supportsFinalization(): boolean {\n return this._supportsFinalization;\n }\n\n /**\n * @param {string} endpoint - The endpoint of the RPC provider\n * @param {object} eventEmitter - Used to monitor the number of RPC requests\n */\n constructor(\n private endpoint: string,\n private eventEmitter: EventEmitter2,\n private config?: IStarknetEndpointConfig,\n ) {\n const { hostname, protocol, searchParams } = new URL(endpoint);\n\n const protocolStr = protocol.replace(':', '');\n\n logger.info(`Api host: ${hostname}, method: ${protocolStr}`);\n\n if (protocolStr !== 'https' && protocolStr !== 'http') {\n throw new Error(`Unsupported protocol: ${protocol}`);\n }\n const connection: RpcProviderOptions | ProviderInterface = {\n nodeUrl: this.endpoint,\n headers: {\n 'User-Agent': `Subquery-Node ${packageVersion}`,\n ...config?.headers,\n },\n batch: this.config?.batchSize ?? false,\n };\n searchParams.forEach((value, name) => {\n (connection.headers as any)[name] = value;\n });\n this.client = new RpcProvider(connection);\n this.finalizedBlockService = new FinalizedBlockService(\n this.getBlockByHeightOrHash.bind(this),\n logger,\n );\n }\n\n private get genesisBlock(): Record<string, any> {\n if (!this._genesisBlock) {\n throw new Error('Genesis block is not available');\n }\n return this._genesisBlock;\n }\n\n async init(): Promise<void> {\n try {\n this._genesisBlock = await this.getGenesisBlock();\n this.chainId = await this.client.getChainId();\n this.specVersion = await this.client.getSpecVersion();\n } catch (e) {\n if ((e as Error).message.startsWith('Invalid response')) {\n if (!this.nonBatchClient) {\n throw new Error('No suitable client found');\n }\n\n logger.warn(\n `The RPC Node at ${this.endpoint} cannot process batch requests. ` +\n `Switching to non-batch mode for subsequent requests. Please consider checking if batch processing is supported on the RPC node.`,\n );\n\n return this.init();\n }\n\n throw e;\n }\n }\n\n private async getGenesisBlock(): Promise<BlockWithTxs> {\n const block = await this.client.getBlockWithTxs(1);\n if (block === null) {\n throw new Error(`Getting genesis block returned null from block 1`);\n }\n // @ts-ignore\n // TODO, @starknet-io/types-js is not align with starknet rpc types, follow this ticket https://github.com/starknet-io/types-js/issues/31\n return block;\n }\n\n /***\n * Get the latest block (with its header)\n * @returns {Promise<BLOCK_HEADER>}\n */\n async getFinalizedBlock(): Promise<SPEC.BLOCK_WITH_RECEIPTS> {\n const block = await this.finalizedBlockService.getFinalizedBlock();\n return block;\n }\n\n async getFinalizedBlockHeight(): Promise<number> {\n return (await this.getFinalizedBlock()).block_number;\n }\n\n async getBestBlockHeight(): Promise<number> {\n return (await this.client.getBlockLatestAccepted()).block_number;\n }\n\n getChainId(): string {\n assert(this.chainId, 'Api has not been initialised');\n return this.chainId;\n }\n\n getGenesisHash(): string {\n return this.genesisBlock.block_hash;\n }\n\n getSpecVersion(): string {\n assert(this.specVersion, 'Api has not been initialised');\n return this.specVersion;\n }\n\n async getBlockByHeightOrHash(\n heightOrHash: number | string,\n ): Promise<SPEC.BLOCK_WITH_RECEIPTS> {\n const block = await this.client.getBlockWithReceipts(heightOrHash);\n if (!isFinalizedBlock(block)) {\n throw `Block ${block} is not a fulfilled block, its parent is ${block.parent_hash}`;\n }\n return block;\n }\n\n async fetchBlock(blockNumber: number): Promise<IBlock<StarknetBlock>> {\n try {\n const rawBlock = await this.getBlockByHeightOrHash(blockNumber);\n const formattedBlock = formatBlock(rawBlock);\n\n const formattedTransactions = rawBlock.transactions.map((tx, index) => {\n const formattedTransaction = formatTransaction(\n tx,\n formattedBlock,\n index,\n );\n return {\n ...formattedTransaction,\n logs: tx.receipt.events.map((l, logIndex) =>\n formatLog(l, logIndex, formattedTransaction, formattedBlock),\n ),\n };\n });\n\n const logs: StarknetLog[] = formattedTransactions.flatMap((tx) =>\n tx.logs.map((l) => ({\n ...l,\n transaction: tx,\n })),\n );\n\n const block: StarknetBlock = {\n ...formattedBlock,\n transactions: formattedTransactions,\n logs,\n };\n\n this.eventEmitter.emit('fetchBlock');\n return formatBlockUtil(block);\n } catch (e: any) {\n throw this.handleError(e);\n }\n }\n\n private async fetchLightBlock(\n blockNumber: number,\n ): Promise<IBlock<LightStarknetBlock>> {\n const block = (await this.client.getBlockWithTxHashes(\n blockNumber,\n )) as SPEC.BLOCK_WITH_TX_HASHES;\n const lightBlock: LightStarknetBlock = {\n ...block,\n blockHash: block.block_hash,\n blockNumber: block.block_number,\n parentHash: block.parent_hash,\n newRoot: block.new_root,\n sequencerAddress: block.sequencer_address,\n l1GasPrice: block.l1_gas_price,\n starknetVersion: block.starknet_version,\n logs: [],\n };\n return formatBlockUtil<LightStarknetBlock>(lightBlock);\n }\n\n async fetchBlocks(bufferBlocks: number[]): Promise<IBlock<StarknetBlock>[]> {\n return Promise.all(bufferBlocks.map(async (num) => this.fetchBlock(num)));\n }\n\n async fetchBlocksLight(\n bufferBlocks: number[],\n ): Promise<IBlock<LightStarknetBlock>[]> {\n return Promise.all(\n bufferBlocks.map(async (num) => this.fetchLightBlock(num)),\n );\n }\n\n get api(): RpcProvider {\n return this.client;\n }\n\n private buildInterface(abiName: string, assets: Record<string, string>): Abi {\n if (!assets[abiName]) {\n throw new Error(`ABI named \"${abiName}\" not referenced in assets`);\n }\n\n // This assumes that all datasources have a different abi name or they are the same abi\n if (!this.contractInterfaces[abiName]) {\n // Constructing the interface validates the ABI\n try {\n const abiObj = JSON.parse(assets[abiName]);\n\n this.contractInterfaces[abiName] = abiObj;\n } catch (e: any) {\n logger.error(`Unable to parse ABI: ${e.message}`);\n throw new Error('ABI is invalid');\n }\n }\n\n return this.contractInterfaces[abiName];\n }\n\n async parseLog<T extends StarknetResult = StarknetResult>(\n log: StarknetLog,\n ds: StarknetRuntimeDatasource,\n ): Promise<StarknetLog | StarknetLog<T>> {\n try {\n if (!ds?.options?.abi) {\n logger.warn('No ABI provided for datasource');\n return log;\n }\n const emittedEvent = reverseToRawLog(log);\n const assets = await loadAssets(ds);\n const iAbi = this.buildInterface(ds.options.abi, assets);\n const abiEvents = events.getAbiEvents(iAbi);\n const abiStructs = CallData.getAbiStruct(iAbi);\n const abiEnums = CallData.getAbiEnum(iAbi);\n const [parsed] = events.parseEvents(\n [emittedEvent],\n abiEvents,\n abiStructs,\n abiEnums,\n );\n log.args = parsed as T;\n return log;\n } catch (e: any) {\n logger.warn(`Failed to parse log data: ${e.message}`);\n return log;\n }\n }\n\n async parseTransaction<T extends StarknetResult = StarknetResult>(\n transaction: StarknetTransaction,\n ds: StarknetRuntimeDatasource,\n ): Promise<StarknetTransaction> {\n try {\n const assets = await loadAssets(ds);\n // If decoded calls not exist, try to parse first\n if (!transaction.decodedCalls) {\n transaction.decodedCalls = transaction.parseCallData();\n }\n if (transaction.decodedCalls && transaction.decodedCalls.length > 0) {\n await this.handleDecodedCallsArgs(transaction.decodedCalls, ds, assets);\n } else {\n logger.warn(\n `No decoded calls found in transaction, will skip decode call data for this transaction ${transaction.hash}`,\n );\n }\n transaction.logs =\n transaction.logs &&\n ((await Promise.all(\n transaction.logs.map(async (log) => this.parseLog(log, ds)),\n )) as Array<StarknetLog | StarknetLog<T>>);\n\n return transaction;\n } catch (e: any) {\n logger.warn(`Failed to parse transaction data: ${e.message}`);\n return transaction;\n }\n }\n\n private async handleDecodedCallsArgs(\n decodedCalls: StarknetContractCall[],\n ds: StarknetRuntimeDatasource,\n assets: Record<string, string>,\n ): Promise<void> {\n await Promise.all(\n decodedCalls.map(async (call) => {\n let iAbi: Abi;\n try {\n if (\n ds.options?.address &&\n hexEq(ds.options.address, call.to) &&\n ds.options.abi\n ) {\n iAbi = this.buildInterface(ds.options.abi, assets);\n } else {\n //We could register this abi in memory improve performance, maybe just record with address instead of abi name here\n if (!this.contractInterfaces[call.to]) {\n iAbi = await fetchAbiFromContractAddress(this.client, call.to);\n } else {\n iAbi = this.contractInterfaces[call.to];\n }\n }\n call.decodedArgs = StarknetApi.DecodeCallDataWithAbi(iAbi, call);\n } catch (e: any) {\n logger.warn(\n `Could not decode call data with contract address ${call.to}: ${e.message}`,\n );\n }\n }),\n );\n }\n\n static DecodeCallDataWithAbi(iAbi: Abi, call: StarknetContractCall): any {\n const callData = new CallData(iAbi);\n const { inputs } = callData.parser\n .getLegacyFormat()\n .find(\n (abiItem: AbiEntry) =>\n encodeSelectorToHex(abiItem.name) === call.selector,\n ) as FunctionAbi;\n const inputsTypes = inputs.map((inp: any) => {\n return inp.type as string;\n });\n const res = callData.decodeParameters(inputsTypes, call.calldata);\n const result = inputs.reduce((acc, item, index) => {\n acc[item.name] = res[index];\n return acc;\n }, {});\n return result;\n }\n\n // eslint-disable-next-line @typescript-eslint/require-await\n async connect(): Promise<void> {\n logger.error('Starknet API connect is not implemented');\n throw new Error('Not implemented');\n }\n\n //TODO\n async disconnect(): Promise<void> {\n return Promise.resolve();\n }\n\n handleError(e: Error): Error {\n if ((e as any)?.status === 429) {\n const { hostname } = new URL(this.endpoint);\n return new Error(`Rate Limited at endpoint: ${hostname}`);\n }\n\n return e;\n }\n\n getSafeApi(height: number) {\n return new SafeStarknetProvider(this.client, height);\n }\n}\n"]}
|
|
@@ -47,6 +47,13 @@ describe('Api.starknet', () => {
|
|
|
47
47
|
await strkApi.init();
|
|
48
48
|
blockData = await fetchBlock(979358);
|
|
49
49
|
});
|
|
50
|
+
it('should get finalized block and best block', async () => {
|
|
51
|
+
const finalized = await strkApi.getFinalizedBlock();
|
|
52
|
+
const best = await strkApi.getBestBlockHeight();
|
|
53
|
+
expect(finalized).toBeDefined();
|
|
54
|
+
expect(best).toBeDefined();
|
|
55
|
+
expect(best).toBeGreaterThan(finalized.block_number);
|
|
56
|
+
});
|
|
50
57
|
it('should get finalized block', async () => {
|
|
51
58
|
const finalized = await strkApi.getFinalizedBlock();
|
|
52
59
|
expect(finalized).toBeDefined();
|
|
@@ -57,13 +64,13 @@ describe('Api.starknet', () => {
|
|
|
57
64
|
expect(typeof blockData.logs[0].transaction.transactionIndex).toBe('number');
|
|
58
65
|
expect(blockData.logs[0].transaction.calldata.length).toBeGreaterThan(1);
|
|
59
66
|
});
|
|
60
|
-
it('should have the ability to get receipts via transactions from all types',
|
|
61
|
-
expect(
|
|
62
|
-
expect(typeof blockData.transactions[0].receipt).toEqual('
|
|
63
|
-
expect(typeof blockData.logs[0].transaction.receipt).toEqual('
|
|
67
|
+
it('should have the ability to get receipts via transactions from all types', () => {
|
|
68
|
+
expect(blockData.transactions[0].receipt).toBeDefined();
|
|
69
|
+
expect(typeof blockData.transactions[0].receipt).toEqual('object');
|
|
70
|
+
expect(typeof blockData.logs[0].transaction.receipt).toEqual('object');
|
|
64
71
|
expect(typeof blockData.logs[0].transaction.from).toEqual('string');
|
|
65
72
|
expect(typeof blockData.transactions[1].logs[0].transaction.from).toEqual('string');
|
|
66
|
-
expect(typeof blockData.transactions[1].logs[0].transaction.receipt).toEqual('
|
|
73
|
+
expect(typeof blockData.transactions[1].logs[0].transaction.receipt).toEqual('object');
|
|
67
74
|
});
|
|
68
75
|
//https://starkscan.co/tx/0x0153a20567e66728f3c4ba60913a6011b9c73db9ea4d960e959923ed5afd8a24
|
|
69
76
|
it('Decode logs', async () => {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"api.starknet.test.js","sourceRoot":"","sources":["../../src/starknet/api.starknet.test.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright 2020-2024 SubQuery Pte Ltd authors & contributors\n// SPDX-License-Identifier: GPL-3.0\n\nimport path from 'path';\nimport { EventEmitter2 } from '@nestjs/event-emitter';\nimport {\n StarknetBlock,\n StarknetContractCall,\n StarknetDatasourceKind,\n StarknetHandlerKind,\n StarknetRuntimeDatasource,\n} from '@subql/types-starknet';\nimport { StarknetApi } from './api.starknet';\nimport { isFullBlock } from './block.starknet';\n\n// Add api key to work\nconst HTTP_ENDPOINT = 'https://starknet-mainnet.public.blastapi.io/rpc/v0_7';\n\nconst ds: StarknetRuntimeDatasource = {\n mapping: {\n file: '',\n handlers: [\n {\n handler: 'test',\n kind: StarknetHandlerKind.Call,\n filter: { function: 'deposit' },\n },\n ],\n },\n kind: StarknetDatasourceKind.Runtime,\n startBlock: 979358,\n options: {\n abi: 'zkLend',\n address:\n '0x04c0a5193d58f74fbace4b74dcf65481e734ed1714121bdc571da345540efa05',\n },\n assets: new Map([\n ['zkLend', { file: path.join(__dirname, '../../test/zkLend.abi.json') }],\n ]),\n};\n\njest.setTimeout(90000);\ndescribe('Api.starknet', () => {\n let strkApi: StarknetApi;\n const eventEmitter = new EventEmitter2();\n let blockData: StarknetBlock;\n\n const fetchBlock = async (height: number) => {\n const block = await strkApi.fetchBlock(height);\n\n return block.block as StarknetBlock;\n };\n\n beforeEach(async () => {\n strkApi = new StarknetApi(HTTP_ENDPOINT, eventEmitter);\n await strkApi.init();\n blockData = await fetchBlock(979358);\n });\n\n it('should get finalized block', async () => {\n const finalized = await strkApi.getFinalizedBlock();\n expect(finalized).toBeDefined();\n expect(finalized.block_number).toBeGreaterThan(979358);\n });\n\n it('Should format transaction in logs', () => {\n expect(typeof blockData.logs[0].transaction.blockNumber).toBe('number');\n expect(typeof blockData.logs[0].transaction.transactionIndex).toBe(\n 'number',\n );\n expect(blockData.logs[0].transaction.calldata.length).toBeGreaterThan(1);\n });\n\n it('should have the ability to get receipts via transactions from all types', async () => {\n expect(await blockData.transactions[0].receipt?.()).toBeDefined();\n\n expect(typeof blockData.transactions[0].receipt).toEqual('function');\n expect(typeof blockData.logs[0].transaction.receipt).toEqual('function');\n expect(typeof blockData.logs[0].transaction.from).toEqual('string');\n expect(typeof blockData.transactions[1].logs![0].transaction.from).toEqual(\n 'string',\n );\n expect(\n typeof blockData.transactions[1].logs![0].transaction.receipt,\n ).toEqual('function');\n });\n\n //https://starkscan.co/tx/0x0153a20567e66728f3c4ba60913a6011b9c73db9ea4d960e959923ed5afd8a24\n it('Decode logs', async () => {\n const tx = blockData.transactions.find(\n (t) =>\n t.hash ===\n '0x153a20567e66728f3c4ba60913a6011b9c73db9ea4d960e959923ed5afd8a24',\n );\n // const parsedTx = await strkApi.parseTransaction(tx!, ds);\n const parsedLog = await strkApi.parseLog(tx!.logs![5], ds);\n expect(parsedLog.args).toStrictEqual({\n 'zklend::market::Market::Deposit': {\n user: 888570324763985402246768015919558310269514530881625296825528005560714345717n,\n token:\n 2009894490435840142178314390393166646092438090257831307886760648929397478285n,\n face_amount: 2100000000000000000000n,\n },\n block_hash:\n '0x20dda386e8cb1da79a94716bca62e704b8664a13674d9bf4805d05125755a4a',\n block_number: 979358,\n transaction_hash:\n '0x153a20567e66728f3c4ba60913a6011b9c73db9ea4d960e959923ed5afd8a24',\n });\n });\n\n //https://starkscan.co/tx/0x0153a20567e66728f3c4ba60913a6011b9c73db9ea4d960e959923ed5afd8a24\n it('Decode invoke v3 function type transaction calldata with contract abi (local and remote)', async () => {\n const tx = blockData.transactions.find(\n (t) =>\n t.hash ===\n '0x153a20567e66728f3c4ba60913a6011b9c73db9ea4d960e959923ed5afd8a24',\n );\n // Expect before parse (or been passed a filter), decodedCalls is undefined\n expect(tx!.decodedCalls).toBeUndefined();\n const parsedTransaction = await strkApi.parseTransaction(tx!, ds);\n expect(\n parsedTransaction.decodedCalls as StarknetContractCall<{\n amount: bigint;\n spender: bigint;\n }>[],\n ).toStrictEqual([\n {\n calldata: [\n '0x4c0a5193d58f74fbace4b74dcf65481e734ed1714121bdc571da345540efa05',\n '0x71d75ab9b920500000',\n '0x0',\n ],\n decodedArgs: {\n amount: 2100000000000000000000n,\n spender:\n 2149625499377050772775701191274921578103398273298955620360611655307104287237n,\n },\n selector:\n '0x219209e083275171774dab1df80982e9df2096516f06319c5c6d71ae0a8480c',\n to: '0x4718f5a0fc34cc1af16a1cdee98ffb20c31f5cd61d6ab07201858f4287c938d',\n },\n {\n calldata: [\n '0x4718f5a0fc34cc1af16a1cdee98ffb20c31f5cd61d6ab07201858f4287c938d',\n '0x71d75ab9b920500000',\n ],\n decodedArgs: {\n amount: 2100000000000000000000n,\n token:\n 2009894490435840142178314390393166646092438090257831307886760648929397478285n,\n },\n selector:\n '0xc73f681176fc7b3f9693986fd7b14581e8d540519e27400e88b8713932be01',\n to: '0x4c0a5193d58f74fbace4b74dcf65481e734ed1714121bdc571da345540efa05',\n },\n ]);\n });\n\n //https://starkscan.co/tx/0x043ce8e6e2ad703a81701f85ce26a8fb32ad54cc2fac7685ed0b1367a4813ade\n it('Decode L1 transaction calldata, and decode with remote abi', async () => {\n const blockData = await fetchBlock(981920);\n const tx = blockData.transactions.find(\n (t) =>\n t.hash ===\n '0x43ce8e6e2ad703a81701f85ce26a8fb32ad54cc2fac7685ed0b1367a4813ade',\n );\n const parsedTransaction = await strkApi.parseTransaction(tx!, ds);\n expect(parsedTransaction.decodedCalls).toStrictEqual([\n {\n calldata: [\n '0xae0ee0a63a2ce6baeeffe56e7714fb4efe48d419',\n '0x455448',\n '0x1c7edb66155e3c72b27e6165d7a1912ec97a1286',\n '0x296a93b1c3672a6093de21df2f7b665e0907abc97868e9bf52d6fea07921591',\n '0x13883834c2e180b5',\n '0x0',\n ],\n decodedArgs: {\n amount: 1407436682812293301n,\n depositor: 162680747805905936472113782182998614066721329798n,\n from_address: 993696174272377493693496825928908586134624850969n,\n l1_token: 4543560n,\n l2_recipient:\n 1170820745623894104757945010321258484362311313101582454359316155358757655953n,\n },\n selector:\n '0x1b64b1b3b690b43b9b514fb81377518f4039cd3e4f4914d8a6bdf01d679fb19',\n to: '0x73314940630fd6dcda0d772d4c972c4e0a9946bef9dabf4ef84eda8ef542b82',\n },\n ]);\n });\n\n it('Should not include decodedArgs if decode failed', async () => {\n // TODO, not sure how to test this yet when remote abi always available\n });\n\n it('Should able to check is fullBlock', async () => {\n // block with transactions\n const lightBlock = (await (strkApi as any).fetchLightBlock(500000)).block;\n expect(isFullBlock(blockData)).toBeTruthy();\n expect(isFullBlock(lightBlock)).toBeFalsy();\n });\n});\n"]}
|
|
1
|
+
{"version":3,"file":"api.starknet.test.js","sourceRoot":"","sources":["../../src/starknet/api.starknet.test.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright 2020-2024 SubQuery Pte Ltd authors & contributors\n// SPDX-License-Identifier: GPL-3.0\n\nimport path from 'path';\nimport { EventEmitter2 } from '@nestjs/event-emitter';\nimport {\n StarknetBlock,\n StarknetContractCall,\n StarknetDatasourceKind,\n StarknetHandlerKind,\n StarknetRuntimeDatasource,\n} from '@subql/types-starknet';\nimport { StarknetApi } from './api.starknet';\nimport { isFullBlock } from './block.starknet';\n\n// Add api key to work\nconst HTTP_ENDPOINT = 'https://starknet-mainnet.public.blastapi.io/rpc/v0_7';\n\nconst ds: StarknetRuntimeDatasource = {\n mapping: {\n file: '',\n handlers: [\n {\n handler: 'test',\n kind: StarknetHandlerKind.Call,\n filter: { function: 'deposit' },\n },\n ],\n },\n kind: StarknetDatasourceKind.Runtime,\n startBlock: 979358,\n options: {\n abi: 'zkLend',\n address:\n '0x04c0a5193d58f74fbace4b74dcf65481e734ed1714121bdc571da345540efa05',\n },\n assets: new Map([\n ['zkLend', { file: path.join(__dirname, '../../test/zkLend.abi.json') }],\n ]),\n};\n\njest.setTimeout(90000);\ndescribe('Api.starknet', () => {\n let strkApi: StarknetApi;\n const eventEmitter = new EventEmitter2();\n let blockData: StarknetBlock;\n\n const fetchBlock = async (height: number) => {\n const block = await strkApi.fetchBlock(height);\n\n return block.block as StarknetBlock;\n };\n\n beforeEach(async () => {\n strkApi = new StarknetApi(HTTP_ENDPOINT, eventEmitter);\n await strkApi.init();\n blockData = await fetchBlock(979358);\n });\n\n it('should get finalized block and best block', async () => {\n const finalized = await strkApi.getFinalizedBlock();\n const best = await strkApi.getBestBlockHeight();\n\n expect(finalized).toBeDefined();\n expect(best).toBeDefined();\n\n expect(best).toBeGreaterThan(finalized.block_number);\n });\n\n it('should get finalized block', async () => {\n const finalized = await strkApi.getFinalizedBlock();\n expect(finalized).toBeDefined();\n expect(finalized.block_number).toBeGreaterThan(979358);\n });\n\n it('Should format transaction in logs', () => {\n expect(typeof blockData.logs[0].transaction.blockNumber).toBe('number');\n expect(typeof blockData.logs[0].transaction.transactionIndex).toBe(\n 'number',\n );\n expect(blockData.logs[0].transaction.calldata.length).toBeGreaterThan(1);\n });\n\n it('should have the ability to get receipts via transactions from all types', () => {\n expect(blockData.transactions[0].receipt).toBeDefined();\n\n expect(typeof blockData.transactions[0].receipt).toEqual('object');\n expect(typeof blockData.logs[0].transaction.receipt).toEqual('object');\n expect(typeof blockData.logs[0].transaction.from).toEqual('string');\n expect(typeof blockData.transactions[1].logs![0].transaction.from).toEqual(\n 'string',\n );\n expect(\n typeof blockData.transactions[1].logs![0].transaction.receipt,\n ).toEqual('object');\n });\n\n //https://starkscan.co/tx/0x0153a20567e66728f3c4ba60913a6011b9c73db9ea4d960e959923ed5afd8a24\n it('Decode logs', async () => {\n const tx = blockData.transactions.find(\n (t) =>\n t.hash ===\n '0x153a20567e66728f3c4ba60913a6011b9c73db9ea4d960e959923ed5afd8a24',\n );\n // const parsedTx = await strkApi.parseTransaction(tx!, ds);\n const parsedLog = await strkApi.parseLog(tx!.logs![5], ds);\n expect(parsedLog.args).toStrictEqual({\n 'zklend::market::Market::Deposit': {\n user: 888570324763985402246768015919558310269514530881625296825528005560714345717n,\n token:\n 2009894490435840142178314390393166646092438090257831307886760648929397478285n,\n face_amount: 2100000000000000000000n,\n },\n block_hash:\n '0x20dda386e8cb1da79a94716bca62e704b8664a13674d9bf4805d05125755a4a',\n block_number: 979358,\n transaction_hash:\n '0x153a20567e66728f3c4ba60913a6011b9c73db9ea4d960e959923ed5afd8a24',\n });\n });\n\n //https://starkscan.co/tx/0x0153a20567e66728f3c4ba60913a6011b9c73db9ea4d960e959923ed5afd8a24\n it('Decode invoke v3 function type transaction calldata with contract abi (local and remote)', async () => {\n const tx = blockData.transactions.find(\n (t) =>\n t.hash ===\n '0x153a20567e66728f3c4ba60913a6011b9c73db9ea4d960e959923ed5afd8a24',\n );\n // Expect before parse (or been passed a filter), decodedCalls is undefined\n expect(tx!.decodedCalls).toBeUndefined();\n const parsedTransaction = await strkApi.parseTransaction(tx!, ds);\n expect(\n parsedTransaction.decodedCalls as StarknetContractCall<{\n amount: bigint;\n spender: bigint;\n }>[],\n ).toStrictEqual([\n {\n calldata: [\n '0x4c0a5193d58f74fbace4b74dcf65481e734ed1714121bdc571da345540efa05',\n '0x71d75ab9b920500000',\n '0x0',\n ],\n decodedArgs: {\n amount: 2100000000000000000000n,\n spender:\n 2149625499377050772775701191274921578103398273298955620360611655307104287237n,\n },\n selector:\n '0x219209e083275171774dab1df80982e9df2096516f06319c5c6d71ae0a8480c',\n to: '0x4718f5a0fc34cc1af16a1cdee98ffb20c31f5cd61d6ab07201858f4287c938d',\n },\n {\n calldata: [\n '0x4718f5a0fc34cc1af16a1cdee98ffb20c31f5cd61d6ab07201858f4287c938d',\n '0x71d75ab9b920500000',\n ],\n decodedArgs: {\n amount: 2100000000000000000000n,\n token:\n 2009894490435840142178314390393166646092438090257831307886760648929397478285n,\n },\n selector:\n '0xc73f681176fc7b3f9693986fd7b14581e8d540519e27400e88b8713932be01',\n to: '0x4c0a5193d58f74fbace4b74dcf65481e734ed1714121bdc571da345540efa05',\n },\n ]);\n });\n\n //https://starkscan.co/tx/0x043ce8e6e2ad703a81701f85ce26a8fb32ad54cc2fac7685ed0b1367a4813ade\n it('Decode L1 transaction calldata, and decode with remote abi', async () => {\n const blockData = await fetchBlock(981920);\n const tx = blockData.transactions.find(\n (t) =>\n t.hash ===\n '0x43ce8e6e2ad703a81701f85ce26a8fb32ad54cc2fac7685ed0b1367a4813ade',\n );\n const parsedTransaction = await strkApi.parseTransaction(tx!, ds);\n expect(parsedTransaction.decodedCalls).toStrictEqual([\n {\n calldata: [\n '0xae0ee0a63a2ce6baeeffe56e7714fb4efe48d419',\n '0x455448',\n '0x1c7edb66155e3c72b27e6165d7a1912ec97a1286',\n '0x296a93b1c3672a6093de21df2f7b665e0907abc97868e9bf52d6fea07921591',\n '0x13883834c2e180b5',\n '0x0',\n ],\n decodedArgs: {\n amount: 1407436682812293301n,\n depositor: 162680747805905936472113782182998614066721329798n,\n from_address: 993696174272377493693496825928908586134624850969n,\n l1_token: 4543560n,\n l2_recipient:\n 1170820745623894104757945010321258484362311313101582454359316155358757655953n,\n },\n selector:\n '0x1b64b1b3b690b43b9b514fb81377518f4039cd3e4f4914d8a6bdf01d679fb19',\n to: '0x73314940630fd6dcda0d772d4c972c4e0a9946bef9dabf4ef84eda8ef542b82',\n },\n ]);\n });\n\n it('Should not include decodedArgs if decode failed', async () => {\n // TODO, not sure how to test this yet when remote abi always available\n });\n\n it('Should able to check is fullBlock', async () => {\n // block with transactions\n const lightBlock = (await (strkApi as any).fetchLightBlock(500000)).block;\n expect(isFullBlock(blockData)).toBeTruthy();\n expect(isFullBlock(lightBlock)).toBeFalsy();\n });\n});\n"]}
|
|
@@ -50,10 +50,14 @@ function filterTransactionsProcessor(transaction, filter, address) {
|
|
|
50
50
|
}
|
|
51
51
|
// Only decode calls lazily if filter applies
|
|
52
52
|
const decodedCalls = transaction.parseCallData();
|
|
53
|
+
const func = filter.function;
|
|
54
|
+
const to = filter.to;
|
|
53
55
|
if (decodedCalls && decodedCalls?.length !== 0) {
|
|
54
|
-
if (
|
|
55
|
-
const index = decodedCalls?.findIndex((call) =>
|
|
56
|
-
|
|
56
|
+
if (func !== undefined) {
|
|
57
|
+
const index = decodedCalls?.findIndex((call) => func === null
|
|
58
|
+
? call.selector === null
|
|
59
|
+
: (0, utils_starknet_1.hexEq)(call.selector, func) ||
|
|
60
|
+
(0, utils_starknet_1.hexEq)(call.selector, (0, utils_starknet_1.encodeSelectorToHex)(func)));
|
|
57
61
|
if (index === -1) {
|
|
58
62
|
return false;
|
|
59
63
|
}
|
|
@@ -63,10 +67,13 @@ function filterTransactionsProcessor(transaction, filter, address) {
|
|
|
63
67
|
}
|
|
64
68
|
// do not return true here
|
|
65
69
|
}
|
|
66
|
-
if (
|
|
67
|
-
//
|
|
68
|
-
|
|
69
|
-
const
|
|
70
|
+
if (to !== undefined || address) {
|
|
71
|
+
// If filter.to is undefined, we use address as filter
|
|
72
|
+
// We also handle when filter.to is null
|
|
73
|
+
const filterAddress = to !== undefined ? to : address;
|
|
74
|
+
const index = decodedCalls?.findIndex((call) => filterAddress === null
|
|
75
|
+
? call.to === null
|
|
76
|
+
: filterAddress && (0, utils_starknet_1.hexEq)(call.to, filterAddress));
|
|
70
77
|
if (index === -1) {
|
|
71
78
|
return false;
|
|
72
79
|
}
|
|
@@ -77,15 +84,16 @@ function filterTransactionsProcessor(transaction, filter, address) {
|
|
|
77
84
|
}
|
|
78
85
|
// In case decode calls failed, we try to look into raw calldata
|
|
79
86
|
else {
|
|
80
|
-
if (
|
|
81
|
-
const index = transaction.calldata?.findIndex((call) =>
|
|
82
|
-
call ===
|
|
87
|
+
if (func !== undefined) {
|
|
88
|
+
const index = transaction.calldata?.findIndex((call) => func === null
|
|
89
|
+
? call === null
|
|
90
|
+
: call === func || call === (0, utils_starknet_1.encodeSelectorToHex)(func));
|
|
83
91
|
if (index === -1) {
|
|
84
92
|
return false;
|
|
85
93
|
}
|
|
86
94
|
}
|
|
87
|
-
if (
|
|
88
|
-
const index = transaction.calldata?.findIndex((call) => (0, utils_starknet_1.hexEq)(call,
|
|
95
|
+
if (to !== undefined) {
|
|
96
|
+
const index = transaction.calldata?.findIndex((call) => to === null ? call === null : (0, utils_starknet_1.hexEq)(call, to));
|
|
89
97
|
if (index === -1) {
|
|
90
98
|
return false;
|
|
91
99
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"block.starknet.js","sourceRoot":"","sources":["../../src/starknet/block.starknet.ts"],"names":[],"mappings":";AAAA,8DAA8D;AAC9D,mCAAmC;;AAenC,sDAkBC;AAGD,
|
|
1
|
+
{"version":3,"file":"block.starknet.js","sourceRoot":"","sources":["../../src/starknet/block.starknet.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright 2020-2024 SubQuery Pte Ltd authors & contributors\n// SPDX-License-Identifier: GPL-3.0\n\nimport { filterBlockTimestamp } from '@subql/node-core';\nimport {\n StarknetBlock,\n StarknetTransactionFilter,\n StarknetLog,\n StarknetLogFilter,\n StarknetBlockFilter,\n StarknetTransaction,\n} from '@subql/types-starknet';\nimport { SubqlProjectBlockFilter } from '../configure/SubqueryProject';\nimport { BlockContent } from '../indexer/types';\nimport { hexEq, encodeSelectorToHex, encodeEventKey } from './utils.starknet';\n\nexport function filterBlocksProcessor(\n block: StarknetBlock,\n filter: StarknetBlockFilter,\n address?: string,\n): boolean {\n if (filter?.modulo && block.blockNumber % filter.modulo !== 0) {\n return false;\n }\n // Multiply to add MS\n if (\n !filterBlockTimestamp(\n Number(block.timestamp) * 1000,\n filter as SubqlProjectBlockFilter,\n )\n ) {\n return false;\n }\n return true;\n}\n\n/* eslint-disable-next-line complexity */\nexport function filterTransactionsProcessor(\n transaction: StarknetTransaction,\n filter?: StarknetTransactionFilter,\n address?: string,\n): boolean {\n if (!filter) return true;\n\n if (filter.type && filter.type !== transaction.type) {\n return false;\n }\n\n // L1 or INVOKE V0 contract type\n if (transaction.contractAddress) {\n if (\n transaction.contractAddress &&\n address &&\n !hexEq(address, transaction.contractAddress)\n ) {\n return false;\n }\n if (filter.to && !hexEq(filter.to, transaction.contractAddress)) {\n return false;\n }\n }\n if (transaction.entryPointSelector && filter.function) {\n if (\n !hexEq(transaction.entryPointSelector, filter.function) ||\n !hexEq(\n transaction.entryPointSelector,\n encodeSelectorToHex(filter.function),\n )\n ) {\n return false;\n }\n }\n // INVOKE contract type\n if (\n transaction.from &&\n filter.from &&\n !hexEq(transaction.from, filter.from)\n ) {\n return false;\n }\n\n // Only decode calls lazily if filter applies\n const decodedCalls = transaction.parseCallData();\n const func = filter.function;\n const to = filter.to;\n\n if (decodedCalls && decodedCalls?.length !== 0) {\n if (func !== undefined) {\n const index = decodedCalls?.findIndex((call) =>\n func === null\n ? call.selector === null\n : hexEq(call.selector, func) ||\n hexEq(call.selector, encodeSelectorToHex(func)),\n );\n if (index === -1) {\n return false;\n } else {\n // Only filtered calls are stored, reduce memory usage\n transaction.decodedCalls = decodedCalls;\n }\n // do not return true here\n }\n if (to !== undefined || address) {\n // If filter.to is undefined, we use address as filter\n // We also handle when filter.to is null\n const filterAddress = to !== undefined ? to : address;\n const index = decodedCalls?.findIndex((call) =>\n filterAddress === null\n ? call.to === null\n : filterAddress && hexEq(call.to, filterAddress),\n );\n if (index === -1) {\n return false;\n } else {\n transaction.decodedCalls = decodedCalls;\n }\n }\n }\n // In case decode calls failed, we try to look into raw calldata\n else {\n if (func !== undefined) {\n const index = transaction.calldata?.findIndex((call) =>\n func === null\n ? call === null\n : call === func || call === encodeSelectorToHex(func),\n );\n if (index === -1) {\n return false;\n }\n }\n if (to !== undefined) {\n const index = transaction.calldata?.findIndex((call) =>\n to === null ? call === null : hexEq(call, to),\n );\n if (index === -1) {\n return false;\n }\n }\n }\n return true;\n}\n\nexport function filterLogsProcessor(\n log: StarknetLog,\n filter: StarknetLogFilter,\n address?: string,\n): boolean {\n if (address && !hexEq(address, log.address)) {\n return false;\n }\n if (!filter) return true;\n if (\n filter.topics?.length &&\n log.topics?.length &&\n topicsHaveNoCommonElements(filter.topics, log.topics)\n ) {\n return false;\n }\n return true;\n}\n\n// check two topics/keys have NO element in common\nfunction topicsHaveNoCommonElements(array1, array2) {\n for (const item1 of array1) {\n for (const item2 of array2) {\n if (\n hexEq(item1, item2) ||\n hexEq(item1, encodeEventKey(item2)) ||\n hexEq(item2, encodeEventKey(item1))\n ) {\n return false;\n }\n }\n }\n return true;\n}\n\nexport function isFullBlock(block: BlockContent): block is StarknetBlock {\n if ((block as any).transactions.length) {\n return (block as any).transactions[0].type;\n }\n return false;\n}\n"]}
|
|
@@ -11,7 +11,6 @@ jest.setTimeout(100000);
|
|
|
11
11
|
describe('block filters', () => {
|
|
12
12
|
let strkApi;
|
|
13
13
|
const eventEmitter = new event_emitter_1.EventEmitter2();
|
|
14
|
-
let blockData;
|
|
15
14
|
const fetchBlock = async (height) => {
|
|
16
15
|
const block = await strkApi.fetchBlock(height);
|
|
17
16
|
return block.block;
|
|
@@ -54,6 +53,42 @@ describe('block filters', () => {
|
|
|
54
53
|
expect((0, block_starknet_1.filterTransactionsProcessor)(tx, {
|
|
55
54
|
to: '0x047aaaaad',
|
|
56
55
|
})).toBeFalsy();
|
|
56
|
+
//Filter with function is "null"
|
|
57
|
+
expect((0, block_starknet_1.filterTransactionsProcessor)(tx, {
|
|
58
|
+
function: null,
|
|
59
|
+
})).toBeFalsy();
|
|
60
|
+
//Filter with to is "null"
|
|
61
|
+
expect((0, block_starknet_1.filterTransactionsProcessor)(tx, {
|
|
62
|
+
to: null,
|
|
63
|
+
})).toBeFalsy();
|
|
64
|
+
});
|
|
65
|
+
it('filter with tx function or to is null', () => {
|
|
66
|
+
const mockTx1 = {
|
|
67
|
+
calldata: ['0xmock', null],
|
|
68
|
+
parseCallData: jest.fn(),
|
|
69
|
+
};
|
|
70
|
+
//Filter with function is "null"
|
|
71
|
+
expect((0, block_starknet_1.filterTransactionsProcessor)(mockTx1, {
|
|
72
|
+
function: null,
|
|
73
|
+
})).toBeTruthy();
|
|
74
|
+
//Filter with to is "null"
|
|
75
|
+
expect((0, block_starknet_1.filterTransactionsProcessor)(mockTx1, {
|
|
76
|
+
to: null,
|
|
77
|
+
})).toBeTruthy();
|
|
78
|
+
// test with decode calls
|
|
79
|
+
const mockTx2 = {
|
|
80
|
+
parseCallData: () => {
|
|
81
|
+
return [{ to: null, selector: null, calldata: [] }];
|
|
82
|
+
},
|
|
83
|
+
};
|
|
84
|
+
//Filter with function is "null"
|
|
85
|
+
expect((0, block_starknet_1.filterTransactionsProcessor)(mockTx2, {
|
|
86
|
+
function: null,
|
|
87
|
+
})).toBeTruthy();
|
|
88
|
+
//Filter with to is "null"
|
|
89
|
+
expect((0, block_starknet_1.filterTransactionsProcessor)(mockTx2, {
|
|
90
|
+
to: null,
|
|
91
|
+
})).toBeTruthy();
|
|
57
92
|
});
|
|
58
93
|
it('should filter tx with multiple conditions', async () => {
|
|
59
94
|
const block_997058 = await fetchBlock(997058);
|