Blockchain Indexer
| Area | common/indexer | indexer |
|---|---|---|
| Type | Shared library | Standalone application / service |
| Technology | Kotlin, Micronaut, Apollo GraphQL | TypeScript/Node.js, Subsquid |
| Purpose | Calls the Indexer | Indexes blockchain data |
| Database | No owned database | PostgreSQL |
| Blockchain access | No direct blockchain access | Reads blockchain through RPC |
| API | GraphQL client | GraphQL server |
| Deployment | Bundled into consuming services | Deployed as processor and API |
| Kafka | No Kafka integration | Publishes blockchain events to Kafka |
| Data source | External Indexer GraphQL API | Blockchain/RPC |
| Location | common/indexer | indexer |
Overview
The DEUSS platform contains two separate components named around the Indexer:
indexeris the actual blockchain indexing application. It reads smart-contract activity from the blockchain, stores the indexed data, exposes it through GraphQL, and publishes selected events to Kafka.common/indexeris a reusable Kotlin client library. It allows other DEUSS services to query the running Indexer GraphQL API through a configured Apollo client. The components are complementary but have different responsibilities. Theindexercreates and serves indexed blockchain data, whilecommon/indexerconsumes that data from application services.
Indexer
Summary & Purpose
indexer is a standalone TypeScript/Node.js application based on Subsquid. It processes blockchain blocks, transactions, and smart-contract events, persists the resulting domain data in PostgreSQL, and exposes the indexed data through a GraphQL API.
The Indexer also publishes selected normalized blockchain events to Kafka and integrates with selected internal services during processing.
Business Responsibilities
- Index blockchain activity from configured EVM contracts
- Maintain queryable representations of blockchain entities and transactions
- Track:
- Companies and entities
- Company wallets
- Bonds and bond lifecycle
- Tokens and token ownership
- Market offers
- Market deals
- Transfers
- Coupon eligibility
- Historical blockchain changes
- Expose indexed data through GraphQL
- Publish selected blockchain events to Kafka
- Enrich or synchronize data through internal service integrations
- Support off-chain consumers that require blockchain-derived data
Indexed Domains
The processor is configured to monitor contracts and events related to:
- Entity Registry
- Entity registration
- Entity status and metadata changes
- Entity manager and authority updates
- Account registration and role changes
- Bond Registry
- Bond publication
- Bond issuance
- Bond cancellation
- Bond suspension and unsuspension
- Bond redemption
- Interest Discovery
- Offer registration
- Offer cancellation
- Amount updates
- Deal creation
- Deal status changes
- Fungible Token
- Token transfers
- Token pause and freeze operations
- Company Wallets
- Wallet creation
- Wallet operation and role changes
- Access and Role Management
- Granting, revoking, and renouncing contract roles
Owned Data
The Indexer owns the indexed representation of blockchain data in its PostgreSQL database. The GraphQL schema exposes data including:
- Accounts and account histories
- Entities and entity histories
- Entity types and metadata
- Company wallets and wallet histories
- Bonds and bond histories
- Tokens, token owners, and token transfers
- Market offers and market deals
- Deal and offer histories
- Contract operations
- Blockchain synchronization status The Indexer is not the authoritative owner of off-chain business data such as payment records or partner profiles. It provides a queryable blockchain-derived view of the platform.
Inbound Interfaces
Blockchain RPC
The processor reads blockchain data through an EVM RPC endpoint. Relevant configuration includes:
CHAIN_URLSTART_BLOCKFINALITY_CONFIRMATIONRATE_LIMIT- Contract addresses for monitored contracts The processor supports finality confirmation and block-range configuration.
Internal Service Dependencies
The processor requires configuration for:
BOND_ISSUANCE_SERVICE_URLREGISTRY_SERVICE_URLThe exact business operations performed through these clients are implemented in the Indexer’s off-chain service integration layer.
Outbound Interfaces
GraphQL API
The Indexer exposes indexed data through a Subsquid GraphQL server. The API supports queries for:
- Bonds
- Bond ownership
- Market offers
- Market deals
- Company wallets
- Token ownership and transfers
- Entity and account data
- Historical records
- Indexer synchronization status
The API is consumed by services such as Registry Service, Core Payment Service, and Blockchain Event Service through
common/indexeror dedicated clients.
Kafka
The Indexer publishes selected blockchain-derived events to Kafka. These events include activity related to:
- Offers
- Deals
- Deal status changes
- Bond publication
- Token transfers
- Amount updates
- Counter-offer processing Kafka topic names and publishing behavior are implemented in the Indexer’s Kafka integration.
PostgreSQL
The Indexer persists indexed blockchain data in PostgreSQL using TypeORM and Subsquid’s TypeORM store.
Processing Model
The main processing flow is:
- Read blocks from the configured blockchain RPC endpoint.
- Load relevant logs and transactions.
- Identify handlers based on contract address, event topic, or transaction selector.
- Decode and process blockchain activity.
- Load related records and cached entities.
- Apply business-specific processing and off-chain synchronization.
- Commit indexed records to PostgreSQL.
- Publish selected events to Kafka.
The processor uses a
UnitOfWorkto coordinate repositories, caching, service clients, event decoding, and persistence within block processing.
Deployment Topology
The Indexer is deployed as a Subsquid application with:
- A blockchain processor
- A GraphQL API
- PostgreSQL
- Blockchain RPC access
The deployment is defined through
squid.yamland includes: - PostgreSQL addon
- EVM RPC addon
- Processor command:
sqd process:prod - API command:
sqd serve:prodThe Indexer is independently buildable and deployable using Node.js, TypeScript, and the Subsquid toolchain.
Common Indexer
Summary & Purpose
common/indexer is a shared Kotlin library used by DEUSS services that need to access the Indexer GraphQL API. It provides a configured Apollo GraphQL client, generated query models, custom scalar adapters, response normalization, and optional request logging.
It is not an independent service and does not process blockchain data itself.
Business Responsibilities
- Provide a reusable GraphQL client for the Indexer
- Generate strongly typed Kotlin GraphQL operations
- Retrieve indexed blockchain data for consuming services
- Normalize GraphQL responses into the shared
ApiCallResulttype - Provide common pagination helpers
- Provide optional GraphQL request and response logging
- Handle custom GraphQL scalar conversions
Supported Query Areas
The shared query definitions support access to:
- Bond lists and bond details by ISIN
- Bond owners
- Coupon-eligible owners at a specific block
- Market deals created after a timestamp
- Expired pending market deals
- Market deal status by deal ID
- Full market-deal details by deal ID
- Company wallets by company ID
- Indexer synchronization status
Owned Data
common/indexer owns no business data and has no database.
It contains:
- GraphQL schema definitions
- GraphQL query files
- Generated GraphQL client code
- Apollo client configuration
- Scalar adapters
- Response-handling utilities
- Logging and pagination helpers The indexed data remains owned by the standalone Indexer application.
Inbound Interfaces
The library has no inbound runtime interfaces. It is invoked programmatically by consuming Kotlin services.
Outbound Interfaces
Indexer GraphQL API
The library creates an Apollo client configured through:
deuss:
indexer:
url: ${INDEXER_URL}
logging:
enabled: ${INDEXER_LOGGING_ENABLED:true}
The runtime Indexer endpoint is supplied by the consuming application.
Supported GraphQL Scalars
| GraphQL Scalar | Kotlin Type |
|---|---|
BigInt | java.math.BigInteger |
DateTime | java.time.LocalDateTime |
JSON | String |
Response Handling
GraphQL calls are processed through the shared executeAndSanitize utility.
The utility handles:
- Transport exceptions
- GraphQL errors
- Null response data
- Successful responses Results are represented as:
ApiCallResult.SuccessApiCallResult.UnrecoverableError.DownstreamErrorBusiness-specific error handling remains the responsibility of the consuming service.
Consumers
Verified consumers include:
- Blockchain Event Service
- Retrieves market deals by deal ID
- Retrieves bonds by ISIN
- Enriches decoded blockchain events before Kafka publication
- Core Payment Service
- Queries market-deal state
- Retrieves bond ownership information
- Supports payment and settlement processing Other consumers may exist and should be verified through repository-wide dependency usage.
Deployment Topology
common/indexer is packaged as a shared Gradle/Micronaut library.
It has:
- No application entry point
- No Docker image
- No database migrations
- No independent deployment
- No Kafka consumers or producers
- No independent REST or GraphQL server The library is included in consuming services at build time. Those services provide the runtime configuration and network access to the Indexer.
Relationship Between the Components
Blockchain
|
| RPC
v
Indexer Processor
|
v
Indexer PostgreSQL
|
v
Indexer GraphQL API
|
| Apollo GraphQL
v
common/indexer
|
v
Registry Service
Core Payment Service
Blockchain Event Service
Other Kotlin consumers
The main responsibility boundary is:
indexer: ingest, persist, and expose blockchain-derived datacommon/indexer: provide standardized client access to that data
Architectural Characteristics
indexeris a data-producing platform component.common/indexeris a data-consuming integration library.- The two components do not share a database directly.
- Consuming Kotlin services access the Indexer through GraphQL.
- Blockchain Event Service may also receive blockchain events through Kafka rather than querying the Indexer directly for every event.
common/indexerdoes not define business workflows; it only provides reusable access primitives.- The Indexer is independently deployable, while
common/indexeris deployed transitively with consuming services.
Key Configuration
Indexer
Relevant variables include:
CHAIN_URLSTART_BLOCKFINALITY_CONFIRMATIONRATE_LIMITCHAIN_ENTITY_REGISTRY_ADDRESSCHAIN_BOND_REGISTRY_ADDRESSCHAIN_INTEREST_DISCOVERY_ADDRESSCHAIN_WALLET_FACTORY_ADDRESSCHAIN_FUNGIBLE_TOKEN_CONTRACT_ADDRESSBOND_ISSUANCE_SERVICE_URLREGISTRY_SERVICE_URL
Common Indexer
Relevant variables include:
INDEXER_URLINDEXER_LOGGING_ENABLED
Source References
indexer
indexer/src/processor.tsindexer/src/main.tsindexer/squid.yamlindexer/package.jsonindexer/schema.graphqlindexer/offchain-services/indexer/handlers/
common/indexer
common/indexer/build.gradle.ktscommon/indexer/src/main/resources/schema.graphqlscommon/indexer/src/main/resources/queries/common/indexer/src/main/kotlin/.../indexer/client/ApolloClientFactory.ktcommon/indexer/src/main/kotlin/.../indexer/client/ApolloResponseSanitizer.ktcommon/indexer/src/main/kotlin/.../indexer/client/ApolloLoggingInterceptor.ktcommon/indexer/src/main/resources/application-framework-indexer.yaml