/**
 * Canonical token list for GRU base money, W-tokens, asset (ac*), and debt (vdc* / sdc*) tokens.
 * Used for CMC/CoinGecko reporting and token-aggregation indexing.
 * Addresses can be overridden via env (e.g. CUSDC_ADDRESS_138) or filled by indexer.
 */

import { isISO4217Supported } from './iso4217-symbol-registry';
import { isMonetaryUnitSupported } from './monetary-unit-symbol-registry';
import { loadTokenMappingLoader } from './repo-config-loader';
import {
  getCapitalMarketsClassification,
  type CapitalMarketsFields,
} from './capital-markets-taxonomy';

export type TokenType = 'base' | 'w' | 'asset' | 'debt';
export type TokenRegistryFamily = 'iso4217' | 'commodity' | 'monetary_unit' | 'gas_native' | 'unclassified';

export interface CanonicalTokenSpec {
  symbol: string;
  name: string;
  type: TokenType;
  decimals: number;
  currencyCode?: string;
  registryFamily?: TokenRegistryFamily;
  /** ChainId -> contract address (placeholder or from env) */
  addresses: Partial<Record<number, string>>;
  description?: string;
  websiteUrl?: string;
  logoUrl?: string;
  /** v1 matrix symbol for origin reference only (e.g. cXUSDC when bridged); on Chain 138 symbol is v0 only (no X) */
  v1Symbol?: string;
  /** v0 symbol alias; on ChainID 138 tokens use v0 only (cUSDC, cUSDT), no chain designator */
  v0Alias?: string;
  /** Shared family symbol when multiple on-chain deployments exist for the same monetary unit. */
  familySymbol?: string;
  /** Deployment version when a family has multiple contract surfaces. */
  deploymentVersion?: string;
  /** Deployment lifecycle status (for example active or staged). */
  deploymentStatus?: string;
  /** Whether this deployment is the preferred x402 / permit-capable surface. */
  preferredForX402?: boolean;
  /** Symbol whose current liquidity should be used for quote fallback until cutover. */
  liquiditySourceSymbol?: string;
  /** Institutional capital-markets taxonomy (from rwa-capital-markets-taxonomy.v1.json). */
  capitalMarkets?: CapitalMarketsFields;
}

interface GruTransportDeployment {
  version?: string;
  address?: string;
  status?: string;
}

interface GruTransportCanonicalToken {
  symbol?: string;
  activeVersion?: string;
  activeAddress?: string;
  x402PreferredVersion?: string;
  x402PreferredAddress?: string;
  deployments?: GruTransportDeployment[];
}

