fix: TTS rate limiting, retry backoff, contract auth checks, and overflow guards#1006
Open
Grace-CODE-D wants to merge 4 commits into
Open
Conversation
…solutions-plug#994) Transient provider errors (429, rate-limited; 5xx, server errors) are now retried up to TTS_MAX_RETRIES (default 3) times with exponential backoff capped at TTS_MAX_DELAY_MS (default 60 s). Full jitter avoids thundering-herd on shared quota. Non-retriable errors (400, 401, 403) propagate immediately without consuming retry budget. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…ns-plug#995) Adds express-rate-limit middleware that enforces TTS_RATE_LIMIT_PER_MINUTE (default 60) requests per 60-second window per caller. Authenticated callers are bucketed by their API key; anonymous callers by IP address. Exceeding the limit returns 429 with a Retry-After: 60 header. Health-check endpoints are exempt. The in-service RateLimiter (TTSService) continues to operate as a secondary per-caller guard. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…cked ops (solutions-plug#996) - bets.rs: existing_bet.fee_paid now uses checked_add (returns ArithmeticOverflow instead of wrapping in release builds) - fees.rs: collect_fee changed to return Result<(), ErrorCode>; both per-token and overall fee accumulators now use checked_add so a protocol-revenue overflow fails the bet rather than silently undercount protocol fees - bets_fuzz_test.rs: added two payout-path fuzz properties — boundary-value claim scenarios and a direct overflow guard on the parimutuel multiplication formula Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…zation model (solutions-plug#997) Two state-mutating functions were missing Soroban authorization checks: - governance.rs::vote_on_guardian_removal — verified guardian membership by address comparison but never called voter.require_auth(), allowing any account to cast votes as any guardian. Fixed by adding voter.require_auth() before the membership check. - markets.rs::release_creation_deposit — had no authorization at all; any account could trigger the deposit refund. Fixed by calling market.creator.require_auth() so only the creator can claim their deposit. Also adds an Authorization Model section to contracts/predict-iq/README.md documenting the role-based access model for every mutable contract function. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
@Grace-CODE-D Great news! 🎉 Based on an automated assessment of this PR, the linked Wave issue(s) no longer count against your application limits. You can now already apply to more issues while waiting for a review of this PR. Keep up the great work! 🚀 |
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
Resolves four security and reliability issues across the TTS service and the Soroban prediction-market contract.
#994 — Exponential backoff with jitter on TTS provider retry
Files:
services/tts/src/TTSService.ts,services/tts/src/server.tsRetryConfiginterface (maxRetries,maxDelayMs) and extendedTTSConfigwith an optionalretryfield.withRetry<T>()helper that retries a callback up tomaxRetriestimes on transient errors (HTTP 429, 5xx / mapped 502). Non-retriable errors (400, 401, 403) propagate immediately without consuming retry budget.delay ∈ [0, min(maxDelayMs, 1000 × 2^attempt)], avoiding thundering-herd against shared provider quota._generateWithFallbacknow wraps both the primary and fallback_callProvidercalls withwithRetry, so each leg gets independent retry budget.server.tsreadsTTS_MAX_RETRIES(default3) andTTS_MAX_DELAY_MS(default60000) from environment and passes them through config.#995 — Rate limiting at TTS server level
Files:
services/tts/src/server.ts,services/tts/package.jsonexpress-rate-limit ^7.5.0to production dependencies.rateLimitmiddleware that applies to all routes (health endpoints exempted viaskip).apikey:<key>); anonymous callers are bucketed by IP (ip:<addr>). This gives authenticated users an independent quota and prevents shared-IP over-counting.TTS_RATE_LIMIT_PER_MINUTE=60requests per 60-second window; fully configurable via environment variable.Retry-After: 60response header.#996 — Arithmetic overflow in payout calculations
Files:
contracts/predict-iq/src/modules/bets.rs,contracts/predict-iq/src/modules/fees.rs,contracts/predict-iq/src/modules/bets_fuzz_test.rsbets.rs–existing_bet.fee_paid += feereplaced withchecked_add(...).ok_or(ErrorCode::ArithmeticOverflow)?. A bet that would overflow cumulative fee accounting now returns a typed contract error instead of wrapping silently in release builds.fees.rs–collect_feesignature changed fromfn(...) -> ()tofn(...) -> Result<(), ErrorCode>. Both the per-tokenFeeRevenueaccumulator and the globalTotalFeesCollectedaccumulator now usechecked_add, returningArithmeticOverflowon overflow. The single caller inbets.rspropagates the error with?.bets_fuzz_test.rs– Two new payout-path fuzz properties added:prop_payout_claim_boundary_values_do_not_panic— exercisesclaim_winningswith boundary bet amounts (1,i128::MAX/4,i128::MAX/2) and asserts no host panic.prop_payout_multiplication_overflow_returns_typed_error— directly asserts that the intermediate multiplication inwinnings = (bet.amount × total_staked) / winning_stakeproducesNonefromchecked_mulfor overflow-inducing inputs.#997 — Authorization checks missing before state mutations in Soroban contract
Files:
contracts/predict-iq/src/modules/governance.rs,contracts/predict-iq/src/modules/markets.rs,contracts/predict-iq/README.mdgovernance.rs::vote_on_guardian_removal— was verifying guardian membership by address comparison but never calledvoter.require_auth(). Any account could impersonate a guardian and cast removal votes. Fixed by addingvoter.require_auth()as the first statement before the membership check.markets.rs::release_creation_deposit— had no authorization at all. Any account could trigger the token transfer path (funds go tomarket.creatorregardless, but the lack of auth violates the principle of least privilege). Fixed by addingmarket.creator.require_auth()after loading the market, so only the creator can initiate their own deposit refund.README.md— Added a full Authorization Model section documenting every mutable contract function, the role required to authorize it (Admin, FeeAdmin, Guardian, Creator, Bettor, Voter, Referrer, or Permissionless), and the key invariants that the model enforces (admin/guardian separation,vote_on_guardian_removalauth,release_creation_depositauth, dual-layer admin checks).Test plan
services/tts—npm testpasses (existing suite coversRateLimiter,AudioCache,sanitizeInput,TTSProviderError; new retry helpers follow the same error-class contracts)contracts/predict-iq—cargo testpasses including the two newbets_fuzz_testpropertiesTTS_RATE_LIMIT_PER_MINUTE=2returns 429 +Retry-Afteron the 3rd request within a windowTTS_MAX_RETRIES=1 TTS_MAX_DELAY_MS=100produces one retry log line on a simulated 502Closes #994
Closes #995
Closes #996
Closes #997
🤖 Generated with Claude Code