Hey, was reading through zero-contracts and noticed a gap in the circuit breaker. _resetWindowIfExpired fully resets releasedInWindow to 0 the moment the 24h window expires, rather than using a rolling window. So a release just before expiry and another right after reset land in two separate windows even if they're minutes apart in wall-clock time. That means 2-of-3 guardians (the normal-tier threshold) could release up to ~40% of reserves back to back by straddling the boundary, and all 3 could reach 100%, without the "auto-revert above 50%" tier ever triggering, since each call only checks its own window's running total.
A rolling window (or requiring the reset to only zero out amounts older than 24h rather than the whole counter) would close this. Is the tumbling window intentional given resetWindowIfExpired is cheaper to compute, or worth tightening given this is exactly the scenario (partially compromised guardian set) the tiered structure exists to bound?
Clean bridge design otherwise, tiered signature requirements tied to release size are a sensible way to scale trust to risk, and the asymmetric pause (any guardian can pause, only the timelock can unpause) is the right shape for that tradeoff.
I work through similar rate-limit-window edge cases on invariant tests for a cross-chain vault on Chainlink CCIP (https://github.com/aegonmyy/meridian), tumbling-vs-rolling windows are a really easy thing to get subtly wrong. Happy to talk through it if useful.
Hey, was reading through zero-contracts and noticed a gap in the circuit breaker. _resetWindowIfExpired fully resets releasedInWindow to 0 the moment the 24h window expires, rather than using a rolling window. So a release just before expiry and another right after reset land in two separate windows even if they're minutes apart in wall-clock time. That means 2-of-3 guardians (the normal-tier threshold) could release up to ~40% of reserves back to back by straddling the boundary, and all 3 could reach 100%, without the "auto-revert above 50%" tier ever triggering, since each call only checks its own window's running total.
A rolling window (or requiring the reset to only zero out amounts older than 24h rather than the whole counter) would close this. Is the tumbling window intentional given resetWindowIfExpired is cheaper to compute, or worth tightening given this is exactly the scenario (partially compromised guardian set) the tiered structure exists to bound?
Clean bridge design otherwise, tiered signature requirements tied to release size are a sensible way to scale trust to risk, and the asymmetric pause (any guardian can pause, only the timelock can unpause) is the right shape for that tradeoff.
I work through similar rate-limit-window edge cases on invariant tests for a cross-chain vault on Chainlink CCIP (https://github.com/aegonmyy/meridian), tumbling-vs-rolling windows are a really easy thing to get subtly wrong. Happy to talk through it if useful.