listeners/
folder fits into your Sim IDX app.listeners/src/
.
Contract | Purpose | Location |
---|---|---|
Triggers | Registers all triggers via addTrigger . Must be named Triggers and defined in Main.sol . | listeners/src/Main.sol |
Listener(s) | One or more contracts that implement handler logic and emit events. They can have any name and be defined in any .sol file within listeners/src/ . | listeners/src/ |
Main.sol
file from the sample app down step-by-step.
Simidx.sol
provides core helpers, while Generated.sol
contains the Solidity code created from your ABIs.
The ./UniswapV3FactoryListener.sol
import brings in the listener contract from a separate file.
Triggers
contract must be named Triggers
and must be located in listeners/src/Main.sol
.
chainAbi
and chainGlobal
.
For other trigger types, see the Listener Features page.BaseTriggers
: An abstract contract from Simidx.sol
that provides the addTrigger
helper.triggers()
: The required function where you register all your triggers.new UniswapV3FactoryListener()
: The listener contract is instantiated from its own contract type.chainContract(...)
: This helper function uses the Chains
enum for readability. The sample app registers the same trigger for Ethereum, Base, and Unichain, demonstrating how to monitor a contract across multiple networks.listeners/src/UniswapV3FactoryListener.sol
.
UniswapV3Factory$OnCreatePoolFunction
) that is automatically generated from your ABI. This provides the required handler function signature and typed structs for inputs
and outputs
.PoolCreated
defines the shape of your database.UniswapV3FactoryListener
.
You should use descriptive names for your contracts.
For larger projects, you can even split logic into multiple listener contracts, each in its own .sol
file within the src/
directory.
snake_case
to become the view name, and each event parameter becomes a column.
For example, the PoolCreated
event from the sample app results in a queryable pool_created
view:
chain_id | caller | pool | token0 | token1 | fee |
---|---|---|---|---|---|
1 | 0x1f98431c8ad98523631ae4a59f267346ea31f984 | 0xf2c1e03841e06127db207fda0c3819ed9f788903 | 0x4a074a606ccc467c513933fa0b48cf37033cac1f | 0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2 | 10000 |
emit
statement in your handler. Let’s modify the sample app to also record the block number.
1. Extend the Event Definition
Add the new blockNumber
parameter to your PoolCreated
event in Main.sol
.
onCreatePoolFunction
handler.
pool_created
table will automatically include the new block_number
column.
addTrigger
in your Triggers
contract to activate the trigger.UniswapV3FactoryListener
contract.
We will extend the Listener
to also index the OwnerChanged
event from the Uniswap V3 Factory.
listeners/lib/sim-idx-generated/UniswapV3Factory.sol
. You will find an abstract contract for the OwnerChanged
event.
UniswapV3Factory$OnOwnerChangedEvent
to the inheritance list of the UniswapV3FactoryListener
contract in UniswapV3FactoryListener.sol
.
UniswapV3FactoryListener
contract, add a new event to define the schema for the owner_changed
table.
onOwnerChangedEvent
function required by the abstract contract, also inside UniswapV3FactoryListener
.
Triggers
contract within Main.sol
. You will need to instantiate the listener first.
onCreatePoolFunction
. The handler is called after the contract’s function completes, so it has access to both inputs
and outputs
.
Pre-Execution: To react to a function before it executes, you use the corresponding Pre-
abstract contract (e.g., preCreatePoolFunction
). The handler receives a PreFunctionContext
and only has access to the function’s inputs
, as outputs have not yet been generated. This logic can live in its own file.
Triggers
contract inside Main.sol
.
listeners
folder is a Foundry project. sim test
is a thin wrapper around forge test
. It will compile your contracts, execute all Forge unit tests inside listeners/test/
, and surface any failures.
sim listeners evaluate
to see how your listener reacts to real onchain data before pushing your updates. This command compiles your listener and executes the transactions in any block range you specify.
--listeners
flag specifies which listener contract to evaluate. You can update this to match your specific listener contract name. Visit the sim listeners evaluate
documentation to learn more about the available flags.