Skip to content

Feature/be payment session validator and exchange rate oracle cache - #1589

Merged
emdevelopa merged 4 commits into
emdevelopa:mainfrom
rahmanabimbs:feature/be-payment-session-validator-and-exchange-rate-oracle-cache
Sep 26, 2026
Merged

emdevelopa merged 4 commits into
emdevelopa:mainfrom
rahmanabimbs:feature/be-payment-session-validator-and-exchange-rate-oracle-cache

Conversation

@rahmanabimbs

Copy link
Copy Markdown
Contributor

Closes #1448
Closes #1447
Closes #1446
Closes #1445

LawalRahman and others added 4 commits September 26, 2026 17:23
…or Payment Session Validator

- sanitizeSessionPayload: reject non-object bodies and prototype-pollution
  keys at any depth; NFC-normalize and strip control, bidi and zero-width
  characters from string fields; enforce per-field length caps
- validateSessionAsset / validateSessionAmount: 1-12 alphanumeric asset
  codes; positive, finite amounts within int64 stroops and <= 7 decimals
- validatePerAssetLimits: own-property lookup only, numeric coercion of
  bounds; inspectPaymentLimitsConfig reports malformed merchant config
- validateAllowedIssuers: ignore non-string allowlist entries
- request-schemas: import isValidStellarPublicKey (was a ReferenceError
  for every non-XLM session with an issuer)
- sanitize-metadata: reject __proto__/constructor/prototype keys instead
  of assigning them onto the sanitized object

Closes emdevelopa#1447

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ayment Session Validator

- validatePaymentSession(): single instrumented entry point running
  sanitization -> payload -> issuer -> limits -> allowlist, used by the
  HTTP route and paymentService (now before the on-chain issuer lookup)
- dedicated metrics registry merged into /metrics: evaluations,
  rejections by rule/reason, latency, sanitized fields, suspicious
  payloads, merchant config anomalies, rolling health gauges
- constant-memory rolling-window health monitor exposed at
  GET /health/payment-session-validator (503 only when unhealthy) and as
  an informational field on /health
- Prometheus alerting rules with a test guarding against metric drift
- structured logging that never includes the raw payload
- docs/PAYMENT_SESSION_VALIDATOR.md

Closes emdevelopa#1448

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…r Exchange Rate Oracle Cache

- ExchangeRateCache.getOrLoad(): single-flight loading so concurrent
  misses for a quote make one Horizon call per process; loader errors
  reach every waiter and are not cached; bounded load timeout (504)
- invalidation-safe writes: delete()/clear() detach in-flight loads so a
  load that started before invalidation can never write back
- ExchangeRateCoordinator: Redis SET NX PX lock with owner tokens and
  compare-and-delete release, shared quote store, follower polling with
  leader takeover and wait timeout; fails open to a direct Horizon query
- shared entries are validated before use (poisoned/corrupt = miss)
- cross-instance invalidation via the shared store
- concurrency metrics on the path-payment registry
- enabled by createApp() when Redis is connected
- fix two tests whose expectations contradicted the behavior they name
- docs/EXCHANGE_RATE_ORACLE_CACHE.md

Closes emdevelopa#1445

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…r Exchange Rate Oracle Cache

- tests/integration/exchange-rate-cache.test.js: real HTTP stack on
  GET /api/path-payment-quote/:id — burst coalescing, distinct pairs,
  404/502 fan-out without caching, 504 on hung Horizon, invalidation
  mid-flight, /metrics exposure, Redis coordination, poisoned shared
  entry, Redis outage
- load-tests/exchange-rate-cache-stress.test.js: 5k-20k concurrent
  requests, LRU churn, invalidation storm, failure isolation, and 8
  simulated instances sharing Redis (1 Horizon call per key), lock-holder
  crash, Redis outage mid-burst, stuck lock, leak checks
- CacheLoadTimeoutError now sets `status` so the Express error handler
  returns 504 instead of 500 (found by the integration suite)
- document suites and mutation-check results

Closes emdevelopa#1446

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@vercel

vercel Bot commented Sep 26, 2026

Copy link
Copy Markdown

@LawalRahman is attempting to deploy a commit to the Emmanuel's projects Team on Vercel.

A member of the Team first needs to authorize it.

@drips-wave

drips-wave Bot commented Sep 26, 2026

Copy link
Copy Markdown

@rahmanabimbs 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! 🚀

Learn more about application limits

@emdevelopa
emdevelopa merged commit 30479b8 into emdevelopa:main Sep 26, 2026
1 of 4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment