fix(operator): wait out EVM period caps before withdraw execute #198

Open
PlasticDigits wants to merge 1 commit from issue/170 into main

Summary

  • Dest-approved EVM withdrawExecute* now waits until the TokenRegistry withdraw window ends on period-full, instead of retrying at WRITER_RPC_BACKOFF_MAX. RateLimitExceededPerPeriod stays retryable and is not stored as a terminal string.
  • Payouts below min or above maxPerTx / maxPerPeriod are not sent. Permanent caps use PermanentPerTxCapExceeded / PermanentPeriodCapExceeded (terminal). On-chain limits are unchanged and there is no execute bypass.
  • GuardBridge WithdrawRateLimitExceeded waits one full 24h window. In-flight execute timers are not reset when a pending row is still stored; scheduling a retry refreshes that row's cache TTL.

Fixes #170.

Acceptance

  • AC1. Execute still sends withdrawExecuteMint / withdrawExecuteUnlock after the cancel window when the payout fits the current window. A non-terminal limiter defers the send until the window ends.
  • AC2 / AC3 / AC7. Unchanged from #171: Hash Verification stays Pending while dest is Approved, names cancel remaining and GL-127 rate-limit banners, and becomes verified only after dest executed.
  • AC4. CancelWindowActive and period-full stay out of terminal_executions. Period-full retries at windowStart + RATE_LIMIT_WINDOW (or one full window if that read fails).
  • AC5. Below-min, cancelled, already-executed, and permanent over-max stay terminal. Enumeration does not reset a stored execute timer.
  • AC6. No TokenRateLimit / min / max change and no admin execute bypass.
  • AC8. #164 / #127 / #139 paths were not edited.

Validation

  • cargo test --bins writers:: — 49 passed (execute-queue period wait, permanent cap, terminal vs retryable, decimal normalize).
  • cargo test --bins bounded_cache:: — 7 passed (stored-row update refreshes TTL).
  • No live hash ids or operator logs in this PR.

Gaps

  • Live AC1/AC2 still need a dest payout at or above minPerTransaction after this binary is deployed. Below-min rows stay terminal on purpose. Redeploy and that live check remain on #172.
  • Guard over-max (amount above the guard limit) is retried after 24h rather than classified terminal, because that revert does not separate a full window from a permanent over-limit without another guard read.
  • The wait uses local unix time against the registry window. A clock that runs ahead can cause one period revert, which is then rescheduled; it does not drop the hash.

Invariants: docs/OPERATOR_WRITER_INVARIANTS.md (INV-OP-W11). Skill: skills/agent-operator-evm-writer-rpc.md.

## Summary - Dest-approved EVM `withdrawExecute*` now waits until the TokenRegistry withdraw window ends on period-full, instead of retrying at `WRITER_RPC_BACKOFF_MAX`. `RateLimitExceededPerPeriod` stays retryable and is not stored as a terminal string. - Payouts below min or above `maxPerTx` / `maxPerPeriod` are not sent. Permanent caps use `PermanentPerTxCapExceeded` / `PermanentPeriodCapExceeded` (terminal). On-chain limits are unchanged and there is no execute bypass. - GuardBridge `WithdrawRateLimitExceeded` waits one full 24h window. In-flight execute timers are not reset when a pending row is still stored; scheduling a retry refreshes that row's cache TTL. Fixes #170. ## Acceptance - AC1. Execute still sends `withdrawExecuteMint` / `withdrawExecuteUnlock` after the cancel window when the payout fits the current window. A non-terminal limiter defers the send until the window ends. - AC2 / AC3 / AC7. Unchanged from #171: Hash Verification stays Pending while dest is Approved, names cancel remaining and GL-127 rate-limit banners, and becomes verified only after dest executed. - AC4. `CancelWindowActive` and period-full stay out of `terminal_executions`. Period-full retries at `windowStart + RATE_LIMIT_WINDOW` (or one full window if that read fails). - AC5. Below-min, cancelled, already-executed, and permanent over-max stay terminal. Enumeration does not reset a stored execute timer. - AC6. No `TokenRateLimit` / min / max change and no admin execute bypass. - AC8. #164 / #127 / #139 paths were not edited. ## Validation - `cargo test --bins writers::` — 49 passed (execute-queue period wait, permanent cap, terminal vs retryable, decimal normalize). - `cargo test --bins bounded_cache::` — 7 passed (stored-row update refreshes TTL). - No live hash ids or operator logs in this PR. ## Gaps - Live AC1/AC2 still need a dest payout at or above `minPerTransaction` after this binary is deployed. Below-min rows stay terminal on purpose. Redeploy and that live check remain on #172. - Guard over-max (amount above the guard limit) is retried after 24h rather than classified terminal, because that revert does not separate a full window from a permanent over-limit without another guard read. - The wait uses local unix time against the registry window. A clock that runs ahead can cause one period revert, which is then rescheduled; it does not drop the hash. Invariants: `docs/OPERATOR_WRITER_INVARIANTS.md` (INV-OP-W11). Skill: `skills/agent-operator-evm-writer-rpc.md`.
fix(operator): wait out EVM period caps before withdraw execute
All checks were successful
ci/woodpecker/pr/woodpecker Pipeline was successful
ci/woodpecker/push/woodpecker Pipeline was successful
931fd0e20e
Dest-approved executes retried period-full on the short RPC backoff and still sent payouts that can never fit the cap. Hold those until the TokenRegistry window ends, and do not send permanent over-max amounts.
Author
Owner

drain skip: no occupying job for rebase/fix-pr/CI-wait; remaining continue

drain skip: no occupying job for rebase/fix-pr/CI-wait; remaining continue
Author
Owner

drain skip: default autoland requires tip ACCEPT (#77)

drain skip: default autoland requires tip ACCEPT (#77)
All checks were successful
ci/woodpecker/pr/woodpecker Pipeline was successful
Required
Details
ci/woodpecker/push/woodpecker Pipeline was successful
This pull request can be merged automatically.
You are not authorized to merge this pull request.
View command line instructions

Checkout

From your project repository, check out a new branch and test the changes.
git fetch -u origin issue/170:issue/170
git switch issue/170
Sign in to join this conversation.
No description provided.