const CHAIN_138 = 138;
const CHAIN_25 = 25; // Cronos
const CHAIN_651940 = 651940;
const LEGACY_CHAIN_ENV_SUFFIX: Partial<Record<number, string>> = {
  1: 'MAINNET',
  10: 'OPTIMISM',
  25: 'CRONOS',
  56: 'BSC',
  100: 'GNOSIS',
  137: 'POLYGON',
  42161: 'ARBITRUM',
  43114: 'AVALANCHE',
  8453: 'BASE',
};
/** L2/mainnet chain IDs for cUSDT/cUSDC multichain (env: CUSDT_ADDRESS_56, CUSDC_ADDRESS_137, etc.) */
const L2_CHAIN_IDS = [1, 56, 137, 10, 42161, 8453, 43114, 25, 100, 42220, 1111] as const;
const GRU_CW_CHAIN_IDS = [1, 10, 25, 56, 100, 137, 8453, 42161, 42220, 43114] as const;
const BTC_CW_CHAIN_IDS = [1, 10, 25, 56, 100, 137, 42161, 42220, 43114, 8453, 1111] as const;
const ETH_MAINNET_CW_CHAIN_IDS = [1] as const;
const ETH_L2_CW_CHAIN_IDS = [10, 42161, 8453] as const;
const BNB_CW_CHAIN_IDS = [56] as const;
const POL_CW_CHAIN_IDS = [137] as const;
const AVAX_CW_CHAIN_IDS = [43114] as const;
const CRO_CW_CHAIN_IDS = [25] as const;
const XDAI_CW_CHAIN_IDS = [100] as const;
const CELO_CW_CHAIN_IDS = [42220] as const;
const WEMIX_CW_CHAIN_IDS = [1111] as const;
/** Verified addresses from CHAIN138_TOKEN_ADDRESSES, .env, and deployment summaries */
const FALLBACK_ADDRESSES: Record<string, Partial<Record<number, string>>> = {
  USDC: {
    [CHAIN_138]: '0x71D6687F38b93CCad569Fa6352c876eea967201b',
  },
  USDT: {
    [CHAIN_138]: '0x004b63A7B5b0E06f6bB6adb4a5F9f590BF3182D1',
  },
  cUSDC: {
    [CHAIN_138]: '0xf22258f57794CC8E06237084b353Ab30fFfa640b',
    [CHAIN_651940]: '0xa95EeD79f84E6A0151eaEb9d441F9Ffd50e8e881', // AUSDC on ALL Mainnet
    [1]: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48', // Ethereum USDC
    [56]: '0x8AC76a51cc950d9822D68b83fE1Ad97B32Cd580d', // BSC USDC
    [137]: '0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359', // Polygon USDC
    [100]: '0xDDAfbb505ad214D7b80b1f830fcCc89B60fb7A83', // Gnosis USDC
    [10]: '0x0b2C639c533813f4Aa9D7837CAf62653d097Ff85', // Optimism USDC
    [42161]: '0xaf88d065e77c8cC2239327C5EDb3A432268e5831', // Arbitrum USDC
    [8453]: '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913', // Base USDC
    [43114]: '0xB97EF9Ef8734C71904D8002F8b6Bc66Dd9c48a6E', // Avalanche USDC
    [CHAIN_25]: '0xc21223249CA28397B4B6541dfFaEcC539BfF0c59', // Cronos USDC
    [42220]: '0xcebA9300f2b948710d2653dD7B07f33A8B32118C', // Celo USDC
    [1111]: '0xE3F5a90F9cb311505cd691a46596599aA1A0AD7D', // Wemix USDC
  },
  cUSDT: {
    [CHAIN_138]: '0x93E66202A11B1772E55407B32B44e5Cd8eda7f22',
    [CHAIN_651940]: '0x015B1897Ed5279930bC2Be46F661894d219292A6', // AUSDT primary on ALL Mainnet
    [1]: '0xdAC17F958D2ee523a2206206994597C13D831ec7', // Ethereum USDT
    [56]: '0x55d398326f99059fF775485246999027B3197955', // BSC USDT
    [137]: '0xc2132D05D31c914a87C6611C10748AEb04B58e8F', // Polygon USDT
    [100]: '0x4ECaBa5870353805a9F068101A40E0f32ed605C6', // Gnosis USDT
    [10]: '0x94b008aA00579c1307B0EF2c499aD98a8ce58e58', // Optimism USDT
    [42161]: '0xFd086bC7CD5C481DCC9C85ebE478A1C0b69FCbb9', // Arbitrum USDT
    [8453]: '0xfde4C96c8593536E31F229EA8f37b2ADa2699bb2', // Base USDT
    [43114]: '0x9702230A8Ea53601f5cD2dc00fDBc13d4dF4A8c7', // Avalanche USDT
    [CHAIN_25]: '0x66e428c3f67a68878562e79A0234c1F83c208770', // Cronos USDT
    [42220]: '0x48065fbBE25f71C9282ddf5e1cD6D6A887483D5e', // Celo USDT
    [1111]: '0xA649325Aa7C5093d12D6F98EB4378deAe68CE23F', // Wemix USDT
  },
  cUSDC_V2: {
    [CHAIN_138]: '0x219522c60e83dEe01FC5b0329d6fA8fD84b9D13d',
  },
  cUSDT_V2: {
    [CHAIN_138]: '0x9FBfab33882Efe0038DAa608185718b772EE5660',
  },
  LiXAU: {
    [CHAIN_138]: '0xff862f0d1f96aa4882a0c2d6b4a3516fd8d68e75',
  },
  LiPMG: {
    [CHAIN_138]: '0x148b0f5c6fc8c5975e9406635654d88b20db2ed6',
  },
  LiBMG1: {
    [CHAIN_138]: '0xc5b802662447d1ae492a1618c3ad7161a449ebc9',
  },
  LiBMG2: {
    [CHAIN_138]: '0x2ca3b3e7f4f216015833b0b334273d44493c0c45',
  },
  LiBMG3: {
    [CHAIN_138]: '0xb03d872196c0e84fe6fae841335001db44bda6c7',
  },
  cUSDW: {
    [CHAIN_138]: '0xcA6BFa614935f1AB71c9aB106bAA6FBB6057095e',
  },
  // ALL / AUSDT corridor hub on Chain 138 (see config/smart-contracts-master.json COMPLIANT_AUSDT_ADDRESS)
  cAUSDT: {
    [CHAIN_138]: '0x5fdDF65733e3d590463F68f93Cf16E8c04081271',
  },
  cBTC: {
    [CHAIN_138]: '0xe94260c555ac1d9d3cc9e1632883452ebdf0082e',
  },
  cETH: {
    [CHAIN_138]: '0xce7e00000000000000000000000000000000008a',
  },
  cETHL2: {
    [CHAIN_138]: '0xce7200000000000000000000000000000000008a',
  },
  cBNB: {
    [CHAIN_138]: '0xcb6b00000000000000000000000000000000008a',
  },
  cPOL: {
    [CHAIN_138]: '0xc90100000000000000000000000000000000008a',
  },
  cAVAX: {
    [CHAIN_138]: '0xcaaa00000000000000000000000000000000008a',
  },
  cCRO: {
    [CHAIN_138]: '0xcc2000000000000000000000000000000000008a',
  },
  cXDAI: {
    [CHAIN_138]: '0xcda100000000000000000000000000000000008a',
  },
  cCELO: {
    [CHAIN_138]: '0xcce100000000000000000000000000000000008a',
  },
  cWEMIX: {
    [CHAIN_138]: '0xc11100000000000000000000000000000000008a',
  },
  cWAUSDT: {
    [1]: '0xe1a51Bc037a79AB36767561B147eb41780124934',
    [56]: '0xe1a51Bc037a79AB36767561B147eb41780124934',
    [137]: '0xf12e262F85107df26741726b074606CaFa24AAe7',
    [42220]: '0xC158b6cD3A3088C52F797D41f5Aa02825361629e',
    [43114]: '0xff3084410A732231472Ee9f93F5855dA89CC5254',
  },
  cWUSDC: {
    [1]: '0x2de5F116bFcE3d0f922d9C8351e0c5Fc24b9284a',
    [10]: '0x377a5FaA3162b3Fc6f4e267301A3c817bAd18105',
    [25]: '0x932566E5bB6BEBF6B035B94f3DE1f75f126304Ec',
    [56]: '0x5355148C4740fcc3D7a96F05EdD89AB14851206b',
    [100]: '0xd6969bC19b53f866C64f2148aE271B2Dae0C58E4',
    [137]: '0xd6969bC19b53f866C64f2148aE271B2Dae0C58E4',
    [8453]: '0x377a5FaA3162b3Fc6f4e267301A3c817bAd18105',
    [42161]: '0x0cb0192C056aa425C557BdeAD8E56C7eEabf7acF',
    [42220]: '0x4C38F9A5ed68A04cd28a72E8c68C459Ec34576f3',
    [43114]: '0x0C242b513008Cd49C89078F5aFb237A3112251EB',
  },
  cWUSDT: {
    [1]: '0xaF5017d0163ecb99D9B5D94e3b4D7b09Af44D8AE',
    [10]: '0x04B2AE3c3bb3d70Df506FAd8717b0FBFC78ED7E6',
    [25]: '0x72948a7a813B60b37Cd0c920C4657DbFF54312b8',
    [56]: '0x9a1D0dBEE997929ED02fD19E0E199704d20914dB',
    [100]: '0x0cb0192C056aa425C557BdeAD8E56C7eEabf7acF',
    [137]: '0x0cb0192C056aa425C557BdeAD8E56C7eEabf7acF',
    [8453]: '0x04B2AE3c3bb3d70Df506FAd8717b0FBFC78ED7E6',
    [42161]: '0x73ADaF7dBa95221c080db5631466d2bC54f6a76B',
    [42220]: '0x73376eB92c16977B126dB9112936A20Fa0De3442',
    [43114]: '0x8142BA530B08f3950128601F00DaaA678213DFdf',
  },
  cWEURC: {
    [1]: '0xD4aEAa8cD3fB41Dc8437FaC7639B6d91B60A5e8d',
    [10]: '0x4ab39b5bab7b463435209a9039bd40cf241f5a82',
    [25]: '0x7574d37F42528B47c88962931e48FC61608a4050',
    [56]: '0x50b073d0D1D2f002745cb9FC28a057d5be84911c',
    [100]: '0x25603ae4bff0b71d637b3573d1b6657f5f6d17ef',
    [137]: '0x3CD9ee18db7ad13616FCC1c83bC6098e03968E66',
    [8453]: '0xcb145ba9a370681e3545f60e55621ebf218b1031',
    [42161]: '0x2a0023ad5ce1ac6072b454575996dffb1bb11b16',
    [42220]: '0xb6D2f38b9015F32ccE8818509c712264E7fceeD3',
    [43114]: '0x84353ed1f0c7a703a17abad19b0db15bc9a5e3e5',
  },
  cWEURT: {
    [1]: '0x855d74FFB6CF75721a9bAbc8B2ed35c8119241dC',
    [10]: '0x6f521cd9fcf7884cd4e9486c7790e818638e09dd',
    [25]: '0x9f833b4f1012F52eb3317b09922a79c6EdFca77D',
    [56]: '0x1ED9E491A5eCd53BeF21962A5FCE24880264F63f',
    [100]: '0x8e54c52d34a684e22865ac9f2d7c27c30561a7b9',
    [137]: '0xBeF5A0Bcc0E77740c910f197138cdD90F98d2427',
    [8453]: '0x73e0cf8bf861d376b3a4c87c136f975027f045ff',
    [42161]: '0x22b98130ab4d9c355512b25ade4c35e75a4e7e89',
    [42220]: '0x7e6fB8D80f81430e560F8232b2A4fd06249d74ce',
    [43114]: '0xfc7d256e48253f7a7e08f0e55b9ff7039eb2524c',
  },
  cWGBPC: {
    [1]: '0xc074007dc0bfb384b1cf6426a56287ed23fe4d52',
    [10]: '0x3f8c409c6072a2b6a4ff17071927ba70f80c725f',
    [25]: '0xe5c65A76A541368d3061fe9E7A2140cABB903dbF',
    [56]: '0x8b6EE72001cAFcb21D56a6c4686D6Db951d499A6',
    [100]: '0x4d9bc6c74ba65e37c4139f0aec9fc5ddff28dcc4',
    [137]: '0x948690147D2e50ffe50C5d38C14125aD6a9FA036',
    [8453]: '0x2a0023ad5ce1ac6072b454575996dffb1bb11b16',
    [42161]: '0xa846aead3071df1b6439d5d813156ace7c2c1da1',
    [42220]: '0xE37c332a88f112F9e039C5d92D821402A89c7052',
    [43114]: '0xbdf0c4ea1d81e8e769b0f41389a2c733e3ff723e',
  },
  cWGBPT: {
    [1]: '0x1dDF9970F01c76A692Fdba2706203E6f16e0C46F',
    [10]: '0x456373d095d6b9260f01709f93fccf1d8aa14d11',
    [25]: '0xBb58fa16bAc8E789f09C14243adEE6480D8213A2',
    [56]: '0xA6eFb8783C8ad2740ec880e46D4f7E608E893B1B',
    [100]: '0x9f6d2578003fe04e58a9819a4943732f2a203a61',
    [137]: '0x58a8D8F78F1B65c06dAd7542eC46b299629A60dd',
    [8453]: '0x22b98130ab4d9c355512b25ade4c35e75a4e7e89',
    [42161]: '0x29828e9ab2057cd3df3c9211455ae1f76e53d2af',
    [42220]: '0x1dBa81f91f1BeC47FFf60eC3e7DeD780ad9968E3',
    [43114]: '0x4611d3424e059392a52b957e508273bc761c80f2',
  },
  cWAUDC: {
    [1]: '0x5020Db641B3Fc0dAbBc0c688C845bc4E3699f35F',
    [10]: '0x25603ae4bff0b71d637b3573d1b6657f5f6d17ef',
    [25]: '0xff3084410A732231472Ee9f93F5855dA89CC5254',
    [56]: '0x7062f35567BBAb4d98dc33af03B0d14Df42294D5',
    [100]: '0xddc4063f770f7c49d00b5a10fb552e922aa39b2c',
    [137]: '0xFb4B6Cc81211F7d886950158294A44C312abCA29',
    [8453]: '0xa846aead3071df1b6439d5d813156ace7c2c1da1',
    [42161]: '0xc1535e88578d984f12eab55863376b8d8b9fb05a',
    [42220]: '0x2d3a2ED4Ca4d69912d217c305EE921609F7906A8',
    [43114]: '0x04e1e22b0d41e99f4275bd40a50480219bc9a223',
  },
  cWJPYC: {
    [1]: '0x07EEd0D7dD40984e47B9D3a3bdded1c536435582',
    [10]: '0x8e54c52d34a684e22865ac9f2d7c27c30561a7b9',
    [25]: '0x52aD62B8bD01154e2A4E067F8Dc4144C9988d203',
    [56]: '0x5fbCE65524211BC1bFb0309fd9EE09E786c6D097',
    [100]: '0x145e8e8c49b6a021969dd9d2c01c8fea44374f61',
    [137]: '0xf9f5D0ACD71C76F9476F10B3F3d3E201F0883C68',
    [8453]: '0x29828e9ab2057cd3df3c9211455ae1f76e53d2af',
    [42161]: '0xdc383c489533a4dd9a6bd3007386e25d5078b878',
    [42220]: '0x0b39F47D2E68aB0eB18d4b637Bbd1dD8E97cFbB5',
    [43114]: '0x3714b1a312e0916c7dcdc4edf480fc0339e59a59',
  },
  cWCHFC: {
    [1]: '0x0F91C5E6Ddd46403746aAC970D05d70FFe404780',
    [10]: '0x4d9bc6c74ba65e37c4139f0aec9fc5ddff28dcc4',
    [25]: '0xB55F49D6316322d5caA96D34C6e4b1003BD3E670',
    [56]: '0xD9f8710caeeBA3b3D423D7D14a918701426B5ef3',
    [100]: '0x46d90d7947f1139477c206c39268923b99cf09e4',
    [137]: '0xeE17bB0322383fecCA2784fbE2d4CD7d02b1905B',
    [8453]: '0xc1535e88578d984f12eab55863376b8d8b9fb05a',
    [42161]: '0x7e4b4682453bcce19ec903fb69153d3031986bc4',
    [42220]: '0x8142BA530B08f3950128601F00DaaA678213DFdf',
    [43114]: '0xc2fa05f12a75ac84ea778af9d6935ca807275e55',
  },
  cWCADC: {
    [1]: '0x209FE32fe7B541751D190ae4e50cd005DcF8EDb4',
    [10]: '0x9f6d2578003fe04e58a9819a4943732f2a203a61',
    [25]: '0x32aD687F24F77bF8C86605c202c829163Ac5Ab36',
    [56]: '0x9AE7a6B311584D60Fa93f973950d609061875775',
    [100]: '0xa7133c78e0ec74503a5941bcbd44257615b6b4f6',
    [137]: '0xc9750828124D4c10e7a6f4B655cA8487bD3842EB',
    [8453]: '0xdc383c489533a4dd9a6bd3007386e25d5078b878',
    [42161]: '0xcc6ae6016d564e9ab82aaff44d65e05a9b18951c',
    [42220]: '0x0C242b513008Cd49C89078F5aFb237A3112251EB',
    [43114]: '0x1872e033b30f3ce0498847926857433e0146394e',
  },
  cWXAUC: {
    [1]: '0x572Be0fa8CA0534d642A567CEDb398B771D8a715',
    [10]: '0xddc4063f770f7c49d00b5a10fb552e922aa39b2c',
    [25]: '0xf1B771c95573113E993374c0c7cB2dc1a7908B12',
    [56]: '0xCB145bA9A370681e3545F60e55621eBf218B1031',
    [100]: '0x23873b85cfeb343eb952618e8c9e9bfb7f6a0d45',
    [137]: '0x328Cd365Bb35524297E68ED28c6fF2C9557d1363',
    [8453]: '0x7e4b4682453bcce19ec903fb69153d3031986bc4',
    [42161]: '0xa7762b63c4871581885ad17c5714ebb286a7480b',
    [42220]: '0x61D642979eD75c1325f35b9275C5A7FE97F22451',
    [43114]: '0x4f95297c23d9f4a1032b1c6a2e553225cb175bee',
  },
  cWXAUT: {
    [1]: '0xACE1DBF857549a11aF1322e1f91F2F64b029c906',
    [10]: '0x145e8e8c49b6a021969dd9d2c01c8fea44374f61',
    [25]: '0xD517C0cF7013f988946A468c880Cc9F8e2A4BCbE',
    [56]: '0x73E0CF8BF861D376B3a4C87c136F975027f045ff',
    [100]: '0xc6189d404dc60cae7b48e2190e44770a03193e5f',
    [137]: '0x9e6044d730d4183bF7a666293d257d035Fba6d44',
    [8453]: '0xcc6ae6016d564e9ab82aaff44d65e05a9b18951c',
    [42161]: '0x66568899ffe8f00b25dc470e878b65a478994e76',
    [42220]: '0x30751782486eed825187C1EAe5DE4b4baD428AaE',
    [43114]: '0xd2b4dbf2f6bd6704e066d752eec61fb0be953fd3',
  },
  cWUSDW: {
    [56]: '0xC2FA05F12a75Ac84ea778AF9D6935cA807275E55',
    [42220]: '0x176a1b6Aa59F24B3aa65F2b697AB262Bca9093B5',
    [43114]: '0xcfdCe5E660FC2C8052BDfa7aEa1865DD753411Ae',
  },
  cWBTC: {
    [1]: '0x2BBe3c809386FA5349EB2da31E0848ee9f54EE59',
    [10]: '0xcb7c00000000000000000000000000000000000a',
    [25]: '0xcb7c000000000000000000000000000000000019',
    [56]: '0xcb7c000000000000000000000000000000000038',
    [100]: '0xcb7c000000000000000000000000000000000064',
    [137]: '0xcb7c000000000000000000000000000000000089',
    [1111]: '0xcb7c000000000000000000000000000000000457',
    [8453]: '0xcb7c000000000000000000000000000000002105',
    [42161]: '0xcb7c00000000000000000000000000000000a4b1',
    [42220]: '0xcb7c00000000000000000000000000000000a4ec',
    [43114]: '0xcb7c00000000000000000000000000000000a86a',
  },
  cWETH: {
    [1]: '0xce7e000000000000000000000000000000000001',
  },
  cWETHL2: {
    [10]: '0xce7200000000000000000000000000000000000a',
    [42161]: '0xce7200000000000000000000000000000000a4b1',
    [8453]: '0xce72000000000000000000000000000000002105',
  },
  cWBNB: {
    [56]: '0xcb6b000000000000000000000000000000000038',
  },
  cWPOL: {
    [137]: '0xc901000000000000000000000000000000000089',
  },
  cWAVAX: {
    [43114]: '0xcaaa00000000000000000000000000000000a86a',
  },
  cWCRO: {
    [25]: '0xcc20000000000000000000000000000000000019',
  },
  cWXDAI: {
    [100]: '0xcda1000000000000000000000000000000000064',
  },
  cWCELO: {
    [42220]: '0xcce100000000000000000000000000000000a4ec',
  },
  cWWEMIX: {
    [1111]: '0xc111000000000000000000000000000000000457',
  },
  // Compliant Fiat on Chain 138 - from DeployCompliantFiatTokens (2026-02-27)
  cEURC: { [CHAIN_138]: '0x8085961F9cF02b4d800A3c6d386D31da4B34266a' },
  cEURT: { [CHAIN_138]: '0xdf4b71c61E5912712C1Bdd451416B9aC26949d72' },
  cGBPC: { [CHAIN_138]: '0x003960f16D9d34F2e98d62723B6721Fb92074aD2' },
  cGBPT: { [CHAIN_138]: '0x350f54e4D23795f86A9c03988c7135357CCaD97c' },
  cAUDC: { [CHAIN_138]: '0xD51482e567c03899eecE3CAe8a058161FD56069D' },
  cJPYC: { [CHAIN_138]: '0xEe269e1226a334182aace90056EE4ee5Cc8A6770' },
  cCHFC: { [CHAIN_138]: '0x873990849DDa5117d7C644f0aF24370797C03885' },
  cCADC: { [CHAIN_138]: '0x54dBd40cF05e15906A2C21f600937e96787f5679' },
  cXAUC: { [CHAIN_138]: '0x290E52a8819A4fbD0714E517225429aA2B70EC6b' },
  cXAUT: { [CHAIN_138]: '0x94e408E26c6FD8F4ee00b54dF19082FDA07dC96E' },
  LINK: { [CHAIN_138]: '0xb7721dD53A8c629d9f1Ba31a5819AFe250002b03' },
  WETH: { [CHAIN_138]: '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2' },
  WETH10: { [CHAIN_138]: '0xf4BB2e28688e89fCcE3c0580D37d36A7672E8A9f' },
  // ISO-4217W on Cronos (25) - from DeployISO4217WSystem
  USDW: { [CHAIN_25]: '0x948690147D2e50ffe50C5d38C14125aD6a9FA036' },
  EURW: { [CHAIN_25]: '0x58a8D8F78F1B65c06dAd7542eC46b299629A60dd' },
  GBPW: { [CHAIN_25]: '0xFb4B6Cc81211F7d886950158294A44C312abCA29' },
  AUDW: { [CHAIN_25]: '0xf9f5D0ACD71C76F9476F10B3F3d3E201F0883C68' },
  JPYW: { [CHAIN_25]: '0xeE17bB0322383fecCA2784fbE2d4CD7d02b1905B' },
  CHFW: { [CHAIN_25]: '0xc9750828124D4c10e7a6f4B655cA8487bD3842EB' },
  CADW: { [CHAIN_25]: '0x328Cd365Bb35524297E68ED28c6fF2C9557d1363' },
};

