zenchain-bridge-indexer
v0.3.4
Published
ZenChain Ethereum Bridge Indexer
Readme
ZenChain Bridge Indexer
This is a SubQuery project that indexes data for the ZenChain Cross-Chain Messaging (CCIM) Bridge. It monitors both the ZenChain and a connected EVM chain (e.g., Ethereum) to track the entire lifecycle of cross-chain transfers.
The indexer provides a comprehensive GraphQL API to query for:
- Initiated, signed, and processed cross-chain transfers.
- Bridge operator set activations and versioning.
- Bridge service fee updates.
- Detailed information about each transfer, including sender, recipient, tokens, and amounts.
⚠️ Important Notice
This software has not been audited or reviewed for security. It may contain vulnerabilities and is not recommended for use with real financial assets.
Use at your own risk.
The authors of this software are not responsible for any loss, damage, or liability resulting from its use.
Key Features
- Multi-Chain Indexing: Simultaneously indexes events from ZenChain (a Substrate/Frontier EVM chain) and an external EVM chain.
- Complete Transfer Lifecycle: Tracks
CCIMTransferInitiated,CCIMTransferMessageSigned, andCCIMTransferProcessedevents. - Operator Versioning: Indexes
VersionActivatedevents to keep track of the active bridge operator sets. - Bridge Fee Tracking: Indexes
BridgeFeeUpdatedevents on ZenChain to track changes in the bridge's service fees. - Rich Data Model: Uses a structured GraphQL schema (
schema.graphql) with entities for transfers, events, and operator versions. - CAIP Standards: Leverages CAIP (Chain Agnostic Improvement Proposal) for identifying chains, accounts, and assets in a standardized way.
GraphQL Schema
The core of the indexer is its GraphQL schema, which defines the shape of the queryable data. Key entities include:
CCIMTransferMessage: The central entity representing a single cross-chain transfer. It tracks the status from initiation to final processing, including the number of operator signatures.CCIMTransferInitiatedEvent: Records the details of the transaction that initiated the transfer on the source chain.CCIMTransferMessageSignedEvent: Records each operator signature for a given transfer message.CCIMTransferProcessedEvent: Records the details of the transaction that processed the transfer on the destination chain.ActivatedOperatorVersionEvent: Stores information about activated bridge operator sets, including the quorum required for signing messages.BridgeFeeUpdatedEvent: Stores a historical record of changes to the bridge fee.
Getting Started
Prerequisites
- Node.js
- Yarn or NPM
- Docker
- SubQuery CLI:
npm install -g @subql/cli
1. Clone the Repository
git clone https://github.com/zenchain-protocol/zenchain-bridge-indexer.git
cd zenchain-bridge-indexer2. Install Dependencies
npm install3. Configure Environment Variables
Copy the example environment file and fill in the required values. You will need access to RPC endpoints for both ZenChain and the external EVM chain you wish to index.
cp .env.example .envYou will need to populate .env with the correct contract addresses and RPC endpoints.
4. Configure Project Constants
This project has two layers of configuration that must be kept in sync:
- .env file: This file is used at build time to configure the project manifests (
project-ethereum.ts,project-zenchain.ts) with network endpoints and contract addresses. src/constants.ts: This file contains hardcoded values that are used at run time by the mapping handlers.
You must ensure that the contract addresses and chain IDs in src/constants.ts match the values you have provided in your .env file. This is because the mapping handlers that process the blockchain data do not have access to environment variables at run time.
5. Generate Types and Build the Code
This command inspects the GraphQL schema and contract ABIs to generate corresponding TypeScript interfaces, then builds the project.
yarn build6. Run the Indexer
This command will start all the required services (indexer, database, query service) using Docker.
yarn devOnce the services are running, you can open your browser to http://localhost:3000 to access the GraphQL playground.
Example Query
You can use the GraphQL playground to query the indexed data. Here is an example query to fetch the 5 most recent cross-chain transfer messages, along with their initiation and processing status.
query {
ccimTransferMessages(first: 5, orderBy: INITIATED_EVENT_TIMESTAMP_DESC) {
nodes {
id # Message Hash
isSigned
isProcessed
signatureCount
initiatedEvent {
txHash
timestamp
block
chainId {
namespace
ref
}
}
processedEvent {
txHash
timestamp
block
chainId {
namespace
ref
}
}
destination {
amount
fee
recipient {
accountAddress
}
token {
assetRef
}
}
}
}
}Project Structure
subquery-multichain.yaml: Defines the multi-chain configuration.project-zenchain.ts/project-ethereum.ts: Individual manifest files for each chain, defining data sources, ABIs, and mapping handlers.schema.graphql: The GraphQL schema defining the data model.src/mappings/: Contains the TypeScript functions that handle the transformation logic for each blockchain event.abis/: Contains the JSON ABI files for the smart contracts.
Available Scripts
yarn build: Build the project and generate types.yarn codegen: Generate types fromschema.graphqland ABIs.yarn dev: Start the complete indexer stack (Postgres, indexer node, query service) using Docker.yarn test: Run tests for the mapping handlers.yarn abigen: Compiles smart contracts in thezenchain-bridge-labsubmodule and extracts ABIs to the./abisdirectory. Run this if you update the contracts.yarn create-mock-data: A utility script to generate mock data for testing purposes.
Limitations
The maximum operator set size must be greater than or equal to the query limit (set with the --query-limit flag; default: 100).
The maximum operator set size is currently set to 100 to match the default value of query-limit. To increase the maximum operator set size, update the value of MAX_OPERATOR_SET_SIZE in src/constants.ts.
If you need a significantly larger operator set size, or if you would like to decouple the operator set size from the query limit, you must implement pagination for fetching signed events in src/mappings/handleCCIMTransferInitiated.ts. There are pitfalls to this approach: the store searches the in-memory database cache before the persisted database, which affects how the offset and order parameters are interpreted. It is better to avoid pagination altogether if possible.
