11import { BaseCoin } from './base' ;
22import { DuplicateCoinDefinitionError , CoinNotDefinedError , DuplicateCoinIdDefinitionError } from './errors' ;
33import { ContractAddressDefinedToken , NFTCollectionIdDefinedToken } from './account' ;
4+ import { EthereumNetwork } from './networks' ;
45
56export class CoinMap {
67 private readonly _map = new Map < string , Readonly < BaseCoin > > ( ) ;
@@ -12,6 +13,8 @@ export class CoinMap {
1213 private readonly _coinByContractAddress = new Map < string , Readonly < BaseCoin > > ( ) ;
1314 // map of coin by NFT collection ID -> the key is the (t)family:nftCollectionID
1415 private readonly _coinByNftCollectionID = new Map < string , Readonly < BaseCoin > > ( ) ;
16+ // Lazily initialized cache for chainId to coin name mapping (derived from network definitions)
17+ private _coinByChainId : Map < number , string > | null = null ;
1518
1619 private constructor ( ) {
1720 // Do not instantiate
@@ -75,85 +78,122 @@ export class CoinMap {
7578 this . addCoin ( coin ) ;
7679 }
7780
78- static coinNameFromChainId ( chainId : number ) : string {
79- const ethLikeCoinFromChainId : Record < number , string > = {
80- 1 : 'eth' ,
81- 42 : 'teth' ,
82- 5 : 'gteth' ,
83- 560048 : 'hteth' ,
84- 10001 : 'ethw' ,
85- 80002 : 'tpolygon' ,
86- 137 : 'polygon' ,
87- 56 : 'bsc' ,
88- 97 : 'tbsc' ,
89- 42161 : 'arbeth' ,
90- 421614 : 'tarbeth' ,
91- 10 : 'opeth' ,
92- 11155420 : 'topeth' ,
93- 1116 : 'coredao' ,
94- 1114 : 'tcoredao' ,
95- 248 : 'oas' ,
96- 9372 : 'toas' ,
97- 14 : 'flr' ,
98- 114 : 'tflr' ,
99- 19 : 'sgb' ,
100- 16 : 'tsgb' ,
101- 1111 : 'wemix' ,
102- 1112 : 'twemix' ,
103- 50 : 'xdc' ,
104- 51 : 'txdc' ,
105- 80094 : 'bera' ,
106- 80069 : 'tbera' ,
107- 42220 : 'celo' ,
108- 11142220 : 'tcelo' ,
109- 2222 : 'kava' ,
110- 2221 : 'tkava' ,
111- 43114 : 'avax' ,
112- 43113 : 'tavax' ,
113- 100 : 'gno' ,
114- 130 : 'uni' ,
115- 324 : 'zketh' ,
116- 8453 : 'baseeth' ,
117- 84532 : 'tbaseeth' ,
118- 30143 : 'mon' ,
119- 10143 : 'tmon' ,
120- 480 : 'world' ,
121- 4801 : 'tworld' ,
122- 5031 : 'somi' ,
123- 50312 : 'tstt' ,
124- 1868 : 'soneium' ,
125- 1946 : 'tsoneium' ,
126- 33111 : 'tapechain' ,
127- 33139 : 'apechain' ,
128- 688688 : 'tphrs' ,
129- 102030 : 'ctc' ,
130- 102031 : 'tctc' ,
131- 998 : 'thypeevm' ,
132- 999 : 'hypeevm' ,
133- 16602 : 'tog' ,
134- 16661 : 'og' ,
135- 9746 : 'txpl' ,
136- 9745 : 'xpl' ,
137- 14601 : 'tsonic' ,
138- 146 : 'sonic' ,
139- 1328 : 'tseievm' ,
140- 1329 : 'seievm' ,
141- 1001 : 'tkaia' ,
142- 8217 : 'kaia' ,
143- 1270 : 'tirys' ,
144- 59141 : 'tlineaeth' ,
145- 59144 : 'lineaeth' ,
146- 1315 : 'tip' ,
147- 1514 : 'ip' ,
148- 545 : 'tflow' ,
149- 747 : 'flow' ,
150- 98867 : 'tplume' ,
151- 98866 : 'plume' ,
152- 6342 : 'tmegaeth' ,
153- 295 : 'hbarevm' ,
154- 296 : 'thbarevm' ,
155- } ;
156- return ethLikeCoinFromChainId [ chainId ] ;
81+ /**
82+ * Hardcoded mapping for backward compatibility.
83+ */
84+ private static readonly LEGACY_CHAIN_ID_MAP : Record < number , string > = {
85+ 1 : 'eth' ,
86+ 42 : 'teth' ,
87+ 5 : 'gteth' ,
88+ 560048 : 'hteth' ,
89+ 10001 : 'ethw' ,
90+ 80002 : 'tpolygon' ,
91+ 137 : 'polygon' ,
92+ 56 : 'bsc' ,
93+ 97 : 'tbsc' ,
94+ 42161 : 'arbeth' ,
95+ 421614 : 'tarbeth' ,
96+ 10 : 'opeth' ,
97+ 11155420 : 'topeth' ,
98+ 1116 : 'coredao' ,
99+ 1114 : 'tcoredao' ,
100+ 248 : 'oas' ,
101+ 9372 : 'toas' ,
102+ 14 : 'flr' ,
103+ 114 : 'tflr' ,
104+ 19 : 'sgb' ,
105+ 16 : 'tsgb' ,
106+ 1111 : 'wemix' ,
107+ 1112 : 'twemix' ,
108+ 50 : 'xdc' ,
109+ 51 : 'txdc' ,
110+ 80094 : 'bera' ,
111+ 80069 : 'tbera' ,
112+ 42220 : 'celo' ,
113+ 11142220 : 'tcelo' ,
114+ 2222 : 'kava' ,
115+ 2221 : 'tkava' ,
116+ 43114 : 'avax' ,
117+ 43113 : 'tavax' ,
118+ 100 : 'gno' ,
119+ 130 : 'uni' ,
120+ 324 : 'zketh' ,
121+ 8453 : 'baseeth' ,
122+ 84532 : 'tbaseeth' ,
123+ 30143 : 'mon' ,
124+ 10143 : 'tmon' ,
125+ 480 : 'world' ,
126+ 4801 : 'tworld' ,
127+ 5031 : 'somi' ,
128+ 50312 : 'tstt' ,
129+ 1868 : 'soneium' ,
130+ 1946 : 'tsoneium' ,
131+ 33111 : 'tapechain' ,
132+ 33139 : 'apechain' ,
133+ 688688 : 'tphrs' ,
134+ 102030 : 'ctc' ,
135+ 102031 : 'tctc' ,
136+ 998 : 'thypeevm' ,
137+ 999 : 'hypeevm' ,
138+ 16602 : 'tog' ,
139+ 16661 : 'og' ,
140+ 9746 : 'txpl' ,
141+ 9745 : 'xpl' ,
142+ 14601 : 'tsonic' ,
143+ 146 : 'sonic' ,
144+ 1328 : 'tseievm' ,
145+ 1329 : 'seievm' ,
146+ 1001 : 'tkaia' ,
147+ 8217 : 'kaia' ,
148+ 1270 : 'tirys' ,
149+ 59141 : 'tlineaeth' ,
150+ 59144 : 'lineaeth' ,
151+ 1315 : 'tip' ,
152+ 1514 : 'ip' ,
153+ 545 : 'tflow' ,
154+ 747 : 'flow' ,
155+ 98867 : 'tplume' ,
156+ 98866 : 'plume' ,
157+ 6342 : 'tmegaeth' ,
158+ 295 : 'hbarevm' ,
159+ 296 : 'thbarevm' ,
160+ } ;
161+
162+ private buildChainIdMap ( ) : Map < number , string > {
163+ const chainIdMap = new Map < number , string > ( ) ;
164+ this . _map . forEach ( ( coin , coinName ) => {
165+ // Skip tokens - they share the same chainId as their parent chain
166+ if ( coin . isToken ) {
167+ return ;
168+ }
169+ const network = coin . network ;
170+ if ( 'chainId' in network && typeof ( network as EthereumNetwork ) . chainId === 'number' ) {
171+ const chainId = ( network as EthereumNetwork ) . chainId ;
172+ if ( ! chainIdMap . has ( chainId ) ) {
173+ chainIdMap . set ( chainId , coinName ) ;
174+ }
175+ }
176+ } ) ;
177+ return chainIdMap ;
178+ }
179+
180+ /**
181+ * Get coin name from chain ID.
182+ * First checks the legacy hardcoded map for backward compatibility,
183+ * then falls back to dynamic lookup from network definitions.
184+ * @param {number } chainId - the EVM chain ID
185+ * @returns {string | undefined } the coin name, or undefined if not found
186+ */
187+ public coinNameFromChainId ( chainId : number ) : string | undefined {
188+ const coinName = CoinMap . LEGACY_CHAIN_ID_MAP [ chainId ] ;
189+ if ( coinName ) {
190+ return coinName ;
191+ }
192+
193+ if ( this . _coinByChainId === null ) {
194+ this . _coinByChainId = this . buildChainIdMap ( ) ;
195+ }
196+ return this . _coinByChainId . get ( chainId ) ;
157197 }
158198
159199 /**
0 commit comments