Skip to main content

Stellar & Soroban Manifest File [Beta]

SubQuery TeamAbout 7 min

Stellar & Soroban Manifest File [Beta]

The Manifest project.ts file can be seen as an entry point of your project and it defines most of the details on how SubQuery will index and transform the chain data. It clearly indicates where we are indexing data from, and to what on chain events we are subscribing to.

The Manifest can be in either Typescript, Yaml, or JSON format.

With the number of new features we are adding to SubQuery, and the slight differences between each chain that mostly occur in the manifest, the project manifest is now written by default in Typescript. This means that you get a fully typed project manifest with documentation and examples provided your code editor.

Below is a standard example of a basic project.ts.

import {
  StellarDatasourceKind,
  StellarHandlerKind,
  StellarProject,
} from "@subql/types-stellar";
import { Horizon } from "stellar-sdk";

/* This is your project configuration */
const project: StellarProject = {
  specVersion: "1.0.0",
  name: "soroban-testnet-starter",
  version: "0.0.1",
  runner: {
    node: {
      name: "@subql/node-stellar",
      version: "*",
    },
    query: {
      name: "@subql/query",
      version: "*",
    },
  },
  description:
    "This project can be use as a starting point for developing your new Stellar SubQuery project (testnet)",
  repository: "https://github.com/subquery/stellar-subql-starter",
  schema: {
    file: "./schema.graphql",
  },
  network: {
    /* Stellar and Soroban uses the network passphrase as the chainId
      'Test SDF Network ; September 2015' for testnet
      'Public Global Stellar Network ; September 2015' for mainnet
      'Test SDF Future Network ; October 2022' for Future Network */
    chainId: "Test SDF Network ; September 2015",
    /* This Stellar endpoint must be a 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 */
    endpoint: ["https://horizon-testnet.stellar.org"],
    /* This is a specific Soroban endpoint
      It is only required when you are using a soroban/EventHandler */
    sorobanEndpoint: "https://soroban-testnet.stellar.org",
    /* Recommended to provide the HTTP endpoint of a full chain dictionary to speed up processing
      dictionary: "https://gx.api.subquery.network/sq/subquery/eth-dictionary" */
  },
  dataSources: [
    {
      kind: StellarDatasourceKind.Runtime,
      /* Set this as a logical start block, it might be block 1 (genesis) or when your contract was deployed */
      startBlock: 1700000,
      mapping: {
        file: "./dist/index.js",
        handlers: [
          {
            handler: "handleOperation",
            kind: StellarHandlerKind.Operation,
            filter: {
              type: Horizon.OperationResponseType.payment,
            },
          },
          {
            handler: "handleCredit",
            kind: StellarHandlerKind.Effects,
            filter: {
              type: "account_credited",
            },
          },
          {
            handler: "handleDebit",
            kind: StellarHandlerKind.Effects,
            filter: {
              type: "account_debited",
            },
          },
          {
            handler: "handleEvent",
            kind: StellarHandlerKind.Event,
            filter: {
              /* You can optionally specify a smart contract address here
                contractId: "" */
              topics: [
                "transfer", // Topic signature(s) for the events, there can be up to 4
              ],
            },
          },
        ],
      },
    },
  ],
};

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

Below is a standard example of the legacy YAML version (project.yaml).

Legacy YAML Manifest
specVersion: "1.0.0"

name: "soroban-subql-starter"
version: "0.0.1"
runner:
  node:
    name: "@subql/node-stellar"
    version: "*"
  query:
    name: "@subql/query"
    version: "*"
description: "This project can be use as a starting point for developing your new Stellar Soroban Future Network SubQuery project"
repository: "https://github.com/subquery/stellar-subql-starter"

schema:
  file: "./schema.graphql"

network:
  # Stellar and Soroban uses the network passphrase as the chainId
  # 'Public Global Stellar Network ; September 2015' for mainnet
  # 'Test SDF Future Network ; October 2022' for Future Network
  chainId: "Test SDF Future Network ; October 2022"
  # This endpoint must be a 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
  endpoint: ["https://horizon-futurenet.stellar.org:443"]
  sorobanEndpoint: "https://rpc-futurenet.stellar.org"
  # Recommended to provide the HTTP endpoint of a full chain dictionary to speed up processing
  # dictionary: "https://gx.api.subquery.network/sq/subquery/eth-dictionary"