function normalizeAddress(address?: string | null): string {
  return typeof address === 'string' ? address.trim().toLowerCase() : '';
}

function getGruTransportCanonicalToken(symbol: string): GruTransportCanonicalToken | null {
  const loader = loadTokenMappingLoader<{
    getEnabledCanonicalToken?: (identifier: string) => GruTransportCanonicalToken | null;
  }>();
  return loader?.getEnabledCanonicalToken?.(symbol) ?? null;
}

function getTransportLookup(symbol: string): { baseSymbol: string; version: 'v1' | 'v2' } | null {
  if (symbol === 'cUSDT' || symbol === 'cUSDC') {
    return { baseSymbol: symbol, version: 'v1' };
  }
  if (symbol === 'cUSDT_V2') {
    return { baseSymbol: 'cUSDT', version: 'v2' };
  }
  if (symbol === 'cUSDC_V2') {
    return { baseSymbol: 'cUSDC', version: 'v2' };
  }
  return null;
}

function getTransportDeploymentAddress(symbol: string, version: 'v1' | 'v2'): string | undefined {
  const token = getGruTransportCanonicalToken(symbol);
  if (!token) return undefined;

  const deploymentMatch = Array.isArray(token.deployments)
    ? token.deployments.find((deployment) => String(deployment.version || '').trim().toLowerCase() === version)
    : null;
  if (deploymentMatch?.address) return deploymentMatch.address;

  if (version === 'v1') {
    if (String(token.activeVersion || '').trim().toLowerCase() === 'v1' && token.activeAddress) {
      return token.activeAddress;
    }
  } else if (String(token.x402PreferredVersion || '').trim().toLowerCase() === 'v2' && token.x402PreferredAddress) {
    return token.x402PreferredAddress;
  }

  return undefined;
}

