feat(vault): optimistic minting exposure cap and per-minter rate limits - #1035
Draft
mswilkison wants to merge 6 commits into
Draft
feat(vault): optimistic minting exposure cap and per-minter rate limits#1035mswilkison wants to merge 6 commits into
mswilkison wants to merge 6 commits into
Conversation
Bound the worst-case TBTC issuance through the optimistic minting path ahead of re-enabling it. The primary control is a cap on outstanding optimistic minting exposure: the sum of debt not yet repaid by swept deposits (tracked globally as optimisticMintingDebtTotal) and the value of in-flight requests (optimisticMintingPendingTotal). Debt of deposits that never settle permanently consumes the cap, acting as an automatic circuit breaker; capacity recycles as deposits are swept. Complementary per-Minter limits are time-based: a rolling 24h value bucket and a request count bucket bounding Guardians' per-window validation workload, plus a per-deposit size limit routing large deposits through the standard sweep flow. Consumed per-Minter allowance is not restored on cancellation, so caught request bursts consume the requesting Minter's own capacity. All limits are governance-tunable via the existing two-step 24h-delay idiom; zero disables a limit. An internal virtual exemption hook lets derived vaults exempt requesters governed by separate, dedicated exposure limits. Applies to future TBTCVault deployments; the deployed vault is not upgradeable in place. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01AnrPAUEuN6uKDVeASMxb4M
|
Important Draft PR not reviewedDraft PRs are not automatically reviewed by default.
To automatically review draft PRs, update your CodeRabbit configuration: reviews:
auto_review:
drafts: true✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Set the initial defaults to a deliberately tight posture for the re-enablement period: 10 BTC debt cap, 10 BTC per-Minter 24h bucket, and 5 BTC per-deposit size limit (roughly the p95 of historical deposit sizes, and half the debt cap so a single deposit cannot monopolize the optimistic minting pipeline while it settles). Hitting a cap costs only latency, while raising one takes the 24-hour governance delay, so the intended operating posture is to start tight and ratchet up based on observed cap-utilization telemetry. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01AnrPAUEuN6uKDVeASMxb4M
- Delete the accidentally committed root pnpm-lock.yaml that broke the
prettier --check code-format gate (the repo uses yarn).
- Suppress two slither findings in TBTCOptimisticMinting with the repo's
established annotations:
- incorrect-equality on the refill sentinel checks (valueRefilledAt /
requestsRefilledAt == 0 detect a never-initialized timestamp, not a
manipulable balance equality).
- costly-loop on the optimisticMintingDebtTotal decrements in
repayOptimisticMintingDebt (called per-depositor from
receiveBalanceIncrease); the aggregate must be updated as debt is
repaid, matching the existing costly-loop suppression in this file.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AxCWMXfUdFygLaGaS2SPhg
Advance each refill checkpoint only by the time represented by credited whole tokens so partial accrual is retained. Use ceiling division to prevent the retained timestamp remainder from making tokens available early at non-divisible rates.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds native, governance-tunable limits to the optimistic minting path in
TBTCOptimisticMinting, bounding the worst-case TBTC issuance through optimistic minting. Optimistic minting is currently paused on mainnet; these controls are part of the hardening required before it can be re-enabled. They apply to future deployments ofTBTCVault— the currently deployed vault is not upgradeable in place.Today, a single compromised Minter key can request optimistic mints for the bridge's entire TVL, with Guardian cancellation as the only backstop during the
optimisticMintingDelaywindow. With these limits, the worst-case unauthorized issuance is bounded by the caps instead of being unbounded.Design
The primary control is a cap on outstanding optimistic minting exposure rather than a time-windowed rate: at any moment, the TBTC that could turn out to be unbacked is exactly the optimistic minting debt not yet repaid by swept deposits, plus the value of in-flight (requested, not yet finalized) mints. The contract now tracks both quantities globally (
optimisticMintingDebtTotal, mirroring the per-depositoroptimisticMintingDebtledger, andoptimisticMintingPendingTotal) and rejects requests that would push their sum above the cap.This shape has three properties a pure rate limit lacks:
Four limits, each disabled by setting it to zero:
optimisticMintingDebtCapoptimisticMintingCapPerMinteroptimisticMintingMaxDepositSizeoptimisticMintingRequestLimitPerMinterThe per-Minter limits stay time-based deliberately. Debt repayment reaches the vault as per-depositor amounts with no per-Minter attribution, so a per-Minter debt cap is not cleanly implementable — and a per-Minter rate limit is independently valuable because it bounds how much value can enter each
optimisticMintingDelaycancellation window, keeping the Guardians' verification workload bounded per window. Per-Minter caps are meant to overlap: their sum may exceed the debt cap, which remains the binding total.Other semantics worth noting:
Bridge.deposits().amount(satoshi), the same value optimistic minting is accountable for viaoptimisticMintingDebt._isOptimisticMintingThrottleExempt(address)is aninternal virtualhook (alwaysfalsehere) allowing derived vault implementations to exempt classes of requesters whose issuance is bounded by separate, dedicated exposure limits. Exempt requests bypass the checks but still count toward the measured totals; overriding contracts must account for that overlap.Defaults were derived from historical mainnet optimistic minting activity (typical outstanding exposure given observed daily volume and reveal-to-sweep settlement times, and the per-deposit size distribution) and are set deliberately conservative for the initial re-enablement: hitting a cap costs only latency (deposits fall back to the sweep flow) while raising one takes the 24-hour governance delay, so the intended posture is to start tight and ratchet up based on observed cap-utilization telemetry.
Governance
The four limits are updated together via the existing two-step idiom (
beginOptimisticMintingCapsUpdate/finalizeOptimisticMintingCapsUpdate) with the same 24-hourGOVERNANCE_DELAYused by the fee and delay updates, mirroring the Bridge's grouped-parameter governance.Monitoring
OptimisticMintingAllowanceConsumedis emitted on every request with the amount, the Minter's remaining bucket, and the remaining debt-cap headroom (sentineltype(uint64).maxwhen a limit is disabled) — cap-utilization alerts double as an anomaly detector for a misbehaving Minter.getOptimisticMintingAllowance(minter)returns live remaining allowances (including accrued bucket refill) for Minter clients and dashboards;optimisticMintingDebtTotalandoptimisticMintingPendingTotalare public for exposure monitoring.Testing
New suite
TBTCVault.OptimisticMintingCaps.test.ts(35 tests, self-contained against a mocked Bridge): defaults; all four limits; cross-minter bucket independence; the debt cap binding across Minters; cancellation releasing headroom while per-Minter allowance stays consumed; the full settle-and-recycle cycle (in-flight → outstanding debt on finalization → capacity recycled on repayment viareceiveBalanceIncrease); the cap lowered below current exposure clamping to zero headroom; continuous bucket refill and clamping; count-limit exhaustion and recovery; disabled-limit sentinels; finalization not double-consuming; governance update flow (authorization, delay, event, state reset); the enable-transition semantics (a limit enabled after being disabled starts every Minter from a full bucket, exercised with an exact-boundary request); fractional refill accrual for small request limits; and the exemption seam via a test stub, including exempt in-flight exposure still being measured.The pre-existing vault suites are unchanged; default limits sit far above the fixture deposit sizes, so their behavior is unaffected.
Compatibility
TBTCVaultis deployed fresh (the deployed instance cannot be upgraded in place), and these controls target the next vault deployment.requestOptimisticMintgains new revert paths (size cap, per-Minter limits, debt cap). Minter clients should consultgetOptimisticMintingAllowancebefore submitting.optimisticMintingDebtTotalmaintenance adds one storage write tofinalizeOptimisticMintand to debt-repayingreceiveBalanceIncreasecalls; behavior of finalization, cancellation, Minter/Guardian management, and the pause switch is otherwise unchanged.🤖 Generated with Claude Code
https://claude.ai/code/session_01AnrPAUEuN6uKDVeASMxb4M