dataSources:
  - kind: stellar/Runtime
    startBlock: 270000 # This is the start block from which you begin indexing
    mapping:
      file: "./dist/index.js"
      handlers:
        - handler: handleTransaction
          kind: soroban/TransactionHandler
           filter:
            account: "GAKNXHJ5PCZYFIBNBWB4RCQHH6GDEO7Z334N74BOQUQCHKOURQEPMXCH"
        - handler: handleOperation
          kind: stellar/OperationHandler
          filter:
            type: "payment"
        - handler: handleCredit
          kind: stellar/EffectHandler
          filter:
            type: "account_credited"
        - handler: handleEvent
          kind: stellar/EventHandler
          filter:
            # contractId: "" # You can optionally specify a smart contract address here
            topics:
              - "transfer" # Topic signature(s) for the events, there can be up to 4

Overview

Top Level Spec

FieldTypeDescription
specVersionStringThe spec version of the manifest file
nameStringName of your project
versionStringVersion of your project
descriptionStringDescription of your project
runnerRunner SpecRunner specs info
repositoryStringGit repository address of your project
schemaSchema SpecThe location of your GraphQL schema file
networkNetwork SpecDetail of the network to be indexed
dataSourcesDataSource SpecThe datasource to your project
templatesTemplates SpecAllows creating new datasources from this templates

Schema Spec

FieldTypeDescription
fileStringThe location of your GraphQL schema file

Network Spec

If you start your project by using the subql init command, you'll generally receive a starter project with the correct network settings. If you are changing the target chain of an existing project, you'll need to edit the Network Spec section of this manifest.

The chainId is the network identifier of the blockchain, Stellar and Soroban uses the network passphraseopen in new window. Examples in Stellar are Public Global Stellar Network ; September 2015 for mainnet and Test SDF Future Network ; October 2022 for Future Network.

A unique aspect of Stellar's Soroban network is that there is an additional seperate RPC for the Soroban smart contract layer. If you are indexing using the soroban/TransactionHandler or soroban/EventHandler, you will need to provide an HTTP RPC Soroban endpoint under the sorobanEndpoint property - you will want archive nodes with high rate limits if you want to index large amounts of historical data. This only accepts a single endpoint.

You will need to update the endpoint. This defines the HTTP RPC endpoint of the blockchain to be indexed - you will want archive nodes with high rate limits if you want to index large amounts of historical data. This property can be a string or an array of strings (e.g. endpoint: ['rpc1.endpoint.com', 'rpc2.endpoint.com']). We suggest providing an array of endpoints as it has the following benefits:

  • Increased speed - When enabled with worker threads, RPC calls are distributed and parallelised among RPC providers. Historically, RPC latency is often the limiting factor with SubQuery.
  • Increased reliability - If an endpoint goes offline, SubQuery will automatically switch to other RPC providers to continue indexing without interruption.
  • Reduced load on RPC providers - Indexing is a computationally expensive process on RPC providers, by distributing requests among RPC providers you are lowering the chance that your project will be rate limited.

Public nodes may be rate limited which can affect indexing speed, when developing your project we suggest getting a private API key from a professional RPC provider.

FieldTypeDescription
chainIdStringA network identifier for the blockchain, Stellar and Soroban uses the network passphraseopen in new window
endpointString or String[]Defines the endpoint of the blockchain to be indexed - you will want archive nodes with high rate limits if you want to index large amounts of historical datae.
sorobanEndpointStringDefines the soroban RPC endpoint - you will want archive nodes with high rate limits if you want to index large amounts of historical data.
portNumberOptional port number on the endpoint to connect to
dictionaryStringIt is suggested to provide the HTTP endpoint of a full chain dictionary to speed up processing - read how a SubQuery Dictionary works.
bypassBlocksArrayBypasses stated block numbers, the values can be a range(e.g. "10- 50") or integer, see Bypass Blocks

Runner Spec

FieldTypeDescription
nodeRunner node specDescribe the node service use for indexing
queryRunner query specDescribe the query service

Runner Node Spec

FieldTypeDescription
nameString@subql/node-stellar
versionStringVersion of the indexer Node service, it must follow the SEMVERopen in new window rules or latest, you can also find available versions in subquery SDK releasesopen in new window
optionsRunner Node OptionsRunner specific options for how to run your project. These will have an impact on the data your project produces. CLI flags can be used to override these.

Runner Query Spec

