August 19, 2025
CLI v0.0.95
The Sim IDX framework has been updated with a new core import and a standardized function for accessing the block number in listener contracts.What’s new:
  • Core Import: All listeners should now include import "sim-idx-sol/Simidx.sol";. This file provides essential framework helpers required for core functionality.
  • blockNumber() Function: This function is now available to get the current block number. Use this instead of block.number for standardized access across all supported blockchains.
Impact:To use the blockNumber() function, listeners must include the sim-idx-sol/Simidx.sol import. Attempting to call the function without the import will result in a compilation error. Going forward, all listener contracts should adopt this pattern to access core framework features.
Example Listener
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.13;

+ import "sim-idx-sol/Simidx.sol";
  import "sim-idx-generated/Generated.sol";

contract MyListener is MyContract$OnMyEvent {
    event MyEvent(uint64 chainId, uint256 blockNum);

    function onMyEvent(
        EventContext memory /*ctx*/,
        MyContract$MyEventParams memory /*inputs*/
    ) external override {
        emit MyEvent(
            uint64(block.chainid),
-           block.number
+           blockNumber()
        );
    }
}
August 5, 2025
CLI v0.0.86
New Feature: Custom Block Range SupportYou can now specify custom block ranges for your triggers, allowing you to target specific blocks or time periods for each trigger.What’s new:
  • Chain helper functions now support .withStartBlock(), .withEndBlock(), and .withBlockRange() methods
  • Block range support for contract, ABI, and global targets
Examples:Range from Block Onwards
addTrigger(chainContract(Chains.Ethereum.withStartBlock(10000000), 0x1F98431c8aD98523631AE4a59f267346ea31F984), listener.triggerOnPoolCreatedEvent());
This creates a trigger that listens to events starting from block 10,000,000 onwards with no end block. The withStartBlock() method creates a BlockRange struct with BlockRangeKind.RangeFrom, meaning it captures all blocks from the specified start block to the latest available block.Inclusive Block Range
addTrigger(chainContract(Chains.Ethereum.withStartBlock(10000000).withEndBlock(10000001), 0x1F98431c8aD98523631AE4a59f267346ea31F984), listener.triggerOnPoolCreatedEvent());
This creates a trigger that listens to events only within blocks 10,000,000 to 10,000,001 (both inclusive). The withEndBlock() method modifies the BlockRange to use BlockRangeKind.RangeInclusive, creating a bounded range that stops processing after the end block.Using BlockRange Struct Directly
BlockRange memory range = BlockRangeLib.withStartBlock(100000).withEndBlock(10000001);
addTrigger(chainContract(Chains.Ethereum.withBlockRange(range), 0x1F98431c8aD98523631AE4a59f267346ea31F984), listener.triggerOnPoolCreatedEvent());
This demonstrates creating a BlockRange struct directly using the BlockRangeLib library functions before applying it to the chain. The BlockRange struct is available through the sim-idx-sol import. This approach gives you more flexibility to reuse ranges across multiple triggers or build complex range logic.
July 25, 2025
CLI v0.0.83
CallFrame Properties Are Now FunctionsEvery field on ctx.txn.call’s CallFrame structure has been updated to use function calls instead of direct property access.What changed:
Old (≤ v0.0.82)New (v0.0.83+)
ctx.txn.call.calleectx.txn.call.callee()
ctx.txn.call.callerctx.txn.call.caller()
ctx.txn.call.callDatactx.txn.call.callData()
ctx.txn.call.callDepthctx.txn.call.callDepth()
ctx.txn.call.valuectx.txn.call.value()
ctx.txn.call.callTypectx.txn.call.callType()
(new)ctx.txn.call.delegator()
(new)ctx.txn.call.delegatee()
ctx.txn.call.verificationSource is unchanged (still a property).Impact:If you were directly reading these fields, your code will no longer compile. Add () everywhere you touch ctx.txn.call.*.
Example (UniswapV3Factory Listener)
emit PoolCreated(
-     uint64(block.chainid), ctx.txn.call.callee, outputs.pool, inputs.tokenA, inputs.tokenB, inputs.fee
+     uint64(block.chainid), ctx.txn.call.callee(), outputs.pool, inputs.tokenA, inputs.tokenB, inputs.fee
);
July 23, 2025
CLI v0.0.82
New Feature: Database Indexing SupportYou can now define database indexes directly within your listener contracts. This gives you more control over your app’s query performance.What’s new:
  • Define indexes directly above your event declarations using a /// @custom:index comment in your Solidity code.
  • Support for multiple index types, including BTREE, HASH, BRIN, and GIN.
  • The sim build command now validates your index definitions to catch errors early.
