@@ -16,7 +16,6 @@ import {
1616} from '@hyperlane-xyz/utils' ;
1717import { Keypair } from '@solana/web3.js' ;
1818
19- import type { ChainMetadata } from '../metadata/chainMetadataTypes.js' ;
2019import type { ConfiguredMultiProtocolProvider as MultiProtocolProvider } from '../providers/ConfiguredMultiProtocolProvider.js' ;
2120import { ProviderType } from '../providers/ProviderType.js' ;
2221import {
@@ -26,7 +25,7 @@ import {
2625import { IToken } from '../token/IToken.js' ;
2726import { Token } from '../token/Token.js' ;
2827import { TokenAmount } from '../token/TokenAmount.js' ;
29- import { TokenMetadata } from '../token/TokenMetadata .js' ;
28+ import { parseTokenConnectionId } from '../token/TokenConnection .js' ;
3029import {
3130 LOCKBOX_STANDARDS ,
3231 MINT_LIMITED_STANDARDS ,
@@ -44,7 +43,7 @@ import {
4443 IHypXERC20Adapter ,
4544 InterchainGasQuote ,
4645} from '../token/adapters/ITokenAdapter.js' ;
47- import { ChainNameOrId } from '../types.js' ;
46+ import { ChainName , ChainNameOrId } from '../types.js' ;
4847
4948import {
5049 FeeConstantConfig ,
@@ -54,7 +53,6 @@ import {
5453 WarpTxCategory ,
5554 WarpTypedTransaction ,
5655} from './types.js' ;
57- import { WarpRouteGraph , buildWarpRouteTokens } from './WarpRouteGraph.js' ;
5856
5957export interface WarpCoreOptions {
6058 logger ?: Logger ;
@@ -63,7 +61,9 @@ export interface WarpCoreOptions {
6361 routeBlacklist ?: RouteBlacklist ;
6462}
6563
66- export class WarpCore extends WarpRouteGraph < Token > {
64+ export class WarpCore {
65+ public readonly multiProvider : MultiProtocolProvider < { mailbox ?: Address } > ;
66+ public readonly tokens : Token [ ] ;
6767 public readonly localFeeConstants : FeeConstantConfig ;
6868 public readonly interchainFeeConstants : FeeConstantConfig ;
6969 public readonly routeBlacklist : RouteBlacklist ;
@@ -74,7 +74,8 @@ export class WarpCore extends WarpRouteGraph<Token> {
7474 tokens : Token [ ] ,
7575 options ?: WarpCoreOptions ,
7676 ) {
77- super ( multiProvider , tokens ) ;
77+ this . multiProvider = multiProvider ;
78+ this . tokens = tokens ;
7879 this . localFeeConstants = options ?. localFeeConstants || [ ] ;
7980 this . interchainFeeConstants = options ?. interchainFeeConstants || [ ] ;
8081 this . routeBlacklist = options ?. routeBlacklist || [ ] ;
@@ -95,23 +96,40 @@ export class WarpCore extends WarpRouteGraph<Token> {
9596 config : unknown ,
9697 ) : WarpCore {
9798 const parsedConfig = WarpCoreConfigSchema . parse ( config ) ;
98- const routeGraph = new WarpRouteGraph (
99- multiProvider ,
100- buildWarpRouteTokens ( parsedConfig , ( token ) => new TokenMetadata ( token ) ) ,
99+ const tokens = parsedConfig . tokens . map (
100+ ( token ) =>
101+ new Token ( {
102+ ...token ,
103+ addressOrDenom : token . addressOrDenom || '' ,
104+ connections : undefined ,
105+ } ) ,
101106 ) ;
102- return WarpCore . FromRouteGraph ( routeGraph , parsedConfig . options ) ;
103- }
104107
105- static FromRouteGraph (
106- routeGraph : WarpRouteGraph ,
107- options ?: WarpCoreOptions ,
108- ) : WarpCore {
109- const tokens = routeGraph . mapTokens ( ( token ) => new Token ( token ) ) . tokens ;
110- return new WarpCore ( routeGraph . multiProvider , tokens , options ) ;
111- }
108+ parsedConfig . tokens . forEach ( ( config , i ) => {
109+ for ( const connection of config . connections || [ ] ) {
110+ const token1 = tokens [ i ] ;
111+ assert ( token1 , `Token config missing at index ${ i } ` ) ;
112+ const { chainName, addressOrDenom } = parseTokenConnectionId (
113+ connection . token ,
114+ ) ;
115+ const token2 = tokens . find (
116+ ( token ) =>
117+ token . chainName === chainName &&
118+ token . addressOrDenom === addressOrDenom &&
119+ ( ! token1 . warpRouteId || token . warpRouteId === token1 . warpRouteId ) ,
120+ ) ;
121+ assert (
122+ token2 ,
123+ `Connected token not found: ${ chainName } ${ addressOrDenom } ` ,
124+ ) ;
125+ token1 . addConnection ( {
126+ ...connection ,
127+ token : token2 ,
128+ } ) ;
129+ }
130+ } ) ;
112131
113- protected override createNativeToken ( chainMetadata : ChainMetadata ) : Token {
114- return Token . FromChainMetadataNativeToken ( chainMetadata ) ;
132+ return new WarpCore ( multiProvider , tokens , parsedConfig . options ) ;
115133 }
116134
117135 /**
@@ -1253,6 +1271,91 @@ export class WarpCore extends WarpRouteGraph<Token> {
12531271 return null ;
12541272 }
12551273
1274+ protected resolveDestinationToken ( {
1275+ originToken,
1276+ destination,
1277+ destinationToken,
1278+ } : {
1279+ originToken : IToken ;
1280+ destination : ChainNameOrId ;
1281+ destinationToken ?: IToken ;
1282+ } ) : IToken {
1283+ const destinationName = this . multiProvider . getChainName ( destination ) ;
1284+ const destinationCandidates = originToken
1285+ . getConnections ( )
1286+ . filter ( ( connection ) => connection . token . chainName === destinationName )
1287+ . map ( ( connection ) => connection . token ) ;
1288+
1289+ assert (
1290+ destinationCandidates . length > 0 ,
1291+ `No connection found for ${ destinationName } ` ,
1292+ ) ;
1293+
1294+ if ( destinationToken ) {
1295+ assert (
1296+ destinationToken . chainName === destinationName ,
1297+ `Destination token chain mismatch for ${ destinationName } ` ,
1298+ ) ;
1299+ const matchedToken = destinationCandidates . find (
1300+ ( candidate ) =>
1301+ candidate . equals ( destinationToken ) ||
1302+ candidate . addressOrDenom . toLowerCase ( ) ===
1303+ destinationToken . addressOrDenom . toLowerCase ( ) ,
1304+ ) ;
1305+ assert (
1306+ matchedToken ,
1307+ `Destination token ${ destinationToken . addressOrDenom } is not connected from ${ originToken . chainName } to ${ destinationName } ` ,
1308+ ) ;
1309+ return matchedToken ;
1310+ }
1311+
1312+ assert (
1313+ destinationCandidates . length === 1 ,
1314+ `Ambiguous route to ${ destinationName } ; specify destination token` ,
1315+ ) ;
1316+ return destinationCandidates [ 0 ] ;
1317+ }
1318+
1319+ findToken (
1320+ chainName : ChainName ,
1321+ addressOrDenom ?: Address | string ,
1322+ ) : Token | null {
1323+ if ( ! addressOrDenom ) return null ;
1324+
1325+ const results = this . tokens . filter (
1326+ ( token ) =>
1327+ token . chainName === chainName &&
1328+ token . addressOrDenom . toLowerCase ( ) === addressOrDenom . toLowerCase ( ) ,
1329+ ) ;
1330+
1331+ if ( results . length === 1 ) return results [ 0 ] ;
1332+
1333+ if ( results . length > 1 )
1334+ throw new Error ( `Ambiguous token search results for ${ addressOrDenom } ` ) ;
1335+
1336+ const chainMetadata = this . multiProvider . getChainMetadata ( chainName ) ;
1337+ if ( chainMetadata . nativeToken ?. denom === addressOrDenom ) {
1338+ return Token . FromChainMetadataNativeToken ( chainMetadata ) ;
1339+ }
1340+
1341+ return null ;
1342+ }
1343+
1344+ getTokenChains ( ) : ChainName [ ] {
1345+ return [ ...new Set ( this . tokens . map ( ( token ) => token . chainName ) ) . values ( ) ] ;
1346+ }
1347+
1348+ getTokensForChain ( chainName : ChainName ) : Token [ ] {
1349+ return this . tokens . filter ( ( token ) => token . chainName === chainName ) ;
1350+ }
1351+
1352+ getTokensForRoute ( origin : ChainName , destination : ChainName ) : Token [ ] {
1353+ return this . tokens . filter (
1354+ ( token ) =>
1355+ token . chainName === origin && token . getConnectionForChain ( destination ) ,
1356+ ) ;
1357+ }
1358+
12561359 /**
12571360 * Ensure the sender has sufficient balances for transfer and interchain gas
12581361 */
0 commit comments