Repository navigation
feat(minter): automatic deposit flow - #274
gregorydemay wants to merge 163 commits into
Conversation
Replace the outdated section 3.1.1, which described per-transaction crediting with getSignaturesForAddress and quotas replenished by the removed process_deposit endpoint, with a design that builds on the balance sweep of deposit_sol: a free registration endpoint, a scan timer reading watched deposit addresses in batches with getMultipleAccounts, a schedule adapted from the ckETH minter, a fixed fee in SOL deducted from the minted amount, and a watchlist persisted only as a bounded snapshot at pre_upgrade. Every change to the interface, the arguments and the event log is additive, since the minter is deployed on mainnet. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
State that a re-armed account is reported as watching again, that the main account receives the sweepable amount minus the fee share, correct the worst-case cost arithmetic and state its success assumption, and distinguish a failed upgrade from a reinstallation. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…ring Move the sequence diagram of the automatic flow ahead of its explanation, remove the semicolon that broke the mermaid parser on GitHub, and define the deposit id where it is first used in the section. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…he constraint State that scan ticks are guarded like the other timers so that they never overlap, and base the automatic deposit fee constraint on the single-signature fee share that a pending mint actually bears. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Drop the separate status query: calling the registration endpoint again returns the stored registration or the id of the deposit in flight, as deposit_eth does in the ckETH minter. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
… signature lookup Spell out that scan ticks never overlap, that the fee derivation is a single-attempt estimate with re-arm costs absorbed by the minter, and that only manual deposits are retried by the caller. Remove getSignaturesForAddress from the RPC inventory and cost tables, since the minter no longer uses it. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
A re-armed entry restarts its schedule from the first gap, bounded by the remaining window, and a re-arm only ever follows a detection. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Record the watchlist snapshot on every upgrade so that an older one cannot be replayed after the watchlist emptied, and let the transaction submission section account for deposits queued by the balance scan. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The window ends with the last scan, and the next registration call starts a new window rather than reporting a registration without a next scan. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…it ids Follow the ckETH minter: a registration freezes neither the minimum deposit amount nor the automatic deposit fee, both are quoted and the values in force at detection apply, the fee being recorded with the queued deposit. deposit_sol compares the latest deposit id of the account before and after its balance read, and a registration is allowed while a deposit_sol call is in progress. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…edule Measure gaps from the previous scan as before, but end the window at a fixed 24 hours after registration, as the ckETH minter does, so that the accumulated tick and call delays have slack and clients and the re-arm share one unambiguous boundary. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…ence Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…owner rationale The fee recorded at detection matters for deposits an upgrade finds not yet credited; a credited deposit has its mint amount in CreditedSweep. The minter's principal is excluded as a deposit owner because its default account is the ledger's minting account, not because of an address collision. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
8e2c061 to
dd0421b
Compare
There was a problem hiding this comment.
🟡 Changes recommended
Raw provider responses cannot reliably reach consensus on mainnet, causing scans to fail and retry indefinitely.
1 open finding
What changed in this PR
Adds automatic SOL deposit detection through an expiring watchlist, scheduled balance scans, and automatic deposit fees.
Changes:
- Adds the watch endpoint, scan timer, batching, concurrency handling, and upgrade persistence.
- Tracks automatic fees, deposit history, metrics, and dashboard data.
- Extends Candid types and comprehensive unit/integration coverage.
| File | Description |
|---|---|
minter/templates/dashboard.html |
Displays automatic-deposit data. |
minter/src/utils/timed_sized_map/tests.rs |
Tests the bounded TTL map. |
minter/src/utils/timed_sized_map/mod.rs |
Implements the bounded TTL map. |
minter/src/utils/mod.rs |
Exports the new map module. |
minter/src/test_fixtures/runtime.rs |
Improves inter-canister call simulation. |
minter/src/test_fixtures/mod.rs |
Adds automatic-deposit fixtures. |
minter/src/test_fixtures/flow/deposit.rs |
Supports automatic deposit test flows. |
minter/src/storage/mod.rs |
Tracks scan outcomes. |
minter/src/state/watchlist/tests.rs |
Tests watchlist behavior. |
minter/src/state/watchlist/mod.rs |
Implements watch registration and scheduling. |
minter/src/state/tests.rs |
Tests persistence, fees, and validation. |
minter/src/state/mod.rs |
Integrates watchlist and fee state. |
minter/src/state/event/candid/tests.rs |
Updates Candid event tests. |
minter/src/state/event/candid/mod.rs |
Converts new event types. |
minter/src/state/event.rs |
Adds automatic-deposit and snapshot events. |
minter/src/state/deposits/tests.rs |
Tests returned dropped deposits. |
minter/src/state/deposits/sweeps/tests.rs |
Tests automatic fee deductions. |
minter/src/state/deposits/sweeps/mod.rs |
Applies automatic fees to mints. |
minter/src/state/deposits/mod.rs |
Tracks automatic and latest deposits. |
minter/src/state/audit.rs |
Replays new state transitions. |
minter/src/rpc/tests.rs |
Tests batched balance RPC handling. |
minter/src/rpc/mod.rs |
Adds getMultipleAccounts support. |
minter/src/metrics.rs |
Exposes automatic-flow metrics. |
minter/src/main.rs |
Exposes endpoint and scan timer. |
minter/src/lifecycle/tests.rs |
Tests watchlist snapshots. |
minter/src/lifecycle.rs |
Persists watchlist before upgrades. |
minter/src/deposit/sweep/tests.rs |
Tests manual/automatic race handling. |
minter/src/deposit/sweep/mod.rs |
Shares deposit queueing logic. |
minter/src/deposit/mod.rs |
Exports the automatic flow. |
minter/src/deposit/automatic/tests.rs |
Tests watch endpoint behavior. |
minter/src/deposit/automatic/scan/tests.rs |
Tests scheduled balance scans. |
minter/src/deposit/automatic/scan/mod.rs |
Implements concurrent scans. |
minter/src/deposit/automatic/mod.rs |
Implements watch registration API. |
minter/src/dashboard/tests.rs |
Tests automatic-flow dashboard output. |
minter/src/dashboard/mod.rs |
Builds watchlist dashboard data. |
minter/src/cycles.rs |
Adds RPC-cost-only charging. |
minter/src/constants.rs |
Defines scan and RPC limits. |
minter/src/canbench.rs |
Updates benchmark fixtures. |
minter/cksol_minter.did |
Extends the public Candid interface. |
minter/Cargo.toml |
Promotes serde_json to runtime dependency. |
libs/types/src/lib.rs |
Adds public watch API types. |
libs/types-internal/src/lib.rs |
Adds fee configuration fields. |
libs/types-internal/src/event.rs |
Adds debug event types. |
integration_tests/tests/tests.rs |
Adds end-to-end watch-flow tests. |
integration_tests/tests/solana_test_validator.rs |
Tests mixed automatic/manual sweeping. |
integration_tests/src/lib.rs |
Adds integration client helpers. |
integration_tests/src/fixtures.rs |
Adds batched RPC mocks. |
🧠 Review effort: Balanced
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
…xample with the automatic flow Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
e25dd6b to
781f9fc
Compare
…matic-flow-metrics
The sum only grows, across upgrades too, since replaying the event log rebuilds it whole before the first query can read it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…oldest registration The age of the oldest registration stays within the window whether the scan timer runs or not, so no threshold separates a healthy minter from a broken one. A due scan that has not run yet ages only while the timer does not keep up, e.g. when a tick whose calls never return keeps its guard, which an alert then sees within minutes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
An alert on a filling watchlist can then compare the number of live registrations with the capacity in force instead of hard-coding it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…d after it ran Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
An expired registration stays in the watchlist until the next tick evicts it, and replaying an older snapshot can bring back a batch of them, none of which is watched any more. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…the next scan Times in nanoseconds can't be read at a glance; they are shown as on the dashboard of the ckETH minter. The next scan of each address shows when the scan timer is behind. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…t-snapshot # Conflicts: # docs/src/development/design.md # integration_tests/tests/tests.rs # minter/src/deposit/automatic/scan/mod.rs # minter/src/deposit/automatic/scan/tests.rs # minter/src/deposit/sweep/tests.rs # minter/src/state/event/candid/mod.rs # minter/src/state/tests.rs # minter/src/state/watchlist/mod.rs # minter/src/state/watchlist/tests.rs
… into DEFI-2780-12-automatic-flow-metrics
…ics' into DEFI-2780-automatic-deposit-flow-impl # Conflicts: # docs/src/development/design.md
There was a problem hiding this comment.
🔵 Needs a closer look
The integration test has a timer race that can fail its single-transaction assertion without a regression, and the documentation incorrectly implies automatic detection throughout the full 24-hour registration window.
8 open issues
Use current fee when validating and queueing deposits after await Prevent sweep timer from interleaving before deposits are queued Failed-read metric counts registrations no longer advanced Warn about mainnet RPC consensus limits and recommend deposit_sol Document mainnet RPC consensus limitation and manual deposit flow Qualify latest_deposit_id availability and successful response conditions Clarify finalization deadline before the last watch scan Disclose final-scan boundary in CLI watch guidance
Review effort: Balanced
…atched address The age of the oldest live registration is bounded by the watch window, so it was replaced by the scan lag as a metric and has no caller. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…bled Without a snapshot, the previous version would still mint the automatic deposits already queued without deducting their fee. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… into DEFI-2780-12-automatic-flow-metrics # Conflicts: # minter/src/state/watchlist/mod.rs # minter/src/state/watchlist/tests.rs
…sits A sweep that keeps failing re-arms its automatic deposits over and over, and a full watchlist leaves them to their users; both are visible only in the logs. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A dropped automatic deposit is re-armed while a dropped manual deposit waits for its user, so the two call for different follow-ups. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ics' into DEFI-2780-automatic-deposit-flow-impl
There was a problem hiding this comment.
🔵 Needs a closer look
The deposit instructions omit the final scan cutoff at 23.5 hours, so users can follow the stated 24-hour window yet remain uncredited without guidance to re-register after expiry or call deposit_sol.
8 open issues
Use current fee when validating and queueing deposits after await Prevent sweep timer from interleaving before deposits are queued Failed-read metric counts registrations no longer advanced Warn about mainnet RPC consensus limits and recommend deposit_sol Document mainnet RPC consensus limitation and manual deposit flow Qualify latest_deposit_id availability and successful response conditions Clarify finalization deadline before the last watch scan Disclose final-scan boundary in CLI watch guidance
Review effort: Balanced
…c-flow-metrics # Conflicts: # minter/src/state/watchlist/mod.rs # minter/src/state/watchlist/tests.rs
…ics' into DEFI-2780-automatic-deposit-flow-impl
…six columns Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…d collect the fee Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ics' into DEFI-2780-automatic-deposit-flow-impl
There was a problem hiding this comment.
🔵 Needs a closer look
The documentation implies deposits are detected throughout the 24-hour registration window, but scans stop at 23.5 hours; it must clarify that cutoff and explain re-registration after expiry or a manual deposit_sol call for missed deposits.
8 open issues
Use current fee when validating and queueing deposits after await Prevent sweep timer from interleaving before deposits are queued Failed-read metric counts registrations no longer advanced Warn about mainnet RPC consensus limits and recommend deposit_sol Document mainnet RPC consensus limitation and manual deposit flow Qualify latest_deposit_id availability and successful response conditions Clarify finalization deadline before the last watch scan Disclose final-scan boundary in CLI watch guidance
Review effort: Balanced
…between tests Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ics' into DEFI-2780-automatic-deposit-flow-impl
There was a problem hiding this comment.
🔵 Needs a closer look
The documentation omits the 23.5-hour final-scan cutoff, which can leave transfers within the stated 24-hour window uncredited, and needs to explain re-registering after expiry or using deposit_sol.
8 open issues
Use current fee when validating and queueing deposits after await Prevent sweep timer from interleaving before deposits are queued Failed-read metric counts registrations no longer advanced Warn about mainnet RPC consensus limits and recommend deposit_sol Document mainnet RPC consensus limitation and manual deposit flow Qualify latest_deposit_id availability and successful response conditions Clarify finalization deadline before the last watch scan Disclose final-scan boundary in CLI watch guidance
Review effort: Balanced
…ad advances A registration removed, replaced or expired while the read was in flight was counted, unlike after a successful read. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…t of the automatic flow Qualify when the id of the latest deposit is returned, list the user-visible changes of the stack in the changelogs, and enable the flow in a second upgrade. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>



Last pull request of the stack implementing the automatic deposit flow designed in #272, on top of #276 to #287 and #291, which add the flow piece by piece: the fee parameter, the watchlist and its schedule, the
watch_deposit_addressendpoint, the fee deduction, the batched balance reads, the scan timer, the re-arm of dropped sweeps, the watchlist snapshot on upgrade, the concurrency rule betweendeposit_soland the scan, the origin of a queued deposit, and the metrics.This one adds the end-to-end test on
solana-test-validator, in which two deposits detected by the scan timer and two queued withdeposit_solare swept in a single transaction, minted with and without the automatic deposit fee, and the collected fees are reported byget_minter_info. It also adds the user documentation of the flow, the changelog entries and the rollout in two upgrades: the flow stays disabled until a second upgrade sets the automatic deposit fee.🤖 Generated with Claude Code