Repository navigation
Add a vesting drip that batches due claims - #186
Conversation
A running drip submits every due schedule together so payouts stay at the minimum step without a separate extrinsic per claim. Co-authored-by: Cursor <cursoragent@cursor.com>
n13
left a comment
There was a problem hiding this comment.
Reviewer model: GPT-6.1 Sol
REQUEST_CHANGES — the drip must respect the runtime's minimum interval between claims.
[P1] Keep interval-locked schedules out of the due batch — src/cli/vesting.rs:691–701
VestingTerms drops schedule.last_claim_at, and both claimable and next_claim_ms consider only accrued amounts. The checked-in runtime metadata sets Vesting::MinClaimInterval to 86,400,000 ms (24 hours), and the pallet rejects earlier claims with ClaimTooSoon, including final payouts. For example, a 100 QTC schedule over four hours can pay its first 25 QTC at hour 1; this loop selects its next 25 QTC at hour 2, although the next permitted claim is hour 25. The transaction fails, batch_all rolls back every other claim in that batch, and the propagated error terminates the drip. Restarting during the cooldown selects the same failing schedule again.
Read MinClaimInterval, preserve last_claim_at, and use the later of the vesting boundary and last_claim_at + MinClaimInterval for both due selection and the next wake-up. Add coverage for an accrued-but-interval-locked schedule, including a final remainder and a batch containing another eligible schedule.
Reviewed head: d5748f342c6460514ed7b6a0bdc040b2389e997e.
Validation:
SKIP_CIRCUIT_BUILD=1 cargo test --lib cli::vesting::tests --locked: 9 passed.cargo +nightly-2026-08-31 fmt --all -- --checkandgit diff --check: passed.- Standalone probe using the PR's unchanged calculation functions reproduced the hour-2 selection during the 24-hour cooldown.
- GitHub format, dependency cooldown, and security audit checks passed; build/test, Clippy/docs, and examples were still pending. No live-chain transaction was submitted.
The chain no longer exposes MinClaimInterval or ClaimTooSoon, and the later vesting error indices shifted down by one. Co-authored-by: Cursor <cursoragent@cursor.com>
n13
left a comment
There was a problem hiding this comment.
Reviewer model: GPT-6.1 Sol
REQUEST_CHANGES — preserve Ctrl-C requests while a claim is in flight.
[P2] Keep the shutdown listener alive between idle waits — src/cli/vesting.rs:717–723
After the first idle sleep wins this select!, its ctrl_c() future is dropped, but Tokio's process-wide SIGINT handler remains installed. A Ctrl-C received during the subsequent RPC reads or submit_due_claims(...).await is therefore swallowed: there is no live listener, and the next idle iteration creates a new listener that only receives future signals. The drip continues after the transaction completes and can submit further fee-paying claims despite the stop request. Inclusion/finalization waits make this a substantial window, and repeated Ctrl-C during that window does not terminate the process either.
Keep a persistent shutdown listener/flag for the lifetime of the drip, including both the single-claim and batch paths. Latch a stop request while a transaction is in flight and exit before submitting another claim/batch. Add a regression that sends SIGINT after the initial idle wait, during a simulated submission, and verifies that the loop stops afterward.
The previous cooldown finding is resolved: chain PR #712 merged the removal of MinClaimInterval and ClaimTooSoon.
Reviewed head: 4f4640eb051c706f37c08cf0b7c92a6660f6b141 (base a74fd735fdb7cae2381b66dbaaa513630c0d58d9).
Validation:
SKIP_CIRCUIT_BUILD=1 cargo test --lib cli::vesting::tests --locked: 9 passed.cargo +nightly-2026-08-31 fmt --all -- --checkandgit diff --check: passed.- Standalone Tokio probe mirroring idle/select → simulated submission → idle/select reproduced the lost SIGINT; it continued into the next wait.
- GitHub format, dependency cooldown, security audit, and Clippy/docs checks passed; build/test and examples remained pending. No live-chain transaction was submitted.
A signal during submission is latched and the drip exits before the next claim or batch chunk. Co-authored-by: Cursor <cursoragent@cursor.com>
n13
left a comment
There was a problem hiding this comment.
Reviewer model: GPT-6.1 Sol
APPROVE — no blocking findings at 96495aea6ca70517a08c67e888b4f3d94903ac78 (base a74fd735fdb7cae2381b66dbaaa513630c0d58d9).
Reviewed the complete diff, payout/cliff/remainder calculations, beneficiary filtering, batching limits, and shared transaction submission paths. The previous findings are resolved: chain PR #712 removed the claim cooldown, and the persistent Ctrl-C listener now latches shutdown during RPC/submission and prevents subsequent claims or batch chunks.
Validation:
SKIP_CIRCUIT_BUILD=1 cargo test --lib cli::vesting::tests --locked: 11 passed, including actual SIGINT during submission and stopping between batch chunks.cargo +nightly-2026-08-31 fmt --all -- --checkandgit diff --check: passed.- GitHub format, dependency cooldown, security audit, and Clippy/docs checks passed. Both build/test jobs and examples remain in progress.
No live-chain transaction was submitted; end-to-end payout behavior remains unverified on a deployed node.
Summary
quantus vesting drip, which watches vesting schedules and claims each one as soon as the next non-final payout (25 QTC) has vested.utility.batch_all. A single due schedule stays a plainclaim. Batches split only when they exceedUtility::batched_calls_limit.Test plan
cargo test --lib cli::vesting::tests --lockedquantus vesting drip --from <wallet>against a chain with several schedules, and confirm multiple due claims land in one extrinsicvesting.claim, not a one-call batchMade with Cursor