feat(vault-v1-reallocation): migrate vault v1 reallocation bot - #165
feat(vault-v1-reallocation): migrate vault v1 reallocation bot#165haydenshively wants to merge 14 commits into
Conversation
Widen Policy.executor to Address | readonly Address[] so a bot whose transactions target a set of contracts (e.g. whitelisted vaults) can keep the default-deny pre-broadcast guard. Single-address callers are unchanged. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Drop the dead share fields from MarketState, convert the cap buffer to a WAD once at strategy construction, gate equalize's min-delta trigger on actual contribution (mirroring apy-range), drop a redundant idle flag re-check, and stop repeating the full plan in the dry-run log line. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…econciler Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
💡 Codex Reviewmorpho-bots/bots/vault-v1-reallocation/docker-compose.yml Lines 15 to 16 in 622f3eb When an operator sets the documented morpho-bots/bots/vault-v1-reallocation/src/strategies/reconcile.ts Lines 78 to 80 in 622f3eb When one side has more candidate liquidity than the other, a later market can have morpho-bots/bots/vault-v1-reallocation/scripts/deploy-railway.ts Lines 49 to 52 in 622f3eb When required configuration is missing or a Railway CLI operation fails, this new script throws plain AGENTS.md reference: AGENTS.md:L43-L50 This utility and the other helpers added throughout the deployment script are function declarations, contrary to the repository's mandatory arrow-utility convention. Convert them to AGENTS.md reference: AGENTS.md:L51-L52 morpho-bots/bots/vault-v1-reallocation/src/config.ts Lines 79 to 84 in 622f3eb When an integer environment variable contains enough digits, the regex accepts it but AGENTS.md reference: AGENTS.md:L155-L156 morpho-bots/bots/vault-v1-reallocation/scripts/deploy-railway.ts Lines 87 to 89 in 622f3eb The deployment path validates the private key with a local hexadecimal regex even though repository policy requires viem for hex parsing, validation, and byte sizing. Use viem's hex validation and size utilities here so provisioning and runtime validation share the repository's canonical semantics instead of maintaining a second parser. AGENTS.md reference: AGENTS.md:L53-L54 ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
If Codex has suggestions, it will comment; otherwise it will react with 👍. Codex can also answer questions or update the PR. Try commenting "@codex address that feedback". |
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
Review feedback addressed in e03c88e:
81 bot tests green (+2), existing tests unmodified, typecheck/lint/knip clean. |
cashd
left a comment
There was a problem hiding this comment.
approved for OSS as a reference
cashd
left a comment
There was a problem hiding this comment.
Read through the whole thing plus a pass over the shared bot-kit changes — nice port, the reconciler split and the SDK-first math read well. One real bug (the WAD withdraw target), a few efficiency things on the hot path, and a batch of nits. Numbered inline.
Deliberately not raising here, will file as follow-ups: the env-parser / Railway-helper copies (3rd/5th copy, but that's the documented per-bot convention) and the deploy/release job copies → matrix.
…zation A WAD target sizes a withdrawal to the market's entire free liquidity, which reverts on the first wei of accrual — and the AdaptiveCurve inverse legitimately produces WAD bounds on cold markets. Clamp every classifier target at 99.9% in the reconciler. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Migrates the standalone morpho-blue-reallocation-bot (Vault V1 / MetaMorpho reallocation) into the monorepo as
bots/vault-v1-reallocation, modeled on the liquidation bots' flat bots-as-programs shape and the shared@repo/bot-kitruntime.What's here
apy-range(per-market borrow-APY ranges via the AdaptiveCurveIRM inverse, idle-market absorption) andequalize-utilizations(vault-wide average utilization), rewritten from classes to config-injected closures. Local WAD/IRM math replaced with@morpho-org/blue-sdk'sMathLib/AdaptiveCurveIrmLib(SDK-first; equivalence verified numerically — the only intentional delta is clamping >100% utilization to the curve's max rate, matching the old code).REALLOCATION_INTERVAL_MStime gate on the reallocation pass (resolves the old repo's seconds-vs-minutes interval bug by construction); signer with default-deny policy (targets = vault whitelist, selector =reallocate, computed from the ABI); pending queue with fee bumps/nonce reconciliation; balance + heartbeat monitors; structured JSON-lines events with a widetick.endcounters line.Policy.executorwidened toAddress | readonly Address[]with a membership check — this bot signs to N whitelisted vaults. Existing single-address consumers compile unchanged; empty list denies everything (tested).DRY_RUNmode (full live read→strategy→encode→simulate, logs the plan, never submits) as the operator ramp-up story — compose and the Railway deploy default new services to dry-run.deploy-railway.ts, CI wiring (vault-v1-reallocin deploy-bot/staging/production + CalVer release job).src/strategy-config.ts, market > vault > env-default precedence) — the old repo's stale per-vault entries were deliberately not carried over.Deliberately dropped from the old repo
apps/configpackage,script.ts, local MorphoBlue/AdaptiveCurveIrm ABIs, multi-chain-in-one-process,Promise.allvault fan-out, bareestimateGas+writeContracttx path, console logging, and the anvil fork suites (follow-up;@morpho-org/test+ vault-factory harness deliberately deferred —DRY_RUNagainst a live RPC is the current end-to-end check).Also fixes two latent old-repo bugs: the equalize min-delta override was looked up by market id against a vault-keyed table (never matched), and an empty vault whitelist silently no-oped (now fails loud).
TIB decision
docs/decisions/TIB-2026-08-17-vault-v1-reallocation-bot.md— records the migration onto the flat bots-as-programs shape, SDK-first math, thePolicy.executortarget-set widening, template-not-verbatim strategy tables, deferred fork tests withDRY_RUNas the ramp-up story, and the enforced AdaptiveCurveIRM-only assumption. (Originally shipped without a TIB as a routine runtime extension; the review pass below surfaced enough load-bearing decisions to warrant one.)Verification
pnpm lint/pnpm format/ typecheck /pnpm knip: clean.pnpm test: all pass except the pre-existing fork/e2e suites requiringRPC_URL_8453in.env.test.local(fail identically on main in this checkout). 71 tests for this bot + widened bot-kit policy tests + 4 newsimulateCallcases; the blue-liquidation and midnight-liquidation unit projects (239 tests) pass too, proving the shared-simulate refactor is behavior-neutral. Test-breakage verified per repo rule, including the new AdaptiveCurveIRM / idle-cap / zero-leg regression tests.DRY_RUN=true): startup vault validation,allocator.missing_roleskip path, per-block maintenance, cleantick.endcounters, clean SIGINT. Separate live probe exercisedfetchVaultData→ strategy on a real vault's 3-market queue.docker buildnot verified locally (daemon not running) — the Dockerfile is blue-liquidation's byte-for-byte with paths adjusted; Railway builds server-side.Notes for review
Policy.targets: readonly Address[](union dropped, check idtarget),queue.submitreturns whether it broadcast, opt-in JSON-RPC-batched transport (this bot opts in); vaults now run concurrently with a snapshot-derived allocator|owner|curator check, deduped whitelist, SDK-first math adoptions, and vault-checks/interval-gate extraction with tests. All threads replied and resolved except the staging-provisioning question (answered, left open).blue-reallocationafter the initial migration: the bot manages Blue markets x Vault V1 (MetaMorpho), andvault-v1-reallocationpairs with the upcoming Vault V2 bot migration. The git branch name keeps its originalfeat/blue-reallocation-bot(a ref rename is cosmetic); the GitHub Environments for CI deploys must be created asvault-v1-realloc-staging/vault-v1-realloc-productionwhen Railway is provisioned.@morpho-org/blue-sdk/blue-sdk-viemto the catalog re-resolved quoter-bot's transitive blue-sdk from 6.4.0 → 6.5.0 (lockfile); single viem + single blue-sdk instance confirmed (test/viem-dedupe.test.tsgreen).src/strategies/reconcile.ts) that owns all mechanics: clamped sizing, idle netting, the firing gate, budget trimming in withdraw-queue order, and leg building.Strategy/createStrategyare unchanged, and the existing strategy tests pass unmodified as the behavioral-equivalence proof.Math.abs(Number(apyDelta / 1e9)) / 1e5) for fidelity — a pure-bigint cleanup is a cheap follow-up.rateAtTarget, andrateAtTarget = 0nmakes the curve inverse return WAD for every rate, collapsing both APY bounds so the market always read "below range" andapy-rangewould withdraw the vault's entire position out of it on sim-passing calldata. Such markets are now classified invault-data.tsagainstgetChainAddresses(chainId).adaptiveCurveIrm(plus a non-zerorateAtTarget) and excluded from both legs;equalize-utilizationsis utilization-only and keeps them.idleCap - vaultAssetsunderflowed to a negative bigint when a curator dropped the cap below the current allocation, corrupting the plan; now clamped and cap-buffered like every other deposit target.assets: maxUint256once the deposit budget is spent.allocator || curator || owner, matching MetaMorpho'sonlyAllocatorRole(a curator- or owner-keyed EOA was skipped forever).fetchAccrualVaultfetcher — replaces the hand-rolled 1 + N + ~4N reads with one deployless SDK query;fetchVaultData's signature and theVaultData/VaultMarketDatatypes are unchanged.simulateCallin bot-kit — the bot's near-duplicate ofsimulateLiquidationExecis gone;simulateLiquidationExecis now a thin delegating wrapper with an unchanged public API.timestamprather thanDate.now(), so a snapshot is fully block-coherent and reproducible.isAddressEqualfor idle detection), README fixes (correctrelease-vault-v1-realloclabel, thevault.inflight/market.non_adaptive_curveevents and full counter list, the ~100%-utilization-attracts-deposits behavior, reconciled role prose), and the TIB above.🤖 Generated with Claude Code