Conversation
* fix: gate JUSD gateway deposits when savings disabled * fix: harden JUSD gateway deposit gating * refactor(gateway): telemetry, SWR probe, and shared deposit-disabled guard Improvements on top of the issue-263 Phase 1 gating: - Telemetry: expose JuiceGatewayService.getMetrics() (blocked-deposit counters keyed by chain:routeShape + SavingsRateProbe gauge/failure counters) via the existing JSON /metrics endpoint. Closes the acceptance-criteria telemetry gap without adding a Prometheus dep. - SavingsRateProbe: true stale-while-revalidate — serve the cached rate immediately and refresh in a coalesced background probe, so request latency never pays for the RPC. Adds an idle() test hook. - Observability: warn-log the fail-open path when an integrated chain has no registered vault. - DRY: extract isGatewayDepositDisabledError()/sendGatewayDepositDisabled() into endpoints/gatewayDepositGuard.ts and drop the duplicated error blocks in quote/swap/lpCreate/lpIncrease. typecheck clean, eslint 0 errors, jest 73/73 green (+4 new tests). * test(gateway): cover deposit-disabled guard and testnet gating Tester gap-analysis follow-ups: - gatewayDepositGuard.test.ts: isGatewayDepositDisabledError type guard (positive/negative/null) + sendGatewayDepositDisabled with and without error.message — closes the FALLBACK_DETAIL branch (now 100% coverage). - JuiceGatewayService: assert the deposit gate also fires on Citrea Testnet (5115), not just mainnet. jest 78/78 green. * test(gateway): live Citrea integration test + clearOverride coverage - SavingsRateProbe.integration.test.ts: opt-in (RUN_CITREA_INTEGRATION=1) live check against Citrea Mainnet — probe reads currentRatePPM()==0, Savings.save reverts with ModuleDisabled() (0x6dff2fe8), JUSD->cBTC is gated while JUSD->CTUSD direct conversion stays open. Skipped by default so the unit CI matrix stays deterministic. Closes the issue-263 acceptance-criteria RPC integration gap. - Cover clearOverride() (per-chain and clear-all) — SavingsRateProbe rises to 95.6% line coverage; remaining uncovered lines are the default ethers factory (exercised by the integration test) and defensive no-vault/swallow branches. jest 80 passed, 3 skipped (integration), green. * fix(probe): coalesce cold-cache probes; clear override gauge Fixer-Architect (Big Brother loop) finding on PR #266: - Thundering herd: the cold-cache path of getCurrentRate() bypassed the inFlight coalescing, so N concurrent first-callers per chain each fired SAVINGS()+currentRatePPM(). Route both the cold path and the background SWR refresh through a single shared getOrStartRefresh() promise — a burst of startup requests now triggers exactly one probe. Regression test added. - clearOverride() now drops the override-seeded ratePpmByChain gauge entry so /metrics never reports a stale forced rate after the override lifts. jest 81 passed, 3 skipped; SavingsRateProbe branch coverage 89.5%. * style: apply prettier formatting to gateway gating files * fix(probe): override must beat a late in-flight probe Round-2 Fixer-Architect finding on PR #266: refresh() persisted the probed rate to cache+gauge unconditionally. A probe that resolved after setOverride() resurrected the pre-override rate, so /metrics contradicted the active override and (cache not cleared by clearOverride) a stale rate could be served within TTL after the override lifted. refresh() now skips the cache/gauge write while an override is active. Deterministic regression test added. jest green. * fix(gateway): keep LP Gateway routing JUSD-only, decouple deposit gate detectLpGatewayRouting/getInternalPoolToken were widened to JUSD || bridged stablecoin || JUICE, but the LP handlers (handleGatewayLpCreate/handleGatewayLpIncrease) only convert literal JUSD legs to svJUSD. Once Savings is re-enabled, a USDC/cBTC or JUICE/cBTC LP would route into the svJUSD pool with a raw, unconverted amount fed into Position.fromAmount*, producing wrong amount0Raw/ amount1Raw. The new deposit gate masks this only while disabled. Revert both routing functions to JUSD-only so non-JUSD LP legs fall back to standard (pre-existing) handling. Decouple the deposit gate from detectLpGatewayRouting: lpCreate/lpIncrease now always call rejectIfLpRouteRequiresJusdDepositDisabled (a no-op unless a JUSD/ bridged/JUICE deposit leg is present), so bridged/JUICE LPs are still blocked while the Savings rate is zero. Add regression tests asserting bridged/JUICE LP legs do not route through the Gateway and are never mapped to svJUSD. --------- Co-authored-by: Josh - Agents <josh-agends@Mini-von-Josh.fritz.box> Co-authored-by: Daniel Padrino <danswarrior1@gmail.com>
Danswar
approved these changes
Jun 8, 2026
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.
Automatic Release PR
This PR was automatically created after changes were pushed to develop.
Commits: 1 new commit(s)
Checklist