function addr(symbol: string, chainId: number): string | undefined {
  if (chainId === CHAIN_138 && symbol === 'USDT') {
    return process.env.USDT_ADDRESS_138 || process.env.OFFICIAL_USDT_ADDRESS || FALLBACK_ADDRESSES[symbol]?.[chainId];
  }
  if (chainId === CHAIN_138 && symbol === 'USDC') {
    return process.env.USDC_ADDRESS_138 || process.env.OFFICIAL_USDC_ADDRESS || FALLBACK_ADDRESSES[symbol]?.[chainId];
  }
  if (chainId === CHAIN_138) {
    const transportLookup = getTransportLookup(symbol);
    if (transportLookup) {
      const envKey = `${symbol.replace(/-/g, '_').toUpperCase()}_ADDRESS_${chainId}`;
      const envVal = process.env[envKey];
      if (envVal && envVal.trim() !== '') return envVal;
      return (
        getTransportDeploymentAddress(transportLookup.baseSymbol, transportLookup.version) ||
        FALLBACK_ADDRESSES[symbol]?.[chainId]
      );
    }
  }
  const key = `${symbol.replace(/-/g, '_').toUpperCase()}_ADDRESS_${chainId}`;
  const envVal = process.env[key];
  if (envVal && envVal.trim() !== '') return envVal;
  const legacySuffix = LEGACY_CHAIN_ENV_SUFFIX[chainId];
  if (legacySuffix) {
    const legacyKey = `${symbol.replace(/-/g, '_').toUpperCase()}_${legacySuffix}`;
    const legacyVal = process.env[legacyKey];
    if (legacyVal && legacyVal.trim() !== '') return legacyVal;
  }
  return FALLBACK_ADDRESSES[symbol]?.[chainId];
}

