test(cketh): adversarial end-to-end coverage of sweeper fee funding - #11097
Draft
mbjorkqvist wants to merge 6 commits into
Draft
test(cketh): adversarial end-to-end coverage of sweeper fee funding#11097mbjorkqvist wants to merge 6 commits into
mbjorkqvist wants to merge 6 commits into
Conversation
Complements the happy-path e2e with the three ways funding can go wrong, each driven through the real pipeline — real ckETH ledger, real EVM RPC canister, tECDSA signature, local anvil: - An empty fee account halts funding: nothing is burned, no ETH leaves the main address, and the minter reports why: if the fee account cannot cover a sweep, no sweep is submitted. - A sweeper already above the low-water mark is left alone, so no ckETH is burned for gas that is already in place — the failure mode a wrongly-defaulted balance read would cause. - A funding transaction that fails on chain is NOT reimbursed: the supply stays reduced and the burn is tracked as prepaid gas. This is the central promise, and it is now demonstrated end to end rather than only against a mocked receipt. The last one has to be arranged, because it is otherwise unreachable: a bare value transfer to a code-less EOA cannot fail, which is exactly why the sweeper is an EOA. Placing `PUSH1 0, PUSH1 0, REVERT` at the sweeper address leaves the transfer's 21'000 base gas with nothing to execute the code, so it fails. Two of the three are bounded *negative* assertions — "the minter must not do X" cannot be proven outright, so they watch for longer than a withdrawal-timer tick, which is the practical substitute. That makes the target slow on purpose; if nine minutes per CI run is not worth it, these are the natural candidates for a nightly-only tag. No live fee-spike test: the ceiling is pinned precisely by `should_cap_resubmission_at_the_funded_amount` and `should_fail_to_create_a_transaction_when_the_fee_exceeds_the_funded_amount`, and reproducing it live would mean driving anvil's base fee up and waiting out several timer ticks for little extra signal. Recorded in the test file so the omission is deliberate rather than forgotten. The harness now reads the sweeper address from the dashboard instead of scraping the funding task's log line. That is what makes the "already topped up" scenario possible — the address is needed before the task acts — and it exercises the dashboard section as a side effect. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This was referenced Aug 11, 2026
… into mathias/DEFI-2933-hardening
… into mathias/DEFI-2933-hardening
… into mathias/DEFI-2933-hardening
… into mathias/DEFI-2933-hardening
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Part of DEFI-2933 (sweeper fee funding), last of a seven-PR stack. Targets #11094.
Why
The stack's existing live test proves funding works. This one proves it fails safe. Each test drives a distinct way funding can go wrong through the real pipeline — real ckETH ledger, real EVM RPC canister, local anvil, threshold-ECDSA signature — and asserts the invariant the feature exists to protect: ETH never moves ahead of the ckETH burned to pay for it.
What
Three adversarial scenarios:
No live fee-spike test: that ceiling is pinned exactly by unit tests, and reproducing it here would mean driving anvil's base fee up over several ticks for little extra signal.
What it found
Waiting for finalization — rather than asserting mid-flight, as the earlier live test did — surfaced a production defect that would trap the withdrawal timer permanently. The fix ships in #11086, where it belongs; this PR is what made it visible.
Harness work this required
Two things had to change before these tests could run at all, both also in #11086:
anvil_setBalancemoves ETH the minter's accounting has never seen. The harness now emits a genuineReceivedEthlog for the minter to scrape, so its ETH balance counter is backed the way it is in production.PocketIc::newhard-codes a 600-second hard TTL, after which the server exits unconditionally — mid-request, ignoring in-flight work, with the budget shared across the whole test binary. Any suite past ten minutes has its backend shot out from under it, and every client then panics withConnection reset by peer. The harness starts its own server with a TTL above the Bazel timeout.Stack
Merge in order; each PR targets the one above it.