FieldTypeDescription
nameString@subql/query
versionStringVersion of the Query service, available versions can be found hereopen in new window, it also must follow the SEMVER rules or latest.

Runner Node Options

Fieldv1.0.0 (default)Description
historicalBoolean (true)Historical indexing allows you to query the state at a specific block height. e.g A users balance in the past.
unfinalizedBlocksBoolean (false)If enabled unfinalized blocks will be indexed, when a fork is detected the project will be reindexed from the fork. Requires historical.
unsafeBoolean (false)Removes all sandbox restrictions and allows access to all inbuilt node packages as well as being able to make network requests. WARNING: this can make your project non-deterministic.

Datasource Spec

Defines the data that will be filtered and extracted and the location of the mapping function handler for the data transformation to be applied.

FieldTypeDescription
kindstringstellar/Runtime
startBlockIntegerThis changes your indexing start block for this datasource, set this as high as possible to skip initial blocks with no relevant data
endBlockIntegerThis sets a end block for processing on the datasource. After this block is processed, this datasource will no longer index your data.

Useful when your contracts change at a certain block height, or when you want to insert data at genesis. For example, setting both the startBlock and endBlock to 320, will mean this datasource only operates on block 320
mappingMapping Spec

Mapping Spec

FieldTypeDescription
handlers & filtersDefault handlers and filtersList all the mapping functions and their corresponding handler types, with additional mapping filters.

Data Sources and Mapping

In this section, we will talk about the default Stellar runtime and its mapping. Here is an example:

{
  ...
  dataSources: [
    {
      kind: StellarDataSourceKind.Runtime, // Indicates that this is default runtime
      startBlock: 1, // This changes your indexing start block, set this higher to skip initial blocks with less data
      mapping: {
        file: "./dist/index.js", // Entry path for this mapping
        handlers: [
          /* Enter handers here */
        ],
      }
    }
  ]
}

Mapping Handlers and Filters

The following table explains filters supported by different handlers.

HandlerSupported filter
stellar/BlockHandlermodulo and timestamp
stellar/TransactionHandleraccount (address from)
soroban/TransactionHandleraccount (address from)
stellar/OperationHandlertype, sourceAccount
stellar/EffectHandlertype, account (address from)
soroban/EventHandlercontractId and/or up to 4 topics filters applied as an array, and an optional contractId
handlers:
  - handler: handleBlock
    kind: soroban/BlockHandler
  - handler: handleTransaction
    kind: soroban/TransactionHandler
    filter:
      account: "GAKNXHJ5PCZYFIBNBWB4RCQHH6GDEO7Z334N74BOQUQCHKOURQEPMXCH"
  - handler: handleOperation
    kind: stellar/OperationHandler
    filter:
      type: "payment"
  - handler: handleEffect
    kind: stellar/EffectHandler
    filter:
      type: "account_credited"
  - handler: handleEvent
    kind: soroban/EventHandler
    filter:
      # contractId: "" # You can optionally specify a smart contract address here
      topics:
        - "transfer" # Topic signature(s) for the events, there can be up to 4

Default runtime mapping filters are an extremely useful feature to decide what event will trigger a mapping handler.

Only incoming data that satisfies the filter conditions will be processed by the mapping functions. Mapping filters are optional but are highly recommended as they significantly reduce the amount of data processed by your SubQuery project and will improve indexing performance.

Real-time indexing (Block Confirmations)

As indexers are an additional layer in your data processing pipeline, they can introduce a massive delay between when an on-chain event occurs and when the data is processed and able to be queried from the indexer.

SubQuery provides real time indexing of unconfirmed data directly from the RPC endpoint that solves this problem. SubQuery takes the most probabilistic data before it is confirmed to provide to the app. In the unlikely event that the data isn’t confirmed and a reorg occurs, SubQuery will automatically roll back and correct its mistakes quickly and efficiently - resulting in an insanely quick user experience for your customers.

To control this feature, please adjust the --block-confirmations command to fine tune your project and also ensure that historic indexing is enabled (enabled by default)

Bypass Blocks

Bypass Blocks allows you to skip the stated blocks, this is useful when there are erroneous blocks in the chain or when a chain skips a block after an outage or a hard fork. It accepts both a range or single integer entry in the array.

When declaring a range use an string in the format of "start - end". Both start and end are inclusive, e.g. a range of "100-102" will skip blocks 100, 101, and 102.

{
  network: {
    bypassBlocks: [1, 2, 3, "105-200", 290];
  }
}