Skip to content

fix(quoter-bot): accept fractional gwei fee bounds - #218

Merged
haydenshively merged 2 commits into
mainfrom
fix/quoter-bot-decimal-gwei
Sep 14, 2026
Merged

haydenshively merged 2 commits into
mainfrom
fix/quoter-bot-decimal-gwei

Conversation

@haydenshively

Copy link
Copy Markdown
Collaborator

Why

The Base maker's gas wallet ran down to 0.0043 ETH and the bot halted. PRIORITY_FEE_GWEI was set
to 1, but Base's going tip is ~0.005 gwei — ~200x the market rate on every publication and
cancellation, on a 60-second loop. It could not be set lower: both fee bounds parsed as positive
integers, so 1 was the floor.

midnight-liquidation already parses decimal gwei. quoter-bot was the outlier.

What

Funds-at-risk — touches fee bounds and the signing-policy ceilings that gate every transaction.

  • New positiveGweiWeiValue in config.utils.ts: decimal regex capped at nine places, viem
    parseGwei, and a >=1 wei floor. MAX_FEE_GWEI and PRIORITY_FEE_GWEI use it; the other twelve
    integer env vars keep positiveBigIntValue untouched. The nine-place cap is load-bearing —
    parseGwei rounds half-up beyond it, so MAX_FEE_GWEI=1.0000000005 would otherwise resolve one
    wei above the ceiling its operator declared.
  • YAML: the two keys move from yamlIntegerEnvironmentKeys to a new yamlDecimalEnvironmentKeys.
    Both priorityFeeGwei: 0.005 and '0.005' load; exponent notation fails loud as
    invalid-decimal, because parseGwei throws its own untyped error on it.
  • No downstream change: the values were already bigint wei on QuoterWritePolicy, and bot-kit's
    initialFees / bumpFees / hasBumpHeadroom are wei-granular with a +1 wei bump floor.
  • Examples and docs: every one showed PRIORITY_FEE_GWEI=1, which is where the 200x came from.
    Now 0.01, with a per-chain calibration note.

Review

Codex (GPT Sol, high reasoning) reviewed the first commit. It found the parseGwei rounding above,
fixed in 84b4be4. Its other two findings are one pre-existing root cause — config validates fee and
spend bounds against nominal values that do not hold at send time, so a combination that can never
admit a send passes validation. Deferred as
BOTS-136:
the real guard needs the runtime base fee, which is a send-path change wanting its own review. This
PR mitigates the newly reachable half with an operator-facing note on MAX_FEE_GWEI.

Not in scope

Deriving the tip from eth_maxPriorityFeePerGas and demoting PRIORITY_FEE_GWEI to a ceiling. That
is the durable fix for "a hand-set constant silently drains the wallet over days" — nothing today
compares the configured tip to the market. It changes first-send behaviour on a funds-at-risk path
and wants its own TIB rather than riding along with a parser fix the operator is waiting on.

Verified

typecheck, lint, format, knip clean. Root suite: 2942 passed. The two failures are
midnight-liquidation fork suites missing RPC_URL_8453; the quoter-bot fork e2e fails identically on
a pristine origin/main worktree (same 0x5e71e7fb revert), so both are environmental.

New coverage in test/config/config.service.test.ts and test/config/config-loading.test.ts:
decimal parses to exact wei, sub-wei and exponent and signed values reject with stable reasons, a
decimal pair with no bump headroom still reports incoherent-bounds, and a field that must stay
integral still rejects a decimal.

🤖 Generated with Claude Code

haydenshively and others added 2 commits September 14, 2026 10:43
MAX_FEE_GWEI and PRIORITY_FEE_GWEI parsed as integers, so 1 gwei was the
lowest tip an operator could set. Base's going tip is ~0.005 gwei, and the
Base maker paid the 200x difference on every publication until the wallet
ran down and the bot halted.

Parse both through viem parseGwei with a >=1 wei floor, matching what
midnight-liquidation already does, and relax the YAML gate to match. The
values are bigint wei downstream, so bumping and policy ceilings are
unchanged.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
parseGwei rounds half-up past nine decimal places, so MAX_FEE_GWEI
1.0000000005 resolved to one wei ABOVE the ceiling its operator declared,
and a sub-wei tip rounded up instead of being rejected. Cap the decimal
regex at nine places on both the env and YAML paths so the conversion is
exact.

Also note on MAX_FEE_GWEI that a ceiling near twice the base fee clamps the
first send and makes the first bump drop — newly reachable on Base now that
the ceiling can go below a gwei. BOTS-136 covers guarding it.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@linear-code

linear-code Bot commented Sep 14, 2026

Copy link
Copy Markdown

BOTS-136

@haydenshively haydenshively self-assigned this Sep 14, 2026
@haydenshively
haydenshively marked this pull request as ready for review September 14, 2026 16:03
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Sep 14, 2026

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review Completed 2026-09-14T17:50:18.984064Z 84b4be4 Manual request
🔒 Security Review Completed 2026-09-14T17:52:11.734756Z 84b4be4 Manual request
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@devin-ai-integration devin-ai-integration Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Devin Review found 1 potential issue.