export const CANONICAL_TOKENS: CanonicalTokenSpec[] = [
  // --- Base (GRU-M1) ---
  // Local Chain 138 quote-side mirror stables used by PMM pools.
  { symbol: 'USDC', name: 'USD Coin (Official Mirror)', type: 'base', decimals: 6, currencyCode: 'USD', addresses: { [CHAIN_138]: addr('USDC', CHAIN_138) || '' } },
  { symbol: 'USDT', name: 'Tether USD (Official Mirror)', type: 'base', decimals: 6, currencyCode: 'USD', addresses: { [CHAIN_138]: addr('USDT', CHAIN_138) || '' } },
  // Chain 138 v0 only (no X): cUSDC on 138; cXUSDC used only for bridged/origin reference elsewhere. See ISO4217_COMPLIANT_TOKEN_MATRIX.md
  { symbol: 'cUSDC', name: 'USD Coin (Compliant)', type: 'base', decimals: 6, currencyCode: 'USD', v0Alias: 'cUSDC', addresses: { [CHAIN_138]: addr('cUSDC', CHAIN_138) || '', [CHAIN_651940]: addr('cUSDC', CHAIN_651940) || '', ...Object.fromEntries(L2_CHAIN_IDS.map((id) => [id, addr('cUSDC', id)])) } },
  { symbol: 'cUSDC_V2', name: 'USD Coin (Compliant V2)', type: 'base', decimals: 6, currencyCode: 'USD', familySymbol: 'cUSDC', deploymentVersion: 'v2', deploymentStatus: 'staged', preferredForX402: true, liquiditySourceSymbol: 'cUSDC', description: 'Chain 138 x402 / permit-capable V2 deployment. Liquidity and PMM routing remain on cUSDC until cutover.', addresses: { [CHAIN_138]: addr('cUSDC_V2', CHAIN_138) || '' } },
  // Chain 138 v0 only (no X): cUSDT on 138; cXUSDT used only for bridged/origin reference elsewhere. See ISO4217_COMPLIANT_TOKEN_MATRIX.md
  { symbol: 'cUSDT', name: 'Tether USD (Compliant)', type: 'base', decimals: 6, currencyCode: 'USD', v0Alias: 'cUSDT', addresses: { [CHAIN_138]: addr('cUSDT', CHAIN_138) || '', [CHAIN_651940]: addr('cUSDT', CHAIN_651940) || '', ...Object.fromEntries(L2_CHAIN_IDS.map((id) => [id, addr('cUSDT', id)])) } },
  { symbol: 'cUSDT_V2', name: 'Tether USD (Compliant V2)', type: 'base', decimals: 6, currencyCode: 'USD', familySymbol: 'cUSDT', deploymentVersion: 'v2', deploymentStatus: 'staged', preferredForX402: true, liquiditySourceSymbol: 'cUSDT', description: 'Chain 138 x402 / permit-capable V2 deployment. Liquidity and PMM routing remain on cUSDT until cutover.', addresses: { [CHAIN_138]: addr('cUSDT_V2', CHAIN_138) || '' } },
  { symbol: 'cAUSDT', name: 'Alltra USD Token (Compliant)', type: 'base', decimals: 6, currencyCode: 'USD', description: 'Live Chain 138 compliant landing asset for the ALL Mainnet AUSDT corridor.', addresses: { [CHAIN_138]: addr('cAUSDT', CHAIN_138) || '' } },
  { symbol: 'cUSDW', name: 'USD W (Compliant)', type: 'base', decimals: 6, currencyCode: 'USD', description: 'Chain 138 repo-native cUSDW hub asset for D-WIN-aligned PMM and cWUSDW transport planning.', addresses: { [CHAIN_138]: addr('cUSDW', CHAIN_138) || '' } },
  {
    symbol: 'cBTC',
    name: 'Bitcoin (Compliant)',
    type: 'base',
    decimals: 8,
    currencyCode: 'BTC',
    registryFamily: 'monetary_unit',
    description: 'Canonical Chain 138 compliant Bitcoin monetary unit with satoshi-precision accounting and custody-backed mint controls.',
    addresses: { [CHAIN_138]: addr('cBTC', CHAIN_138) || '' },
  },
  {
    symbol: 'cETH',
    name: 'Ether Mainnet (Compliant)',
    type: 'base',
    decimals: 18,
    currencyCode: 'ETH',
    registryFamily: 'gas_native',
    description: 'Canonical Chain 138 representation of Ethereum mainnet gas inventory. This family remains isolated from the shared ETH L2 family.',
    addresses: { [CHAIN_138]: addr('cETH', CHAIN_138) || '' },
  },
  {
    symbol: 'cETHL2',
    name: 'Ether L2 Basket (Compliant)',
    type: 'base',
    decimals: 18,
    currencyCode: 'ETH',
    registryFamily: 'gas_native',
    description: 'Canonical Chain 138 representation of the shared ETH L2 family across Optimism, Arbitrum, and Base.',
    addresses: { [CHAIN_138]: addr('cETHL2', CHAIN_138) || '' },
  },
  {
    symbol: 'cBNB',
    name: 'BNB (Compliant)',
    type: 'base',
    decimals: 18,
    currencyCode: 'BNB',
    registryFamily: 'gas_native',
    description: 'Canonical Chain 138 representation of BNB gas inventory.',
    addresses: { [CHAIN_138]: addr('cBNB', CHAIN_138) || '' },
  },
  {
    symbol: 'cPOL',
    name: 'POL (Compliant)',
    type: 'base',
    decimals: 18,
    currencyCode: 'POL',
    registryFamily: 'gas_native',
    description: 'Canonical Chain 138 representation of Polygon gas inventory.',
    addresses: { [CHAIN_138]: addr('cPOL', CHAIN_138) || '' },
  },
  {
    symbol: 'cAVAX',
    name: 'Avalanche (Compliant)',
    type: 'base',
    decimals: 18,
    currencyCode: 'AVAX',
    registryFamily: 'gas_native',
    description: 'Canonical Chain 138 representation of Avalanche gas inventory.',
    addresses: { [CHAIN_138]: addr('cAVAX', CHAIN_138) || '' },
  },
  {
    symbol: 'cCRO',
    name: 'Cronos (Compliant)',
    type: 'base',
    decimals: 18,
    currencyCode: 'CRO',
    registryFamily: 'gas_native',
    description: 'Canonical Chain 138 representation of Cronos gas inventory.',
    addresses: { [CHAIN_138]: addr('cCRO', CHAIN_138) || '' },
  },
  {
    symbol: 'cXDAI',
    name: 'xDAI (Compliant)',
    type: 'base',
    decimals: 18,
    currencyCode: 'XDAI',
    registryFamily: 'gas_native',
    description: 'Canonical Chain 138 representation of Gnosis Chain xDAI gas inventory.',
    addresses: { [CHAIN_138]: addr('cXDAI', CHAIN_138) || '' },
  },
  {
    symbol: 'cCELO',
    name: 'Celo (Compliant)',
    type: 'base',
    decimals: 18,
    currencyCode: 'CELO',
    registryFamily: 'gas_native',
    description: 'Canonical Chain 138 representation of Celo gas inventory.',
    addresses: { [CHAIN_138]: addr('cCELO', CHAIN_138) || '' },
  },
  {
    symbol: 'cWEMIX',
    name: 'Wemix Hub (Compliant)',
    type: 'base',
    decimals: 18,
    currencyCode: 'WEMIX',
    registryFamily: 'gas_native',
    description: 'Canonical Chain 138 representation of Wemix gas inventory. The public mirror keeps the distinct cWWEMIX symbol to avoid naming collisions.',
    addresses: { [CHAIN_138]: addr('cWEMIX', CHAIN_138) || '' },
  },
  // Public-network transport mirrors for canonical Chain 138 c* assets.
  { symbol: 'cWAUSDT', name: 'Alltra USD Token (Compliant Wrapped ISO-4217 M1)', type: 'w', decimals: 6, currencyCode: 'USD', description: 'Public-network mirrored transport form for the live Chain 138 cAUSDT surface.', addresses: { ...Object.fromEntries(GRU_CW_CHAIN_IDS.map((id) => [id, addr('cWAUSDT', id)])) } },
  { symbol: 'cWUSDC', name: 'USD Coin (Compliant Wrapped ISO-4217 M1)', type: 'w', decimals: 6, currencyCode: 'USD', description: 'Public-network mirrored transport form of canonical Chain 138 cUSDC.', addresses: { ...Object.fromEntries(GRU_CW_CHAIN_IDS.map((id) => [id, addr('cWUSDC', id)])) } },
  { symbol: 'cWUSDT', name: 'Tether USD (Compliant Wrapped ISO-4217 M1)', type: 'w', decimals: 6, currencyCode: 'USD', description: 'Public-network mirrored transport form of canonical Chain 138 cUSDT.', addresses: { ...Object.fromEntries(GRU_CW_CHAIN_IDS.map((id) => [id, addr('cWUSDT', id)])) } },
  { symbol: 'cWEURC', name: 'Euro Coin (Compliant Wrapped ISO-4217 M1)', type: 'w', decimals: 6, currencyCode: 'EUR', description: 'Public-network mirrored transport form of canonical Chain 138 cEURC.', addresses: { ...Object.fromEntries(GRU_CW_CHAIN_IDS.map((id) => [id, addr('cWEURC', id)])) } },
  { symbol: 'cWEURT', name: 'Tether EUR (Compliant Wrapped ISO-4217 M1)', type: 'w', decimals: 6, currencyCode: 'EUR', description: 'Public-network mirrored transport form of canonical Chain 138 cEURT.', addresses: { ...Object.fromEntries(GRU_CW_CHAIN_IDS.map((id) => [id, addr('cWEURT', id)])) } },
  { symbol: 'cWGBPC', name: 'Pound Sterling (Compliant Wrapped ISO-4217 M1)', type: 'w', decimals: 6, currencyCode: 'GBP', description: 'Public-network mirrored transport form of canonical Chain 138 cGBPC.', addresses: { ...Object.fromEntries(GRU_CW_CHAIN_IDS.map((id) => [id, addr('cWGBPC', id)])) } },
  { symbol: 'cWGBPT', name: 'Tether GBP (Compliant Wrapped ISO-4217 M1)', type: 'w', decimals: 6, currencyCode: 'GBP', description: 'Public-network mirrored transport form of canonical Chain 138 cGBPT.', addresses: { ...Object.fromEntries(GRU_CW_CHAIN_IDS.map((id) => [id, addr('cWGBPT', id)])) } },
  { symbol: 'cWAUDC', name: 'Australian Dollar (Compliant Wrapped ISO-4217 M1)', type: 'w', decimals: 6, currencyCode: 'AUD', description: 'Public-network mirrored transport form of canonical Chain 138 cAUDC.', addresses: { ...Object.fromEntries(GRU_CW_CHAIN_IDS.map((id) => [id, addr('cWAUDC', id)])) } },
  { symbol: 'cWJPYC', name: 'Japanese Yen (Compliant Wrapped ISO-4217 M1)', type: 'w', decimals: 6, currencyCode: 'JPY', description: 'Public-network mirrored transport form of canonical Chain 138 cJPYC.', addresses: { ...Object.fromEntries(GRU_CW_CHAIN_IDS.map((id) => [id, addr('cWJPYC', id)])) } },
  { symbol: 'cWCHFC', name: 'Swiss Franc (Compliant Wrapped ISO-4217 M1)', type: 'w', decimals: 6, currencyCode: 'CHF', description: 'Public-network mirrored transport form of canonical Chain 138 cCHFC.', addresses: { ...Object.fromEntries(GRU_CW_CHAIN_IDS.map((id) => [id, addr('cWCHFC', id)])) } },
  { symbol: 'cWCADC', name: 'Canadian Dollar (Compliant Wrapped ISO-4217 M1)', type: 'w', decimals: 6, currencyCode: 'CAD', description: 'Public-network mirrored transport form of canonical Chain 138 cCADC.', addresses: { ...Object.fromEntries(GRU_CW_CHAIN_IDS.map((id) => [id, addr('cWCADC', id)])) } },
  { symbol: 'cWXAUC', name: 'Gold (Compliant Wrapped ISO-4217 M1)', type: 'w', decimals: 6, currencyCode: 'XAU', registryFamily: 'commodity', description: 'Public-network mirrored transport form of canonical Chain 138 cXAUC.', addresses: { ...Object.fromEntries(GRU_CW_CHAIN_IDS.map((id) => [id, addr('cWXAUC', id)])) } },
  { symbol: 'cWXAUT', name: 'Tether XAU (Compliant Wrapped ISO-4217 M1)', type: 'w', decimals: 6, currencyCode: 'XAU', registryFamily: 'commodity', description: 'Public-network mirrored transport form of canonical Chain 138 cXAUT.', addresses: { ...Object.fromEntries(GRU_CW_CHAIN_IDS.map((id) => [id, addr('cWXAUT', id)])) } },
  { symbol: 'cWUSDW', name: 'USD W (Compliant Wrapped ISO-4217 M1)', type: 'w', decimals: 6, currencyCode: 'USD', description: 'Public-network mirrored transport form of canonical Chain 138 cUSDW.', addresses: { ...Object.fromEntries(GRU_CW_CHAIN_IDS.map((id) => [id, addr('cWUSDW', id)])) } },
  {
    symbol: 'WETH',
    name: 'Wrapped Ether (WETH9)',
    type: 'w',
    decimals: 18,
    currencyCode: 'ETH',
    registryFamily: 'gas_native',
    description: 'Legacy WETH9 surface used on Chain 138 for canonical ETH swap routing and CCIP WETH9 bridge lanes.',
    addresses: { [CHAIN_138]: addr('WETH', CHAIN_138) || '' },
  },
  {
    symbol: 'WETH10',
    name: 'Wrapped Ether 10',
    type: 'w',
    decimals: 18,
    currencyCode: 'ETH',
    registryFamily: 'gas_native',
    description: 'Chain 138 WETH10 pilot wrapped ETH surface used by DODO v3 routing and flash-capable paths.',
    addresses: { [CHAIN_138]: addr('WETH10', CHAIN_138) || '' },
  },
  {
    symbol: 'LINK',
    name: 'Chainlink Token',
    type: 'base',
    decimals: 18,
    currencyCode: 'LINK',
    registryFamily: 'unclassified',
    description: 'Chain 138 LINK token used for CCIP and oracle fee accounting.',
    addresses: { [CHAIN_138]: addr('LINK', CHAIN_138) || '' },
  },
  {
    symbol: 'cWBTC',
    name: 'Bitcoin (Compliant Wrapped Monetary Unit)',
    type: 'w',
    decimals: 8,
    currencyCode: 'BTC',
    registryFamily: 'monetary_unit',
    description: 'Public-network mirrored transport form of canonical Chain 138 cBTC. Distinct from Ethereum WBTC and other third-party wrapped BTC products.',
    addresses: { ...Object.fromEntries(BTC_CW_CHAIN_IDS.map((id) => [id, addr('cWBTC', id)])) },
  },
  {
    symbol: 'cWETH',
    name: 'Ether Mainnet (Compliant Wrapped)',
    type: 'w',
    decimals: 18,
    currencyCode: 'ETH',
    registryFamily: 'gas_native',
    description: 'Public-network mirrored transport form of canonical Chain 138 cETH for Ethereum mainnet only.',
    addresses: { ...Object.fromEntries(ETH_MAINNET_CW_CHAIN_IDS.map((id) => [id, addr('cWETH', id)])) },
  },
  {
    symbol: 'cWETHL2',
    name: 'Ether L2 Basket (Compliant Wrapped)',
    type: 'w',
    decimals: 18,
    currencyCode: 'ETH',
    registryFamily: 'gas_native',
    description: 'Public-network mirrored transport form of canonical Chain 138 cETHL2 across the approved ETH L2 family.',
    addresses: { ...Object.fromEntries(ETH_L2_CW_CHAIN_IDS.map((id) => [id, addr('cWETHL2', id)])) },
  },
  {
    symbol: 'cWBNB',
    name: 'BNB (Compliant Wrapped)',
    type: 'w',
    decimals: 18,
    currencyCode: 'BNB',
    registryFamily: 'gas_native',
    description: 'Public-network mirrored transport form of canonical Chain 138 cBNB.',
    addresses: { ...Object.fromEntries(BNB_CW_CHAIN_IDS.map((id) => [id, addr('cWBNB', id)])) },
  },
  {
    symbol: 'cWPOL',
    name: 'POL (Compliant Wrapped)',
    type: 'w',
    decimals: 18,
    currencyCode: 'POL',
    registryFamily: 'gas_native',
    description: 'Public-network mirrored transport form of canonical Chain 138 cPOL.',
    addresses: { ...Object.fromEntries(POL_CW_CHAIN_IDS.map((id) => [id, addr('cWPOL', id)])) },
  },
  {
    symbol: 'cWAVAX',
    name: 'Avalanche (Compliant Wrapped)',
    type: 'w',
    decimals: 18,
    currencyCode: 'AVAX',
    registryFamily: 'gas_native',
    description: 'Public-network mirrored transport form of canonical Chain 138 cAVAX.',
    addresses: { ...Object.fromEntries(AVAX_CW_CHAIN_IDS.map((id) => [id, addr('cWAVAX', id)])) },
  },
  {
    symbol: 'cWCRO',
    name: 'Cronos (Compliant Wrapped)',
    type: 'w',
    decimals: 18,
    currencyCode: 'CRO',
    registryFamily: 'gas_native',
    description: 'Public-network mirrored transport form of canonical Chain 138 cCRO.',
    addresses: { ...Object.fromEntries(CRO_CW_CHAIN_IDS.map((id) => [id, addr('cWCRO', id)])) },
  },
  {
    symbol: 'cWXDAI',
    name: 'xDAI (Compliant Wrapped)',
    type: 'w',
    decimals: 18,
    currencyCode: 'XDAI',
    registryFamily: 'gas_native',
    description: 'Public-network mirrored transport form of canonical Chain 138 cXDAI.',
    addresses: { ...Object.fromEntries(XDAI_CW_CHAIN_IDS.map((id) => [id, addr('cWXDAI', id)])) },
  },
  {
    symbol: 'cWCELO',
    name: 'Celo (Compliant Wrapped)',
    type: 'w',
    decimals: 18,
    currencyCode: 'CELO',
    registryFamily: 'gas_native',
    description: 'Public-network mirrored transport form of canonical Chain 138 cCELO.',
    addresses: { ...Object.fromEntries(CELO_CW_CHAIN_IDS.map((id) => [id, addr('cWCELO', id)])) },
  },
  {
    symbol: 'cWWEMIX',
    name: 'Wemix (Compliant Wrapped)',
    type: 'w',
    decimals: 18,
    currencyCode: 'WEMIX',
    registryFamily: 'gas_native',
    description: 'Public-network mirrored transport form of canonical Chain 138 cWEMIX. The doubled W preserves the cW* naming discipline and keeps the canonical hub symbol distinct.',
    addresses: { ...Object.fromEntries(WEMIX_CW_CHAIN_IDS.map((id) => [id, addr('cWWEMIX', id)])) },
  },
  { symbol: 'cEURC', name: 'Euro Coin (Compliant)', type: 'base', decimals: 6, currencyCode: 'EUR', addresses: { [CHAIN_138]: addr('cEURC', CHAIN_138), [CHAIN_651940]: addr('cEURC', CHAIN_651940) } },
  { symbol: 'cEURT', name: 'Tether EUR (Compliant)', type: 'base', decimals: 6, currencyCode: 'EUR', addresses: { [CHAIN_138]: addr('cEURT', CHAIN_138), [CHAIN_651940]: addr('cEURT', CHAIN_651940) } },
  { symbol: 'cGBPC', name: 'Pound Sterling (Compliant)', type: 'base', decimals: 6, currencyCode: 'GBP', addresses: { [CHAIN_138]: addr('cGBPC', CHAIN_138), [CHAIN_651940]: addr('cGBPC', CHAIN_651940) } },
  { symbol: 'cGBPT', name: 'Tether GBP (Compliant)', type: 'base', decimals: 6, currencyCode: 'GBP', addresses: { [CHAIN_138]: addr('cGBPT', CHAIN_138), [CHAIN_651940]: addr('cGBPT', CHAIN_651940) } },
  { symbol: 'cAUDC', name: 'Australian Dollar (Compliant)', type: 'base', decimals: 6, currencyCode: 'AUD', addresses: { [CHAIN_138]: addr('cAUDC', CHAIN_138), [CHAIN_651940]: addr('cAUDC', CHAIN_651940) } },
  { symbol: 'cJPYC', name: 'Japanese Yen (Compliant)', type: 'base', decimals: 6, currencyCode: 'JPY', addresses: { [CHAIN_138]: addr('cJPYC', CHAIN_138), [CHAIN_651940]: addr('cJPYC', CHAIN_651940) } },
  { symbol: 'cCHFC', name: 'Swiss Franc (Compliant)', type: 'base', decimals: 6, currencyCode: 'CHF', addresses: { [CHAIN_138]: addr('cCHFC', CHAIN_138), [CHAIN_651940]: addr('cCHFC', CHAIN_651940) } },
  { symbol: 'cCADC', name: 'Canadian Dollar (Compliant)', type: 'base', decimals: 6, currencyCode: 'CAD', addresses: { [CHAIN_138]: addr('cCADC', CHAIN_138), [CHAIN_651940]: addr('cCADC', CHAIN_651940) } },
  {
    symbol: 'cXAUC',
    name: 'Gold (Compliant)',
    type: 'base',
    decimals: 6,
    currencyCode: 'XAU',
    description: '1 full token = 1 troy ounce fine gold (10^6 base units = 1 oz).',
    addresses: { [CHAIN_138]: addr('cXAUC', CHAIN_138) },
  },
  {
    symbol: 'cXAUT',
    name: 'Tether XAU (Compliant)',
    type: 'base',
    decimals: 6,
    currencyCode: 'XAU',
    description: '1 full token = 1 troy ounce fine gold (10^6 base units = 1 oz).',
    addresses: { [CHAIN_138]: addr('cXAUT', CHAIN_138) },
  },
  {
    symbol: 'cAXAUC',
    name: 'Alltra Gold Coin',
    type: 'base',
    decimals: 6,
    currencyCode: 'XAU',
    description: 'Planned ALL Mainnet native-unwrapped gold landing asset for the 138 -> 651940 corridor.',
    addresses: { [CHAIN_651940]: addr('cAXAUC', CHAIN_651940) || '' },
  },
  {
    symbol: 'cAXAUT',
    name: 'Alltra Tether XAU',
    type: 'base',
    decimals: 6,
    currencyCode: 'XAU',
    description: 'Planned ALL Mainnet native-unwrapped XAU token for the 138 -> 651940 corridor.',
    addresses: { [CHAIN_651940]: addr('cAXAUT', CHAIN_651940) || '' },
  },
  {
    symbol: 'cWAXAUC',
    name: 'Alltra Wrapped Gold Coin',
    type: 'w',
    decimals: 6,
    currencyCode: 'XAU',
    description: 'Planned ALL Mainnet bridge-minted wrapped gold representation for inbound Chain 138 cXAUC transport.',
    addresses: { [CHAIN_651940]: addr('cWAXAUC', CHAIN_651940) || '' },
  },
  {
    symbol: 'cWAXAUT',
    name: 'Alltra Wrapped Tether XAU',
    type: 'w',
    decimals: 6,
    currencyCode: 'XAU',
    description: 'Planned ALL Mainnet bridge-minted wrapped XAU representation for inbound Chain 138 cXAUT transport.',
    addresses: { [CHAIN_651940]: addr('cWAXAUT', CHAIN_651940) || '' },
  },
  {
    symbol: 'LiXAU',
    name: 'XAU Liquidity Index (M00, not cXAUC eMoney)',
    type: 'base',
    decimals: 6,
    currencyCode: 'XAU',
    registryFamily: 'commodity',
    capitalMarkets: getCapitalMarketsClassification('LiXAU'),
    description: 'M00 GRU XAU liquidity index — DefiLlama RWA candidate; not M1 cXAUC eMoney.',
    addresses: { [CHAIN_138]: addr('LiXAU', CHAIN_138) },
  },
  {
    symbol: 'LiPMG',
    name: 'Precious Metals Group Index (M00)',
    type: 'base',
    decimals: 6,
    currencyCode: 'XAU',
    registryFamily: 'commodity',
    capitalMarkets: getCapitalMarketsClassification('LiPMG'),
    description: 'M00 GRU precious metals group liquidity index — not M1 eMoney.',
    addresses: { [CHAIN_138]: addr('LiPMG', CHAIN_138) },
  },
  {
    symbol: 'LiBMG1',
    name: 'Base Metals Group Index 1 (M00)',
    type: 'base',
    decimals: 6,
    currencyCode: 'USD',
    registryFamily: 'commodity',
    capitalMarkets: getCapitalMarketsClassification('LiBMG1'),
    description: 'M00 GRU base metals group liquidity index — not M1 eMoney.',
    addresses: { [CHAIN_138]: addr('LiBMG1', CHAIN_138) },
  },
  {
    symbol: 'LiBMG2',
    name: 'Base Metals Group Index 2 (M00)',
    type: 'base',
    decimals: 6,
    currencyCode: 'USD',
    registryFamily: 'commodity',
    capitalMarkets: getCapitalMarketsClassification('LiBMG2'),
    description: 'M00 GRU base metals group liquidity index — not M1 eMoney.',
    addresses: { [CHAIN_138]: addr('LiBMG2', CHAIN_138) },
  },
  {
    symbol: 'LiBMG3',
    name: 'Base Metals Group Index 3 (M00)',
    type: 'base',
    decimals: 6,
    currencyCode: 'USD',
    registryFamily: 'commodity',
    capitalMarkets: getCapitalMarketsClassification('LiBMG3'),
    description: 'M00 GRU base metals group liquidity index — not M1 eMoney.',
    addresses: { [CHAIN_138]: addr('LiBMG3', CHAIN_138) },
  },
  // --- ISO-4217 W ---
  { symbol: 'USDW', name: 'USD W Token', type: 'w', decimals: 2, currencyCode: 'USD', addresses: { [CHAIN_138]: addr('USDW', CHAIN_138), [CHAIN_25]: addr('USDW', CHAIN_25), [CHAIN_651940]: addr('USDW', CHAIN_651940) } },
  { symbol: 'EURW', name: 'EUR W Token', type: 'w', decimals: 2, currencyCode: 'EUR', addresses: { [CHAIN_138]: addr('EURW', CHAIN_138), [CHAIN_25]: addr('EURW', CHAIN_25), [CHAIN_651940]: addr('EURW', CHAIN_651940) } },
  { symbol: 'GBPW', name: 'GBP W Token', type: 'w', decimals: 2, currencyCode: 'GBP', addresses: { [CHAIN_138]: addr('GBPW', CHAIN_138), [CHAIN_25]: addr('GBPW', CHAIN_25), [CHAIN_651940]: addr('GBPW', CHAIN_651940) } },
  { symbol: 'AUDW', name: 'AUD W Token', type: 'w', decimals: 2, currencyCode: 'AUD', addresses: { [CHAIN_138]: addr('AUDW', CHAIN_138), [CHAIN_25]: addr('AUDW', CHAIN_25), [CHAIN_651940]: addr('AUDW', CHAIN_651940) } },
  { symbol: 'JPYW', name: 'JPY W Token', type: 'w', decimals: 2, currencyCode: 'JPY', addresses: { [CHAIN_138]: addr('JPYW', CHAIN_138), [CHAIN_25]: addr('JPYW', CHAIN_25), [CHAIN_651940]: addr('JPYW', CHAIN_651940) } },
  { symbol: 'CHFW', name: 'CHF W Token', type: 'w', decimals: 2, currencyCode: 'CHF', addresses: { [CHAIN_138]: addr('CHFW', CHAIN_138), [CHAIN_25]: addr('CHFW', CHAIN_25), [CHAIN_651940]: addr('CHFW', CHAIN_651940) } },
  { symbol: 'CADW', name: 'CAD W Token', type: 'w', decimals: 2, currencyCode: 'CAD', addresses: { [CHAIN_138]: addr('CADW', CHAIN_138), [CHAIN_25]: addr('CADW', CHAIN_25), [CHAIN_651940]: addr('CADW', CHAIN_651940) } },
  // --- Asset (ac*) ---
  { symbol: 'acUSDC', name: 'Deposit cUSDC', type: 'asset', decimals: 6, addresses: { [CHAIN_138]: addr('acUSDC', CHAIN_138), [CHAIN_651940]: addr('acUSDC', CHAIN_651940) } },
  { symbol: 'acUSDT', name: 'Deposit cUSDT', type: 'asset', decimals: 6, addresses: { [CHAIN_138]: addr('acUSDT', CHAIN_138), [CHAIN_651940]: addr('acUSDT', CHAIN_651940) } },
  { symbol: 'acEURC', name: 'Deposit cEURC', type: 'asset', decimals: 6, addresses: { [CHAIN_138]: addr('acEURC', CHAIN_138), [CHAIN_651940]: addr('acEURC', CHAIN_651940) } },
  { symbol: 'acGBPC', name: 'Deposit cGBPC', type: 'asset', decimals: 6, addresses: { [CHAIN_138]: addr('acGBPC', CHAIN_138), [CHAIN_651940]: addr('acGBPC', CHAIN_651940) } },
  { symbol: 'acAUDC', name: 'Deposit cAUDC', type: 'asset', decimals: 6, addresses: { [CHAIN_138]: addr('acAUDC', CHAIN_138), [CHAIN_651940]: addr('acAUDC', CHAIN_651940) } },
  { symbol: 'acJPYC', name: 'Deposit cJPYC', type: 'asset', decimals: 6, addresses: { [CHAIN_138]: addr('acJPYC', CHAIN_138), [CHAIN_651940]: addr('acJPYC', CHAIN_651940) } },
  { symbol: 'acCHFC', name: 'Deposit cCHFC', type: 'asset', decimals: 6, addresses: { [CHAIN_138]: addr('acCHFC', CHAIN_138), [CHAIN_651940]: addr('acCHFC', CHAIN_651940) } },
  { symbol: 'acCADC', name: 'Deposit cCADC', type: 'asset', decimals: 6, addresses: { [CHAIN_138]: addr('acCADC', CHAIN_138), [CHAIN_651940]: addr('acCADC', CHAIN_651940) } },
  { symbol: 'acXAUC', name: 'Deposit cXAUC', type: 'asset', decimals: 6, addresses: { [CHAIN_138]: addr('acXAUC', CHAIN_138), [CHAIN_651940]: addr('acXAUC', CHAIN_651940) } },
  // --- Debt (vdc* / sdc*) ---
  { symbol: 'vdcUSDC', name: 'Debt cUSDC (variable)', type: 'debt', decimals: 6, addresses: { [CHAIN_138]: addr('vdcUSDC', CHAIN_138), [CHAIN_651940]: addr('vdcUSDC', CHAIN_651940) } },
  { symbol: 'sdcUSDC', name: 'Debt cUSDC (stable)', type: 'debt', decimals: 6, addresses: { [CHAIN_138]: addr('sdcUSDC', CHAIN_138), [CHAIN_651940]: addr('sdcUSDC', CHAIN_651940) } },
  { symbol: 'vdcUSDT', name: 'Debt cUSDT (variable)', type: 'debt', decimals: 6, addresses: { [CHAIN_138]: addr('vdcUSDT', CHAIN_138), [CHAIN_651940]: addr('vdcUSDT', CHAIN_651940) } },
  { symbol: 'sdcUSDT', name: 'Debt cUSDT (stable)', type: 'debt', decimals: 6, addresses: { [CHAIN_138]: addr('sdcUSDT', CHAIN_138), [CHAIN_651940]: addr('sdcUSDT', CHAIN_651940) } },
  { symbol: 'vdcEURC', name: 'Debt cEURC (variable)', type: 'debt', decimals: 6, addresses: { [CHAIN_138]: addr('vdcEURC', CHAIN_138), [CHAIN_651940]: addr('vdcEURC', CHAIN_651940) } },
  { symbol: 'sdcEURC', name: 'Debt cEURC (stable)', type: 'debt', decimals: 6, addresses: { [CHAIN_138]: addr('sdcEURC', CHAIN_138), [CHAIN_651940]: addr('sdcEURC', CHAIN_651940) } },
  { symbol: 'vdcGBPC', name: 'Debt cGBPC (variable)', type: 'debt', decimals: 6, addresses: { [CHAIN_138]: addr('vdcGBPC', CHAIN_138), [CHAIN_651940]: addr('vdcGBPC', CHAIN_651940) } },
  { symbol: 'sdcGBPC', name: 'Debt cGBPC (stable)', type: 'debt', decimals: 6, addresses: { [CHAIN_138]: addr('sdcGBPC', CHAIN_138), [CHAIN_651940]: addr('sdcGBPC', CHAIN_651940) } },
  { symbol: 'vdcAUDC', name: 'Debt cAUDC (variable)', type: 'debt', decimals: 6, addresses: { [CHAIN_138]: addr('vdcAUDC', CHAIN_138), [CHAIN_651940]: addr('vdcAUDC', CHAIN_651940) } },
  { symbol: 'sdcAUDC', name: 'Debt cAUDC (stable)', type: 'debt', decimals: 6, addresses: { [CHAIN_138]: addr('sdcAUDC', CHAIN_138), [CHAIN_651940]: addr('sdcAUDC', CHAIN_651940) } },
  { symbol: 'vdcJPYC', name: 'Debt cJPYC (variable)', type: 'debt', decimals: 6, addresses: { [CHAIN_138]: addr('vdcJPYC', CHAIN_138), [CHAIN_651940]: addr('vdcJPYC', CHAIN_651940) } },
  { symbol: 'sdcJPYC', name: 'Debt cJPYC (stable)', type: 'debt', decimals: 6, addresses: { [CHAIN_138]: addr('sdcJPYC', CHAIN_138), [CHAIN_651940]: addr('sdcJPYC', CHAIN_651940) } },
  { symbol: 'vdcCHFC', name: 'Debt cCHFC (variable)', type: 'debt', decimals: 6, addresses: { [CHAIN_138]: addr('vdcCHFC', CHAIN_138), [CHAIN_651940]: addr('vdcCHFC', CHAIN_651940) } },
  { symbol: 'sdcCHFC', name: 'Debt cCHFC (stable)', type: 'debt', decimals: 6, addresses: { [CHAIN_138]: addr('sdcCHFC', CHAIN_138), [CHAIN_651940]: addr('sdcCHFC', CHAIN_651940) } },
  { symbol: 'vdcCADC', name: 'Debt cCADC (variable)', type: 'debt', decimals: 6, addresses: { [CHAIN_138]: addr('vdcCADC', CHAIN_138), [CHAIN_651940]: addr('vdcCADC', CHAIN_651940) } },
  { symbol: 'sdcCADC', name: 'Debt cCADC (stable)', type: 'debt', decimals: 6, addresses: { [CHAIN_138]: addr('sdcCADC', CHAIN_138), [CHAIN_651940]: addr('sdcCADC', CHAIN_651940) } },
  { symbol: 'vdcXAUC', name: 'Debt cXAUC (variable)', type: 'debt', decimals: 6, addresses: { [CHAIN_138]: addr('vdcXAUC', CHAIN_138), [CHAIN_651940]: addr('vdcXAUC', CHAIN_651940) } },
  { symbol: 'sdcXAUC', name: 'Debt cXAUC (stable)', type: 'debt', decimals: 6, addresses: { [CHAIN_138]: addr('sdcXAUC', CHAIN_138), [CHAIN_651940]: addr('sdcXAUC', CHAIN_651940) } },
];

