Skip to content

feat(cketh): sign the authorizations a batched sweep needs - #11360

Merged
gregorydemay merged 7 commits into
gdemay/DEFI-2926-sign-attestationsfrom
gdemay/DEFI-2926-sign-authorizations
Aug 28, 2026
Merged

feat(cketh): sign the authorizations a batched sweep needs#11360
gregorydemay merged 7 commits into
gdemay/DEFI-2926-sign-attestationsfrom
gdemay/DEFI-2926-sign-authorizations

Conversation

@gregorydemay

@gregorydemay gregorydemay commented Aug 27, 2026

Copy link
Copy Markdown
Contributor

Why

  • The attestations the previous layer signs name the account a sweep credits, but nothing yet lets the delegate move the funds: a deposit address only executes the sweeper contract's code once it has signed an EIP-7702 authorization delegating to it.

What

  • Each deposit address in a batch signs the tuple delegating its code to the configured sweeper contract.
  • The tuple carries nonce 0 whatever nonce the address actually holds. A deposit address is at nonce 0 exactly while it has never been delegated, so the authorization either installs the delegation or is skipped — both correct, in any ordering of the sweeps carrying them. That is what lets a sweep authorize every address it touches without tracking which ones are already delegated, at the price of a skipped tuple's intrinsic gas.
  • Signatures are recorded through the event log, keyed by what was signed, so a later sweep of the same address reuses one rather than paying for another threshold-ECDSA signature. Keying by the request rather than the account is what makes that safe: re-pointing the minter at another sweeper contract changes the tuple, so it misses the cache and is signed afresh instead of reusing one that delegates the old contract.
  • Attestations and authorizations are signed independently. A deposit needs both before it can be swept, but neither signature depends on the other, so authorizing an address whose attestation failed costs nothing: the tuple is recorded and reused once the attestation lands.
  • Recording the tuple is a shortcut: it saves the signature but not the gas, since an address that is already delegated still gets sent a tuple the chain skips. Recording that the address is delegated, rather than what it signed, would save both — left for a later layer.

Candid compatibility

  • Needs the CI_OVERRIDE_DIDC_CHECK label: get_events returns a variant, and AuthorizedDepositAddress adds a case to it. A variant with more cases is not a Candid subtype of one with fewer, so the check against the merge base rejects it, exactly as it did for the attestation event in feat(cketh): remember the attestations the minter has signed #11319.
  • The case is additive: no existing case changes shape, so every event emitted so far decodes as before. Only a client reading an event of the new kind needs to know it.

Copilot AI 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.

Pull request overview

Adds EIP-7702 authorization signing for attested ckERC20 deposit addresses.

Changes:

  • Signs nonce-0 delegation authorizations in batches.
  • Adds signing expectations and coverage for authorization tuples.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.

File Description
sweep/mod.rs Implements batched authorization signing.
sweep/tests.rs Tests authorization digest, path, and signature count.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread rs/ethereum/cketh/minter/src/sweep/mod.rs Outdated
Comment thread rs/ethereum/cketh/minter/src/sweep/mod.rs Outdated
@gregorydemay
gregorydemay force-pushed the gdemay/DEFI-2926-sign-authorizations branch from da8f9c1 to 17b3988 Compare August 27, 2026 19:01
@gregorydemay
gregorydemay force-pushed the gdemay/DEFI-2926-sign-authorizations branch 2 times, most recently from d0cfdac to 6f44c38 Compare August 27, 2026 19:14
@gregorydemay gregorydemay added the CI_OVERRIDE_DIDC_CHECK Skips the backwards compatibility didc check (explain in PR description why) label Aug 27, 2026
@gregorydemay
gregorydemay marked this pull request as ready for review August 27, 2026 20:48
@gregorydemay
gregorydemay requested a review from a team as a code owner August 27, 2026 20:48
@github-actions github-actions Bot added the @defi label Aug 27, 2026
@zeropath-ai

zeropath-ai Bot commented Aug 27, 2026

Copy link
Copy Markdown

No security or compliance issues detected. Reviewed everything up to 4c36bb1.

Security Overview
Detected Code Changes
Change Type Relevant files
Enhancement ► rs/ethereum/cketh/minter/src/endpoints.rs
     AuthorizedDepositAddress field added to Event types
Enhancement ► rs/ethereum/cketh/minter/src/main.rs
     Handle AuthorizedDepositAddress event type in get_events mapping
     Expose stored_authorizations gauge
     Add authorization-related data extraction from events
Enhancement ► rs/ethereum/cketh/minter/src/state.rs
     Add authorization_requests method to generate AuthorizationRequest objects
Enhancement ► rs/ethereum/cketh/minter/src/state/audit.rs
     Handle AuthorizedDepositAddress in apply_state_transition
Enhancement ► rs/ethereum/cketh/minter/src/state/audit/tests.rs
     Update tests to include AuthorizedDepositAddress event and related authorization logic
Enhancement ► rs/ethereum/cketh/minter/src/state/automatic_deposits/mod.rs
     Add authorization map with record_authorization and related accessors
     Expose authorizations_len
Enhancement ► rs/ethereum/cketh/minter/src/state/event.rs
     Add AuthorizedDepositAddress variant to EventType enum with corresponding payload fields
Enhancement ► rs/ethereum/cketh/minter/src/sweep/mod.rs
     Import AuthorizationRequest and related changes; adjust sweeper request flow to include authorization handling
     Add batching for sign_authorizations_batch and integrate into sweep creation
Enhancement ► rs/ethereum/cketh/minter/src/tx/eip_7702.rs
     Introduce AuthorizationRequest struct and related methods (account, derivation_path, authorization, signed_with) for authorization handling
