diff --git a/rs/ethereum/cketh/docs/deposit_from_cex.md b/rs/ethereum/cketh/docs/deposit_from_cex.md
new file mode 100644
index 000000000000..4e05607e9fbd
--- /dev/null
+++ b/rs/ethereum/cketh/docs/deposit_from_cex.md
@@ -0,0 +1,684 @@
+---
+id: DEFI-2096
+title: Support deposit from CEX via per-account deposit addresses (EIP-7702 sweeping)
+tags: [cketh, ckerc20, minter, deposit, eip-7702]
+---
+
+# Support deposit from CEX via per-account deposit addresses (EIP-7702 sweeping)
+
+## Motivation
+
+Today the only way to deposit ETH or ERC-20 tokens into ckETH/ckERC20 is to call the
+helper smart contract (`DepositHelperWithSubaccount.sol`), which forwards the funds to
+the minter's single tECDSA address and emits a `ReceivedEthOrErc20` event carrying the
+beneficiary IC principal and subaccount. The minter discovers deposits exclusively by
+scraping this event (`src/deposit.rs`, `src/eth_logs/`), i.e. attribution of funds to an
+IC account relies entirely on the depositor *executing a contract call*.
+
+A withdrawal from a centralized exchange (CEX) cannot fit through this path:
+
+* A CEX only performs plain transfers: a bare ERC-20 `transfer(to, value)` (standard
+ `Transfer` event, no principal) or a native ETH send (no log at all).
+* The sender is the exchange's omnibus hot wallet, shared by all its customers, so
+ sender-based attribution is impossible.
+* Ethereum has no memo/data side-channel on plain transfers.
+
+Consequently a user holding e.g. USDT or USDC on Coinbase/Binance cannot onramp into
+ckUSDT/ckUSDC without first withdrawing to a self-custody wallet, funding it with ETH
+for gas, and interacting with the helper contract — a prohibitive UX. Funds sent
+directly to the minter address today are simply unaccounted, with no recovery path
+(see the documentation of the `eth_balance` field of the `EthBalance` struct in
+`src/state.rs`).
+
+The only attribution channel a CEX supports is the **destination address**. This design
+therefore gives each IC account a **unique, deterministic deposit address**, controlled
+by the minter through threshold ECDSA (the ckBTC model), and uses **EIP-7702**
+(live on Ethereum mainnet since the Pectra upgrade, May 2025) to sweep funds from these
+addresses to the minter's main address **without pre-funding them with ETH for gas**:
+the deposit EOA signs a one-time authorization delegating its code to a minimal sweeper
+contract, and the minter's main (funded) address submits the sweep transaction and pays
+for gas.
+
+Target UX: *"I have USDT on a CEX and I want ckUSDT: I paste my deposit address into
+the exchange withdrawal form and the tokens automagically appear as ckUSDT."*
+
+The design is delivered in two phases:
+
+* **Phase 1 — ckERC20 only** (ckUSDC, ckUSDT, …): deposits are ERC-20 `Transfer`s,
+ which always emit logs and never execute recipient code, making detection and
+ crediting straightforward.
+* **Phase 2 — ckETH**: native ETH transfers emit no logs and interact badly with
+ EIP-7702 delegated code under fixed 21'000 gas limits; this phase has additional
+ design constraints, described separately.
+
+## Requirements
+
+### Phase 1 (ckERC20)
+
+* `R1`: For every IC account `(principal, subaccount)`, the minter returns a unique,
+ deterministic Ethereum deposit address. Repeated calls return the same address. Two
+ distinct accounts never share an address, and no deposit address ever equals the
+ minter's main address or a helper contract address.
+* `R2`: If a supported ERC-20 token is transferred to a registered deposit address, and
+ the transfer is in a finalized block, and the amount is at least the per-token
+ minimum deposit amount, then the minter mints `amount - deposit_fee` ckERC20 to the
+ associated IC account, exactly once (deduplication by `(transaction hash, log
+ index)`, as for helper-based deposits).
+* `R3`: If the ERC-20 `Transfer` sender is on the blocklist, no mint occurs; the
+ deposit is recorded as invalid (same semantics as today's blocked helper deposits).
+* `R4`: Transfers below the per-token minimum deposit amount, and transfers of
+ unsupported ERC-20 tokens, are not credited. No funds are ever burned or destroyed:
+ they remain at a tECDSA-controlled address and remain recoverable by the minter.
+* `R5`: Every credited deposit is eventually swept to the minter's main address. A
+ sweep failure or delay never affects already-minted balances; sweeps are retried
+ until confirmed.
+* `R6`: A sweep transaction moves funds only to the minter's main address, regardless
+ of who triggers it. No other destination is reachable through the sweeper delegate.
+* `R7`: The per-token `deposit_fee` and minimum deposit amount are configurable
+ (upgrade argument / NNS proposal) such that fees cover the amortized sweep gas cost.
+* `R8`: All new state transitions (address registration, accepted/invalid deposit,
+ delegation, sweep sent/confirmed) are recorded as audit events, replayable on
+ upgrade, consistent with the minter's event-sourcing architecture.
+* `R9`: The minter dashboard and metrics expose: registered deposit addresses,
+ credited-but-unswept balances per token, delegation status, and sweep activity.
+* `R10`: Withdrawals (ckERC20 → ERC-20 and ckETH → ETH) are unaffected: they continue
+ to be served from the minter's main address and its existing nonce sequence.
+* `R13`: Registering a deposit address (`get_deposit_address`) triggers no
+ threshold-ECDSA signature and no Ethereum transaction. The minter only signs a
+ delegation and sweeps an address after having observed there a balance of a
+ supported token of at least the per-token minimum deposit amount. (Registrations
+ are free for callers; anything the minter spends per registration is a DoS vector
+ on its cycles and ETH.)
+* `R14`: Sweeping never reduces the 1:1 backing of ckETH. Before any ETH is spent on
+ a sweep transaction, the minter burns from its fee account on the ckETH ledger at
+ least the maximum fee of that transaction; at all times, cumulative ckETH burned
+ for sweeping ≥ cumulative ETH spent on sweeping. Burned-but-unspent amounts are
+ tracked and offset against subsequent burns; they are never re-minted. If the fee
+ account cannot cover a sweep, no sweep is submitted.
+
+### Phase 2 (ckETH)
+
+* `R11`: If the finalized ETH balance of a deposit address exceeds the sum of all
+ previously credited (minus swept) amounts by at least the minimum ETH deposit
+ amount, the minter mints the difference minus the deposit fee to the associated
+ account, exactly once per balance observation (monotone accounting: total credited
+ never exceeds total received).
+* `R12`: A plain ETH transfer sent with a fixed 21'000 gas limit to a deposit address
+ MUST NOT be permanently locked: it either succeeds (address has no code at transfer
+ time) or fails on the sender side (funds never leave the exchange). See the
+ delegation lifecycle decision below.
+
+## Non-goals
+
+* **Gasless deposits from self-custody wallets** (EIP-2612 `permit` / Permit2
+ sponsoring): a related but different problem — and mainnet USDT does not implement
+ EIP-2612. Deposit addresses incidentally also cover this use case (a self-custody
+ wallet can simply `transfer` to the deposit address), which further reduces its
+ urgency.
+* **Deposits from L2s / other chains**: only Ethereum L1 withdrawals are in scope. A
+ CEX withdrawal on Arbitrum/Base to the deposit address is out of scope (and must be
+ documented as unsupported).
+* **Replacing the helper-contract flow**: the existing flow remains the cheapest path
+ for power users and is untouched.
+* **Automatic discovery without any user/frontend interaction**: crediting is
+ claim-based (see Design Decisions); a frontend polling on the user's behalf makes
+ this invisible in practice.
+* **Automatic recovery of unsupported-token deposits**: funds remain recoverable
+ (key-controlled address) but recovery tooling is future work.
+* **Replenishing the sweep-gas fee account**: sweep gas is burned from the minter's
+ ckETH fee account (`R14`), while deposit-fee revenue accrues per ckToken
+ (ckUSDC, ckUSDT, …). Converting that revenue into ckETH to keep the fee account
+ funded is a treasury/market operation outside this design; the design only
+ requires that sweeping halts safely when the fee account is empty.
+* Accepted residual limitations:
+ * A CEX that batches ETH withdrawals through a contract (internal transactions)
+ provides no sender information without trace APIs; Phase 2 compliance screening is
+ therefore weaker for ETH than for ERC-20 (see Phase 2 section).
+ * An account's ETH deposit address (Phase 2) differs from its ERC-20 one, matching
+ the per-asset deposit-address UX of exchanges; sending the wrong asset class to
+ an address is not credited automatically, but funds always remain recoverable
+ (key-controlled addresses, `R12` guarantees no loss on the sender side).
+
+## Design Decisions
+
+* **Attribution by destination address, not by sender or contract call.** This is the
+ only mechanism compatible with plain CEX transfers. Chosen over sender-address
+ registration (CEX hot wallets are shared and unpredictable) and exact-amount
+ matching (collision-prone, griefable); see Discussed Alternatives.
+* **Deposit addresses are tECDSA-derived EOAs, not contracts.** The minter derives one
+ EOA per IC account using a non-empty ECDSA derivation path (the main address keeps
+ the empty path `MAIN_DERIVATION_PATH`). Decisive property: *the minter holds the
+ key*. Funds at a deposit address are never dependent on contract code being correct —
+ even with no EIP-7702 at all, any balance is recoverable by classically funding the
+ address with gas and signing a normal transfer. Chosen over CREATE2 counterfactual
+ forwarder contracts, where funds are controlled by code alone (see Discussed
+ Alternatives).
+* **Sweeping via EIP-7702, gas paid by the minter's main address.** Each deposit EOA
+ signs (threshold ECDSA) a one-time EIP-7702 authorization delegating its code to a
+ single immutable, storage-less sweeper delegate whose only capability is *transfer
+ everything to the minter's main address*. Sweep transactions are type-`0x04`
+ transactions sent from the funded main address; many deposit addresses are swept in
+ one transaction. No deposit address ever needs an ETH balance for gas.
+* **Sweeps are permissionless-safe** (variant A). The delegate's sweep functions are
+ callable by anyone because the destination is hardcoded (`R6`); a third party
+ triggering a sweep only donates gas. This removes access-control state from the
+ delegate and lets one transaction sweep many deposit addresses through a batch entry
+ point on the deployed `CkSweeper` instance itself — the delegate doubles as the
+ batcher, so no additional contract is needed (the canonical, already-deployed
+ [Multicall3](https://www.multicall3.com/) would work as well). Variant B trades this
+ property away, see the open decision below.
+* **Mint on finalized deposit, sweep asynchronously** (variant A). The user is
+ credited as soon as the deposit is finalized and detected; sweeping is pure treasury
+ consolidation, batched to amortize gas, and never blocks or reverts a mint (`R5`).
+ This decouples UX latency from gas-optimization policy. Variant B instead credits on
+ the sweep's own finalized event, see the open decision below.
+* **Claim-based detection instead of continuous scraping.** Deposits are detected when
+ a `notify_deposit` endpoint is called for a specific account (by the user, or
+ transparently by a frontend/timer polling recently active addresses). A targeted
+ `eth_getLogs` on one token contract filtered by one recipient address is small and
+ cheap; continuously scraping `Transfer` logs for an unbounded, growing set of
+ addresses is not. This mirrors ckBTC's `update_balance`. (The existing helper-contract
+ scraping is unchanged.)
+* **No up-front spending per registered address (anti-DoS).** `get_deposit_address`
+ is pure key derivation plus a state entry: no threshold-ECDSA signature, no
+ Ethereum transaction (`R13`). Registrations are free for callers, so any eager
+ per-address spending — signing the delegation up-front, let alone submitting it
+ on-chain — would let an attacker drain the minter's cycles and ETH by spamming
+ registrations. The pipeline is strictly gated: register → observe a balance of a
+ supported token ≥ the per-token minimum at the address (targeted, claim-driven
+ scan) → only then sign the delegation and sweep. For the same reason the balance
+ scanning itself must stay bounded: the registered set is attacker-inflatable, so
+ scans are claim-driven (`notify_deposit`, guarded per account) or bounded batches,
+ never an unbounded standing scan of every registered address.
+* **Phase 1 delegation is therefore installed lazily, with the first sweep, and is
+ permanent.** For ERC-20-only crediting, delegated code on the deposit address is
+ harmless (ERC-20 transfers never execute recipient code), so one authorization per
+ address — ever — suffices. Phase 2 sidesteps the question for native ETH with
+ separate, never-delegated ETH deposit addresses (see below).
+* **Fees are deducted from the minted amount and land in a fee account.** A CEX
+ depositor owns no ckETH to pay gas with, so the sweep cost is recovered as a
+ per-token flat fee: the depositor is credited `amount - deposit_fee` and the fee
+ portion is minted to a minter-controlled fee account on the same ckToken ledger —
+ the full deposited amount is swept, so minting it in full keeps supply exactly
+ equal to backing and makes fee revenue explicit and auditable. Flat and
+ proposal-configurable rather than oracle-priced, for simplicity and predictability
+ (`R7`).
+* **Sweep gas is paid by the minter's ETH, but never out of ckETH backing (`R14`).**
+ The ETH at the minter's main address backs ckETH 1:1, so spending it on sweep gas
+ without a matching ckETH burn would leave ckETH under-backed. Sweeps are therefore
+ funded exclusively through the minter's fee account on the ckETH ledger, mirroring
+ how withdrawals already pay for gas (burn ckETH, spend ETH): before submitting a
+ sweep, the minter **burns first** — at least the transaction's maximum fee
+ (`gas_limit × max_fee_per_gas`, an overestimate by construction) minus any
+ previously burned-but-unspent credit. The receipt's effective fee is then deducted
+ from a running `prepaid_sweep_gas` counter; the leftover of the overestimate is
+ **not re-minted** but carried as credit for the next burn, so the invariant
+ "cumulative burned ≥ cumulative spent" holds at every instant. An empty ckETH fee
+ account halts sweeping (safely: under variant A, credited balances are unaffected
+ and deposits keep accumulating at key-controlled addresses; under variant B,
+ crediting pauses with sweeping); replenishing it is out of scope (see Non-goals).
+
+### Open decision: what the sweep does — variant A (direct) vs variant B (through the helper contract)
+
+Both variants share everything above (address derivation, EIP-7702 delegation,
+batching, fees); they differ in the delegate's action and, consequently, in *where
+crediting happens*. The decision between them is **not yet taken**.
+
+**Variant A — direct sweep (`CkSweeper`).** The delegate transfers the funds straight
+to the minter's main address. Crediting requires a *new* detection-and-mint path in
+the minter (`notify_deposit` → finalized `Transfer` log → mint), with its own event
+types, deduplication and audit trail. Sweeps are permissionless-safe and mint timing
+is independent of sweep scheduling. Measured in the demo (mock USDT): 66'854 gas for
+a first single-address sweep including its authorization, ≈ 26k marginal gas per
+additional address in a batch.
+
+**Variant B — sweep through the existing helper contract (`CkSweeperViaHelper`).**
+The delegate approves and calls `depositErc20` on the already-deployed helper
+(`DepositHelperWithSubaccount.sol`): the helper moves the funds to the minter *and
+emits the canonical `ReceivedEthOrErc20` event* — with the deposit EOA as `owner` and
+a caller-supplied IC principal/subaccount — at the single contract address the minter
+already scrapes. **The minter's crediting pipeline (scrape → parse → dedup → mint) is
+reused unchanged.** Consequences:
+
+* *Massively smaller minter change.* No second crediting path: deposit detection is
+ demoted from a correctness-critical component to a mere sweep-scheduling hint (it
+ can be sloppy, delayed, or even frontend-driven without any double-mint or
+ lost-credit risk). Correctness lives entirely in the existing, battle-tested
+ pipeline.
+* *Sweeping must be restricted to the minter.* The principal is a sweep argument, so a
+ permissionless sweep would let anyone credit a deposit to their own principal. The
+ delegate stays stateless via two immutables: `MINTER`, and `SELF` (the deployed
+ instance's own address, captured at construction), accepting
+ `msg.sender ∈ {MINTER, SELF}` so the batch entry point still works. Belt-and-braces,
+ the minter additionally validates scraped events whose `owner` is a registered
+ deposit address against its own address↔account map and quarantines mismatches.
+* *Minting follows the sweep, but latency need not suffer.* The minter can schedule
+ the sweep as soon as it observes the deposit at the `latest` block, **without
+ waiting for the deposit to be finalized**: crediting only ever follows the
+ *finalized* helper event emitted by the sweep itself, so a reorg that drops the
+ deposit merely wastes the sweep's gas (the delegate sweeps a zero balance — a
+ no-op) and costs some cycles; a reorged sweep transaction is handled by the
+ existing nonce-tracking and resubmission machinery. End-to-end latency is then
+ comparable to today's helper flow (deposit inclusion + sweep + finalization).
+* *Screening point shifts.* The scraped event's `from`/`owner` is the deposit EOA,
+ not the CEX hot wallet, so blocklist screening of the actual sender (`R3`) must
+ happen when scheduling the sweep, based on the observed `Transfer` log.
+* *Extra gas per sweep* for `approve` + `transferFrom` + event. Measured in the demo:
+ 82'207 gas single (+15'353 vs variant A), 164'746 for a batch re-delegating three
+ EOAs and sweeping two of them through the helper.
+* *Native ETH works symmetrically* via the helper's `depositEth` (Phase 2).
+
+Both variants are exercised end-to-end in the runnable demo, including the
+adversarial case for variant B (a non-minter caller attempting to sweep with their
+own principal is rejected).
+
+## Implementation
+
+### End-to-end flows
+
+Deposit of USDT from a CEX under **variant A** (direct sweep; crediting via a new
+detection path, mint on finalized deposit, sweep asynchronously):
+
+```mermaid
+sequenceDiagram
+ autonumber
+ actor User as User (principal p)
+ participant CEX
+ participant Minter
+ participant Eth as Ethereum (via EVM-RPC)
+ participant CkUsdtLedger as ckUSDT ledger
+ participant CkEthLedger as ckETH ledger
+
+ User->>Minter: get_deposit_address(p)
+ Note right of Minter: derive addr(p) locally, register it.
No tECDSA signature, no Ethereum tx (R13)
+ Minter-->>User: addr(p)
+ User->>CEX: withdraw USDT to addr(p)
+ CEX->>Eth: USDT.transfer(addr(p), 250)
+ loop frontend polls until credited
+ User->>Minter: notify_deposit(p)
+ Minter->>Eth: eth_getLogs(USDT Transfer to addr(p), up to finalized)
+ end
+ Note over Minter: amount >= min (R4), sender not blocked (R3),
dedup by (tx hash, log index) (R2)
+ Minter->>CkUsdtLedger: mint 250 - fee to p
+ Minter->>CkUsdtLedger: mint fee to minter fee account
+ Note over Minter: user is credited - sweeping is asynchronous
treasury consolidation (R5)
+ Minter->>CkEthLedger: burn max_tx_fee - prepaid_sweep_gas
from the ckETH fee account (R14)
+ Note over Minter: sign EIP-7702 authorization for addr(p)
(tECDSA, only before the first sweep)
+ Minter->>Eth: type-0x04 tx: sweepErc20 on addr(p)
USDT: addr(p) -> minter address
+ Eth-->>Minter: receipt: prepaid_sweep_gas -= effective fee
+```
+
+Deposit of USDT from a CEX under **variant B** (sweep through the existing helper
+contract; crediting via the unchanged existing pipeline):
+
+```mermaid
+sequenceDiagram
+ autonumber
+ actor User as User (principal p)
+ participant CEX
+ participant Minter
+ participant Eth as Ethereum (via EVM-RPC)
+ participant CkUsdtLedger as ckUSDT ledger
+ participant CkEthLedger as ckETH ledger
+
+ User->>Minter: get_deposit_address(p)
+ Minter-->>User: addr(p)
+ User->>CEX: withdraw USDT to addr(p)
+ CEX->>Eth: USDT.transfer(addr(p), 250)
+ Minter->>Eth: balance scan of registered addresses (latest block)
+ Note over Minter: scheduling hint only, no finality needed:
a reorged deposit just wastes the sweep's gas
+ Minter->>CkEthLedger: burn max_tx_fee - prepaid_sweep_gas (R14)
+ Minter->>Eth: type-0x04 tx: sweepErc20(tokens, p, s) on addr(p)
= approve + helper.depositErc20:
USDT: addr(p) -> minter address, and the helper emits
ReceivedEthOrErc20(USDT, addr(p), 250, p, s)
+ Eth-->>Minter: receipt: prepaid_sweep_gas -= effective fee
+ Note over Minter,Eth: from here the EXISTING deposit pipeline runs unchanged
+ Minter->>Eth: eth_getLogs(helper contract, up to finalized)
+ Note over Minter: cross-check owner addr(p) vs p against own map,
dedup by (tx hash, log index)
+ Minter->>CkUsdtLedger: mint 250 - fee to p, fee to minter fee account
+```
+
+Deposit of ETH from a CEX (**Phase 2**, dedicated never-delegated ETH deposit
+address; the deposit pays its own sweep gas, no `R14` burn involved):
+
+```mermaid
+sequenceDiagram
+ autonumber
+ actor User as User (principal p)
+ participant CEX
+ participant Minter
+ participant Eth as Ethereum (via EVM-RPC)
+ participant CkEthLedger as ckETH ledger
+
+ User->>Minter: get_deposit_address(p) for ETH
+ Minter-->>User: eth_addr(p) (schema 2: never delegated, never any code)
+ User->>CEX: withdraw ETH to eth_addr(p)
+ CEX->>Eth: plain transfer, even with a fixed 21000 gas limit (R12)
+ User->>Minter: notify_deposit(p) (frontend polls)
+ Minter->>Eth: eth_getBalance(eth_addr(p), finalized)
+ alt variant A
+ Minter->>CkEthLedger: mint balance delta - fee to p (R11),
fee to minter fee account
+ Minter->>Eth: EIP-1559 tx FROM eth_addr(p), signed via tECDSA:
transfer balance - gas to the minter address
(max fee capped by the charged deposit fee)
+ else variant B
+ Minter->>Eth: EIP-1559 tx FROM eth_addr(p), signed via tECDSA:
helper.depositEth{value: balance - gas}(p, s)
+ Minter->>Eth: eth_getLogs(helper contract, up to finalized)
+ Minter->>CkEthLedger: mint to p (existing pipeline, unchanged)
+ end
+```
+
+### Constraints
+
+* The minter's transaction layer supports only EIP-1559 (type `0x02`) transactions
+ (`src/tx.rs`, `EIP1559_TX_ID`); EIP-7702 requires adding the type `0x04`
+ (`SetCode`) transaction and authorization-tuple signing.
+* The minter's main address uses the *empty* ECDSA derivation path
+ (`MAIN_DERIVATION_PATH` in `src/lib.rs`); any per-account path must be non-empty and
+ collision-free with it. Withdrawals assume a single sequential nonce for the main
+ address (`src/state/transactions`); sweep transactions originate from the main
+ address and therefore share that nonce sequence.
+* All Ethereum interaction goes through the EVM-RPC canister with multi-provider
+ threshold consensus (`src/eth_rpc_client/`); every new call (`eth_getLogs` per
+ deposit address, `eth_getBalance`, `eth_getTransactionCount` for deposit EOAs) must
+ use the same reduction strategies.
+* Each EVM-RPC call today is one HTTPS outcall *per provider* and each outcall burns
+ cycles, so observing the balances of many registered addresses (`R13` gate) must
+ not cost one call per address. This depends on **JSON-RPC batch request support in
+ the EVM-RPC canister** (`eth_batch`,
+ [dfinity/evm-rpc-canister#561](https://github.com/dfinity/evm-rpc-canister/pull/561),
+ in progress): one batch of `eth_getBalance` / `eth_call` requests per outcall.
+ Until it lands, a [Multicall3](https://www.multicall3.com/) `aggregate3` `eth_call`
+ can read many `balanceOf` (and, via `getEthBalance`, native ETH) values in a single
+ request — at the cost of depending on an extra on-chain contract.
+* The minter is event-sourced (`src/state/audit.rs`, `src/state/event.rs`): all new
+ state must be reconstructible from persisted events (`R8`).
+* Deposits are only credited at *finalized* blocks, as today.
+
+### Address derivation and registration
+
+* Derivation path for account `(p, s)`:
+ `[SCHEMA_DEPOSIT_ADDRESS, p.as_slice(), s]` where `SCHEMA_DEPOSIT_ADDRESS = [1u8]`
+ is a schema tag reserving room for future schemes, and `s` is the 32-byte subaccount
+ (all-zero for the default subaccount). Non-empty by construction, hence distinct
+ from the main address path.
+* The child *public key* (and hence the address) is computed locally from the cached
+ master public key using non-hardened derivation (`ic-secp256k1`'s
+ `derive_subkey` / `DerivationPath`, as ckBTC does) — no management-canister call and
+ no signature is needed to *create* an address; `sign_with_ecdsa` with the same path
+ is only invoked to sign authorizations (and, as a recovery fallback, transactions).
+* New endpoint `get_deposit_address(account) -> String` (EIP-55 checksummed). The
+ first call is an update call that registers the address in state
+ (`deposit_addresses: Account ↔ Address` bimap + per-address bookkeeping:
+ `registered_at_block`, delegation status, credited/swept counters), emitting a
+ `DepositAddressRegistered` audit event — and does nothing else: no threshold-ECDSA
+ signature, no Ethereum transaction (`R13`). Any per-address spending happens only
+ once a balance ≥ the per-token minimum has been observed at the address.
+ Subsequent calls are cheap lookups.
+
+### Deposit detection and minting (Phase 1, ckERC20)
+
+* New endpoint `notify_deposit(account, token?)` (update, fee-less, guarded against
+ concurrent calls per account like `update_balance` in ckBTC):
+ 1. Look up the registered deposit address; determine the block range
+ `(last_checked_block + 1) ..= latest_finalized_block`.
+ 2. `eth_getLogs` with `address = token contract(s)`, `topics = [Transfer,
+ any, deposit_address]` over that range (chunked by the existing 500-block spread
+ logic). The response is tiny: it concerns a single recipient.
+ 3. For each log: validate amount ≥ per-token minimum (`R4`), screen the `Transfer`
+ sender against the blocklist (`R3`), deduplicate by `(tx_hash, log_index)` and
+ record `AcceptedErc20Deposit`-style events with a new deposit-source variant;
+ invalid ones are recorded like today's `InvalidDeposit`.
+ 4. Mint through the existing `mint()` path with `amount - deposit_fee`, reusing the
+ ledger-client, memo (tx hash + log index) and quarantine-on-panic machinery
+ (`R2`).
+* A frontend (e.g. OISY) polls `notify_deposit` after showing the address, so the flow
+ is automatic from the user's perspective; a background timer may additionally
+ re-check addresses with recent activity, bounded to a fixed batch per tick.
+* Scanning many registered addresses at once (the `R13` gate, and cheap periodic
+ re-checks) reads balances in bulk rather than per address: a single JSON-RPC batch
+ of `balanceOf` `eth_call`s / `eth_getBalance`s per HTTPS outcall once the EVM-RPC
+ canister supports `eth_batch`
+ ([dfinity/evm-rpc-canister#561](https://github.com/dfinity/evm-rpc-canister/pull/561)),
+ or one Multicall3 `aggregate3` `eth_call` for a whole batch meanwhile. A cheap
+ balance scan decides *whether* to act; the log-based steps above remain the source
+ of truth for crediting (variant A) or the helper event does (variant B).
+
+### Sweeper delegate contract
+
+A single immutable Solidity contract, deployed once per network, with **no storage**
+(EIP-7702 delegates share the EOA's storage; using none avoids collision hazards
+entirely) and the minter's main address hardcoded as an `immutable`. Shown below for
+variant A; variant B's delegate (`CkSweeperViaHelper` in the demo) has the same shape
+but calls the helper's `depositErc20` with caller-supplied principal/subaccount and
+restricts callers to the minter (see the open decision above):
+
+```solidity
+contract CkSweeper {
+ address payable private immutable MINTER;
+ constructor(address minter) { MINTER = payable(minter); }
+
+ /// Callable by anyone: funds can only move to MINTER (R6).
+ function sweepErc20(IERC20[] calldata tokens) external {
+ for (uint i = 0; i < tokens.length; ++i) {
+ uint256 b = tokens[i].balanceOf(address(this));
+ if (b > 0) tokens[i].safeTransfer(MINTER, b); // USDT-safe transfer
+ }
+ }
+
+ /// Batch entry point: the deployed CkSweeper instance doubles as the
+ /// batcher, sweeping many delegated deposit EOAs in a single transaction.
+ function sweepErc20Batch(address[] calldata depositAddresses, address[] calldata tokens) external {
+ for (uint i = 0; i < depositAddresses.length; ++i) {
+ CkSweeper(depositAddresses[i]).sweepErc20(tokens);
+ }
+ }
+
+ function sweepEth() external {
+ if (address(this).balance > 0) {
+ (bool ok,) = MINTER.call{value: address(this).balance}("");
+ require(ok);
+ }
+ }
+}
+```
+
+Notes: `safeTransfer` handles non-standard ERC-20s (USDT returns no value); no
+`receive()` is defined on purpose — plain ETH sends to a *delegated* address are meant
+to fail rather than be silently accepted while delegated (Phase 2, `R12`); reentrancy
+is moot (fixed destination, no state).
+
+### EIP-7702 support in the transaction layer (`src/tx.rs`)
+
+* New `Eip7702TransactionRequest` with `SET_CODE_TX_ID: u8 = 4`, payload
+ `0x04 || rlp([chain_id, nonce, max_priority_fee_per_gas, max_fee_per_gas, gas_limit,
+ to, value, data, access_list, authorization_list, y_parity, r, s])`.
+* `AuthorizationTuple { chain_id, delegate, nonce, y_parity, r, s }`, signed over
+ `keccak256(0x05 || rlp([chain_id, delegate, nonce]))` with `sign_with_ecdsa` using
+ the deposit address' derivation path; `chain_id` is set explicitly (never 0) to
+ prevent cross-chain replay; recovery-id determination reuses the existing
+ `Eip1559Signature` machinery.
+* Deposit-EOA nonces: fetched via `eth_getTransactionCount` (finalized) with the usual
+ consensus strategy at authorization-signing time; an applied authorization increments
+ the EOA nonce, tracked in state to avoid re-fetching. Deposit EOAs never send
+ transactions themselves, so races are limited to re-delegation.
+* Resubmission with fee bumping mirrors the existing `Resubmittable` logic.
+
+### Sweeping task
+
+* A periodic task selects deposit addresses with observed-but-unswept balances where
+ `unswept_value ≥ sweep_gas_cost × margin` or `age > max_age`, up to `N` addresses
+ per batch (gas-limit bound; initial `N ≈ 20`). Only addresses that pass this gate
+ ever cost the minter anything: the delegation authorization is signed here, not at
+ registration time (`R13`).
+* Before submission, burn `max(0, gas_limit × max_fee_per_gas - prepaid_sweep_gas)`
+ from the minter's fee account on the ckETH ledger and add it to
+ `prepaid_sweep_gas`; abort the sweep (and retry later) if the burn fails (`R14`).
+ On the receipt, subtract the effective transaction fee from `prepaid_sweep_gas` —
+ the surplus of the overestimate stays as credit for the next burn and is never
+ re-minted. Both movements are recorded as audit events and `prepaid_sweep_gas` is
+ exposed on the dashboard (`R8`, `R9`).
+* One type-`0x04` transaction from the main address:
+ * `authorization_list`: tuples for all not-yet-delegated addresses in the batch
+ (≈ 12'500–25'000 gas each, one-time);
+ * `to = CkSweeper`, `data = sweepErc20Batch(deposit_addresses, [tokens])`. Measured
+ in the runnable demo (mock token): ≈ 67k gas for a first single-address sweep
+ including its authorization, ≈ 26k marginal gas per additional address in a batch.
+* Confirmation via transaction receipt, exactly like withdrawals; on success emit
+ `SweepConfirmed` events updating per-address `total_swept`. Sweep gas is paid from
+ the main address' ETH balance and recouped by `deposit_fee` (`R7`); the effective
+ fee/cost ratio is exported as a metric to recalibrate fees via proposal.
+* Accounting invariant: main-address liquidity for withdrawals = today's
+ `eth_balance` bookkeeping; credited-but-unswept amounts are tracked per address and
+ shown on the dashboard (`R9`).
+
+### Phase 2: native ETH
+
+Two ETH-specific problems and their resolutions:
+
+1. **Detection without logs.** Plain ETH transfers emit no events, and CEXs may send
+ ETH via internal transactions (contract-batched withdrawals), which even
+ `eth_getTransactionByHash` cannot attribute without trace APIs. Detection is
+ therefore **balance-based**: `notify_deposit` reads `eth_getBalance(addr,
+ finalized)` and credits `balance + total_swept - total_credited` when the delta
+ exceeds the ETH minimum (`R11`). This is robust to internal transactions and
+ requires no trace support from providers.
+ * Compliance caveat: balance deltas carry no sender information. Screening is
+ limited to (a) optional sender screening when the caller supplies withdrawal
+ transaction hashes, and (b) address-level screening. This weakening relative to
+ `R3` is an accepted limitation (see Non-goals) and should be reviewed with
+ compliance before Phase 2 ships.
+2. **Fixed 21'000-gas transfers vs delegated code (`R12`).** A value transfer to an
+ address with EIP-7702 delegated code *executes* that code, and a transfer with
+ exactly 21'000 gas has zero gas left for execution — it always fails (with the
+ Phase 1 delegate, which deliberately has no `receive()`, it fails at any gas).
+ Exchanges commonly hard-code 21'000 for ETH withdrawals, so ETH deposits and a
+ (permanently) delegated address are incompatible.
+
+ Resolution: **a separate, ETH-specific deposit address per account, which is
+ never delegated.** The key observation is that a native-ETH deposit *carries its
+ own gas* — the EIP-7702 machinery exists only because ERC-20 tokens cannot pay
+ for their own movement, and ETH can:
+ * Derivation reuses the Phase 1 scheme with a second schema tag
+ (`SCHEMA_ETH_DEPOSIT_ADDRESS = [2u8]` instead of `[1u8]`), so an account's ETH
+ deposit address differs from its ERC-20 one.
+ * The ETH address never carries code: fixed-21'000-gas CEX withdrawals *always*
+ succeed — `R12` is satisfied trivially, with no failure window at all.
+ * Sweep: a plain EIP-1559 transfer of `balance - fee` signed with the address'
+ own derived key (`sign_with_ecdsa`), gas paid from the swept balance itself —
+ 21'000 gas, the cheapest possible sweep; the ETH minimum deposit covers it.
+ One tECDSA signature and a per-address nonce (only the minter ever sends from
+ it) per sweep; fee-refund dust left at the address rolls into the next sweep.
+ * No `R14` burn is involved: the gas never comes out of the minter's
+ main-address backing. However, since (under variant A) the account is credited
+ `balance - fee` *before* the sweep executes, the sweep's
+ `gas_limit × max_fee_per_gas` must be capped by the charged deposit fee — if
+ gas prices exceed that cap, the sweep waits — so that the gas spent can never
+ exceed what was withheld from minting.
+ * Under variant B, the sweep is instead a call to the helper's
+ `depositEth{value: balance - fee}(principal, subaccount)` signed the same way:
+ slightly more gas, but the sweep emits the canonical event and the existing
+ pipeline credits ckETH unchanged.
+ * Cross-asset mistakes remain recoverable in both directions: ERC-20 sent to an
+ ETH address sits at a tECDSA-controlled EOA (delegate it on demand to sweep);
+ ETH sent to a not-yet-delegated ERC-20 address is recovered by the delegate's
+ `sweepEth`, and once the ERC-20 address is delegated, plain ETH sends to it
+ fail on the sender side, so funds never leave the exchange.
+
+ The previously considered *set-and-clear* delegation lifecycle on a single shared
+ address (install the delegate, sweep, re-delegate to `address(0)` — two tECDSA
+ signatures and ≈ 2 × 12'500–25'000 gas per sweep cycle, with a short window in
+ which fixed-gas ETH transfers fail) is kept only as a fallback if per-asset
+ addresses are rejected for UX reasons.
+
+### Test plan
+
+A runnable end-to-end demonstration of the sweep mechanism (unfunded deposit EOAs,
+plain USDT-style transfers, single and batched type-`0x04` sweep transactions with gas
+paid by the minter, gas assertions) against a local dev node (any post-Pectra
+version) is available in [`deposit_from_cex_demo/`](deposit_from_cex_demo/README.md).
+It exercises both sweep variants — including variant B against the *real*
+`DepositHelperWithSubaccount.sol` bytecode, asserting the emitted
+`ReceivedEthOrErc20` events carry the right principals, re-delegation of already
+delegated deposit EOAs, and the rejected non-minter sweep attempt.
+
+Unit tests (in `tests.rs` files per module, helpers in `test_fixtures.rs`):
+
+* Address derivation: determinism, uniqueness across principals/subaccounts,
+ non-collision with the main address, EIP-55 encoding (`R1`).
+* Type-`0x04` transaction and authorization encoding/signing against EIP-7702
+ published test vectors; authorization hash `0x05 || rlp(...)`; recovery-id
+ round-trip (`R5`, `R6` plumbing).
+* `Transfer`-log parsing, minimum/fee arithmetic incl. `amount ≤ fee` rejection
+ (`R2`, `R4`), blocklist screening (`R3`), dedup by `(tx_hash, log_index)` (`R2`).
+* Balance-delta crediting monotonicity across sweep interleavings (`R11`).
+* Event replay: state reconstructed from audit events equals live state (`R8`).
+
+Integration tests (state-machine tests in `rs/ethereum/cketh/minter/tests` with the
+mocked EVM-RPC canister, extending the existing fixtures):
+
+* End-to-end Phase 1 happy path: register address → mock `Transfer` log → notify →
+ mint − fee → sweep tx submitted with expected `0x04` payload → receipt → swept
+ (`R2`, `R5`, `R7`).
+* Double-notify / concurrent-notify produce a single mint (`R2`); blocked sender
+ (`R3`); below-minimum and unsupported token (`R4`); sweep failure then retry with
+ fee bump, mint unaffected (`R5`); withdrawal flow regression (`R10`); dashboard
+ rendering (`R9`).
+* Solidity: Foundry tests for `CkSweeper` (permissionless sweep only reaches minter,
+ USDT-style token, delegated-EOA execution against a Prague-enabled local node)
+ (`R6`, `R12`).
+
+Verification commands: `bazel test //rs/ethereum/cketh/minter:lib_unit_tests
+//rs/ethereum/cketh/minter/tests:...` (exact targets per PR), plus `forge test` for
+the delegate.
+
+### Delivery / PR sequence
+
+1. **EIP-7702 transaction support** in `src/tx.rs` + authorization signing in
+ `src/management` — pure library code, no behavior change. AC: encoding/signing unit
+ tests vs. EIP test vectors.
+2. **Deposit address derivation, registration state, `get_deposit_address`** + audit
+ events + dashboard section. AC: `R1`, `R8`, `R9` (addresses only).
+3. **ckERC20 deposit detection and minting** (`notify_deposit`, log queries, fees,
+ minimums, blocklist). AC: `R2`, `R3`, `R4`, `R7` (fee deduction), `R8`.
+4. **Sweeper delegate contract** (Solidity, audited) + **sweeping task** (delegation,
+ Multicall3 batching, receipts, metrics). AC: `R5`, `R6`, `R7`, `R9`, `R10`.
+5. **Phase 1 launch on Sepolia**, then mainnet via NNS upgrade proposal; frontend
+ (OISY) integration of `get_deposit_address` + `notify_deposit` polling.
+6. **Phase 2: ckETH** (balance-delta crediting, set-and-clear delegation lifecycle,
+ compliance sign-off). AC: `R11`, `R12`.
+
+## Discussed Alternatives
+
+* **CREATE2 counterfactual forwarder contracts** (the classic exchange pattern): a
+ factory computes `CREATE2(factory, salt = hash(account), forwarder_init_code)`
+ addresses; sweeping deploys the forwarder, which pushes funds to the minter and
+ `selfdestruct`s in the same transaction (still permitted post-EIP-6780), leaving the
+ address codeless. Pros: decade of production use by exchanges, no dependency on
+ EIP-7702 or a new transaction type, native-ETH-safe by construction. Rejected as
+ the primary design because funds at deposit addresses would be controlled *by code
+ alone* — a factory/forwarder bug strands funds with no recovery — whereas tECDSA
+ EOAs keep key-based recovery independent of any contract; CREATE2 also costs more
+ gas per sweep (redeployment every cycle) and inherits residual `selfdestruct`
+ protocol risk. It remains the documented fallback if EIP-7702 adoption in the
+ transaction layer is reconsidered.
+* **ERC-4337 smart accounts + paymaster**: counterfactual 4337 accounts as deposit
+ addresses with sponsored sweeps. Rejected: the minter is already its own transaction
+ submitter with multi-provider consensus, so EntryPoint/bundler/paymaster
+ infrastructure adds ≈100k+ gas per operation, an external-bundler dependency, and a
+ large audit surface for zero benefit over EIP-7702 here.
+* **EIP-2612 permit / Permit2 sponsored helper deposits**: gasless `depositWithPermit`
+ relayed by the minter. Does not address CEX at all (a hot wallet signs no custom
+ message) and mainnet USDT lacks EIP-2612; noted as possible future work for
+ self-custody UX only.
+* **Attribution hacks on the single minter address**: sender-address registration
+ (CEX hot wallets are shared/unpredictable), exact-amount matching (collisions,
+ fee-adjusted amounts, griefable by front-running), or per-exchange integration of
+ the helper contract (business-development dependency, not a protocol design). All
+ rejected as unsound.
+* **Continuous scraping of `Transfer` logs for all deposit addresses** instead of
+ claim-based detection: `eth_getLogs` with a growing disjunction of thousands of
+ recipient topics scales linearly in cost with the user base, must be chunked across
+ providers' topic limits, and still misses native ETH. Rejected in favor of targeted,
+ claim-triggered queries; can be revisited as an optimization for hot addresses.
+* **Pre-funding deposit EOAs with ETH for gas** (no EIP-7702): requires one extra
+ funding transaction per sweep (≈21k gas + transfer latency), doubles the transaction
+ count, leaves ETH dust stranded on every deposit address, and complicates fee
+ accounting. Kept only as the implicit *recovery* path that key-controlled addresses
+ always allow.
diff --git a/rs/ethereum/cketh/docs/deposit_from_cex_demo/.gitignore b/rs/ethereum/cketh/docs/deposit_from_cex_demo/.gitignore
new file mode 100644
index 000000000000..00025442dd2a
--- /dev/null
+++ b/rs/ethereum/cketh/docs/deposit_from_cex_demo/.gitignore
@@ -0,0 +1,3 @@
+cache/
+out/
+target/
diff --git a/rs/ethereum/cketh/docs/deposit_from_cex_demo/Cargo.lock b/rs/ethereum/cketh/docs/deposit_from_cex_demo/Cargo.lock
new file mode 100644
index 000000000000..d28b7cd3a11a
--- /dev/null
+++ b/rs/ethereum/cketh/docs/deposit_from_cex_demo/Cargo.lock
@@ -0,0 +1,5057 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+version = 4
+
+[[package]]
+name = "allocator-api2"
+version = "0.2.21"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923"
+
+[[package]]
+name = "alloy"
+version = "1.8.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "50ab0cd8afe573d1f7dc2353698a51b1f93aec362c8211e28cfd3948c6adba39"
+dependencies = [
+ "alloy-consensus",
+ "alloy-contract",
+ "alloy-core",
+ "alloy-eips",
+ "alloy-genesis",
+ "alloy-network",
+ "alloy-provider",
+ "alloy-pubsub",
+ "alloy-rpc-client",
+ "alloy-rpc-types",
+ "alloy-serde",
+ "alloy-signer",
+ "alloy-signer-local",
+ "alloy-transport",
+ "alloy-transport-http",
+ "alloy-transport-ipc",
+ "alloy-transport-ws",
+ "alloy-trie",
+]
+
+[[package]]
+name = "alloy-chains"
+version = "0.2.34"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "84e0378e959aa6a885897522080a990e80eb317f1e9a222a604492ea50e13096"
+dependencies = [
+ "alloy-primitives",
+ "num_enum",
+ "strum",
+]
+
+[[package]]
+name = "alloy-consensus"
+version = "1.8.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7f16daaf7e1f95f62c6c3bf8a3fc3d78b08ae9777810c0bb5e94966c7cd57ef0"
+dependencies = [
+ "alloy-eips",
+ "alloy-primitives",
+ "alloy-rlp",
+ "alloy-serde",
+ "alloy-trie",
+ "alloy-tx-macros",
+ "auto_impl",
+ "borsh",
+ "c-kzg",
+ "derive_more",
+ "either",
+ "k256",
+ "once_cell",
+ "rand 0.8.6",
+ "secp256k1 0.30.0",
+ "serde",
+ "serde_json",
+ "serde_with",
+ "thiserror 2.0.18",
+]
+
+[[package]]
+name = "alloy-consensus-any"
+version = "1.8.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "118998d9015332ab1b4720ae1f1e3009491966a0349938a1f43ff45a8a4c6299"
+dependencies = [
+ "alloy-consensus",
+ "alloy-eips",
+ "alloy-primitives",
+ "alloy-rlp",
+ "alloy-serde",
+ "serde",
+]
+
+[[package]]
+name = "alloy-contract"
+version = "1.8.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7ac9e0c34dc6bce643b182049cdfcca1b8ce7d9c260cbdd561f511873b7e26cd"
+dependencies = [
+ "alloy-consensus",
+ "alloy-dyn-abi",
+ "alloy-json-abi",
+ "alloy-network",
+ "alloy-network-primitives",
+ "alloy-primitives",
+ "alloy-provider",
+ "alloy-pubsub",
+ "alloy-rpc-types-eth",
+ "alloy-sol-types",
+ "alloy-transport",
+ "futures",
+ "futures-util",
+ "serde_json",
+ "thiserror 2.0.18",
+ "tracing",
+]
+
+[[package]]
+name = "alloy-core"
+version = "1.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "62ddde5968de6044d67af107ad835bc0069a7ca245870b94c5958a7d8712b184"
+dependencies = [
+ "alloy-dyn-abi",
+ "alloy-json-abi",
+ "alloy-primitives",
+ "alloy-rlp",
+ "alloy-sol-types",
+]
+
+[[package]]
+name = "alloy-dyn-abi"
+version = "1.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a475bb02d9cef2dbb99065c1664ab3fe1f9352e21d6d5ed3f02cdbfc06ed1abc"
+dependencies = [
+ "alloy-json-abi",
+ "alloy-primitives",
+ "alloy-sol-type-parser",
+ "alloy-sol-types",
+ "itoa",
+ "serde",
+ "serde_json",
+ "winnow",
+]
+
+[[package]]
+name = "alloy-eip2124"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "741bdd7499908b3aa0b159bba11e71c8cddd009a2c2eb7a06e825f1ec87900a5"
+dependencies = [
+ "alloy-primitives",
+ "alloy-rlp",
+ "crc",
+ "serde",
+ "thiserror 2.0.18",
+]
+
+[[package]]
+name = "alloy-eip2930"
+version = "0.2.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9441120fa82df73e8959ae0e4ab8ade03de2aaae61be313fbf5746277847ce25"
+dependencies = [
+ "alloy-primitives",
+ "alloy-rlp",
+ "borsh",
+ "serde",
+]
+
+[[package]]
+name = "alloy-eip7702"
+version = "0.6.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2919c5a56a1007492da313e7a3b6d45ef5edc5d33416fdec63c0d7a2702a0d20"
+dependencies = [
+ "alloy-primitives",
+ "alloy-rlp",
+ "borsh",
+ "k256",
+ "serde",
+ "thiserror 2.0.18",
+]
+
+[[package]]
+name = "alloy-eip7928"
+version = "0.3.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6b827a6d7784fe3eb3489d40699407a4cdcce74271421a01bdffe60cf573bb16"
+dependencies = [
+ "alloy-primitives",
+ "alloy-rlp",
+ "borsh",
+ "once_cell",
+ "serde",
+ "thiserror 2.0.18",
+]
+
+[[package]]
+name = "alloy-eips"
+version = "1.8.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e6ef28c9fdad22d4eec52d894f5f2673a0895f1e5ef196734568e68c0f6caca8"
+dependencies = [
+ "alloy-eip2124",
+ "alloy-eip2930",
+ "alloy-eip7702",
+ "alloy-eip7928",
+ "alloy-primitives",
+ "alloy-rlp",
+ "alloy-serde",
+ "auto_impl",
+ "borsh",
+ "c-kzg",
+ "derive_more",
+ "either",
+ "serde",
+ "serde_with",
+ "sha2",
+]
+
+[[package]]
+name = "alloy-genesis"
+version = "1.8.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bbf9480307b09d22876efb67d30cadd9013134c21f3a17ec9f93fd7536d38024"
+dependencies = [
+ "alloy-eips",
+ "alloy-primitives",
+ "alloy-serde",
+ "alloy-trie",
+ "borsh",
+ "serde",
+ "serde_with",
+]
+
+[[package]]
+name = "alloy-json-abi"
+version = "1.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7c36c9d7f9021601b04bfef14a4b64849f6d73116a4e91e071d7fbfe10247901"
+dependencies = [
+ "alloy-primitives",
+ "alloy-sol-type-parser",
+ "serde",
+ "serde_json",
+]
+
+[[package]]
+name = "alloy-json-rpc"
+version = "1.8.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "422d110f1c40f1f8d0e5562b0b649c35f345fccb7093d9f02729943dcd1eef71"
+dependencies = [
+ "alloy-primitives",
+ "alloy-sol-types",
+ "http",
+ "serde",
+ "serde_json",
+ "thiserror 2.0.18",
+ "tracing",
+]
+
+[[package]]
+name = "alloy-network"
+version = "1.8.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7197a66d94c4de1591cdc16a9bcea5f8cccd0da81b865b49aef97b1b4016e0fa"
+dependencies = [
+ "alloy-consensus",
+ "alloy-consensus-any",
+ "alloy-eips",
+ "alloy-json-rpc",
+ "alloy-network-primitives",
+ "alloy-primitives",
+ "alloy-rpc-types-any",
+ "alloy-rpc-types-eth",
+ "alloy-serde",
+ "alloy-signer",
+ "alloy-sol-types",
+ "async-trait",
+ "auto_impl",
+ "derive_more",
+ "futures-utils-wasm",
+ "serde",
+ "serde_json",
+ "thiserror 2.0.18",
+]
+
+[[package]]
+name = "alloy-network-primitives"
+version = "1.8.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "eb82711d59a43fdfd79727c99f270b974c784ec4eb5728a0d0d22f26716c87ef"
+dependencies = [
+ "alloy-consensus",
+ "alloy-eips",
+ "alloy-primitives",
+ "alloy-serde",
+ "serde",
+]
+
+[[package]]
+name = "alloy-primitives"
+version = "1.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4885c1409b6936c4898e646ef58baf6ec54edaf6d8179f79df805a7b85b7cf3e"
+dependencies = [
+ "alloy-rlp",
+ "bytes",
+ "cfg-if",
+ "const-hex",
+ "derive_more",
+ "foldhash",
+ "hashbrown 0.17.1",
+ "indexmap 2.14.0",
+ "itoa",
+ "k256",
+ "keccak-asm",
+ "paste",
+ "proptest",
+ "rand 0.9.4",
+ "rapidhash",
+ "ruint",
+ "rustc-hash",
+ "secp256k1 0.31.1",
+ "serde",
+ "sha3",
+]
+
+[[package]]
+name = "alloy-provider"
+version = "1.8.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bf6b18b929ef1d078b834c3631e9c925177f3b23ddc6fa08a722d13047205876"
+dependencies = [
+ "alloy-chains",
+ "alloy-consensus",
+ "alloy-eips",
+ "alloy-json-rpc",
+ "alloy-network",
+ "alloy-network-primitives",
+ "alloy-primitives",
+ "alloy-pubsub",
+ "alloy-rpc-client",
+ "alloy-rpc-types-anvil",
+ "alloy-rpc-types-debug",
+ "alloy-rpc-types-eth",
+ "alloy-rpc-types-trace",
+ "alloy-rpc-types-txpool",
+ "alloy-signer",
+ "alloy-sol-types",
+ "alloy-transport",
+ "alloy-transport-http",
+ "alloy-transport-ipc",
+ "alloy-transport-ws",
+ "async-stream",
+ "async-trait",
+ "auto_impl",
+ "dashmap",
+ "either",
+ "futures",
+ "futures-utils-wasm",
+ "lru",
+ "parking_lot",
+ "pin-project",
+ "reqwest",
+ "serde",
+ "serde_json",
+ "thiserror 2.0.18",
+ "tokio",
+ "tracing",
+ "url",
+ "wasmtimer",
+]
+
+[[package]]
+name = "alloy-pubsub"
+version = "1.8.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5ad54073131e7292d4e03e1aa2287730f737280eb160d8b579fb31939f558c11"
+dependencies = [
+ "alloy-json-rpc",
+ "alloy-primitives",
+ "alloy-transport",
+ "auto_impl",
+ "bimap",
+ "futures",
+ "parking_lot",
+ "serde",
+ "serde_json",
+ "tokio",
+ "tokio-stream",
+ "tower",
+ "tracing",
+ "wasmtimer",
+]
+
+[[package]]
+name = "alloy-rlp"
+version = "0.3.15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dc90b1e703d3c03f4ff7f48e82dd0bc1c8211ab7d079cd836a06fcfeb06651cb"
+dependencies = [
+ "alloy-rlp-derive",
+ "arrayvec 0.7.8",
+ "bytes",
+]
+
+[[package]]
+name = "alloy-rlp-derive"
+version = "0.3.15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f36834a5c0a2fa56e171bf256c34d70fca07d0c0031583edea1c4946b7889c9e"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.118",
+]
+
+[[package]]
+name = "alloy-rpc-client"
+version = "1.8.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "94fcc9604042ca80bd37aa5e232ea1cd851f337e31e2babbbb345bc0b1c30de3"
+dependencies = [
+ "alloy-json-rpc",
+ "alloy-primitives",
+ "alloy-pubsub",
+ "alloy-transport",
+ "alloy-transport-http",
+ "alloy-transport-ipc",
+ "alloy-transport-ws",
+ "futures",
+ "pin-project",
+ "reqwest",
+ "serde",
+ "serde_json",
+ "tokio",
+ "tokio-stream",
+ "tower",
+ "tracing",
+ "url",
+ "wasmtimer",
+]
+
+[[package]]
+name = "alloy-rpc-types"
+version = "1.8.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4faad925d3a669ffc15f43b3deec7fbdf2adeb28a4d6f9cf4bc661698c0f8f4b"
+dependencies = [
+ "alloy-primitives",
+ "alloy-rpc-types-anvil",
+ "alloy-rpc-types-debug",
+ "alloy-rpc-types-engine",
+ "alloy-rpc-types-eth",
+ "alloy-rpc-types-trace",
+ "alloy-rpc-types-txpool",
+ "alloy-serde",
+ "serde",
+]
+
+[[package]]
+name = "alloy-rpc-types-anvil"
+version = "1.8.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "47df51bedb3e6062cb9981187a51e86d0d64a4de66eb0855e9efe6574b044ddf"
+dependencies = [
+ "alloy-primitives",
+ "alloy-rpc-types-eth",
+ "alloy-serde",
+ "serde",
+]
+
+[[package]]
+name = "alloy-rpc-types-any"
+version = "1.8.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3823026d1ed239a40f12364fac50726c8daf1b6ab8077a97212c5123910429ed"
+dependencies = [
+ "alloy-consensus-any",
+ "alloy-rpc-types-eth",
+ "alloy-serde",
+]
+
+[[package]]
+name = "alloy-rpc-types-debug"
+version = "1.8.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2145138f3214928f08cd13da3cb51ef7482b5920d8ac5a02ecd4e38d1a8f6d1e"
+dependencies = [
+ "alloy-primitives",
+ "derive_more",
+ "serde",
+ "serde_with",
+]
+
+[[package]]
+name = "alloy-rpc-types-engine"
+version = "1.8.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bb9b97b6e7965679ad22df297dda809b11cebc13405c1b537e5cffecc95834fa"
+dependencies = [
+ "alloy-consensus",
+ "alloy-eips",
+ "alloy-primitives",
+ "alloy-rlp",
+ "alloy-serde",
+ "derive_more",
+ "rand 0.8.6",
+ "serde",
+ "strum",
+]
+
+[[package]]
+name = "alloy-rpc-types-eth"
+version = "1.8.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "59c095f92c4e1ff4981d89e9aa02d5f98c762a1980ab66bec49c44be11349da2"
+dependencies = [
+ "alloy-consensus",
+ "alloy-consensus-any",
+ "alloy-eips",
+ "alloy-network-primitives",
+ "alloy-primitives",
+ "alloy-rlp",
+ "alloy-serde",
+ "alloy-sol-types",
+ "itertools 0.14.0",
+ "serde",
+ "serde_json",
+ "serde_with",
+ "thiserror 2.0.18",
+]
+
+[[package]]
+name = "alloy-rpc-types-trace"
+version = "1.8.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2e5a4d010f86cd4e01e5205ec273911e538e1738e76d8bafe9ecd245910ea5a3"
+dependencies = [
+ "alloy-primitives",
+ "alloy-rpc-types-eth",
+ "alloy-serde",
+ "serde",
+ "serde_json",
+ "thiserror 2.0.18",
+]
+
+[[package]]
+name = "alloy-rpc-types-txpool"
+version = "1.8.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "942d26a2ca8891b26de4a8529d21091e21c1093e27eb99698f1a86405c76b1ff"
+dependencies = [
+ "alloy-primitives",
+ "alloy-rpc-types-eth",
+ "alloy-serde",
+ "serde",
+]
+
+[[package]]
+name = "alloy-serde"
+version = "1.8.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "11ece63b89294b8614ab3f483560c08d016930f842bf36da56bf0b764a15c11e"
+dependencies = [
+ "alloy-primitives",
+ "serde",
+ "serde_json",
+]
+
+[[package]]
+name = "alloy-signer"
+version = "1.8.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "43f447aefab0f1c0649f71edc33f590992d4e122bc35fb9cdbbf67d4421ace85"
+dependencies = [
+ "alloy-primitives",
+ "async-trait",
+ "auto_impl",
+ "either",
+ "elliptic-curve",
+ "k256",
+ "thiserror 2.0.18",
+]
+
+[[package]]
+name = "alloy-signer-local"
+version = "1.8.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f721f4bf2e4812e5505aaf5de16ef3065a8e26b9139ac885862d00b5a55a659a"
+dependencies = [
+ "alloy-consensus",
+ "alloy-network",
+ "alloy-primitives",
+ "alloy-signer",
+ "async-trait",
+ "k256",
+ "rand 0.8.6",
+ "thiserror 2.0.18",
+]
+
+[[package]]
+name = "alloy-sol-macro"
+version = "1.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "840128ed2b2971d6d4668a553fe403a82683d3acc646c73e75887e7157408033"
+dependencies = [
+ "alloy-sol-macro-expander",
+ "alloy-sol-macro-input",
+ "proc-macro-error2",
+ "proc-macro2",
+ "quote",
+ "syn 2.0.118",
+]
+
+[[package]]
+name = "alloy-sol-macro-expander"
+version = "1.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "63ec265e5d65d725175f6ca7711c970824c90ef9c0d1f1973711d4150ee612dd"
+dependencies = [
+ "alloy-json-abi",
+ "alloy-sol-macro-input",
+ "const-hex",
+ "heck",
+ "indexmap 2.14.0",
+ "proc-macro-error2",
+ "proc-macro2",
+ "quote",
+ "sha3",
+ "syn 2.0.118",
+ "syn-solidity",
+]
+
+[[package]]
+name = "alloy-sol-macro-input"
+version = "1.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "89bf01077f18650876cfa682eb1f949967b5cde03f1a51c955c469d2c9b4aa67"
+dependencies = [
+ "alloy-json-abi",
+ "const-hex",
+ "dunce",
+ "heck",
+ "macro-string",
+ "proc-macro2",
+ "quote",
+ "serde_json",
+ "syn 2.0.118",
+ "syn-solidity",
+]
+
+[[package]]
+name = "alloy-sol-type-parser"
+version = "1.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "857b470ecdd2ed38beaf82ad1a38c516a8ff75266750f38b9eeed001d575241b"
+dependencies = [
+ "serde",
+ "winnow",
+]
+
+[[package]]
+name = "alloy-sol-types"
+version = "1.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "384cf252de0db2dec52821eac037a7f57e2aa33fe5b900ce6fe39973402341f1"
+dependencies = [
+ "alloy-json-abi",
+ "alloy-primitives",
+ "alloy-sol-macro",
+ "serde",
+]
+
+[[package]]
+name = "alloy-transport"
+version = "1.8.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8098f965442a9feb620965ba4b4be5e2b320f4ec5a3fff6bfa9e1ff7ef42bed1"
+dependencies = [
+ "alloy-json-rpc",
+ "auto_impl",
+ "base64",
+ "derive_more",
+ "futures",
+ "futures-utils-wasm",
+ "parking_lot",
+ "serde",
+ "serde_json",
+ "thiserror 2.0.18",
+ "tokio",
+ "tower",
+ "tracing",
+ "url",
+ "wasmtimer",
+]
+
+[[package]]
+name = "alloy-transport-http"
+version = "1.8.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e8597d36d546e1dab822345ad563243ec3920e199322cb554ce56c8ef1a1e2e7"
+dependencies = [
+ "alloy-json-rpc",
+ "alloy-transport",
+ "itertools 0.14.0",
+ "reqwest",
+ "serde_json",
+ "tower",
+ "tracing",
+ "url",
+]
+
+[[package]]
+name = "alloy-transport-ipc"
+version = "1.8.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a1bd98c3870b8a44b79091dde5216a81d58ffbc1fd8ed61b776f9fee0f3bdf20"
+dependencies = [
+ "alloy-json-rpc",
+ "alloy-pubsub",
+ "alloy-transport",
+ "bytes",
+ "futures",
+ "interprocess",
+ "pin-project",
+ "serde",
+ "serde_json",
+ "tokio",
+ "tokio-util",
+ "tracing",
+]
+
+[[package]]
+name = "alloy-transport-ws"
+version = "1.8.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ec3ab7a72b180992881acc112628b7668337a19ce15293ee974600ea7b693691"
+dependencies = [
+ "alloy-pubsub",
+ "alloy-transport",
+ "futures",
+ "http",
+ "rustls",
+ "serde_json",
+ "tokio",
+ "tokio-tungstenite",
+ "tracing",
+ "url",
+ "ws_stream_wasm",
+]
+
+[[package]]
+name = "alloy-trie"
+version = "0.9.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3f14b5d9b2c2173980202c6ff470d96e7c5e202c65a9f67884ad565226df7fbb"
+dependencies = [
+ "alloy-primitives",
+ "alloy-rlp",
+ "derive_more",
+ "nybbles",
+ "serde",
+ "smallvec",
+ "thiserror 2.0.18",
+ "tracing",
+]
+
+[[package]]
+name = "alloy-tx-macros"
+version = "1.8.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d69722eddcdf1ce096c3ab66cf8116999363f734eb36fe94a148f4f71c85da84"
+dependencies = [
+ "darling",
+ "proc-macro2",
+ "quote",
+ "syn 2.0.118",
+]
+
+[[package]]
+name = "android_system_properties"
+version = "0.1.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311"
+dependencies = [
+ "libc",
+]
+
+[[package]]
+name = "anyhow"
+version = "1.0.103"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2a4385e2e34eb35d6b3efe798b9eb88096925d87726c0798709bf56d9ed84af3"
+
+[[package]]
+name = "ar_archive_writer"
+version = "0.5.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4087686b4b0a3427190bae57a1d9a478dbb2d40c5dc1bd6e2b6d797913bdd348"
+dependencies = [
+ "object",
+]
+
+[[package]]
+name = "ark-ff"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6b3235cc41ee7a12aaaf2c575a2ad7b46713a8a50bda2fc3b003a04845c05dd6"
+dependencies = [
+ "ark-ff-asm 0.3.0",
+ "ark-ff-macros 0.3.0",
+ "ark-serialize 0.3.0",
+ "ark-std 0.3.0",
+ "derivative",
+ "num-bigint",
+ "num-traits",
+ "paste",
+ "rustc_version 0.3.3",
+ "zeroize",
+]
+
+[[package]]
+name = "ark-ff"
+version = "0.4.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ec847af850f44ad29048935519032c33da8aa03340876d351dfab5660d2966ba"
+dependencies = [
+ "ark-ff-asm 0.4.2",
+ "ark-ff-macros 0.4.2",
+ "ark-serialize 0.4.2",
+ "ark-std 0.4.0",
+ "derivative",
+ "digest 0.10.7",
+ "itertools 0.10.5",
+ "num-bigint",
+ "num-traits",
+ "paste",
+ "rustc_version 0.4.1",
+ "zeroize",
+]
+
+[[package]]
+name = "ark-ff"
+version = "0.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a177aba0ed1e0fbb62aa9f6d0502e9b46dad8c2eab04c14258a1212d2557ea70"
+dependencies = [
+ "ark-ff-asm 0.5.0",
+ "ark-ff-macros 0.5.0",
+ "ark-serialize 0.5.0",
+ "ark-std 0.5.0",
+ "arrayvec 0.7.8",
+ "digest 0.10.7",
+ "educe",
+ "itertools 0.13.0",
+ "num-bigint",
+ "num-traits",
+ "paste",
+ "zeroize",
+]
+
+[[package]]
+name = "ark-ff"
+version = "0.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f7a806ac6c8307b929df4645776290a50ee2aac754ad09d8bdf73391309e43af"
+dependencies = [
+ "ark-ff-asm 0.6.0",
+ "ark-ff-macros 0.6.0",
+ "ark-serialize 0.6.0",
+ "ark-std 0.6.0",
+ "digest 0.10.7",
+ "educe",
+ "num-bigint",
+ "num-traits",
+ "zeroize",
+]
+
+[[package]]
+name = "ark-ff-asm"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "db02d390bf6643fb404d3d22d31aee1c4bc4459600aef9113833d17e786c6e44"
+dependencies = [
+ "quote",
+ "syn 1.0.109",
+]
+
+[[package]]
+name = "ark-ff-asm"
+version = "0.4.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3ed4aa4fe255d0bc6d79373f7e31d2ea147bcf486cba1be5ba7ea85abdb92348"
+dependencies = [
+ "quote",
+ "syn 1.0.109",
+]
+
+[[package]]
+name = "ark-ff-asm"
+version = "0.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "62945a2f7e6de02a31fe400aa489f0e0f5b2502e69f95f853adb82a96c7a6b60"
+dependencies = [
+ "quote",
+ "syn 2.0.118",
+]
+
+[[package]]
+name = "ark-ff-asm"
+version = "0.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1479009684adc073dff49a1025d3a7065b317a9ead25aaaca38cdc70058ba8a2"
+dependencies = [
+ "quote",
+ "syn 2.0.118",
+]
+
+[[package]]
+name = "ark-ff-macros"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "db2fd794a08ccb318058009eefdf15bcaaaaf6f8161eb3345f907222bac38b20"
+dependencies = [
+ "num-bigint",
+ "num-traits",
+ "quote",
+ "syn 1.0.109",
+]
+
+[[package]]
+name = "ark-ff-macros"
+version = "0.4.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7abe79b0e4288889c4574159ab790824d0033b9fdcb2a112a3182fac2e514565"
+dependencies = [
+ "num-bigint",
+ "num-traits",
+ "proc-macro2",
+ "quote",
+ "syn 1.0.109",
+]
+
+[[package]]
+name = "ark-ff-macros"
+version = "0.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "09be120733ee33f7693ceaa202ca41accd5653b779563608f1234f78ae07c4b3"
+dependencies = [
+ "num-bigint",
+ "num-traits",
+ "proc-macro2",
+ "quote",
+ "syn 2.0.118",
+]
+
+[[package]]
+name = "ark-ff-macros"
+version = "0.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4a0691ed21ef00ef89c1e9bda832eba493dda3ec2f8d892fb25b705f73f06bb8"
+dependencies = [
+ "num-bigint",
+ "num-traits",
+ "proc-macro2",
+ "quote",
+ "syn 2.0.118",
+]
+
+[[package]]
+name = "ark-serialize"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1d6c2b318ee6e10f8c2853e73a83adc0ccb88995aa978d8a3408d492ab2ee671"
+dependencies = [
+ "ark-std 0.3.0",
+ "digest 0.9.0",
+]
+
+[[package]]
+name = "ark-serialize"
+version = "0.4.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "adb7b85a02b83d2f22f89bd5cac66c9c89474240cb6207cb1efc16d098e822a5"
+dependencies = [
+ "ark-std 0.4.0",
+ "digest 0.10.7",
+ "num-bigint",
+]
+
+[[package]]
+name = "ark-serialize"
+version = "0.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3f4d068aaf107ebcd7dfb52bc748f8030e0fc930ac8e360146ca54c1203088f7"
+dependencies = [
+ "ark-std 0.5.0",
+ "arrayvec 0.7.8",
+ "digest 0.10.7",
+ "num-bigint",
+]
+
+[[package]]
+name = "ark-serialize"
+version = "0.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a74dd304fd536fb95d0a328e72be759209cc496a9da094c5bc56e5fea4f9e86b"
+dependencies = [
+ "ark-serialize-derive",
+ "ark-std 0.6.0",
+ "digest 0.10.7",
+ "num-bigint",
+ "serde_with",
+]
+
+[[package]]
+name = "ark-serialize-derive"
+version = "0.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4f153690697a2b91e5e1251ff98411ee5371500a111a0fd317a70e588eb300f9"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.118",
+]
+
+[[package]]
+name = "ark-std"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1df2c09229cbc5a028b1d70e00fdb2acee28b1055dfb5ca73eea49c5a25c4e7c"
+dependencies = [
+ "num-traits",
+ "rand 0.8.6",
+]
+
+[[package]]
+name = "ark-std"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "94893f1e0c6eeab764ade8dc4c0db24caf4fe7cbbaafc0eba0a9030f447b5185"
+dependencies = [
+ "num-traits",
+ "rand 0.8.6",
+]
+
+[[package]]
+name = "ark-std"
+version = "0.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "246a225cc6131e9ee4f24619af0f19d67761fff15d7ccc22e42b80846e69449a"
+dependencies = [
+ "num-traits",
+ "rand 0.8.6",
+]
+
+[[package]]
+name = "ark-std"
+version = "0.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "367c9c827ed431bff6868b7aa926e05b16eb46603cc8b6e768e4a5553fa1d155"
+dependencies = [
+ "num-traits",
+ "rand 0.8.6",
+]
+
+[[package]]
+name = "arrayvec"
+version = "0.5.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b"
+
+[[package]]
+name = "arrayvec"
+version = "0.7.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d3fb67a6e08acf24fdeccbac2cb6ac4305825bd1f117462e0e6f2f193345ad56"
+
+[[package]]
+name = "async-stream"
+version = "0.3.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0b5a71a6f37880a80d1d7f19efd781e4b5de42c88f0722cc13bcb6cc2cfe8476"
+dependencies = [
+ "async-stream-impl",
+ "futures-core",
+ "pin-project-lite",
+]
+
+[[package]]
+name = "async-stream-impl"
+version = "0.3.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c7c24de15d275a1ecfd47a380fb4d5ec9bfe0933f309ed5e705b775596a3574d"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.118",
+]
+
+[[package]]
+name = "async-trait"
+version = "0.1.89"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9035ad2d096bed7955a320ee7e2230574d28fd3c3a0f186cbea1ff3c7eed5dbb"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.118",
+]
+
+[[package]]
+name = "async_io_stream"
+version = "0.3.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b6d7b9decdf35d8908a7e3ef02f64c5e9b1695e230154c0e8de3969142d9b94c"
+dependencies = [
+ "futures",
+ "pharos",
+ "rustc_version 0.4.1",
+]
+
+[[package]]
+name = "atomic-waker"
+version = "1.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0"
+
+[[package]]
+name = "auto_impl"
+version = "1.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ffdcb70bdbc4d478427380519163274ac86e52916e10f0a8889adf0f96d3fee7"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.118",
+]
+
+[[package]]
+name = "autocfg"
+version = "1.5.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f2032f911046de80f0a198e0901378627c33f59ea0ac00e363d481118bd70a53"
+
+[[package]]
+name = "aws-lc-rs"
+version = "1.17.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4342d8937fc7e5dd9b1c60292261c0670c882a2cd1719cfc11b1af41731e32ad"
+dependencies = [
+ "aws-lc-sys",
+ "zeroize",
+]
+
+[[package]]
+name = "aws-lc-sys"
+version = "0.42.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6d9ceb1da931507a12f4fccea479dccd00da1943e1b4ae72d8e502d707361444"
+dependencies = [
+ "cc",
+ "cmake",
+ "dunce",
+ "fs_extra",
+ "pkg-config",
+]
+
+[[package]]
+name = "base16ct"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf"
+
+[[package]]
+name = "base64"
+version = "0.22.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6"
+
+[[package]]
+name = "base64ct"
+version = "1.8.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2af50177e190e07a26ab74f8b1efbfe2ef87da2116221318cb1c2e82baf7de06"
+
+[[package]]
+name = "bimap"
+version = "0.6.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "230c5f1ca6a325a32553f8640d31ac9b49f2411e901e427570154868b46da4f7"
+
+[[package]]
+name = "binread"
+version = "2.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "16598dfc8e6578e9b597d9910ba2e73618385dc9f4b1d43dd92c349d6be6418f"
+dependencies = [
+ "binread_derive",
+ "lazy_static",
+ "rustversion",
+]
+
+[[package]]
+name = "binread_derive"
+version = "2.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1d9672209df1714ee804b1f4d4f68c8eb2a90b1f7a07acf472f88ce198ef1fed"
+dependencies = [
+ "either",
+ "proc-macro2",
+ "quote",
+ "syn 1.0.109",
+]
+
+[[package]]
+name = "bit-set"
+version = "0.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "08807e080ed7f9d5433fa9b275196cfc35414f66a0c79d864dc51a0d825231a3"
+dependencies = [
+ "bit-vec",
+]
+
+[[package]]
+name = "bit-vec"
+version = "0.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5e764a1d40d510daf35e07be9eb06e75770908c27d411ee6c92109c9840eaaf7"
+
+[[package]]
+name = "bitcoin-consensus-encoding"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b2d6094e2a1ba3c93b5a596fe5a10d1a10c3c6e06785cde89f693a044c01aa40"
+dependencies = [
+ "bitcoin-internals",
+]
+
+[[package]]
+name = "bitcoin-internals"
+version = "0.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a30a22d1f112dde8e16be7b45c63645dc165cef254f835b3e1e9553e485cfa64"
+dependencies = [
+ "hex-conservative 0.3.2",
+]
+
+[[package]]
+name = "bitcoin-io"
+version = "0.1.101"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bb5de036369d1ac59d3c1819ebc4d850f89466f5401c571a285b6ed564a4cb78"
+dependencies = [
+ "bitcoin-consensus-encoding",
+]
+
+[[package]]
+name = "bitcoin_hashes"
+version = "0.14.101"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bca4c7abb40c8817d77403c880988cfd484f23ab2365726afb2f798363e2c4a2"
+dependencies = [
+ "bitcoin-io",
+ "hex-conservative 0.2.2",
+]
+
+[[package]]
+name = "bitflags"
+version = "2.13.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b4388bee8683e3d04af747c73422af53102d2bd24d9eadb6cbc100baef4b43f8"
+
+[[package]]
+name = "bitvec"
+version = "1.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ddcec3d12c579d40898fe0a9a358a803c23e9c52ca3c425707f81c9436211837"
+dependencies = [
+ "funty",
+ "radium",
+ "tap",
+ "wyz",
+]
+
+[[package]]
+name = "block-buffer"
+version = "0.10.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71"
+dependencies = [
+ "generic-array",
+]
+
+[[package]]
+name = "block-buffer"
+version = "0.12.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d2f6c7dbe95a6ed67ad9f18e57daf93a2f034c524b99fd2b76d18fdfeb6660aa"
+dependencies = [
+ "hybrid-array",
+]
+
+[[package]]
+name = "blst"
+version = "0.3.16"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dcdb4c7013139a150f9fc55d123186dbfaba0d912817466282c73ac49e71fb45"
+dependencies = [
+ "cc",
+ "glob",
+ "threadpool",
+ "zeroize",
+]
+
+[[package]]
+name = "borsh"
+version = "1.7.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2f3f6da4992df95bbcd9af42a6c7dcb994498fc9048230405f3b36ff7cd3f145"
+dependencies = [
+ "borsh-derive",
+ "bytes",
+ "cfg_aliases",
+]
+
+[[package]]
+name = "borsh-derive"
+version = "1.7.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3ae8fb4fb5740e4b2c4884ff95f5f32f5e8479db1e8fd8eb49ddbe09eb09bb7c"
+dependencies = [
+ "once_cell",
+ "proc-macro-crate",
+ "proc-macro2",
+ "quote",
+ "syn 2.0.118",
+]
+
+[[package]]
+name = "bs58"
+version = "0.5.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bf88ba1141d185c399bee5288d850d63b8369520c1eafc32a0430b5b6c287bf4"
+dependencies = [
+ "tinyvec",
+]
+
+[[package]]
+name = "bumpalo"
+version = "3.20.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "72f5acc6cb2ba439de613abc23857ec3d78374d8ed5ac84e9d11336e87da8649"
+
+[[package]]
+name = "byte-slice-cast"
+version = "1.2.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7575182f7272186991736b70173b0ea045398f984bf5ebbb3804736ce1330c9d"
+
+[[package]]
+name = "byteorder"
+version = "1.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
+
+[[package]]
+name = "bytes"
+version = "1.12.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8ae3f5d315924270530207e2a68396c3cc547f6dca3fbdca317cfb1a51edb593"
+dependencies = [
+ "serde",
+]
+
+[[package]]
+name = "c-kzg"
+version = "2.1.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6648ed1e4ea8e8a1a4a2c78e1cda29a3fd500bc622899c340d8525ea9a76b24a"
+dependencies = [
+ "blst",
+ "cc",
+ "glob",
+ "hex",
+ "libc",
+ "once_cell",
+ "serde",
+]
+
+[[package]]
+name = "candid"
+version = "0.10.31"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1347fd6b24f5ad23e4ab16d49551a03d396410dcb086e8f969c21efdf4b1dbd8"
+dependencies = [
+ "anyhow",
+ "binread",
+ "byteorder",
+ "candid_derive",
+ "hex",
+ "ic_principal",
+ "leb128",
+ "num-bigint",
+ "num-traits",
+ "paste",
+ "pretty",
+ "serde",
+ "serde_bytes",
+ "stacker",
+ "thiserror 1.0.69",
+]
+
+[[package]]
+name = "candid_derive"
+version = "0.10.31"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ad381629d2d2940899c3a784ccd4fe59e255b5714e7520f016f839f07d2236e7"
+dependencies = [
+ "lazy_static",
+ "proc-macro2",
+ "quote",
+ "syn 2.0.118",
+]
+
+[[package]]
+name = "cc"
+version = "1.2.65"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e228eec9be7c17ccb640b59b36a5cd805ea2a564a4c5e162c2f659fea30d3b96"
+dependencies = [
+ "find-msvc-tools",
+ "jobserver",
+ "libc",
+ "shlex",
+]
+
+[[package]]
+name = "cfg-if"
+version = "1.0.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801"
+
+[[package]]
+name = "cfg_aliases"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724"
+
+[[package]]
+name = "chrono"
+version = "0.4.45"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1aa79e62e7697b8e29b513a68abacf485adcd1fe8284a4316c5ae868e6633327"
+dependencies = [
+ "iana-time-zone",
+ "num-traits",
+ "serde",
+ "windows-link",
+]
+
+[[package]]
+name = "cmake"
+version = "0.1.58"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c0f78a02292a74a88ac736019ab962ece0bc380e3f977bf72e376c5d78ff0678"
+dependencies = [
+ "cc",
+]
+
+[[package]]
+name = "combine"
+version = "4.6.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ba5a308b75df32fe02788e748662718f03fde005016435c444eea572398219fd"
+dependencies = [
+ "bytes",
+ "memchr",
+]
+
+[[package]]
+name = "const-hex"
+version = "1.19.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "33e2a781ebdf4467d1428dc4593067825fb646f6871475098d8577421af73558"
+dependencies = [
+ "cfg-if",
+ "cpufeatures 0.2.17",
+ "proptest",
+ "serde_core",
+]
+
+[[package]]
+name = "const-oid"
+version = "0.9.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8"
+
+[[package]]
+name = "const_format"
+version = "0.2.36"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4481a617ad9a412be3b97c5d403fef8ed023103368908b9c50af598ff467cc1e"
+dependencies = [
+ "const_format_proc_macros",
+ "konst",
+]
+
+[[package]]
+name = "const_format_proc_macros"
+version = "0.2.34"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1d57c2eccfb16dbac1f4e61e206105db5820c9d26c3c472bc17c774259ef7744"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "unicode-xid",
+]
+
+[[package]]
+name = "convert_case"
+version = "0.10.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "633458d4ef8c78b72454de2d54fd6ab2e60f9e02be22f3c6104cdc8a4e0fceb9"
+dependencies = [
+ "unicode-segmentation",
+]
+
+[[package]]
+name = "core-foundation"
+version = "0.10.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b2a6cd9ae233e7f62ba4e9353e81a88df7fc8a5987b8d445b4d90c879bd156f6"
+dependencies = [
+ "core-foundation-sys",
+ "libc",
+]
+
+[[package]]
+name = "core-foundation-sys"
+version = "0.8.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b"
+
+[[package]]
+name = "cpufeatures"
+version = "0.2.17"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280"
+dependencies = [
+ "libc",
+]
+
+[[package]]
+name = "cpufeatures"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8b2a41393f66f16b0823bb79094d54ac5fbd34ab292ddafb9a0456ac9f87d201"
+dependencies = [
+ "libc",
+]
+
+[[package]]
+name = "crc"
+version = "3.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5eb8a2a1cd12ab0d987a5d5e825195d372001a4094a0376319d5a0ad71c1ba0d"
+dependencies = [
+ "crc-catalog",
+]
+
+[[package]]
+name = "crc-catalog"
+version = "2.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "217698eaf96b4a3f0bc4f3662aaa55bdf913cd54d7204591faa790070c6d0853"
+
+[[package]]
+name = "crc32fast"
+version = "1.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9481c1c90cbf2ac953f07c8d4a58aa3945c425b7185c9154d67a65e4230da511"
+dependencies = [
+ "cfg-if",
+]
+
+[[package]]
+name = "crossbeam-utils"
+version = "0.8.21"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28"
+
+[[package]]
+name = "crunchy"
+version = "0.2.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "460fbee9c2c2f33933d720630a6a0bac33ba7053db5344fac858d4b8952d77d5"
+
+[[package]]
+name = "crypto-bigint"
+version = "0.5.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0dc92fb57ca44df6db8059111ab3af99a63d5d0f8375d9972e319a379c6bab76"
+dependencies = [
+ "generic-array",
+ "rand_core 0.6.4",
+ "subtle",
+ "zeroize",
+]
+
+[[package]]
+name = "crypto-common"
+version = "0.1.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3"
+dependencies = [
+ "generic-array",
+ "typenum",
+]
+
+[[package]]
+name = "crypto-common"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ce6e4c961d6cd6c9a86db418387425e8bdeaf05b3c8bc1411e6dca4c252f1453"
+dependencies = [
+ "hybrid-array",
+]
+
+[[package]]
+name = "darling"
+version = "0.23.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "25ae13da2f202d56bd7f91c25fba009e7717a1e4a1cc98a76d844b65ae912e9d"
+dependencies = [
+ "darling_core",
+ "darling_macro",
+]
+
+[[package]]
+name = "darling_core"
+version = "0.23.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9865a50f7c335f53564bb694ef660825eb8610e0a53d3e11bf1b0d3df31e03b0"
+dependencies = [
+ "ident_case",
+ "proc-macro2",
+ "quote",
+ "serde",
+ "strsim",
+ "syn 2.0.118",
+]
+
+[[package]]
+name = "darling_macro"
+version = "0.23.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ac3984ec7bd6cfa798e62b4a642426a5be0e68f9401cfc2a01e3fa9ea2fcdb8d"
+dependencies = [
+ "darling_core",
+ "quote",
+ "syn 2.0.118",
+]
+
+[[package]]
+name = "dashmap"
+version = "6.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e6361d5c062261c78a176addb82d4c821ae42bed6089de0e12603cd25de2059c"
+dependencies = [
+ "cfg-if",
+ "crossbeam-utils",
+ "hashbrown 0.14.5",
+ "lock_api",
+ "once_cell",
+ "parking_lot_core",
+]
+
+[[package]]
+name = "data-encoding"
+version = "2.11.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a4ae5f15dda3c708c0ade84bfee31ccab44a3da4f88015ed22f63732abe300c8"
+
+[[package]]
+name = "deposit-from-cex-demo"
+version = "0.1.0"
+dependencies = [
+ "alloy",
+ "anyhow",
+ "candid",
+ "hex",
+ "tokio",
+]
+
+[[package]]
+name = "der"
+version = "0.7.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e7c1832837b905bbfb5101e07cc24c8deddf52f93225eee6ead5f4d63d53ddcb"
+dependencies = [
+ "const-oid",
+ "zeroize",
+]
+
+[[package]]
+name = "deranged"
+version = "0.5.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7cd812cc2bc1d69d4764bd80df88b4317eaef9e773c75226407d9bc0876b211c"
+dependencies = [
+ "serde_core",
+]
+
+[[package]]
+name = "derivative"
+version = "2.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 1.0.109",
+]
+
+[[package]]
+name = "derive_more"
+version = "2.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d751e9e49156b02b44f9c1815bcb94b984cdcc4396ecc32521c739452808b134"
+dependencies = [
+ "derive_more-impl",
+]
+
+[[package]]
+name = "derive_more-impl"
+version = "2.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "799a97264921d8623a957f6c3b9011f3b5492f557bbb7a5a19b7fa6d06ba8dcb"
+dependencies = [
+ "convert_case",
+ "proc-macro2",
+ "quote",
+ "rustc_version 0.4.1",
+ "syn 2.0.118",
+ "unicode-xid",
+]
+
+[[package]]
+name = "digest"
+version = "0.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066"
+dependencies = [
+ "generic-array",
+]
+
+[[package]]
+name = "digest"
+version = "0.10.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292"
+dependencies = [
+ "block-buffer 0.10.4",
+ "const-oid",
+ "crypto-common 0.1.6",
+ "subtle",
+]
+
+[[package]]
+name = "digest"
+version = "0.11.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f1dd6dbb5841937940781866fa1281a1ff7bd3bf827091440879f9994983d5c2"
+dependencies = [
+ "block-buffer 0.12.1",
+ "crypto-common 0.2.2",
+]
+
+[[package]]
+name = "displaydoc"
+version = "0.2.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1ac70aa55017e108007fbaf5aa0f54b021c98f92ff8af59d42eda9da96e3dd4f"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.118",
+]
+
+[[package]]
+name = "doctest-file"
+version = "1.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c2db04e74f0a9a93103b50e90b96024c9b2bdca8bce6a632ec71b88736d3d359"
+
+[[package]]
+name = "dunce"
+version = "1.0.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "92773504d58c093f6de2459af4af33faa518c13451eb8f2b5698ed3d36e7c813"
+
+[[package]]
+name = "dyn-clone"
+version = "1.0.20"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d0881ea181b1df73ff77ffaaf9c7544ecc11e82fba9b5f27b262a3c73a332555"
+
+[[package]]
+name = "ecdsa"
+version = "0.16.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ee27f32b5c5292967d2d4a9d7f1e0b0aed2c15daded5a60300e4abb9d8020bca"
+dependencies = [
+ "der",
+ "digest 0.10.7",
+ "elliptic-curve",
+ "rfc6979",
+ "serdect",
+ "signature",
+ "spki",
+]
+
+[[package]]
+name = "educe"
+version = "0.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1d7bc049e1bd8cdeb31b68bbd586a9464ecf9f3944af3958a7a9d0f8b9799417"
+dependencies = [
+ "enum-ordinalize",
+ "proc-macro2",
+ "quote",
+ "syn 2.0.118",
+]
+
+[[package]]
+name = "either"
+version = "1.16.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "91622ff5e7162018101f2fea40d6ebf4a78bbe5a49736a2020649edf9693679e"
+dependencies = [
+ "serde",
+]
+
+[[package]]
+name = "elliptic-curve"
+version = "0.13.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b5e6043086bf7973472e0c7dff2142ea0b680d30e18d9cc40f267efbf222bd47"
+dependencies = [
+ "base16ct",
+ "crypto-bigint",
+ "digest 0.10.7",
+ "ff",
+ "generic-array",
+ "group",
+ "pkcs8",
+ "rand_core 0.6.4",
+ "sec1",
+ "serdect",
+ "subtle",
+ "zeroize",
+]
+
+[[package]]
+name = "enum-ordinalize"
+version = "4.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "07f808d588c10e464ea6f7d3eaed500049eff30aaac103460f61828c2d65b3eb"
+dependencies = [
+ "enum-ordinalize-derive",
+]
+
+[[package]]
+name = "enum-ordinalize-derive"
+version = "4.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "42e528e2d34ba8a67a1a650b86beae8ef69fc5fdb638016f386b973226590432"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.118",
+]
+
+[[package]]
+name = "equivalent"
+version = "1.0.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f"
+
+[[package]]
+name = "errno"
+version = "0.3.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb"
+dependencies = [
+ "libc",
+ "windows-sys 0.61.2",
+]
+
+[[package]]
+name = "fastrand"
+version = "2.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9f1f227452a390804cdb637b74a86990f2a7d7ba4b7d5693aac9b4dd6defd8d6"
+
+[[package]]
+name = "fastrlp"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "139834ddba373bbdd213dffe02c8d110508dcf1726c2be27e8d1f7d7e1856418"
+dependencies = [
+ "arrayvec 0.7.8",
+ "auto_impl",
+ "bytes",
+]
+
+[[package]]
+name = "fastrlp"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ce8dba4714ef14b8274c371879b175aa55b16b30f269663f19d576f380018dc4"
+dependencies = [
+ "arrayvec 0.7.8",
+ "auto_impl",
+ "bytes",
+]
+
+[[package]]
+name = "ff"
+version = "0.13.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c0b50bfb653653f9ca9095b427bed08ab8d75a137839d9ad64eb11810d5b6393"
+dependencies = [
+ "rand_core 0.6.4",
+ "subtle",
+]
+
+[[package]]
+name = "find-msvc-tools"
+version = "0.1.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582"
+
+[[package]]
+name = "fixed-hash"
+version = "0.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "835c052cb0c08c1acf6ffd71c022172e18723949c8282f2b9f27efbc51e64534"
+dependencies = [
+ "byteorder",
+ "rand 0.8.6",
+ "rustc-hex",
+ "static_assertions",
+]
+
+[[package]]
+name = "fnv"
+version = "1.0.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
+
+[[package]]
+name = "foldhash"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "77ce24cb58228fbb8aa041425bb1050850ac19177686ea6e0f41a70416f56fdb"
+
+[[package]]
+name = "form_urlencoded"
+version = "1.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cb4cb245038516f5f85277875cdaa4f7d2c9a0fa0468de06ed190163b1581fcf"
+dependencies = [
+ "percent-encoding",
+]
+
+[[package]]
+name = "fs_extra"
+version = "1.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "42703706b716c37f96a77aea830392ad231f44c9e9a67872fa5548707e11b11c"
+
+[[package]]
+name = "funty"
+version = "2.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c"
+
+[[package]]
+name = "futures"
+version = "0.3.32"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8b147ee9d1f6d097cef9ce628cd2ee62288d963e16fb287bd9286455b241382d"
+dependencies = [
+ "futures-channel",
+ "futures-core",
+ "futures-executor",
+ "futures-io",
+ "futures-sink",
+ "futures-task",
+ "futures-util",
+]
+
+[[package]]
+name = "futures-channel"
+version = "0.3.32"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "07bbe89c50d7a535e539b8c17bc0b49bdb77747034daa8087407d655f3f7cc1d"
+dependencies = [
+ "futures-core",
+ "futures-sink",
+]
+
+[[package]]
+name = "futures-core"
+version = "0.3.32"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7e3450815272ef58cec6d564423f6e755e25379b217b0bc688e295ba24df6b1d"
+
+[[package]]
+name = "futures-executor"
+version = "0.3.32"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "baf29c38818342a3b26b5b923639e7b1f4a61fc5e76102d4b1981c6dc7a7579d"
+dependencies = [
+ "futures-core",
+ "futures-task",
+ "futures-util",
+]
+
+[[package]]
+name = "futures-io"
+version = "0.3.32"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cecba35d7ad927e23624b22ad55235f2239cfa44fd10428eecbeba6d6a717718"
+
+[[package]]
+name = "futures-macro"
+version = "0.3.32"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e835b70203e41293343137df5c0664546da5745f82ec9b84d40be8336958447b"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.118",
+]
+
+[[package]]
+name = "futures-sink"
+version = "0.3.32"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c39754e157331b013978ec91992bde1ac089843443c49cbc7f46150b0fad0893"
+
+[[package]]
+name = "futures-task"
+version = "0.3.32"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "037711b3d59c33004d3856fbdc83b99d4ff37a24768fa1be9ce3538a1cde4393"
+
+[[package]]
+name = "futures-util"
+version = "0.3.32"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "389ca41296e6190b48053de0321d02a77f32f8a5d2461dd38762c0593805c6d6"
+dependencies = [
+ "futures-channel",
+ "futures-core",
+ "futures-io",
+ "futures-macro",
+ "futures-sink",
+ "futures-task",
+ "memchr",
+ "pin-project-lite",
+ "slab",
+]
+
+[[package]]
+name = "futures-utils-wasm"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "42012b0f064e01aa58b545fe3727f90f7dd4020f4a3ea735b50344965f5a57e9"
+
+[[package]]
+name = "generic-array"
+version = "0.14.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4bb6743198531e02858aeaea5398fcc883e71851fcbcb5a2f773e2fb6cb1edf2"
+dependencies = [
+ "typenum",
+ "version_check",
+ "zeroize",
+]
+
+[[package]]
+name = "getrandom"
+version = "0.2.17"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ff2abc00be7fca6ebc474524697ae276ad847ad0a6b3faa4bcb027e9a4614ad0"
+dependencies = [
+ "cfg-if",
+ "js-sys",
+ "libc",
+ "wasi",
+ "wasm-bindgen",
+]
+
+[[package]]
+name = "getrandom"
+version = "0.3.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd"
+dependencies = [
+ "cfg-if",
+ "js-sys",
+ "libc",
+ "r-efi 5.3.0",
+ "wasip2",
+ "wasm-bindgen",
+]
+
+[[package]]
+name = "getrandom"
+version = "0.4.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "300e883d756b2e4ec94e02791f39b04b522276138852cfc41d9fb7e904106099"
+dependencies = [
+ "cfg-if",
+ "libc",
+ "r-efi 6.0.0",
+]
+
+[[package]]
+name = "glob"
+version = "0.3.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0cc23270f6e1808e30a928bdc84dea0b9b4136a8bc82338574f23baf47bbd280"
+
+[[package]]
+name = "group"
+version = "0.13.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63"
+dependencies = [
+ "ff",
+ "rand_core 0.6.4",
+ "subtle",
+]
+
+[[package]]
+name = "hashbrown"
+version = "0.12.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
+
+[[package]]
+name = "hashbrown"
+version = "0.14.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1"
+
+[[package]]
+name = "hashbrown"
+version = "0.16.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100"
+dependencies = [
+ "allocator-api2",
+ "equivalent",
+ "foldhash",
+]
+
+[[package]]
+name = "hashbrown"
+version = "0.17.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ed5909b6e89a2db4456e54cd5f673791d7eca6732202bbf2a9cc504fe2f9b84a"
+dependencies = [
+ "foldhash",
+ "serde",
+ "serde_core",
+]
+
+[[package]]
+name = "heck"
+version = "0.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
+
+[[package]]
+name = "hermit-abi"
+version = "0.5.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fc0fef456e4baa96da950455cd02c081ca953b141298e41db3fc7e36b1da849c"
+
+[[package]]
+name = "hex"
+version = "0.4.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70"
+
+[[package]]
+name = "hex-conservative"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fda06d18ac606267c40c04e41b9947729bf8b9efe74bd4e82b61a5f26a510b9f"
+dependencies = [
+ "arrayvec 0.7.8",
+]
+
+[[package]]
+name = "hex-conservative"
+version = "0.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "830e599c2904b08f0834ee6337d8fe8f0ed4a63b5d9e7a7f49c0ffa06d08d360"
+dependencies = [
+ "arrayvec 0.7.8",
+]
+
+[[package]]
+name = "hmac"
+version = "0.12.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e"
+dependencies = [
+ "digest 0.10.7",
+]
+
+[[package]]
+name = "http"
+version = "1.4.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6970f50e31d6fc17d3fa27329444bfa74e196cf62e95052a3f6fee181dba6425"
+dependencies = [
+ "bytes",
+ "itoa",
+]
+
+[[package]]
+name = "http-body"
+version = "1.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184"
+dependencies = [
+ "bytes",
+ "http",
+]
+
+[[package]]
+name = "http-body-util"
+version = "0.1.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b021d93e26becf5dc7e1b75b1bed1fd93124b374ceb73f43d4d4eafec896a64a"
+dependencies = [
+ "bytes",
+ "futures-core",
+ "http",
+ "http-body",
+ "pin-project-lite",
+]
+
+[[package]]
+name = "httparse"
+version = "1.10.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87"
+
+[[package]]
+name = "hybrid-array"
+version = "0.4.13"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "818356c5132c1fede50f837ca96afbe78ff42413047f4abb886217845e1b6c8c"
+dependencies = [
+ "typenum",
+]
+
+[[package]]
+name = "hyper"
+version = "1.10.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "55281c53a1894c864990125767da440a4e630446785086f52523b20033b74498"
+dependencies = [
+ "atomic-waker",
+ "bytes",
+ "futures-channel",
+ "futures-core",
+ "http",
+ "http-body",
+ "httparse",
+ "itoa",
+ "pin-project-lite",
+ "smallvec",
+ "tokio",
+ "want",
+]
+
+[[package]]
+name = "hyper-rustls"
+version = "0.27.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "33ca68d021ef39cf6463ab54c1d0f5daf03377b70561305bb89a8f83aab66e0f"
+dependencies = [
+ "http",
+ "hyper",
+ "hyper-util",
+ "rustls",
+ "tokio",
+ "tokio-rustls",
+ "tower-service",
+]
+
+[[package]]
+name = "hyper-util"
+version = "0.1.20"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "96547c2556ec9d12fb1578c4eaf448b04993e7fb79cbaad930a656880a6bdfa0"
+dependencies = [
+ "base64",
+ "bytes",
+ "futures-channel",
+ "futures-util",
+ "http",
+ "http-body",
+ "hyper",
+ "ipnet",
+ "libc",
+ "percent-encoding",
+ "pin-project-lite",
+ "socket2",
+ "tokio",
+ "tower-service",
+ "tracing",
+]
+
+[[package]]
+name = "iana-time-zone"
+version = "0.1.65"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e31bc9ad994ba00e440a8aa5c9ef0ec67d5cb5e5cb0cc7f8b744a35b389cc470"
+dependencies = [
+ "android_system_properties",
+ "core-foundation-sys",
+ "iana-time-zone-haiku",
+ "js-sys",
+ "log",
+ "wasm-bindgen",
+ "windows-core",
+]
+
+[[package]]
+name = "iana-time-zone-haiku"
+version = "0.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f"
+dependencies = [
+ "cc",
+]
+
+[[package]]
+name = "ic_principal"
+version = "0.1.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8747dcb4d382080cc7c40ae9d80b33e35792ee06cb816b5c133dd6086d2f8730"
+dependencies = [
+ "crc32fast",
+ "data-encoding",
+ "serde",
+ "sha2",
+ "thiserror 1.0.69",
+]
+
+[[package]]
+name = "icu_collections"
+version = "2.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2984d1cd16c883d7935b9e07e44071dca8d917fd52ecc02c04d5fa0b5a3f191c"
+dependencies = [
+ "displaydoc",
+ "potential_utf",
+ "utf8_iter",
+ "yoke",
+ "zerofrom",
+ "zerovec",
+]
+
+[[package]]
+name = "icu_locale_core"
+version = "2.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "92219b62b3e2b4d88ac5119f8904c10f8f61bf7e95b640d25ba3075e6cac2c29"
+dependencies = [
+ "displaydoc",
+ "litemap",
+ "tinystr",
+ "writeable",
+ "zerovec",
+]
+
+[[package]]
+name = "icu_normalizer"
+version = "2.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c56e5ee99d6e3d33bd91c5d85458b6005a22140021cc324cea84dd0e72cff3b4"
+dependencies = [
+ "icu_collections",
+ "icu_normalizer_data",
+ "icu_properties",
+ "icu_provider",
+ "smallvec",
+ "zerovec",
+]
+
+[[package]]
+name = "icu_normalizer_data"
+version = "2.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "da3be0ae77ea334f4da67c12f149704f19f81d1adf7c51cf482943e84a2bad38"
+
+[[package]]
+name = "icu_properties"
+version = "2.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bee3b67d0ea5c2cca5003417989af8996f8604e34fb9ddf96208a033901e70de"
+dependencies = [
+ "icu_collections",
+ "icu_locale_core",
+ "icu_properties_data",
+ "icu_provider",
+ "zerotrie",
+ "zerovec",
+]
+
+[[package]]
+name = "icu_properties_data"
+version = "2.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8e2bbb201e0c04f7b4b3e14382af113e17ba4f63e2c9d2ee626b720cbce54a14"
+
+[[package]]
+name = "icu_provider"
+version = "2.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "139c4cf31c8b5f33d7e199446eff9c1e02decfc2f0eec2c8d71f65befa45b421"
+dependencies = [
+ "displaydoc",
+ "icu_locale_core",
+ "writeable",
+ "yoke",
+ "zerofrom",
+ "zerotrie",
+ "zerovec",
+]
+
+[[package]]
+name = "ident_case"
+version = "1.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39"
+
+[[package]]
+name = "idna"
+version = "1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3b0875f23caa03898994f6ddc501886a45c7d3d62d04d2d90788d47be1b1e4de"
+dependencies = [
+ "idna_adapter",
+ "smallvec",
+ "utf8_iter",
+]
+
+[[package]]
+name = "idna_adapter"
+version = "1.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cb68373c0d6620ef8105e855e7745e18b0d00d3bdb07fb532e434244cdb9a714"
+dependencies = [
+ "icu_normalizer",
+ "icu_properties",
+]
+
+[[package]]
+name = "impl-codec"
+version = "0.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ba6a270039626615617f3f36d15fc827041df3b78c439da2cadfa47455a77f2f"
+dependencies = [
+ "parity-scale-codec",
+]
+
+[[package]]
+name = "impl-trait-for-tuples"
+version = "0.2.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a0eb5a3343abf848c0984fe4604b2b105da9539376e24fc0a3b0007411ae4fd9"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.118",
+]
+
+[[package]]
+name = "indexmap"
+version = "1.9.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99"
+dependencies = [
+ "autocfg",
+ "hashbrown 0.12.3",
+ "serde",
+]
+
+[[package]]
+name = "indexmap"
+version = "2.14.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d466e9454f08e4a911e14806c24e16fba1b4c121d1ea474396f396069cf949d9"
+dependencies = [
+ "equivalent",
+ "hashbrown 0.17.1",
+ "serde",
+ "serde_core",
+]
+
+[[package]]
+name = "interprocess"
+version = "2.4.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "069323743400cb7ab06a8fe5c1ed911d36b6919ec531661d034c89083629595b"
+dependencies = [
+ "doctest-file",
+ "futures-core",
+ "libc",
+ "recvmsg",
+ "tokio",
+ "widestring",
+ "windows-sys 0.61.2",
+]
+
+[[package]]
+name = "ipnet"
+version = "2.12.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d98f6fed1fde3f8c21bc40a1abb88dd75e67924f9cffc3ef95607bad8017f8e2"
+
+[[package]]
+name = "itertools"
+version = "0.10.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473"
+dependencies = [
+ "either",
+]
+
+[[package]]
+name = "itertools"
+version = "0.13.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186"
+dependencies = [
+ "either",
+]
+
+[[package]]
+name = "itertools"
+version = "0.14.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2b192c782037fadd9cfa75548310488aabdbf3d2da73885b31bd0abd03351285"
+dependencies = [
+ "either",
+]
+
+[[package]]
+name = "itoa"
+version = "1.0.18"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682"
+
+[[package]]
+name = "jni"
+version = "0.22.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5efd9a482cf3a427f00d6b35f14332adc7902ce91efb778580e180ff90fa3498"
+dependencies = [
+ "cfg-if",
+ "combine",
+ "jni-macros",
+ "jni-sys",
+ "log",
+ "simd_cesu8",
+ "thiserror 2.0.18",
+ "walkdir",
+ "windows-link",
+]
+
+[[package]]
+name = "jni-macros"
+version = "0.22.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a00109accc170f0bdb141fed3e393c565b6f5e072365c3bd58f5b062591560a3"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "rustc_version 0.4.1",
+ "simd_cesu8",
+ "syn 2.0.118",
+]
+
+[[package]]
+name = "jni-sys"
+version = "0.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c6377a88cb3910bee9b0fa88d4f42e1d2da8e79915598f65fb0c7ee14c878af2"
+dependencies = [
+ "jni-sys-macros",
+]
+
+[[package]]
+name = "jni-sys-macros"
+version = "0.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "38c0b942f458fe50cdac086d2f946512305e5631e720728f2a61aabcd47a6264"
+dependencies = [
+ "quote",
+ "syn 2.0.118",
+]
+
+[[package]]
+name = "jobserver"
+version = "0.1.34"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9afb3de4395d6b3e67a780b6de64b51c978ecf11cb9a462c66be7d4ca9039d33"
+dependencies = [
+ "getrandom 0.3.4",
+ "libc",
+]
+
+[[package]]
+name = "js-sys"
+version = "0.3.103"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "53b44bfcdb3f8d5837a46dae1ca9660a837176eee74a28b229bc626816589102"
+dependencies = [
+ "cfg-if",
+ "futures-util",
+ "wasm-bindgen",
+]
+
+[[package]]
+name = "k256"
+version = "0.13.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f6e3919bbaa2945715f0bb6d3934a173d1e9a59ac23767fbaaef277265a7411b"
+dependencies = [
+ "cfg-if",
+ "ecdsa",
+ "elliptic-curve",
+ "once_cell",
+ "serdect",
+ "sha2",
+]
+
+[[package]]
+name = "keccak"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9e24a010dd405bd7ed803e5253182815b41bf2e6a80cc3bfc066658e03a198aa"
+dependencies = [
+ "cfg-if",
+ "cpufeatures 0.3.0",
+]
+
+[[package]]
+name = "keccak-asm"
+version = "0.1.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dd5dc2c0d691cbf7595cde551ced329cca99c2387c2cbc97754c5d0cd045d3ee"
+dependencies = [
+ "digest 0.10.7",
+ "sha3-asm",
+]
+
+[[package]]
+name = "konst"
+version = "0.2.20"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "128133ed7824fcd73d6e7b17957c5eb7bacb885649bd8c69708b2331a10bcefb"
+dependencies = [
+ "konst_macro_rules",
+]
+
+[[package]]
+name = "konst_macro_rules"
+version = "0.2.19"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a4933f3f57a8e9d9da04db23fb153356ecaf00cbd14aee46279c33dc80925c37"
+
+[[package]]
+name = "lazy_static"
+version = "1.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
+
+[[package]]
+name = "leb128"
+version = "0.2.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c83bff1d572d6b9aeef67ddfc8448e4a3737909cb28e81f97c791b9018703e52"
+
+[[package]]
+name = "libc"
+version = "0.2.186"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "68ab91017fe16c622486840e4c83c9a37afeff978bd239b5293d61ece587de66"
+
+[[package]]
+name = "libm"
+version = "0.2.16"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b6d2cec3eae94f9f509c767b45932f1ada8350c4bdb85af2fcab4a3c14807981"
+
+[[package]]
+name = "linux-raw-sys"
+version = "0.12.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "32a66949e030da00e8c7d4434b251670a91556f4144941d37452769c25d58a53"
+
+[[package]]
+name = "litemap"
+version = "0.8.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "92daf443525c4cce67b150400bc2316076100ce0b3686209eb8cf3c31612e6f0"
+
+[[package]]
+name = "lock_api"
+version = "0.4.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965"
+dependencies = [
+ "scopeguard",
+]
+
+[[package]]
+name = "log"
+version = "0.4.33"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0ceec5bc11778974d1bcb055b18002eba7f4b3518b6a0081b3af5f21666da9ad"
+
+[[package]]
+name = "lru"
+version = "0.16.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7f66e8d5d03f609abc3a39e6f08e4164ebf1447a732906d39eb9b99b7919ef39"
+dependencies = [
+ "hashbrown 0.16.1",
+]
+
+[[package]]
+name = "lru-slab"
+version = "0.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "112b39cec0b298b6c1999fee3e31427f74f676e4cb9879ed1a121b43661a4154"
+
+[[package]]
+name = "macro-string"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "59a9dbbfc75d2688ed057456ce8a3ee3f48d12eec09229f560f3643b9f275653"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.118",
+]
+
+[[package]]
+name = "memchr"
+version = "2.8.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "88904434abc2901f197fe8cc55f0445e7ded921dba5911dad2e2b39b48e663c4"
+
+[[package]]
+name = "mio"
+version = "1.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "02bd0af71c67b473010cbbc60715ee815645a4dc942899111f494b4b737d6fda"
+dependencies = [
+ "libc",
+ "wasi",
+ "windows-sys 0.61.2",
+]
+
+[[package]]
+name = "num-bigint"
+version = "0.4.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c863e9ab5e7bf9c99ba75e1050f1e4d624ae87ed3532d6238ffbdc7b585dbbe6"
+dependencies = [
+ "num-integer",
+ "num-traits",
+ "serde",
+]
+
+[[package]]
+name = "num-conv"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "521739c6d2bac4aa25192232afe6841231376b2b26d4d9fae5ecf8ca5772e441"
+
+[[package]]
+name = "num-integer"
+version = "0.1.46"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f"
+dependencies = [
+ "num-traits",
+]
+
+[[package]]
+name = "num-traits"
+version = "0.2.19"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841"
+dependencies = [
+ "autocfg",
+ "libm",
+]
+
+[[package]]
+name = "num_cpus"
+version = "1.17.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "91df4bbde75afed763b708b7eee1e8e7651e02d97f6d5dd763e89367e957b23b"
+dependencies = [
+ "hermit-abi",
+ "libc",
+]
+
+[[package]]
+name = "num_enum"
+version = "0.7.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5d0bca838442ec211fa11de3a8b0e0e8f3a4522575b5c4c06ed722e005036f26"
+dependencies = [
+ "num_enum_derive",
+ "rustversion",
+]
+
+[[package]]
+name = "num_enum_derive"
+version = "0.7.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "680998035259dcfcafe653688bf2aa6d3e2dc05e98be6ab46afb089dc84f1df8"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.118",
+]
+
+[[package]]
+name = "nybbles"
+version = "0.4.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0d49ff0c0d00d4a502b39df9af3a525e1efeb14b9dabb5bb83335284c1309210"
+dependencies = [
+ "alloy-rlp",
+ "cfg-if",
+ "proptest",
+ "ruint",
+ "serde",
+ "smallvec",
+]
+
+[[package]]
+name = "object"
+version = "0.37.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ff76201f031d8863c38aa7f905eca4f53abbfa15f609db4277d44cd8938f33fe"
+dependencies = [
+ "memchr",
+]
+
+[[package]]
+name = "once_cell"
+version = "1.21.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50"
+
+[[package]]
+name = "openssl-probe"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7c87def4c32ab89d880effc9e097653c8da5d6ef28e6b539d313baaacfbafcbe"
+
+[[package]]
+name = "parity-scale-codec"
+version = "3.7.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "799781ae679d79a948e13d4824a40970bfa500058d245760dd857301059810fa"
+dependencies = [
+ "arrayvec 0.7.8",
+ "bitvec",
+ "byte-slice-cast",
+ "const_format",
+ "impl-trait-for-tuples",
+ "parity-scale-codec-derive",
+ "rustversion",
+ "serde",
+]
+
+[[package]]
+name = "parity-scale-codec-derive"
+version = "3.7.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "34b4653168b563151153c9e4c08ebed57fb8262bebfa79711552fa983c623e7a"
+dependencies = [
+ "proc-macro-crate",
+ "proc-macro2",
+ "quote",
+ "syn 2.0.118",
+]
+
+[[package]]
+name = "parking_lot"
+version = "0.12.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "93857453250e3077bd71ff98b6a65ea6621a19bb0f559a85248955ac12c45a1a"
+dependencies = [
+ "lock_api",
+ "parking_lot_core",
+]
+
+[[package]]
+name = "parking_lot_core"
+version = "0.9.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1"
+dependencies = [
+ "cfg-if",
+ "libc",
+ "redox_syscall",
+ "smallvec",
+ "windows-link",
+]
+
+[[package]]
+name = "paste"
+version = "1.0.15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a"
+
+[[package]]
+name = "percent-encoding"
+version = "2.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220"
+
+[[package]]
+name = "pest"
+version = "2.8.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e0848c601009d37dfa3430c4666e147e49cdcf1b92ecd3e63657d8a5f19da662"
+dependencies = [
+ "memchr",
+ "ucd-trie",
+]
+
+[[package]]
+name = "pharos"
+version = "0.5.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e9567389417feee6ce15dd6527a8a1ecac205ef62c2932bcf3d9f6fc5b78b414"
+dependencies = [
+ "futures",
+ "rustc_version 0.4.1",
+]
+
+[[package]]
+name = "pin-project"
+version = "1.1.13"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2466b2336ed02bcdca6b294417127b90ec92038d1d5c4fbeac971a922e0e0924"
+dependencies = [
+ "pin-project-internal",
+]
+
+[[package]]
+name = "pin-project-internal"
+version = "1.1.13"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c96395f0a926bc13b1c17622aaddda1ecb55d49c8f1bf9777e4d877800a43f8b"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.118",
+]
+
+[[package]]
+name = "pin-project-lite"
+version = "0.2.17"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd"
+
+[[package]]
+name = "pin-utils"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
+
+[[package]]
+name = "pkcs8"
+version = "0.10.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7"
+dependencies = [
+ "der",
+ "spki",
+]
+
+[[package]]
+name = "pkg-config"
+version = "0.3.33"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "19f132c84eca552bf34cab8ec81f1c1dcc229b811638f9d283dceabe58c5569e"
+
+[[package]]
+name = "potential_utf"
+version = "0.1.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0103b1cef7ec0cf76490e969665504990193874ea05c85ff9bab8b911d0a0564"
+dependencies = [
+ "zerovec",
+]
+
+[[package]]
+name = "powerfmt"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391"
+
+[[package]]
+name = "ppv-lite86"
+version = "0.2.21"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9"
+dependencies = [
+ "zerocopy",
+]
+
+[[package]]
+name = "pretty"
+version = "0.12.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0d22152487193190344590e4f30e219cf3fe140d9e7a3fdb683d82aa2c5f4156"
+dependencies = [
+ "arrayvec 0.5.2",
+ "typed-arena",
+ "unicode-width",
+]
+
+[[package]]
+name = "primitive-types"
+version = "0.12.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0b34d9fd68ae0b74a41b21c03c2f62847aa0ffea044eee893b4c140b37e244e2"
+dependencies = [
+ "fixed-hash",
+ "impl-codec",
+ "uint",
+]
+
+[[package]]
+name = "proc-macro-crate"
+version = "3.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e67ba7e9b2b56446f1d419b1d807906278ffa1a658a8a5d8a39dcb1f5a78614f"
+dependencies = [
+ "toml_edit",
+]
+
+[[package]]
+name = "proc-macro-error-attr2"
+version = "2.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "96de42df36bb9bba5542fe9f1a054b8cc87e172759a1868aa05c1f3acc89dfc5"
+dependencies = [
+ "proc-macro2",
+ "quote",
+]
+
+[[package]]
+name = "proc-macro-error2"
+version = "2.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "11ec05c52be0a07b08061f7dd003e7d7092e0472bc731b4af7bb1ef876109802"
+dependencies = [
+ "proc-macro-error-attr2",
+ "proc-macro2",
+ "quote",
+ "syn 2.0.118",
+]
+
+[[package]]
+name = "proc-macro2"
+version = "1.0.106"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934"
+dependencies = [
+ "unicode-ident",
+]
+
+[[package]]
+name = "proptest"
+version = "1.11.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4b45fcc2344c680f5025fe57779faef368840d0bd1f42f216291f0dc4ace4744"
+dependencies = [
+ "bit-set",
+ "bit-vec",
+ "bitflags",
+ "num-traits",
+ "rand 0.9.4",
+ "rand_chacha 0.9.0",
+ "rand_xorshift",
+ "regex-syntax",
+ "rusty-fork",
+ "tempfile",
+ "unarray",
+]
+
+[[package]]
+name = "psm"
+version = "0.1.31"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "645dbe486e346d9b5de3ef16ede18c26e6c70ad97418f4874b8b1889d6e761ea"
+dependencies = [
+ "ar_archive_writer",
+ "cc",
+]
+
+[[package]]
+name = "quick-error"
+version = "1.2.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0"
+
+[[package]]
+name = "quinn"
+version = "0.11.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0c1a41e437b6bbd489372cd4971de128e85c855f56c57f283d20ff016cf7c0a8"
+dependencies = [
+ "bytes",
+ "cfg_aliases",
+ "pin-project-lite",
+ "quinn-proto",
+ "quinn-udp",
+ "rustc-hash",
+ "rustls",
+ "socket2",
+ "thiserror 2.0.18",
+ "tokio",
+ "tracing",
+ "web-time",
+]
+
+[[package]]
+name = "quinn-proto"
+version = "0.11.15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4fcb935c5bec503c2f0e306bdd3e58bb9029dcb14fa8d9ac76e3a5256ac0763e"
+dependencies = [
+ "aws-lc-rs",
+ "bytes",
+ "getrandom 0.3.4",
+ "lru-slab",
+ "rand 0.9.4",
+ "ring",
+ "rustc-hash",
+ "rustls",
+ "rustls-pki-types",
+ "slab",
+ "thiserror 2.0.18",
+ "tinyvec",
+ "tracing",
+ "web-time",
+]
+
+[[package]]
+name = "quinn-udp"
+version = "0.5.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "addec6a0dcad8a8d96a771f815f0eaf55f9d1805756410b39f5fa81332574cbd"
+dependencies = [
+ "cfg_aliases",
+ "libc",
+ "once_cell",
+ "socket2",
+ "tracing",
+ "windows-sys 0.60.2",
+]
+
+[[package]]
+name = "quote"
+version = "1.0.46"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dfbc457d0c7a0759a614551b11a6409e5951f6c7537be1f1b7682b9ae9230368"
+dependencies = [
+ "proc-macro2",
+]
+
+[[package]]
+name = "r-efi"
+version = "5.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f"
+
+[[package]]
+name = "r-efi"
+version = "6.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf"
+
+[[package]]
+name = "radium"
+version = "0.7.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09"
+
+[[package]]
+name = "rand"
+version = "0.8.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5ca0ecfa931c29007047d1bc58e623ab12e5590e8c7cc53200d5202b69266d8a"
+dependencies = [
+ "libc",
+ "rand_chacha 0.3.1",
+ "rand_core 0.6.4",
+ "serde",
+]
+
+[[package]]
+name = "rand"
+version = "0.9.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "44c5af06bb1b7d3216d91932aed5265164bf384dc89cd6ba05cf59a35f5f76ea"
+dependencies = [
+ "rand_chacha 0.9.0",
+ "rand_core 0.9.5",
+ "serde",
+]
+
+[[package]]
+name = "rand_chacha"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
+dependencies = [
+ "ppv-lite86",
+ "rand_core 0.6.4",
+]
+
+[[package]]
+name = "rand_chacha"
+version = "0.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb"
+dependencies = [
+ "ppv-lite86",
+ "rand_core 0.9.5",
+]
+
+[[package]]
+name = "rand_core"
+version = "0.6.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
+dependencies = [
+ "getrandom 0.2.17",
+]
+
+[[package]]
+name = "rand_core"
+version = "0.9.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "76afc826de14238e6e8c374ddcc1fa19e374fd8dd986b0d2af0d02377261d83c"
+dependencies = [
+ "getrandom 0.3.4",
+ "serde",
+]
+
+[[package]]
+name = "rand_xorshift"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "513962919efc330f829edb2535844d1b912b0fbe2ca165d613e4e8788bb05a5a"
+dependencies = [
+ "rand_core 0.9.5",
+]
+
+[[package]]
+name = "rapidhash"
+version = "4.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b1a224897b65b7ce38bf7b0adb569e7d77e11460d0cc3577908b263d8b5a89aa"
+dependencies = [
+ "rustversion",
+]
+
+[[package]]
+name = "recvmsg"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d3edd4d5d42c92f0a659926464d4cce56b562761267ecf0f469d85b7de384175"
+
+[[package]]
+name = "redox_syscall"
+version = "0.5.18"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d"
+dependencies = [
+ "bitflags",
+]
+
+[[package]]
+name = "ref-cast"
+version = "1.0.25"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f354300ae66f76f1c85c5f84693f0ce81d747e2c3f21a45fef496d89c960bf7d"
+dependencies = [
+ "ref-cast-impl",
+]
+
+[[package]]
+name = "ref-cast-impl"
+version = "1.0.25"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b7186006dcb21920990093f30e3dea63b7d6e977bf1256be20c3563a5db070da"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.118",
+]
+
+[[package]]
+name = "regex-syntax"
+version = "0.8.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d6f6ff9a378485b298a5286656da665ba74413d36db0979633275d2e708145d4"
+
+[[package]]
+name = "reqwest"
+version = "0.13.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "219c5811de6525e5416c7d5d53bb656d3afdbc6c5af816e0802bcfa42dbdc1c3"
+dependencies = [
+ "base64",
+ "bytes",
+ "futures-core",
+ "http",
+ "http-body",
+ "http-body-util",
+ "hyper",
+ "hyper-rustls",
+ "hyper-util",
+ "js-sys",
+ "log",
+ "percent-encoding",
+ "pin-project-lite",
+ "quinn",
+ "rustls",
+ "rustls-pki-types",
+ "rustls-platform-verifier",
+ "serde",
+ "serde_json",
+ "sync_wrapper",
+ "tokio",
+ "tokio-rustls",
+ "tower",
+ "tower-http",
+ "tower-service",
+ "url",
+ "wasm-bindgen",
+ "wasm-bindgen-futures",
+ "web-sys",
+]
+
+[[package]]
+name = "rfc6979"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f8dd2a808d456c4a54e300a23e9f5a67e122c3024119acbfd73e3bf664491cb2"
+dependencies = [
+ "hmac",
+ "subtle",
+]
+
+[[package]]
+name = "ring"
+version = "0.17.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7"
+dependencies = [
+ "cc",
+ "cfg-if",
+ "getrandom 0.2.17",
+ "libc",
+ "untrusted",
+ "windows-sys 0.52.0",
+]
+
+[[package]]
+name = "rlp"
+version = "0.5.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bb919243f34364b6bd2fc10ef797edbfa75f33c252e7998527479c6d6b47e1ec"
+dependencies = [
+ "bytes",
+ "rustc-hex",
+]
+
+[[package]]
+name = "ruint"
+version = "1.19.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "45caf26f647c19115bf9c453c70ffe4a4a3a6390dceebd942610584f99b8ddce"
+dependencies = [
+ "alloy-rlp",
+ "ark-ff 0.3.0",
+ "ark-ff 0.4.2",
+ "ark-ff 0.5.0",
+ "ark-ff 0.6.0",
+ "bytes",
+ "fastrlp 0.3.1",
+ "fastrlp 0.4.0",
+ "num-bigint",
+ "num-integer",
+ "num-traits",
+ "parity-scale-codec",
+ "primitive-types",
+ "proptest",
+ "rand 0.8.6",
+ "rand 0.9.4",
+ "rlp",
+ "ruint-macro",
+ "serde_core",
+ "valuable",
+ "zeroize",
+]
+
+[[package]]
+name = "ruint-macro"
+version = "1.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "48fd7bd8a6377e15ad9d42a8ec25371b94ddc67abe7c8b9127bec79bebaaae18"
+
+[[package]]
+name = "rustc-hash"
+version = "2.1.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6b1e7f9a428571be2dc5bc0505c13fb6bf936822b894ec87abf8a08a4e51742d"
+
+[[package]]
+name = "rustc-hex"
+version = "2.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3e75f6a532d0fd9f7f13144f392b6ad56a32696bfcd9c78f797f16bbb6f072d6"
+
+[[package]]
+name = "rustc_version"
+version = "0.3.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f0dfe2087c51c460008730de8b57e6a320782fbfb312e1f4d520e6c6fae155ee"
+dependencies = [
+ "semver 0.11.0",
+]
+
+[[package]]
+name = "rustc_version"
+version = "0.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92"
+dependencies = [
+ "semver 1.0.28",
+]
+
+[[package]]
+name = "rustix"
+version = "1.1.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b6fe4565b9518b83ef4f91bb47ce29620ca828bd32cb7e408f0062e9930ba190"
+dependencies = [
+ "bitflags",
+ "errno",
+ "libc",
+ "linux-raw-sys",
+ "windows-sys 0.61.2",
+]
+
+[[package]]
+name = "rustls"
+version = "0.23.41"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6b92b125634d9b795e7beca796cc790df15a7fb38323bf3196fda83292d06b1f"
+dependencies = [
+ "aws-lc-rs",
+ "once_cell",
+ "rustls-pki-types",
+ "rustls-webpki",
+ "subtle",
+ "zeroize",
+]
+
+[[package]]
+name = "rustls-native-certs"
+version = "0.8.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dab5152771c58876a2146916e53e35057e1a4dfa2b9df0f0305b07f611fdea4d"
+dependencies = [
+ "openssl-probe",
+ "rustls-pki-types",
+ "schannel",
+ "security-framework",
+]
+
+[[package]]
+name = "rustls-pki-types"
+version = "1.15.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "764899a24af3980067ee14bc143654f297b22eaebfe3c7b6b211920a5a59b046"
+dependencies = [
+ "web-time",
+ "zeroize",
+]
+
+[[package]]
+name = "rustls-platform-verifier"
+version = "0.7.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "26d1e2536ce4f35f4846aa13bff16bd0ff40157cdb14cc056c7b14ba41233ba0"
+dependencies = [
+ "core-foundation",
+ "core-foundation-sys",
+ "jni",
+ "log",
+ "once_cell",
+ "rustls",
+ "rustls-native-certs",
+ "rustls-platform-verifier-android",
+ "rustls-webpki",
+ "security-framework",
+ "security-framework-sys",
+ "webpki-root-certs",
+ "windows-sys 0.61.2",
+]
+
+[[package]]
+name = "rustls-platform-verifier-android"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f87165f0995f63a9fbeea62b64d10b4d9d8e78ec6d7d51fb2125fda7bb36788f"
+
+[[package]]
+name = "rustls-webpki"
+version = "0.103.13"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "61c429a8649f110dddef65e2a5ad240f747e85f7758a6bccc7e5777bd33f756e"
+dependencies = [
+ "aws-lc-rs",
+ "ring",
+ "rustls-pki-types",
+ "untrusted",
+]
+
+[[package]]
+name = "rustversion"
+version = "1.0.22"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d"
+
+[[package]]
+name = "rusty-fork"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cc6bf79ff24e648f6da1f8d1f011e9cac26491b619e6b9280f2b47f1774e6ee2"
+dependencies = [
+ "fnv",
+ "quick-error",
+ "tempfile",
+ "wait-timeout",
+]
+
+[[package]]
+name = "same-file"
+version = "1.0.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502"
+dependencies = [
+ "winapi-util",
+]
+
+[[package]]
+name = "schannel"
+version = "0.1.29"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "91c1b7e4904c873ef0710c1f407dde2e6287de2bebc1bbbf7d430bb7cbffd939"
+dependencies = [
+ "windows-sys 0.61.2",
+]
+
+[[package]]
+name = "schemars"
+version = "0.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4cd191f9397d57d581cddd31014772520aa448f65ef991055d7f61582c65165f"
+dependencies = [
+ "dyn-clone",
+ "ref-cast",
+ "serde",
+ "serde_json",
+]
+
+[[package]]
+name = "schemars"
+version = "1.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a2b42f36aa1cd011945615b92222f6bf73c599a102a300334cd7f8dbeec726cc"
+dependencies = [
+ "dyn-clone",
+ "ref-cast",
+ "serde",
+ "serde_json",
+]
+
+[[package]]
+name = "scopeguard"
+version = "1.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
+
+[[package]]
+name = "sec1"
+version = "0.7.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d3e97a565f76233a6003f9f5c54be1d9c5bdfa3eccfb189469f11ec4901c47dc"
+dependencies = [
+ "base16ct",
+ "der",
+ "generic-array",
+ "pkcs8",
+ "serdect",
+ "subtle",
+ "zeroize",
+]
+
+[[package]]
+name = "secp256k1"
+version = "0.30.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b50c5943d326858130af85e049f2661ba3c78b26589b8ab98e65e80ae44a1252"
+dependencies = [
+ "bitcoin_hashes",
+ "rand 0.8.6",
+ "secp256k1-sys 0.10.1",
+ "serde",
+]
+
+[[package]]
+name = "secp256k1"
+version = "0.31.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2c3c81b43dc2d8877c216a3fccf76677ee1ebccd429566d3e67447290d0c42b2"
+dependencies = [
+ "bitcoin_hashes",
+ "rand 0.9.4",
+ "secp256k1-sys 0.11.0",
+]
+
+[[package]]
+name = "secp256k1-sys"
+version = "0.10.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d4387882333d3aa8cb20530a17c69a3752e97837832f34f6dccc760e715001d9"
+dependencies = [
+ "cc",
+]
+
+[[package]]
+name = "secp256k1-sys"
+version = "0.11.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dcb913707158fadaf0d8702c2db0e857de66eb003ccfdda5924b5f5ac98efb38"
+dependencies = [
+ "cc",
+]
+
+[[package]]
+name = "security-framework"
+version = "3.7.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b7f4bc775c73d9a02cde8bf7b2ec4c9d12743edf609006c7facc23998404cd1d"
+dependencies = [
+ "bitflags",
+ "core-foundation",
+ "core-foundation-sys",
+ "libc",
+ "security-framework-sys",
+]
+
+[[package]]
+name = "security-framework-sys"
+version = "2.17.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6ce2691df843ecc5d231c0b14ece2acc3efb62c0a398c7e1d875f3983ce020e3"
+dependencies = [
+ "core-foundation-sys",
+ "libc",
+]
+
+[[package]]
+name = "semver"
+version = "0.11.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f301af10236f6df4160f7c3f04eec6dbc70ace82d23326abad5edee88801c6b6"
+dependencies = [
+ "semver-parser",
+]
+
+[[package]]
+name = "semver"
+version = "1.0.28"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8a7852d02fc848982e0c167ef163aaff9cd91dc640ba85e263cb1ce46fae51cd"
+
+[[package]]
+name = "semver-parser"
+version = "0.10.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9900206b54a3527fdc7b8a938bffd94a568bac4f4aa8113b209df75a09c0dec2"
+dependencies = [
+ "pest",
+]
+
+[[package]]
+name = "send_wrapper"
+version = "0.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cd0b0ec5f1c1ca621c432a25813d8d60c88abe6d3e08a3eb9cf37d97a0fe3d73"
+
+[[package]]
+name = "serde"
+version = "1.0.228"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e"
+dependencies = [
+ "serde_core",
+ "serde_derive",
+]
+
+[[package]]
+name = "serde_bytes"
+version = "0.11.19"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a5d440709e79d88e51ac01c4b72fc6cb7314017bb7da9eeff678aa94c10e3ea8"
+dependencies = [
+ "serde",
+ "serde_core",
+]
+
+[[package]]
+name = "serde_core"
+version = "1.0.228"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad"
+dependencies = [
+ "serde_derive",
+]
+
+[[package]]
+name = "serde_derive"
+version = "1.0.228"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.118",
+]
+
+[[package]]
+name = "serde_json"
+version = "1.0.150"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e8014e44b4736ed0538adeecded0fce2a272f22dc9578a7eb6b2d9993c74cfb9"
+dependencies = [
+ "itoa",
+ "memchr",
+ "serde",
+ "serde_core",
+ "zmij",
+]
+
+[[package]]
+name = "serde_with"
+version = "3.21.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "76a5c54c7310e7b8b9577c286d7e399ddd876c3e12b3ed917a8aabc4b96e9e8c"
+dependencies = [
+ "base64",
+ "bs58",
+ "chrono",
+ "hex",
+ "indexmap 1.9.3",
+ "indexmap 2.14.0",
+ "schemars 0.9.0",
+ "schemars 1.2.1",
+ "serde_core",
+ "serde_json",
+ "serde_with_macros",
+ "time",
+]
+
+[[package]]
+name = "serde_with_macros"
+version = "3.21.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "84d57bc0c8b9a17920c178daa6bb924850d54a9c97ab45194bb8c17ad66bb660"
+dependencies = [
+ "darling",
+ "proc-macro2",
+ "quote",
+ "syn 2.0.118",
+]
+
+[[package]]
+name = "serdect"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a84f14a19e9a014bb9f4512488d9829a68e04ecabffb0f9904cd1ace94598177"
+dependencies = [
+ "base16ct",
+ "serde",
+]
+
+[[package]]
+name = "sha1"
+version = "0.10.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba"
+dependencies = [
+ "cfg-if",
+ "cpufeatures 0.2.17",
+ "digest 0.10.7",
+]
+
+[[package]]
+name = "sha2"
+version = "0.10.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283"
+dependencies = [
+ "cfg-if",
+ "cpufeatures 0.2.17",
+ "digest 0.10.7",
+]
+
+[[package]]
+name = "sha3"
+version = "0.11.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "be176f1a57ce4e3d31c1a166222d9768de5954f811601fb7ca06fc8203905ce1"
+dependencies = [
+ "digest 0.11.3",
+ "keccak",
+]
+
+[[package]]
+name = "sha3-asm"
+version = "0.1.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a6287fd675f713484342a89cbf0a386abef5f15919cfad607e5e1f19e1e15331"
+dependencies = [
+ "cc",
+ "cfg-if",
+]
+
+[[package]]
+name = "shlex"
+version = "2.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f8fadd59c855ef2080decdef8ff161eb6661b86933c9d82e5ba29dc602a55aba"
+
+[[package]]
+name = "signature"
+version = "2.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de"
+dependencies = [
+ "digest 0.10.7",
+ "rand_core 0.6.4",
+]
+
+[[package]]
+name = "simd_cesu8"
+version = "1.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "94f90157bb87cddf702797c5dadfa0be7d266cdf49e22da2fcaa32eff75b2c33"
+dependencies = [
+ "rustc_version 0.4.1",
+ "simdutf8",
+]
+
+[[package]]
+name = "simdutf8"
+version = "0.1.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e3a9fe34e3e7a50316060351f37187a3f546bce95496156754b601a5fa71b76e"
+
+[[package]]
+name = "slab"
+version = "0.4.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5"
+
+[[package]]
+name = "smallvec"
+version = "1.15.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8ed6a63f02c8539c91a8685a86f4099661ba3da017932f6ebbea6de3f0fa7c90"
+dependencies = [
+ "serde",
+]
+
+[[package]]
+name = "socket2"
+version = "0.6.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "52d1cfed4120b4d927bf7c0f86d2087a4a7d6027c906d9f9d525a80573b9be51"
+dependencies = [
+ "libc",
+ "windows-sys 0.61.2",
+]
+
+[[package]]
+name = "spki"
+version = "0.7.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29d"
+dependencies = [
+ "base64ct",
+ "der",
+]
+
+[[package]]
+name = "stable_deref_trait"
+version = "1.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596"
+
+[[package]]
+name = "stacker"
+version = "0.1.24"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "640c8cdd92b6b12f5bcb1803ca3bbf5ab96e5e6b6b96b9ab77dabe9e880b3190"
+dependencies = [
+ "cc",
+ "cfg-if",
+ "libc",
+ "psm",
+ "windows-sys 0.61.2",
+]
+
+[[package]]
+name = "static_assertions"
+version = "1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
+
+[[package]]
+name = "strsim"
+version = "0.11.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
+
+[[package]]
+name = "strum"
+version = "0.27.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "af23d6f6c1a224baef9d3f61e287d2761385a5b88fdab4eb4c6f11aeb54c4bcf"
+dependencies = [
+ "strum_macros",
+]
+
+[[package]]
+name = "strum_macros"
+version = "0.27.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7695ce3845ea4b33927c055a39dc438a45b059f7c1b3d91d38d10355fb8cbca7"
+dependencies = [
+ "heck",
+ "proc-macro2",
+ "quote",
+ "syn 2.0.118",
+]
+
+[[package]]
+name = "subtle"
+version = "2.6.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292"
+
+[[package]]
+name = "syn"
+version = "1.0.109"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "unicode-ident",
+]
+
+[[package]]
+name = "syn"
+version = "2.0.118"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1b9ae57f904213ebb649ce6895b8a66c66f0203b9319718f69a5612a065b1422"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "unicode-ident",
+]
+
+[[package]]
+name = "syn-solidity"
+version = "1.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ec005042c7d952febc1a3ef5b0f6674e9054aa836877a31c90b20e25b3d31744"
+dependencies = [
+ "paste",
+ "proc-macro2",
+ "quote",
+ "syn 2.0.118",
+]
+
+[[package]]
+name = "sync_wrapper"
+version = "1.0.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0bf256ce5efdfa370213c1dabab5935a12e49f2c58d15e9eac2870d3b4f27263"
+dependencies = [
+ "futures-core",
+]
+
+[[package]]
+name = "synstructure"
+version = "0.13.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.118",
+]
+
+[[package]]
+name = "tap"
+version = "1.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369"
+
+[[package]]
+name = "tempfile"
+version = "3.27.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "32497e9a4c7b38532efcdebeef879707aa9f794296a4f0244f6f69e9bc8574bd"
+dependencies = [
+ "fastrand",
+ "getrandom 0.4.3",
+ "once_cell",
+ "rustix",
+ "windows-sys 0.61.2",
+]
+
+[[package]]
+name = "thiserror"
+version = "1.0.69"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52"
+dependencies = [
+ "thiserror-impl 1.0.69",
+]
+
+[[package]]
+name = "thiserror"
+version = "2.0.18"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4288b5bcbc7920c07a1149a35cf9590a2aa808e0bc1eafaade0b80947865fbc4"
+dependencies = [
+ "thiserror-impl 2.0.18",
+]
+
+[[package]]
+name = "thiserror-impl"
+version = "1.0.69"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.118",
+]
+
+[[package]]
+name = "thiserror-impl"
+version = "2.0.18"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.118",
+]
+
+[[package]]
+name = "threadpool"
+version = "1.8.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d050e60b33d41c19108b32cea32164033a9013fe3b46cbd4457559bfbf77afaa"
+dependencies = [
+ "num_cpus",
+]
+
+[[package]]
+name = "time"
+version = "0.3.53"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "18dfaaeddcb932337b5e7866ee7d0ce9b76d2fd092997146f187ec09b4558a50"
+dependencies = [
+ "deranged",
+ "num-conv",
+ "powerfmt",
+ "serde_core",
+ "time-core",
+ "time-macros",
+]
+
+[[package]]
+name = "time-core"
+version = "0.1.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9e1c906769ad99c88eaa54e728060edef082f8e358ff32030cb7c7d315e81109"
+
+[[package]]
+name = "time-macros"
+version = "0.2.31"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c431b87111666e491a90baa837f914fb45cd5dc3c268591b0220ff5057f2085f"
+dependencies = [
+ "num-conv",
+ "time-core",
+]
+
+[[package]]
+name = "tinystr"
+version = "0.8.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c8323304221c2a851516f22236c5722a72eaa19749016521d6dff0824447d96d"
+dependencies = [
+ "displaydoc",
+ "zerovec",
+]
+
+[[package]]
+name = "tinyvec"
+version = "1.11.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3e61e67053d25a4e82c844e8424039d9745781b3fc4f32b8d55ed50f5f667ef3"
+dependencies = [
+ "tinyvec_macros",
+]
+
+[[package]]
+name = "tinyvec_macros"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
+
+[[package]]
+name = "tokio"
+version = "1.52.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8fc7f01b389ac15039e4dc9531aa973a135d7a4135281b12d7c1bc79fd57fffe"
+dependencies = [
+ "bytes",
+ "libc",
+ "mio",
+ "pin-project-lite",
+ "socket2",
+ "tokio-macros",
+ "windows-sys 0.61.2",
+]
+
+[[package]]
+name = "tokio-macros"
+version = "2.7.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "385a6cb71ab9ab790c5fe8d67f1645e6c450a7ce006a33de03daa956cf70a496"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.118",
+]
+
+[[package]]
+name = "tokio-rustls"
+version = "0.26.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1729aa945f29d91ba541258c8df89027d5792d85a8841fb65e8bf0f4ede4ef61"
+dependencies = [
+ "rustls",
+ "tokio",
+]
+
+[[package]]
+name = "tokio-stream"
+version = "0.1.18"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "32da49809aab5c3bc678af03902d4ccddea2a87d028d86392a4b1560c6906c70"
+dependencies = [
+ "futures-core",
+ "pin-project-lite",
+ "tokio",
+ "tokio-util",
+]
+
+[[package]]
+name = "tokio-tungstenite"
+version = "0.28.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d25a406cddcc431a75d3d9afc6a7c0f7428d4891dd973e4d54c56b46127bf857"
+dependencies = [
+ "futures-util",
+ "log",
+ "rustls",
+ "rustls-pki-types",
+ "tokio",
+ "tokio-rustls",
+ "tungstenite",
+ "webpki-roots 0.26.11",
+]
+
+[[package]]
+name = "tokio-util"
+version = "0.7.18"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9ae9cec805b01e8fc3fd2fe289f89149a9b66dd16786abd8b19cfa7b48cb0098"
+dependencies = [
+ "bytes",
+ "futures-core",
+ "futures-sink",
+ "pin-project-lite",
+ "tokio",
+]
+
+[[package]]
+name = "toml_datetime"
+version = "1.1.1+spec-1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3165f65f62e28e0115a00b2ebdd37eb6f3b641855f9d636d3cd4103767159ad7"
+dependencies = [
+ "serde_core",
+]
+
+[[package]]
+name = "toml_edit"
+version = "0.25.12+spec-1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d2153edc6955a6c354fad8f5efd38b6a8769bdccf9fe50f8e1329f81b0baa5d7"
+dependencies = [
+ "indexmap 2.14.0",
+ "toml_datetime",
+ "toml_parser",
+ "winnow",
+]
+
+[[package]]
+name = "toml_parser"
+version = "1.1.2+spec-1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a2abe9b86193656635d2411dc43050282ca48aa31c2451210f4202550afb7526"
+dependencies = [
+ "winnow",
+]
+
+[[package]]
+name = "tower"
+version = "0.5.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ebe5ef63511595f1344e2d5cfa636d973292adc0eec1f0ad45fae9f0851ab1d4"
+dependencies = [
+ "futures-core",
+ "futures-util",
+ "pin-project-lite",
+ "sync_wrapper",
+ "tokio",
+ "tower-layer",
+ "tower-service",
+]
+
+[[package]]
+name = "tower-http"
+version = "0.6.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4cfcf7e2740e6fc6d4d688b4ef00650406bb94adf4731e43c096c3a19fe40840"
+dependencies = [
+ "bitflags",
+ "bytes",
+ "futures-util",
+ "http",
+ "http-body",
+ "pin-project-lite",
+ "tower",
+ "tower-layer",
+ "tower-service",
+ "url",
+]
+
+[[package]]
+name = "tower-layer"
+version = "0.3.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "121c2a6cda46980bb0fcd1647ffaf6cd3fc79a013de288782836f6df9c48780e"
+
+[[package]]
+name = "tower-service"
+version = "0.3.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3"
+
+[[package]]
+name = "tracing"
+version = "0.1.44"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "63e71662fa4b2a2c3a26f570f037eb95bb1f85397f3cd8076caed2f026a6d100"
+dependencies = [
+ "pin-project-lite",
+ "tracing-attributes",
+ "tracing-core",
+]
+
+[[package]]
+name = "tracing-attributes"
+version = "0.1.31"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.118",
+]
+
+[[package]]
+name = "tracing-core"
+version = "0.1.36"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "db97caf9d906fbde555dd62fa95ddba9eecfd14cb388e4f491a66d74cd5fb79a"
+dependencies = [
+ "once_cell",
+]
+
+[[package]]
+name = "try-lock"
+version = "0.2.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b"
+
+[[package]]
+name = "tungstenite"
+version = "0.28.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8628dcc84e5a09eb3d8423d6cb682965dea9133204e8fb3efee74c2a0c259442"
+dependencies = [
+ "bytes",
+ "data-encoding",
+ "http",
+ "httparse",
+ "log",
+ "rand 0.9.4",
+ "rustls",
+ "rustls-pki-types",
+ "sha1",
+ "thiserror 2.0.18",
+ "utf-8",
+]
+
+[[package]]
+name = "typed-arena"
+version = "2.0.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6af6ae20167a9ece4bcb41af5b80f8a1f1df981f6391189ce00fd257af04126a"
+
+[[package]]
+name = "typenum"
+version = "1.20.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b6f5e870be6c3b371b77fe0ee0bafb859fa4964b4404c27de1d380043c4dda20"
+
+[[package]]
+name = "ucd-trie"
+version = "0.1.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2896d95c02a80c6d6a5d6e953d479f5ddf2dfdb6a244441010e373ac0fb88971"
+
+[[package]]
+name = "uint"
+version = "0.9.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "76f64bba2c53b04fcab63c01a7d7427eadc821e3bc48c34dc9ba29c501164b52"
+dependencies = [
+ "byteorder",
+ "crunchy",
+ "hex",
+ "static_assertions",
+]
+
+[[package]]
+name = "unarray"
+version = "0.1.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "eaea85b334db583fe3274d12b4cd1880032beab409c0d774be044d4480ab9a94"
+
+[[package]]
+name = "unicode-ident"
+version = "1.0.24"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75"
+
+[[package]]
+name = "unicode-segmentation"
+version = "1.13.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c6f5d3c3b1bf09027a88a6bc961fc00497d651009560b5463668dc81b0fa87a8"
+
+[[package]]
+name = "unicode-width"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b4ac048d71ede7ee76d585517add45da530660ef4390e49b098733c6e897f254"
+
+[[package]]
+name = "unicode-xid"
+version = "0.2.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853"
+
+[[package]]
+name = "untrusted"
+version = "0.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1"
+
+[[package]]
+name = "url"
+version = "2.5.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ff67a8a4397373c3ef660812acab3268222035010ab8680ec4215f38ba3d0eed"
+dependencies = [
+ "form_urlencoded",
+ "idna",
+ "percent-encoding",
+ "serde",
+ "serde_derive",
+]
+
+[[package]]
+name = "utf-8"
+version = "0.7.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9"
+
+[[package]]
+name = "utf8_iter"
+version = "1.0.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be"
+
+[[package]]
+name = "valuable"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65"
+
+[[package]]
+name = "version_check"
+version = "0.9.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a"
+
+[[package]]
+name = "wait-timeout"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "09ac3b126d3914f9849036f826e054cbabdc8519970b8998ddaf3b5bd3c65f11"
+dependencies = [
+ "libc",
+]
+
+[[package]]
+name = "walkdir"
+version = "2.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b"
+dependencies = [
+ "same-file",
+ "winapi-util",
+]
+
+[[package]]
+name = "want"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e"
+dependencies = [
+ "try-lock",
+]
+
+[[package]]
+name = "wasi"
+version = "0.11.1+wasi-snapshot-preview1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b"
+
+[[package]]
+name = "wasip2"
+version = "1.0.4+wasi-0.2.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b67efb37e106e55ce722a510d6b5f9c17f083e5fc79afc2badeb12cc313d9487"
+dependencies = [
+ "wit-bindgen",
+]
+
+[[package]]
+name = "wasm-bindgen"
+version = "0.2.126"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4b067c0c11094aef6b7a801c1e34a26affafdf3d051dba08456b868789aaf9a4"
+dependencies = [
+ "cfg-if",
+ "once_cell",
+ "rustversion",
+ "wasm-bindgen-macro",
+ "wasm-bindgen-shared",
+]
+
+[[package]]
+name = "wasm-bindgen-futures"
+version = "0.4.76"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c62df1340f32221cb9c54d6a27b030e3dba64361d4a95bed55f9aacb44da291d"
+dependencies = [
+ "js-sys",
+ "wasm-bindgen",
+]
+
+[[package]]
+name = "wasm-bindgen-macro"
+version = "0.2.126"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "167ce5e579f6bcf889c4f7175a8a5a585de84e8ff93976ce393efa5f2837aab1"
+dependencies = [
+ "quote",
+ "wasm-bindgen-macro-support",
+]
+
+[[package]]
+name = "wasm-bindgen-macro-support"
+version = "0.2.126"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f3997c7839262f4ef12cf90b818d6340c18e80f263f1a94bf157d0ec4420380e"
+dependencies = [
+ "bumpalo",
+ "proc-macro2",
+ "quote",
+ "syn 2.0.118",
+ "wasm-bindgen-shared",
+]
+
+[[package]]
+name = "wasm-bindgen-shared"
+version = "0.2.126"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dc1b4cb0cc549fcf58d7dfc081778139b3d283a081644e833e84682ad71cea24"
+dependencies = [
+ "unicode-ident",
+]
+
+[[package]]
+name = "wasmtimer"
+version = "0.4.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1c598d6b99ea013e35844697fc4670d08339d5cda15588f193c6beedd12f644b"
+dependencies = [
+ "futures",
+ "js-sys",
+ "parking_lot",
+ "pin-utils",
+ "slab",
+ "wasm-bindgen",
+]
+
+[[package]]
+name = "web-sys"
+version = "0.3.103"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8622dcb61c0bcc9fffa6938bed81210af2da9a7e4a1a834b2e37a59b6dfb6141"
+dependencies = [
+ "js-sys",
+ "wasm-bindgen",
+]
+
+[[package]]
+name = "web-time"
+version = "1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5a6580f308b1fad9207618087a65c04e7a10bc77e02c8e84e9b00dd4b12fa0bb"
+dependencies = [
+ "js-sys",
+ "wasm-bindgen",
+]
+
+[[package]]
+name = "webpki-root-certs"
+version = "1.0.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0d46a5a140e6f7afeccd8eae97eff335163939eac8b929834875168b29b3d267"
+dependencies = [
+ "rustls-pki-types",
+]
+
+[[package]]
+name = "webpki-roots"
+version = "0.26.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "521bc38abb08001b01866da9f51eb7c5d647a19260e00054a8c7fd5f9e57f7a9"
+dependencies = [
+ "webpki-roots 1.0.8",
+]
+
+[[package]]
+name = "webpki-roots"
+version = "1.0.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bf85cb06032201fa7c6f829d7db5a7e5aa45bcc0655327713065f6f0576731bf"
+dependencies = [
+ "rustls-pki-types",
+]
+
+[[package]]
+name = "widestring"
+version = "1.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "72069c3113ab32ab29e5584db3c6ec55d416895e60715417b5b883a357c3e471"
+
+[[package]]
+name = "winapi-util"
+version = "0.1.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22"
+dependencies = [
+ "windows-sys 0.61.2",
+]
+
+[[package]]
+name = "windows-core"
+version = "0.62.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b8e83a14d34d0623b51dce9581199302a221863196a1dde71a7663a4c2be9deb"
+dependencies = [
+ "windows-implement",
+ "windows-interface",
+ "windows-link",
+ "windows-result",
+ "windows-strings",
+]
+
+[[package]]
+name = "windows-implement"
+version = "0.60.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.118",
+]
+
+[[package]]
+name = "windows-interface"
+version = "0.59.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.118",
+]
+
+[[package]]
+name = "windows-link"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5"
+
+[[package]]
+name = "windows-result"
+version = "0.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7781fa89eaf60850ac3d2da7af8e5242a5ea78d1a11c49bf2910bb5a73853eb5"
+dependencies = [
+ "windows-link",
+]
+
+[[package]]
+name = "windows-strings"
+version = "0.5.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7837d08f69c77cf6b07689544538e017c1bfcf57e34b4c0ff58e6c2cd3b37091"
+dependencies = [
+ "windows-link",
+]
+
+[[package]]
+name = "windows-sys"
+version = "0.52.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
+dependencies = [
+ "windows-targets 0.52.6",
+]
+
+[[package]]
+name = "windows-sys"
+version = "0.60.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb"
+dependencies = [
+ "windows-targets 0.53.5",
+]
+
+[[package]]
+name = "windows-sys"
+version = "0.61.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc"
+dependencies = [
+ "windows-link",
+]
+
+[[package]]
+name = "windows-targets"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973"
+dependencies = [
+ "windows_aarch64_gnullvm 0.52.6",
+ "windows_aarch64_msvc 0.52.6",
+ "windows_i686_gnu 0.52.6",
+ "windows_i686_gnullvm 0.52.6",
+ "windows_i686_msvc 0.52.6",
+ "windows_x86_64_gnu 0.52.6",
+ "windows_x86_64_gnullvm 0.52.6",
+ "windows_x86_64_msvc 0.52.6",
+]
+
+[[package]]
+name = "windows-targets"
+version = "0.53.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4945f9f551b88e0d65f3db0bc25c33b8acea4d9e41163edf90dcd0b19f9069f3"
+dependencies = [
+ "windows-link",
+ "windows_aarch64_gnullvm 0.53.1",
+ "windows_aarch64_msvc 0.53.1",
+ "windows_i686_gnu 0.53.1",
+ "windows_i686_gnullvm 0.53.1",
+ "windows_i686_msvc 0.53.1",
+ "windows_x86_64_gnu 0.53.1",
+ "windows_x86_64_gnullvm 0.53.1",
+ "windows_x86_64_msvc 0.53.1",
+]
+
+[[package]]
+name = "windows_aarch64_gnullvm"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
+
+[[package]]
+name = "windows_aarch64_gnullvm"
+version = "0.53.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a9d8416fa8b42f5c947f8482c43e7d89e73a173cead56d044f6a56104a6d1b53"
+
+[[package]]
+name = "windows_aarch64_msvc"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
+
+[[package]]
+name = "windows_aarch64_msvc"
+version = "0.53.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b9d782e804c2f632e395708e99a94275910eb9100b2114651e04744e9b125006"
+
+[[package]]
+name = "windows_i686_gnu"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b"
+
+[[package]]
+name = "windows_i686_gnu"
+version = "0.53.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "960e6da069d81e09becb0ca57a65220ddff016ff2d6af6a223cf372a506593a3"
+
+[[package]]
+name = "windows_i686_gnullvm"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
+
+[[package]]
+name = "windows_i686_gnullvm"
+version = "0.53.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fa7359d10048f68ab8b09fa71c3daccfb0e9b559aed648a8f95469c27057180c"
+
+[[package]]
+name = "windows_i686_msvc"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
+
+[[package]]
+name = "windows_i686_msvc"
+version = "0.53.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1e7ac75179f18232fe9c285163565a57ef8d3c89254a30685b57d83a38d326c2"
+
+[[package]]
+name = "windows_x86_64_gnu"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
+
+[[package]]
+name = "windows_x86_64_gnu"
+version = "0.53.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9c3842cdd74a865a8066ab39c8a7a473c0778a3f29370b5fd6b4b9aa7df4a499"
+
+[[package]]
+name = "windows_x86_64_gnullvm"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
+
+[[package]]
+name = "windows_x86_64_gnullvm"
+version = "0.53.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0ffa179e2d07eee8ad8f57493436566c7cc30ac536a3379fdf008f47f6bb7ae1"
+
+[[package]]
+name = "windows_x86_64_msvc"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
+
+[[package]]
+name = "windows_x86_64_msvc"
+version = "0.53.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650"
+
+[[package]]
+name = "winnow"
+version = "1.0.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0592e1c9d151f854e6fd382574c3a0855250e1d9b2f99d9281c6e6391af352f1"
+dependencies = [
+ "memchr",
+]
+
+[[package]]
+name = "wit-bindgen"
+version = "0.57.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1ebf944e87a7c253233ad6766e082e3cd714b5d03812acc24c318f549614536e"
+
+[[package]]
+name = "writeable"
+version = "0.6.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1ffae5123b2d3fc086436f8834ae3ab053a283cfac8fe0a0b8eaae044768a4c4"
+
+[[package]]
+name = "ws_stream_wasm"
+version = "0.7.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6c173014acad22e83f16403ee360115b38846fe754e735c5d9d3803fe70c6abc"
+dependencies = [
+ "async_io_stream",
+ "futures",
+ "js-sys",
+ "log",
+ "pharos",
+ "rustc_version 0.4.1",
+ "send_wrapper",
+ "thiserror 2.0.18",
+ "wasm-bindgen",
+ "wasm-bindgen-futures",
+ "web-sys",
+]
+
+[[package]]
+name = "wyz"
+version = "0.5.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed"
+dependencies = [
+ "tap",
+]
+
+[[package]]
+name = "yoke"
+version = "0.8.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "709fe23a0424b6a435d82152b1bd3fdfb0833487d5fa90d05d42762a9891fef5"
+dependencies = [
+ "stable_deref_trait",
+ "yoke-derive",
+ "zerofrom",
+]
+
+[[package]]
+name = "yoke-derive"
+version = "0.8.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "de844c262c8848816172cef550288e7dc6c7b7814b4ee56b3e1553f275f1858e"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.118",
+ "synstructure",
+]
+
+[[package]]
+name = "zerocopy"
+version = "0.8.52"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ce1022995ff5ff5d841ad7d994facc23098cd40152f2c1d11cd607c6f530653f"
+dependencies = [
+ "zerocopy-derive",
+]
+
+[[package]]
+name = "zerocopy-derive"
+version = "0.8.52"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1ae7f38b72ec2a254e2b87ef277cf2cd4fb97cbebf944faa6f33354da0867930"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.118",
+]
+
+[[package]]
+name = "zerofrom"
+version = "0.1.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0ec05a11813ea801ff6d75110ad09cd0824ddba17dfe17128ea0d5f68e6c5272"
+dependencies = [
+ "zerofrom-derive",
+]
+
+[[package]]
+name = "zerofrom-derive"
+version = "0.1.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "11532158c46691caf0f2593ea8358fed6bbf68a0315e80aae9bd41fbade684a1"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.118",
+ "synstructure",
+]
+
+[[package]]
+name = "zeroize"
+version = "1.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e13c156562582aa81c60cb29407084cdb54c4164760106ab78e6c5b0858cf64e"
+dependencies = [
+ "zeroize_derive",
+]
+
+[[package]]
+name = "zeroize_derive"
+version = "1.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3c50655cbb0fe3fc43170059e702f1ce5e19b84cec58dc87b037a09935c2f328"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.118",
+]
+
+[[package]]
+name = "zerotrie"
+version = "0.2.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0f9152d31db0792fa83f70fb2f83148effb5c1f5b8c7686c3459e361d9bc20bf"
+dependencies = [
+ "displaydoc",
+ "yoke",
+ "zerofrom",
+]
+
+[[package]]
+name = "zerovec"
+version = "0.11.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "90f911cbc359ab6af17377d242225f4d75119aec87ea711a880987b18cd7b239"
+dependencies = [
+ "yoke",
+ "zerofrom",
+ "zerovec-derive",
+]
+
+[[package]]
+name = "zerovec-derive"
+version = "0.11.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "625dc425cab0dca6dc3c3319506e6593dcb08a9f387ea3b284dbd52a92c40555"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.118",
+]
+
+[[package]]
+name = "zmij"
+version = "1.0.21"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa"
diff --git a/rs/ethereum/cketh/docs/deposit_from_cex_demo/Cargo.toml b/rs/ethereum/cketh/docs/deposit_from_cex_demo/Cargo.toml
new file mode 100644
index 000000000000..c8aff0b4f30e
--- /dev/null
+++ b/rs/ethereum/cketh/docs/deposit_from_cex_demo/Cargo.toml
@@ -0,0 +1,16 @@
+[package]
+name = "deposit-from-cex-demo"
+version = "0.1.0"
+edition = "2021"
+publish = false
+
+# Standalone on purpose: this is a runnable design-doc demo, not part of the IC
+# build (not a member of the root Cargo workspace, no bazel target).
+[workspace]
+
+[dependencies]
+alloy = { version = "1", features = ["full"] }
+anyhow = "1"
+candid = "0.10"
+hex = "0.4"
+tokio = { version = "1", features = ["macros", "rt-multi-thread"] }
diff --git a/rs/ethereum/cketh/docs/deposit_from_cex_demo/README.md b/rs/ethereum/cketh/docs/deposit_from_cex_demo/README.md
new file mode 100644
index 000000000000..1890ba551030
--- /dev/null
+++ b/rs/ethereum/cketh/docs/deposit_from_cex_demo/README.md
@@ -0,0 +1,74 @@
+# Deposit-from-CEX demo
+
+Runnable demonstration of the sweep mechanism designed in
+[`../deposit_from_cex.md`](../deposit_from_cex.md), using [alloy](https://alloy.rs)
+against a local Prague-enabled node. The minter is simulated by a plain EOA
+controlling a family of derived EOAs (stand-in for threshold ECDSA on the IC).
+
+It shows that an **unfunded** deposit EOA (0 ETH, no code) receiving a plain
+USDT-style ERC-20 transfer can be swept to the minter in a **single EIP-7702
+transaction** whose gas is paid entirely by the minter — first for one deposit
+address, then **batched** (one transaction sweeping three deposit EOAs, their
+authorizations riding in the same transaction's authorization list).
+
+It then exercises **both sweep variants** of the design doc's open decision:
+
+* **Variant A** (`CkSweeper`): the delegate transfers straight to the minter;
+ sweeps are permissionless-safe.
+* **Variant B** (`CkSweeperViaHelper`): the deposit EOAs are re-delegated and
+ the sweep calls `depositErc20` on the **real helper contract** (`CkDeposit`,
+ compiled from `../../minter/DepositHelperWithSubaccount.sol`), so each sweep
+ emits the canonical `ReceivedEthOrErc20` event — asserted to carry the right
+ IC principal — that the minter's existing deposit pipeline already scrapes
+ and mints from. Because the principal is a sweep argument, sweeping is
+ restricted to the minter: the demo ends with an **attacker attempting to
+ sweep with their own principal and being rejected**, followed by the correct
+ minter sweep (a plain EIP-1559 transaction — delegation persists).
+
+Every sweep prints the minter's nonce, the raw signed transaction and the
+receipt, and the gas used by each sweep is asserted against hard-coded
+constants (the run is fully deterministic).
+
+## Run
+
+Start anvil (its default hardfork is the latest supported one, which includes
+EIP-7702 in any foundry release ≥ v1.0 / Pectra):
+
+```shell
+anvil
+```
+
+or, without foundry installed:
+
+```shell
+docker run --rm -p 8545:8545 ghcr.io/foundry-rs/foundry:v1.7.1 \
+ "anvil --host 0.0.0.0"
+```
+
+then:
+
+```shell
+cargo run
+```
+
+(`ETH_RPC_URL` overrides the default `http://127.0.0.1:8545`.)
+
+## Contracts
+
+`contracts/` holds the Solidity sources (`CkSweeper.sol` and
+`CkSweeperViaHelper.sol`, the EIP-7702 delegates and batchers for the two sweep
+variants; `MockUSDT.sol`, a USDT-style ERC-20 whose `transfer`/`approve`/
+`transferFrom` return no value). The deployment bytecode embedded in the binary
+lives in `artifacts/`, including `CkDeposit.bin.hex` compiled from the real
+helper contract `../../minter/DepositHelperWithSubaccount.sol`. Regenerate
+after changing the contracts with:
+
+```shell
+cp ../../minter/DepositHelperWithSubaccount.sol contracts/
+forge build
+for c in CkSweeper CkSweeperViaHelper MockUSDT; do
+ grep -o '"object":"0x[0-9a-f]*"' out/$c.sol/$c.json | head -1 | sed 's/"object":"//;s/"//' > artifacts/$c.bin.hex
+done
+grep -o '"object":"0x[0-9a-f]*"' out/DepositHelperWithSubaccount.sol/CkDeposit.json | head -1 | sed 's/"object":"//;s/"//' > artifacts/CkDeposit.bin.hex
+rm contracts/DepositHelperWithSubaccount.sol
+```
diff --git a/rs/ethereum/cketh/docs/deposit_from_cex_demo/artifacts/CkDeposit.bin.hex b/rs/ethereum/cketh/docs/deposit_from_cex_demo/artifacts/CkDeposit.bin.hex
new file mode 100644
index 000000000000..e01c67c09b4b
--- /dev/null
+++ b/rs/ethereum/cketh/docs/deposit_from_cex_demo/artifacts/CkDeposit.bin.hex
@@ -0,0 +1 @@
+0x60a060405234801561000f575f5ffd5b50604051610a4e380380610a4e833981810160405281019061003191906100c9565b8073ffffffffffffffffffffffffffffffffffffffff1660808173ffffffffffffffffffffffffffffffffffffffff1681525050506100f4565b5f5ffd5b5f73ffffffffffffffffffffffffffffffffffffffff82169050919050565b5f6100988261006f565b9050919050565b6100a88161008e565b81146100b2575f5ffd5b50565b5f815190506100c38161009f565b92915050565b5f602082840312156100de576100dd61006b565b5b5f6100eb848285016100b5565b91505092915050565b60805161093461011a5f395f818161010f01528181610178015261021401526109345ff3fe608060405260043610610033575f3560e01c806317c819c41461003757806393e5d42a14610053578063db9751af1461007d575b5f5ffd5b610051600480360381019061004c91906105c7565b6100a5565b005b34801561005e575f5ffd5b50610067610175565b6040516100749190610644565b60405180910390f35b348015610088575f5ffd5b506100a3600480360381019061009e91906106ba565b61019c565b005b813373ffffffffffffffffffffffffffffffffffffffff165f73ffffffffffffffffffffffffffffffffffffffff167f918adbebdb8f3b36fc337ab76df10b147b2def5c9dd62cb3456d9aeca40e0b07348560405161010592919061073c565b60405180910390a47f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff166108fc3490811502906040515f60405180830381858888f19350505050158015610170573d5f5f3e3d5ffd5b505050565b5f7f0000000000000000000000000000000000000000000000000000000000000000905090565b5f73ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff160361020a576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610201906107e3565b60405180910390fd5b5f84905061025b337f0000000000000000000000000000000000000000000000000000000000000000868473ffffffffffffffffffffffffffffffffffffffff166102ca909392919063ffffffff16565b823373ffffffffffffffffffffffffffffffffffffffff168673ffffffffffffffffffffffffffffffffffffffff167f918adbebdb8f3b36fc337ab76df10b147b2def5c9dd62cb3456d9aeca40e0b0787866040516102bb92919061073c565b60405180910390a45050505050565b610346848573ffffffffffffffffffffffffffffffffffffffff166323b872dd8686866040516024016102ff93929190610801565b604051602081830303815290604052915060e01b6020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff838183161783525050505061034c565b50505050565b5f610376828473ffffffffffffffffffffffffffffffffffffffff166103e190919063ffffffff16565b90505f81511415801561039a575080806020019051810190610398919061086b565b155b156103dc57826040517f5274afe70000000000000000000000000000000000000000000000000000000081526004016103d39190610644565b60405180910390fd5b505050565b60606103ee83835f6103f6565b905092915050565b60608147101561043d57306040517fcd7860590000000000000000000000000000000000000000000000000000000081526004016104349190610644565b60405180910390fd5b5f5f8573ffffffffffffffffffffffffffffffffffffffff16848660405161046591906108e8565b5f6040518083038185875af1925050503d805f811461049f576040519150601f19603f3d011682016040523d82523d5f602084013e6104a4565b606091505b50915091506104b48683836104bf565b925050509392505050565b6060826104d4576104cf8261054c565b610544565b5f82511480156104fa57505f8473ffffffffffffffffffffffffffffffffffffffff163b145b1561053c57836040517f9996b3150000000000000000000000000000000000000000000000000000000081526004016105339190610644565b60405180910390fd5b819050610545565b5b9392505050565b5f8151111561055e5780518082602001fd5b6040517f1425ea4200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f5ffd5b5f819050919050565b6105a681610594565b81146105b0575f5ffd5b50565b5f813590506105c18161059d565b92915050565b5f5f604083850312156105dd576105dc610590565b5b5f6105ea858286016105b3565b92505060206105fb858286016105b3565b9150509250929050565b5f73ffffffffffffffffffffffffffffffffffffffff82169050919050565b5f61062e82610605565b9050919050565b61063e81610624565b82525050565b5f6020820190506106575f830184610635565b92915050565b61066681610624565b8114610670575f5ffd5b50565b5f813590506106818161065d565b92915050565b5f819050919050565b61069981610687565b81146106a3575f5ffd5b50565b5f813590506106b481610690565b92915050565b5f5f5f5f608085870312156106d2576106d1610590565b5b5f6106df87828801610673565b94505060206106f0878288016106a6565b9350506040610701878288016105b3565b9250506060610712878288016105b3565b91505092959194509250565b61072781610687565b82525050565b61073681610594565b82525050565b5f60408201905061074f5f83018561071e565b61075c602083018461072d565b9392505050565b5f82825260208201905092915050565b7f45524332303a206465706f73697445726332302066726f6d20746865207a65725f8201527f6f20616464726573730000000000000000000000000000000000000000000000602082015250565b5f6107cd602983610763565b91506107d882610773565b604082019050919050565b5f6020820190508181035f8301526107fa816107c1565b9050919050565b5f6060820190506108145f830186610635565b6108216020830185610635565b61082e604083018461071e565b949350505050565b5f8115159050919050565b61084a81610836565b8114610854575f5ffd5b50565b5f8151905061086581610841565b92915050565b5f602082840312156108805761087f610590565b5b5f61088d84828501610857565b91505092915050565b5f81519050919050565b5f81905092915050565b8281835e5f83830152505050565b5f6108c282610896565b6108cc81856108a0565b93506108dc8185602086016108aa565b80840191505092915050565b5f6108f382846108b8565b91508190509291505056fea2646970667358221220263cd2fa0b93cbb3f839a2b0960aa616a17d29543bd751aa6f489399c0b0c9f364736f6c63430008230033
diff --git a/rs/ethereum/cketh/docs/deposit_from_cex_demo/artifacts/CkSweeper.bin.hex b/rs/ethereum/cketh/docs/deposit_from_cex_demo/artifacts/CkSweeper.bin.hex
new file mode 100644
index 000000000000..958df895a343
--- /dev/null
+++ b/rs/ethereum/cketh/docs/deposit_from_cex_demo/artifacts/CkSweeper.bin.hex
@@ -0,0 +1 @@
+0x60a060405234801561000f575f5ffd5b50604051610b58380380610b58833981810160405281019061003191906100c9565b8073ffffffffffffffffffffffffffffffffffffffff1660808173ffffffffffffffffffffffffffffffffffffffff1681525050506100f4565b5f5ffd5b5f73ffffffffffffffffffffffffffffffffffffffff82169050919050565b5f6100988261006f565b9050919050565b6100a88161008e565b81146100b2575f5ffd5b50565b5f815190506100c38161009f565b92915050565b5f602082840312156100de576100dd61006b565b5b5f6100eb848285016100b5565b91505092915050565b608051610a456101135f395f818161019101526103270152610a455ff3fe608060405234801561000f575f5ffd5b506004361061003f575f3560e01c806302c8012c146100435780639ac844141461005f578063f5d1ea2414610069575b5f5ffd5b61005d600480360381019061005891906104fb565b610085565b005b610067610182565b005b610083600480360381019061007e9190610546565b61025b565b005b5f5f90505b8282905081101561017d575f8383838181106100a9576100a86105c4565b5b90506020020160208101906100be919061064b565b73ffffffffffffffffffffffffffffffffffffffff166370a08231306040518263ffffffff1660e01b81526004016100f69190610685565b602060405180830381865afa158015610111573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061013591906106d1565b90505f81111561017157610170848484818110610155576101546105c4565b5b905060200201602081019061016a919061064b565b8261030c565b5b5080600101905061008a565b505050565b5f4790505f811115610258575f7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16826040516101d390610729565b5f6040518083038185875af1925050503d805f811461020d576040519150601f19603f3d011682016040523d82523d5f602084013e610212565b606091505b5050905080610256576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161024d90610797565b60405180910390fd5b505b50565b5f5f90505b848490508110156103055784848281811061027e5761027d6105c4565b5b9050602002016020810190610293919061064b565b73ffffffffffffffffffffffffffffffffffffffff166302c8012c84846040518363ffffffff1660e01b81526004016102cd929190610871565b5f604051808303815f87803b1580156102e4575f5ffd5b505af11580156102f6573d5f5f3e3d5ffd5b50505050806001019050610260565b5050505050565b5f5f8373ffffffffffffffffffffffffffffffffffffffff167f0000000000000000000000000000000000000000000000000000000000000000846040516024016103589291906108c2565b6040516020818303038152906040527fa9059cbb000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff83818316178352505050506040516103e29190610931565b5f604051808303815f865af19150503d805f811461041b576040519150601f19603f3d011682016040523d82523d5f602084013e610420565b606091505b509150915081801561044d57505f8151148061044c57508080602001905181019061044b919061097c565b5b5b61048c576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610483906109f1565b60405180910390fd5b50505050565b5f5ffd5b5f5ffd5b5f5ffd5b5f5ffd5b5f5ffd5b5f5f83601f8401126104bb576104ba61049a565b5b8235905067ffffffffffffffff8111156104d8576104d761049e565b5b6020830191508360208202830111156104f4576104f36104a2565b5b9250929050565b5f5f6020838503121561051157610510610492565b5b5f83013567ffffffffffffffff81111561052e5761052d610496565b5b61053a858286016104a6565b92509250509250929050565b5f5f5f5f6040858703121561055e5761055d610492565b5b5f85013567ffffffffffffffff81111561057b5761057a610496565b5b610587878288016104a6565b9450945050602085013567ffffffffffffffff8111156105aa576105a9610496565b5b6105b6878288016104a6565b925092505092959194509250565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b5f73ffffffffffffffffffffffffffffffffffffffff82169050919050565b5f61061a826105f1565b9050919050565b61062a81610610565b8114610634575f5ffd5b50565b5f8135905061064581610621565b92915050565b5f602082840312156106605761065f610492565b5b5f61066d84828501610637565b91505092915050565b61067f81610610565b82525050565b5f6020820190506106985f830184610676565b92915050565b5f819050919050565b6106b08161069e565b81146106ba575f5ffd5b50565b5f815190506106cb816106a7565b92915050565b5f602082840312156106e6576106e5610492565b5b5f6106f3848285016106bd565b91505092915050565b5f81905092915050565b50565b5f6107145f836106fc565b915061071f82610706565b5f82019050919050565b5f61073382610709565b9150819050919050565b5f82825260208201905092915050565b7f455448207377656570206661696c6564000000000000000000000000000000005f82015250565b5f61078160108361073d565b915061078c8261074d565b602082019050919050565b5f6020820190508181035f8301526107ae81610775565b9050919050565b5f82825260208201905092915050565b5f819050919050565b6107d781610610565b82525050565b5f6107e883836107ce565b60208301905092915050565b5f6108026020840184610637565b905092915050565b5f602082019050919050565b5f61082183856107b5565b935061082c826107c5565b805f5b858110156108645761084182846107f4565b61084b88826107dd565b97506108568361080a565b92505060018101905061082f565b5085925050509392505050565b5f6020820190508181035f83015261088a818486610816565b90509392505050565b5f61089d826105f1565b9050919050565b6108ad81610893565b82525050565b6108bc8161069e565b82525050565b5f6040820190506108d55f8301856108a4565b6108e260208301846108b3565b9392505050565b5f81519050919050565b8281835e5f83830152505050565b5f61090b826108e9565b61091581856106fc565b93506109258185602086016108f3565b80840191505092915050565b5f61093c8284610901565b915081905092915050565b5f8115159050919050565b61095b81610947565b8114610965575f5ffd5b50565b5f8151905061097681610952565b92915050565b5f6020828403121561099157610990610492565b5b5f61099e84828501610968565b91505092915050565b7f746f6b656e207377656570206661696c656400000000000000000000000000005f82015250565b5f6109db60128361073d565b91506109e6826109a7565b602082019050919050565b5f6020820190508181035f830152610a08816109cf565b905091905056fea26469706673582212203a28b8c14da8f13f437e7f491eec771d15bcb5cc8d07181297088fb510f4460564736f6c63430008230033
diff --git a/rs/ethereum/cketh/docs/deposit_from_cex_demo/artifacts/CkSweeperViaHelper.bin.hex b/rs/ethereum/cketh/docs/deposit_from_cex_demo/artifacts/CkSweeperViaHelper.bin.hex
new file mode 100644
index 000000000000..646b414a65d8
--- /dev/null
+++ b/rs/ethereum/cketh/docs/deposit_from_cex_demo/artifacts/CkSweeperViaHelper.bin.hex
@@ -0,0 +1 @@
+0x60e060405234801561000f575f5ffd5b50604051610f4d380380610f4d83398181016040528101906100319190610132565b8173ffffffffffffffffffffffffffffffffffffffff1660808173ffffffffffffffffffffffffffffffffffffffff16815250508073ffffffffffffffffffffffffffffffffffffffff1660a08173ffffffffffffffffffffffffffffffffffffffff16815250503073ffffffffffffffffffffffffffffffffffffffff1660c08173ffffffffffffffffffffffffffffffffffffffff16815250505050610170565b5f5ffd5b5f73ffffffffffffffffffffffffffffffffffffffff82169050919050565b5f610101826100d8565b9050919050565b610111816100f7565b811461011b575f5ffd5b50565b5f8151905061012c81610108565b92915050565b5f5f60408385031215610148576101476100d4565b5b5f6101558582860161011e565b92505060206101668582860161011e565b9150509250929050565b60805160a05160c051610da66101a75f395f61029901525f818161040d015261043401525f8181607201526102440152610da65ff3fe608060405234801561000f575f5ffd5b5060043610610034575f3560e01c80635373f03314610038578063dfff6b1d14610054575b5f5ffd5b610052600480360381019061004d919061071e565b610070565b005b61006e60048036038101906100699190610835565b610242565b005b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16146100fe576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016100f590610900565b60405180910390fd5b858590508888905014801561011857508383905086869050145b610157576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161014e90610968565b60405180910390fd5b5f5f90505b888890508110156102375788888281811061017a57610179610986565b5b905060200201602081019061018f9190610a0d565b73ffffffffffffffffffffffffffffffffffffffff1663dfff6b1d84848a8a868181106101bf576101be610986565b5b905060200201358989878181106101d9576101d8610986565b5b905060200201356040518563ffffffff1660e01b81526004016101ff9493929190610b03565b5f604051808303815f87803b158015610216575f5ffd5b505af1158015610228573d5f5f3e3d5ffd5b5050505080600101905061015c565b505050505050505050565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614806102e757507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16145b610326576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161031d90610900565b60405180910390fd5b5f5f90505b848490508110156104f2575f85858381811061034a57610349610986565b5b905060200201602081019061035f9190610a0d565b73ffffffffffffffffffffffffffffffffffffffff166370a08231306040518263ffffffff1660e01b81526004016103979190610b50565b602060405180830381865afa1580156103b2573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906103d69190610b9c565b90505f8111156104e6576104328686848181106103f6576103f5610986565b5b905060200201602081019061040b9190610a0d565b7f0000000000000000000000000000000000000000000000000000000000000000836104f9565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663db9751af87878581811061048157610480610986565b5b90506020020160208101906104969190610a0d565b8387876040518563ffffffff1660e01b81526004016104b89493929190610bd6565b5f604051808303815f87803b1580156104cf575f5ffd5b505af11580156104e1573d5f5f3e3d5ffd5b505050505b5080600101905061032b565b5050505050565b5f5f8473ffffffffffffffffffffffffffffffffffffffff168484604051602401610525929190610c19565b6040516020818303038152906040527f095ea7b3000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff83818316178352505050506040516105af9190610c92565b5f604051808303815f865af19150503d805f81146105e8576040519150601f19603f3d011682016040523d82523d5f602084013e6105ed565b606091505b509150915081801561061a57505f815114806106195750808060200190518101906106189190610cdd565b5b5b610659576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161065090610d52565b60405180910390fd5b5050505050565b5f5ffd5b5f5ffd5b5f5ffd5b5f5ffd5b5f5ffd5b5f5f83601f84011261068957610688610668565b5b8235905067ffffffffffffffff8111156106a6576106a561066c565b5b6020830191508360208202830111156106c2576106c1610670565b5b9250929050565b5f5f83601f8401126106de576106dd610668565b5b8235905067ffffffffffffffff8111156106fb576106fa61066c565b5b60208301915083602082028301111561071757610716610670565b5b9250929050565b5f5f5f5f5f5f5f5f6080898b03121561073a57610739610660565b5b5f89013567ffffffffffffffff81111561075757610756610664565b5b6107638b828c01610674565b9850985050602089013567ffffffffffffffff81111561078657610785610664565b5b6107928b828c016106c9565b9650965050604089013567ffffffffffffffff8111156107b5576107b4610664565b5b6107c18b828c016106c9565b9450945050606089013567ffffffffffffffff8111156107e4576107e3610664565b5b6107f08b828c01610674565b92509250509295985092959890939650565b5f819050919050565b61081481610802565b811461081e575f5ffd5b50565b5f8135905061082f8161080b565b92915050565b5f5f5f5f6060858703121561084d5761084c610660565b5b5f85013567ffffffffffffffff81111561086a57610869610664565b5b61087687828801610674565b9450945050602061088987828801610821565b925050604061089a87828801610821565b91505092959194509250565b5f82825260208201905092915050565b7f63616c6c6572206973206e6f7420746865206d696e74657200000000000000005f82015250565b5f6108ea6018836108a6565b91506108f5826108b6565b602082019050919050565b5f6020820190508181035f830152610917816108de565b9050919050565b7f6c656e677468206d69736d6174636800000000000000000000000000000000005f82015250565b5f610952600f836108a6565b915061095d8261091e565b602082019050919050565b5f6020820190508181035f83015261097f81610946565b9050919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b5f73ffffffffffffffffffffffffffffffffffffffff82169050919050565b5f6109dc826109b3565b9050919050565b6109ec816109d2565b81146109f6575f5ffd5b50565b5f81359050610a07816109e3565b92915050565b5f60208284031215610a2257610a21610660565b5b5f610a2f848285016109f9565b91505092915050565b5f82825260208201905092915050565b5f819050919050565b610a5a816109d2565b82525050565b5f610a6b8383610a51565b60208301905092915050565b5f610a8560208401846109f9565b905092915050565b5f602082019050919050565b5f610aa48385610a38565b9350610aaf82610a48565b805f5b85811015610ae757610ac48284610a77565b610ace8882610a60565b9750610ad983610a8d565b925050600181019050610ab2565b5085925050509392505050565b610afd81610802565b82525050565b5f6060820190508181035f830152610b1c818688610a99565b9050610b2b6020830185610af4565b610b386040830184610af4565b95945050505050565b610b4a816109d2565b82525050565b5f602082019050610b635f830184610b41565b92915050565b5f819050919050565b610b7b81610b69565b8114610b85575f5ffd5b50565b5f81519050610b9681610b72565b92915050565b5f60208284031215610bb157610bb0610660565b5b5f610bbe84828501610b88565b91505092915050565b610bd081610b69565b82525050565b5f608082019050610be95f830187610b41565b610bf66020830186610bc7565b610c036040830185610af4565b610c106060830184610af4565b95945050505050565b5f604082019050610c2c5f830185610b41565b610c396020830184610bc7565b9392505050565b5f81519050919050565b5f81905092915050565b8281835e5f83830152505050565b5f610c6c82610c40565b610c768185610c4a565b9350610c86818560208601610c54565b80840191505092915050565b5f610c9d8284610c62565b915081905092915050565b5f8115159050919050565b610cbc81610ca8565b8114610cc6575f5ffd5b50565b5f81519050610cd781610cb3565b92915050565b5f60208284031215610cf257610cf1610660565b5b5f610cff84828501610cc9565b91505092915050565b7f617070726f7665206661696c65640000000000000000000000000000000000005f82015250565b5f610d3c600e836108a6565b9150610d4782610d08565b602082019050919050565b5f6020820190508181035f830152610d6981610d30565b905091905056fea2646970667358221220f85b472306107bdf2ff8076ead503d7e2ee0413f08df91d7aceae4d76e586d5d64736f6c63430008230033
diff --git a/rs/ethereum/cketh/docs/deposit_from_cex_demo/artifacts/MockUSDT.bin.hex b/rs/ethereum/cketh/docs/deposit_from_cex_demo/artifacts/MockUSDT.bin.hex
new file mode 100644
index 000000000000..d38e6581cf1a
--- /dev/null
+++ b/rs/ethereum/cketh/docs/deposit_from_cex_demo/artifacts/MockUSDT.bin.hex
@@ -0,0 +1 @@
+0x60a060405234801561000f575f5ffd5b50604051610f06380380610f0683398181016040528101906100319190610177565b805f5f8473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f208190555080608081815250508173ffffffffffffffffffffffffffffffffffffffff165f73ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef836040516100d791906101c4565b60405180910390a350506101dd565b5f5ffd5b5f73ffffffffffffffffffffffffffffffffffffffff82169050919050565b5f610113826100ea565b9050919050565b61012381610109565b811461012d575f5ffd5b50565b5f8151905061013e8161011a565b92915050565b5f819050919050565b61015681610144565b8114610160575f5ffd5b50565b5f815190506101718161014d565b92915050565b5f5f6040838503121561018d5761018c6100e6565b5b5f61019a85828601610130565b92505060206101ab85828601610163565b9150509250929050565b6101be81610144565b82525050565b5f6020820190506101d75f8301846101b5565b92915050565b608051610d116101f55f395f6103a60152610d115ff3fe608060405234801561000f575f5ffd5b5060043610610091575f3560e01c8063313ce56711610064578063313ce5671461010957806370a082311461012757806395d89b4114610157578063a9059cbb14610175578063dd62ed3e1461019157610091565b806306fdde0314610095578063095ea7b3146100b357806318160ddd146100cf57806323b872dd146100ed575b5f5ffd5b61009d6101c1565b6040516100aa919061090c565b60405180910390f35b6100cd60048036038101906100c891906109bd565b6101fa565b005b6100d76103a4565b6040516100e49190610a0a565b60405180910390f35b61010760048036038101906101029190610a23565b6103c8565b005b61011161069e565b60405161011e9190610a8e565b60405180910390f35b610141600480360381019061013c9190610aa7565b6106a3565b60405161014e9190610a0a565b60405180910390f35b61015f6106b7565b60405161016c919061090c565b60405180910390f35b61018f600480360381019061018a91906109bd565b6106f0565b005b6101ab60048036038101906101a69190610ad2565b61087c565b6040516101b89190610a0a565b60405180910390f35b6040518060400160405280600f81526020017f4d6f636b2054657468657220555344000000000000000000000000000000000081525081565b5f81148061027f57505f60015f3373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f8473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f2054145b6102be576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016102b590610b5a565b60405180910390fd5b8060015f3373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f8473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f20819055508173ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925836040516103989190610a0a565b60405180910390a35050565b7f000000000000000000000000000000000000000000000000000000000000000081565b8060015f8573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f3373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f20541015610483576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161047a90610bc2565b60405180910390fd5b805f5f8573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f20541015610502576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016104f990610c2a565b60405180910390fd5b8060015f8573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f3373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f8282546105899190610c75565b92505081905550805f5f8573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f8282546105db9190610c75565b92505081905550805f5f8473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f82825461062d9190610ca8565b925050819055508173ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef836040516106919190610a0a565b60405180910390a3505050565b600681565b5f602052805f5260405f205f915090505481565b6040518060400160405280600481526020017f555344540000000000000000000000000000000000000000000000000000000081525081565b805f5f3373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f2054101561076f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161076690610c2a565b60405180910390fd5b805f5f3373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f8282546107ba9190610c75565b92505081905550805f5f8473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f82825461080c9190610ca8565b925050819055508173ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef836040516108709190610a0a565b60405180910390a35050565b6001602052815f5260405f20602052805f5260405f205f91509150505481565b5f81519050919050565b5f82825260208201905092915050565b8281835e5f83830152505050565b5f601f19601f8301169050919050565b5f6108de8261089c565b6108e881856108a6565b93506108f88185602086016108b6565b610901816108c4565b840191505092915050565b5f6020820190508181035f83015261092481846108d4565b905092915050565b5f5ffd5b5f73ffffffffffffffffffffffffffffffffffffffff82169050919050565b5f61095982610930565b9050919050565b6109698161094f565b8114610973575f5ffd5b50565b5f8135905061098481610960565b92915050565b5f819050919050565b61099c8161098a565b81146109a6575f5ffd5b50565b5f813590506109b781610993565b92915050565b5f5f604083850312156109d3576109d261092c565b5b5f6109e085828601610976565b92505060206109f1858286016109a9565b9150509250929050565b610a048161098a565b82525050565b5f602082019050610a1d5f8301846109fb565b92915050565b5f5f5f60608486031215610a3a57610a3961092c565b5b5f610a4786828701610976565b9350506020610a5886828701610976565b9250506040610a69868287016109a9565b9150509250925092565b5f60ff82169050919050565b610a8881610a73565b82525050565b5f602082019050610aa15f830184610a7f565b92915050565b5f60208284031215610abc57610abb61092c565b5b5f610ac984828501610976565b91505092915050565b5f5f60408385031215610ae857610ae761092c565b5b5f610af585828601610976565b9250506020610b0685828601610976565b9150509250929050565b7f726573657420616c6c6f77616e636520746f20302066697273740000000000005f82015250565b5f610b44601a836108a6565b9150610b4f82610b10565b602082019050919050565b5f6020820190508181035f830152610b7181610b38565b9050919050565b7f696e73756666696369656e7420616c6c6f77616e6365000000000000000000005f82015250565b5f610bac6016836108a6565b9150610bb782610b78565b602082019050919050565b5f6020820190508181035f830152610bd981610ba0565b9050919050565b7f696e73756666696369656e742062616c616e63650000000000000000000000005f82015250565b5f610c146014836108a6565b9150610c1f82610be0565b602082019050919050565b5f6020820190508181035f830152610c4181610c08565b9050919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b5f610c7f8261098a565b9150610c8a8361098a565b9250828203905081811115610ca257610ca1610c48565b5b92915050565b5f610cb28261098a565b9150610cbd8361098a565b9250828201905080821115610cd557610cd4610c48565b5b9291505056fea264697066735822122062325128908826748d8550bd08c25a9c48f69baf2faaa5381c6ea50e3e8c888a64736f6c63430008230033
diff --git a/rs/ethereum/cketh/docs/deposit_from_cex_demo/contracts/CkSweeper.sol b/rs/ethereum/cketh/docs/deposit_from_cex_demo/contracts/CkSweeper.sol
new file mode 100644
index 000000000000..8f0c781985c1
--- /dev/null
+++ b/rs/ethereum/cketh/docs/deposit_from_cex_demo/contracts/CkSweeper.sol
@@ -0,0 +1,49 @@
+// SPDX-License-Identifier: Apache-2.0
+pragma solidity ^0.8.20;
+
+interface IERC20View {
+ function balanceOf(address account) external view returns (uint256);
+}
+
+/// EIP-7702 delegate for minter-controlled deposit addresses.
+/// Stateless on purpose: a 7702 delegate executes in the EOA's storage context.
+/// Sweep functions are callable by anyone since funds can only move to MINTER.
+contract CkSweeper {
+ address payable private immutable MINTER;
+
+ constructor(address minter) {
+ MINTER = payable(minter);
+ }
+
+ function sweepErc20(address[] calldata tokens) external {
+ for (uint256 i = 0; i < tokens.length; ++i) {
+ uint256 balance = IERC20View(tokens[i]).balanceOf(address(this));
+ if (balance > 0) {
+ _safeTransfer(tokens[i], balance);
+ }
+ }
+ }
+
+ /// Batch entry point: the deployed CkSweeper instance doubles as the
+ /// batcher, sweeping many delegated deposit EOAs in a single transaction.
+ function sweepErc20Batch(address[] calldata depositAddresses, address[] calldata tokens) external {
+ for (uint256 i = 0; i < depositAddresses.length; ++i) {
+ CkSweeper(depositAddresses[i]).sweepErc20(tokens);
+ }
+ }
+
+ function sweepEth() external {
+ uint256 balance = address(this).balance;
+ if (balance > 0) {
+ (bool ok,) = MINTER.call{value: balance}("");
+ require(ok, "ETH sweep failed");
+ }
+ }
+
+ /// Tolerates non-standard ERC-20s such as USDT whose transfer returns no value.
+ function _safeTransfer(address token, uint256 value) private {
+ (bool ok, bytes memory data) =
+ token.call(abi.encodeWithSignature("transfer(address,uint256)", MINTER, value));
+ require(ok && (data.length == 0 || abi.decode(data, (bool))), "token sweep failed");
+ }
+}
diff --git a/rs/ethereum/cketh/docs/deposit_from_cex_demo/contracts/CkSweeperViaHelper.sol b/rs/ethereum/cketh/docs/deposit_from_cex_demo/contracts/CkSweeperViaHelper.sol
new file mode 100644
index 000000000000..0ff91092b461
--- /dev/null
+++ b/rs/ethereum/cketh/docs/deposit_from_cex_demo/contracts/CkSweeperViaHelper.sol
@@ -0,0 +1,66 @@
+// SPDX-License-Identifier: Apache-2.0
+pragma solidity ^0.8.20;
+
+interface ICkDeposit {
+ function depositErc20(address erc20Address, uint256 amount, bytes32 principal, bytes32 subaccount) external;
+}
+
+interface IErc20Balance {
+ function balanceOf(address account) external view returns (uint256);
+}
+
+/// EIP-7702 delegate variant that sweeps by calling the existing ckETH helper
+/// contract (CkDeposit, see minter/DepositHelperWithSubaccount.sol), so that
+/// the sweep emits the canonical ReceivedEthOrErc20 event consumed by the
+/// minter's unchanged deposit pipeline.
+/// The IC principal/subaccount are caller-supplied, so sweeping MUST NOT be
+/// permissionless (anyone could credit deposits to their own principal):
+/// only the minter, directly or through the batch entry point of the deployed
+/// instance (SELF), may sweep.
+contract CkSweeperViaHelper {
+ address private immutable MINTER;
+ address private immutable HELPER;
+ address private immutable SELF;
+
+ constructor(address minter, address helper) {
+ MINTER = minter;
+ HELPER = helper;
+ SELF = address(this);
+ }
+
+ function sweepErc20(address[] calldata tokens, bytes32 principal, bytes32 subaccount) external {
+ require(msg.sender == MINTER || msg.sender == SELF, "caller is not the minter");
+ for (uint256 i = 0; i < tokens.length; ++i) {
+ uint256 balance = IErc20Balance(tokens[i]).balanceOf(address(this));
+ if (balance > 0) {
+ _safeApprove(tokens[i], HELPER, balance);
+ ICkDeposit(HELPER).depositErc20(tokens[i], balance, principal, subaccount);
+ }
+ }
+ }
+
+ /// Batch entry point on the deployed instance: sweeps many delegated
+ /// deposit EOAs in a single transaction, each towards its own IC account.
+ function sweepErc20Batch(
+ address[] calldata depositAddresses,
+ bytes32[] calldata principals,
+ bytes32[] calldata subaccounts,
+ address[] calldata tokens
+ ) external {
+ require(msg.sender == MINTER, "caller is not the minter");
+ require(
+ depositAddresses.length == principals.length && principals.length == subaccounts.length,
+ "length mismatch"
+ );
+ for (uint256 i = 0; i < depositAddresses.length; ++i) {
+ CkSweeperViaHelper(depositAddresses[i]).sweepErc20(tokens, principals[i], subaccounts[i]);
+ }
+ }
+
+ /// Tolerates non-standard ERC-20s such as USDT whose approve returns no value.
+ function _safeApprove(address token, address spender, uint256 value) private {
+ (bool ok, bytes memory data) =
+ token.call(abi.encodeWithSignature("approve(address,uint256)", spender, value));
+ require(ok && (data.length == 0 || abi.decode(data, (bool))), "approve failed");
+ }
+}
diff --git a/rs/ethereum/cketh/docs/deposit_from_cex_demo/contracts/MockUSDT.sol b/rs/ethereum/cketh/docs/deposit_from_cex_demo/contracts/MockUSDT.sol
new file mode 100644
index 000000000000..627241d86258
--- /dev/null
+++ b/rs/ethereum/cketh/docs/deposit_from_cex_demo/contracts/MockUSDT.sol
@@ -0,0 +1,44 @@
+// SPDX-License-Identifier: Apache-2.0
+pragma solidity ^0.8.20;
+
+/// Mimics USDT's non-standard ERC-20: `transfer`, `approve` and `transferFrom`
+/// return no value, and `approve` requires resetting the allowance to zero first.
+contract MockUSDT {
+ string public constant name = "Mock Tether USD";
+ string public constant symbol = "USDT";
+ uint8 public constant decimals = 6;
+ uint256 public immutable totalSupply;
+ mapping(address => uint256) public balanceOf;
+ mapping(address => mapping(address => uint256)) public allowance;
+
+ event Transfer(address indexed from, address indexed to, uint256 value);
+ event Approval(address indexed owner, address indexed spender, uint256 value);
+
+ constructor(address initialHolder, uint256 initialSupply) {
+ balanceOf[initialHolder] = initialSupply;
+ totalSupply = initialSupply;
+ emit Transfer(address(0), initialHolder, initialSupply);
+ }
+
+ function transfer(address to, uint256 value) external {
+ require(balanceOf[msg.sender] >= value, "insufficient balance");
+ balanceOf[msg.sender] -= value;
+ balanceOf[to] += value;
+ emit Transfer(msg.sender, to, value);
+ }
+
+ function approve(address spender, uint256 value) external {
+ require(value == 0 || allowance[msg.sender][spender] == 0, "reset allowance to 0 first");
+ allowance[msg.sender][spender] = value;
+ emit Approval(msg.sender, spender, value);
+ }
+
+ function transferFrom(address from, address to, uint256 value) external {
+ require(allowance[from][msg.sender] >= value, "insufficient allowance");
+ require(balanceOf[from] >= value, "insufficient balance");
+ allowance[from][msg.sender] -= value;
+ balanceOf[from] -= value;
+ balanceOf[to] += value;
+ emit Transfer(from, to, value);
+ }
+}
diff --git a/rs/ethereum/cketh/docs/deposit_from_cex_demo/foundry.toml b/rs/ethereum/cketh/docs/deposit_from_cex_demo/foundry.toml
new file mode 100644
index 000000000000..399aa456c414
--- /dev/null
+++ b/rs/ethereum/cketh/docs/deposit_from_cex_demo/foundry.toml
@@ -0,0 +1,5 @@
+[profile.default]
+src = "contracts"
+out = "out"
+cache_path = "cache"
+evm_version = "prague"
diff --git a/rs/ethereum/cketh/docs/deposit_from_cex_demo/src/main.rs b/rs/ethereum/cketh/docs/deposit_from_cex_demo/src/main.rs
new file mode 100644
index 000000000000..b33eeba44d98
--- /dev/null
+++ b/rs/ethereum/cketh/docs/deposit_from_cex_demo/src/main.rs
@@ -0,0 +1,689 @@
+//! Demo of the "deposit from CEX" flow designed in ../deposit_from_cex.md,
+//! with the minter simulated by a plain EOA controlling a family of EOAs
+//! (stand-in for threshold ECDSA key derivation on the IC).
+//!
+//! 0) minter EOA + CEX hot-wallet EOA; CkSweeper delegate and a USDT-like
+//! ERC-20 are deployed.
+//! 1) the minter derives user-specific deposit addresses.
+//! 2) those addresses are unfunded: 0 ETH, 0 USDT, no code.
+//! 3) users withdraw USDT from the CEX: plain ERC-20 transfers to the
+//! deposit addresses (the CEX pays that gas).
+//! 4) the minter sweeps a deposit address in ONE type-0x04 (EIP-7702)
+//! transaction: authorization signed by the deposit EOA + call to
+//! sweepErc20, gas paid by the minter (variant A: direct sweep).
+//! 5) batched sweep: ONE transaction targets several deposit EOAs at once
+//! via CkSweeper.sweepErc20Batch, their authorizations riding in the same
+//! transaction's authorization list.
+//! 6) variant B setup: the REAL helper contract (CkDeposit, compiled from
+//! minter/DepositHelperWithSubaccount.sol) and the CkSweeperViaHelper
+//! delegate are deployed; the CEX sends a second round of deposits.
+//! 7) variant B sweeps: the deposit EOAs are re-delegated (new
+//! authorizations) to CkSweeperViaHelper, which sweeps by calling the
+//! helper's depositErc20, so each sweep emits the canonical
+//! ReceivedEthOrErc20 event (with the right IC principal) that the
+//! minter's existing deposit pipeline already scrapes and mints from.
+//! 8) attack: someone other than the minter tries to sweep (passing their
+//! own principal) and is rejected; the deposit is then swept correctly.
+//!
+//! Requires a dev node supporting EIP-7702 (Ethereum mainnet since the Pectra
+//! upgrade, May 2025), e.g.
+//! anvil
+//! or, without foundry installed:
+//! docker run --rm -p 8545:8545 ghcr.io/foundry-rs/foundry:v1.7.1 \
+//! "anvil --host 0.0.0.0"
+
+use alloy::{
+ consensus::{Transaction, TxEnvelope},
+ eips::{eip2718::Encodable2718, eip7702::Authorization, eip7702::SignedAuthorization},
+ network::{EthereumWallet, TransactionBuilder, TransactionBuilder7702},
+ primitives::{Address, FixedBytes, U256, keccak256},
+ providers::{DynProvider, Provider, ProviderBuilder},
+ rpc::types::{TransactionReceipt, TransactionRequest},
+ signers::{SignerSync, local::PrivateKeySigner},
+ sol,
+ sol_types::{SolCall, SolConstructor, SolEvent},
+};
+use anyhow::{Context, Result, ensure};
+use candid::Principal;
+
+sol! {
+ #[sol(rpc)]
+ contract CkSweeper {
+ constructor(address minter);
+ function sweepErc20(address[] calldata tokens) external;
+ function sweepErc20Batch(address[] calldata depositAddresses, address[] calldata tokens) external;
+ }
+
+ #[sol(rpc)]
+ contract CkSweeperViaHelper {
+ constructor(address minter, address helper);
+ function sweepErc20(address[] calldata tokens, bytes32 principal, bytes32 subaccount) external;
+ function sweepErc20Batch(address[] calldata depositAddresses, bytes32[] calldata principals, bytes32[] calldata subaccounts, address[] calldata tokens) external;
+ }
+
+ /// The existing ckETH helper smart contract
+ /// (minter/DepositHelperWithSubaccount.sol).
+ #[sol(rpc)]
+ contract CkDeposit {
+ constructor(address _minterAddress);
+ function getMinterAddress() public view returns (address);
+ event ReceivedEthOrErc20(
+ address indexed erc20ContractAddress,
+ address indexed owner,
+ uint256 amount,
+ bytes32 indexed principal,
+ bytes32 subaccount
+ );
+ }
+
+ #[sol(rpc)]
+ contract MockUSDT {
+ constructor(address initialHolder, uint256 initialSupply);
+ function balanceOf(address account) external view returns (uint256);
+ function transfer(address to, uint256 value) external;
+ event Transfer(address indexed from, address indexed to, uint256 value);
+ }
+}
+
+const CKSWEEPER_BYTECODE: &str = include_str!("../artifacts/CkSweeper.bin.hex");
+const CKSWEEPER_VIA_HELPER_BYTECODE: &str = include_str!("../artifacts/CkSweeperViaHelper.bin.hex");
+const CKDEPOSIT_BYTECODE: &str = include_str!("../artifacts/CkDeposit.bin.hex");
+const MOCKUSDT_BYTECODE: &str = include_str!("../artifacts/MockUSDT.bin.hex");
+
+// Anvil's first three well-known dev accounts.
+const MINTER_PRIVATE_KEY: &str =
+ "0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80";
+const CEX_PRIVATE_KEY: &str = "0x59c6995e998f97a5a0044966f0945389dc9e86dae88c7a8412f4603b6b78690d";
+const ATTACKER_PRIVATE_KEY: &str =
+ "0x5de4111afa1a4b94908f83103eb1f1706367c2e68ca870fc3fb9a804cdab365a";
+
+const USDT_SUPPLY: u64 = 1_000_000_000_000; // 1M USDT (6 decimals)
+
+// The demo is fully deterministic (fixed keys, fixed contracts, fresh chain),
+// so the gas used by each sweep transaction is a constant.
+const SINGLE_SWEEP_GAS_USED: u64 = 66_854;
+const BATCH_SWEEP_GAS_USED: u64 = 118_876;
+const SINGLE_SWEEP_VIA_HELPER_GAS_USED: u64 = 82_207;
+const BATCH_SWEEP_VIA_HELPER_GAS_USED: u64 = 164_746;
+
+fn step(title: &str) {
+ println!("\n== {title}");
+}
+
+fn show(label: &str, value: impl std::fmt::Display) {
+ println!(" {label:<46} {value}");
+}
+
+fn ok(what: &str) {
+ println!(" OK: {what}");
+}
+
+/// Demo stand-in for threshold ECDSA derivation: the "minter master key"
+/// deterministically derives one child key per IC account. On the IC the
+/// private key never exists anywhere; sign_with_ecdsa produces the signatures.
+fn derive_deposit_signer(principal: &str) -> PrivateKeySigner {
+ let seed = keccak256(format!(
+ "cketh-deposit-address|{MINTER_PRIVATE_KEY}|{principal}"
+ ));
+ PrivateKeySigner::from_bytes(&seed).expect("valid derived key")
+}
+
+/// Encodes an IC principal as the bytes32 expected by the helper contract:
+/// byte 0 is the principal length, followed by the principal bytes.
+fn encode_principal(principal_text: &str) -> FixedBytes<32> {
+ let principal = Principal::from_text(principal_text).expect("valid principal");
+ let bytes = principal.as_slice();
+ let mut encoded = [0u8; 32];
+ encoded[0] = bytes.len() as u8;
+ encoded[1..=bytes.len()].copy_from_slice(bytes);
+ FixedBytes::from(encoded)
+}
+
+/// Fills chain id, nonce, fees and gas, then signs with the given wallet,
+/// without sending. An explicit gas limit skips estimation (needed for
+/// transactions that are expected to revert).
+async fn fill_and_sign(
+ provider: &DynProvider,
+ wallet: &EthereumWallet,
+ from: Address,
+ tx: TransactionRequest,
+ gas_limit: Option,
+) -> Result {
+ let fees = provider.estimate_eip1559_fees().await?;
+ let mut tx = tx
+ .with_from(from)
+ .with_chain_id(provider.get_chain_id().await?)
+ .with_nonce(provider.get_transaction_count(from).await?)
+ .with_max_fee_per_gas(fees.max_fee_per_gas)
+ .with_max_priority_fee_per_gas(fees.max_priority_fee_per_gas);
+ let gas_limit = match gas_limit {
+ Some(gas_limit) => gas_limit,
+ None => provider.estimate_gas(tx.clone()).await?,
+ };
+ tx = tx.with_gas_limit(gas_limit);
+ Ok(tx.build(wallet).await?)
+}
+
+async fn deploy(
+ provider: &DynProvider,
+ wallet: &EthereumWallet,
+ deployer: &str,
+ deployer_address: Address,
+ bytecode_hex: &str,
+ constructor_args: Vec,
+) -> Result {
+ let mut code = hex::decode(bytecode_hex.trim().trim_start_matches("0x"))?;
+ code.extend(constructor_args);
+ let envelope = fill_and_sign(
+ provider,
+ wallet,
+ deployer_address,
+ TransactionRequest::default().with_deploy_code(code),
+ None,
+ )
+ .await?;
+ show(&format!("{deployer} nonce (deploy):"), envelope.nonce());
+ let receipt = provider
+ .send_tx_envelope(envelope)
+ .await?
+ .get_receipt()
+ .await?;
+ receipt.contract_address.context("no contract address")
+}
+
+fn sign_delegation(
+ deposit_signer: &PrivateKeySigner,
+ sweeper: Address,
+ chain_id: u64,
+ nonce: u64,
+) -> Result {
+ let authorization = Authorization {
+ chain_id: U256::from(chain_id),
+ address: sweeper,
+ nonce,
+ };
+ let signature = deposit_signer.sign_hash_sync(&authorization.signature_hash())?;
+ Ok(authorization.into_signed(signature))
+}
+
+/// Signs a sweep transaction with the minter's wallet, prints it in full
+/// (including the minter's nonce and the raw signed transaction hex), sends it
+/// and prints the resulting receipt.
+async fn send_and_print_sweep_transaction(
+ minter_provider: &DynProvider,
+ minter_wallet: &EthereumWallet,
+ minter: Address,
+ tx: TransactionRequest,
+ authorizations: &[SignedAuthorization],
+) -> Result {
+ let envelope = fill_and_sign(minter_provider, minter_wallet, minter, tx, None).await?;
+ show("minter nonce (sweep):", envelope.nonce());
+ show(
+ "raw signed transaction:",
+ alloy::hex::encode_prefixed(envelope.encoded_2718()),
+ );
+ let receipt = minter_provider
+ .send_tx_envelope(envelope)
+ .await?
+ .get_receipt()
+ .await?;
+
+ show("transaction hash:", receipt.transaction_hash);
+ let transaction_type = receipt.transaction_type() as u8;
+ show(
+ "transaction type:",
+ format!(
+ "{transaction_type}{}",
+ match transaction_type {
+ 4 => " (EIP-7702 SetCode)",
+ 2 => " (EIP-1559, no authorization needed anymore)",
+ _ => "",
+ }
+ ),
+ );
+ show("from (pays gas):", receipt.from);
+ show("to:", receipt.to.expect("call, not create"));
+ show("gas used:", receipt.gas_used);
+ show(
+ "effective gas price:",
+ format!("{} wei", receipt.effective_gas_price),
+ );
+ for auth in authorizations {
+ show(
+ "authorization:",
+ format!(
+ "EOA {} -> delegate {} (nonce {})",
+ auth.recover_authority().expect("valid signature"),
+ auth.address,
+ auth.nonce
+ ),
+ );
+ }
+ for log in receipt.logs() {
+ if let Ok(transfer) = MockUSDT::Transfer::decode_log(&log.inner) {
+ show(
+ "Transfer event:",
+ format!(
+ "{} -> {}: {} USDT",
+ transfer.from,
+ transfer.to,
+ transfer.value / U256::from(1_000_000)
+ ),
+ );
+ }
+ if let Ok(received) = CkDeposit::ReceivedEthOrErc20::decode_log(&log.inner) {
+ show(
+ "ReceivedEthOrErc20 event:",
+ format!(
+ "token {}, owner {}, amount {}, principal {}, subaccount {}",
+ received.erc20ContractAddress,
+ received.owner,
+ received.amount / U256::from(1_000_000),
+ received.principal,
+ received.subaccount
+ ),
+ );
+ }
+ }
+ Ok(receipt)
+}
+
+#[tokio::main]
+async fn main() -> Result<()> {
+ let rpc_url =
+ std::env::var("ETH_RPC_URL").unwrap_or_else(|_| "http://127.0.0.1:8545".to_string());
+
+ let minter_signer: PrivateKeySigner = MINTER_PRIVATE_KEY.parse()?;
+ let cex_signer: PrivateKeySigner = CEX_PRIVATE_KEY.parse()?;
+ let minter = minter_signer.address();
+ let cex = cex_signer.address();
+ // The minter and the CEX are unrelated parties: two separate wallets.
+ let minter_wallet = EthereumWallet::from(minter_signer);
+ let cex_wallet = EthereumWallet::from(cex_signer);
+ let minter_provider = ProviderBuilder::new()
+ .wallet(minter_wallet.clone())
+ .connect_http(rpc_url.parse()?)
+ .erased();
+ let cex_provider = ProviderBuilder::new()
+ .wallet(cex_wallet.clone())
+ .connect_http(rpc_url.parse()?)
+ .erased();
+ let chain_id = minter_provider.get_chain_id().await?;
+
+ step("0) Setup: minter EOA, CEX hot wallet, contracts");
+ let sweeper_address = deploy(
+ &minter_provider,
+ &minter_wallet,
+ "minter",
+ minter,
+ CKSWEEPER_BYTECODE,
+ CkSweeper::constructorCall { minter }.abi_encode(),
+ )
+ .await?;
+ let usdt_address = deploy(
+ &cex_provider,
+ &cex_wallet,
+ "CEX",
+ cex,
+ MOCKUSDT_BYTECODE,
+ MockUSDT::constructorCall {
+ initialHolder: cex,
+ initialSupply: U256::from(USDT_SUPPLY),
+ }
+ .abi_encode(),
+ )
+ .await?;
+ let usdt = MockUSDT::new(usdt_address, minter_provider.clone());
+ let usdt_as_cex = MockUSDT::new(usdt_address, cex_provider.clone());
+ show("minter (EOA, pays all sweep gas):", minter);
+ show("CEX hot wallet (EOA):", cex);
+ show("CkSweeper delegate + batcher:", sweeper_address);
+ show("MockUSDT (USDT-style ERC-20, 6 decimals):", usdt_address);
+
+ step("1) Minter derives user-specific deposit addresses");
+ let principals: Vec = (0u8..4)
+ .map(|i| Principal::self_authenticating([i]).to_text())
+ .collect();
+ let deposit_signers: Vec = principals
+ .iter()
+ .map(|p| derive_deposit_signer(p))
+ .collect();
+ let deposit_addresses: Vec = deposit_signers.iter().map(|s| s.address()).collect();
+ for (principal, address) in principals.iter().zip(&deposit_addresses) {
+ show(&format!("{}...:", &principal[..20]), address);
+ }
+
+ step("2) Deposit addresses are unfunded: no ETH, no token, no code");
+ for address in &deposit_addresses {
+ ensure!(minter_provider.get_balance(*address).await?.is_zero());
+ ensure!(usdt.balanceOf(*address).call().await?.is_zero());
+ ensure!(minter_provider.get_code_at(*address).await?.is_empty());
+ }
+ ok("every deposit address has 0 ETH, 0 USDT and no code");
+
+ step("3) Users withdraw USDT from the CEX (plain ERC-20 transfers)");
+ let amounts: [u64; 4] = [250_000_000, 100_000_000, 75_000_000, 50_000_000];
+ for (address, amount) in deposit_addresses.iter().zip(amounts) {
+ usdt_as_cex
+ .transfer(*address, U256::from(amount))
+ .send()
+ .await?
+ .get_receipt()
+ .await?;
+ show(
+ &format!("CEX -> {address}:"),
+ format!("{} USDT", amount / 1_000_000),
+ );
+ }
+ for address in &deposit_addresses {
+ ensure!(minter_provider.get_balance(*address).await?.is_zero());
+ }
+ ok("deposit addresses still have 0 ETH (cannot pay gas themselves)");
+
+ step("4) Variant A: minter sweeps ONE deposit address in ONE EIP-7702 transaction");
+ let single_authorization = sign_delegation(&deposit_signers[0], sweeper_address, chain_id, 0)?;
+ let single_sweep = TransactionRequest::default()
+ .with_to(deposit_addresses[0])
+ .with_input(
+ CkSweeper::sweepErc20Call {
+ tokens: vec![usdt_address],
+ }
+ .abi_encode(),
+ )
+ .with_authorization_list(vec![single_authorization.clone()]);
+ let single_receipt = send_and_print_sweep_transaction(
+ &minter_provider,
+ &minter_wallet,
+ minter,
+ single_sweep,
+ &[single_authorization],
+ )
+ .await?;
+
+ ensure!(single_receipt.status(), "single sweep reverted");
+ ensure!(usdt.balanceOf(deposit_addresses[0]).call().await?.is_zero());
+ ensure!(usdt.balanceOf(minter).call().await? == U256::from(amounts[0]));
+ ok("250 USDT swept to the minter; deposit address needed 0 ETH throughout");
+ let single_gas = single_receipt.gas_used;
+ ensure!(
+ single_gas == SINGLE_SWEEP_GAS_USED,
+ "unexpected single-sweep gas: {single_gas}, expected {SINGLE_SWEEP_GAS_USED}"
+ );
+ ok(&format!(
+ "gas used is exactly {SINGLE_SWEEP_GAS_USED} \
+ (21000 base + 25000 authorization + ~21000 delegated ERC-20 sweep)"
+ ));
+
+ step("5) Variant A batched: ONE transaction targets the 3 remaining deposit EOAs");
+ let batch_authorizations: Vec = deposit_signers[1..]
+ .iter()
+ .map(|signer| sign_delegation(signer, sweeper_address, chain_id, 0))
+ .collect::>()?;
+ let batch_targets = deposit_addresses[1..].to_vec();
+ let batch_sweep = TransactionRequest::default()
+ .with_to(sweeper_address)
+ .with_input(
+ CkSweeper::sweepErc20BatchCall {
+ depositAddresses: batch_targets.clone(),
+ tokens: vec![usdt_address],
+ }
+ .abi_encode(),
+ )
+ .with_authorization_list(batch_authorizations.clone());
+ let batch_receipt = send_and_print_sweep_transaction(
+ &minter_provider,
+ &minter_wallet,
+ minter,
+ batch_sweep,
+ &batch_authorizations,
+ )
+ .await?;
+
+ ensure!(batch_receipt.status(), "batched sweep reverted");
+ for address in &batch_targets {
+ ensure!(usdt.balanceOf(*address).call().await?.is_zero());
+ }
+ let expected_total: u64 = amounts.iter().sum();
+ ensure!(usdt.balanceOf(minter).call().await? == U256::from(expected_total));
+ ok("all deposit addresses swept; minter now holds all 475 USDT");
+
+ let batch_gas = batch_receipt.gas_used;
+ ensure!(
+ batch_gas == BATCH_SWEEP_GAS_USED,
+ "unexpected batch-sweep gas: {batch_gas}, expected {BATCH_SWEEP_GAS_USED}"
+ );
+ let marginal = (batch_gas - single_gas) / 2;
+ ok(&format!(
+ "gas used is exactly {BATCH_SWEEP_GAS_USED} for 3 EOAs < 3 x {single_gas} \
+ (3 separate sweeps); ~{marginal} gas per additional EOA"
+ ));
+
+ step("6) Variant B setup: the existing helper contract and its sweeper delegate");
+ let helper_address = deploy(
+ &minter_provider,
+ &minter_wallet,
+ "minter",
+ minter,
+ CKDEPOSIT_BYTECODE,
+ CkDeposit::constructorCall {
+ _minterAddress: minter,
+ }
+ .abi_encode(),
+ )
+ .await?;
+ let via_helper_address = deploy(
+ &minter_provider,
+ &minter_wallet,
+ "minter",
+ minter,
+ CKSWEEPER_VIA_HELPER_BYTECODE,
+ CkSweeperViaHelper::constructorCall {
+ minter,
+ helper: helper_address,
+ }
+ .abi_encode(),
+ )
+ .await?;
+ let helper = CkDeposit::new(helper_address, minter_provider.clone());
+ ensure!(helper.getMinterAddress().call().await? == minter);
+ show(
+ "CkDeposit helper (DepositHelperWithSubaccount):",
+ helper_address,
+ );
+ show("CkSweeperViaHelper delegate + batcher:", via_helper_address);
+ let amounts_b: [u64; 4] = [150_000_000, 80_000_000, 60_000_000, 40_000_000];
+ for (address, amount) in deposit_addresses.iter().zip(amounts_b) {
+ usdt_as_cex
+ .transfer(*address, U256::from(amount))
+ .send()
+ .await?
+ .get_receipt()
+ .await?;
+ show(
+ &format!("CEX -> {address}:"),
+ format!("{} USDT", amount / 1_000_000),
+ );
+ }
+
+ step("7) Variant B: sweeps go through the helper, emitting ReceivedEthOrErc20");
+ // Each deposit EOA re-delegates to CkSweeperViaHelper: the applied variant-A
+ // authorization incremented its nonce to 1.
+ let re_delegation = sign_delegation(&deposit_signers[0], via_helper_address, chain_id, 1)?;
+ let via_helper_sweep = TransactionRequest::default()
+ .with_to(deposit_addresses[0])
+ .with_input(
+ CkSweeperViaHelper::sweepErc20Call {
+ tokens: vec![usdt_address],
+ principal: encode_principal(&principals[0]),
+ subaccount: FixedBytes::ZERO,
+ }
+ .abi_encode(),
+ )
+ .with_authorization_list(vec![re_delegation.clone()]);
+ let via_helper_receipt = send_and_print_sweep_transaction(
+ &minter_provider,
+ &minter_wallet,
+ minter,
+ via_helper_sweep,
+ &[re_delegation],
+ )
+ .await?;
+
+ ensure!(via_helper_receipt.status(), "sweep via helper reverted");
+ ensure!(usdt.balanceOf(deposit_addresses[0]).call().await?.is_zero());
+ let received = via_helper_receipt
+ .logs()
+ .iter()
+ .find_map(|log| CkDeposit::ReceivedEthOrErc20::decode_log(&log.inner).ok())
+ .context("no ReceivedEthOrErc20 event")?;
+ ensure!(received.address == helper_address);
+ ensure!(received.erc20ContractAddress == usdt_address);
+ ensure!(received.owner == deposit_addresses[0]);
+ ensure!(received.amount == U256::from(amounts_b[0]));
+ ensure!(received.principal == encode_principal(&principals[0]));
+ ensure!(received.subaccount == FixedBytes::ZERO);
+ ok(
+ "the sweep emitted the canonical ReceivedEthOrErc20 event from the helper, \
+ carrying the right IC principal: the minter's existing deposit pipeline \
+ scrapes and mints from it unchanged",
+ );
+ let via_helper_gas = via_helper_receipt.gas_used;
+ ensure!(
+ via_helper_gas == SINGLE_SWEEP_VIA_HELPER_GAS_USED,
+ "unexpected sweep-via-helper gas: {via_helper_gas}, \
+ expected {SINGLE_SWEEP_VIA_HELPER_GAS_USED}"
+ );
+ ok(&format!(
+ "gas used is exactly {SINGLE_SWEEP_VIA_HELPER_GAS_USED} \
+ (+{} vs the direct sweep: approve + transferFrom + event)",
+ SINGLE_SWEEP_VIA_HELPER_GAS_USED - SINGLE_SWEEP_GAS_USED
+ ));
+
+ // Batched variant B: re-delegate the 3 remaining EOAs in one transaction;
+ // EOAs 1 and 2 are swept, EOA 3 is only re-delegated (swept in step 8).
+ let re_delegations: Vec = deposit_signers[1..]
+ .iter()
+ .map(|signer| sign_delegation(signer, via_helper_address, chain_id, 1))
+ .collect::>()?;
+ let via_helper_batch = TransactionRequest::default()
+ .with_to(via_helper_address)
+ .with_input(
+ CkSweeperViaHelper::sweepErc20BatchCall {
+ depositAddresses: deposit_addresses[1..3].to_vec(),
+ principals: principals[1..3]
+ .iter()
+ .map(|p| encode_principal(p))
+ .collect(),
+ subaccounts: vec![FixedBytes::ZERO; 2],
+ tokens: vec![usdt_address],
+ }
+ .abi_encode(),
+ )
+ .with_authorization_list(re_delegations.clone());
+ let via_helper_batch_receipt = send_and_print_sweep_transaction(
+ &minter_provider,
+ &minter_wallet,
+ minter,
+ via_helper_batch,
+ &re_delegations,
+ )
+ .await?;
+ ensure!(
+ via_helper_batch_receipt.status(),
+ "batched sweep via helper reverted"
+ );
+ let received_events: Vec<_> = via_helper_batch_receipt
+ .logs()
+ .iter()
+ .filter_map(|log| CkDeposit::ReceivedEthOrErc20::decode_log(&log.inner).ok())
+ .collect();
+ ensure!(received_events.len() == 2);
+ for (i, event) in received_events.iter().enumerate() {
+ ensure!(event.owner == deposit_addresses[i + 1]);
+ ensure!(event.principal == encode_principal(&principals[i + 1]));
+ }
+ let via_helper_batch_gas = via_helper_batch_receipt.gas_used;
+ ensure!(
+ via_helper_batch_gas == BATCH_SWEEP_VIA_HELPER_GAS_USED,
+ "unexpected batched sweep-via-helper gas: {via_helper_batch_gas}, \
+ expected {BATCH_SWEEP_VIA_HELPER_GAS_USED}"
+ );
+ ok(&format!(
+ "batched sweep through the helper: 2 canonical deposit events, \
+ gas used is exactly {BATCH_SWEEP_VIA_HELPER_GAS_USED} \
+ (incl. the deferred re-delegation of the 4th deposit address)"
+ ));
+
+ step("8) Attack: someone other than the minter tries to sweep");
+ // Deposit EOA 3 is already delegated to CkSweeperViaHelper (step 7) but not
+ // yet swept: it still holds 40 USDT. The attacker tries to credit that
+ // deposit to their own IC principal.
+ let attacker_signer: PrivateKeySigner = ATTACKER_PRIVATE_KEY.parse()?;
+ let attacker = attacker_signer.address();
+ let attacker_wallet = EthereumWallet::from(attacker_signer);
+ let attacker_provider = ProviderBuilder::new()
+ .wallet(attacker_wallet.clone())
+ .connect_http(rpc_url.parse()?)
+ .erased();
+ let attacker_principal = "2vxsx-fae";
+ show("attacker (EOA):", attacker);
+ let attack = TransactionRequest::default()
+ .with_to(deposit_addresses[3])
+ .with_input(
+ CkSweeperViaHelper::sweepErc20Call {
+ tokens: vec![usdt_address],
+ principal: encode_principal(attacker_principal),
+ subaccount: FixedBytes::ZERO,
+ }
+ .abi_encode(),
+ );
+ // Gas estimation would already fail with "caller is not the minter", so the
+ // attacker forces an explicit gas limit to get the transaction on chain.
+ let attack_envelope = fill_and_sign(
+ &attacker_provider,
+ &attacker_wallet,
+ attacker,
+ attack,
+ Some(300_000),
+ )
+ .await?;
+ let attack_receipt = attacker_provider
+ .send_tx_envelope(attack_envelope)
+ .await?
+ .get_receipt()
+ .await?;
+ ensure!(
+ !attack_receipt.status(),
+ "attacker's sweep should have reverted"
+ );
+ ensure!(usdt.balanceOf(deposit_addresses[3]).call().await? == U256::from(amounts_b[3]));
+ ok("the attacker's sweep reverted (caller is not the minter); funds untouched");
+
+ // The minter sweeps it correctly: the delegation is already installed, so no
+ // authorization is needed anymore.
+ let final_sweep = TransactionRequest::default()
+ .with_to(deposit_addresses[3])
+ .with_input(
+ CkSweeperViaHelper::sweepErc20Call {
+ tokens: vec![usdt_address],
+ principal: encode_principal(&principals[3]),
+ subaccount: FixedBytes::ZERO,
+ }
+ .abi_encode(),
+ );
+ let final_receipt = send_and_print_sweep_transaction(
+ &minter_provider,
+ &minter_wallet,
+ minter,
+ final_sweep,
+ &[],
+ )
+ .await?;
+ ensure!(final_receipt.status(), "final sweep reverted");
+ let grand_total: u64 = amounts.iter().sum::() + amounts_b.iter().sum::();
+ ensure!(usdt.balanceOf(minter).call().await? == U256::from(grand_total));
+ ok("the minter swept it with the right principal; it now holds all 805 USDT");
+
+ println!("\nDemo completed successfully.");
+ Ok(())
+}