A TypeScript indexer for DEX trades on Raydium (Solana) using Yellowstone GRPC.
It is best used in conjunction with the dex-graphql package, which provides a GraphQL API for querying the data, and the complete infra for setting up a Timescale database optimized for time-series data, and interacting with it through Hasura.
DEX Indexer is available from npm
as
@primodiumxyz/dex-indexer
.
This package is used to index filtered transactions streamed from a Yellowstone GRPC server—i.e. swaps made on the Raydium AMM program—into a postgres database, with relevant data being parsed and/or fetched from external sources. The resulting trades and associated tokens are then available for querying through the dex-graphql package.
The indexer is designed to be run in a Docker container, but it can also be run directly in a node environment.
There are a few dependencies on external services:
- Jupiter for fetching token prices (
/prices
) - DAS API for fetching token metadata in the Metaplex standard (
/getAssets
) - Yellowstone GRPC for streaming transactions with low latency
All of these are available from QuickNode through add-ons, which is the recommended way to run the indexer.
This also requires careful consideration and planning to configure batch sizes and batching mode, due to possible rate limits.
On the database side, the preferred way is to use Timescale, which is optimized for time-series data, meaning that insertions performance won't be an issue. Additionally, the dex-graphql package provides functionality that is focused on leveraging Timescale's capabilities for super-fast queries and subscriptions.
Otherwise, the indexer just needs a postgres interface that will support inserting many trade entries in the following format (see insertTrades):
// As a TypeScript type for better readability
type Trade = {
token_mint: string;
volume_usd: string;
token_price_usd: string;
created_at: Date;
token_metadata: string;
};
// `token_metadata` being a composite type:
type TokenMetadata = {
name: string;
symbol: string;
description: string;
image_uri: string;
external_url: string;
decimals: string;
supply: number;
is_pump_token: boolean;
};
Just install the package from npm, preferably with pnpm.
pnpm add @primodiumxyz/dex-indexer
- Configuration
Add the following environment variables to your .env
file:
Variable | Description | Default |
---|---|---|
NODE_ENV |
Node environment | local |
HASURA_URL |
Hasura URL | http://localhost:8090 |
HASURA_ADMIN_SECRET |
Hasura admin secret | |
QUICKNODE_ENDPOINT |
Quicknode endpoint | |
QUICKNODE_TOKEN |
Quicknode token | |
JUPITER_URL |
Jupiter API URL | |
PROCESSING_MODE |
Processing mode | parallel |
MAX_BATCH_SIZE |
Maximum batch size | 100 |
MIN_BATCH_FREQUENCY |
Minimum batch frequency | 500 |
The variables with no default value are required.
- Run
local-dex-indexer
# or specify the path to your .env file (install @dotenvx/dotenvx first)
dotenvx run -f ./path/to/.env --quiet -- local-dex-indexer
Usage with Docker is the recommended way to run the indexer, as you can directly consume the image published on the GitHub Container Registry.
You can use the indexer.docker-compose.yaml
file linked in the resources, fill in the environment variables, and run:
docker compose up
This will pull the image from the registry and start the indexer.
To stop the indexer, you can use:
docker compose down --remove-orphans
Usage with TypeScript is pretty straightforward as well, although it is not the way it was designed for.
Just import the start
function from the package and call it:
import { start } from "@primodiumxyz/dex-indexer";
const run = async () => {
await start();
};
run();
Don't forget to run it with the environment variables context.
If you would like to develop on the indexer, you can do so by following these steps:
-
Clone the repository:
git clone https://github.com/primodiumxyz/dex-indexer-stack.git
-
Install the dependencies:
pnpm i
-
Run
a. everything (indexer & database) from root dir with:
pnpm dev
b. only the indexer if the database is already running:
cd packages/indexer pnpm start
You can also build the package for production at any point:
```sh
cd packages/indexer
pnpm build
```
dist - "Compiled files for distribution"
src - "Source files"
├── bin - "Entry point of the package (running the indexer & validating the environment)"
├── lib - "All of the internal logic, constants & types"
│ └── parsers - "Parsing logic with the global Solana parser, any parser specific to a DEX and utilities"
└── index.ts - "Main module, exports the `start` function to run the indexer"
If you wish to contribute to the package, please open an issue first to make sure that this is within the scope of the library, and that it is not already being worked on.
This project is licensed under the MIT License - see LICENSE for details.
The library contains a few chunks of code copied and modified from Shyft, especially in lib/parsers
, mainly for fixing formatting inconsistencies or missing types, and easier integration with the rest of the codebase. It is as best as possible documented above each block of code inside the JSDoc comments.