Skip to content
montra

For builders

Events to index

Everything that happens on Montra is announced on chain as an event, so an indexer can rebuild every token, trade and fee from the logs alone. Montra's own API is built that way.

Copy for AI
Every token
TokenLaunched
From the factory: the token, its pool, its terms and the first buy.
Every trade
Swap
From the PoolManager, filtered by pool id.
Each trade's fee
FeeAccrued
From the hook: the fee and the protocol's part, in the quote.
A new hook
ModuleSetPublished
From the factory, once it has checked the hook. The registry's HookAdded mirrors it.

Where to start

Start from the factory's TokenLaunched: it describes a launch in full, so describing a token never needs the factory's state. Trades are the pool manager's own Swap events. The hook's FeeAccrued comes once per swap, even when the fee rounds to zero, so it pairs with Swap one-to-one.

Read from the factory proxy's deployment block: nothing of the launchpad's comes before it. Read the whole of each launch's transaction, not from TokenLaunched on: the creator's first buy, its FeeAccrued and Swap among them, is logged before it. Every ABI to decode them with is at /docs/abis/events.json (Build on Montra).

The owned contracts also emit OpenZeppelin's ownership events, the factory its proxy's Upgraded, and every token the ERC-20 Transfer and Approval, and OpenZeppelin's Initialized once, as the launch sets it up.

What a trader paid: Swap and FeeAccrued

A v4 Swap shows the pool's side of a trade, and the hook's fee is outside it. Its amounts are signed as the swapper sees them, negative paid into the pool and positive paid out. On a buy, the pool sees what is left of the input once the hook has taken its fee; on a sell, the pool pays out the whole and the hook takes its fee from that. So a trader's own amounts are the Swap's quote amount plus FeeAccrued.fee on a buy and less it on a sell; the token amounts are exact either way. Montra's router reports a trader's amounts directly (Swapped), but a trade through any other router has only the two.

On the 2% tier, below the LP line, native quote as currency0

