fix(cketh): provision sweep gas out of the sweeper balance bound - #11342
fix(cketh): provision sweep gas out of the sweeper balance bound#11342gregorydemay wants to merge 13 commits into
Conversation
There was a problem hiding this comment.
Pull request overview
Updates ckETH sweeper funding accounting so in-flight and finalized sweep costs correctly reduce the tracked balance lower bound.
Changes:
- Provision accepted sweeps against the sweeper balance bound.
- Refund unused fees and failed transfer values upon finalization.
- Add lifecycle tests, shared fixtures, and updated documentation.
Reviewed changes
Copilot reviewed 7 out of 7 changed files in this pull request and generated no comments.
Show a summary per file
| File | Description |
|---|---|
rs/ethereum/cketh/minter/src/test_fixtures.rs |
Adds a reusable sweep request fixture. |
rs/ethereum/cketh/minter/src/state/transactions/tests.rs |
Reuses the shared sweep fixture. |
rs/ethereum/cketh/minter/src/state/sweeper_funding/tests.rs |
Tests provisioning, refunds, accounting invariants, and flooring. |
rs/ethereum/cketh/minter/src/state/sweeper_funding.rs |
Tracks provisioned and refunded sweep costs. |
rs/ethereum/cketh/minter/src/state/audit.rs |
Wires accounting into sweep lifecycle events. |
rs/ethereum/cketh/minter/src/state.rs |
Settles sweeper balance accounting at acceptance and finalization. |
rs/ethereum/cketh/docs/deposit_from_cex.md |
Documents the revised lower-bound calculation. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
63a865b to
928e0c0
Compare
0651dfc to
452ee12
Compare
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 29 out of 29 changed files in this pull request and generated 3 comments.
Suppressed comments (2)
Previously missed (2) — in code that hasn't changed since the last review.
rs/ethereum/cketh/minter/src/state/automatic_deposits/mod.rs:220
- This literal emits large runs of spaces in the operational log message, making failure diagnostics harder to read. Use Rust line continuations so source wrapping produces single spaces.
"[record_finalized_sweep_transaction]: DROPPING {request:?} from the sweep queue: {id:?} failed and the minter does not retry. Its {:?} stays at {}, and reaching it again needs the pair armed afresh.",
rs/ethereum/cketh/test_utils/src/anvil.rs:316
- Blocks are searched newest-first, but transactions within each block are still searched oldest-first. With interval mining, multiple transactions from this sender can share the head block, so this can return an earlier transaction rather than the documented most recent one. Reverse the per-block iteration too.
for transaction in transactions {
542ceb8 to
a124541
Compare
The funding decision reads a lower bound on the sweeper address' balance, tracked from the minter's own events. Nothing debited it, which was true while nothing spent from that address — and the layers below have since landed the pipeline that does. With those in place the bound only ever grows: fundings top the sweeper up once, sweeps spend the gas, and the bound still reports a full sweeper, so `amount_due` declines every later funding. The sweeper drains, sweeping stalls, and every counter says it is funded. An accepted sweep now provisions the most it can cost that address — its fee ceiling, which caps every resubmission the pipeline makes for it — and gets back the fee it did not pay when it finalizes. An ERC-20 sweep moves its tokens through call data and carries no ETH value of its own, so the fee is the whole of what it can cost, and a reverted sweep is charged for its gas like any other. Provisioning at acceptance rather than debiting at spend is what keeps this a bound while sweeps are in flight. Gas a committed sweep will pay stops counting as available immediately, and a sweep whose finalization is never observed leaves the bound too low — which delays a funding — rather than too high, which would let the minter believe in gas that is gone. It is the discipline the withdrawal pipeline already applies to its own fees. The counters are kept out of `cumulative_spent`: this ETH was counted there once already, when the funding that delivered it finalized, and counting it twice would make spend overtake burn and trip the burn-first invariant. The bound floors at zero rather than trapping, since an upgrade that starts the counters from zero — or a sweeper funded before it was tracked — can legitimately leave provisioning above deliveries, and trapping in a state transition would take the replay of every later event with it. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01YK3ggw1xtE3HZTGGBu66oD
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01YK3ggw1xtE3HZTGGBu66oD
…prepaid gas Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01YK3ggw1xtE3HZTGGBu66oD
…line Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01SJ2pJpCcJWSmYfrhLjmUZ8
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01SJ2pJpCcJWSmYfrhLjmUZ8
e9dfee9 to
b254286
Compare
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01SJ2pJpCcJWSmYfrhLjmUZ8
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01SJ2pJpCcJWSmYfrhLjmUZ8
…r it Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01SJ2pJpCcJWSmYfrhLjmUZ8
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01SJ2pJpCcJWSmYfrhLjmUZ8
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01SJ2pJpCcJWSmYfrhLjmUZ8
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01SJ2pJpCcJWSmYfrhLjmUZ8
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01SJ2pJpCcJWSmYfrhLjmUZ8
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01SJ2pJpCcJWSmYfrhLjmUZ8
|
✅ No security or compliance issues detected. Reviewed everything up to 1835071. Security Overview
Detected Code Changes
|
mbjorkqvist
left a comment
There was a problem hiding this comment.
LGTM, thanks @gregorydemay!
Why
amount_duedeclines fundings the sweeper actually needs, and sweeping stalls while looking healthy.What
EthBalanceinstead of floored at zero: provisioning beyond deliveries is a bug to surface, not a state to tolerate (no deployed minter ever wrote a sweep event, so there is no legacy log to indulge).cumulative_spent— that ETH was counted there when the funding delivered it, and counting it twice would trip the burn-first invariant (R14).This is #11329 (thanks @mbjorkqvist), integrated on top of the sweep stack per the hand-off on DEFI-2933: rebased onto the sweep-queue lifecycle, whose deposit release now lives in the same finalization transition the refund settles in.