/** * Load relay mappings, GRU transport overlay config, routing registry, and deployment JSON. * Used by relay service, token-aggregation, bridge/LP tooling, and docs. Safe to publish. * * @version 2026-03-30 */ const path = require('path'); const fs = require('fs'); const ZERO_ADDRESS = '0x0000000000000000000000000000000000000000'; const DEFAULT_JSON_PATH = path.resolve(__dirname, 'token-mapping.json'); const DEFAULT_MULTICHAIN_JSON_PATH = path.resolve(__dirname, 'token-mapping-multichain.json'); const DEFAULT_GRU_ACTIVE_JSON_PATH = path.resolve(__dirname, 'gru-transport-active.json'); const DEFAULT_ROUTING_REGISTRY_JSON_PATH = path.resolve(__dirname, 'routing-registry.json'); const DEFAULT_DEPLOYMENT_STATUS_JSON_PATH = path.resolve( __dirname, '..', 'cross-chain-pmm-lps', 'config', 'deployment-status.json' ); const DEFAULT_POOL_MATRIX_JSON_PATH = path.resolve( __dirname, '..', 'cross-chain-pmm-lps', 'config', 'pool-matrix.json' ); const DEFAULT_CW_RESERVE_VERIFIER_BROADCAST_PATH = path.resolve( __dirname, '..', 'smom-dbis-138', 'broadcast', 'DeployCWReserveVerifier.s.sol', '138', 'run-latest.json' ); const ENV_ALIASES = { CHAIN138_L1_BRIDGE: ['CW_L1_BRIDGE', 'CW_L1_BRIDGE_CHAIN138'], CW_L1_BRIDGE: ['CHAIN138_L1_BRIDGE', 'CW_L1_BRIDGE_CHAIN138'], }; const JSON_CACHES = { token: null, multichain: null, gruTransport: null, routingRegistry: null, deploymentStatus: null, poolMatrix: null, }; function loadCachedJson(cacheKey, jsonPath) { const current = JSON_CACHES[cacheKey]; if (current && current.path === jsonPath) return current.data; try { const raw = fs.readFileSync(jsonPath, 'utf8'); const data = JSON.parse(raw); JSON_CACHES[cacheKey] = { path: jsonPath, data }; return data; } catch (e) { return null; } } function normalizeAddress(address) { return typeof address === 'string' ? address.trim().toLowerCase() : ''; } function isActiveRolloutRecord(record) { return !record || typeof record !== 'object' || record.active !== false; } function normalizeSymbol(symbol) { return typeof symbol === 'string' ? symbol.trim().toLowerCase() : ''; } function normalizeTransportSymbol(symbol) { const normalized = normalizeSymbol(symbol).replace(/[\s_-]/g, ''); if (normalized.startsWith('cw')) { return `c${normalized.slice(2)}`; } return normalized; } function resolveChainSelectorValue(...values) { for (const value of values) { if (typeof value === 'number' && Number.isFinite(value)) { return String(Math.trunc(value)); } if (typeof value === 'string') { const trimmed = value.trim(); if (/^\d+$/.test(trimmed)) { return trimmed; } } } return ''; } function isNonZeroAddress(address) { const normalized = normalizeAddress(address); return /^0x[a-f0-9]{40}$/.test(normalized) && normalized !== ZERO_ADDRESS; } function resolveConfigRef(ref) { if (!ref || typeof ref !== 'object') return ''; if (isNonZeroAddress(ref.address)) return ref.address; if (typeof ref.env === 'string') { const envValue = resolveEnvAddress(ref.env); if (isNonZeroAddress(envValue)) return envValue; } return ''; } function resolveEnvAddress(envKey) { if (typeof envKey !== 'string' || envKey.trim() === '') return ''; const direct = process.env[envKey]; if (isNonZeroAddress(direct)) return direct; const aliases = ENV_ALIASES[envKey] || []; for (const alias of aliases) { const candidate = process.env[alias]; if (isNonZeroAddress(candidate)) return candidate; } if (envKey === 'CW_RESERVE_VERIFIER_CHAIN138') { const derived = deriveCwReserveVerifierFromBroadcast(); if (isNonZeroAddress(derived)) return derived; } return ''; } function deriveCwReserveVerifierFromBroadcast() { try { const data = loadCachedJson('cwReserveVerifierBroadcast', DEFAULT_CW_RESERVE_VERIFIER_BROADCAST_PATH); if (!data || !Array.isArray(data.transactions)) return ''; const tx = data.transactions.find( (entry) => entry && entry.contractName === 'CWReserveVerifier' && entry.transactionType === 'CREATE' && isNonZeroAddress(entry.contractAddress) ); return tx?.contractAddress || ''; } catch (e) { return ''; } } function hasConfigRef(ref) { if (!ref || typeof ref !== 'object') return false; return isNonZeroAddress(ref.address) || (typeof ref.env === 'string' && ref.env.trim() !== ''); } function resolvePolicyRefValue(ref) { if (!ref || typeof ref !== 'object') return ''; if (typeof ref.amount === 'string' && ref.amount.trim() !== '') return ref.amount.trim(); if (typeof ref.env === 'string') { const value = process.env[ref.env]; if (typeof value === 'string' && value.trim() !== '') return value.trim(); } return ''; } function loadTokenMappingJson(jsonPath = DEFAULT_JSON_PATH) { return loadCachedJson('token', jsonPath); } function loadTokenMappingMultichainJson(jsonPath = DEFAULT_MULTICHAIN_JSON_PATH) { return loadCachedJson('multichain', jsonPath); } function loadGruTransportActiveJson(jsonPath = DEFAULT_GRU_ACTIVE_JSON_PATH) { return loadCachedJson('gruTransport', jsonPath); } function loadRoutingRegistryJson(jsonPath = DEFAULT_ROUTING_REGISTRY_JSON_PATH) { return loadCachedJson('routingRegistry', jsonPath); } function loadDeploymentStatusJson(jsonPath = DEFAULT_DEPLOYMENT_STATUS_JSON_PATH) { return loadCachedJson('deploymentStatus', jsonPath); } function loadPoolMatrixJson(jsonPath = DEFAULT_POOL_MATRIX_JSON_PATH) { return loadCachedJson('poolMatrix', jsonPath); } function getRelayTokenMapping(jsonPath) { const data = loadTokenMappingJson(jsonPath); if (!data || !Array.isArray(data.tokens)) return {}; const out = {}; for (const t of data.tokens) { if (t.chain138Address && t.mainnetAddress) { out[t.chain138Address] = t.mainnetAddress; } } return out; } function getTokenList(jsonPath) { const data = loadTokenMappingJson(jsonPath); if (!data || !Array.isArray(data.tokens)) return []; return data.tokens; } function getTokenMappingForPair(fromChainId, toChainId, jsonPath) { const data = loadTokenMappingMultichainJson(jsonPath); if (!data || !Array.isArray(data.pairs)) return null; const from = Number(fromChainId); const to = Number(toChainId); let pair = data.pairs.find((p) => p.fromChainId === from && p.toChainId === to); let reverse = false; if (!pair) { pair = data.pairs.find((p) => p.fromChainId === to && p.toChainId === from); reverse = true; } if (!pair || !Array.isArray(pair.tokens)) return null; const tokens = reverse ? pair.tokens.map((t) => ({ key: t.key, name: t.name, addressFrom: t.addressTo, addressTo: t.addressFrom, notes: t.notes, })) : pair.tokens; const addressMapFromTo = {}; const addressMapToFrom = {}; for (const t of tokens) { if (t.addressFrom && t.addressTo) { addressMapFromTo[t.addressFrom.toLowerCase()] = t.addressTo; addressMapToFrom[t.addressTo.toLowerCase()] = t.addressFrom; } } return { tokens, addressMapFromTo, addressMapToFrom }; } function getAllMultichainPairs(jsonPath) { const data = loadTokenMappingMultichainJson(jsonPath); if (!data || !Array.isArray(data.pairs)) return []; return data.pairs.map((p) => ({ fromChainId: p.fromChainId, toChainId: p.toChainId, notes: p.notes })); } function getMappedAddress(fromChainId, toChainId, tokenAddressOnSource, jsonPath) { const activeTransportPair = getActiveTransportPair( fromChainId, toChainId, { sourceTokenAddress: tokenAddressOnSource }, { multichainJsonPath: jsonPath } ); if (activeTransportPair) { const sameDirection = Number(activeTransportPair.canonicalChainId) === Number(fromChainId) && Number(activeTransportPair.destinationChainId) === Number(toChainId); const targetAddress = sameDirection ? activeTransportPair.mirroredAddress : activeTransportPair.canonicalAddress; if (isNonZeroAddress(targetAddress)) { return targetAddress; } } const result = getTokenMappingForPair(fromChainId, toChainId, jsonPath); if (!result) return undefined; return result.addressMapFromTo[String(tokenAddressOnSource).toLowerCase()]; } function getRoutingRegistryRoutes(jsonPath = DEFAULT_ROUTING_REGISTRY_JSON_PATH) { const data = loadRoutingRegistryJson(jsonPath); if (!data || !Array.isArray(data.routes)) return []; return data.routes; } function getGruTransportMetadata(jsonPath = DEFAULT_GRU_ACTIVE_JSON_PATH) { const data = loadGruTransportActiveJson(jsonPath); if (!data || typeof data !== 'object') return null; const enabledCanonicalTokens = getEnabledCanonicalTokens(jsonPath); const enabledDestinationChains = getEnabledDestinationChains(jsonPath); const approvedBridgePeers = Array.isArray(data.approvedBridgePeers) ? data.approvedBridgePeers.filter(isActiveRolloutRecord) : []; const configuredTransportPairs = Array.isArray(data.transportPairs) ? data.transportPairs : []; const deferredTransportPairs = configuredTransportPairs.filter((pair) => !isActiveRolloutRecord(pair)).length; const activeTransportPairs = getActiveTransportPairs({ activeJsonPath: jsonPath }); const activePublicPools = getActivePublicPools(jsonPath); const gasAssetFamilies = getGasAssetFamilies(jsonPath); const gasRedeemGroups = getGasRedeemGroups(jsonPath); const gasProtocolExposure = getGasProtocolExposure(jsonPath); return { system: data.system || null, terminology: data.terminology || {}, enabledCanonicalTokens, enabledDestinationChains, gasAssetFamilies, gasRedeemGroups, gasProtocolExposure, counts: { enabledCanonicalTokens: enabledCanonicalTokens.length, enabledDestinationChains: enabledDestinationChains.length, approvedBridgePeers: approvedBridgePeers.length, transportPairs: activeTransportPairs.length, configuredTransportPairs: configuredTransportPairs.length, deferredTransportPairs, gasAssetFamilies: gasAssetFamilies.length, gasRedeemGroups: gasRedeemGroups.length, gasProtocolExposure: gasProtocolExposure.length, gasTransportPairs: activeTransportPairs.filter((pair) => pair.assetClass === 'gas_native').length, strictEscrowTransportPairs: activeTransportPairs.filter((pair) => pair.backingMode === 'strict_escrow').length, hybridCapTransportPairs: activeTransportPairs.filter((pair) => pair.backingMode === 'hybrid_cap').length, eligibleTransportPairs: activeTransportPairs.filter((pair) => pair.eligible).length, runtimeReadyTransportPairs: activeTransportPairs.filter((pair) => pair.runtimeReady).length, publicPools: Array.isArray(data.publicPools) ? data.publicPools.length : 0, activePublicPools: activePublicPools.filter((pool) => pool.active === true).length, routablePublicPools: activePublicPools.filter( (pool) => pool.active === true && pool.routingEnabled === true ).length, mcpVisiblePublicPools: activePublicPools.filter( (pool) => pool.active === true && pool.mcpVisible === true ).length, }, }; } function getGasAssetFamilies(jsonPath = DEFAULT_GRU_ACTIVE_JSON_PATH) { const data = loadGruTransportActiveJson(jsonPath); if (!data || !Array.isArray(data.gasAssetFamilies)) return []; return data.gasAssetFamilies; } function getGasAssetFamily(identifier, jsonPath = DEFAULT_GRU_ACTIVE_JSON_PATH) { const normalized = normalizeSymbol(identifier || ''); if (!normalized) return null; return ( getGasAssetFamilies(jsonPath).find((family) => { if (normalizeSymbol(family.familyKey) === normalized) return true; if (normalizeSymbol(family.canonicalSymbol138) === normalized) return true; if (normalizeSymbol(family.mirroredSymbol) === normalized) return true; return false; }) || null ); } function getGasRedeemGroups(jsonPath = DEFAULT_GRU_ACTIVE_JSON_PATH) { const data = loadGruTransportActiveJson(jsonPath); if (!data || !Array.isArray(data.gasRedeemGroups)) return []; return data.gasRedeemGroups; } function getGasProtocolExposure(jsonPath = DEFAULT_GRU_ACTIVE_JSON_PATH) { const data = loadGruTransportActiveJson(jsonPath); if (!data || !Array.isArray(data.gasProtocolExposure)) return []; return data.gasProtocolExposure; } function getGasProtocolExposureRecord(identifier, jsonPath = DEFAULT_GRU_ACTIVE_JSON_PATH) { const normalized = normalizeSymbol(identifier || ''); if (!normalized) return null; return ( getGasProtocolExposure(jsonPath).find((record) => { if (normalizeSymbol(record.key) === normalized) return true; if (normalizeSymbol(record.familyKey) === normalized) return true; if (normalizeSymbol(record.mirroredSymbol) === normalized) return true; return false; }) || null ); } function isGasRedemptionPathAllowed(fromChainId, toChainId, identifier, jsonPath = DEFAULT_GRU_ACTIVE_JSON_PATH) { const family = getGasAssetFamily(identifier, jsonPath); if (!family) return false; const from = Number(fromChainId); const to = Number(toChainId); const redeemGroups = getGasRedeemGroups(jsonPath).filter( (group) => normalizeSymbol(group.familyKey) === normalizeSymbol(family.familyKey) ); if (redeemGroups.length === 0) { return from === to && Array.isArray(family.originChains) && family.originChains.includes(from); } return redeemGroups.some((group) => { const allowedChains = Array.isArray(group.allowedChains) ? group.allowedChains.map((chainId) => Number(chainId)) : []; if (!allowedChains.includes(from) || !allowedChains.includes(to)) return false; const policy = String(group.redeemPolicy || family.redeemPolicy || '').trim().toLowerCase(); if (policy === 'family_fungible_inventory_gated') return true; return from === to; }); } function getEnabledCanonicalTokens(jsonPath = DEFAULT_GRU_ACTIVE_JSON_PATH) { const data = loadGruTransportActiveJson(jsonPath); if (!data || !Array.isArray(data.enabledCanonicalTokens)) return []; return data.enabledCanonicalTokens.filter(isActiveRolloutRecord); } function getEnabledCanonicalToken(identifier, jsonPath = DEFAULT_GRU_ACTIVE_JSON_PATH) { const normalizedSymbol = normalizeSymbol(identifier || ''); const normalizedAddress = normalizeAddress(identifier || ''); return ( getEnabledCanonicalTokens(jsonPath).find((token) => { if (normalizedSymbol) { if (normalizeSymbol(token.symbol) === normalizedSymbol) return true; if (normalizeSymbol(token.mirroredSymbol) === normalizedSymbol) return true; } if (!normalizedAddress) return false; if (normalizeAddress(token.activeAddress) === normalizedAddress) return true; if (normalizeAddress(token.x402PreferredAddress) === normalizedAddress) return true; if (Array.isArray(token.deployments)) { return token.deployments.some((deployment) => normalizeAddress(deployment.address) === normalizedAddress); } return false; }) || null ); } function getEnabledDestinationChains(jsonPath = DEFAULT_GRU_ACTIVE_JSON_PATH) { const data = loadGruTransportActiveJson(jsonPath); if (!data || !Array.isArray(data.enabledDestinationChains)) return []; return data.enabledDestinationChains.filter(isActiveRolloutRecord); } function isCanonicalTokenActive(symbol, jsonPath = DEFAULT_GRU_ACTIVE_JSON_PATH) { const normalized = normalizeSymbol(symbol); return getEnabledCanonicalTokens(jsonPath).some((token) => normalizeSymbol(token.symbol) === normalized); } function isDestinationChainActive(chainId, jsonPath = DEFAULT_GRU_ACTIVE_JSON_PATH) { const numericChainId = Number(chainId); return getEnabledDestinationChains(jsonPath).some((chain) => Number(chain.chainId) === numericChainId); } function getApprovedBridgePeer(chainId, jsonPath = DEFAULT_GRU_ACTIVE_JSON_PATH) { const data = loadGruTransportActiveJson(jsonPath); if (!data || !Array.isArray(data.approvedBridgePeers)) return null; const numericChainId = Number(chainId); return data.approvedBridgePeers.find((peer) => isActiveRolloutRecord(peer) && Number(peer.chainId) === numericChainId) || null; } function getRawMappingTokenEntry(fromChainId, toChainId, mappingKey, jsonPath = DEFAULT_MULTICHAIN_JSON_PATH) { const data = loadTokenMappingMultichainJson(jsonPath); if (!data || !Array.isArray(data.pairs)) return null; const pair = data.pairs.find( (entry) => Number(entry.fromChainId) === Number(fromChainId) && Number(entry.toChainId) === Number(toChainId) ); if (!pair || !Array.isArray(pair.tokens)) return null; return pair.tokens.find((token) => token.key === mappingKey) || null; } /** * GRU ISO-4217 bridge versioning from gru-transport-active enabledCanonicalTokens[].bridge * (canonical c* on 138 + mirrored cW* on destination via lock / mint / burn / release). */ function getBridgeAssetVersionsForCanonicalSymbol(canonicalSymbol, activeJsonPath = DEFAULT_GRU_ACTIVE_JSON_PATH) { const tokens = getEnabledCanonicalTokens(activeJsonPath); const match = tokens.find((t) => normalizeSymbol(t.symbol) === normalizeSymbol(canonicalSymbol)); if (!match || typeof match.bridge !== 'object' || match.bridge === null) { return { canonicalAssetVersion: 'v1', mirroredAssetVersion: 'v1' }; } const b = match.bridge; const cv = typeof b.canonicalAssetVersion === 'string' ? b.canonicalAssetVersion.trim().toLowerCase() : 'v1'; const mv = typeof b.mirroredAssetVersion === 'string' ? b.mirroredAssetVersion.trim().toLowerCase() : 'v1'; return { canonicalAssetVersion: cv === 'v2' ? 'v2' : 'v1', mirroredAssetVersion: mv === 'v2' ? 'v2' : 'v1', }; } function getGasRegistryEntry(multichainData, mappingKey) { if (!multichainData || !multichainData.gasAssetRegistry || !Array.isArray(multichainData.gasAssetRegistry.families)) { return null; } return ( multichainData.gasAssetRegistry.families.find( (family) => normalizeSymbol(family.mappingKey) === normalizeSymbol(mappingKey) ) || null ); } function resolveGruIso4217BridgeAddresses(multichainData, mappingKey, destinationChainId, versions, mappingEntry) { const bridgeCfg = multichainData && multichainData.gruIso4217Bridge; const canonTable = bridgeCfg && bridgeCfg.canonical138ByMappingKey && bridgeCfg.canonical138ByMappingKey[mappingKey]; let canonicalAddress = mappingEntry ? mappingEntry.addressFrom : null; if (canonTable) { const want = versions.canonicalAssetVersion === 'v2' ? 'v2' : 'v1'; const picked = canonTable[want]; if (isNonZeroAddress(picked)) { canonicalAddress = picked; } } let mirroredAddress = mappingEntry ? mappingEntry.addressTo : null; if (versions.mirroredAssetVersion === 'v2') { const chainKey = String(Number(destinationChainId)); const m = bridgeCfg && bridgeCfg.mirroredV2ByMappingKeyAndChain && bridgeCfg.mirroredV2ByMappingKeyAndChain[mappingKey] && bridgeCfg.mirroredV2ByMappingKeyAndChain[mappingKey][chainKey]; mirroredAddress = isNonZeroAddress(m) ? m : null; } const gasEntry = getGasRegistryEntry(multichainData, mappingKey); if (gasEntry) { if (isNonZeroAddress(gasEntry.canonicalAddress138)) { canonicalAddress = gasEntry.canonicalAddress138; } const chainKey = String(Number(destinationChainId)); const gasMirror = gasEntry.mirroredAddresses && typeof gasEntry.mirroredAddresses === 'object' ? gasEntry.mirroredAddresses[chainKey] : null; if (isNonZeroAddress(gasMirror)) { mirroredAddress = gasMirror; } } return { canonicalAddress, mirroredAddress }; } function parseBigIntString(value) { if (typeof value !== 'string') return null; const trimmed = value.trim(); if (!/^-?\d+$/.test(trimmed)) return null; try { return BigInt(trimmed); } catch { return null; } } function evaluateTransportSupplyInvariant(values = {}) { const mode = String(values.backingMode || '').trim().toLowerCase(); if (!mode) { return { applicable: false, inputsReady: true, valid: null, blockers: [], }; } const outstanding = parseBigIntString(values.outstandingValue); const escrowed = parseBigIntString(values.escrowedValue); const treasuryBacked = parseBigIntString(values.treasuryBackedValue); const treasuryCap = parseBigIntString(values.treasuryCapValue); const blockers = []; if (outstanding === null) blockers.push('supplyAccounting:outstanding'); if (escrowed === null) blockers.push('supplyAccounting:escrowed'); if (mode === 'strict_escrow' && treasuryBacked === null && values.treasuryBackedValue != null) { blockers.push('supplyAccounting:treasuryBacked'); } if (mode === 'hybrid_cap') { if (treasuryBacked === null) blockers.push('supplyAccounting:treasuryBacked'); if (treasuryCap === null) blockers.push('supplyAccounting:treasuryCap'); } if (blockers.length > 0) { return { applicable: true, inputsReady: false, valid: null, blockers, }; } let valid = true; const invariantBlockers = []; if (mode === 'strict_escrow') { valid = outstanding <= escrowed; if (!valid) invariantBlockers.push('policy:strictEscrowShortfall'); if (treasuryBacked !== null && treasuryBacked !== 0n) { valid = false; invariantBlockers.push('policy:strictEscrowTreasuryBackedNonZero'); } } else if (mode === 'hybrid_cap') { if (treasuryBacked > treasuryCap) { valid = false; invariantBlockers.push('policy:treasuryCapExceeded'); } if (outstanding > escrowed + treasuryCap) { valid = false; invariantBlockers.push('policy:hybridCapExceeded'); } if (outstanding > escrowed + treasuryBacked) { valid = false; invariantBlockers.push('policy:hybridBackingDeficit'); } } return { applicable: true, inputsReady: true, valid, blockers: invariantBlockers, }; } function getActiveTransportPairs(options = {}) { const activeJsonPath = options.activeJsonPath || DEFAULT_GRU_ACTIVE_JSON_PATH; const multichainJsonPath = options.multichainJsonPath || DEFAULT_MULTICHAIN_JSON_PATH; const deploymentJsonPath = options.deploymentJsonPath || DEFAULT_DEPLOYMENT_STATUS_JSON_PATH; const active = loadGruTransportActiveJson(activeJsonPath); const deployment = loadDeploymentStatusJson(deploymentJsonPath); if (!active || !Array.isArray(active.transportPairs)) return []; const configuredTransportPairs = active.transportPairs.filter(isActiveRolloutRecord); const enabledCanonicalTokens = new Set( getEnabledCanonicalTokens(activeJsonPath).map((token) => normalizeSymbol(token.symbol)) ); const enabledDestinationChains = new Set( getEnabledDestinationChains(activeJsonPath).map((chain) => Number(chain.chainId)) ); const destinationChainsById = new Map( getEnabledDestinationChains(activeJsonPath).map((chain) => [Number(chain.chainId), chain]) ); const peersByKey = new Map( (Array.isArray(active.approvedBridgePeers) ? active.approvedBridgePeers : []) .filter(isActiveRolloutRecord) .map((peer) => [String(peer.key), peer]) ); const reserveVerifiers = active.reserveVerifiers && typeof active.reserveVerifiers === 'object' ? active.reserveVerifiers : {}; const gasProtocolExposure = new Map( getGasProtocolExposure(activeJsonPath).map((record) => [String(record.key), record]) ); return configuredTransportPairs.map((pair) => { const canonicalChainId = Number(pair.canonicalChainId ?? active.system?.canonicalChainId ?? 138); const destinationChainId = Number(pair.destinationChainId); const canonicalSymbol = String(pair.canonicalSymbol || '').trim(); const mirroredSymbol = String(pair.mirroredSymbol || '').trim(); const mappingEntry = getRawMappingTokenEntry(canonicalChainId, destinationChainId, pair.mappingKey, multichainJsonPath); const multichainRoot = loadTokenMappingMultichainJson(multichainJsonPath); const bridgeVersions = getBridgeAssetVersionsForCanonicalSymbol(canonicalSymbol, activeJsonPath); const resolvedAddrs = resolveGruIso4217BridgeAddresses( multichainRoot, pair.mappingKey, destinationChainId, bridgeVersions, mappingEntry ); const deploymentChain = deployment && deployment.chains && typeof deployment.chains === 'object' ? deployment.chains[String(destinationChainId)] || null : null; const mirrorDeploymentAddress = deploymentChain && typeof deploymentChain === 'object' ? ( (deploymentChain.cwTokens && typeof deploymentChain.cwTokens === 'object' ? deploymentChain.cwTokens[mirroredSymbol] : null) || (deploymentChain.gasMirrors && typeof deploymentChain.gasMirrors === 'object' ? deploymentChain.gasMirrors[mirroredSymbol] : null) || null ) : null; const peer = peersByKey.get(String(pair.peerKey || '')) || null; const maxOutstanding = pair.maxOutstanding && typeof pair.maxOutstanding === 'object' ? pair.maxOutstanding : {}; const reserveVerifier = pair.reserveVerifierKey ? reserveVerifiers[pair.reserveVerifierKey] : null; const supplyAccounting = pair.supplyAccounting && typeof pair.supplyAccounting === 'object' ? pair.supplyAccounting : null; const protocolExposure = pair.protocolExposureKey && gasProtocolExposure.has(String(pair.protocolExposureKey)) ? gasProtocolExposure.get(String(pair.protocolExposureKey)) : null; const routeDiscoveryEnabled = pair.routeDiscoveryEnabled !== false; const canonicalAddress = resolvedAddrs.canonicalAddress; const mirroredAddress = resolvedAddrs.mirroredAddress; const destinationConfig = destinationChainsById.get(destinationChainId) || null; const destinationChainSelector = resolveChainSelectorValue( pair.destinationChainSelector, peer && peer.ccipChainSelector, destinationConfig && destinationConfig.ccipChainSelector ); const runtimeL1BridgeAddress = peer ? resolveConfigRef(peer.l1Bridge) : ''; const runtimeL2BridgeAddress = peer ? resolveConfigRef(peer.l2Bridge) : ''; const runtimeMaxOutstandingValue = resolvePolicyRefValue(maxOutstanding); const runtimeReserveVerifier = reserveVerifier && typeof reserveVerifier === 'object' ? reserveVerifier : null; const runtimeReserveVerifierBridgeAddress = runtimeReserveVerifier ? resolveConfigRef(runtimeReserveVerifier.bridgeRef) : ''; const runtimeReserveVerifierAddress = runtimeReserveVerifier ? resolveConfigRef(runtimeReserveVerifier.verifierRef) : ''; const runtimeReserveVaultAddress = runtimeReserveVerifier ? resolveConfigRef(runtimeReserveVerifier.vaultRef) : ''; const runtimeReserveSystemAddress = runtimeReserveVerifier ? resolveConfigRef(runtimeReserveVerifier.reserveSystemRef) : ''; const runtimeOutstandingValue = supplyAccounting ? resolvePolicyRefValue(supplyAccounting.outstanding) : ''; const runtimeEscrowedValue = supplyAccounting ? resolvePolicyRefValue(supplyAccounting.escrowed) : ''; const runtimeTreasuryBackedValue = supplyAccounting ? resolvePolicyRefValue(supplyAccounting.treasuryBacked) : ''; const runtimeTreasuryCapValue = supplyAccounting ? resolvePolicyRefValue(supplyAccounting.treasuryCap) : ''; const supplyInvariant = evaluateTransportSupplyInvariant({ backingMode: pair.backingMode, outstandingValue: runtimeOutstandingValue, escrowedValue: runtimeEscrowedValue, treasuryBackedValue: runtimeTreasuryBackedValue, treasuryCapValue: runtimeTreasuryCapValue, }); const mirrorDeployed = isNonZeroAddress(mirrorDeploymentAddress) && isNonZeroAddress(mirroredAddress) && normalizeAddress(mirrorDeploymentAddress) === normalizeAddress(mirroredAddress); const bridgePeerConfigured = !!peer && hasConfigRef(peer.l1Bridge) && hasConfigRef(peer.l2Bridge); const maxOutstandingConfigured = !maxOutstanding.required || !!maxOutstanding.amount || !!maxOutstanding.env; const reserveVerifierConfigured = !pair.reserveVerifierKey || (!!runtimeReserveVerifier && hasConfigRef(runtimeReserveVerifier.bridgeRef) && hasConfigRef(runtimeReserveVerifier.verifierRef) && (!runtimeReserveVerifier.requireVaultBacking || hasConfigRef(runtimeReserveVerifier.vaultRef)) && (!runtimeReserveVerifier.requireReserveSystemBalance || hasConfigRef(runtimeReserveVerifier.reserveSystemRef)) && (!runtimeReserveVerifier.requireTokenOwnerMatchVault || hasConfigRef(runtimeReserveVerifier.vaultRef))); const runtimeBridgeReady = !!runtimeL1BridgeAddress && !!runtimeL2BridgeAddress; const runtimeMaxOutstandingReady = !maxOutstanding.required || !!runtimeMaxOutstandingValue; const runtimeReserveVerifierReady = !pair.reserveVerifierKey || (!!runtimeReserveVerifierBridgeAddress && !!runtimeReserveVerifierAddress && (!runtimeReserveVerifier.requireVaultBacking || !!runtimeReserveVaultAddress) && (!runtimeReserveVerifier.requireReserveSystemBalance || !!runtimeReserveSystemAddress) && (!runtimeReserveVerifier.requireTokenOwnerMatchVault || !!runtimeReserveVaultAddress)); const eligibilityBlockers = []; if (!routeDiscoveryEnabled) eligibilityBlockers.push('policy:routeDiscoveryDisabled'); if (!enabledCanonicalTokens.has(normalizeSymbol(canonicalSymbol))) { eligibilityBlockers.push('overlay:canonicalTokenDisabled'); } if (!enabledDestinationChains.has(destinationChainId)) { eligibilityBlockers.push('overlay:destinationChainDisabled'); } if (!mappingEntry) eligibilityBlockers.push('mapping:pairMissing'); if (!isNonZeroAddress(canonicalAddress)) eligibilityBlockers.push('mapping:canonicalAddressMissing'); if (!isNonZeroAddress(mirroredAddress)) { eligibilityBlockers.push( bridgeVersions.mirroredAssetVersion === 'v2' ? 'mapping:mirroredV2AddressMissing' : 'mapping:mirroredAddressMissing' ); } if (pair.assetClass === 'gas_native' && !getGasAssetFamily(pair.familyKey || canonicalSymbol, activeJsonPath)) { eligibilityBlockers.push('config:gasAssetFamilyMissing'); } if (pair.protocolExposureKey && !protocolExposure) { eligibilityBlockers.push('config:gasProtocolExposureMissing'); } if (!mirrorDeployed) eligibilityBlockers.push('deployment:mirroredTokenNotDeployed'); if (!bridgePeerConfigured) eligibilityBlockers.push('config:bridgePeerRefMissing'); if (!maxOutstandingConfigured) eligibilityBlockers.push('config:maxOutstandingRefMissing'); if (!reserveVerifierConfigured) eligibilityBlockers.push('config:reserveVerifierRefMissing'); const eligible = eligibilityBlockers.length === 0; const runtimeMissingRequirements = []; if (!runtimeL1BridgeAddress) runtimeMissingRequirements.push('bridge:l1Bridge'); if (!runtimeL2BridgeAddress) runtimeMissingRequirements.push('bridge:l2Bridge'); if (maxOutstanding.required && !runtimeMaxOutstandingValue) { runtimeMissingRequirements.push('policy:maxOutstanding'); } if (pair.reserveVerifierKey) { if (!runtimeReserveVerifierBridgeAddress) runtimeMissingRequirements.push('reserveVerifier:bridgeRef'); if (!runtimeReserveVerifierAddress) runtimeMissingRequirements.push('reserveVerifier:verifierRef'); if (runtimeReserveVerifier?.requireVaultBacking && !runtimeReserveVaultAddress) { runtimeMissingRequirements.push('reserveVerifier:vaultRef'); } if (runtimeReserveVerifier?.requireReserveSystemBalance && !runtimeReserveSystemAddress) { runtimeMissingRequirements.push('reserveVerifier:reserveSystemRef'); } } if (supplyInvariant.inputsReady === false) { runtimeMissingRequirements.push(...supplyInvariant.blockers); } else if (supplyInvariant.valid === false) { runtimeMissingRequirements.push(...supplyInvariant.blockers); } if (deploymentChain?.bridgeAvailable === false) { runtimeMissingRequirements.push('deployment:bridgeUnavailable'); } const runtimeReady = eligible && runtimeMissingRequirements.length === 0; return { ...pair, canonicalChainId, destinationChainId, destinationChainName: (destinationConfig && typeof destinationConfig.name === 'string' && destinationConfig.name.trim()) || (peer && typeof peer.chainName === 'string' && peer.chainName.trim()) || null, canonicalSymbol, mirroredSymbol, bridgeCanonicalAssetVersion: bridgeVersions.canonicalAssetVersion, bridgeMirroredAssetVersion: bridgeVersions.mirroredAssetVersion, destinationChainSelector: destinationChainSelector || null, canonicalAddress, mirroredAddress, mirrorDeploymentAddress, peer, mappingFound: !!mappingEntry, mirrorDeployed, canonicalEnabled: enabledCanonicalTokens.has(normalizeSymbol(canonicalSymbol)), destinationEnabled: enabledDestinationChains.has(destinationChainId), bridgeAvailable: deploymentChain?.bridgeAvailable ?? null, bridgePeerConfigured, maxOutstandingConfigured, reserveVerifierConfigured, runtimeL1BridgeAddress: runtimeL1BridgeAddress || null, runtimeL2BridgeAddress: runtimeL2BridgeAddress || null, runtimeBridgeReady, runtimeMaxOutstandingValue: runtimeMaxOutstandingValue || null, runtimeMaxOutstandingReady, runtimeReserveVerifierBridgeAddress: runtimeReserveVerifierBridgeAddress || null, runtimeReserveVerifierAddress: runtimeReserveVerifierAddress || null, runtimeReserveVaultAddress: runtimeReserveVaultAddress || null, runtimeReserveSystemAddress: runtimeReserveSystemAddress || null, runtimeReserveVerifierReady, runtimeOutstandingValue: runtimeOutstandingValue || null, runtimeEscrowedValue: runtimeEscrowedValue || null, runtimeTreasuryBackedValue: runtimeTreasuryBackedValue || null, runtimeTreasuryCapValue: runtimeTreasuryCapValue || null, runtimeSupplyAccountingReady: supplyInvariant.applicable ? supplyInvariant.inputsReady : null, supplyInvariantSatisfied: supplyInvariant.applicable ? supplyInvariant.valid : null, protocolExposure, runtimeMissingRequirements, eligibilityBlockers, runtimeReady, eligible, }; }); } function getActiveTransportPair(fromChainId, toChainId, criteria = {}, options = {}) { const from = Number(fromChainId); const to = Number(toChainId); const normalizedSymbol = normalizeTransportSymbol( criteria.symbol || criteria.canonicalSymbol || criteria.mirroredSymbol || '' ); const normalizedSourceAddress = normalizeAddress( criteria.address || criteria.sourceTokenAddress || criteria.tokenAddress || '' ); const normalizedTargetAddress = normalizeAddress(criteria.targetTokenAddress || ''); return ( getActiveTransportPairs(options).find((pair) => { const sameDirection = pair.canonicalChainId === from && pair.destinationChainId === to; const reverseDirection = pair.canonicalChainId === to && pair.destinationChainId === from; if (!sameDirection && !reverseDirection) return false; if (normalizedSymbol) { const pairSymbols = new Set([ normalizeTransportSymbol(pair.canonicalSymbol), normalizeTransportSymbol(pair.mirroredSymbol), normalizeSymbol(pair.canonicalSymbol), normalizeSymbol(pair.mirroredSymbol), ]); if (!pairSymbols.has(normalizedSymbol)) return false; } if (normalizedSourceAddress) { const allowedSourceAddresses = sameDirection ? [pair.canonicalAddress, pair.mirroredAddress] : [pair.mirroredAddress, pair.canonicalAddress]; if (!allowedSourceAddresses.some((address) => normalizeAddress(address) === normalizedSourceAddress)) { return false; } } if (normalizedTargetAddress) { const targetAddress = sameDirection ? pair.mirroredAddress : pair.canonicalAddress; if (normalizeAddress(targetAddress) !== normalizedTargetAddress) return false; } return true; }) || null ); } function getKnownMirroredTokenAddresses(chainId, options = {}) { const multichainJsonPath = options.multichainJsonPath || DEFAULT_MULTICHAIN_JSON_PATH; const deploymentJsonPath = options.deploymentJsonPath || DEFAULT_DEPLOYMENT_STATUS_JSON_PATH; const data = loadTokenMappingMultichainJson(multichainJsonPath); const deployment = loadDeploymentStatusJson(deploymentJsonPath); const chainKey = String(Number(chainId)); const out = new Set(); if (deployment && deployment.chains && deployment.chains[chainKey]?.cwTokens) { for (const address of Object.values(deployment.chains[chainKey].cwTokens)) { if (isNonZeroAddress(address)) out.add(normalizeAddress(address)); } } if (deployment && deployment.chains && deployment.chains[chainKey]?.gasMirrors) { for (const address of Object.values(deployment.chains[chainKey].gasMirrors)) { if (isNonZeroAddress(address)) out.add(normalizeAddress(address)); } } if (data && Array.isArray(data.pairs)) { const pair = data.pairs.find((entry) => Number(entry.fromChainId) === 138 && Number(entry.toChainId) === Number(chainId)); if (pair && Array.isArray(pair.tokens)) { for (const token of pair.tokens) { if (String(token.key || '').endsWith('_cW') && isNonZeroAddress(token.addressTo)) { out.add(normalizeAddress(token.addressTo)); } } } } return Array.from(out); } function getActivePublicPools(jsonPath = DEFAULT_GRU_ACTIVE_JSON_PATH) { const data = loadGruTransportActiveJson(jsonPath); if (!data || !Array.isArray(data.publicPools)) return []; return data.publicPools; } function getPublicPoolRecord(chainId, poolAddress, jsonPath = DEFAULT_GRU_ACTIVE_JSON_PATH) { if (!isNonZeroAddress(poolAddress)) return null; const normalizedPoolAddress = normalizeAddress(poolAddress); return ( getActivePublicPools(jsonPath).find( (pool) => Number(pool.chainId) === Number(chainId) && normalizeAddress(pool.poolAddress) === normalizedPoolAddress ) || null ); } function isPublicPoolActive(chainId, poolAddress, jsonPath = DEFAULT_GRU_ACTIVE_JSON_PATH) { const record = getPublicPoolRecord(chainId, poolAddress, jsonPath); return !!record && record.active === true; } function isPublicPoolRoutable(chainId, poolAddress, jsonPath = DEFAULT_GRU_ACTIVE_JSON_PATH) { const record = getPublicPoolRecord(chainId, poolAddress, jsonPath); return !!record && record.active === true && record.routingEnabled === true; } function isPublicPoolMcpVisible(chainId, poolAddress, jsonPath = DEFAULT_GRU_ACTIVE_JSON_PATH) { const record = getPublicPoolRecord(chainId, poolAddress, jsonPath); return !!record && record.active === true && record.mcpVisible === true; } function shouldExposePublicPool( chainId, poolAddress, token0Address, token1Address, activeJsonPath = DEFAULT_GRU_ACTIVE_JSON_PATH, multichainJsonPath = DEFAULT_MULTICHAIN_JSON_PATH, deploymentJsonPath = DEFAULT_DEPLOYMENT_STATUS_JSON_PATH ) { const mirroredAddresses = new Set(getKnownMirroredTokenAddresses(chainId, { multichainJsonPath, deploymentJsonPath })); const touchesMirroredToken = mirroredAddresses.has(normalizeAddress(token0Address)) || mirroredAddresses.has(normalizeAddress(token1Address)); if (!touchesMirroredToken) return true; return isPublicPoolActive(chainId, poolAddress, activeJsonPath); } function shouldUsePublicPoolForRouting( chainId, poolAddress, token0Address, token1Address, activeJsonPath = DEFAULT_GRU_ACTIVE_JSON_PATH, multichainJsonPath = DEFAULT_MULTICHAIN_JSON_PATH, deploymentJsonPath = DEFAULT_DEPLOYMENT_STATUS_JSON_PATH ) { const mirroredAddresses = new Set(getKnownMirroredTokenAddresses(chainId, { multichainJsonPath, deploymentJsonPath })); const touchesMirroredToken = mirroredAddresses.has(normalizeAddress(token0Address)) || mirroredAddresses.has(normalizeAddress(token1Address)); if (!touchesMirroredToken) return true; return isPublicPoolRoutable(chainId, poolAddress, activeJsonPath); } module.exports = { loadTokenMappingJson, loadTokenMappingMultichainJson, loadGruTransportActiveJson, loadRoutingRegistryJson, loadDeploymentStatusJson, loadPoolMatrixJson, getRelayTokenMapping, getTokenList, getTokenMappingForPair, getAllMultichainPairs, getMappedAddress, getRoutingRegistryRoutes, getGruTransportMetadata, getEnabledCanonicalTokens, getEnabledCanonicalToken, getEnabledDestinationChains, getGasAssetFamilies, getGasAssetFamily, getGasRedeemGroups, getGasProtocolExposure, getGasProtocolExposureRecord, isGasRedemptionPathAllowed, isCanonicalTokenActive, isDestinationChainActive, getApprovedBridgePeer, getBridgeAssetVersionsForCanonicalSymbol, resolveGruIso4217BridgeAddresses, evaluateTransportSupplyInvariant, getActiveTransportPairs, getActiveTransportPair, getKnownMirroredTokenAddresses, getActivePublicPools, isPublicPoolActive, isPublicPoolRoutable, isPublicPoolMcpVisible, shouldExposePublicPool, shouldUsePublicPoolForRouting, resolveConfigRef, isNonZeroAddress, DEFAULT_JSON_PATH, DEFAULT_MULTICHAIN_JSON_PATH, DEFAULT_GRU_ACTIVE_JSON_PATH, DEFAULT_ROUTING_REGISTRY_JSON_PATH, DEFAULT_DEPLOYMENT_STATUS_JSON_PATH, DEFAULT_POOL_MATRIX_JSON_PATH, };