Skip to content

Make Soroswap, Aquarius, and Reflector config per-network - #138

Merged
Miracle656 merged 1 commit into
Miracle656:mainfrom
Olorunfemi20:feat/per-network-venues
Aug 30, 2026
Merged

Make Soroswap, Aquarius, and Reflector config per-network#138
Miracle656 merged 1 commit into
Miracle656:mainfrom
Olorunfemi20:feat/per-network-venues

Conversation

@Olorunfemi20

Copy link
Copy Markdown
Contributor

Summary

Several venue endpoints were hardcoded mainnet-only: the Soroswap token-list URL, the Aquarius pools API, and the default Soroswap factory / Reflector contract only had sensible values for mainnet. On testnet these differ or do not exist at all, which blocks running the dual-network ingesters cleanly.

This PR moves the Soroswap token-list URL and the Aquarius API URL into the per-network config block (NetworkConfig), and adds an enabled flag per venue per network so a venue with no usable deployment on a given network can be skipped cleanly instead of failing.

Changes

  • src/config.ts: adds soroswap.enabled, soroswap.tokenListUrl, aquarius.enabled, aquarius.apiUrl, and oracle.enabled to NetworkConfig, each resolved per-network with the existing paired-var -> generic-var -> default precedence. Aquarius defaults to disabled on testnet (no public testnet deployment) and enabled on mainnet; Soroswap defaults to enabled on both. oracle.enabled is derived from whether a Reflector contract id is configured for the network.
  • src/ingesters/soroswap.ts: removes the hardcoded SOROSWAP_TOKEN_LIST_URL constant in favor of config.soroswap.tokenListUrl; fetchSoroswapTokenList now takes the URL as a parameter (defaulting to config) so tests can override it; startSoroswapIngester returns immediately without entering its polling loop when Soroswap is disabled on the active network.
  • src/ingest/venues/aquarius.ts: removes the hardcoded AQUARIUS_AMM_API constant in favor of config.aquarius.apiUrl; fetchAquariusPools takes the URL as a parameter; startAquariusIngester returns immediately when Aquarius is disabled on the active network.
  • src/ingest/oracles/reflector.ts: fetchReflectorPrice returns null immediately when config.oracle.enabled is false, rather than attempting a simulation against an empty contract id.
  • .env.example: documents the new SOROSWAP_ENABLED_*, AQUARIUS_ENABLED_*, SOROSWAP_TOKEN_LIST_URL, and AQUARIUS_API_URL vars.

Related issue

closes #116

Type of change

  • New feature
  • Bug fix
  • Refactor
  • Docs
  • Tests
  • CI / tooling

Testing

  • Added src/__tests__/networkVenueConfig.test.ts covering the enable-flag defaults/overrides and URL resolution for both networks.
  • Added src/__tests__/aquariusIngester.test.ts and src/__tests__/soroswapEnabled.test.ts covering the disabled-venue skip path and the configurable API URL.
  • npx tsc --noEmit passes.
  • npx vitest run passes (190 passed, 1 skipped); the two pre-existing failures in bestRoute.test.ts and aggregator.property.test.ts are unrelated to this change and reproduce identically on main.

Checklist

  • I have read CONTRIBUTING.md
  • npx tsc --noEmit passes
  • npm run build passes
  • I added / updated tests where relevant
  • I updated docs where relevant

Move the Soroswap token-list URL, Aquarius pools API URL, and their
enable flags into the per-network config block so dual-network
deployments can point each venue at network-appropriate endpoints
instead of the previously hardcoded mainnet-only URLs.

Aquarius has no public testnet deployment today, so it now defaults to
disabled on testnet and enabled on mainnet; both flags are overridable
via AQUARIUS_ENABLED_TESTNET / AQUARIUS_ENABLED_MAINNET. Soroswap
defaults to enabled on both networks and is likewise overridable via
SOROSWAP_ENABLED_TESTNET / SOROSWAP_ENABLED_MAINNET. The Reflector
oracle is now considered disabled whenever no contract id is
configured for the active network, so callers can check
config.oracle.enabled instead of special-casing an empty string.