Benefits:
  • Improved Query Performance: Significantly speed up data retrieval by indexing columns that are frequently used in your API queries.
  • Declarative and Convenient: Manage database performance directly from your Solidity code without writing separate migration scripts.
  • Fine-Grained Control: Apply the right index types to the right columns for optimal performance.
For more details on how to define indexes, see the Listener Features documentation.
July 16, 2025
CLI v0.0.79
Breaking Change: Generated Struct Names Now Include Contract NamesWith CLI version v0.0.79 and upwards, there will be a breaking change that impacts users who import and use generated structs from the ABI.Why this change was needed: The same struct name can be used across different contracts (example: GPv2Trade.Data and GPv2Interaction.Data within the same ABI) with different definitions. Using just the struct name for generated structs prevented proper triggering on protocols like CoW Swap.What changed: We now include the contract name as part of the struct name in the generated Solidity file associated with the ABI. Instead of using $AbiName$StructName for the names, we now use $AbiName$ContractName$StructName.Impact: If you have imported a generated struct, you’ll need to update the name to include the contract name the next time you run codegen. This doesn’t impact the default inputs/outputs/context structs, so most users won’t encounter this issue.Who is affected: You’ll only run into this issue if you:
  • Update to use CLI v0.0.79 or higher
  • Add a new ABI or manually run a new codegen
  • AND you’ve been using generated structs that aren’t the ones provided in the trigger inputs/outputs object (i.e., you’re using a nested struct from the inputs/outputs for some variable or part of the event)
July 15, 2025
CLI v0.0.78
New Feature: Multiple Listener Contracts SupportThe Sim CLI now supports defining multiple listener contracts within a single IDX application, enabling better code organization and structure.What’s new:
  • You can now define listeners in separate files instead of having everything in Main.sol
  • Listeners can be organized across multiple contracts for better code maintainability
  • The Main.sol file still needs to contain the Triggers contract, but individual listeners can be defined anywhere
  • Enhanced sim listeners evaluate command to target specific listeners for focused testing
Benefits:
  • Better Code Organization: Split large applications with many listeners into manageable, separate files
  • Improved Maintainability: Organize related listeners together (e.g., all DEX-specific listeners in one file)
  • Focused Testing: Evaluate specific listeners without noise from other listeners in your application
Migration:
  • Existing single-file applications continue to work without changes
  • Main.sol must still exist and contain your Triggers contract
  • Listener contracts can be moved to separate files as needed
This feature is particularly valuable for complex applications like DEX trade indexers that may have 15+ listeners and benefit from better file organization.
July 4, 2025
CLI v0.0.73
New Feature: Pre-Execution TriggersThe Sim CLI now supports pre-execution triggers, allowing you to execute code before a function runs instead of the default behavior of executing after.What’s new:
  • Pre-triggers use corresponding Pre- abstract contracts (e.g., preCreatePoolFunction)
  • Handlers receive a PreFunctionContext with access to function inputs only (outputs haven’t been generated yet)
  • Enables reactive logic that needs to run before the target function executes
Use cases:
  • Emit events or perform actions based on upcoming function calls
  • Pre-process or validate function inputs before execution
  • Set up state or conditions that the main function execution will depend on
For detailed implementation examples and usage patterns, see the Function Triggers documentation.