Tycho
  • Quickstart
  • Overview
  • Motivation
  • Concepts
  • How to Contribute
    • Bounties
  • For Solvers
    • Indexer
      • Tycho RPC
      • Tycho Client
        • Binary / CLI
        • Rust Client
        • Python Client
    • Simulation
    • Execution
      • Encoding
      • Executing
      • Contract Addresses
      • Execution Venues
    • Hosted Endpoints
    • Supported Protocols
  • For DEXs
    • Protocol Integration
      • Indexing
        • 1. Setup
        • 2. Implementation
        • 3. Testing
          • How to Run
        • Common Problems & Patterns
          • Tracking Components
          • Tracking Contract Storage
          • Normalizing relative ERC20 Balances
          • Tracking Contract Balances
          • Custom protobuf models
        • Best Practices
        • Reserved Attributes
      • Simulation
        • Ethereum: Solidity
      • Execution
        • Code Architecture
      • Contributing guidelines
Powered by GitBook
On this page
  • Factory protocols
  • Other protocols
Export as PDF
  1. For DEXs
  2. Protocol Integration
  3. Indexing
  4. Common Problems & Patterns

Tracking Contract Storage

PreviousTracking ComponentsNextNormalizing relative ERC20 Balances

Last updated 2 months ago

This implementation pattern is, by default, used in both the and the templates.

In VM implementations, accurately identifying and extracting relevant contract changes is essential.

The tycho_substreams::contract::extract_contract_changes helper function simplifies this process significantly.

Note: These contract helper functions require the extended block model from substreams for your target chain.

Factory protocols

In factory-based protocols, each contract typically corresponds to a unique component, allowing its hex-encoded address to serve as the component ID, provided there is a one-to-one relationship between contracts and components.

The example below shows how to use a component store to define a predicate. This predicate filters for contract addresses of interest:

use tycho_substreams::contract::extract_contract_changes;

// all changes on this block, aggregated by transaction
let mut transaction_changes: HashMap<_, TransactionChanges> = HashMap::new();

extract_contract_changes(
    &block,
    |addr| {
        components_store
            .get_last(format!("pool:{0}", hex::encode(addr)))
            .is_some()
    },
    &mut transaction_changes,
);

Other protocols

For protocols where contracts aren't necessarily pools themselves, you'll need to identify specific contracts to track. These addresses can be:

  1. Hard-coded (for single-chain implementations)

  2. Read from the storage of a known contract (hardcoded or configured)

Here's how to extract changes for specific addresses using configuration parameters:

// substreams.yaml
...

networks:
  mainnet:
    params:
      map_protocol_changes: "vault_address=0000,swap_helper_address=0000"

...
// map_protocol_changes
use tycho_substreams::contract::extract_contract_changes;

// all changes on this block, aggregated by transaction
let mut transaction_changes: HashMap<_, TransactionChanges> = HashMap::new();

// *params* is a module input var
let config: DeploymentConfig = serde_qs::from_str(params.as_str())?;
extract_contract_changes_builder(
    &block,
    |addr| {
        addr == config.vault_address
        || addr == config.swap_helper_address
    },
    &mut transaction_changes,
);

Configured via parameters in your file (for chain-agnostic implementations)

ethereum-template-factory
ethereum-template-singleton
substreams.yaml