Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion bots/quoter-bot/.env.example
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@ MARKET_IDS=0x5555555555555555555555555555555555555555555555555555555555555555
# Required by commands whose active targetRate strategy is variable_rate_avg.
REFERENCE_MARKET_ID=0x7777777777777777777777777777777777777777777777777777777777777777
NATIVE_RESERVE_WEI=10000000000000000
MAXIMUM_LEND_EXPOSURE_ASSETS=10000000000
MORPHO_API_BASE_URL=https://api.example
V0_OFFER_GROUP_IDS=0x8888888888888888888888888888888888888888888888888888888888888888
REQUEST_TIMEOUT_MS=10000
Expand Down
25 changes: 20 additions & 5 deletions bots/quoter-bot/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -492,7 +492,6 @@ unit; for six-decimal USDC, `101000000` is 101 USDC. No value is inferred from a
| `REFERENCE_MARKET_ID` | `markets.referenceMarketId` | Required when the selected command has an active `variable_rate_avg` target. Must be a 0x-prefixed bytes32 Morpho Blue market ID. |
| `V0_OFFER_GROUP_IDS` | `markets.v0OfferGroupIds` | Optional comma-separated list of unique, explicitly strategy-owned bytes32 offer-group IDs; defaults to empty. Use it to adopt known pre-existing groups safely. |
| `NATIVE_RESERVE_WEI` | `setup.nativeReserveWei` | Required unsigned integer. Minimum maker native-token balance, in wei, required by readiness for transaction fees. |
| `MAXIMUM_LEND_EXPOSURE_ASSETS` | `setup.maximumLendExposureAssets` | Required unsigned integer in raw loan-token units. Minimum maker allowance to Midnight required by readiness; it is not a strategy position cap. |
| `REQUEST_TIMEOUT_MS` | `setup.requestTimeoutMs` | Optional provider-operation and aggregate pagination timeout in milliseconds. Defaults to `10000`; accepted range is `1` through `120000`. |
| `TRANSACTION_RECEIPT_TIMEOUT_MS` | `setup.transactionReceiptTimeoutMs` | Optional timeout for confirming an already-submitted transaction, in milliseconds. Defaults to `180000`; accepted range is `1` through `900000`. |
| `BOOTSTRAP_MARKETS` | `bootstrap` | Optional exact JSON array of position-bootstrap entries documented below; defaults to `[]` and replaces the complete YAML `bootstrap` list when supplied. |
Expand Down Expand Up @@ -575,7 +574,8 @@ no field is human-scaled — resolve decimals downstream from the `loanAsset` ad
| `book.observed` | A verbose ladder cycle observed post-check market state (both sides always) | `marketId`, `side`, `state`, `rungs`, `totalAssets`, `bestRateBps?`, `worstRateBps?`, `centerRateBps?` |
| `offer.consumed` | A group's monotonic `consumed` grew since the previous cycle | `marketId`, `side`, `consumedDeltaAssets`, `groupRateBps`, `remainingAssets`, `groupId` _(trace only)_ |
| `transaction.settled` | A submitted transaction confirmed; `marketId` is absent for strategy-wide halt/invalidation cancellations | `workflow`, `marketId?`, `operation`, `txHash` _(trace only)_ |
| `setup.check-failed` | One named setup check failed | `check` |
| `setup.check-failed` | One named setup check failed, blocking readiness | `check`, `status` |
| `setup.check-warning` | One named setup check warned without blocking readiness | `check`, `status` |

`txHash` and `groupId` are unbounded trace-only correlation fields: use them to join records, never
as grouping dimensions. The safe dimensions are `workflow`, `marketId`, `side`, `status`, `stage`,
Expand All @@ -602,7 +602,8 @@ Absence alerts are scoped per market by `market.configured`, which names the mar

**Known limits.**

