Files
TimandGitHub 39247a11fa feat(web): migrate chain config fetching to /v2/chains endpoint (#7275)
* feat(web): migrate chain config fetching to `/v2/chains` endpoint

Switch the chains list endpoint from `/v1/chains` to `/v2/chains` across
all callers in the web app and shared store package. The v2 endpoint
requires a serviceKey to scope chain features per service (e.g.
WALLET_WEB, MOBILE). The key is configurable via
NEXT_PUBLIC_CONFIG_SERVICE_KEY with a default of 'WALLET_WEB'.

Updated callers: useChains, useInitStaticChains, ofac API, swap order listener, build-time fetch-chains script, and service worker
gateway-utils. Also migrates the single-chain getChainConfig utility
to chainsGetChainV2.

* test: replace crypto UUID with faker UUID in dynamicBaseQuery tests

Updated the test cases in cgwClient.test.ts to use faker for generating UUIDs instead of crypto.randomUUID, ensuring consistent and controlled test data generation.

* refactor: update chain configuration hooks and API calls to use v2 endpoint

Replaced all instances of `getChainsConfig` with `getChainsConfigV2` in the web app and store, ensuring consistent usage of the new endpoint. This includes updates in hooks, API slices, and tests to align with the new service key requirements for fetching chain configurations.

* tests: restore v1/chains MSW handler for mobile test compatibility

The v1/chains handler was removed when migrating to v2, but mobile still queries getChainsConfig which hits /v1/chains. Without a handler, requests fell through to the real staging API, causing snapshot drift in mobile tests. Also extracts the shared mock data into a chainsConfig constant to keep v1
and v2 handlers in sync.

* test: replace hardcoded service key with constant in chains retry tests

Updated the chains retry functionality tests to use a constant for the service key instead of a hardcoded string.

* fix: add validation for serviceKey in getChainsConfigV2 query

Implemented a check to ensure that the serviceKey is provided when calling the getChainsConfigV2 query. If the serviceKey is missing, a custom error is returned, improving error handling and preventing potential issues during API calls.

* fix: add validation for results array in getChainsConfigs

Enhanced error handling in the getChainsConfigs function by adding a check to ensure the results array is present in the API response. If the results array is missing, a custom error is returned, improving robustness against invalid responses.

* fix: remove JSON.stringify from service key in getChainsConfigV2 query

Updated the getChainsConfigV2 query to directly use the CONFIG_SERVICE_KEY constant instead of stringifying it, simplifying the code and ensuring the correct value is passed.
2026-03-02 13:52:49 +01:00

67 lines
2.3 KiB
TypeScript

/**
* Build-time script to pre-fetch chain configurations from the CGW API.
* Writes the result to src/config/__generated__/chains.json so the app can
* use it as an instant cache seed on startup, avoiding the blocking /v2/chains
* network request before any other API call can proceed.
*
* Run with: yarn fetch-chains
*/
import fs from 'fs'
import path from 'path'
import { fileURLToPath } from 'url'
const IS_PRODUCTION = process.env.NEXT_PUBLIC_IS_PRODUCTION === 'true'
const GATEWAY_URL_PRODUCTION = process.env.NEXT_PUBLIC_GATEWAY_URL_PRODUCTION || 'https://safe-client.safe.global'
const GATEWAY_URL_STAGING = process.env.NEXT_PUBLIC_GATEWAY_URL_STAGING || 'https://safe-client.staging.5afe.dev'
const GATEWAY_URL = IS_PRODUCTION ? GATEWAY_URL_PRODUCTION : GATEWAY_URL_STAGING
const CONFIG_SERVICE_KEY = process.env.NEXT_PUBLIC_CONFIG_SERVICE_KEY || 'WALLET_WEB'
const __dirname = path.dirname(fileURLToPath(import.meta.url))
const OUTPUT_DIR = path.join(__dirname, '..', 'src', 'config', '__generated__')
const OUTPUT_FILE = path.join(OUTPUT_DIR, 'chains.json')
type ChainPage = {
results: unknown[]
next?: string | null
}
async function fetchAllChains(): Promise<unknown[]> {
const allChains: unknown[] = []
let url: URL | null = new URL('/v2/chains', GATEWAY_URL)
url.searchParams.set('serviceKey', CONFIG_SERVICE_KEY)
url.searchParams.set('cursor', 'limit=50&offset=0')
while (url) {
const response = await fetch(url)
if (!response.ok) {
throw new Error(`Failed to fetch chains: ${response.status} ${response.statusText}`)
}
const data: ChainPage = await response.json()
allChains.push(...data.results)
url = data.next ? new URL(data.next) : null
}
return allChains
}
async function main() {
fs.mkdirSync(OUTPUT_DIR, { recursive: true })
try {
console.log(`Fetching chains from ${GATEWAY_URL}...`)
const chains = await fetchAllChains()
fs.writeFileSync(OUTPUT_FILE, JSON.stringify(chains, null, 2))
console.log(`Wrote ${chains.length} chains to ${path.relative(process.cwd(), OUTPUT_FILE)}`)
} catch (error) {
console.warn('Warning: Failed to fetch chains at build time. Using empty array as fallback.')
console.warn(error instanceof Error ? error.message : error)
fs.writeFileSync(OUTPUT_FILE, '[]')
}
}
main()