Automation
Nothing in Inference Markets needs an operator, but some things need someone to call them: a fresh index sample has to be requested and published, a peg has to be repriced when the feed moves, fees have to be collected before they can be claimed, the protocol's share has to be swept. Every one of those calls is a public function on a contract that anyone may send, and the contract itself decides what a call is allowed to do. Who sends it does not matter to the protocol, and the site offers a button for each one.
What has to be called
| Call | Who pays gas | When | What the contract enforces |
|---|---|---|---|
InferenceIndex.submitSample() |
the sampler only |
every hour | at most one sample per 55 minutes; the program and model lists come from on-chain config, so any sample can be rechecked |
InferenceIndex.publish() |
the caller | after each stored sample, once 24 are stored | pushes the median of the stored window and nothing else; reverts when there is no new sample, and during the first day of samples |
PegManager.reprice(coin) |
the caller | when needsReprice(coin) |
placement fully determined by the feed band; reverts on a stale feed |
PegManager.refill(coin) |
the caller | when needsRefill(coin) |
mints only up to the seed and only when the ask is below half of it |
Launchpad.collectFees(token) |
the caller | before a claim, or on a schedule | the 50 / 30 / 20 split and the token side in kind are fixed in code |
Distributor.claim(token, minOut) |
the holder | whenever | pays only the caller, only what the accumulator says |
Treasury.sweepToBuyback(token, coin, amount) |
the caller | when a ledger has value | floor: index value of the coin minus 2%, in ETH at Chainlink ETH/USD |
Treasury.sweepProtocol(token, coin, amount) |
the caller | when a ledger has value | the same floor; ETH goes to the protocol wallet |
Treasury.topUpVault(token, coin, amount) |
the caller | when coverageBps(coin) < 100% |
floor: index value minus 2%, in USDC; reverts at or above 100% coverage |
RedemptionVault.rebalance(coin) |
the caller | when needsRebalance(coin) |
one $2,000 tranche per five minutes, at no worse than the DIEM TWAP minus 400 bps; reverts inside the 20–40% band |
Buyback.execute(minOut) |
the executor | when the Buyback holds ETH | executor only, whole balance, caller-supplied floor |
Everything except claim (which pays the holder who calls it) and execute (which is the one gated call, see below) is open to any address.
What protects the protocol when a stranger calls
The rule is the same everywhere: the caller chooses whether a maintenance action happens, and never at what price.
Feed-derived floors. The Treasury computes its own minimum-out on every sweep from the coin's index price and the Chainlink ETH/USD price: MAX_SLIPPAGE_BPS is 200, so the sale must return at least 98% of the index value. There is no parameter for a caller to lower it. A synthetic coin usually sells at exactly the index anyway, because the router redeems it through the vault. The vault's rebalance floors every DIEM trade at the six-hour TWAP minus 400 bps, which covers the three Aerodrome hops and refuses anything worse.
Deterministic placement. reprice places the ask one tick spacing above the feed band and the bid one below, and nothing about the caller changes that. Calling it when nothing moved re-places the same liquidity in the same ticks. refill only mints up to the seed amount and only when the ask has fallen below half of it.
Gated by state, not by identity. topUpVault reverts unless that coin's coverage is below 100%, so protocol money cannot be moved into a vault that does not need it. rebalance reverts inside the band and within five minutes of the last call. publish reverts when there is no new sample and until a day of samples (24) is stored. submitSample reverts within 55 minutes of the last accepted sample, so the sampler cannot fill the window faster than the median can absorb it.
Fixed arithmetic. collectFees can only split the coin 50 / 30 / 20 and send the token side to holders; the caller does not choose amounts or recipients. publish can only push the median of what the sampler stored.
What a stranger can do is spend their own gas to make the protocol current. The floors above are what they trade against, and they are derived from the feeds rather than supplied by the caller, so the protocol realizes its share at the index and never more than 2% under it. That bound is the whole cost of having no operator.
Who pays
The caller pays gas for everything in the table. The sampler pays its own gas for each hourly submitSample, which on Base is cents a day, and there is no other external cost. A holder pays for their own claim, including the conversion inside it if they chose a payout asset. The executor pays for execute.
The site's buttons
The web reads the same needs* views the table uses and offers the call when it would do something:
- Publish on the units page, when
lastSampleAtis later thanlastPublishedAt. - Collect then claim on the rewards page, which sends
collectFeesand thenclaimso what you see accrued is what you receive. - Rebalance on the units page, when
needsRebalance(coin)is true.
The transactions are yours, signed by your wallet, and the contracts treat them exactly as they would treat anyone else's.
Cron and Chainlink Automation
A stateless script that reads needsReprice, needsRefill, needsRebalance, coverageBps, ledgerOf and the index timestamps, and calls whatever is due, can be run by anyone, in parallel with anyone else's, with no key beyond a funded gas wallet. Chainlink Automation can be pointed at the same functions. A reference script is planned under ops/ and is not yet written.
Neither is part of the trust model, which is the point. With no cron running at all, every position, every balance and every accrued reward stays exactly where it is: fees wait in the pool positions until someone collects, pegs hold their last band until someone reprices, and the class feeds carry a six-hour window that any address on earth can refresh with one transaction. A running cron keeps the numbers current, and anyone who wants them current can be the one running it.
The one gated call
Buyback.execute is the exception. It spends the protocol's own ETH on the ETH/INFERENCE v4 pool, whose price the protocol does not index, so there is no on-chain floor to derive; a caller has to supply one from a simulation. That caller is a single executor address the owner appoints. It can buy and burn, and nothing else: it holds no withdrawal path, reaches no other contract, and touches no holder and no price. $INFERENCE has the mechanics.