startSoroswapIngester and startAquariusIngester return immediately
without entering their polling loop when their venue is disabled on
the active network, so a network with no deployment does not spin on
a venue that will only ever fail.
@drips-wave

drips-wave Bot commented Aug 29, 2026

Copy link
Copy Markdown

@Olorunfemi20 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

@Miracle656 Miracle656 left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Careful work. Per-network venue config with ${VAR}_${SUFFIX} overrides falling back to a shared default is the right shape, and the defaults encode real knowledge rather than guesses:

const aquariusEnabled =
  (process.env[`AQUARIUS_ENABLED_${suffix}`] ?? (network === 'mainnet' ? 'true' : 'false')) 

Defaulting Aquarius off on testnet because there is no public testnet deployment is exactly the kind of thing that otherwise shows up as a mystery ingester crash loop six months later. The comment explaining why is worth as much as the code.

The detail I liked most:

const oracleEnabled =
  (process.env[`REFLECTOR_ENABLED_${suffix}`] ?? 'true').toLowerCase() !== 'false' &&
  reflectorContractId !== ''

An oracle cannot be enabled without a contract id, so the flag can't claim a capability the config can't deliver. That's the same discipline #143 is missing on /supported, and it's the right instinct.

Two minor notes, neither blocking:

  • (… ?? 'true').toLowerCase() !== 'false' treats every value except false as enabled, so SOROSWAP_ENABLED_MAINNET=0 or =no silently enables it. Common enough pattern, but a shared envFlag(name, default) helper would make the three call sites agree and handle 0/no/off.
  • AQUARIUS_API_URL defaults to a trailing-slash URL (…/pools/) while the others don't. Worth checking the join logic in aquarius.ts doesn't produce a double slash.

No schema changes here, so this is independent of the #141 ordering problem and can land whenever.

@Miracle656
Miracle656 merged commit ea7d5f6 into Miracle656:main Aug 30, 2026
1 check passed
Miracle656 added a commit that referenced this pull request Aug 30, 2026
Resolves three conflicts against #138 (per-network venue config), which
landed first and touched the same functions for a different reason.

Every conflict was the same shape: #138 added per-network *enable* flags
while #139 added per-network *parameterisation*. Both are wanted, so each
resolution is the union rather than a choice.

  reflector.ts  fetchReflectorPrice takes `network` (#139) and keeps the
                oracle.enabled gate (#138). config.ts already makes
                oracle.enabled imply a non-empty reflectorContractId, so
                the single check subsumes #139's contract-id guard.

  soroswap.ts   startSoroswapIngester takes `network` (#139) and keeps the
                enabled check plus tokenListUrl (#138), now read from
                getNetworkConfig(network) rather than the module-level
                config. The log line names the network it skipped.

  bestRoute.ts  Takes #139's shared getHorizonServer over the local
                per-network Horizon map, which was duplicating what
                network/clients.ts exists to provide. Kept #138's comment
                about the AMM path having no network column yet — still
                accurate, and the reason SDEX and AMM differ here.

Two follow-on fixes the merge itself required:

  - bestRoute exported _resetHorizonServers, used by bestRoute.test.ts.
    Dropping the local map removed it, so network/clients.ts gains
    resetNetworkClients() and bestRoute keeps a thin delegating export.
    The test's import path is unchanged.

  - fetchSoroswapTokenList defaulted its argument from the module-level
    `config`, which #139 removed. Now defaults via
    getNetworkConfig(activeNetwork). Caught by tsc, not by the tests --
    the default is not exercised at runtime by the suite.

  - soroswapEnabled.test.ts mocked '../config' with only `config`. The
    merged ingester also reads activeNetwork and getNetworkConfig, so the
    mock supplies both; getNetworkConfig returns the same object the test
    mutates, keeping `enabled` toggleable. Same partial-mock trap as #146.

Verified: tsc --noEmit clean, 245 tests pass across 34 files, 1 skipped.
package-lock.json untouched.

Claude-Session: https://claude.ai/code/session_01USgemLt4Rnz4SGB1Srf3GB
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Per-network Soroswap / Reflector / Aquarius / token-list config

2 participants