@subql/node-solana 6.0.2 → 6.0.3-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.
@@ -36,7 +36,6 @@ let IndexerManager = class IndexerManager extends node_core_1.BaseIndexerManager
36
36
  return this.sandboxService.getDsProcessor(ds, safeApi, this.apiService.api);
37
37
  }
38
38
  async indexBlockData(block, dataSources, getVM) {
39
- // console.time(`Indexed block ${block.blockHeight}`);
40
39
  await this.indexBlockContent(block, dataSources, getVM);
41
40
  for (const tx of block.transactions) {
42
41
  await this.indexTransaction(tx, dataSources, getVM);
@@ -1 +1 @@
1
- {"version":3,"file":"indexer.manager.js","sourceRoot":"","sources":["../../src/indexer/indexer.manager.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright 2020-2025 SubQuery Pte Ltd authors & contributors\n// SPDX-License-Identifier: GPL-3.0\n\nimport { Inject, Injectable } from '@nestjs/common';\nimport {\n isBlockHandlerProcessor,\n isCustomDs,\n isRuntimeDs,\n SubqlSolanaCustomDataSource,\n SubqlSolanaDataSource,\n isInstructionHandlerProcessor,\n isTransactionHandlerProcessor,\n isLogHandlerProcessor,\n} from '@subql/common-solana';\nimport {\n NodeConfig,\n profiler,\n IndexerSandbox,\n ProcessBlockResponse,\n BaseIndexerManager,\n IBlock,\n SandboxService,\n DsProcessorService,\n DynamicDsService,\n UnfinalizedBlocksService,\n} from '@subql/node-core';\nimport {\n SolanaHandlerKind,\n SolanaTransaction,\n SolanaBlock,\n SubqlRuntimeDatasource,\n SolanaBlockFilter,\n SolanaTransactionFilter,\n SolanaInstruction,\n SolanaInstructionFilter,\n SolanaRuntimeHandlerInputMap,\n SolanaLogMessage,\n SolanaLogFilter,\n} from '@subql/types-solana';\nimport { groupBy } from 'lodash';\nimport { BlockchainService } from '../blockchain.service';\nimport { SolanaProjectDs } from '../configure/SubqueryProject';\nimport {\n SolanaApi,\n SolanaApiService,\n SolanaDecoder,\n SolanaSafeApi,\n} from '../solana';\nimport {\n filterBlocksProcessor,\n filterInstructionsProcessor,\n filterLogsProcessor,\n filterTransactionsProcessor,\n} from '../solana/utils.solana';\nimport { BlockContent } from './types';\n\n@Injectable()\nexport class IndexerManager extends BaseIndexerManager<\n SolanaApi,\n SolanaSafeApi,\n BlockContent,\n SolanaApiService,\n SubqlSolanaDataSource,\n SubqlSolanaCustomDataSource,\n ReturnType<typeof getFilterTypeMap>,\n typeof ProcessorTypeMap,\n SolanaRuntimeHandlerInputMap\n> {\n protected isRuntimeDs = isRuntimeDs;\n protected isCustomDs = isCustomDs;\n\n constructor(\n @Inject('APIService') apiService: SolanaApiService,\n nodeConfig: NodeConfig,\n sandboxService: SandboxService<SolanaSafeApi, SolanaApi>,\n dsProcessorService: DsProcessorService<\n SubqlSolanaDataSource,\n SubqlSolanaCustomDataSource\n >,\n dynamicDsService: DynamicDsService<SubqlSolanaDataSource>,\n @Inject('IUnfinalizedBlocksService')\n unfinalizedBlocksService: UnfinalizedBlocksService,\n @Inject('IBlockchainService') blockchainService: BlockchainService,\n ) {\n super(\n apiService,\n nodeConfig,\n sandboxService,\n dsProcessorService,\n dynamicDsService,\n unfinalizedBlocksService,\n getFilterTypeMap(apiService.decoder),\n ProcessorTypeMap,\n blockchainService,\n );\n }\n\n @profiler()\n async indexBlock(\n block: IBlock<BlockContent>,\n dataSources: SubqlSolanaDataSource[],\n ): Promise<ProcessBlockResponse> {\n return super.internalIndexBlock(block, dataSources, () =>\n this.blockchainService.getSafeApi(block.block),\n );\n }\n\n protected getDsProcessor(\n ds: SubqlSolanaDataSource,\n safeApi: SolanaSafeApi,\n ): IndexerSandbox {\n return this.sandboxService.getDsProcessor(ds, safeApi, this.apiService.api);\n }\n\n protected async indexBlockData(\n block: BlockContent,\n dataSources: SolanaProjectDs[],\n getVM: (d: SolanaProjectDs) => Promise<IndexerSandbox>,\n ): Promise<void> {\n // console.time(`Indexed block ${block.blockHeight}`);\n await this.indexBlockContent(block, dataSources, getVM);\n\n for (const tx of block.transactions) {\n await this.indexTransaction(tx, dataSources, getVM);\n\n // There is probably only one item per group but that could change based on the data structure\n const innerInstructions = groupBy(\n tx.meta?.innerInstructions,\n (inner) => inner.index,\n );\n\n for (const [idx, instruction] of Object.entries(\n tx.transaction.message.instructions ?? [],\n )) {\n await this.indexInstruction(instruction, dataSources, getVM);\n\n for (const innerInstrutions1 of innerInstructions[idx] ?? []) {\n for (const innerInstrution of innerInstrutions1.instructions) {\n await this.indexInstruction(innerInstrution, dataSources, getVM);\n }\n }\n }\n\n for (const log of tx.meta?.logs ?? []) {\n await this.indexLog(log, dataSources, getVM);\n }\n }\n // console.timeEnd(`Indexed block ${block.blockHeight}`);\n }\n\n private async indexBlockContent(\n block: SolanaBlock,\n dataSources: SolanaProjectDs[],\n getVM: (d: SolanaProjectDs) => Promise<IndexerSandbox>,\n ): Promise<void> {\n for (const ds of dataSources) {\n await this.indexData(SolanaHandlerKind.Block, block, ds, getVM);\n }\n }\n\n private async indexTransaction(\n tx: SolanaTransaction,\n dataSources: SolanaProjectDs[],\n getVM: (d: SolanaProjectDs) => Promise<IndexerSandbox>,\n ): Promise<void> {\n for (const ds of dataSources) {\n await this.indexData(SolanaHandlerKind.Transaction, tx, ds, getVM);\n }\n }\n\n private async indexInstruction(\n instruction: SolanaInstruction,\n dataSources: SolanaProjectDs[],\n getVM: (d: SolanaProjectDs) => Promise<IndexerSandbox>,\n ): Promise<void> {\n for (const ds of dataSources) {\n await this.indexData(\n SolanaHandlerKind.Instruction,\n instruction,\n ds,\n getVM,\n );\n }\n }\n\n private async indexLog(\n log: SolanaLogMessage,\n dataSources: SolanaProjectDs[],\n getVM: (d: SolanaProjectDs) => Promise<IndexerSandbox>,\n ): Promise<void> {\n for (const ds of dataSources) {\n await this.indexData(SolanaHandlerKind.Log, log, ds, getVM);\n }\n }\n\n // eslint-disable-next-line @typescript-eslint/require-await\n protected async prepareFilteredData(\n kind: SolanaHandlerKind,\n data: any,\n ds: SubqlRuntimeDatasource,\n ): Promise<any> {\n // Ensure any provided IDLs are available\n await this.apiService.api.decoder.loadIdls(ds);\n\n return DataIDLParser[kind](data);\n }\n}\n\nconst ProcessorTypeMap = {\n [SolanaHandlerKind.Block]: isBlockHandlerProcessor,\n [SolanaHandlerKind.Transaction]: isTransactionHandlerProcessor,\n [SolanaHandlerKind.Instruction]: isInstructionHandlerProcessor,\n [SolanaHandlerKind.Log]: isLogHandlerProcessor,\n};\n\nconst getFilterTypeMap = (decoder: SolanaDecoder) => ({\n [SolanaHandlerKind.Block]: (\n data: SolanaBlock,\n filter: SolanaBlockFilter,\n ds: SubqlSolanaDataSource,\n ) => filterBlocksProcessor(data, filter),\n [SolanaHandlerKind.Transaction]: (\n data: SolanaTransaction,\n filter: SolanaTransactionFilter,\n ds: SubqlSolanaDataSource,\n ) => filterTransactionsProcessor(data, filter),\n [SolanaHandlerKind.Instruction]: (\n data: SolanaInstruction,\n filter: SolanaInstructionFilter,\n ds: SubqlSolanaDataSource,\n ) => filterInstructionsProcessor(data, decoder, filter),\n [SolanaHandlerKind.Log]: (\n data: SolanaLogMessage,\n filter: SolanaLogFilter,\n ds: SubqlSolanaDataSource,\n ) => filterLogsProcessor(data, filter),\n});\n\nconst DataIDLParser = {\n [SolanaHandlerKind.Block]: (data: SolanaBlock) => data,\n [SolanaHandlerKind.Transaction]: (data: SolanaTransaction) => data,\n [SolanaHandlerKind.Instruction]: async (data: SolanaInstruction) => {\n // Preload the decoded data\n await data.decodedData;\n return data;\n },\n [SolanaHandlerKind.Log]: async (data: SolanaLogMessage) => {\n // Preload the decoded data\n await data.decodedMessage;\n return data;\n },\n};\n"]}
1
+ {"version":3,"file":"indexer.manager.js","sourceRoot":"","sources":["../../src/indexer/indexer.manager.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright 2020-2025 SubQuery Pte Ltd authors & contributors\n// SPDX-License-Identifier: GPL-3.0\n\nimport { Inject, Injectable } from '@nestjs/common';\nimport {\n isBlockHandlerProcessor,\n isCustomDs,\n isRuntimeDs,\n SubqlSolanaCustomDataSource,\n SubqlSolanaDataSource,\n isInstructionHandlerProcessor,\n isTransactionHandlerProcessor,\n isLogHandlerProcessor,\n} from '@subql/common-solana';\nimport {\n NodeConfig,\n profiler,\n IndexerSandbox,\n ProcessBlockResponse,\n BaseIndexerManager,\n IBlock,\n SandboxService,\n DsProcessorService,\n DynamicDsService,\n UnfinalizedBlocksService,\n} from '@subql/node-core';\nimport {\n SolanaHandlerKind,\n SolanaTransaction,\n SolanaBlock,\n SubqlRuntimeDatasource,\n SolanaBlockFilter,\n SolanaTransactionFilter,\n SolanaInstruction,\n SolanaInstructionFilter,\n SolanaRuntimeHandlerInputMap,\n SolanaLogMessage,\n SolanaLogFilter,\n} from '@subql/types-solana';\nimport { groupBy } from 'lodash';\nimport { BlockchainService } from '../blockchain.service';\nimport { SolanaProjectDs } from '../configure/SubqueryProject';\nimport {\n SolanaApi,\n SolanaApiService,\n SolanaDecoder,\n SolanaSafeApi,\n} from '../solana';\nimport {\n filterBlocksProcessor,\n filterInstructionsProcessor,\n filterLogsProcessor,\n filterTransactionsProcessor,\n} from '../solana/utils.solana';\nimport { BlockContent } from './types';\n\n@Injectable()\nexport class IndexerManager extends BaseIndexerManager<\n SolanaApi,\n SolanaSafeApi,\n BlockContent,\n SolanaApiService,\n SubqlSolanaDataSource,\n SubqlSolanaCustomDataSource,\n ReturnType<typeof getFilterTypeMap>,\n typeof ProcessorTypeMap,\n SolanaRuntimeHandlerInputMap\n> {\n protected isRuntimeDs = isRuntimeDs;\n protected isCustomDs = isCustomDs;\n\n constructor(\n @Inject('APIService') apiService: SolanaApiService,\n nodeConfig: NodeConfig,\n sandboxService: SandboxService<SolanaSafeApi, SolanaApi>,\n dsProcessorService: DsProcessorService<\n SubqlSolanaDataSource,\n SubqlSolanaCustomDataSource\n >,\n dynamicDsService: DynamicDsService<SubqlSolanaDataSource>,\n @Inject('IUnfinalizedBlocksService')\n unfinalizedBlocksService: UnfinalizedBlocksService,\n @Inject('IBlockchainService') blockchainService: BlockchainService,\n ) {\n super(\n apiService,\n nodeConfig,\n sandboxService,\n dsProcessorService,\n dynamicDsService,\n unfinalizedBlocksService,\n getFilterTypeMap(apiService.decoder),\n ProcessorTypeMap,\n blockchainService,\n );\n }\n\n @profiler()\n async indexBlock(\n block: IBlock<BlockContent>,\n dataSources: SubqlSolanaDataSource[],\n ): Promise<ProcessBlockResponse> {\n return super.internalIndexBlock(block, dataSources, () =>\n this.blockchainService.getSafeApi(block.block),\n );\n }\n\n protected getDsProcessor(\n ds: SubqlSolanaDataSource,\n safeApi: SolanaSafeApi,\n ): IndexerSandbox {\n return this.sandboxService.getDsProcessor(ds, safeApi, this.apiService.api);\n }\n\n protected async indexBlockData(\n block: BlockContent,\n dataSources: SolanaProjectDs[],\n getVM: (d: SolanaProjectDs) => Promise<IndexerSandbox>,\n ): Promise<void> {\n await this.indexBlockContent(block, dataSources, getVM);\n\n for (const tx of block.transactions) {\n await this.indexTransaction(tx, dataSources, getVM);\n\n // There is probably only one item per group but that could change based on the data structure\n const innerInstructions = groupBy(\n tx.meta?.innerInstructions,\n (inner) => inner.index,\n );\n\n for (const [idx, instruction] of Object.entries(\n tx.transaction.message.instructions ?? [],\n )) {\n await this.indexInstruction(instruction, dataSources, getVM);\n\n for (const innerInstrutions1 of innerInstructions[idx] ?? []) {\n for (const innerInstrution of innerInstrutions1.instructions) {\n await this.indexInstruction(innerInstrution, dataSources, getVM);\n }\n }\n }\n\n for (const log of tx.meta?.logs ?? []) {\n await this.indexLog(log, dataSources, getVM);\n }\n }\n // console.timeEnd(`Indexed block ${block.blockHeight}`);\n }\n\n private async indexBlockContent(\n block: SolanaBlock,\n dataSources: SolanaProjectDs[],\n getVM: (d: SolanaProjectDs) => Promise<IndexerSandbox>,\n ): Promise<void> {\n for (const ds of dataSources) {\n await this.indexData(SolanaHandlerKind.Block, block, ds, getVM);\n }\n }\n\n private async indexTransaction(\n tx: SolanaTransaction,\n dataSources: SolanaProjectDs[],\n getVM: (d: SolanaProjectDs) => Promise<IndexerSandbox>,\n ): Promise<void> {\n for (const ds of dataSources) {\n await this.indexData(SolanaHandlerKind.Transaction, tx, ds, getVM);\n }\n }\n\n private async indexInstruction(\n instruction: SolanaInstruction,\n dataSources: SolanaProjectDs[],\n getVM: (d: SolanaProjectDs) => Promise<IndexerSandbox>,\n ): Promise<void> {\n for (const ds of dataSources) {\n await this.indexData(\n SolanaHandlerKind.Instruction,\n instruction,\n ds,\n getVM,\n );\n }\n }\n\n private async indexLog(\n log: SolanaLogMessage,\n dataSources: SolanaProjectDs[],\n getVM: (d: SolanaProjectDs) => Promise<IndexerSandbox>,\n ): Promise<void> {\n for (const ds of dataSources) {\n await this.indexData(SolanaHandlerKind.Log, log, ds, getVM);\n }\n }\n\n // eslint-disable-next-line @typescript-eslint/require-await\n protected async prepareFilteredData(\n kind: SolanaHandlerKind,\n data: any,\n ds: SubqlRuntimeDatasource,\n ): Promise<any> {\n // Ensure any provided IDLs are available\n await this.apiService.api.decoder.loadIdls(ds);\n\n return DataIDLParser[kind](data);\n }\n}\n\nconst ProcessorTypeMap = {\n [SolanaHandlerKind.Block]: isBlockHandlerProcessor,\n [SolanaHandlerKind.Transaction]: isTransactionHandlerProcessor,\n [SolanaHandlerKind.Instruction]: isInstructionHandlerProcessor,\n [SolanaHandlerKind.Log]: isLogHandlerProcessor,\n};\n\nconst getFilterTypeMap = (decoder: SolanaDecoder) => ({\n [SolanaHandlerKind.Block]: (\n data: SolanaBlock,\n filter: SolanaBlockFilter,\n ds: SubqlSolanaDataSource,\n ) => filterBlocksProcessor(data, filter),\n [SolanaHandlerKind.Transaction]: (\n data: SolanaTransaction,\n filter: SolanaTransactionFilter,\n ds: SubqlSolanaDataSource,\n ) => filterTransactionsProcessor(data, filter),\n [SolanaHandlerKind.Instruction]: (\n data: SolanaInstruction,\n filter: SolanaInstructionFilter,\n ds: SubqlSolanaDataSource,\n ) => filterInstructionsProcessor(data, decoder, filter),\n [SolanaHandlerKind.Log]: (\n data: SolanaLogMessage,\n filter: SolanaLogFilter,\n ds: SubqlSolanaDataSource,\n ) => filterLogsProcessor(data, filter),\n});\n\nconst DataIDLParser = {\n [SolanaHandlerKind.Block]: (data: SolanaBlock) => data,\n [SolanaHandlerKind.Transaction]: (data: SolanaTransaction) => data,\n [SolanaHandlerKind.Instruction]: async (data: SolanaInstruction) => {\n // Preload the decoded data\n await data.decodedData;\n return data;\n },\n [SolanaHandlerKind.Log]: async (data: SolanaLogMessage) => {\n // Preload the decoded data\n await data.decodedMessage;\n return data;\n },\n};\n"]}
@@ -13,8 +13,9 @@ describe('Api.solana', () => {
13
13
  let solanaApi;
14
14
  const eventEmitter = new event_emitter_1.EventEmitter2();
15
15
  let block;
16
+ const decoder = new decoder_1.SolanaDecoder();
16
17
  beforeAll(async () => {
17
- solanaApi = await api_solana_1.SolanaApi.create(HTTP_ENDPOINT, eventEmitter, new decoder_1.SolanaDecoder());
18
+ solanaApi = await api_solana_1.SolanaApi.create(HTTP_ENDPOINT, eventEmitter, decoder);
18
19
  // https://solscan.io/block/325922873
19
20
  block = await solanaApi.fetchBlock(325_922_873);
20
21
  }, 20_000);
@@ -176,12 +177,16 @@ describe('Api.solana', () => {
176
177
  const tx = getTxBySig('4V5S9ymSheic34SsHN9AHA86b41qXfA9JwdEra1UUgoNdvWFTMA5ueSCHn6nRTBDphMQFUFLPgU4N2QsG8En3J1d');
177
178
  const inst = tx?.transaction.message.instructions[4];
178
179
  expect(inst).toBeDefined();
180
+ const decodeInst = jest.spyOn(solanaApi.decoder, 'decodeInstruction');
179
181
  expect(() => JSON.stringify(inst)).not.toThrow();
182
+ expect(decodeInst).not.toHaveBeenCalled();
180
183
  });
181
184
  it('can stringify a LogMessage', () => {
182
185
  const tx = getTxBySig('4V5S9ymSheic34SsHN9AHA86b41qXfA9JwdEra1UUgoNdvWFTMA5ueSCHn6nRTBDphMQFUFLPgU4N2QsG8En3J1d');
183
186
  for (const log of tx.meta.logs) {
187
+ const decodeLog = jest.spyOn(solanaApi.decoder, 'decodeLog');
184
188
  expect(() => JSON.stringify(log)).not.toThrow();
189
+ expect(decodeLog).not.toHaveBeenCalled();
185
190
  }
186
191
  });
187
192
  });
@@ -1 +1 @@
1
- {"version":3,"file":"api.solana.spec.js","sourceRoot":"","sources":["../../src/solana/api.solana.spec.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright 2020-2025 SubQuery Pte Ltd authors & contributors\n// SPDX-License-Identifier: GPL-3.0\n\nimport { IdlV01 } from '@codama/nodes-from-anchor';\nimport { EventEmitter2 } from '@nestjs/event-emitter';\nimport { TransactionFilter } from '@subql/common-solana';\nimport { IBlock } from '@subql/node-core';\nimport {\n SolanaBlock,\n SolanaBlockFilter,\n SolanaTransaction,\n} from '@subql/types-solana';\nimport { SolanaApi } from './api.solana';\nimport { SolanaDecoder } from './decoder';\nimport {\n filterBlocksProcessor,\n filterInstructionsProcessor,\n filterLogsProcessor,\n filterTransactionsProcessor,\n} from './utils.solana';\n\n// Add api key to work\nconst HTTP_ENDPOINT =\n process.env.HTTP_ENDPOINT ?? 'https://solana.api.onfinality.io/public';\n\nconst IDL_swap: IdlV01 = require('../../test/swapFpHZwjELNnjvThjajtiVmkz3yPQEHjLtka2fwHW.idl.json');\n\ndescribe('Api.solana', () => {\n let solanaApi: SolanaApi;\n const eventEmitter = new EventEmitter2();\n let block: IBlock<SolanaBlock>;\n\n beforeAll(async () => {\n solanaApi = await SolanaApi.create(\n HTTP_ENDPOINT,\n eventEmitter,\n new SolanaDecoder(),\n );\n // https://solscan.io/block/325922873\n block = await solanaApi.fetchBlock(325_922_873);\n }, 20_000);\n\n function getTxBySig(sig: string): SolanaTransaction {\n const tx = block.block.transactions.find((tx) =>\n tx.transaction.signatures.find((s) => s === sig),\n );\n if (!tx) {\n throw new Error(`Unable to find tx with signature ${sig}`);\n }\n return tx;\n }\n\n it('parses block timestamps correctly', () => {\n expect(block.getHeader().timestamp).toEqual(\n new Date('2025-03-10T22:40:28.000Z'),\n );\n });\n\n describe('Filters', () => {\n it('Should run block filters correctly', () => {\n const moduloBlockFilter: SolanaBlockFilter = {\n modulo: 1,\n };\n expect(\n filterBlocksProcessor(block.block, moduloBlockFilter),\n ).toBeTruthy();\n\n const moduloBlockFilter2: SolanaBlockFilter = {\n modulo: 325_922_870,\n };\n expect(\n filterBlocksProcessor(block.block, moduloBlockFilter2),\n ).toBeFalsy();\n\n // TODO timestamp block filter\n });\n\n it('Should run transaction filters correctly', () => {\n // https://solscan.io/tx/FQNxV3NQHf6JBzYkaaWaRVj3eAtdEVSsjdStXM9ciZmWfoeiABaG3dXqK612T3LMi3McP5hf967AgJByvRkkRJY\n const tx = getTxBySig(\n 'FQNxV3NQHf6JBzYkaaWaRVj3eAtdEVSsjdStXM9ciZmWfoeiABaG3dXqK612T3LMi3McP5hf967AgJByvRkkRJY',\n );\n\n const signerMatch: TransactionFilter = {\n signerAccountKey: '3j1iDNRseKJVEWAb62Xxn74mVjJ7sUTVJaaBNb3gKtUe',\n };\n expect(filterTransactionsProcessor(tx!, signerMatch)).toBeTruthy();\n\n const signerMismatch: TransactionFilter = {\n signerAccountKey: '7yYGUXSY9hSa3MqmU7t4acCMBzSQyjxZyoRC1bDKMKJh',\n };\n expect(filterTransactionsProcessor(tx!, signerMismatch)).toBeFalsy();\n });\n\n describe('instructions', () => {\n it('can filter failed instructions', () => {\n const failedTx = block.block.transactions.find((tx) => tx.meta?.err);\n const failedInst = failedTx!.transaction.message.instructions[0];\n expect(\n filterInstructionsProcessor(failedInst, solanaApi.decoder, {\n includeFailed: true,\n }),\n ).toBeTruthy();\n expect(\n filterInstructionsProcessor(failedInst, solanaApi.decoder, {\n includeFailed: false,\n }),\n ).toBeFalsy();\n });\n\n it('can filter programIds', () => {\n const tx = getTxBySig(\n '4V5S9ymSheic34SsHN9AHA86b41qXfA9JwdEra1UUgoNdvWFTMA5ueSCHn6nRTBDphMQFUFLPgU4N2QsG8En3J1d',\n );\n const inst = tx?.transaction.message.instructions[4];\n\n expect(inst).toBeDefined();\n\n // A program called by this instruction\n expect(\n filterInstructionsProcessor(inst!, solanaApi.decoder, {\n programId: '675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8',\n }),\n ).toBe(true);\n\n // A program not called by this instruction\n expect(\n filterInstructionsProcessor(inst!, solanaApi.decoder, {\n programId: 'TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA',\n }),\n ).toBe(false);\n });\n\n it.each([\n // ['human', 'swap', true], // TODO wrong IDL currently\n ['hex', '0x09', true],\n ['base58', 'A', true],\n ['human', 'shutdown', false],\n ['hex', '0x74ce1bbfa6130049', false],\n ['base58', 'kPf6M86k1NDLT', false],\n ])(\n 'should correctly match discrminators in %s format',\n (_, discriminator, result) => {\n // TODO wrong IDL currently\n solanaApi.decoder.idls[\n '675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8'\n ] = IDL_swap;\n const tx = getTxBySig(\n '4V5S9ymSheic34SsHN9AHA86b41qXfA9JwdEra1UUgoNdvWFTMA5ueSCHn6nRTBDphMQFUFLPgU4N2QsG8En3J1d',\n );\n const inst = tx?.transaction.message.instructions[4];\n\n expect(\n filterInstructionsProcessor(inst!, solanaApi.decoder, {\n programId: '675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8',\n discriminator,\n }),\n ).toBe(result);\n },\n );\n\n it('can filter accounts', () => {\n const tx = getTxBySig(\n '4V5S9ymSheic34SsHN9AHA86b41qXfA9JwdEra1UUgoNdvWFTMA5ueSCHn6nRTBDphMQFUFLPgU4N2QsG8En3J1d',\n );\n const inst = tx?.transaction.message.instructions[4];\n\n expect(\n filterInstructionsProcessor(inst!, solanaApi.decoder, {\n accounts: [null, ['6fuLRV8aLJF96MaNi44bLJUhaSJu1yzc588kHM4DfG2W']],\n }),\n ).toBe(true);\n\n expect(\n filterInstructionsProcessor(inst!, solanaApi.decoder, {\n accounts: [\n null,\n null,\n ['6fuLRV8aLJF96MaNi44bLJUhaSJu1yzc588kHM4DfG2W'], // Out of position\n ],\n }),\n ).toBe(false);\n\n expect(\n filterInstructionsProcessor(inst!, solanaApi.decoder, {\n accounts: [null, null, []],\n }),\n ).toBe(false);\n\n expect(\n filterInstructionsProcessor(inst!, solanaApi.decoder, {\n accounts: [\n null,\n [\n '6fuLRV8aLJF96MaNi44bLJUhaSJu1yzc588kHM4DfG2W',\n '5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1',\n ], // Out of position\n ],\n }),\n ).toBe(true);\n });\n });\n\n describe('logs', () => {\n it('should filter logs by program Id', () => {\n const tx = getTxBySig(\n '4V5S9ymSheic34SsHN9AHA86b41qXfA9JwdEra1UUgoNdvWFTMA5ueSCHn6nRTBDphMQFUFLPgU4N2QsG8En3J1d',\n );\n\n const log = tx!.meta!.logs![1];\n expect(log).toBeDefined();\n // Matching program id\n expect(\n filterLogsProcessor(log, {\n programId: '675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8',\n }),\n ).toBe(true);\n\n // non-matching programId\n expect(\n filterLogsProcessor(log, {\n programId: '5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1',\n }),\n ).toBe(false);\n });\n });\n });\n\n describe('Block parsing', () => {\n it('makes instructions that have a transaction property', () => {\n const tx = getTxBySig(\n 'FQNxV3NQHf6JBzYkaaWaRVj3eAtdEVSsjdStXM9ciZmWfoeiABaG3dXqK612T3LMi3McP5hf967AgJByvRkkRJY',\n );\n\n for (const instruction of tx!.transaction.message.instructions) {\n expect(instruction.transaction).toBeDefined();\n }\n\n for (const innerInstruction of tx!.meta!.innerInstructions) {\n for (const instruction of innerInstruction.instructions) {\n expect(instruction.transaction).toBeDefined();\n }\n }\n });\n\n it('corretly parses logs', () => {\n const tx = getTxBySig(\n '4vGc5nP4W7VZe7SmSb2GsJMG3KJijZJ4KGHUCQ14FmqfPsyDotn7kwR5nA13PpzjwT732ggiLuDGs5PDpjRCKsC6',\n );\n expect(tx!.meta!.logs).toBeDefined();\n expect(tx!.meta!.logs!.length).toBeGreaterThan(0);\n\n // Tx with data logs\n const txWData = getTxBySig(\n 'qtUujQqx16ChZRMG4TE9eNMp4th3GxLvuuCQBEXK4KYyjqfAAPbP6xejA2ZTUe7X1cZYiHCnJHpC5v6GRctYc8c',\n );\n expect(txWData!.meta!.logs).toBeDefined();\n expect(txWData!.meta!.logs!.length).toBeGreaterThan(0);\n\n // Tx with a failure\n const txWError = getTxBySig(\n '8q3z3WoYUcA8UQLYgdgriGCZrGJUAYoeUwTJaVuuq43AmKLQxKLAMxuEAWXMquozVXEX4eL91r3jxKFVifmeXrv',\n );\n expect(txWError!.meta!.logs).toBeDefined();\n expect(txWError!.meta!.logs!.length).toBeGreaterThan(0);\n });\n });\n\n // Tests that data types can be stringified, this is important to test because of circular references\n describe('JSON serialization', () => {\n it('can stringify a SolanaBlock', () => {\n expect(() => JSON.stringify(block)).not.toThrow();\n });\n\n it('can stringify a SolanaTransaction', () => {\n const tx = getTxBySig(\n '4vGc5nP4W7VZe7SmSb2GsJMG3KJijZJ4KGHUCQ14FmqfPsyDotn7kwR5nA13PpzjwT732ggiLuDGs5PDpjRCKsC6',\n );\n\n expect(tx).toBeDefined();\n expect(() => JSON.stringify(tx)).not.toThrow();\n });\n\n it('can stringify a SolanaInstruction', () => {\n const tx = getTxBySig(\n '4V5S9ymSheic34SsHN9AHA86b41qXfA9JwdEra1UUgoNdvWFTMA5ueSCHn6nRTBDphMQFUFLPgU4N2QsG8En3J1d',\n );\n const inst = tx?.transaction.message.instructions[4];\n\n expect(inst).toBeDefined();\n expect(() => JSON.stringify(inst)).not.toThrow();\n });\n\n it('can stringify a LogMessage', () => {\n const tx = getTxBySig(\n '4V5S9ymSheic34SsHN9AHA86b41qXfA9JwdEra1UUgoNdvWFTMA5ueSCHn6nRTBDphMQFUFLPgU4N2QsG8En3J1d',\n );\n\n for (const log of tx!.meta!.logs!) {\n expect(() => JSON.stringify(log)).not.toThrow();\n }\n });\n });\n});\n"]}
1
+ {"version":3,"file":"api.solana.spec.js","sourceRoot":"","sources":["../../src/solana/api.solana.spec.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright 2020-2025 SubQuery Pte Ltd authors & contributors\n// SPDX-License-Identifier: GPL-3.0\n\nimport { IdlV01 } from '@codama/nodes-from-anchor';\nimport { EventEmitter2 } from '@nestjs/event-emitter';\nimport { TransactionFilter } from '@subql/common-solana';\nimport { IBlock } from '@subql/node-core';\nimport {\n SolanaBlock,\n SolanaBlockFilter,\n SolanaTransaction,\n} from '@subql/types-solana';\nimport { SolanaApi } from './api.solana';\nimport { SolanaDecoder } from './decoder';\nimport {\n filterBlocksProcessor,\n filterInstructionsProcessor,\n filterLogsProcessor,\n filterTransactionsProcessor,\n} from './utils.solana';\n\n// Add api key to work\nconst HTTP_ENDPOINT =\n process.env.HTTP_ENDPOINT ?? 'https://solana.api.onfinality.io/public';\n\nconst IDL_swap: IdlV01 = require('../../test/swapFpHZwjELNnjvThjajtiVmkz3yPQEHjLtka2fwHW.idl.json');\n\ndescribe('Api.solana', () => {\n let solanaApi: SolanaApi;\n const eventEmitter = new EventEmitter2();\n let block: IBlock<SolanaBlock>;\n const decoder = new SolanaDecoder();\n\n beforeAll(async () => {\n solanaApi = await SolanaApi.create(HTTP_ENDPOINT, eventEmitter, decoder);\n // https://solscan.io/block/325922873\n block = await solanaApi.fetchBlock(325_922_873);\n }, 20_000);\n\n function getTxBySig(sig: string): SolanaTransaction {\n const tx = block.block.transactions.find((tx) =>\n tx.transaction.signatures.find((s) => s === sig),\n );\n if (!tx) {\n throw new Error(`Unable to find tx with signature ${sig}`);\n }\n return tx;\n }\n\n it('parses block timestamps correctly', () => {\n expect(block.getHeader().timestamp).toEqual(\n new Date('2025-03-10T22:40:28.000Z'),\n );\n });\n\n describe('Filters', () => {\n it('Should run block filters correctly', () => {\n const moduloBlockFilter: SolanaBlockFilter = {\n modulo: 1,\n };\n expect(\n filterBlocksProcessor(block.block, moduloBlockFilter),\n ).toBeTruthy();\n\n const moduloBlockFilter2: SolanaBlockFilter = {\n modulo: 325_922_870,\n };\n expect(\n filterBlocksProcessor(block.block, moduloBlockFilter2),\n ).toBeFalsy();\n\n // TODO timestamp block filter\n });\n\n it('Should run transaction filters correctly', () => {\n // https://solscan.io/tx/FQNxV3NQHf6JBzYkaaWaRVj3eAtdEVSsjdStXM9ciZmWfoeiABaG3dXqK612T3LMi3McP5hf967AgJByvRkkRJY\n const tx = getTxBySig(\n 'FQNxV3NQHf6JBzYkaaWaRVj3eAtdEVSsjdStXM9ciZmWfoeiABaG3dXqK612T3LMi3McP5hf967AgJByvRkkRJY',\n );\n\n const signerMatch: TransactionFilter = {\n signerAccountKey: '3j1iDNRseKJVEWAb62Xxn74mVjJ7sUTVJaaBNb3gKtUe',\n };\n expect(filterTransactionsProcessor(tx!, signerMatch)).toBeTruthy();\n\n const signerMismatch: TransactionFilter = {\n signerAccountKey: '7yYGUXSY9hSa3MqmU7t4acCMBzSQyjxZyoRC1bDKMKJh',\n };\n expect(filterTransactionsProcessor(tx!, signerMismatch)).toBeFalsy();\n });\n\n describe('instructions', () => {\n it('can filter failed instructions', () => {\n const failedTx = block.block.transactions.find((tx) => tx.meta?.err);\n const failedInst = failedTx!.transaction.message.instructions[0];\n expect(\n filterInstructionsProcessor(failedInst, solanaApi.decoder, {\n includeFailed: true,\n }),\n ).toBeTruthy();\n expect(\n filterInstructionsProcessor(failedInst, solanaApi.decoder, {\n includeFailed: false,\n }),\n ).toBeFalsy();\n });\n\n it('can filter programIds', () => {\n const tx = getTxBySig(\n '4V5S9ymSheic34SsHN9AHA86b41qXfA9JwdEra1UUgoNdvWFTMA5ueSCHn6nRTBDphMQFUFLPgU4N2QsG8En3J1d',\n );\n const inst = tx?.transaction.message.instructions[4];\n\n expect(inst).toBeDefined();\n\n // A program called by this instruction\n expect(\n filterInstructionsProcessor(inst!, solanaApi.decoder, {\n programId: '675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8',\n }),\n ).toBe(true);\n\n // A program not called by this instruction\n expect(\n filterInstructionsProcessor(inst!, solanaApi.decoder, {\n programId: 'TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA',\n }),\n ).toBe(false);\n });\n\n it.each([\n // ['human', 'swap', true], // TODO wrong IDL currently\n ['hex', '0x09', true],\n ['base58', 'A', true],\n ['human', 'shutdown', false],\n ['hex', '0x74ce1bbfa6130049', false],\n ['base58', 'kPf6M86k1NDLT', false],\n ])(\n 'should correctly match discrminators in %s format',\n (_, discriminator, result) => {\n // TODO wrong IDL currently\n solanaApi.decoder.idls[\n '675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8'\n ] = IDL_swap;\n const tx = getTxBySig(\n '4V5S9ymSheic34SsHN9AHA86b41qXfA9JwdEra1UUgoNdvWFTMA5ueSCHn6nRTBDphMQFUFLPgU4N2QsG8En3J1d',\n );\n const inst = tx?.transaction.message.instructions[4];\n\n expect(\n filterInstructionsProcessor(inst!, solanaApi.decoder, {\n programId: '675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8',\n discriminator,\n }),\n ).toBe(result);\n },\n );\n\n it('can filter accounts', () => {\n const tx = getTxBySig(\n '4V5S9ymSheic34SsHN9AHA86b41qXfA9JwdEra1UUgoNdvWFTMA5ueSCHn6nRTBDphMQFUFLPgU4N2QsG8En3J1d',\n );\n const inst = tx?.transaction.message.instructions[4];\n\n expect(\n filterInstructionsProcessor(inst!, solanaApi.decoder, {\n accounts: [null, ['6fuLRV8aLJF96MaNi44bLJUhaSJu1yzc588kHM4DfG2W']],\n }),\n ).toBe(true);\n\n expect(\n filterInstructionsProcessor(inst!, solanaApi.decoder, {\n accounts: [\n null,\n null,\n ['6fuLRV8aLJF96MaNi44bLJUhaSJu1yzc588kHM4DfG2W'], // Out of position\n ],\n }),\n ).toBe(false);\n\n expect(\n filterInstructionsProcessor(inst!, solanaApi.decoder, {\n accounts: [null, null, []],\n }),\n ).toBe(false);\n\n expect(\n filterInstructionsProcessor(inst!, solanaApi.decoder, {\n accounts: [\n null,\n [\n '6fuLRV8aLJF96MaNi44bLJUhaSJu1yzc588kHM4DfG2W',\n '5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1',\n ], // Out of position\n ],\n }),\n ).toBe(true);\n });\n });\n\n describe('logs', () => {\n it('should filter logs by program Id', () => {\n const tx = getTxBySig(\n '4V5S9ymSheic34SsHN9AHA86b41qXfA9JwdEra1UUgoNdvWFTMA5ueSCHn6nRTBDphMQFUFLPgU4N2QsG8En3J1d',\n );\n\n const log = tx!.meta!.logs![1];\n expect(log).toBeDefined();\n // Matching program id\n expect(\n filterLogsProcessor(log, {\n programId: '675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8',\n }),\n ).toBe(true);\n\n // non-matching programId\n expect(\n filterLogsProcessor(log, {\n programId: '5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1',\n }),\n ).toBe(false);\n });\n });\n });\n\n describe('Block parsing', () => {\n it('makes instructions that have a transaction property', () => {\n const tx = getTxBySig(\n 'FQNxV3NQHf6JBzYkaaWaRVj3eAtdEVSsjdStXM9ciZmWfoeiABaG3dXqK612T3LMi3McP5hf967AgJByvRkkRJY',\n );\n\n for (const instruction of tx!.transaction.message.instructions) {\n expect(instruction.transaction).toBeDefined();\n }\n\n for (const innerInstruction of tx!.meta!.innerInstructions) {\n for (const instruction of innerInstruction.instructions) {\n expect(instruction.transaction).toBeDefined();\n }\n }\n });\n\n it('corretly parses logs', () => {\n const tx = getTxBySig(\n '4vGc5nP4W7VZe7SmSb2GsJMG3KJijZJ4KGHUCQ14FmqfPsyDotn7kwR5nA13PpzjwT732ggiLuDGs5PDpjRCKsC6',\n );\n expect(tx!.meta!.logs).toBeDefined();\n expect(tx!.meta!.logs!.length).toBeGreaterThan(0);\n\n // Tx with data logs\n const txWData = getTxBySig(\n 'qtUujQqx16ChZRMG4TE9eNMp4th3GxLvuuCQBEXK4KYyjqfAAPbP6xejA2ZTUe7X1cZYiHCnJHpC5v6GRctYc8c',\n );\n expect(txWData!.meta!.logs).toBeDefined();\n expect(txWData!.meta!.logs!.length).toBeGreaterThan(0);\n\n // Tx with a failure\n const txWError = getTxBySig(\n '8q3z3WoYUcA8UQLYgdgriGCZrGJUAYoeUwTJaVuuq43AmKLQxKLAMxuEAWXMquozVXEX4eL91r3jxKFVifmeXrv',\n );\n expect(txWError!.meta!.logs).toBeDefined();\n expect(txWError!.meta!.logs!.length).toBeGreaterThan(0);\n });\n });\n\n // Tests that data types can be stringified, this is important to test because of circular references\n describe('JSON serialization', () => {\n it('can stringify a SolanaBlock', () => {\n expect(() => JSON.stringify(block)).not.toThrow();\n });\n\n it('can stringify a SolanaTransaction', () => {\n const tx = getTxBySig(\n '4vGc5nP4W7VZe7SmSb2GsJMG3KJijZJ4KGHUCQ14FmqfPsyDotn7kwR5nA13PpzjwT732ggiLuDGs5PDpjRCKsC6',\n );\n\n expect(tx).toBeDefined();\n expect(() => JSON.stringify(tx)).not.toThrow();\n });\n\n it('can stringify a SolanaInstruction', () => {\n const tx = getTxBySig(\n '4V5S9ymSheic34SsHN9AHA86b41qXfA9JwdEra1UUgoNdvWFTMA5ueSCHn6nRTBDphMQFUFLPgU4N2QsG8En3J1d',\n );\n const inst = tx?.transaction.message.instructions[4];\n expect(inst).toBeDefined();\n\n const decodeInst = jest.spyOn(solanaApi.decoder, 'decodeInstruction');\n expect(() => JSON.stringify(inst)).not.toThrow();\n expect(decodeInst).not.toHaveBeenCalled();\n });\n\n it('can stringify a LogMessage', () => {\n const tx = getTxBySig(\n '4V5S9ymSheic34SsHN9AHA86b41qXfA9JwdEra1UUgoNdvWFTMA5ueSCHn6nRTBDphMQFUFLPgU4N2QsG8En3J1d',\n );\n\n for (const log of tx!.meta!.logs!) {\n const decodeLog = jest.spyOn(solanaApi.decoder, 'decodeLog');\n expect(() => JSON.stringify(log)).not.toThrow();\n expect(decodeLog).not.toHaveBeenCalled();\n }\n });\n });\n});\n"]}
@@ -7,6 +7,16 @@ exports.formatBlockUtil = formatBlockUtil;
7
7
  exports.solanaBlockToHeader = solanaBlockToHeader;
8
8
  const node_core_1 = require("@subql/node-core");
9
9
  const logger = (0, node_core_1.getLogger)('SolanaBlock');
10
+ // We use this function to omit properties without accessing getters
11
+ function omit(input, omit) {
12
+ const json = {};
13
+ for (const key of Object.getOwnPropertyNames(input)) {
14
+ if (!omit.includes(key)) {
15
+ json[key] = input[key];
16
+ }
17
+ }
18
+ return json;
19
+ }
10
20
  function wrapInstruction(index, instruction, transaction, block, decoder) {
11
21
  let pendingDecode;
12
22
  // XXX if we make this fully circular toJSON will need to be added to omit the transaction on the instruction
@@ -22,8 +32,7 @@ function wrapInstruction(index, instruction, transaction, block, decoder) {
22
32
  };
23
33
  // Implement this in order to calculate block size
24
34
  res.toJSON = () => {
25
- const { block, decodedData, transaction, ...rest } = res;
26
- return rest;
35
+ return omit(res, ['block', 'decodedData', 'transaction']);
27
36
  };
28
37
  return res;
29
38
  }
@@ -107,8 +116,7 @@ function wrapLogs(logs, decoder) {
107
116
  // Implement this in order to calculate block size
108
117
  res.forEach((r) => {
109
118
  r.toJSON = () => {
110
- const { decodedMessage, ...rest } = r;
111
- return rest;
119
+ return omit(r, ['decodedMessage']);
112
120
  };
113
121
  });
114
122
  return res;
@@ -131,8 +139,7 @@ function wrapDictionaryLogs(logs, decoder) {
131
139
  };
132
140
  // Implement this in order to calculate block size
133
141
  res.toJSON = () => {
134
- const { decodedMessage, ...rest } = res;
135
- return rest;
142
+ return omit(res, ['decodedMessage']);
136
143
  };
137
144
  return res;
138
145
  });
@@ -1 +1 @@
1
- {"version":3,"file":"block.solana.js","sourceRoot":"","sources":["../../src/solana/block.solana.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright 2020-2025 SubQuery Pte Ltd authors & contributors\n// SPDX-License-Identifier: GPL-3.0\n\nimport type {\n UnixTimestamp,\n Blockhash,\n Slot,\n TransactionForFullJson,\n} from '@solana/rpc-types';\nimport { getLogger, type Header, type IBlock } from '@subql/node-core';\nimport type {\n SolanaBlock,\n BaseSolanaBlock,\n SolanaInstruction,\n DecodedData,\n SolanaLogMessage,\n} from '@subql/types-solana';\nimport { SolanaDecoder } from './decoder';\n\nconst logger = getLogger('SolanaBlock');\n\ntype RawSolanaBlock = Readonly<{\n /** The number of blocks beneath this block */\n blockHeight: bigint;\n /** Estimated production time, as Unix timestamp */\n blockTime: UnixTimestamp;\n /** the blockhash of this block */\n blockhash: Blockhash;\n /** The slot index of this block's parent */\n parentSlot: Slot;\n /** The blockhash of this block's parent */\n previousBlockhash: Blockhash;\n\n transactions: readonly TransactionForFullJson<0>[];\n}>;\n\nfunction wrapInstruction(\n index: number[],\n instruction: Omit<\n SolanaInstruction,\n 'index' | 'block' | 'transaction' | 'decodedData'\n >,\n transaction: TransactionForFullJson<0>,\n block: BaseSolanaBlock,\n decoder: SolanaDecoder,\n): SolanaInstruction {\n let pendingDecode: Promise<DecodedData | null>;\n // XXX if we make this fully circular toJSON will need to be added to omit the transaction on the instruction\n const res = {\n ...instruction,\n index,\n transaction,\n block,\n get decodedData(): Promise<DecodedData | null> {\n pendingDecode ??= decoder.decodeInstruction(this);\n return pendingDecode;\n },\n };\n\n // Implement this in order to calculate block size\n (res as any).toJSON = () => {\n const { block, decodedData, transaction, ...rest } = res;\n return rest;\n };\n\n return res;\n}\n\nfunction wrapLogs(\n logs: readonly string[] | null,\n decoder: SolanaDecoder,\n): SolanaLogMessage[] | null {\n if (logs === null) {\n return null;\n }\n const res: SolanaLogMessage[] = [];\n\n // Keep a stack of the instruction programs\n const instructionPath: string[] = [];\n\n for (const [idx, log] of Object.entries(logs)) {\n let pendingDecode: Promise<DecodedData | null>;\n if (log.startsWith('Program log:')) {\n res.push({\n message: log,\n programId: instructionPath[instructionPath.length - 1],\n logIndex: parseInt(idx, 10),\n type: 'log',\n decodedMessage: Promise.resolve(null),\n });\n } else if (log.startsWith('Program data:')) {\n res.push({\n message: log,\n programId: instructionPath[instructionPath.length - 1],\n logIndex: parseInt(idx, 10),\n type: 'data',\n get decodedMessage(): Promise<DecodedData | null> {\n pendingDecode ??= decoder.decodeLog(this);\n return pendingDecode;\n }, // TODO getter function to parse\n });\n } else if (log.startsWith('Program return:')) {\n res.push({\n message: log,\n programId: instructionPath[instructionPath.length - 1],\n logIndex: parseInt(idx, 10),\n type: 'other',\n get decodedMessage(): Promise<DecodedData | null> {\n pendingDecode ??= decoder.decodeLog(this);\n return pendingDecode;\n }, // TODO getter function to parse, can return data be dcoded?\n });\n } else if (log.startsWith('Program consumption:')) {\n // DO nothing\n } else if (log.startsWith('Program')) {\n const [, /* \"Program\"*/ programAddress, mode, ...rest] = log.split(' '); // TODO doesn't work with compute units\n switch (mode) {\n case 'invoke':\n instructionPath.push(programAddress);\n break;\n case 'success':\n // TODO need to check this is always the last item\n instructionPath.pop();\n break;\n case 'consumed':\n // Do nothing\n break;\n case 'failed:':\n // TODO\n instructionPath.pop();\n break;\n default:\n throw new Error(`Unknown log mode: ${mode}, log: ${log}`);\n }\n } else {\n /**\n * Known examples (prefixes):\n * * Transfer\n * * Create Account\n * * Allocate\n * * Instruction references an unknown account\n * */\n\n logger.warn(`Unable to parse log message: ${log}`);\n }\n }\n\n // Implement this in order to calculate block size\n res.forEach((r) => {\n (r as any).toJSON = () => {\n const { decodedMessage, ...rest } = r;\n return rest;\n };\n });\n\n return res;\n}\n\ntype DictionaryLog = {\n message: string;\n logIndex: number;\n programId: string;\n kind: 'data' | 'log' | 'other';\n};\n\nfunction wrapDictionaryLogs(\n logs: DictionaryLog[],\n decoder: SolanaDecoder,\n): SolanaLogMessage[] {\n return logs.map((l) => {\n let pendingDecode: Promise<DecodedData | null>;\n const res = {\n message: l.message,\n programId: l.programId,\n logIndex: l.logIndex,\n type: l.kind,\n get decodedMessage() {\n if (!['other', 'data'].includes(l.kind)) {\n return Promise.resolve(null);\n }\n\n pendingDecode ??= decoder.decodeLog(this);\n return pendingDecode;\n },\n };\n\n // Implement this in order to calculate block size\n (res as any).toJSON = () => {\n const { decodedMessage, ...rest } = res;\n return rest;\n };\n\n return res;\n });\n}\n\n/**\n * Transforms a block from a raw response to the types injected into handlers*/\nexport function transformBlock(\n block: RawSolanaBlock,\n decoder: SolanaDecoder,\n): SolanaBlock {\n const { transactions, ...baseBlock } = block;\n return {\n ...baseBlock,\n transactions: transactions.map((tx) => {\n try {\n return {\n ...tx,\n block: baseBlock,\n transaction: {\n ...tx.transaction,\n message: {\n ...tx.transaction.message,\n instructions: tx.transaction.message.instructions.map(\n (instruction, index) =>\n wrapInstruction([index], instruction, tx, baseBlock, decoder),\n ),\n },\n },\n meta: tx.meta\n ? {\n ...tx.meta,\n innerInstructions: tx.meta.innerInstructions.map(\n (innerInstruction) => ({\n ...innerInstruction,\n instructions: innerInstruction.instructions.map(\n (instruction, innerIndex) =>\n wrapInstruction(\n [innerInstruction.index, innerIndex],\n instruction,\n tx,\n baseBlock,\n decoder,\n ),\n ),\n }),\n ),\n // Dictionary blocks have logs instead of logMessages that are already somewhat wrapped\n logs: (tx.meta as any).logs\n ? wrapDictionaryLogs((tx.meta as any).logs, decoder)\n : wrapLogs(tx.meta.logMessages, decoder),\n }\n : null,\n };\n } catch (e) {\n throw new Error(\n `Failed to transform transaction: ${tx.transaction.signatures[0]}`,\n { cause: e },\n );\n }\n }),\n };\n}\n\nexport function formatBlockUtil<B extends SolanaBlock = SolanaBlock>(\n block: B,\n): IBlock<B> {\n return {\n block,\n getHeader: () => solanaBlockToHeader(block),\n };\n}\n\nexport function solanaBlockToHeader(block: BaseSolanaBlock): Header {\n return {\n blockHeight: Number(block.parentSlot) + 1, // The blocks don't include the slot because they assume you know that when making the request\n blockHash: block.blockhash,\n parentHash: block.previousBlockhash,\n timestamp: new Date(Number(block.blockTime) * 1000),\n };\n}\n"]}
1
+ {"version":3,"file":"block.solana.js","sourceRoot":"","sources":["../../src/solana/block.solana.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright 2020-2025 SubQuery Pte Ltd authors & contributors\n// SPDX-License-Identifier: GPL-3.0\n\nimport type {\n UnixTimestamp,\n Blockhash,\n Slot,\n TransactionForFullJson,\n} from '@solana/rpc-types';\nimport { getLogger, type Header, type IBlock } from '@subql/node-core';\nimport type {\n SolanaBlock,\n BaseSolanaBlock,\n SolanaInstruction,\n DecodedData,\n SolanaLogMessage,\n} from '@subql/types-solana';\nimport { SolanaDecoder } from './decoder';\n\nconst logger = getLogger('SolanaBlock');\n\ntype RawSolanaBlock = Readonly<{\n /** The number of blocks beneath this block */\n blockHeight: bigint;\n /** Estimated production time, as Unix timestamp */\n blockTime: UnixTimestamp;\n /** the blockhash of this block */\n blockhash: Blockhash;\n /** The slot index of this block's parent */\n parentSlot: Slot;\n /** The blockhash of this block's parent */\n previousBlockhash: Blockhash;\n\n transactions: readonly TransactionForFullJson<0>[];\n}>;\n\n// We use this function to omit properties without accessing getters\nfunction omit<T>(input: T, omit: (keyof T)[]) {\n const json: Record<string, any> = {};\n\n for (const key of Object.getOwnPropertyNames(input)) {\n if (!omit.includes(key as keyof T)) {\n json[key] = (input as any)[key];\n }\n }\n\n return json;\n}\n\nfunction wrapInstruction(\n index: number[],\n instruction: Omit<\n SolanaInstruction,\n 'index' | 'block' | 'transaction' | 'decodedData'\n >,\n transaction: TransactionForFullJson<0>,\n block: BaseSolanaBlock,\n decoder: SolanaDecoder,\n): SolanaInstruction {\n let pendingDecode: Promise<DecodedData | null>;\n // XXX if we make this fully circular toJSON will need to be added to omit the transaction on the instruction\n const res = {\n ...instruction,\n index,\n transaction,\n block,\n get decodedData(): Promise<DecodedData | null> {\n pendingDecode ??= decoder.decodeInstruction(this);\n return pendingDecode;\n },\n };\n\n // Implement this in order to calculate block size\n (res as any).toJSON = () => {\n return omit(res, ['block', 'decodedData', 'transaction']);\n };\n\n return res;\n}\n\nfunction wrapLogs(\n logs: readonly string[] | null,\n decoder: SolanaDecoder,\n): SolanaLogMessage[] | null {\n if (logs === null) {\n return null;\n }\n const res: SolanaLogMessage[] = [];\n\n // Keep a stack of the instruction programs\n const instructionPath: string[] = [];\n\n for (const [idx, log] of Object.entries(logs)) {\n let pendingDecode: Promise<DecodedData | null>;\n if (log.startsWith('Program log:')) {\n res.push({\n message: log,\n programId: instructionPath[instructionPath.length - 1],\n logIndex: parseInt(idx, 10),\n type: 'log',\n decodedMessage: Promise.resolve(null),\n });\n } else if (log.startsWith('Program data:')) {\n res.push({\n message: log,\n programId: instructionPath[instructionPath.length - 1],\n logIndex: parseInt(idx, 10),\n type: 'data',\n get decodedMessage(): Promise<DecodedData | null> {\n pendingDecode ??= decoder.decodeLog(this);\n return pendingDecode;\n }, // TODO getter function to parse\n });\n } else if (log.startsWith('Program return:')) {\n res.push({\n message: log,\n programId: instructionPath[instructionPath.length - 1],\n logIndex: parseInt(idx, 10),\n type: 'other',\n get decodedMessage(): Promise<DecodedData | null> {\n pendingDecode ??= decoder.decodeLog(this);\n return pendingDecode;\n }, // TODO getter function to parse, can return data be dcoded?\n });\n } else if (log.startsWith('Program consumption:')) {\n // DO nothing\n } else if (log.startsWith('Program')) {\n const [, /* \"Program\"*/ programAddress, mode, ...rest] = log.split(' '); // TODO doesn't work with compute units\n switch (mode) {\n case 'invoke':\n instructionPath.push(programAddress);\n break;\n case 'success':\n // TODO need to check this is always the last item\n instructionPath.pop();\n break;\n case 'consumed':\n // Do nothing\n break;\n case 'failed:':\n // TODO\n instructionPath.pop();\n break;\n default:\n throw new Error(`Unknown log mode: ${mode}, log: ${log}`);\n }\n } else {\n /**\n * Known examples (prefixes):\n * * Transfer\n * * Create Account\n * * Allocate\n * * Instruction references an unknown account\n * */\n\n logger.warn(`Unable to parse log message: ${log}`);\n }\n }\n\n // Implement this in order to calculate block size\n res.forEach((r) => {\n (r as any).toJSON = () => {\n return omit(r, ['decodedMessage']);\n };\n });\n\n return res;\n}\n\ntype DictionaryLog = {\n message: string;\n logIndex: number;\n programId: string;\n kind: 'data' | 'log' | 'other';\n};\n\nfunction wrapDictionaryLogs(\n logs: DictionaryLog[],\n decoder: SolanaDecoder,\n): SolanaLogMessage[] {\n return logs.map((l) => {\n let pendingDecode: Promise<DecodedData | null>;\n const res = {\n message: l.message,\n programId: l.programId,\n logIndex: l.logIndex,\n type: l.kind,\n get decodedMessage() {\n if (!['other', 'data'].includes(l.kind)) {\n return Promise.resolve(null);\n }\n\n pendingDecode ??= decoder.decodeLog(this);\n return pendingDecode;\n },\n };\n\n // Implement this in order to calculate block size\n (res as any).toJSON = () => {\n return omit(res, ['decodedMessage']);\n };\n\n return res;\n });\n}\n\n/**\n * Transforms a block from a raw response to the types injected into handlers*/\nexport function transformBlock(\n block: RawSolanaBlock,\n decoder: SolanaDecoder,\n): SolanaBlock {\n const { transactions, ...baseBlock } = block;\n return {\n ...baseBlock,\n transactions: transactions.map((tx) => {\n try {\n return {\n ...tx,\n block: baseBlock,\n transaction: {\n ...tx.transaction,\n message: {\n ...tx.transaction.message,\n instructions: tx.transaction.message.instructions.map(\n (instruction, index) =>\n wrapInstruction([index], instruction, tx, baseBlock, decoder),\n ),\n },\n },\n meta: tx.meta\n ? {\n ...tx.meta,\n innerInstructions: tx.meta.innerInstructions.map(\n (innerInstruction) => ({\n ...innerInstruction,\n instructions: innerInstruction.instructions.map(\n (instruction, innerIndex) =>\n wrapInstruction(\n [innerInstruction.index, innerIndex],\n instruction,\n tx,\n baseBlock,\n decoder,\n ),\n ),\n }),\n ),\n // Dictionary blocks have logs instead of logMessages that are already somewhat wrapped\n logs: (tx.meta as any).logs\n ? wrapDictionaryLogs((tx.meta as any).logs, decoder)\n : wrapLogs(tx.meta.logMessages, decoder),\n }\n : null,\n };\n } catch (e) {\n throw new Error(\n `Failed to transform transaction: ${tx.transaction.signatures[0]}`,\n { cause: e },\n );\n }\n }),\n };\n}\n\nexport function formatBlockUtil<B extends SolanaBlock = SolanaBlock>(\n block: B,\n): IBlock<B> {\n return {\n block,\n getHeader: () => solanaBlockToHeader(block),\n };\n}\n\nexport function solanaBlockToHeader(block: BaseSolanaBlock): Header {\n return {\n blockHeight: Number(block.parentSlot) + 1, // The blocks don't include the slot because they assume you know that when making the request\n blockHash: block.blockhash,\n parentHash: block.previousBlockhash,\n timestamp: new Date(Number(block.blockTime) * 1000),\n };\n}\n"]}
@@ -14,6 +14,9 @@ const HTTP_ENDPOINT = process.env.HTTP_ENDPOINT ?? 'https://solana.api.onfinalit
14
14
  const IDL_Jupiter = require('../../test/JUP6LkbZbjS1jKKwapdHNy74zcZ3tLUZoi5QNyVTaV4.idl.json');
15
15
  const IDL_swap = require('../../test/swapFpHZwjELNnjvThjajtiVmkz3yPQEHjLtka2fwHW.idl.json');
16
16
  const IDL_token = require('../../test/TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA.idl.json');
17
+ function findTx(block, sig) {
18
+ return block.transactions.find((tx) => tx.transaction.signatures.find((s) => s === sig));
19
+ }
17
20
  describe('SolanaDecoder', () => {
18
21
  let solanaApi;
19
22
  let decoder;
@@ -112,8 +115,7 @@ describe('SolanaDecoder', () => {
112
115
  };
113
116
  it('can decode an instruction with an IDL file', async () => {
114
117
  //https://solscan.io/tx/3rf2sSMeJC1dd4t4TDvYPfvQjpL6DG6qdDcMnruDtATPbwjqt3xDnNvddtiTBESL8AWiFt2zENghqAh1h252bKQi
115
- const tx = blockData.transactions.find((tx) => tx.transaction.signatures.find((s) => s ===
116
- '3rf2sSMeJC1dd4t4TDvYPfvQjpL6DG6qdDcMnruDtATPbwjqt3xDnNvddtiTBESL8AWiFt2zENghqAh1h252bKQi'));
118
+ const tx = findTx(blockData, '3rf2sSMeJC1dd4t4TDvYPfvQjpL6DG6qdDcMnruDtATPbwjqt3xDnNvddtiTBESL8AWiFt2zENghqAh1h252bKQi');
117
119
  const instruction = tx.transaction.message.instructions[3];
118
120
  const decoded = await decoder.decodeInstruction(instruction);
119
121
  expect(decoded).toBeDefined();
@@ -123,8 +125,7 @@ describe('SolanaDecoder', () => {
123
125
  // Since removing anchor we don't have a way of fetching IDLS
124
126
  it.skip('can decode an instruction with an IDL found on chain', async () => {
125
127
  // https://solscan.io/tx/3rf2sSMeJC1dd4t4TDvYPfvQjpL6DG6qdDcMnruDtATPbwjqt3xDnNvddtiTBESL8AWiFt2zENghqAh1h252bKQi
126
- const tx = blockData.transactions.find((tx) => tx.transaction.signatures.find((s) => s ===
127
- '3rf2sSMeJC1dd4t4TDvYPfvQjpL6DG6qdDcMnruDtATPbwjqt3xDnNvddtiTBESL8AWiFt2zENghqAh1h252bKQi'));
128
+ const tx = findTx(blockData, '3rf2sSMeJC1dd4t4TDvYPfvQjpL6DG6qdDcMnruDtATPbwjqt3xDnNvddtiTBESL8AWiFt2zENghqAh1h252bKQi');
128
129
  const instruction = tx.transaction.message.instructions[3];
129
130
  const decoded = await decoder.decodeInstruction(instruction);
130
131
  expect(decoded).toBeDefined();
@@ -132,8 +133,7 @@ describe('SolanaDecoder', () => {
132
133
  expect(decoded.data).toEqual(instructionData);
133
134
  });
134
135
  it('can decode SPL token program instructions', async () => {
135
- const tx = blockData.transactions.find((tx) => tx.transaction.signatures.find((s) => s ===
136
- '61vjnjBfvU3e2BqmatPd3uYi37woXS44oqcQ3gD1XoS4demqXSmT32vGpdYdXTHW5niePACTKQaDxipn6jhbTWDL'));
136
+ const tx = findTx(blockData, '61vjnjBfvU3e2BqmatPd3uYi37woXS44oqcQ3gD1XoS4demqXSmT32vGpdYdXTHW5niePACTKQaDxipn6jhbTWDL');
137
137
  // eslint-disable-next-line @typescript-eslint/no-non-null-asserted-optional-chain
138
138
  const instruction = tx.meta?.innerInstructions.find((inner) => inner.index === 0)?.instructions[1];
139
139
  const program = (0, utils_solana_1.getProgramId)(instruction);
@@ -163,8 +163,7 @@ describe('SolanaDecoder', () => {
163
163
  };
164
164
  it('can decode a log with an Anchor IDL file', async () => {
165
165
  // https://solscan.io/tx/5Z18NZWUiDmxmVYncvuyACB9HRRYyzZfRPE9pfT2yaTpAveDTUwghWaYMPRk9Df5HsJy9yd6dBrndrmHz1zfsAig
166
- const tx = blockData.transactions.find((tx) => tx.transaction.signatures.find((s) => s ===
167
- '5Z18NZWUiDmxmVYncvuyACB9HRRYyzZfRPE9pfT2yaTpAveDTUwghWaYMPRk9Df5HsJy9yd6dBrndrmHz1zfsAig'));
166
+ const tx = findTx(blockData, '5Z18NZWUiDmxmVYncvuyACB9HRRYyzZfRPE9pfT2yaTpAveDTUwghWaYMPRk9Df5HsJy9yd6dBrndrmHz1zfsAig');
168
167
  const programLogs = tx.meta.logs?.filter((l) => l.message.startsWith('Program data:'));
169
168
  expect(programLogs?.length).toBe(1);
170
169
  const decoded = await decoder.decodeLog(programLogs[0]);
@@ -1 +1 @@
1
- {"version":3,"file":"decoder.spec.js","sourceRoot":"","sources":["../../src/solana/decoder.spec.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright 2020-2025 SubQuery Pte Ltd authors & contributors\n// SPDX-License-Identifier: GPL-3.0\n\nimport { IdlV01 } from '@codama/nodes-from-anchor';\nimport { EventEmitter2 } from '@nestjs/event-emitter';\nimport { SolanaBlock } from '@subql/types-solana';\nimport bs58 from 'bs58';\nimport { RootNode } from 'codama';\nimport { SolanaApi } from './api.solana';\nimport { SolanaDecoder } from './decoder';\nimport { getProgramId } from './utils.solana';\n\nconst HTTP_ENDPOINT =\n process.env.HTTP_ENDPOINT ?? 'https://solana.api.onfinality.io/public';\n\nconst IDL_Jupiter: IdlV01 = require('../../test/JUP6LkbZbjS1jKKwapdHNy74zcZ3tLUZoi5QNyVTaV4.idl.json');\nconst IDL_swap: IdlV01 = require('../../test/swapFpHZwjELNnjvThjajtiVmkz3yPQEHjLtka2fwHW.idl.json');\nconst IDL_token: RootNode = require('../../test/TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA.idl.json');\n\ndescribe('SolanaDecoder', () => {\n let solanaApi: SolanaApi;\n let decoder: SolanaDecoder;\n let blockData: SolanaBlock;\n\n beforeAll(async () => {\n decoder = new SolanaDecoder();\n solanaApi = await SolanaApi.create(\n HTTP_ENDPOINT,\n new EventEmitter2(),\n decoder,\n );\n });\n\n const loadDecoderIdls = () => {\n // eslint-disable-next-line @typescript-eslint/dot-notation\n decoder.idls['JUP6LkbZbjS1jKKwapdHNy74zcZ3tLUZoi5QNyVTaV4'] = IDL_Jupiter;\n // eslint-disable-next-line @typescript-eslint/dot-notation\n decoder.idls['swapFpHZwjELNnjvThjajtiVmkz3yPQEHjLtka2fwHW'] = IDL_swap;\n // eslint-disable-next-line @typescript-eslint/dot-notation\n decoder.idls['TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA'] = IDL_token;\n };\n\n describe('caching IDLs', () => {\n // Fetching IDLs from the network is not currently supported\n it.skip('caches IDLs from the network', async () => {\n const spy = jest.spyOn(solanaApi, 'getAccountInfo');\n\n const mockInst = {\n transaction: {\n transaction: {\n message: {\n accountKeys: ['JUP6LkbZbjS1jKKwapdHNy74zcZ3tLUZoi5QNyVTaV4'],\n },\n },\n },\n data: '',\n programIdIndex: 0,\n };\n\n await decoder.decodeInstruction(mockInst as any);\n await decoder.decodeInstruction(mockInst as any);\n\n expect(spy).toHaveBeenCalledTimes(1);\n\n await decoder.decodeLog({\n programId: 'JUP6LkbZbjS1jKKwapdHNy74zcZ3tLUZoi5QNyVTaV4',\n message: '',\n } as any);\n\n expect(spy).toHaveBeenCalledTimes(1);\n });\n });\n\n describe('parsing instruction discriminators', () => {\n beforeAll(() => {\n loadDecoderIdls();\n });\n\n it('correctly parses Anchor program discriminators', () => {\n for (const inst of IDL_Jupiter.instructions) {\n expect(\n decoder.parseDiscriminator(\n inst.name,\n 'JUP6LkbZbjS1jKKwapdHNy74zcZ3tLUZoi5QNyVTaV4',\n ),\n ).toEqual(Buffer.from(inst.discriminator));\n }\n });\n\n it('correctly parses SPL program discriminators', () => {\n for (let i = 0; i < IDL_token.program.instructions.length; i++) {\n const inst = IDL_token.program.instructions[i];\n expect(\n decoder.parseDiscriminator(\n inst.name,\n 'TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA',\n ),\n ).toEqual(Buffer.from([i]));\n }\n });\n\n it('correctly parses hex discriminators', () => {\n for (let i = 0; i < IDL_token.program.instructions.length; i++) {\n expect(\n decoder.parseDiscriminator(\n `0x${Buffer.from([i]).toString('hex')}`,\n 'TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA',\n ),\n ).toEqual(Buffer.from([i]));\n }\n\n for (const inst of IDL_Jupiter.instructions) {\n expect(\n decoder.parseDiscriminator(\n `0x${Buffer.from(inst.discriminator).toString('hex')}`,\n 'TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA',\n ),\n ).toEqual(Buffer.from(inst.discriminator));\n }\n });\n\n it('correctly parses base58 discriminators', () => {\n for (let i = 0; i < IDL_token.program.instructions.length; i++) {\n expect(\n decoder.parseDiscriminator(\n bs58.encode(Buffer.from([i])),\n 'TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA',\n ),\n ).toEqual(Buffer.from([i]));\n }\n\n for (const inst of IDL_Jupiter.instructions) {\n expect(\n decoder.parseDiscriminator(\n bs58.encode(Buffer.from(inst.discriminator)),\n 'TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA',\n ),\n ).toEqual(Buffer.from(inst.discriminator));\n }\n });\n });\n\n describe('decode instrutions', () => {\n beforeAll(async () => {\n // https://solscan.io/block/330469167\n const { block } = await solanaApi.fetchBlock(330_469_167);\n blockData = block;\n\n loadDecoderIdls();\n }, 30_000);\n\n const instructionData = {\n routePlan: [\n {\n swap: {\n __kind: 'MeteoraDlmm',\n },\n percent: 100,\n inputIndex: 0,\n outputIndex: 1,\n },\n ],\n inAmount: BigInt(16000),\n quotedOutAmount: BigInt(126754),\n slippageBps: 200,\n platformFeeBps: 98,\n };\n\n it('can decode an instruction with an IDL file', async () => {\n //https://solscan.io/tx/3rf2sSMeJC1dd4t4TDvYPfvQjpL6DG6qdDcMnruDtATPbwjqt3xDnNvddtiTBESL8AWiFt2zENghqAh1h252bKQi\n const tx = blockData.transactions.find((tx) =>\n tx.transaction.signatures.find(\n (s) =>\n s ===\n '3rf2sSMeJC1dd4t4TDvYPfvQjpL6DG6qdDcMnruDtATPbwjqt3xDnNvddtiTBESL8AWiFt2zENghqAh1h252bKQi',\n ),\n );\n const instruction = tx!.transaction.message.instructions[3];\n\n const decoded = await decoder.decodeInstruction(instruction);\n\n expect(decoded).toBeDefined();\n expect(decoded!.name).toEqual('route');\n expect(decoded!.data).toEqual(instructionData);\n });\n\n // Since removing anchor we don't have a way of fetching IDLS\n it.skip('can decode an instruction with an IDL found on chain', async () => {\n // https://solscan.io/tx/3rf2sSMeJC1dd4t4TDvYPfvQjpL6DG6qdDcMnruDtATPbwjqt3xDnNvddtiTBESL8AWiFt2zENghqAh1h252bKQi\n const tx = blockData.transactions.find((tx) =>\n tx.transaction.signatures.find(\n (s) =>\n s ===\n '3rf2sSMeJC1dd4t4TDvYPfvQjpL6DG6qdDcMnruDtATPbwjqt3xDnNvddtiTBESL8AWiFt2zENghqAh1h252bKQi',\n ),\n );\n const instruction = tx!.transaction.message.instructions[3];\n const decoded = await decoder.decodeInstruction(instruction);\n\n expect(decoded).toBeDefined();\n expect(decoded!.name).toEqual('route');\n expect(decoded!.data).toEqual(instructionData);\n });\n\n it('can decode SPL token program instructions', async () => {\n const tx = blockData.transactions.find((tx) =>\n tx.transaction.signatures.find(\n (s) =>\n s ===\n '61vjnjBfvU3e2BqmatPd3uYi37woXS44oqcQ3gD1XoS4demqXSmT32vGpdYdXTHW5niePACTKQaDxipn6jhbTWDL',\n ),\n );\n\n // eslint-disable-next-line @typescript-eslint/no-non-null-asserted-optional-chain\n const instruction = tx!.meta?.innerInstructions.find(\n (inner) => inner.index === 0,\n )?.instructions[1]!;\n\n const program = getProgramId(instruction);\n expect(program).toBe('TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA');\n\n const decoded = await decoder.decodeInstruction(instruction);\n\n expect(decoded).toEqual({\n name: 'transferChecked',\n data: {\n amount: BigInt('5904646875'),\n decimals: 6,\n },\n });\n });\n });\n\n describe('decode log', () => {\n beforeAll(async () => {\n //https://solscan.io/block/327347682\n const { block } = await solanaApi.fetchBlock(327_347_682);\n loadDecoderIdls();\n blockData = block;\n }, 30_000);\n\n const logData = {\n pubkey: 'BQR6JJFyMWxnUERqbCRCCy1ietW2yq8RTKDx9odzruha',\n data: {\n balances: [BigInt('16648442361'), BigInt('4003645427000')],\n },\n };\n\n it('can decode a log with an Anchor IDL file', async () => {\n // https://solscan.io/tx/5Z18NZWUiDmxmVYncvuyACB9HRRYyzZfRPE9pfT2yaTpAveDTUwghWaYMPRk9Df5HsJy9yd6dBrndrmHz1zfsAig\n const tx = blockData.transactions.find((tx) =>\n tx.transaction.signatures.find(\n (s) =>\n s ===\n '5Z18NZWUiDmxmVYncvuyACB9HRRYyzZfRPE9pfT2yaTpAveDTUwghWaYMPRk9Df5HsJy9yd6dBrndrmHz1zfsAig',\n ),\n );\n\n const programLogs = tx!.meta!.logs?.filter((l) =>\n l.message.startsWith('Program data:'),\n );\n expect(programLogs?.length).toBe(1);\n\n const decoded = await decoder.decodeLog(programLogs![0]);\n\n expect(decoded).not.toBeNull();\n expect(decoded!.name).toBe('poolBalanceUpdatedEvent');\n expect(decoded!.data).toEqual(logData);\n });\n });\n});\n"]}
1
+ {"version":3,"file":"decoder.spec.js","sourceRoot":"","sources":["../../src/solana/decoder.spec.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright 2020-2025 SubQuery Pte Ltd authors & contributors\n// SPDX-License-Identifier: GPL-3.0\n\nimport { IdlV01 } from '@codama/nodes-from-anchor';\nimport { EventEmitter2 } from '@nestjs/event-emitter';\nimport { SolanaBlock, SolanaTransaction } from '@subql/types-solana';\nimport bs58 from 'bs58';\nimport { RootNode } from 'codama';\nimport { SolanaApi } from './api.solana';\nimport { SolanaDecoder } from './decoder';\nimport { getProgramId, filterInstructionsProcessor } from './utils.solana';\n\nconst HTTP_ENDPOINT =\n process.env.HTTP_ENDPOINT ?? 'https://solana.api.onfinality.io/public';\n\nconst IDL_Jupiter: IdlV01 = require('../../test/JUP6LkbZbjS1jKKwapdHNy74zcZ3tLUZoi5QNyVTaV4.idl.json');\nconst IDL_swap: IdlV01 = require('../../test/swapFpHZwjELNnjvThjajtiVmkz3yPQEHjLtka2fwHW.idl.json');\nconst IDL_token: RootNode = require('../../test/TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA.idl.json');\n\nfunction findTx(\n block: SolanaBlock,\n sig: string,\n): SolanaTransaction | undefined {\n return block.transactions.find((tx) =>\n tx.transaction.signatures.find((s) => s === sig),\n );\n}\n\ndescribe('SolanaDecoder', () => {\n let solanaApi: SolanaApi;\n let decoder: SolanaDecoder;\n let blockData: SolanaBlock;\n\n beforeAll(async () => {\n decoder = new SolanaDecoder();\n solanaApi = await SolanaApi.create(\n HTTP_ENDPOINT,\n new EventEmitter2(),\n decoder,\n );\n });\n\n const loadDecoderIdls = () => {\n // eslint-disable-next-line @typescript-eslint/dot-notation\n decoder.idls['JUP6LkbZbjS1jKKwapdHNy74zcZ3tLUZoi5QNyVTaV4'] = IDL_Jupiter;\n // eslint-disable-next-line @typescript-eslint/dot-notation\n decoder.idls['swapFpHZwjELNnjvThjajtiVmkz3yPQEHjLtka2fwHW'] = IDL_swap;\n // eslint-disable-next-line @typescript-eslint/dot-notation\n decoder.idls['TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA'] = IDL_token;\n };\n\n describe('caching IDLs', () => {\n // Fetching IDLs from the network is not currently supported\n it.skip('caches IDLs from the network', async () => {\n const spy = jest.spyOn(solanaApi, 'getAccountInfo');\n\n const mockInst = {\n transaction: {\n transaction: {\n message: {\n accountKeys: ['JUP6LkbZbjS1jKKwapdHNy74zcZ3tLUZoi5QNyVTaV4'],\n },\n },\n },\n data: '',\n programIdIndex: 0,\n };\n\n await decoder.decodeInstruction(mockInst as any);\n await decoder.decodeInstruction(mockInst as any);\n\n expect(spy).toHaveBeenCalledTimes(1);\n\n await decoder.decodeLog({\n programId: 'JUP6LkbZbjS1jKKwapdHNy74zcZ3tLUZoi5QNyVTaV4',\n message: '',\n } as any);\n\n expect(spy).toHaveBeenCalledTimes(1);\n });\n });\n\n describe('parsing instruction discriminators', () => {\n beforeAll(() => {\n loadDecoderIdls();\n });\n\n it('correctly parses Anchor program discriminators', () => {\n for (const inst of IDL_Jupiter.instructions) {\n expect(\n decoder.parseDiscriminator(\n inst.name,\n 'JUP6LkbZbjS1jKKwapdHNy74zcZ3tLUZoi5QNyVTaV4',\n ),\n ).toEqual(Buffer.from(inst.discriminator));\n }\n });\n\n it('correctly parses SPL program discriminators', () => {\n for (let i = 0; i < IDL_token.program.instructions.length; i++) {\n const inst = IDL_token.program.instructions[i];\n expect(\n decoder.parseDiscriminator(\n inst.name,\n 'TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA',\n ),\n ).toEqual(Buffer.from([i]));\n }\n });\n\n it('correctly parses hex discriminators', () => {\n for (let i = 0; i < IDL_token.program.instructions.length; i++) {\n expect(\n decoder.parseDiscriminator(\n `0x${Buffer.from([i]).toString('hex')}`,\n 'TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA',\n ),\n ).toEqual(Buffer.from([i]));\n }\n\n for (const inst of IDL_Jupiter.instructions) {\n expect(\n decoder.parseDiscriminator(\n `0x${Buffer.from(inst.discriminator).toString('hex')}`,\n 'TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA',\n ),\n ).toEqual(Buffer.from(inst.discriminator));\n }\n });\n\n it('correctly parses base58 discriminators', () => {\n for (let i = 0; i < IDL_token.program.instructions.length; i++) {\n expect(\n decoder.parseDiscriminator(\n bs58.encode(Buffer.from([i])),\n 'TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA',\n ),\n ).toEqual(Buffer.from([i]));\n }\n\n for (const inst of IDL_Jupiter.instructions) {\n expect(\n decoder.parseDiscriminator(\n bs58.encode(Buffer.from(inst.discriminator)),\n 'TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA',\n ),\n ).toEqual(Buffer.from(inst.discriminator));\n }\n });\n });\n\n describe('decode instrutions', () => {\n beforeAll(async () => {\n // https://solscan.io/block/330469167\n const { block } = await solanaApi.fetchBlock(330_469_167);\n blockData = block;\n\n loadDecoderIdls();\n }, 30_000);\n\n const instructionData = {\n routePlan: [\n {\n swap: {\n __kind: 'MeteoraDlmm',\n },\n percent: 100,\n inputIndex: 0,\n outputIndex: 1,\n },\n ],\n inAmount: BigInt(16000),\n quotedOutAmount: BigInt(126754),\n slippageBps: 200,\n platformFeeBps: 98,\n };\n\n it('can decode an instruction with an IDL file', async () => {\n //https://solscan.io/tx/3rf2sSMeJC1dd4t4TDvYPfvQjpL6DG6qdDcMnruDtATPbwjqt3xDnNvddtiTBESL8AWiFt2zENghqAh1h252bKQi\n const tx = findTx(\n blockData,\n '3rf2sSMeJC1dd4t4TDvYPfvQjpL6DG6qdDcMnruDtATPbwjqt3xDnNvddtiTBESL8AWiFt2zENghqAh1h252bKQi',\n );\n const instruction = tx!.transaction.message.instructions[3];\n\n const decoded = await decoder.decodeInstruction(instruction);\n\n expect(decoded).toBeDefined();\n expect(decoded!.name).toEqual('route');\n expect(decoded!.data).toEqual(instructionData);\n });\n\n // Since removing anchor we don't have a way of fetching IDLS\n it.skip('can decode an instruction with an IDL found on chain', async () => {\n // https://solscan.io/tx/3rf2sSMeJC1dd4t4TDvYPfvQjpL6DG6qdDcMnruDtATPbwjqt3xDnNvddtiTBESL8AWiFt2zENghqAh1h252bKQi\n const tx = findTx(\n blockData,\n '3rf2sSMeJC1dd4t4TDvYPfvQjpL6DG6qdDcMnruDtATPbwjqt3xDnNvddtiTBESL8AWiFt2zENghqAh1h252bKQi',\n );\n\n const instruction = tx!.transaction.message.instructions[3];\n const decoded = await decoder.decodeInstruction(instruction);\n\n expect(decoded).toBeDefined();\n expect(decoded!.name).toEqual('route');\n expect(decoded!.data).toEqual(instructionData);\n });\n\n it('can decode SPL token program instructions', async () => {\n const tx = findTx(\n blockData,\n '61vjnjBfvU3e2BqmatPd3uYi37woXS44oqcQ3gD1XoS4demqXSmT32vGpdYdXTHW5niePACTKQaDxipn6jhbTWDL',\n );\n\n // eslint-disable-next-line @typescript-eslint/no-non-null-asserted-optional-chain\n const instruction = tx!.meta?.innerInstructions.find(\n (inner) => inner.index === 0,\n )?.instructions[1]!;\n\n const program = getProgramId(instruction);\n expect(program).toBe('TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA');\n\n const decoded = await decoder.decodeInstruction(instruction);\n\n expect(decoded).toEqual({\n name: 'transferChecked',\n data: {\n amount: BigInt('5904646875'),\n decimals: 6,\n },\n });\n });\n });\n\n describe('decode log', () => {\n beforeAll(async () => {\n //https://solscan.io/block/327347682\n const { block } = await solanaApi.fetchBlock(327_347_682);\n loadDecoderIdls();\n blockData = block;\n }, 30_000);\n\n const logData = {\n pubkey: 'BQR6JJFyMWxnUERqbCRCCy1ietW2yq8RTKDx9odzruha',\n data: {\n balances: [BigInt('16648442361'), BigInt('4003645427000')],\n },\n };\n\n it('can decode a log with an Anchor IDL file', async () => {\n // https://solscan.io/tx/5Z18NZWUiDmxmVYncvuyACB9HRRYyzZfRPE9pfT2yaTpAveDTUwghWaYMPRk9Df5HsJy9yd6dBrndrmHz1zfsAig\n const tx = findTx(\n blockData,\n '5Z18NZWUiDmxmVYncvuyACB9HRRYyzZfRPE9pfT2yaTpAveDTUwghWaYMPRk9Df5HsJy9yd6dBrndrmHz1zfsAig',\n );\n\n const programLogs = tx!.meta!.logs?.filter((l) =>\n l.message.startsWith('Program data:'),\n );\n expect(programLogs?.length).toBe(1);\n\n const decoded = await decoder.decodeLog(programLogs![0]);\n\n expect(decoded).not.toBeNull();\n expect(decoded!.name).toBe('poolBalanceUpdatedEvent');\n expect(decoded!.data).toEqual(logData);\n });\n });\n});\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@subql/node-solana",
3
- "version": "6.0.2",
3
+ "version": "6.0.3-0",
4
4
  "description": "",
5
5
  "author": "Ian He",
6
6
  "license": "GPL-3.0",
@@ -64,5 +64,6 @@
64
64
  "files": [
65
65
  "/dist",
66
66
  "/bin"
67
- ]
67
+ ],
68
+ "stableVersion": "6.0.2"
68
69
  }