Overview
The Hyperstack Rust DSL (Domain Specific Language) is a declarative syntax for defining streaming data pipelines. Using procedural macros, you describe what data you want from Solana, not how to fetch it.
Overview
Section titled “Overview”Instead of writing complex ETL pipelines with manual account parsing and event handling, the DSL lets you define:
- Entities — Structured data objects that project on-chain state
- Field Mappings — How data flows from Solana accounts into your entities
- Aggregations — Computed metrics that update automatically
- Resolvers — External data (like token metadata) enriched automatically
- Strategies — How incoming data merges with existing state
The macros transform your Rust code into a JSON-based stack spec (.stack.json), which Hyperstack compiles into optimized bytecode for real-time execution.
The DSL in Practice
Section titled “The DSL in Practice”#[hyperstack(idl = "my_program.json")]pub mod my_stream { #[entity] pub struct Token { // Map account fields directly #[map(my_program_sdk::accounts::TokenAccount::balance, strategy = LastWrite)] pub balance: u64,
// Aggregate events into metrics #[aggregate(from = my_program_sdk::instructions::Trade, field = amount, strategy = Sum)] pub total_volume: u64,
// Derive computed values #[computed(balance * price)] pub tvl: u64,
// Enrich with off-chain token metadata (name, symbol, decimals, logo) #[resolve(address = "So11111111111111111111111111111111111111112")] pub token_metadata: Option<TokenMetadata>, }}Key Concepts
Section titled “Key Concepts”Module-Level
Section titled “Module-Level”| Macro | Purpose |
|---|---|
#[hyperstack] | Entry point — defines the stream and links to data sources (IDL/Protobuf) |
Entity-Level
Section titled “Entity-Level”| Macro | Purpose |
|---|---|
#[entity] | Marks a struct as a data projection |
#[view] | Defines queryable views (list, state) for the entity |
Field-Level
Section titled “Field-Level”| Macro | Purpose |
|---|---|
#[map] | Maps fields from Solana account state |
#[from_instruction] | Extracts data from instruction arguments |
#[aggregate] | Computes running values (Sum, Count, etc.) |
#[event] | Captures instructions as structured events |
#[snapshot] | Captures complete account state |
#[computed] | Derives values from other entity fields |
#[derive_from] | Populates from instruction metadata |
#[resolve] | Fetches off-chain data via a named resolver |
Resolvers
Section titled “Resolvers”Resolvers are types that fetch external data server-side and deliver it as part of your entity. You attach them to fields using #[resolve].
| Resolver | Purpose |
|---|---|
TokenMetadata | Fetches SPL token metadata (name, symbol, decimals, logo) for a mint address via the DAS API. Also exposes ui_amount and raw_amount helper methods for use in #[computed] transforms. |
For example, the ORE stack resolves token metadata for the ORE mint at a known address:
#[resolve(address = "oreoU2P8bN6jkk3jbaiVxYnG1dCXcYxwhwyK9jSybcp")]pub ore_metadata: Option<TokenMetadata>,
// The resolved decimals can then be used in transforms:#[map(ore_sdk::accounts::Round::motherlode, strategy = LastWrite, transform = ui_amount(ore_metadata.decimals))]pub motherlode: Option<f64>,See Resolvers for the full reference.
Cross-Account Resolution
Section titled “Cross-Account Resolution”| Syntax | Purpose |
|---|---|
lookup_index(register_from = [...]) | Inline PDA resolution on #[map] fields (preferred) |
#[resolve_key] | Advanced: custom primary key resolution |
#[register_pda] | Advanced: manual PDA mapping registration |
Population Strategies
Section titled “Population Strategies”When data arrives, strategies determine how it’s merged with existing state:
| Strategy | Behavior | Example Use |
|---|---|---|
LastWrite | Overwrite with latest | Current balances |
SetOnce | Write only if empty | IDs, creation timestamps |
Sum | Add to existing total | Volume, TVL |
Count | Increment by 1 | Trade count |
Append | Add to list | Event history |
Max / Min | Keep extreme value | Price highs/lows |
Next Steps
Section titled “Next Steps”- Macro Reference — Complete documentation of every macro and its arguments
- Population Strategies — Deep dive into update strategies and when to use each
- Resolvers — Enrich entities with token metadata and computed fields