What we’re building
A drift-trigger rebalance pair. The strategy contract holds an idle reserve (vault_free_assets = on-chain balanceOf(strategy)). When that reserve drifts above 10% of vault TVL there is excess idle to deploy, so a DEPOSIT strategy fires and pushes it into a single yield source (“Yield Source A”). When the reserve drifts below 5% of TVL the vault is liquidity-thin, so a WITHDRAWAL strategy fires and pulls assets back from Yield Source A to refill the buffer toward a 7.5% target.
Two strategies, one yield source, one EXPR rule each, no indicators.
Step 1 — Understand the lanes
Strategy actions group into three priority lanes. Which lane your action lives in determines which UI column it shows up in and how ordering works.
Full lane reference: Strategy Canvas.
Step 2 — Pick the action
Each strategy has exactly oneaction_config.action. Pick DEPOSIT for the inflow strategy and WITHDRAWAL for the outflow strategy. The other required action_config fields tell the OMS how to execute:
execution_name— the hook identifier from the Erebor hook registry (ApproveAndDeposit4626VaultHookandApproveAndWithdraw4626VaultHookfor ERC-4626 sources).execution_address— the deployed hook contract on the target chain.target_address— the yield source you’re moving assets into or out of.from_address— the account that executes the intent.target_type— the yield source family (erc4626here).objective—MIN_SLIPPAGE,MIN_TIME, orBALANCED.
Step 3 — Write the trigger
The trigger is arules tree. The simplest form is a single EXPR leaf that returns a boolean.
vault_free_assets is sourced live from chain as IERC20(asset).balanceOf(strategy) through the EVM RPC datafeed, so the trigger reflects the strategy contract’s actual idle balance. vault_tvl is derived from yield-source allocations on the subgraph cadence. Both are in the underlying asset’s base units.
The full EvalSnapshot variable list (vault_*, ys_<addr>_*, merkl_*, tick_*, indicator aliases) lives in the strategy schema reference.
Step 4 — Size the action
action_config.size_expr is a separate expression evaluated when the rule fires. It must return a positive number at runtime — that’s the amount, in base units, sent to the OMS.
For the deposit half we deploy everything idle:
size_expr that evaluates to ≤ 0 at runtime is dropped before reaching the OMS.
Indicators (SMA, RSI, MACD, etc.) and conviction tuning (graded confidence, dead bands) are out of scope here — they live in the Cookbook and Conviction pages.
Step 5 — Full strategy JSON
These two payloads are the literal contents ofsuperman-strategy/testdata/cookbook/drift_rebalance_{deposit,withdraw}.json and are asserted by CI to pass the engine’s StrategyValidator on every push.
Replace 0x000…0001 with the real yield source address, the 8453:0xdef… vault id with yours, and from_address / execution_address with the values from your environment.
Deposit half
Withdrawal half
Step 6 — POST it
Each strategy is onePOST /api/v1/strategies call. Save the deposit payload to deposit.json, then:
withdraw.json. A 200 returns the persisted strategy with state: "CREATED". To start ticking, transition each one:
What to watch
Once both strategies areRUNNING, the Dashboard and Intent History views surface what’s happening:
- Strategy Canvas — both strategies should show in their respective lanes in
RUNNINGstate with priority assigned. - Dashboard —
vault_free_assets / vault_tvlshould oscillate between roughly 5% and 10%, settling near 7.5% after the first few rebalances. - Intent History — every fired rule produces an intent. Look for
DEPOSITintents when reserve was high andWITHDRAWALintents when it was low. Inspect events and fills per intent to confirm OMS execution succeeded. - Emergency locks — if a paired emergency exit is armed on Yield Source A, the deposit half is blocked from publishing new intents while the lock holds. The withdrawal half remains operable.
Common rejections
The validator runs atPOST and PUT time only. Most first-time rejections fall into a handful of buckets — unknown identifier, division-by-zero in a dry-run, missing objective, non-hex address. The full list with example error strings is on the Troubleshooting page.