for (const spec of CANONICAL_TOKENS) {
  if (!spec.capitalMarkets) {
    const cm = getCapitalMarketsClassification(spec.symbol);
    if (cm) spec.capitalMarkets = cm;
  }
}

export function getCanonicalTokensByChain(chainId: number): CanonicalTokenSpec[] {
  return CANONICAL_TOKENS.filter(
    (t) => t.addresses[chainId] && String(t.addresses[chainId]).trim() !== ''
  );
}

export function getCanonicalTokenByAddress(chainId: number, address: string): CanonicalTokenSpec | undefined {
  const lower = normalizeAddress(address);
  return CANONICAL_TOKENS.find((t) => t.addresses[chainId]?.toLowerCase() === lower);
}

export function getCanonicalTokenBySymbol(chainId: number, symbol: string): CanonicalTokenSpec | undefined {
  const normalized = symbol.trim().toLowerCase();
  return CANONICAL_TOKENS.find(
    (t) => t.symbol.toLowerCase() === normalized && t.addresses[chainId] && String(t.addresses[chainId]).trim() !== ''
  );
}

export interface CanonicalQuoteAddressResolution {
  requestedAddress: string;
  requestedSymbol?: string;
  lookupAddress: string;
  lookupSymbol?: string;
  usedFallback: boolean;
}