1 flag not posted on this PR by your GitHub settings — view it in Devin Review. (Configure)

Devin Review

Comment thread bots/quoter-bot/src/config/config-source.utils.ts
@haydenshively

Copy link
Copy Markdown
Collaborator Author

@codex review

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Bravo.

Reviewed commit: 84b4be4874

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

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".

@chatgpt-codex-connector

Copy link
Copy Markdown

🛡️ Codex Security Review · Automatically triggered

Security review completed. No security issues were found in this pull request.

Reviewed commit: 84b4be4874

View security finding report

Only the user who started this review can view the report in Codex.

ℹ️ About Codex security reviews in GitHub

This is an experimental Codex feature. Security reviews are triggered when:

  • You comment "@codex security review"
  • A regular code review gets triggered (for example, "@codex review" or when a PR is opened), and you’re opted in so security review runs alongside code review

Once complete, Codex will leave suggestions, or a comment if no findings are found.

@haydenshively
haydenshively merged commit 1c45dd4 into main Sep 14, 2026
6 checks passed
@haydenshively
haydenshively deleted the fix/quoter-bot-decimal-gwei branch September 14, 2026 18:43
haydenshively added a commit that referenced this pull request Sep 15, 2026
`pr-describe` made the agent measure the diff by hand — a `git diff
--numstat` + awk pipeline plus `tokei` — and paste the result into the
PR body under `## Size`. That number was wrong the moment another commit
landed, and nothing corrected it. CI now owns the measurement and keeps
one pinned comment per PR, recomputed on every push.

## Changes

- **`packages/ci-scripts/src/pr-size/`** — `summary.ts` holds the pure
logic (bucketing, tokei-totals validation, table rendering);
`orchestrate/comment.ts` reads the PR files API and upserts a
marker-tagged comment. Reuses the package's existing
`githubApi`/`paginate`/`readPayload` helpers rather than adding a
dependency.
- **`.github/workflows/pr-size.yml`** — two jobs. `Comment` holds
`pull-requests: write`, checks out `main`, and never touches PR code:
GitHub's PR files API serves the per-file additions/deletions the table
needs, so no checkout of the diff is required at all. `Measure` checks
out PR head for `tokei` but holds no write token, and hands over three
integers through a job output.
- **`.claude/commands/pr-describe.md`** — Step 1.2 and the `## Size`
section deleted; the agent no longer measures. Also repairs the
unbalanced code fences in the Step 3 template, which were pre-existing.
- Tests, `knip.json` entry, `README`, `docs/INDEX.md`.

## Notes for review

**The port is verified, not asserted.** Run over a 229-file range
spanning all four buckets, the new renderer produces a table
byte-identical to the old awk. Against live PR #218, the rendered totals
match GitHub's own `additions`/`deletions`/`changed_files` exactly.

**tokei is built from source, pinned to v15.0.0.** It has shipped no
prebuilt binary since v12.1.2 in 2021, so pinning one only gets further
out of date. `ubuntu-latest` already carries a Rust toolchain, and the
cold build measured **45s** in CI on this PR; only the resulting binary
is cached, so restore is near instant and a stale entry just rebuilds.
Verified that v12.1.2, v14.0.0 and v15.0.0 return identical
code/comment/blank totals on the same inputs. The workflow parses
tokei's plain-text `Total` row rather than `--output json`, which is
stable across all three versions.

**Two deliberate divergences from the old pipeline**, both named in
comments: a rename's content delta is attributed to the new path, and a
binary file counts as one changed file at +0/−0 where the old awk
dropped it from the file count entirely.

**Cosmetic means cosmetic.** Both jobs carry `continue-on-error`, so a
failed build or merge-base leaves the PR green and the comment still
posts, saying the code/prose split is unavailable.

**`Comment` fails on this PR, by design.** It runs *main's*
`ci-scripts`, which has no `pr-size-comment` script until this merges.
The workflow run still reports success. It passes from the next PR
onward; the writer path was verified end to end by running the
orchestrator against this PR directly (created, then updated in place,
exactly one comment).

## Deferred


[BOTS-138](https://linear.app/morpho-labs/issue/BOTS-138/cirepo-decide-the-trust-boundary-for-pr-request-workflows-holding)
— `pull_request` runs the workflow as the PR defines it, so a branch can
edit the job holding the write token. That grants a contributor nothing
they lack here (pushing a branch already means repo write) and a fork's
token is read-only, but it is not the boundary `pull_request_target`
would give. `pr-release-label-sync.yml` has the identical exposure, so
it is a repo-wide call rather than one to make in this PR. This
workflow's header now states the exposure instead of claiming a boundary
it does not have.

## Test Plan

- [ ] On this PR, confirm the size comment's numbers match `git diff
--numstat origin/main...HEAD`
- [ ] After merge, confirm the next PR gets the comment from CI and that
it is edited in place on a second push

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants