Rate Limiting, WebSocket Portfolio Notifications, Achievement Engine, USDC Deposit Flow, DOAN Documentation#248
Merged
GoSTEAN merged 2 commits intoNetwalls:mainfrom Feb 26, 2026
Merged
Conversation
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.
Closes #134
Closes #226
Closes #115
Closes #87
Closes #95
Summary
This PR resolves 5 tracked issues: wallet-keyed rate limiting, portfolio update notifications over WebSocket, an achievement engine, a USDC deposit flow with on-chain verification, and DOAN architecture documentation.
Changes
Rate Limiting per Wallet Address (Issue 1)
Previously all rate limits keyed by IP address, which allowed a single user to bypass limits by rotating IPs or operating behind shared NAT. Limiters now key by
wallet:{publicKey}when the user is authenticated, falling back touser:{userId}thenip:{address}.authRateLimiter: 5 requests/minutepredictionRateLimiter: 10 requests/minute (new)tradeRateLimiter: 30 requests/minute (new)Retry-Afterheader populated from theRateLimit-ResettimestampstandardHeaders: 'draft-7'for RFC 9110-compliant rate limit headerstradeRateLimiterapplied to buy, sell, and submit-signed-tx routesWebSocket Portfolio Notifications (Issue 3)
Clients now join a private
portfolio:{userId}room on connection and receive aconnectedacknowledgement with their room list. Three notification helpers emit typed events to that room:notifyPositionChanged— fired after a prediction is committednotifyWinningsClaimed— fired after winnings are claimed, includes new balancenotifyBalanceUpdated— fired after any balance change (deposit, withdrawal, winnings, prediction)setSocketIORef()wires the Socket.IO instance into the realtime module at startup without circular imports.Achievement Engine (Issue 4)
New
achievement.service.tsdefines a catalog of 13 achievements across Bronze, Silver, Gold, and Platinum tiers covering prediction volume, win streaks (5/10/25), trade size (whale/mega-whale), win rate (sharp shooter), and profit milestones.checkAndAward()runs all applicable checks in parallel, skips already-awarded achievements via Prisma unique constraint idempotency, and sends aACHIEVEMENTnotification through the existing notification service. Checks are triggered non-blocking after each prediction settlement inmarket.service.ts.USDC Deposit Flow (Issue 5)
Two-step deposit flow added to
wallet.service.ts:initiateDeposit()— returns the platform's Stellar address, a user-specific memo (dep:{userId.slice(0,8)}), and a 24-hour expiry. The memo allows the backend to attribute incoming payments to the correct account.confirmDeposit()— accepts a Stellar transaction hash, fetches and validates the transaction from Horizon (checks memo, source account, USDC asset, payment destination), then atomically credits the user'susdcBalanceand creates aTransactionrecord. Duplicate submissions are rejected viatxHashuniqueness. In non-production environments, transaction hashes prefixed withmock-deposit-bypass Horizon for testing.withdraw()now also persists aTransactionrecord and emits abalance_updatedWebSocket event. RoutesPOST /api/wallet/deposit/initiateandPOST /api/wallet/deposit/confirmadded with auth guards, rate limiters, and Swagger documentation.DOAN Documentation (Issue 2)
DOAN_DOCS.md added at repo root covering the Decentralized Oracle Attestation Network architecture, oracle lifecycle, attestation flow, staking and slashing parameters, REST and WebSocket integration points, Soroban contract interface, and security considerations. Linked from README.md.
Testing
tsc --noEmit: zero errorsioredis: Connection is closedfailures are unrelated to this PRFiles Changed
tradeRateLimitersetSocketIORefwired at startup