function isEvmAddress(value: string): boolean {
  return /^0x[a-f0-9]{40}$/.test(value);
}

export function resolveCanonicalQuoteAddress(chainId: number, address: string): CanonicalQuoteAddressResolution {
  const raw = address.trim();
  const bySymbol = !isEvmAddress(normalizeAddress(raw))
    ? getCanonicalTokenBySymbol(chainId, raw)
    : undefined;
  if (bySymbol) {
    const lookupAddress = normalizeAddress(bySymbol.addresses[chainId] || '');
    return {
      requestedAddress: raw.toLowerCase(),
      requestedSymbol: bySymbol.symbol,
      lookupAddress: lookupAddress || raw.toLowerCase(),
      lookupSymbol: bySymbol.symbol,
      usedFallback: false,
    };
  }

  const requestedAddress = normalizeAddress(raw);
  const requestedSpec = getCanonicalTokenByAddress(chainId, requestedAddress);
  if (!requestedSpec) {
    return {
      requestedAddress,
      lookupAddress: requestedAddress,
      usedFallback: false,
    };
  }

  const liquiditySourceSymbol = requestedSpec.liquiditySourceSymbol || requestedSpec.symbol;
  const liquiditySpec = getCanonicalTokenBySymbol(chainId, liquiditySourceSymbol) || requestedSpec;
  const lookupAddress = normalizeAddress(liquiditySpec.addresses[chainId] || requestedAddress);

  return {
    requestedAddress,
    requestedSymbol: requestedSpec.symbol,
    lookupAddress,
    lookupSymbol: liquiditySpec.symbol,
    usedFallback: lookupAddress !== requestedAddress,
  };
}

