diff --git a/typescript/helloworld/src/multiProtocolApp/evmAdapter.ts b/typescript/helloworld/src/multiProtocolApp/evmAdapter.ts index 481c1eb34d..0d565f4657 100644 --- a/typescript/helloworld/src/multiProtocolApp/evmAdapter.ts +++ b/typescript/helloworld/src/multiProtocolApp/evmAdapter.ts @@ -29,6 +29,7 @@ export class EvmHelloWorldAdapter destination: ChainName, message: string, value: string, + sender: Address, ): Promise { const contract = this.getConnectedContract(); const toDomain = this.multiProvider.getDomainId(destination); @@ -44,7 +45,14 @@ export class EvmHelloWorldAdapter const estimated = await contract.estimateGas.sendHelloWorld( toDomain, message, - { ...transactionOverrides, value: BigNumber.from(value).add(quote) }, + { + ...transactionOverrides, + // Some networks, like PolygonZkEvm, require a `from` address + // with funds to be specified when estimating gas for a transaction + // that provides non-zero `value`. + from: sender, + value: BigNumber.from(value).add(quote), + }, ); const gasLimit = estimated.mul(12).div(10); diff --git a/typescript/infra/scripts/helloworld/utils.ts b/typescript/infra/scripts/helloworld/utils.ts index 7c4ec54756..cfddb9ee37 100644 --- a/typescript/infra/scripts/helloworld/utils.ts +++ b/typescript/infra/scripts/helloworld/utils.ts @@ -128,7 +128,7 @@ export async function getHelloWorldMultiProtocolApp( }), ); const app = new HelloMultiProtocolApp( - multiProtocolProvider, + multiProtocolProvider.intersect(Object.keys(routersAndMailboxes)).result, routersAndMailboxes, ); diff --git a/typescript/sdk/src/app/MultiProtocolApp.test.ts b/typescript/sdk/src/app/MultiProtocolApp.test.ts index 68f695ba52..9c69f39fb0 100644 --- a/typescript/sdk/src/app/MultiProtocolApp.test.ts +++ b/typescript/sdk/src/app/MultiProtocolApp.test.ts @@ -26,7 +26,13 @@ describe('MultiProtocolApp', () => { describe('constructs', () => { const multiProvider = new MultiProtocolProvider(); it('creates an app class and gleans types from generic', async () => { - const app = new TestMultiProtocolApp(multiProvider, {}); + const addresses = { + ethereum: {}, + }; + const app = new TestMultiProtocolApp( + multiProvider.intersect(Object.keys(addresses)).result, + addresses, + ); expect(app).to.be.instanceOf(MultiProtocolApp); expect(app.adapter(Chains.ethereum).protocol).to.eql( ProtocolType.Ethereum, diff --git a/typescript/sdk/src/app/MultiProtocolApp.ts b/typescript/sdk/src/app/MultiProtocolApp.ts index daf841dcad..e9c99d3a8e 100644 --- a/typescript/sdk/src/app/MultiProtocolApp.ts +++ b/typescript/sdk/src/app/MultiProtocolApp.ts @@ -6,6 +6,7 @@ import { ProtocolType, objMap, promiseObjAll, + symmetricDifference, } from '@hyperlane-xyz/utils'; import { ChainMetadata } from '../metadata/chainMetadataTypes'; @@ -120,6 +121,22 @@ export abstract class MultiProtocolApp< public readonly addresses: ChainMap, public readonly logger = debug('hyperlane:MultiProtocolApp'), ) { + const multiProviderChains = multiProvider.getKnownChainNames(); + const addressesChains = Object.keys(addresses); + const setDifference = symmetricDifference( + new Set(multiProviderChains), + new Set(addressesChains), + ); + if (setDifference.size > 0) { + throw new Error( + `MultiProtocolProvider and addresses must have the same chains. Provider chains: ${multiProviderChains.join( + ', ', + )}. Addresses chains: ${addressesChains.join( + ', ', + )}. Difference: ${Array.from(setDifference)}`, + ); + } + super(multiProvider.metadata); } diff --git a/typescript/sdk/src/router/MultiProtocolRouterApps.test.ts b/typescript/sdk/src/router/MultiProtocolRouterApps.test.ts index c075da32f9..e00b49e989 100644 --- a/typescript/sdk/src/router/MultiProtocolRouterApps.test.ts +++ b/typescript/sdk/src/router/MultiProtocolRouterApps.test.ts @@ -12,9 +12,13 @@ describe('MultiProtocolRouterApp', () => { describe('constructs', () => { const multiProvider = new MultiProtocolProvider(); it('creates an app class', async () => { - const app = new MultiProtocolRouterApp(multiProvider, { + const addresses = { ethereum: { router: ethers.constants.AddressZero }, - }); + }; + const app = new MultiProtocolRouterApp( + multiProvider.intersect(Object.keys(addresses)).result, + addresses, + ); expect(app).to.be.instanceOf(MultiProtocolRouterApp); const ethAdapter = app.adapter(Chains.ethereum); expect(ethAdapter).to.be.instanceOf(EvmRouterAdapter);