Enhancement ► rs/ethereum/cketh/minter/src/tx/mod.rs
     Expose AuthorizationRequest and Authorized types in tx module; adjust imports
Enhancement ► rs/ethereum/cketh/minter/tests/deposit_from_cex_demo.rs
     Add tests for zero-nonce authorization re-delegation and related behavior

@mbjorkqvist mbjorkqvist 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.

Thanks @gregorydemay!

Comment thread rs/ethereum/cketh/minter/src/state/automatic_deposits/mod.rs
Comment thread rs/ethereum/cketh/minter/src/state.rs
Comment thread rs/ethereum/cketh/minter/src/sweep/tests.rs
Comment thread rs/ethereum/cketh/minter/src/sweep/tests.rs

Copilot AI 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.

Pull request overview

Copilot reviewed 14 out of 14 changed files in this pull request and generated 1 comment.

Comment thread rs/ethereum/cketh/minter/src/tx/eip_7702.rs
basvandijk added a commit that referenced this pull request Aug 28, 2026
## Problem

GNU's download infrastructure has been down since ~2026-08-28 00:00 UTC,
and every **CI Main / Build IC** job since then fails to fetch the
`@mtools` external repo (first seen in run 33131446914 at 01:03Z; e.g.
#11360, #11364, #11365):

```
WARNING: Download from https://ftp.gnu.org/gnu/mtools/mtools-4.0.49.tar.gz failed: class java.io.IOException Connect timed out
WARNING: Download from https://ftpmirror.gnu.org/mtools/mtools-4.0.49.tar.gz failed: class java.io.IOException GET returned 502 Bad Gateway
ERROR: no such package '@@+http_archive+mtools//': ...
```

`ftp.gnu.org` is hard-down (TCP connect timeout on every attempt) and
the `ftpmirror.gnu.org` redirector itself intermittently returns 502 (4
out of 8 probes) — so reordering the two existing URLs would not
reliably fix CI. Since `bazel-remote` no longer has the blob cached, the
fetch falls back to these URLs and fails. `@mtools` is on the IC-OS
image build path (`vfat_image`/`fat32_image`) and a runtime dep of every
`uvm_config_image`-using system test, so this blocks most of CI.

## Fix

Add `mirrors.kernel.org` as the primary URL and demote the two GNU hosts
to fallbacks. The kernel.org mirror is fast and reliable (full download
in ~2s vs ~27s via ftpmirror when it works at all) and serves a
byte-identical tarball matching the pinned `sha256`, so this is
risk-free. Precedent: #11134 (pigz via macports mirror when zlib.net was
down).

## Verification

- Downloaded the tarball from both `mirrors.kernel.org` and
`ftpmirror.gnu.org`: both are 569054 bytes with sha256
`10cd1111da87bf2400a380c1639a6cba8bfb937a24f9c51f5f88d393ae5f6f76`,
matching the pin.
- `bazel build //... --nobuild` passes (full workspace loads/analyzes).
- `bazel run //:buildifier` clean.
- `bazel fetch --config=local --repository_cache= --force @mtools//...`
succeeds with no download warnings, i.e. bazel's own downloader fetched
from the new primary URL and the hash verified.

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

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
gregorydemay and others added 2 commits August 28, 2026 15:22
Each attested deposit address signs the EIP-7702 tuple delegating its code to
the sweeper contract, so the delegate can move the deposit's funds.

The tuple names the minter's chain, the configured sweeper contract, and nonce
0 whatever nonce the address actually holds: a deposit address is at nonce 0
exactly while it has never been delegated, so the authorization either installs
the delegation or is skipped, both of which are correct in any ordering. That
is what lets a sweep authorize every address it touches without tracking which
ones are already delegated.

Only attested addresses are authorized: a deposit that could not be attested
drops out of the sweep anyway, so authorizing it would spend a threshold-ECDSA
signature on nothing.
Stores each signed EIP-7702 tuple in the event log, keyed by what was
signed, so a later sweep of the same address reuses it rather than paying
for another threshold-ECDSA signature. Keying by the request rather than
the account means re-pointing the minter at another sweeper contract
misses the cache and signs afresh, instead of reusing a tuple delegating
the old one.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
gregorydemay and others added 5 commits August 28, 2026 15:22
… signing

sign_authorizations_batch now takes the requests, signs the ones it has not
recorded, and records those — the same steps as its attestation sibling.
Building the requests moves onto State, which fills the sweeper contract in
itself, so a caller cannot authorize against a contract the minter does not
run against; the derivation path moves onto AuthorizationRequest, so the
digest and the key that signs it come from the same place.

Drops the attested-only filter. It was justified while authorizations were
signed afresh for every sweep, but a recorded one is reused once the
attestation lands, so signing the two independently wastes nothing and
leaves neither batch waiting on the other.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@gregorydemay
gregorydemay force-pushed the gdemay/DEFI-2926-sign-authorizations branch from 0b12b1c to 4c36bb1 Compare August 28, 2026 15:23
@gregorydemay
gregorydemay added this pull request to the merge queue Aug 28, 2026
Merged via the queue into master with commit 13f49f5 Aug 28, 2026
40 checks passed
@gregorydemay
gregorydemay deleted the gdemay/DEFI-2926-sign-authorizations branch August 28, 2026 19:03
@gregorydemay
gregorydemay restored the gdemay/DEFI-2926-sign-authorizations branch August 28, 2026 19:03
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

CI_OVERRIDE_DIDC_CHECK Skips the backwards compatibility didc check (explain in PR description why) @defi feat

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants