diff --git a/.changeset/late-fishes-end.md b/.changeset/late-fishes-end.md new file mode 100644 index 0000000000..1fe798f3cf --- /dev/null +++ b/.changeset/late-fishes-end.md @@ -0,0 +1,5 @@ +--- +'@hyperlane-xyz/sdk': patch +--- + +Fix contract address filtering to remove undefined factory addresses from the addresses map diff --git a/typescript/sdk/src/contracts/contracts.ts b/typescript/sdk/src/contracts/contracts.ts index df235c7e3f..ee79bc1e0b 100644 --- a/typescript/sdk/src/contracts/contracts.ts +++ b/typescript/sdk/src/contracts/contracts.ts @@ -1,4 +1,4 @@ -import { Contract } from 'ethers'; +import { Contract, constants } from 'ethers'; import { Ownable, Ownable__factory } from '@hyperlane-xyz/core'; import { @@ -12,6 +12,7 @@ import { objMap, pick, promiseObjAll, + rootLogger, } from '@hyperlane-xyz/utils'; import { ChainMetadataManager } from '../metadata/ChainMetadataManager.js'; @@ -62,9 +63,35 @@ export function filterAddressesMap( const pickedAddressesMap = objMap(addressesMap, (_, addresses) => pick(addresses, factoryKeys), ); + + const chainsWithMissingAddresses = new Set(); + const filledAddressesMap = objMap( + pickedAddressesMap, + (chainName, addresses) => + objMap(addresses, (key, value) => { + if (!value) { + rootLogger.warn( + `Missing address for contract "${key}" on chain ${chainName}`, + ); + chainsWithMissingAddresses.add(chainName); + return constants.AddressZero; + } + return value; + }), + ); + // Add summary warning if any addresses were missing + if (chainsWithMissingAddresses.size > 0) { + rootLogger.warn( + `Warning: Core deployment incomplete for chain(s): ${Array.from( + chainsWithMissingAddresses, + ).join(', ')}. ` + + `Please run 'core deploy' again for these chains to fix the deployment.`, + ); + } + // Filter out chains for which we do not have a complete set of addresses return objFilter( - pickedAddressesMap, + filledAddressesMap, (_, addresses): addresses is HyperlaneAddresses => { return Object.keys(addresses).every((a) => factoryKeys.includes(a)); },