- Everything beyond `cycle.completed`, `guardrail.halted`, and `setup.check-failed` requires
- Everything beyond `cycle.completed`, `guardrail.halted`, `setup.check-failed`, and
`setup.check-warning` requires
`--verbose`. Full shipping configuration auto-enables it; running `start`, `bootstrap`, or `ladder`
manually without `--verbose` yields far fewer records.
- Fills are diffed from monotonic per-group `consumed`. A group first seen establishes a baseline and
Expand Down Expand Up @@ -643,11 +644,16 @@ and `ladder`; unknown keys at any level are rejected. Every supported key appear
- `contracts`: `midnightAddress`, `loanAssetAddress`, `ratifierAddress`.
- `apis`: `morphoBaseUrl`, `routerBaseUrl`.
- `markets`: `allowlist`, `referenceMarketId`, `v0OfferGroupIds`.
- `setup`: `nativeReserveWei`, `maximumLendExposureAssets`, `requestTimeoutMs`,
`transactionReceiptTimeoutMs`.
- `setup`: `nativeReserveWei`, `requestTimeoutMs`, `transactionReceiptTimeoutMs`.
- `bootstrap`: an ordered list of the exact per-market objects documented below.
- `ladder`: an ordered list of the exact per-market objects documented below.

`setup.maximumLendExposureAssets` was removed. Delete it from existing configuration files:
unknown keys are rejected and the sanitized error does not name the offending key, so a stale entry
crash-loops the bot at startup with no indication of which line is at fault. A stale
`MAXIMUM_LEND_EXPOSURE_ASSETS` environment variable is inert and needs no action — the loader reads
an allowlist and ignores anything outside it.

Addresses and bytes32 IDs should be quoted YAML strings. Every integer field uses exact
decimal-integer syntax: unsigned fields accept digits only, while `premiumBps`, `quotePremiumBps`,
and `sizeSkewBps` additionally accept one leading minus. Exact raw-unit amounts may be quoted decimal
Expand All @@ -665,6 +671,15 @@ Setup verifies all of the following from the typed configuration:

- Configured chain identity and configured Midnight bytecode.
- Native reserve, loan-token allowance, and ratifier readiness for the configured maker address.
The allowance check requires an unbounded (`type(uint256).max`) approval to Midnight: an ERC-20
allowance is a cumulative lifetime spend budget, not an outstanding-exposure cap, so a finite
approval is consumed by ordinary relending and fails readiness. Exposure is bounded by maker
wallet funds and the strategy's `targetMarketExposureAssets` / `maximumTotalExposureAssets`.
- Active maker offers: an offer on an unconfigured market, or a crossed/inverted book, fails
readiness. A live offer group the bot cannot attribute to itself is reported as `warning` and
does not block readiness — group ownership is a local durable record, so redeploying onto a fresh
filesystem orphans the bot's own groups, and halting on that cannot recover until every orphan
expires. Exposure is derived from live on-chain groups either way.
- Maker/private-key agreement in write mode; only this signer-identity check is `not-required` with
`--readonly`. Maker identity is reduced to configured/derived/matches status and the address is
never included in operator output.
Expand Down
1 change: 0 additions & 1 deletion bots/quoter-bot/docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ services:
REFERENCE_MARKET_ID: ${REFERENCE_MARKET_ID:-}
V0_OFFER_GROUP_IDS: ${V0_OFFER_GROUP_IDS:-}
NATIVE_RESERVE_WEI: ${NATIVE_RESERVE_WEI:?set NATIVE_RESERVE_WEI}
MAXIMUM_LEND_EXPOSURE_ASSETS: ${MAXIMUM_LEND_EXPOSURE_ASSETS:?set MAXIMUM_LEND_EXPOSURE_ASSETS}
REQUEST_TIMEOUT_MS: ${REQUEST_TIMEOUT_MS:-10000}
TRANSACTION_RECEIPT_TIMEOUT_MS: ${TRANSACTION_RECEIPT_TIMEOUT_MS:-180000}
BOOTSTRAP_MARKETS: ${BOOTSTRAP_MARKETS:?set BOOTSTRAP_MARKETS}
Expand Down
26 changes: 20 additions & 6 deletions bots/quoter-bot/docs/reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -346,7 +346,6 @@ unit; for six-decimal USDC, `101000000` is 101 USDC. No value is inferred from a
| `REFERENCE_MARKET_ID` | `markets.referenceMarketId` | Required when the selected command has an active `variable_rate_avg` target. Must be a 0x-prefixed bytes32 Morpho Blue market ID. |
| `V0_OFFER_GROUP_IDS` | `markets.v0OfferGroupIds` | Optional comma-separated list of unique, explicitly strategy-owned bytes32 offer-group IDs; defaults to empty. Use it to adopt known pre-existing groups safely. |
| `NATIVE_RESERVE_WEI` | `setup.nativeReserveWei` | Required unsigned integer. Minimum maker native-token balance, in wei, required by readiness for transaction fees. |
| `MAXIMUM_LEND_EXPOSURE_ASSETS` | `setup.maximumLendExposureAssets` | Required unsigned integer in raw loan-token units. Minimum maker allowance to Midnight required by readiness; it is not a strategy position cap. |
| `REQUEST_TIMEOUT_MS` | `setup.requestTimeoutMs` | Optional provider-operation and aggregate pagination timeout in milliseconds. Defaults to `10000`; accepted range is `1` through `120000`. |
| `TRANSACTION_RECEIPT_TIMEOUT_MS` | `setup.transactionReceiptTimeoutMs` | Optional timeout for confirming an already-submitted transaction, in milliseconds. Defaults to `180000`; accepted range is `1` through `900000`. |
| `BOOTSTRAP_MARKETS` | `bootstrap` | Optional exact JSON array of position-bootstrap entries documented below; defaults to `[]` and replaces the complete YAML `bootstrap` list when supplied. |
Expand Down Expand Up @@ -474,7 +473,8 @@ human-scaled: a consumer resolves decimals from the `loanAsset` address shipped
| `book.observed` | A verbose ladder cycle observed post-check market state; one record per side, on every observed cycle | `marketId`, `side`, `state` (`quoting` \| `empty`), `rungs`, `totalAssets`, `bestRateBps?`, `worstRateBps?`, `centerRateBps?` (absent when no quote is active) |
| `offer.consumed` | A group's monotonic `consumed` grew relative to the previous cycle | `marketId`, `side`, `consumedDeltaAssets`, `groupRateBps`, `remainingAssets`, `groupId` _(trace only)_ |
| `transaction.settled` | A submitted bootstrap or ladder transaction confirmed; `marketId` is absent for strategy-wide halt/invalidation cancellations | `workflow`, `marketId?`, `operation` (`cancel` \| `ratify` \| `publish`), `txHash` _(trace only)_ |
| `setup.check-failed` | One named readiness check failed; `observed`/`required` are typed `unknown` and are omitted | `check` |
| `setup.check-failed` | One named readiness check failed, blocking readiness; `observed`/`required` are typed `unknown` and are omitted | `check`, `status` |
| `setup.check-warning` | One named readiness check warned without blocking readiness; `observed`/`required` are likewise omitted | `check`, `status` |