/** IPFS-hosted logo URLs (Pinata) for Uniswap token list (logoURI).
 * Every token must have logoURI for MetaMask to display icons. getLogoUriForSpec resolves
 * ac-tokens from base (c*), vdc/sdc from base; unknown symbols fall back to ETH_LOGO. */
const IPFS_GATEWAY = 'https://ipfs.io/ipfs';
/** Canonical hosted marks — https://d-bis.org/brand-assets */
export const DBIS_BRAND_LOGO_BASE = 'https://d-bis.org';
const GRU_LOGO_BASE =
  'https://raw.githubusercontent.com/Order-of-Hospitallers/proxmox-cp/main/token-lists/logos/gru';
export function dbisBrandLogoUrl(symbol: string): string {
  if (symbol.startsWith('Li')) return `${DBIS_BRAND_LOGO_BASE}/li/${symbol.toLowerCase()}.svg`;
  return `${DBIS_BRAND_LOGO_BASE}/tokens/${symbol.toLowerCase()}.svg`;
}
const GAS_NATIVE_LOGO_BY_CODE: Record<string, string> = {
  ETH: dbisBrandLogoUrl('cETH'),
  BNB: dbisBrandLogoUrl('cBNB'),
  POL: dbisBrandLogoUrl('cPOL'),
  AVAX: dbisBrandLogoUrl('cAVAX'),
  CRO: dbisBrandLogoUrl('cCRO'),
  XDAI: dbisBrandLogoUrl('cXDAI'),
  CELO: dbisBrandLogoUrl('cCELO'),
  WEMIX: dbisBrandLogoUrl('cWEMIX'),
};
const USDC_LOGO = dbisBrandLogoUrl('cUSDC');
const USDT_LOGO = dbisBrandLogoUrl('cUSDT');
const BTC_LOGO = dbisBrandLogoUrl('cBTC');

const LOGO_BY_SYMBOL: Record<string, string> = {
  USDC: USDC_LOGO,
  USDT: USDT_LOGO,
  cUSDC: USDC_LOGO,
  cUSDT: USDT_LOGO,
  cUSDC_V2: USDC_LOGO,
  cUSDT_V2: USDT_LOGO,
  cAUSDT: USDT_LOGO,
  cUSDW: USDC_LOGO,
  cBTC: BTC_LOGO,
  cWAUSDT: dbisBrandLogoUrl('cWAUSDT'),
  cWBTC: dbisBrandLogoUrl('cWBTC'),
  cWUSDC: dbisBrandLogoUrl('cWUSDC'),
  cWUSDT: dbisBrandLogoUrl('cWUSDT'),
  cWUSDW: dbisBrandLogoUrl('cWUSDW'),
  cWEURC: dbisBrandLogoUrl('cWEURC'),
  cWEURT: dbisBrandLogoUrl('cWEURT'),
  cWGBPC: dbisBrandLogoUrl('cWGBPC'),
  cWGBPT: dbisBrandLogoUrl('cWGBPT'),
  cWAUDC: dbisBrandLogoUrl('cWAUDC'),
  cWJPYC: dbisBrandLogoUrl('cWJPYC'),
  cWCHFC: dbisBrandLogoUrl('cWCHFC'),
  cWCADC: dbisBrandLogoUrl('cWCADC'),
  cWXAUC: dbisBrandLogoUrl('cWXAUC'),
  cWXAUT: dbisBrandLogoUrl('cWXAUT'),
  cWEMIX: dbisBrandLogoUrl('cWEMIX'),
  cETH: dbisBrandLogoUrl('cETH'),
  cETHL2: dbisBrandLogoUrl('cETHL2'),
  cBNB: dbisBrandLogoUrl('cBNB'),
  cPOL: dbisBrandLogoUrl('cPOL'),
  cAVAX: dbisBrandLogoUrl('cAVAX'),
  cCRO: dbisBrandLogoUrl('cCRO'),
  cXDAI: dbisBrandLogoUrl('cXDAI'),
  cCELO: dbisBrandLogoUrl('cCELO'),
  WETH: dbisBrandLogoUrl('WETH'),
  WETH10: dbisBrandLogoUrl('WETH10'),
  LINK: dbisBrandLogoUrl('LINK'),
  cEURC: dbisBrandLogoUrl('cEURC'),
  cEURT: dbisBrandLogoUrl('cEURT'),
  cGBPC: dbisBrandLogoUrl('cGBPC'),
  cGBPT: dbisBrandLogoUrl('cGBPT'),
  cAUDC: dbisBrandLogoUrl('cAUDC'),
  cJPYC: dbisBrandLogoUrl('cJPYC'),
  cCHFC: dbisBrandLogoUrl('cCHFC'),
  cCADC: dbisBrandLogoUrl('cCADC'),
  cXAUC: dbisBrandLogoUrl('cXAUC'),
  cXAUT: dbisBrandLogoUrl('cXAUT'),
  cAXAUC: dbisBrandLogoUrl('cXAUC'),
  cAXAUT: dbisBrandLogoUrl('cXAUT'),
  cWAXAUC: dbisBrandLogoUrl('cWXAUC'),
  cWAXAUT: dbisBrandLogoUrl('cWXAUT'),
  LiXAU: dbisBrandLogoUrl('LiXAU'),
  LiPMG: dbisBrandLogoUrl('LiPMG'),
  LiBMG1: dbisBrandLogoUrl('LiBMG1'),
  LiBMG2: dbisBrandLogoUrl('LiBMG2'),
  LiBMG3: dbisBrandLogoUrl('LiBMG3'),
  USDW: USDC_LOGO,
  EURW: `${IPFS_GATEWAY}/QmPh16PY241zNtePyeK7ep1uf1RcARV2ynGAuRU8U7sSqS`,
  GBPW: `${IPFS_GATEWAY}/QmT2nJ6WyhYBCsYJ6NfS1BPAqiGKkCEuMxiC8ye93Co1hF`,
  AUDW: `${IPFS_GATEWAY}/Qmb9JmuD9ehaQtTLBBZmAoiAbvE53e3FMjkEty8rvbPf9K`,
  JPYW: `${IPFS_GATEWAY}/Qmb9JmuD9ehaQtTLBBZmAoiAbvE53e3FMjkEty8rvbPf9K`,
  CHFW: `${IPFS_GATEWAY}/Qmb9JmuD9ehaQtTLBBZmAoiAbvE53e3FMjkEty8rvbPf9K`,
  CADW: `${IPFS_GATEWAY}/Qmb9JmuD9ehaQtTLBBZmAoiAbvE53e3FMjkEty8rvbPf9K`,
};

/** Resolve logo URI for a canonical token (Uniswap token list format). */
export function getLogoUriForSpec(spec: CanonicalTokenSpec): string {
  if (spec.logoUrl) return spec.logoUrl;
  const bySymbol = LOGO_BY_SYMBOL[spec.symbol];
  if (bySymbol) return bySymbol;
  const gasLogo = spec.registryFamily === 'gas_native' && spec.currencyCode
    ? GAS_NATIVE_LOGO_BY_CODE[spec.currencyCode.toUpperCase()]
    : undefined;
  if (gasLogo) return gasLogo;
  if (spec.symbol.startsWith('cW')) {
    const hubSymbol = `c${spec.symbol.slice(2)}`;
    const hubSpec = CANONICAL_TOKENS.find((t) => t.symbol === hubSymbol);
    if (hubSpec && hubSpec.symbol !== spec.symbol) return getLogoUriForSpec(hubSpec);
  }
  if (spec.symbol.startsWith('ac')) return getLogoUriForSpec(CANONICAL_TOKENS.find((t) => t.symbol === spec.symbol.replace('ac', 'c')) || spec);
  if (spec.symbol.startsWith('vdc') || spec.symbol.startsWith('sdc')) {
    const base = spec.symbol.replace(/^(vd|sd)c/, 'c');
    return getLogoUriForSpec(CANONICAL_TOKENS.find((t) => t.symbol === base) || spec);
  }
  return dbisBrandLogoUrl('WETH');
}

export function getTokenRegistryFamily(spec: Pick<CanonicalTokenSpec, 'currencyCode' | 'registryFamily'>): TokenRegistryFamily {
  if (spec.registryFamily) return spec.registryFamily;
  const code = String(spec.currencyCode || '').trim().toUpperCase();
  if (!code) return 'unclassified';
  if (code === 'XAU') return 'commodity';
  if (isISO4217Supported(code)) return 'iso4217';
  if (isMonetaryUnitSupported(code)) return 'monetary_unit';
  return 'unclassified';
}
