Testing
We provide a comprehensive testing suite for the whole Tycho stack. The suite facilitates end-to-end testing and ensures your protocol integration behaves as expected. For unit tests, please use standard Rust unit testing practices.
Find the suite in /protocol_testing.
What does the suite test?
There are two test modes:
range — indexes and validates test cases defined in
integration_test.tycho.yamlfor specific block ranges.full — indexes and validates the entire protocol history from creation to the latest block, without comparing specific component information.
Here's what the testing suite does:
Runs Tycho Indexer with your Substreams implementation for a specific block range. If running on the range test mode, it also verifies that the components' state matches the expected states specified by the testing YAML file. This confirms that your Substreams package is indexable and that it outputs what you expect.
Retrieves swap quotes using Tycho Simulation. This verifies that all necessary data for simulation is indexed and, for VM implementations, that the provided
SwapAdaptercontract works. It is important to know that the simulation engine runs entirely off-chain and only accesses the data and contracts you index (token contracts are mocked and don't need to be indexed)Encodes and simulates transactions using Tycho Execution against an RPC on an historical block. This ensures that your protocol swaps can be executed on chain and that the indexed data and quotes match onchain state and logic.
How to run
Prerequisites
Archive node
You need an EVM Archive node to fetch the state from a previous block (you can use Alchemy for example). If you index only with Substreams, as in Tycho's production mode, you must sync blocks since the protocol's deployment date, which can take a long time. The archive node skips this requirement by fetching all the required account's storage slots on the block you specify in the testing yaml file.
The node also needs to support the debug_storageRangeAt method, which is required for our Token Quality Analysis.
Test Configuration
Range Mode
Range mode tests specific block intervals to verify that your Substreams implementation correctly indexes and outputs expected component states. Please make sure that this block range is as small as possible so that the test runs quickly. The purpose of this test is to validate the logic on a few blocks only; for longer tests please see full mode test.
Configuration
Create an integration_test.tycho.yaml file in your Substreams directory with the following:
Target Substreams config file
SwapAdapterand construction arguments (for VM integrations)Protocol system identifier
Expected protocol types
Test cases to execute
How It Works
Each test validates your integration across the specified block range:
Index blocks: Indexes all blocks between
start-blockandstop-blockVerify state: Confirms the indexed state matches expected component creation
Simulate swap: Runs
get_amount_outsimulation (uses the providedSwapAdapterfor VM integrations)Execute swap: Encodes a single swap and simulates its execution
Validate consistency: Verifies that execution output matches simulation output
This ensures your indexing captures the correct protocol state and that simulation and execution remain consistent.
Full Mode
Full mode validates the complete protocol lifecycle—from indexing to live streaming—ensuring your integration works end-to-end in a production-like environment.
How It Works
1. Initial Indexing
The test indexes all blocks from start-block to the current block. Depending on the block range, this may take significant time.
Tip: Use the --reuse-last-sync flag to skip re-indexing on subsequent runs. This reuses the existing database state and syncs only new blocks, rather than starting from scratch.
2. Live Streaming
Once syncing catches up, the test begins streaming blocks live, simulating a production environment. For each block and each component, it:
Simulates
get_amount_outusing the current block stateEncodes a single swap and executes it in the current block
Verifies that the execution output matches the simulation output
This validates that your indexing, simulation, and execution implementations are consistent and correct.
⚠️ If you encounter issues running the full test, please contact us for support.
Test Parameters
Here are the test parameters that you need to set:
1. initialized_accounts
initialized_accountsThis is a list of contract addresses that simulation requires, although their creation is not indexed within the test block range. Leave empty if not required.
Importantly, you use this config during testing only. Your Substreams package should still properly initialise the accounts listed here. This configuration only eliminates the need to include historical blocks that contain the initialisation events in your test data. This ensures tests are targeted and quick to run.
You can use the initialized_accounts config at two levels in the test configuration file:
global: accounts listed here are used for all tests in this suite;
test level: accounts listed here are scoped to that test only.
2. expected_components (for range mode)
expected_components (for range mode)This is a list of components whose creation you are testing. It includes all component data (tokens, static attributes, etc.). You don't need to include all components created within your test block range – only those on which the test should focus.
3. skip_balance_check
skip_balance_checkBy default, this should be false. Testing verifies the balances reported for the component by comparing them to the on-chain balances of the Component.id . This should be false if:
the
Component.iddoes not correlate to a contract address;balances are not stored on the component's contract (i.e. they're stored on a vault).
If this skip is set to true, you must comment on why.
4. skip_simulation
skip_simulationBy default this should be false . It should only be true temporarily if you want to isolate testing the indexing phase only. If set to true, you must comment on why.
Code changes
If the protocol you are integrating is not a vm integration, to be able to test simulation, you need to register it in register_decoder_for_protocol (here). This is to match your protocol system name with the State that is used in Tycho Simulation.
5. skip_execution
skip_executionBy default this should be false . It should only be true temporarily if you want to isolate testing the indexing and simulation phases only. If set to true, you must comment on why.
To be able to test execution, you need to provide the executor's runtime bytecode file.
Export it using the helper script in tycho-execution/foundry/scripts/export-runtime-bytecode.js (see the README for instructions on how).
Copy
YourExecutor.runtime.jsonfile to the SDK repository intycho-protocol-sdk/evm/test/executors.Import the file in tycho-protocol-sdk/protocol-testing/src/execution.rs and add the corresponding entry to the
EXECUTOR_MAPPING.
Block Compatibility Requirements
The TychoRouter requires post-Cancun blocks for execution. Testing must use block numbers after the Cancun upgrade.
Testing during development
To test your protocol integration during development, update the tycho-simulation and tycho-execution dependencies in protocol-testing/Cargo.toml to point to your working branch/commit or to your local repository.
Example:
This allows you to iterate on your protocol implementation and run tests against your changes before submitting pull requests.
Running Tests
We offer two approaches for running tests: local run and Docker run.
Local run works best when you're actively developing your integration. You can test individual phases (indexing, simulation, execution) in isolation and get faster iteration cycles for debugging. However, you'll need to handle additional setup and prerequisites yourself.
Docker run suits CI environments and final validation. You run the complete end-to-end test suite in an encapsulated environment, which eliminates the setup complexity you'd face otherwise. The actual test execution is fast once you have the images built, but every time you change something in your package, you'll need to rebuild the images—and that's the slow part. This approach makes most sense once your package is stable.
Here is how you can run the tests with each approach:
Prerequisites:
Before continuing, ensure the following tools and libraries are installed on your system:
Docker: Containerization platform for running applications in isolated environments.
Git: Version control tool
Rust: Programming language and toolchain
GCC: GNU Compiler Collection
libpq: PostgreSQL client library
OpenSSL (libssl): OpenSSL development library
pkg-config: Helper tool for managing compiler flags
Substreams CLI: Indexing tool that uses Rust modules to process blockchain data.
Tycho Indexer: The testing module runs a minified version of Tycho Indexer. You need to ensure that the latest version is correctly setup in your PATH and if it isn't you need to (re)install Tycho. Run the following command on your terminal to check the version:\
Step 1: Export Environment Variables
RPC_URL: The URL for the Ethereum RPC endpoint. This fetches the storage data.
SUBSTREAMS_API_TOKEN: The JWT token for accessing Substreams services. This token is necessary for authentication. Please refer to the Substreams Authentication guide to set up and validate your token.
RUST_LOG: Defines the log level for test output. For enhanced debugging:
Indexer: Run the testing module with Tycho indexer logs enabled:
RUST_LOG=tycho_client=info,tycho_indexer=info,errorSimulation: Set the Tycho simulation module to debug level:
RUST_LOG=tycho-simulation=debug,infoExecution traces: Set the Tycho testing module to debug level:
RUST_LOG=tycho-testing=debug,info
Step 2: Build the substreams wasm file
If you do not have one already, you must build the wasm file of the substreams package you wish to test. This can be done by navigating to the substreams package directory and running:
Step 3: Run a local Postgres test database using docker-compose.
In /protocol-testing , run:
Step 4: Run tests
In /protocol-testing , run:
Select range or full depending on your test mode.
These are the optional arguments:
Complete example
If you want to run the range tests for ethereum-balancer-v2, use the following:
Prerequisites:
Before continuing, ensure the following tools and libraries are installed on your system:
Docker: Containerization platform for running applications in isolated environments.
Step 1: Export Environment Variables
RPC_URL: The URL for the Ethereum RPC endpoint. This fetches the storage data.
SUBSTREAMS_API_TOKEN: The JWT token for accessing Substreams services. This token is necessary for authentication. Please refer to the Substreams Authentication guide to set up and validate your token.
PROTOCOLS to test, separated by space and with optional filter.
Step 2: Build images
Build the image at the repository root path with:
Step 3: Run tests
In /protocol-testing, run:
Complete example
If you want to run tests for ethereum-balancer-v2, use the following:
Note that only range tests are supported with Docker.
Installing or updating the Tycho Indexer version (Optional)
If you're running on a MacOS (either Apple Silicon or Intel) - or any architecture that is not supported by pre-built releases, you need to compile the Tycho Indexer:
Step 1: Clone Tycho-Indexer repo
Step 2: Build the binary in release mode
Step 3: Link the binary to a directory in your system's PATH:
NOTE: This command requires /usr/local/bin to be included in the system's PATH. While this is typically the case, there may be exceptions.
If /usr/local/bin is not in your PATH, you can either:
Add it to your
PATHby exporting it:Or create a symlink in any of the following directories (if they are in your
PATH):
Step 4: Verify Installation
We provide a binary compiled for Linux x86/x64 architecture on our GitHub releases page.
This method will only work if you are running on a Linux with an x86/x64 architecture
Step 1: Download the pre-built binary
Navigate to the Tycho Indexer Releases page, locate the latest version (e.g.: 0.88.0) and download the tycho-indexer-x86_64-unknown-linux-gnu-{version}.tar.gz file.
Step 2: Extract the binary from the tar.gz
Open a terminal and navigate to the directory where the file was downloaded. Run the following command to extract the contents:
Step 3: Link the binary to a directory in your system's PATH:
NOTE: This command requires /usr/local/bin to be included in the system's PATH. While this is typically the case, there may be exceptions.
If /usr/local/bin is not in your PATH, you can either:
Add it to your
PATHby exporting it:Or create a symlink in any of the following directories (if they are in your
PATH):
Step 4: Verify Installation
Troubleshooting
Slow tests
An integration test should take a maximum 5–10 minutes. If the tests take longer, here are key things you can explore:
Ensure you have no infinite loops within your code.
Ensure you're using a small block range for your test, ideally below 1,000 blocks. The blocks in your test only need to cover the creation of the component you are testing. Optionally, they can extend to blocks with changes for the component you want the test to cover. To help limit the test block range, you could explore the initialized_accounts config.
Ensure you are not indexing tokens. Token contracts use a lot of storage, so fetching their historical data is slow. Instead, they are mocked on the simulation engine and don't have to be explicitly indexed. Make an exception if they have unique behavior, like acting as both a token and a pool, or if they are rebasing tokens that provide a
getRatemethod.
Note: Substreams uses cache to improve the speed of subsequent runs of the same module. A test's first run is always slower than subsequent runs, unless you change the Substreams module's code.
Account not initialised
There are two main causes for this error:
Your Substreams package is not indexing a contract that is necessary for simulations.
Your test begins at a block that is later than the block on which the contract was created. To fix this, add the missing contract to the initialized_accounts test config.
Dev Cluster Tests
After your protocol is moved to our dev environment, it will be subject to constant indexing, simulation, and execution testing via a constant running pod in our cluster. If we find problems in any of these areas, we may reach out to you for help debugging.
Last updated
Was this helpful?

