# Setting up an Indexer

SubQuery is a fast, flexible, and reliable open-source data decentralised infrastructure network, providing both RPC and indexed data to consumers around the world.

In this guide, we will walk through the steps required to set up an indexer using SubQuery on AssetChain.

### Prerequisites

Before starting, ensure the following tools are installed on your machine:

* **Node.js**: Install Node.js (LTS version recommended) from the [official site](https://nodejs.org/).
* **Docker**: Required for running SubQuery locally. Install from the [Docker website](https://www.docker.com/).
* **SubQuery CLI**: Install using the command

```sh
# NPM
npm install -g @subql/cli

# Test that it was installed correctly
subql --help
```

### Getting Started

Once you're done installing the Subquery CLI, Initialize[ ](https://academy.subquery.network/indexer/quickstart/quickstart.html#_2-initialise-a-new-subquery-project)a new Subquery project. Run the following command inside the directory that you want to create a SubQuery project in:

```sh
subql init
```

You'll be asked certain questions as you proceed ahead:

* **Project Name**: Choose a name for your SubQuery project.
* **Network Family**: Select the EVM . Use the arrow keys to browse the available options (there may be multiple pages to scroll through).
* **Network**: Pick the specific network(i.e `Asset Chain Testnet`) to be indexed by this SubQuery project. Use the arrow keys to scroll through the available networks.
* **Template Project**: Select a template project to kickstart the development process(`asset-chain-testnet-starter` ).
* **RPC Endpoint**: Provide the HTTP or websocket URL for a running RPC endpoint. This can be a public endpoint, a private node, or the default endpoint. Ensure the node has the full state of the data you wish to index—archive nodes are recommended.
* **Git Repository**: Enter the Git URL for the repository where your SubQuery project will be hosted.
* **Authors**: Specify the owner or author of this project (e.g., your name) or use the default provided.
* **Description**: Write a brief description explaining the data your project indexes and what users can do with it, or use the provided default.
* **Version**: Enter a custom version number or keep the default.
* **License**: Provide a software license for the project or leave it as the default (MIT).

Let's look at an example

```shell
subql init
? Project name indexer-tutorial
? Select a network family EVM
? Select a network Asset Chain Testnet
? Select a template project asset-chain-testnet-starter     This SubQuery project indexes all transfers and approval events for the WRWA Token on Asset Chain Test Network
? RPC endpoint: https://enugu-rpc.assetchain.org
? Author KodeSage
? Description This is my subquery tutorial
indexer-tutorial is ready
? Do you want to generate scaffolding from an existing contract abi? no
```

Finally, run the following command to install the new project’s dependencies from within the new project's directory

```sh
cd indexer-tutorial // Replace with you project name
yarn install
```

You have now initialised your first SubQuery project with just a few simple steps. Let’s now customise the asset-chain-testnet template for our project.

### Building the Project

For this Project, we are going to be indexing this [MultitokenLauncher Contract](https://scan-testnet.assetchain.org/address/0x6fCc46E73E5B96479F6fA731893534b6Ec6bf5E1?tab=contract). Specifically, we will be indexing the `TokenCreated`Event.

Inside your Project, you `abis` directory and rename the `erc20.abi.json` file to `multitokenlauncher.abi.json` and replace the file content with this content below

```json
 [
      {
        anonymous: false,
        inputs: [
          {
            indexed: true,
            internalType: "address",
            name: "previousOwner",
            type: "address",
          },
          {
            indexed: true,
            internalType: "address",
            name: "newOwner",
            type: "address",
          },
        ],
        name: "OwnershipTransferred",
        type: "event",
      },
      {
        anonymous: false,
        inputs: [
          {
            indexed: true,
            internalType: "address",
            name: "tokenAddress",
            type: "address",
          },
          {
            indexed: true,
            internalType: "address",
            name: "deployer",
            type: "address",
          },
          {
            indexed: false,
            internalType: "string",
            name: "tokenname",
            type: "string",
          },
          {
            indexed: false,
            internalType: "string",
            name: "tokensymbol",
            type: "string",
          },
        ],
        name: "TokenCreated",
        type: "event",
      },
      {
        inputs: [
          {
            internalType: "address",
            name: "tokenAddress",
            type: "address",
          },
          {
            internalType: "uint256",
            name: "amount",
            type: "uint256",
          },
        ],
        name: "burnTokens",
        outputs: [],
        stateMutability: "nonpayable",
        type: "function",
      },
      {
        inputs: [
          {
            internalType: "string",
            name: "name",
            type: "string",
          },
          {
            internalType: "string",
            name: "symbol",
            type: "string",
          },
        ],
        name: "createToken",
        outputs: [],
        stateMutability: "nonpayable",
        type: "function",
      },
      {
        inputs: [],
        name: "getTokens",
        outputs: [
          {
            internalType: "address[]",
            name: "",
            type: "address[]",
          },
        ],
        stateMutability: "view",
        type: "function",
      },
      {
        inputs: [],
        name: "owner",
        outputs: [
          {
            internalType: "address",
            name: "",
            type: "address",
          },
        ],
        stateMutability: "view",
        type: "function",
      },
      {
        inputs: [],
        name: "renounceOwnership",
        outputs: [],
        stateMutability: "nonpayable",
        type: "function",
      },
      {
        inputs: [
          {
            internalType: "uint256",
            name: "",
            type: "uint256",
          },
        ],
        name: "tokens",
        outputs: [
          {
            internalType: "address",
            name: "",
            type: "address",
          },
        ],
        stateMutability: "view",
        type: "function",
      },
      {
        inputs: [
          {
            internalType: "address",
            name: "newOwner",
            type: "address",
          },
        ],
        name: "transferOwnership",
        outputs: [],
        stateMutability: "nonpayable",
        type: "function",
      },
    ]
```

We will edit the SubQuery project by changing the following files:

* The project manifest in `project.ts` defines the key project configuration and mapping handler filters
* The GraphQL Schema (`schema.graphql`) defines the shape of the resulting data that you are using SubQuery to index
* The Mapping functions in `src/mappings/` directory are typescript functions that handle transformation logic

In the `schema.graphql` file, replace the content with this:

```graphql
type TokenCreated @entity {
  id: ID!
  tokenAddress: String!
  owner: String!
  name: String!
  symbol: String!
}

```

In the `mappings/mappingHandlers.ts`file, replace the content with this:

```typescript
export async function handleTokenCreated(): Promise<void> {
}

```

In the `project.ts`file, replace the content with this:

```typescript

import {
  EthereumProject,
  EthereumDatasourceKind,
  EthereumHandlerKind,
} from "@subql/types-ethereum";

import * as dotenv from 'dotenv';
import path from 'path';

const mode = process.env.NODE_ENV || 'production';

// Load the appropriate .env file
const dotenvPath = path.resolve(__dirname, `.env${mode !== 'production' ? `.${mode}` : ''}`);
dotenv.config({ path: dotenvPath });

// Can expand the Datasource processor types via the generic param
const project: EthereumProject = {
  specVersion: "1.0.0",
  version: "0.0.1",
  name: "indexer tutorials",
  description: "This is a sample implementation of the indexer tutorials",
  runner: {
    node: {
      name: "@subql/node-ethereum",
      version: ">=3.0.0",
    },
    query: {
      name: "@subql/query",
      version: "*",
    },
  },
  schema: {
    file: "./schema.graphql",
  },
  network: {
    /**
     * chainId is the EVM Chain ID, for Asset Chain Testnet this is 42421
     * https://chainlist.org/chain/42421
     */
    chainId: process.env.CHAIN_ID!,
    /**
     * These endpoint(s) should be public non-pruned archive node
     * We recommend providing more than one endpoint for improved reliability, performance, and uptime
     * Public nodes may be rate limited, which can affect indexing speed
     * When developing your project we suggest getting a private API key
     * If you use a rate limited endpoint, adjust the --batch-size and --workers parameters
     * These settings can be found in your docker-compose.yaml, they will slow indexing but prevent your project being rate limited
     */
    endpoint: process.env.ENDPOINT!?.split(",") as string[] | string,
  },
  dataSources: [
    {
      kind: EthereumDatasourceKind.Runtime,
      startBlock: 141381, //The Block Number where your contract was created
      options: {
        abi: "multitokenlauncher",
        // This is the contract address for MultiTokenlauncher
        address: "0x6fCc46E73E5B96479F6fA731893534b6Ec6bf5E1",
      },
      assets: new Map([
        ["multitokenlauncher", { file: "./abis/multitokenlauncher.abi.json" }],
      ]),
      mapping: {
        file: "./dist/index.js",
        handlers: [
          {
            kind: EthereumHandlerKind.Event,
            handler: "handleTokenCreated",
            filter: {
              /**
               * Follows standard log filters https://docs.ethers.io/v5/concepts/events/
               * address: "0x6fCc46E73E5B96479F6fA731893534b6Ec6bf5E1"
               */
              topics: [
                "TokenCreated(address indexed tokenAddress, address indexed deployer, string tokenname, string tokensymbol)",
              ],
            },
          },
        ],
      },
    },
  ],
  repository: "https://github.com/subquery/ethereum-subql-starter", // Replace with your own repository
};

// Must set default to the project instance
export default project;

```

Afterwards , Then Open your terminal and run the following code below

```
yarn codegen
```

This Generates types from the GraphQL schema definition and contract ABIs and saves them in the `/src/types` directory. This must be done after each change to the `schema.graphql` file or the contract ABIs and Updating the `project.ts`file.

Update `mappings/mappingHandlers.ts` file with this content below:

```javascript

import { TokenCreated } from "../types";
import { TokenCreatedLog } from "../types/abi-interfaces/MultitokenlauncherAbi";
import assert from "assert";

export async function handleTokenCreated(log: TokenCreatedLog): Promise<void> {
  logger.info(`New TokenCreated event log at block ${log.blockNumber}`);
  assert(log.args, "No log.args");

  const token = TokenCreated.create({
    id: log.transactionHash,
    tokenAddress: log.args.tokenAddress,
    owner: log.args.deployer,
    name: log.args.tokenname,
    symbol: log.args.tokensymbol,
  });

  await token.save();
}

// This handles the Transformation Logic and make the data's indexed. 
```

Now that our Project is Completed, we need to build out the `dist` file and test it.

in your terminal, run the following command:

```sh
yarn build
```

Once the Build Passes, Kudos your Subgraph Project is Ready.

### Testing

You need to test the project locally and make sure it is working before deploying.

{% hint style="info" %}
To Test, make sure you have your Docker Environment is running.
{% endhint %}

in your terminal, run the following commands:

```sh
docker-compose pull && docker-compose up
```

Open your Browser and Navigate to this URL <http://localhost:3000/>

query the graphql using the code below to get all Tokens created

```graphql
query GetTokenCreated {
  tokenCreateds{
    edges {
      node {
        id
        tokenAddress
        owner
        name
        symbol
      }
    }
  }
}
```

to get a a Single Token created,

```graphql
query GetSingleToken {
  tokenCreated(id: "0xbb5d708468aefcbca97711c99d7c7db270c7c521059367c64703b7edf785472c") {
    id
    tokenAddress
    owner
    name
    symbol
  }
}

```

You should see the different output of this project in Browser.

### Deploying our Subquery Project

Before you deploy your subquery project, you need to publish it first on the network.

**Prepare your SUBQL\_ACCESS\_TOKEN**

* Step 1: Go to [SubQuery Managed Service](https://managedservice.subquery.network/) and log in.
* Step 2: Click on your profile at the top right of the navigation menu, then click on ***Refresh Token***.
* Step 3: Copy the generated token.
* Step 4: To use this token:
  * Add SUBQL\_ACCESS\_TOKEN in your environment variables. `EXPORT SUBQL_ACCESS_TOKEN=<token>` (Windows) or `export SUBQL_ACCESS_TOKEN=<token>` (Mac/Linux)

**Publish your project**

In your project directory, run the following command

```sh
subql publish
```

you should then see a similar output below

```sh
SubQuery Project project.yaml uploaded to IPFS: QmPWDhbqBqN4peb5BQKuFZPFt1qfAP6b6aQNmzEYzaWg9M
```

**Deploying Our Project to The Network**

To create your first project, head to [SubQuery Managed Service](https://managedservice.subquery.network/). You'll need to authenticate with your GitHub account to login.

SubQuery Projects is where you manage all your hosted projects uploaded to the SubQuery platform. You can create, delete, and even upgrade projects all from this application.

<figure><img src="https://285329334-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FmuBv3mR5xhQRl9pMrnhC%2Fuploads%2Fgit-blob-a194a17b6e55242769c93aa8d3d3c05b2410882e%2FScreenshot%202024-09-24%20at%2015.04.41.png?alt=media" alt=""><figcaption></figcaption></figure>

Click on the `Create Project` Buttton to Create your Project, A Modal will pop up, then you Click on the `Subquery Project` and click the Next Button.

<figure><img src="https://285329334-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FmuBv3mR5xhQRl9pMrnhC%2Fuploads%2Fgit-blob-4defff6be98a8c88cae15b04376faea1557fd197%2FScreenshot%202024-09-24%20at%2015.05.20.png?alt=media" alt=""><figcaption></figcaption></figure>

and then follow the steps and enter the following:

{% hint style="info" %}
The information you are filling should tally with the same information you used while setting up the project using the CLI
{% endhint %}

* **Project Name:** Name your project.
* **Description:** Provide a description of your project.
* **Database:** Premium customers can access dedicated databases to host production SubQuery projects from. If this interests you, you can contact <sales@subquery.network> to have this setting enabled.
* **Visible in Explorer:** If selected, this will show the project from the public SubQuery explorer to share with the community.\\

<figure><img src="https://285329334-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FmuBv3mR5xhQRl9pMrnhC%2Fuploads%2Fgit-blob-61ba1b801766f08d3d4bb8ce46aca53db64cdbe2%2FScreenshot%202024-09-24%20at%2015.08.49.png?alt=media" alt=""><figcaption><p>create a project</p></figcaption></figure>

Below is the final code for our indexer project

{% embed url="<https://github.com/xendfinance/setting-up-an-indexer>" %}


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://academy.assetchain.org/module-4-intermediate-tutorials/setting-up-an-indexer.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
