Skip to content

Commit b26907d

Browse files
authored
Merge pull request #1 from onflow/jribbink/automation-spec
Add Vault Rebalancer Automation Spec
2 parents 98a15b5 + 45cd091 commit b26907d

1 file changed

Lines changed: 56 additions & 0 deletions

File tree

docs/vault-rebalancer.md

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
# Vault Rebalancer
2+
3+
**Status:** Draft
4+
**Owner:** @Jordan Ribbink
5+
6+
A Cadence resource that pokes a single Solidity function on an interval via [`FlowTransactionScheduler`](https://github.com/onflow/flips/blob/main/protocol/20250609-scheduled-transactions.md) (FLIP 330).
7+
8+
## Assumptions
9+
10+
- **EVM-side errors don't panic the scheduled tx.** `coa.call` surfaces revert/OOG as a non-successful `EVM.Result`, never as a Cadence panic. The failure model rests on this — without it, an EVM revert would abort the scheduled tx before it can self-reschedule, killing the chain.
11+
- **Off-chain tick liveness monitoring exists.** Several failure modes (scheduler unavailability, fee-vault depletion, COA depletion) are detectable only as missing events; operators must observe staleness and trigger recovery before LTV drifts to liquidation.
12+
13+
## What we require from the EVM contract
14+
15+
- **`rebalance()` is idempotent and self-guarding** — it inspects vault state and either acts or no-ops.
16+
- **`rebalance()` is permissionless** — callable by any EOA.
17+
- **The COA's EVM-side authority is narrow** — restricted to invoking `rebalance()` only (no admin or fund-movement entrypoints). This bounds the blast radius of an admin-compromised config rewrite to liveness impact.
18+
19+
## Design
20+
21+
One Cadence resource per EVM target, owned by an admin account. Stored at a deterministic path derived from the EVM target address.
22+
23+
- Holds a `Capability<auth(EVM.Call) &EVM.CadenceOwnedAccount>` — the EVM caller identity used to invoke `rebalance()`.
24+
- Identity config (target address, calldata, scheduler priority) is immutable; changing any requires destroy + recreate. Tunable config (tick interval, EVM gas limit, execution effort) is mutable via an admin-entitlement-gated setter per field.
25+
- On each tick: `coa.call(...)` against the EVM contract; emit one event for the EVM-side outcome; self-reschedule via `FlowTransactionScheduler.schedule(...)` with the current config.
26+
- Self-rescheduling failures (insufficient FLOW, invalid capability) emit an event and halt the loop. The restart entry point is permissionless and idempotent — anyone can resume scheduling once the underlying condition is resolved.
27+
28+
**Scheduler priority.** The rebalancer uses Medium: it defers under slot contention but never rejects at submission (see *Scheduler availability* below).
29+
30+
**Effort and gas sizing.** EVM `gasLimit` bounds the EVM call's worst-case cost; the Cadence `executionEffort` budget is sized to cover that bound plus the self-reschedule tail, with margin skewed larger on the Cadence side. EVM out-of-gas just fails the EVM call (surfaced as a non-successful `EVM.Result`) and the next tick retries, but Cadence out-of-effort would abort the entire scheduled tx atomically — including the EVM call — stopping the chain. Values are calibrated from measured worst-case `rebalance()` cost and must be re-tuned if governance changes Cadence execution-effort weights. The self-reschedule tail also includes an internal slot search under Medium-priority contention whose effort consumption grows with distance to the next free slot; margin must accommodate this on top of the EVM call's worst-case cost (see *Scheduler availability*).
31+
32+
**Scheduler availability.** `FlowTransactionScheduler` is best-effort under slot contention — sustained contention can delay the next tick or temporarily halt the self-reschedule loop until manually restarted. Damage is bounded to liveness; the canonical recovery is direct (permissionless) `rebalance()` invocation on the EVM contract. Off-chain tick liveness monitoring is required.
33+
34+
## Failure modes and recovery
35+
36+
| Failure | Observable | Recovery |
37+
| :--- | :--- | :--- |
38+
| EVM call fails, transient (slippage, momentary state, out-of-gas) | Tick event with EVM error code | Next tick retries automatically; persistent OOG requires admin to raise the EVM gas limit |
39+
| EVM call fails, sustained (role revoked EVM-side, persistent Solidity-side condition) | Tick event repeats with non-zero error code N ticks in a row | Admin addresses EVM-side condition (restore role, resolve Solidity state) |
40+
| Fee vault depletion (Cadence scheduling fees) | Failure event with insufficient-FLOW reason; absence of subsequent scheduled events triggers alert | Admin tops up; signs tx to re-invoke self-reschedule |
41+
| COA FLOW depletion (EVM-side gas) | Tick events repeat with non-zero EVM error code; off-chain balance script catches drift earlier | Anyone can send FLOW to the COA (permissionless, from either Cadence or EVM) |
42+
| Cadence-side OOE (effort margin too tight) | Absence of expected events for the scheduled tx; rebalancer stops ticking | Admin re-invokes self-reschedule; retune effort margin if recurring |
43+
| Sustained scheduler unavailability | Tick events absent or persistently delayed; tick liveness monitor alerts | Anyone invokes `rebalance()` directly on the EVM contract; permissionless restart resumes ticking once contention clears |
44+
45+
**Failure scope.** No single failure causes immediate solvency loss; failures degrade first to liveness. Prolonged outage can drift LTV and trigger Morpho liquidation under adverse prices, on a horizon set by market parameters and volatility — not by this design.
46+
47+
---
48+
49+
## Future scope
50+
51+
Possible evolutions of this design — none load-bearing for v0.2:
52+
53+
- **Config hardening.** Multisig/timelock on the setter entitlement, or pushing more fields toward immutability; fully-immutable redeploy-only may require self-replenishing funding to be practical.
54+
- **Self-replenishing funding.** Fee top-ups sourced from a vault-level fee buffer or treasury sweep rather than admin out-of-band top-ups.
55+
56+
If business logic ever moves to Cadence, the failure model fundamentally changes. The principle worth preserving: split scheduling and business logic into separate scheduled transactions, so a panic in the work doesn't take down the rescheduling loop.

0 commit comments

Comments
 (0)