Network selector on routes + per-request x402 network - #136
Open
ibochivincent-lang wants to merge 1 commit into
Open
Network selector on routes + per-request x402 network#136ibochivincent-lang wants to merge 1 commit into
ibochivincent-lang wants to merge 1 commit into
Conversation
Adds a network-selector Fastify plugin (src/middleware/network.ts) that resolves a per-request Stellar network from a ?network= query param or x-network header, validates it (400 on an unrecognised value, default testnet), and attaches it to req.network — registered early so every route, x402, and the WebSocket handler can read it. x402 (both REST and /ws) now resolves its network label and payTo per request from req.network instead of a fixed value computed once from STELLAR_NETWORK at plugin init, via new shared helpers in src/x402/network.ts. Supports optional per-network payment addresses (ORACLE_PAYMENT_ADDRESS_TESTNET/_MAINNET, falling back to the existing ORACLE_PAYMENT_ADDRESS). /price/:assetA/:assetB and /price/:assetA/:assetB/route now look up watched pairs and live SDEX pricing (a real Horizon call) per the resolved network, so ?network=mainnet genuinely returns mainnet SDEX pricing; the price-cache key is network-scoped so testnet/mainnet don't collide. DB-backed reads (candles, history, pools, AMM pricing, GraphQL resolvers) have no network column yet and still serve from this instance's configured STELLAR_NETWORK — documented in the README as follow-up work. /ws validates its requested network the same way and rejects (400) a network other than the one this instance actually streams, since price events carry no network tag yet either. Also fixes a pre-existing bug in three test files' @stellar/stellar-sdk mocks (missing Networks export), which silently broke tests/aggregator.property.test.ts and made src/__tests__/bestRoute.test.ts report false results — both surfaced by getBestRoute's new getNetworkConfig() call.
|
@ibochivincent-lang 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
src/middleware/network.ts: a Fastify plugin resolving the per-request Stellar network from a?network=query param orx-networkheader, validating it (400 for anything nottestnet/mainnet, defaults totestnet), and attaching it toreq.network. Registered early insrc/index.ts(right after cors/compress, ahead of API-key auth/rate-limit/x402) so everything downstream can read it.src/x402/network.ts: shared per-network helpers (X402_NETWORK_LABEL,paymentAddressFor,getX402ResourceServer) used by both REST x402 gating and the WS endpoint, replacing the old module-load-timeSTELLAR_NETWORKread.src/middleware/x402.tsandsrc/api/websocket.ts: x402'snetwork/payToin the402requirements (and the actualverify/settlecalls) are now resolved fromreq.networkper request instead of a value computed once at plugin init. Supports optionalORACLE_PAYMENT_ADDRESS_TESTNET/ORACLE_PAYMENT_ADDRESS_MAINNETenv vars, falling back to the existingORACLE_PAYMENT_ADDRESS.src/api/rest.ts+src/aggregator/bestRoute.ts:/price/:assetA/:assetBand/price/:assetA/:assetB/routenow look up watched pairs (getNetworkConfig(network).pairs) and live SDEX pricing (a real per-network Horizon call) from the resolved network — so?network=mainnetgenuinely returns mainnet SDEX pricing. The price Redis cache key is network-scoped ({network}:{pairKey}) so testnet/mainnet never collide./wsresolves+validates the network the same way and rejects (400, closes the socket) a network other than the one this instance is actually streaming, since live price events don't carry a network tag yet.Scope call — what's not covered
Candles, price history, AMM pool pricing, and the GraphQL resolvers read from Postgres, which has no
networkcolumn yet — that's the deeper aggregation-layer work the issue's suggested execution calls out ("Thread into pricing/aggregation reads (L048)"). Those endpoints still serve from whichever network this instance is currently configured to ingest (STELLAR_NETWORK). Documented explicitly in the README and in code comments at each of these read sites so it's not lost track of.Side fix
While wiring
getBestRoute's new per-networkgetNetworkConfig()call, I foundtests/aggregator.property.test.tsandsrc/__tests__/bestRoute.test.ts's@stellar/stellar-sdkmocks were missing aNetworksexport — pre-existing onmain, not something this PR introduces (verified by running the suite against a cleanmaincheckout first). It silently crashed the property test at import time (0 iterations ever ran) and would have crashedbestRoute.test.tstoo oncegetBestRoutestarted callinggetNetworkConfig(). Fixed both mocks; also bumped the property test's timeout to 30s since, now that its 10,000 iterations actually execute, they don't reliably finish in the default 5s under full-suite load.closes #118
Test plan
npx tsc --noEmit— clean.npx vitest run— 197 passed, 1 skipped, run twice for stability. (Ran against cleanmainfirst to confirm which failures were pre-existing vs. introduced by this change.)src/__tests__/middleware/network.test.ts(selector resolution/validation), new cases insrc/__tests__/middleware/x402.test.ts(per-networkpayTo/networklabel, invalid network short-circuits before x402 runs, mainnet payment verification), new cases insrc/__tests__/bestRoute.test.ts(mainnet Horizon client selection + per-network memoisation).