Swap.amount0 (the quote)
A buy of 0.25 HYPE−245000000000000000: what reached the pool
A sell of tokens+130124515828329726: what the pool paid out
FeeAccrued.fee
A buy of 0.25 HYPE5000000000000000 = ⌊250000000000000000 × 20,000 / 1e6⌋
A sell of tokens2602490316566594 = ⌊130124515828329726 × 20,000 / 1e6⌋
The trader's quote
A buy of 0.25 HYPEPaid 245000000000000000 + 5000000000000000 = 250000000000000000
A sell of tokensReceived 130124515828329726 − 2602490316566594 = 127522025511763132
Swapped (Montra's router only)
A buy of 0.25 HYPEamountIn 250000000000000000
A sell of tokensamountOut 127522025511763132

FeeAccrued comes before its Swap when the quote is the amount named (an exact-input buy, an exact-output sell) and after it otherwise: pair them by transaction, pool and zeroForOne, in order. Its amountSpecified is signed as v4 signs it, negative for exact input and positive for exact output. Swap.fee is v4's own swap fee, the LP fee (zero until the LP line) and Uniswap's protocol fee should that ever be switched on: never show it as the pool's fee.

A buy inside its pool's anti-snipe window pays a higher rate, and the same sum holds: its FeeAccrued.fee is that rate's fee, so the trader paid the Swap's quote amount plus it. protocolPart stays the protocol's own pips of the leg; the rest, the premium included, is the creator side's. The Swap itself never shows the premium, so a chart built from Swap events draws the pool's price, not what buyers paid. The window starts at the block time of the launch's PoolRegistered, which carries its start and length (The anti-snipe fee).

Every event

Factory

TokenLaunched(address indexed token, address indexed creator, bytes32 indexed poolId, uint256 configId, address quote, bool quoteIsCurrency0, uint256 supply, int24 startTick, address feeRecipient, bool feeLocked, uint256 firstBuyIn, uint256 firstBuyOut)
A token launches. Everything an indexer needs to describe it. firstBuyIn is the whole first buy, the swap's fee included, and firstBuyOut the tokens it bought after that fee; both are 0 with no first buy. The launch fee, native and apart, is in neither.
FeeSplitterDeployed(bytes32 indexed poolId, address indexed splitter, address[] recipients, uint16[] shares)
A split is created, at launch or after.
ConfigPublished(uint256 indexed id, LaunchConfig config) · ConfigEnabled(uint256 indexed id, bool enabled)
A launch tier is published, or switched on or off. A tier is published off, so enabled in ConfigPublished is always false: follow it with ConfigEnabled, or read getConfig(id).
ModuleSetPublished(uint256 indexed id, address indexed hook, address indexed tokenMaster, address splitterMaster)
A hook and the token and splitter masters it launches with are published.
LaunchEnabled(bool enabled) · LaunchFeeUpdated(uint256 oldFee, uint256 newFee) · LaunchFeeRecipientUpdated(address indexed oldRecipient, address indexed newRecipient) · QuoteRegistryUpdated(address indexed oldRegistry, address indexed newRegistry)
Launches are switched on or off, or the launch fee, where it is paid, or the quote registry changes.
LaunchFeesCollected(address indexed recipient, uint256 amount)
Launch fees are collected.

Launch hook

PoolRegistered(bytes32 indexed poolId, address indexed recipient, Registration registration) · PoolSeeded(bytes32 indexed poolId, int24 tickLower, int24 tickUpper, uint128 liquidity, uint256 dustBurned)
A pool's terms are recorded, and its seed placed, during its launch.
FeeAccrued(bytes32 indexed poolId, bool zeroForOne, int256 amountSpecified, uint256 fee, uint256 protocolPart)
Every swap, with the hook's fee in the quote and the protocol's part of it.
FeesSwept(bytes32 indexed poolId, address indexed caller, uint256 creatorAmount, uint256 protocolAmount) · SeedFeesHarvested(bytes32 indexed poolId, address indexed caller, uint256 quoteToCreator, uint256 tokensBurned)
Collected fees are booked, and the seed's LP fees harvested.
CreatorFeesClaimed(bytes32 indexed poolId, address indexed to, uint256 amount) · ProtocolCollected(address indexed currency, address indexed vault, uint256 amount)
The creator side is paid out, and the protocol's share sent to the vault.
RecipientUpdated(bytes32 indexed poolId, address indexed oldRecipient, address indexed newRecipient)
A pool's fees are handed to a new recipient.
TotalFeeUpdated(bytes32 indexed poolId, uint24 oldFee, uint24 newFee) · FeeLocked(bytes32 indexed poolId) · ProtocolFeeUpdated(bytes32 indexed poolId, uint24 oldFee, uint24 newFee)
A pool's fee is lowered or locked.
Graduated(bytes32 indexed poolId) · LpFeeActivated(bytes32 indexed poolId, uint24 lpFee)
A pool graduates, and its LP fee switches on.
ProtocolVaultUpdated(address indexed oldVault, address indexed newVault)
The vault the protocol's share is sent to changes.

Launch token

RewardsDistributed(uint256 received, uint256 streaming, uint64 periodFinish)
Fees arrive for the holders and a new stream starts.
ReceiptParked(uint256 received, uint256 parked) · ReleaseParked(uint256 amount)
A payment too small to restart the stream is parked, and later released into one.
RewardsClaimed(address indexed holder, uint256 amount) · RewardsPushed(address indexed holder, address indexed by, uint256 amount, uint256 bounty)
A holder claims, or is paid by a push. RewardsPushed's amount is what reached the holder, net of bounty, the pusher's fee.
RewardsPushSkipped(address indexed holder, uint256 amount) · RewardsCredited(address indexed pusher, uint256 fee)
A push could not pay a holder, or its pusher, who is credited the fee instead.

Fee splitter

SplitterInitialized(address indexed feeSource, bytes32 indexed poolId, address quote, address[] recipients, uint16[] shares)
A splitter is set up for its pool.
Distributed(uint256 amount) · ClaimFailed(bytes reason)
It pulls and divides the pool's fees, or could not pull them.
Collected(address indexed recipient, address indexed to, uint256 amount) · Rotated(uint256 indexed slot, address indexed oldRecipient, address indexed newRecipient)
A recipient collects its share, or hands on its slot.

Protocol fee vault

Allocated(address indexed currency, uint256 amount) · Delivered(uint256 indexed lane, address indexed currency, uint256 amount)
Revenue in a currency is divided among the lanes, or a lane's own asset sent to its destination.
HubSold(address indexed currency, uint256 amount, uint256 received, address indexed recipient, uint256[] sold, uint256[] credited)
A hub sale: a currency sold for HYPE, each lane debited and credited in proportion.
Withdrawn(uint256 indexed lane, address indexed currency, address indexed to, uint256 amount) · Released(uint256 indexed lane, address indexed currency, uint256 amount, uint256 delivered)
A withdrawing lane's destination is paid, or a converting lane's revenue goes to the converter and its own asset reaches the lane's destination.
LaneAdded(uint256 indexed lane, address indexed to, address want, bool converts) · LaneUpdated(uint256 indexed lane, address indexed to, address want, bool converts)
A lane is added or repointed: where it pays, in what asset, and whether it converts.
SharesUpdated(uint16[] shares) · FloorRaised(uint256 indexed lane, uint16 floorBps) · DirectUpdated(uint256 indexed lane, address currency)
The lanes' shares are retuned, a lane's least share is raised for good, or a lane names the one currency it sells straight for its own asset.
ConverterUpdated(address indexed oldConverter, address indexed newConverter)
The vault names what converts its lanes' revenue; naming none stops every sale.

Fee market

MarketOpened(bytes32 indexed market, uint8 kind, uint256 lane, address sell, address want, uint256 anchor)
A sale opens: a hub sale of a currency for HYPE, or a lane's sale for its own asset.
Take(bytes32 indexed market, address indexed taker, address recipient, uint256 amount, uint256 price, uint256 owe, uint256 left, uint256 level)
A take from a sale: what was bought, at what price, what is left and where the price falls from next.
AnchorPosted(bytes32 indexed market, uint256 reading, uint256 anchor, bool halted, bool restarted) · AnchorReset(bytes32 indexed market, uint256 anchor)
A sale's reference moves, or is reset.
PausedSet(bytes32 indexed market, bool paused) · ParamsSet(bytes32 indexed market, Params params) · DripSet(bytes32 indexed market, uint256 perDay) · TakerSet(bytes32 indexed market, address taker)
A sale is paused or resumed, retuned, given a daily cap, or given an only taker.
ReporterSet(address indexed reporter, bool approved, uint256 epoch) · GuardianSet(address indexed guardian)
A reporter is approved or removed (removing one that has posted starts a new epoch, and every reference posted before goes stale), or the guardian is named.

Fillers and the burner

Filled(bytes32 indexed market, uint256 amount, uint256 owe, uint256 out, address surplusTo)
A sale filled through the route filler: what it took, what the sale was paid, what the route returned and where the surplus went.
Bought(bytes32 indexed market, uint256 amount, uint256 owe, uint256 out, address to) · Burned(uint256 amount, uint256 rewards)
The buyback filler buys MONTRA, and the burner destroys it, paying what it earned as a holder to the vault.

Router, registries

Swapped(bytes32 indexed poolId, address indexed sender, address indexed recipient, bool zeroForOne, uint256 amountIn, uint256 amountOut)
A trade through Montra's router, with what was actually spent.
AddressSet(bytes32 indexed key, address indexed previous, address indexed current) · HookAdded(address indexed hook)
The registry names an address under a key, or lists a new hook.
QuoteRegistered(address indexed asset, uint8 decimals, int24 defaultTickSpacing, string symbol) · QuoteEnabled(address indexed asset, bool enabled)
An asset is listed as a quote, or switched on or off for new launches.

For integrators

Terminals, wallets and apps can build on the pools without asking anyone: start with Build on Montra, Contract reference and Public API.

A product that brings launches earns a share of their fees: the Builder programme.

To talk to the team: @MontraXYZ on X.

For AI tools

Every page as Markdown in llms.txt, and all of it in one file at llms-full.txt.