Auto-fund
The runtime pre-funds the PredictManager before mints, so a plugin never has to bundle pmDeposit by hand.
Before a mint, the runtime pre-funds the PredictManager (PM) automatically, so your plugin never has to bundle pmDeposit by hand. It looks like a small ergonomic win, and it is, but it touches pricing, market impact, and a few opt-out paths worth understanding before you move money.
The flow
plugin.decide(ctx) → Action[]
→ filters noop
→ maybeInsertAutoFund:
short-circuits, in this order:
1. autoFundMints === false → proceeds untouched
2. batch already has vault.pmDeposit → proceeds (you own the funding)
3. no qualifying mint → proceeds
4. vault without predict_manager_id → THROW
otherwise: quotes each mint, sums cost + buffer, reads the PM balance,
and prepends pmDeposit(gap) if there's a shortfall
→ checks permission for each action (including the prepended pmDeposit)
→ builds the PTB, submits (or dry-runs)Detection precedence
The 4 short-circuits matter because each has a different blast radius:
1. autoFundMints: false is the kill switch for the whole runner. Use it when you have your own funding policy outside the runtime and don't want it guessing. 2. A manual vault.pmDeposit in the batch is opt-out by intent: the runtime defers entirely and doesn't even quote. Careful, it does not check whether the deposit covers the mints. Deposit 100 for mints that need 120 and the tx aborts on-chain. 3. No qualifying mint, after filtering out skipAutoFund: true on each action. Useful for a hybrid batch, some mints pre-funded and others via auto-fund. 4. A vault without a PredictManager throws. It's the only gate that errors instead of skipping silently, because without a PM there's nothing to fund.
Gates 2 and 3 skip silently on purpose (they're builder choices). Gate 4 is a config inconsistency and deserves a loud failure.
The buffer
autoFundBufferBps (default 200 = 2%) is added on top of the quoted cost:
totalWithBuffer = totalCost + (totalCost × autoFundBufferBps) / 10_000
gap = totalWithBuffer - pmBalance (when pmBalance < totalWithBuffer)The buffer exists because of market impact. get_trade_amounts quotes the price pre-insert ("what does this order cost against the current book?"), but the mint executes post-insert. By the time your order hits the book, your own size has already moved the price against you, and the gap is the impact you caused.
Calibration heuristics (operational, not hard rules):
| Trade vs AUM | Typical impact | Recommended buffer |
|---|---|---|
| ≤ 0.5% of AUM | < 50 bps | 200 (default) is enough |
| 1–3% of AUM | 50–200 bps | 300–500 |
| 3–5% of AUM | 200–500 bps | 500–800, consider splitting |
| > 5% of AUM | 500+ bps, may abort | Don't use auto-fund; pre-deposit with skipAutoFund |
Above 5%, no static buffer reliably covers it (slippage grows non-linearly). Pre-fund the PM with headroom across several ticks instead of aiming for per-tick precision.
new Runner({
autoFundBufferBps: 500, // 5% for larger vaults
});Opt-out cookbook
Skip auto-fund for a single mint in a managed batch: set skipAutoFund: true in the mint's params.
Deposit manually in one PTB: prepend { kind: "vault.pmDeposit", params: { amount } }. Its presence triggers gate 2, so the runtime defers and you own the math.
Turn it off globally with new Runner({ autoFundMints: false }). Every mint then flows through with no pricing or balance check, so the PM had better have a balance or each mint aborts.
Debug
- Prepended an unexpected deposit: look for
auto-fund: prepending pmDeposit(levelinfo). It carriesmintCount,totalCost,bufferBps,pmBalance,gap. - Decided not to deposit:
auto-fund: PM has enough(leveldebug). - Throw, plugin unhealthy:
pricing failed ... EFairPriceAlreadySettledmeans a mint targets a strike outside the oracle's valid range. Filter strikes againstmarket.maxStrike/minStrikebefore returning the action, or usestrikeAtSigma, which clamps on its own.
When auto-fund is the wrong tool
It's the right default for most strategies: signal-driven mints, predictable size, reasonable headroom. It's wrong when the strategy mints continuously and needs the PM exactly drained at the end of a session (auto-fund over-funds by bufferBps every tick), when multiple operators contend for the same PM (race conditions), or when the trade is too large (>5% AUM). In those cases, autoFundMints: false plus explicit pmDeposit/pmWithdraw orchestration wins. Auto-fund is a safety net, not a strategy.