subql
subql copied to clipboard
Using solana-dex-parser with mappings
added the following to mapping
import { DexParser, SolanaTransaction } from 'solana-dex-parser';
const parser = new DexParser();
Test
import { subqlTest } from "@subql/testing";
import { Transfer } from "../types/models";
// Example test for Transfer entity
subqlTest(
"handleTransfer test",
362963837, // block height to process
[],
[
// Expected output entities
{
id: "test-signature-123-0",
from: "source-account-address",
to: "destination-account-address",
amount: BigInt(100),
blockNumber: BigInt(362963837),
transactionHash: "test-signature-123",
date: new Date("2025-08-28T09:32:21.000Z")
}
],
"handleTransfer" // handler name
);
Error on test run
2025-08-29T01:13:29.164Z <SolanaDecoder> INFO Loaded IDL for TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA
2025-08-29T01:13:29.172Z <UnfinalizedBlocks> INFO Unfinalized blocks is disabled
2025-08-29T01:13:46.914Z <SolanaBlock> WARN Unable to parse log message: Transfer: insufficient lamports 1026178, need 1844400
2025-08-29T01:13:47.302Z <test-runner> WARN Test: handleTransfer test field due to runtime error
2025-08-29T01:13:47.302Z <test-runner> WARN Test handleTransfer test failed to run ReferenceError: TextEncoder is not defined
2025-08-29T01:13:47.349Z <StoreCache> WARN Error: SequelizeDatabaseError: relation "test-solana-token-program-starter._metadata" does not exist, Name: SequelizeDatabaseError, Parent: error: relation "test-solana-token-program-starter._metadata" does not exist, Original: error: relation "test-solana-token-program-starter._metadata" does not exist
2025-08-29T01:13:47.349Z <StoreCache> ERROR Database transaction failed, rolling back DatabaseError: relation "test-solana-token-program-starter._metadata" does not exist
2025-08-29T01:13:47.352Z <Testing> ERROR undefined Error: Testing failed
Cause: DatabaseError: relation "test-solana-token-program-starter._metadata" does not exist
Waiting for the debugger to disconnect...
error Command failed with exit code 1.
info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.
Waiting for the debugger to disconnect...
Enabling TextEncoder
sandbox: { atob , TextEncoder },
Error
2025-08-29T01:15:20.883Z <UnfinalizedBlocks> INFO Unfinalized blocks is disabled
2025-08-29T01:15:22.505Z <SolanaBlock> WARN Unable to parse log message: Transfer: insufficient lamports 1026178, need 1844400
2025-08-29T01:15:22.771Z <test-runner> WARN Test: handleTransfer test field due to runtime error
2025-08-29T01:15:22.772Z <test-runner> WARN Test handleTransfer test failed to run Error: Unable to resolve module 'http'. To resolve this you can either:
Narrow your import. e.g Instead of "import { BigNumber } from 'ethers'" you can use "import {BigNumber} from '@ethersproject/bignumber';"
Enable the --unsafe flag.
Cause: VMError: Cannot find module 'http'
2025-08-29T01:15:22.800Z <StoreCache> WARN Error: SequelizeDatabaseError: relation "test-solana-token-program-starter._metadata" does not exist, Name: SequelizeDatabaseError, Parent: error: relation "test-solana-token-program-starter._metadata" does not exist, Original: error: relation "test-solana-token-program-starter._metadata" does not exist
2025-08-29T01:15:22.800Z <StoreCache> ERROR Database transaction failed, rolling back DatabaseError: relation "test-solana-token-program-starter._metadata" does not exist
2025-08-29T01:15:22.804Z <Testing> ERROR undefined Error: Testing failed
Cause: DatabaseError: relation "test-solana-token-program-starter._metadata" does not exist
Waiting for the debugger to disconnect...
error Command failed with exit code 1.
info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.
Waiting for the debugger to disconnect...
Adding
// Using Node.js built-in TextEncoder/TextDecoder
const { TextEncoder, TextDecoder } = require('util');
// @ts-ignore - We know these exist in the global scope in Node.js
global.TextEncoder = TextEncoder;
// @ts-ignore
global.TextDecoder = TextDecoder as typeof global.TextDecoder;
to index.ts fixed it , also I had to use --unsafe
Another issue popped up. while using solana-dex-parser, it throws error because it expects a plain object but vm2 wrapper object is being sent. please advise
import { SolanaTransaction } from '@subql/types-solana';
import { Transaction } from '../types';
import { DexParser, SolanaTransaction as dexSolanaTransaction} from 'solana-dex-parser';
export async function handleTransaction(tx: SolanaTransaction): Promise<void> {
try {
// Skip if no signatures in the transaction
if (!tx.transaction?.signatures?.length) return;
const parser = new DexParser();
// const plainTx = tx;
// logger.info();
const result = parser.parseTrades(tx as unknown as dexSolanaTransaction);
logger.info(safeStringify(result));
const signature = tx.transaction.signatures[0];
const message = tx.transaction.message;
// Get the first and second accounts as from/to addresses
// Note: This is a simplified example - you might need to adjust based on your specific requirements
const from = message.accountKeys[0]?.toString();
const to = message.accountKeys[1]?.toString();
// For token transfers, you would typically need to parse the instruction data
// This is a simplified example - you'll need to implement the actual parsing based on your needs
const value = BigInt(0); // You'll need to parse this from the instruction data
// Create and save the transaction record with all required fields
const txRecord = new Transaction(
signature, // id
from || '', // owner
to || '', // spender
value, // value
'', // contractAddress
BigInt(tx.block?.blockHeight?.toString() || '0'), // blockNumber
new Date() // date
);
await txRecord.save();
} catch (error) {
logger.error(`Error processing transaction: ${error}`);
// You might want to handle specific errors differently
throw error;
}
}
TypeError [ERR_INVALID_ARG_TYPE]: The "otherBuffer" argument must be an instance of Buffer or Uint8Array. Received an instance of Object
[[Handler]] =
VM2 Wrapper
[[IsRevoked]] =
false
[[Target]] =
TypeError
this.eventParsers = {
CREATE: {
discriminator: constants_1.DISCRIMINATORS.PUMPSWAP.CREATE_POOL_EVENT,
decode: this.decodeCreateEvent.bind(this),
},
readonly CREATE_POOL_EVENT: Uint8Array<ArrayBuffer>;
subql is basically converting discriminator of type Uint8Array into object with index as key e.g. {"0":228,"1":69,"2":165,"3":46,"4":81,"5":203,"6":154,"7":29,"8":177,"9":49,"10":12,"11":210,"12":160,"13":118,"14":167,"15":116};
@stwiname please advise
@mogupta, the SubQuery project handlers are running in a sandbox which has some differences from a normal nodejs environment.
You can find more differences here. https://subquery.network/doc/indexer/build/mapping/sandbox.html
The issue you're facing now is that the data passed to the handers is proxy objects so instanceof checks fail. To fix this you could either re-parse the relevant data in the transaction to not be proxied objects. Or you could modify solana-dex-parser
Hey, @mogupta, we'd like to have a more direct line of communication. If you're interested can you reach out to me on telegram. https://t.me/skottnz