`bot.started`, `bot.stopped`, `bot.unexpected-error`, `heartbeat.failed`,
`ladder.transaction-submitted`, `bootstrap.transaction-submitted`, and
Expand Down Expand Up @@ -538,8 +538,8 @@ only and cannot prove a particular market was read or quoted. The per-market `cy

#### Known limits

- **Verbose gating.** Everything beyond `cycle.completed`, `guardrail.halted`, `bot.failed`, and
`setup.check-failed` is projected from verbose diagnostics. Full shipping configuration
- **Verbose gating.** Everything beyond `cycle.completed`, `guardrail.halted`, `bot.failed`,
`setup.check-failed`, and `setup.check-warning` is projected from verbose diagnostics. Full shipping configuration
auto-enables `--verbose` for `start`, `bootstrap`, and `ladder`; an operator running those commands
manually without `--verbose` gets far fewer records.
- **Fill baseline.** `offer.consumed` is a cycle-over-cycle delta of monotonic per-group `consumed`,
Expand Down Expand Up @@ -590,11 +590,16 @@ and `ladder`; unknown keys at any level are rejected. Every supported key appear
- `contracts`: `midnightAddress`, `loanAssetAddress`, `ratifierAddress`.
- `apis`: `morphoBaseUrl`, `routerBaseUrl`.
- `markets`: `allowlist`, `referenceMarketId`, `v0OfferGroupIds`.
- `setup`: `nativeReserveWei`, `maximumLendExposureAssets`, `requestTimeoutMs`,
`transactionReceiptTimeoutMs`.
- `setup`: `nativeReserveWei`, `requestTimeoutMs`, `transactionReceiptTimeoutMs`.
- `bootstrap`: an ordered list of the exact per-market objects documented below.
- `ladder`: an ordered list of the exact per-market objects documented below.

`setup.maximumLendExposureAssets` was removed. Delete it from existing configuration files:
unknown keys are rejected and the sanitized error does not name the offending key, so a stale entry
crash-loops the bot at startup with no indication of which line is at fault. A stale
`MAXIMUM_LEND_EXPOSURE_ASSETS` environment variable is inert and needs no action — the loader reads
an allowlist and ignores anything outside it.

Addresses and bytes32 IDs should be quoted YAML strings. Every integer field uses exact
decimal-integer syntax: unsigned fields accept digits only, while `premiumBps`, `quotePremiumBps`,
and `sizeSkewBps` additionally accept one leading minus. Exact raw-unit amounts may be quoted decimal
Expand All @@ -612,6 +617,15 @@ Setup verifies all of the following from the typed configuration:

- Configured chain identity and configured Midnight bytecode.
- Native reserve, loan-token allowance, and ratifier readiness for the configured maker address.
The allowance check requires an unbounded (`type(uint256).max`) approval to Midnight: an ERC-20
allowance is a cumulative lifetime spend budget, not an outstanding-exposure cap, so a finite
approval is consumed by ordinary relending and fails readiness. Exposure is bounded by maker
wallet funds and the strategy's `targetMarketExposureAssets` / `maximumTotalExposureAssets`.
- Active maker offers: an offer on an unconfigured market, or a crossed/inverted book, fails
readiness. A live offer group the bot cannot attribute to itself is reported as `warning` and
does not block readiness — group ownership is a local durable record, so redeploying onto a fresh
filesystem orphans the bot's own groups, and halting on that cannot recover until every orphan
expires. Exposure is derived from live on-chain groups either way.
- Maker/private-key agreement in write mode; only this signer-identity check is `not-required` with
`--readonly`. Maker identity is reduced to configured/derived/matches status and the address is
never included in operator output.
Expand Down
2 changes: 1 addition & 1 deletion bots/quoter-bot/helm/quoter-bot/Chart.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ description: >-
Morpho Midnight maker bot: validates Base and Midnight setup, bootstraps target lending
positions, and maintains two-sided rate ladders from one long-running container.
type: application
version: 0.1.0
version: 0.2.0
# Default image tag. The Docker Hub repository morphoorg/quoter publishes `latest` plus one
# immutable tag per release commit hash; pin a commit tag through `image.tag` for reproducible
# deployments.
Expand Down
1 change: 0 additions & 1 deletion bots/quoter-bot/helm/quoter-bot/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,6 @@ config:
referenceMarketId: '0x7777777777777777777777777777777777777777777777777777777777777777'
setup:
nativeReserveWei: '10000000000000000'
maximumLendExposureAssets: '10000000000'
bootstrap:
- marketId: '0x5555555555555555555555555555555555555555555555555555555555555555'
targetRate:
Expand Down
1 change: 0 additions & 1 deletion bots/quoter-bot/helm/quoter-bot/values.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,6 @@ config: {}
# referenceMarketId: '0x7777777777777777777777777777777777777777777777777777777777777777'
# setup:
# nativeReserveWei: '10000000000000000'
# maximumLendExposureAssets: '10000000000'
# bootstrap: []
# ladder:
# - marketId: '0x5555555555555555555555555555555555555555555555555555555555555555'
Expand Down
1 change: 0 additions & 1 deletion bots/quoter-bot/quoter-bot.example.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,6 @@ markets:

setup:
nativeReserveWei: '10000000000000000'
maximumLendExposureAssets: '10000000000'
requestTimeoutMs: 10000
transactionReceiptTimeoutMs: 180000

Expand Down
1 change: 0 additions & 1 deletion bots/quoter-bot/scripts/deploy-railway.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,6 @@ const requiredRuntimeVariableNames = [
'MORPHO_API_BASE_URL',
'MARKET_IDS',
'NATIVE_RESERVE_WEI',
'MAXIMUM_LEND_EXPOSURE_ASSETS',
'BOOTSTRAP_MARKETS',
'LADDER_MARKETS'
] as const
Expand Down
Loading
Loading