Add checkers for middlewares (#2030)

### Description

This PR adds apps and checkers for the ICA and IQS middlewares.


### Drive-by changes

- Remove redundant lines from writeJSON
- Automatically detect ownables in checkers
- Automatically detect proxied contracts in checkers
- Deploy ICA and IQS to testnet3


### Backward compatibility

_Are these changes backward compatible?_

Yes

_Are there any infrastructure implications, e.g. changes that would
prohibit deploying older commits using this infra tooling?_

None


### Testing

_What kind of testing have these changes undergone?_

Unit Tests

---------

Co-authored-by: Yorke Rhodes <yorke@hyperlane.xyz>
test-sol-fixes
Asa Oines 2 years ago committed by GitHub
parent 08f3b9b32b
commit 17b400806e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 2
      .github/workflows/node.yml
  2. 2
      typescript/helloworld
  3. 110
      typescript/infra/config/environments/testnet3/middleware/queries/verification.json
  4. 18
      typescript/infra/scripts/check-deploy.ts
  5. 25
      typescript/infra/src/middleware/account/govern.ts
  6. 25
      typescript/infra/src/middleware/query/govern.ts
  7. 3
      typescript/infra/src/utils/utils.ts
  8. 15
      typescript/sdk/src/HyperlaneApp.ts
  9. 8
      typescript/sdk/src/consts/environments/mainnet.json
  10. 52
      typescript/sdk/src/consts/environments/test.json
  11. 18
      typescript/sdk/src/core/HyperlaneCoreChecker.ts
  12. 83
      typescript/sdk/src/deploy/HyperlaneAppChecker.ts
  13. 1
      typescript/sdk/src/deploy/types.ts
  14. 18
      typescript/sdk/src/gas/HyperlaneIgpChecker.ts
  15. 27
      typescript/sdk/src/index.ts
  16. 20
      typescript/sdk/src/middleware/MiddlewareRouterChecker.ts
  17. 96
      typescript/sdk/src/middleware/MiddlewareRouterDeployer.ts
  18. 59
      typescript/sdk/src/middleware/account/InterchainAccount.ts
  19. 11
      typescript/sdk/src/middleware/account/InterchainAccountChecker.ts
  20. 113
      typescript/sdk/src/middleware/account/InterchainAccountDeployer.ts
  21. 43
      typescript/sdk/src/middleware/account/accounts.hardhat-test.ts
  22. 23
      typescript/sdk/src/middleware/account/contracts.ts
  23. 207
      typescript/sdk/src/middleware/deploy.ts
  24. 45
      typescript/sdk/src/middleware/liquidity-layer/LiquidityLayerRouterDeployer.ts
  25. 28
      typescript/sdk/src/middleware/liquidity-layer/contracts.ts
  26. 3
      typescript/sdk/src/middleware/liquidity-layer/liquidity-layer.hardhat-test.ts
  27. 58
      typescript/sdk/src/middleware/query/InterchainQuery.ts
  28. 11
      typescript/sdk/src/middleware/query/InterchainQueryChecker.ts
  29. 31
      typescript/sdk/src/middleware/query/InterchainQueryDeployer.ts
  30. 23
      typescript/sdk/src/middleware/query/contracts.ts
  31. 35
      typescript/sdk/src/middleware/query/queries.hardhat-test.ts
  32. 15
      typescript/sdk/src/proxy.ts
  33. 13
      typescript/sdk/src/router/GasRouterDeployer.ts
  34. 24
      typescript/sdk/src/router/HyperlaneRouterChecker.ts
  35. 38
      typescript/sdk/src/router/HyperlaneRouterDeployer.ts
  36. 33
      typescript/sdk/src/router/RouterApps.ts
  37. 39
      typescript/sdk/src/router/app.ts
  38. 37
      typescript/sdk/src/router/types.ts
  39. 53
      typescript/sdk/src/test/envSubsetDeployer/app.ts
  40. 12
      typescript/sdk/src/test/envSubsetDeployer/check-single-chain.ts
  41. 13
      typescript/sdk/src/test/envSubsetDeployer/deploy.hardhat-test.ts
  42. 2
      typescript/token

@ -115,7 +115,7 @@ jobs:
strategy: strategy:
matrix: matrix:
environment: [testnet3, mainnet2] environment: [testnet3, mainnet2]
module: [core, igp] module: [core, igp, ica, iqs]
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v3

@ -1 +1 @@
Subproject commit 3b443c79bcb7671ef3d49ba7d6765c9adb139789 Subproject commit 591edb07f44e67d95220e6c89d669f11cde68501

@ -2,65 +2,127 @@
"alfajores": [ "alfajores": [
{ {
"name": "InterchainQueryRouter", "name": "InterchainQueryRouter",
"address": "0xF782C6C4A02f2c71BB8a1Db0166FAB40ea956818", "address": "0xfFf9dB6C772525B17cd4eB863A09DcD43e085F59",
"isProxy": false, "constructorArguments": "0x",
"constructorArguments": "0x" "isProxy": false
},
{
"name": "TransparentUpgradeableProxy",
"address": "0xC87F9a6cADF77995b18FddE5049b6274695Dd559",
"constructorArguments": "0x000000000000000000000000c97d8e6f57b0d64971453ddc6eb8483fec9d163a000000000000000000000000fad1c94469700833717fa8a3017278bc1ca8031c00000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000000",
"isProxy": true
} }
], ],
"fuji": [ "fuji": [
{ {
"name": "InterchainQueryRouter", "name": "InterchainQueryRouter",
"address": "0xF782C6C4A02f2c71BB8a1Db0166FAB40ea956818", "address": "0xfFf9dB6C772525B17cd4eB863A09DcD43e085F59",
"isProxy": false, "constructorArguments": "0x",
"constructorArguments": "0x" "isProxy": false
},
{
"name": "TransparentUpgradeableProxy",
"address": "0xC87F9a6cADF77995b18FddE5049b6274695Dd559",
"constructorArguments": "0x000000000000000000000000c97d8e6f57b0d64971453ddc6eb8483fec9d163a000000000000000000000000fad1c94469700833717fa8a3017278bc1ca8031c00000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000000",
"isProxy": true
} }
], ],
"mumbai": [ "mumbai": [
{ {
"name": "InterchainQueryRouter", "name": "InterchainQueryRouter",
"address": "0xF782C6C4A02f2c71BB8a1Db0166FAB40ea956818", "address": "0xfFf9dB6C772525B17cd4eB863A09DcD43e085F59",
"isProxy": false, "constructorArguments": "0x",
"constructorArguments": "0x" "isProxy": false
},
{
"name": "TransparentUpgradeableProxy",
"address": "0xC87F9a6cADF77995b18FddE5049b6274695Dd559",
"constructorArguments": "0x000000000000000000000000c97d8e6f57b0d64971453ddc6eb8483fec9d163a000000000000000000000000fad1c94469700833717fa8a3017278bc1ca8031c00000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000000",
"isProxy": true
} }
], ],
"bsctestnet": [ "bsctestnet": [
{ {
"name": "InterchainQueryRouter", "name": "InterchainQueryRouter",
"address": "0xF782C6C4A02f2c71BB8a1Db0166FAB40ea956818", "address": "0xfFf9dB6C772525B17cd4eB863A09DcD43e085F59",
"isProxy": false, "constructorArguments": "0x",
"constructorArguments": "0x" "isProxy": false
},
{
"name": "TransparentUpgradeableProxy",
"address": "0xC87F9a6cADF77995b18FddE5049b6274695Dd559",
"constructorArguments": "0x000000000000000000000000c97d8e6f57b0d64971453ddc6eb8483fec9d163a000000000000000000000000fad1c94469700833717fa8a3017278bc1ca8031c00000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000000",
"isProxy": true
} }
], ],
"goerli": [ "goerli": [
{ {
"name": "InterchainQueryRouter", "name": "InterchainQueryRouter",
"address": "0xF782C6C4A02f2c71BB8a1Db0166FAB40ea956818", "address": "0xfFf9dB6C772525B17cd4eB863A09DcD43e085F59",
"isProxy": false, "constructorArguments": "0x",
"constructorArguments": "0x" "isProxy": false
},
{
"name": "TransparentUpgradeableProxy",
"address": "0xC87F9a6cADF77995b18FddE5049b6274695Dd559",
"constructorArguments": "0x000000000000000000000000c97d8e6f57b0d64971453ddc6eb8483fec9d163a000000000000000000000000fad1c94469700833717fa8a3017278bc1ca8031c00000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000000",
"isProxy": true
} }
], ],
"moonbasealpha": [ "moonbasealpha": [
{ {
"name": "InterchainQueryRouter", "name": "InterchainQueryRouter",
"address": "0xF782C6C4A02f2c71BB8a1Db0166FAB40ea956818", "address": "0xfFf9dB6C772525B17cd4eB863A09DcD43e085F59",
"isProxy": false, "constructorArguments": "0x",
"constructorArguments": "0x" "isProxy": false
},
{
"name": "TransparentUpgradeableProxy",
"address": "0xC87F9a6cADF77995b18FddE5049b6274695Dd559",
"constructorArguments": "0x000000000000000000000000c97d8e6f57b0d64971453ddc6eb8483fec9d163a000000000000000000000000fad1c94469700833717fa8a3017278bc1ca8031c00000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000000",
"isProxy": true
} }
], ],
"optimismgoerli": [ "optimismgoerli": [
{ {
"name": "InterchainQueryRouter", "name": "InterchainQueryRouter",
"address": "0xF782C6C4A02f2c71BB8a1Db0166FAB40ea956818", "address": "0xfFf9dB6C772525B17cd4eB863A09DcD43e085F59",
"isProxy": false, "constructorArguments": "0x",
"constructorArguments": "0x" "isProxy": false
},
{
"name": "TransparentUpgradeableProxy",
"address": "0xC87F9a6cADF77995b18FddE5049b6274695Dd559",
"constructorArguments": "0x000000000000000000000000c97d8e6f57b0d64971453ddc6eb8483fec9d163a000000000000000000000000fad1c94469700833717fa8a3017278bc1ca8031c00000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000000",
"isProxy": true
} }
], ],
"arbitrumgoerli": [ "arbitrumgoerli": [
{ {
"name": "InterchainQueryRouter", "name": "InterchainQueryRouter",
"address": "0xF782C6C4A02f2c71BB8a1Db0166FAB40ea956818", "address": "0xfFf9dB6C772525B17cd4eB863A09DcD43e085F59",
"isProxy": false, "constructorArguments": "0x",
"constructorArguments": "0x" "isProxy": false
},
{
"name": "TransparentUpgradeableProxy",
"address": "0xC87F9a6cADF77995b18FddE5049b6274695Dd559",
"constructorArguments": "0x000000000000000000000000c97d8e6f57b0d64971453ddc6eb8483fec9d163a000000000000000000000000fad1c94469700833717fa8a3017278bc1ca8031c00000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000000",
"isProxy": true
}
],
"sepolia": [
{
"name": "InterchainQueryRouter",
"address": "0xfFf9dB6C772525B17cd4eB863A09DcD43e085F59",
"constructorArguments": "0x",
"isProxy": false
},
{
"name": "TransparentUpgradeableProxy",
"address": "0xC87F9a6cADF77995b18FddE5049b6274695Dd559",
"constructorArguments": "0x000000000000000000000000c97d8e6f57b0d64971453ddc6eb8483fec9d163a000000000000000000000000fad1c94469700833717fa8a3017278bc1ca8031c00000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000000",
"isProxy": true
} }
] ]
} }

@ -3,23 +3,31 @@ import {
HyperlaneCoreChecker, HyperlaneCoreChecker,
HyperlaneIgp, HyperlaneIgp,
HyperlaneIgpChecker, HyperlaneIgpChecker,
InterchainAccount,
InterchainAccountChecker,
InterchainQuery,
InterchainQueryChecker,
} from '@hyperlane-xyz/sdk'; } from '@hyperlane-xyz/sdk';
import { deployEnvToSdkEnv } from '../src/config/environment'; import { deployEnvToSdkEnv } from '../src/config/environment';
import { HyperlaneCoreGovernor } from '../src/core/govern'; import { HyperlaneCoreGovernor } from '../src/core/govern';
import { HyperlaneIgpGovernor } from '../src/gas/govern'; import { HyperlaneIgpGovernor } from '../src/gas/govern';
import { HyperlaneAppGovernor } from '../src/govern/HyperlaneAppGovernor'; import { HyperlaneAppGovernor } from '../src/govern/HyperlaneAppGovernor';
import { InterchainAccountGovernor } from '../src/middleware/account/govern';
import { InterchainQueryGovernor } from '../src/middleware/query/govern';
import { impersonateAccount, useLocalProvider } from '../src/utils/fork'; import { impersonateAccount, useLocalProvider } from '../src/utils/fork';
import { import {
Modules, Modules,
getArgsWithModuleAndFork, getArgsWithModuleAndFork,
getEnvironmentConfig, getEnvironmentConfig,
getRouterConfig,
} from './utils'; } from './utils';
async function check() { async function check() {
const { fork, govern, module, environment } = await getArgsWithModuleAndFork() const { fork, govern, module, environment } = await getArgsWithModuleAndFork()
.boolean('govern') .boolean('govern')
.default('govern', false)
.alias('g', 'govern').argv; .alias('g', 'govern').argv;
const config = await getEnvironmentConfig(); const config = await getEnvironmentConfig();
const multiProvider = await config.getMultiProvider(); const multiProvider = await config.getMultiProvider();
@ -44,6 +52,16 @@ async function check() {
const igp = HyperlaneIgp.fromEnvironment(env, multiProvider); const igp = HyperlaneIgp.fromEnvironment(env, multiProvider);
const checker = new HyperlaneIgpChecker(multiProvider, igp, config.igp); const checker = new HyperlaneIgpChecker(multiProvider, igp, config.igp);
governor = new HyperlaneIgpGovernor(checker, config.owners); governor = new HyperlaneIgpGovernor(checker, config.owners);
} else if (module === Modules.INTERCHAIN_ACCOUNTS) {
const config = await getRouterConfig(environment, multiProvider);
const ica = InterchainAccount.fromEnvironment(env, multiProvider);
const checker = new InterchainAccountChecker(multiProvider, ica, config);
governor = new InterchainAccountGovernor(checker, config.owners);
} else if (module === Modules.INTERCHAIN_QUERY_SYSTEM) {
const config = await getRouterConfig(environment, multiProvider);
const iqs = InterchainQuery.fromEnvironment(env, multiProvider);
const checker = new InterchainQueryChecker(multiProvider, iqs, config);
governor = new InterchainQueryGovernor(checker, config.owners);
} else { } else {
console.log(`Skipping ${module}, checker or governor unimplemented`); console.log(`Skipping ${module}, checker or governor unimplemented`);
return; return;

@ -0,0 +1,25 @@
import {
ChainMap,
InterchainAccount,
InterchainAccountChecker,
InterchainAccountConfig,
} from '@hyperlane-xyz/sdk';
import { types } from '@hyperlane-xyz/utils';
import { HyperlaneAppGovernor } from '../../govern/HyperlaneAppGovernor';
export class InterchainAccountGovernor extends HyperlaneAppGovernor<
InterchainAccount,
InterchainAccountConfig
> {
constructor(
checker: InterchainAccountChecker,
owners: ChainMap<types.Address>,
) {
super(checker, owners);
}
protected async mapViolationsToCalls() {
throw new Error('governor not implemented for account middleware');
}
}

@ -0,0 +1,25 @@
import {
ChainMap,
InterchainQuery,
InterchainQueryChecker,
InterchainQueryConfig,
} from '@hyperlane-xyz/sdk';
import { types } from '@hyperlane-xyz/utils';
import { HyperlaneAppGovernor } from '../../govern/HyperlaneAppGovernor';
export class InterchainQueryGovernor extends HyperlaneAppGovernor<
InterchainQuery,
InterchainQueryConfig
> {
constructor(
checker: InterchainQueryChecker,
owners: ChainMap<types.Address>,
) {
super(checker, owners);
}
protected async mapViolationsToCalls() {
throw new Error('governor not implemented for query middleware');
}
}

@ -179,9 +179,6 @@ export function writeJsonAtPath(filepath: string, obj: any) {
} }
export function writeJSON(directory: string, filename: string, obj: any) { export function writeJSON(directory: string, filename: string, obj: any) {
if (!fs.existsSync(directory)) {
fs.mkdirSync(directory, { recursive: true });
}
writeJsonAtPath(path.join(directory, filename), obj); writeJsonAtPath(path.join(directory, filename), obj);
} }

@ -1,5 +1,6 @@
import { import {
HyperlaneAddresses, HyperlaneAddresses,
HyperlaneContract,
HyperlaneContracts, HyperlaneContracts,
HyperlaneFactories, HyperlaneFactories,
buildContracts, buildContracts,
@ -7,9 +8,10 @@ import {
serializeContracts, serializeContracts,
} from './contracts'; } from './contracts';
import { MultiProvider } from './providers/MultiProvider'; import { MultiProvider } from './providers/MultiProvider';
import { isProxiedContract } from './proxy';
import { ChainMap, ChainName } from './types'; import { ChainMap, ChainName } from './types';
import { MultiGeneric } from './utils/MultiGeneric'; import { MultiGeneric } from './utils/MultiGeneric';
import { objMap, pick } from './utils/objects'; import { objFilter, objMap, pick } from './utils/objects';
export class HyperlaneApp< export class HyperlaneApp<
Contracts extends HyperlaneContracts, Contracts extends HyperlaneContracts,
@ -45,6 +47,17 @@ export class HyperlaneApp<
return this.get(chain); return this.get(chain);
} }
getFlattenedFilteredContracts<K extends HyperlaneContract>(
chain: ChainName,
filter: (k: ChainName, v: HyperlaneContract) => v is K,
): { [key: string]: K } {
const filtered = objFilter(this.getContracts(chain), filter);
const flattened = objMap(filtered, (name, contract) =>
isProxiedContract(contract) ? contract.contract : contract,
);
return flattened;
}
getAddresses(chain: ChainName): HyperlaneAddresses { getAddresses(chain: ChainName): HyperlaneAddresses {
return serializeContracts(this.get(chain)); return serializeContracts(this.get(chain));
} }

@ -17,7 +17,6 @@
"multisigIsm": "0x9bDE63104EE030d9De419EEd6bA7D14b86D6fE3f", "multisigIsm": "0x9bDE63104EE030d9De419EEd6bA7D14b86D6fE3f",
"create2Factory": "0xc97D8e6f57b0d64971453dDc6EB8483fec9d163a", "create2Factory": "0xc97D8e6f57b0d64971453dDc6EB8483fec9d163a",
"testRecipient": "0x36FdA966CfffF8a9Cdc814f546db0e6378bFef35", "testRecipient": "0x36FdA966CfffF8a9Cdc814f546db0e6378bFef35",
"interchainAccountRouter": "0xE0Be420779cAd6E2bEA1E4F7C02F996D9ED1fCB5",
"interchainQueryRouter": "0x234b19282985882d6d6fd54dEBa272271f4eb784" "interchainQueryRouter": "0x234b19282985882d6d6fd54dEBa272271f4eb784"
}, },
"ethereum": { "ethereum": {
@ -38,7 +37,6 @@
"multisigIsm": "0xec48E52D960E54a179f70907bF28b105813877ee", "multisigIsm": "0xec48E52D960E54a179f70907bF28b105813877ee",
"create2Factory": "0xc97D8e6f57b0d64971453dDc6EB8483fec9d163a", "create2Factory": "0xc97D8e6f57b0d64971453dDc6EB8483fec9d163a",
"testRecipient": "0x36FdA966CfffF8a9Cdc814f546db0e6378bFef35", "testRecipient": "0x36FdA966CfffF8a9Cdc814f546db0e6378bFef35",
"interchainAccountRouter": "0xE0Be420779cAd6E2bEA1E4F7C02F996D9ED1fCB5",
"interchainQueryRouter": "0x234b19282985882d6d6fd54dEBa272271f4eb784" "interchainQueryRouter": "0x234b19282985882d6d6fd54dEBa272271f4eb784"
}, },
"avalanche": { "avalanche": {
@ -59,7 +57,6 @@
"multisigIsm": "0xeE80ab5B563cB3825133f29502bA34eD3707cb8C", "multisigIsm": "0xeE80ab5B563cB3825133f29502bA34eD3707cb8C",
"create2Factory": "0xc97D8e6f57b0d64971453dDc6EB8483fec9d163a", "create2Factory": "0xc97D8e6f57b0d64971453dDc6EB8483fec9d163a",
"testRecipient": "0x36FdA966CfffF8a9Cdc814f546db0e6378bFef35", "testRecipient": "0x36FdA966CfffF8a9Cdc814f546db0e6378bFef35",
"interchainAccountRouter": "0xE0Be420779cAd6E2bEA1E4F7C02F996D9ED1fCB5",
"interchainQueryRouter": "0x234b19282985882d6d6fd54dEBa272271f4eb784" "interchainQueryRouter": "0x234b19282985882d6d6fd54dEBa272271f4eb784"
}, },
"polygon": { "polygon": {
@ -80,7 +77,6 @@
"multisigIsm": "0x61A80297e77FC5395bd6Ff60EEacf7CD4f18d4a4", "multisigIsm": "0x61A80297e77FC5395bd6Ff60EEacf7CD4f18d4a4",
"create2Factory": "0xc97D8e6f57b0d64971453dDc6EB8483fec9d163a", "create2Factory": "0xc97D8e6f57b0d64971453dDc6EB8483fec9d163a",
"testRecipient": "0x36FdA966CfffF8a9Cdc814f546db0e6378bFef35", "testRecipient": "0x36FdA966CfffF8a9Cdc814f546db0e6378bFef35",
"interchainAccountRouter": "0xE0Be420779cAd6E2bEA1E4F7C02F996D9ED1fCB5",
"interchainQueryRouter": "0x234b19282985882d6d6fd54dEBa272271f4eb784" "interchainQueryRouter": "0x234b19282985882d6d6fd54dEBa272271f4eb784"
}, },
"bsc": { "bsc": {
@ -101,7 +97,6 @@
"multisigIsm": "0x3a579C0bd04FC4C98A8D70EEABD9094e7be4B26D", "multisigIsm": "0x3a579C0bd04FC4C98A8D70EEABD9094e7be4B26D",
"create2Factory": "0xc97D8e6f57b0d64971453dDc6EB8483fec9d163a", "create2Factory": "0xc97D8e6f57b0d64971453dDc6EB8483fec9d163a",
"testRecipient": "0x36FdA966CfffF8a9Cdc814f546db0e6378bFef35", "testRecipient": "0x36FdA966CfffF8a9Cdc814f546db0e6378bFef35",
"interchainAccountRouter": "0xE0Be420779cAd6E2bEA1E4F7C02F996D9ED1fCB5",
"interchainQueryRouter": "0x234b19282985882d6d6fd54dEBa272271f4eb784" "interchainQueryRouter": "0x234b19282985882d6d6fd54dEBa272271f4eb784"
}, },
"arbitrum": { "arbitrum": {
@ -122,7 +117,6 @@
"multisigIsm": "0x32B92bd3e5045B67FDD8dbb7A58D25980836d04C", "multisigIsm": "0x32B92bd3e5045B67FDD8dbb7A58D25980836d04C",
"create2Factory": "0xc97D8e6f57b0d64971453dDc6EB8483fec9d163a", "create2Factory": "0xc97D8e6f57b0d64971453dDc6EB8483fec9d163a",
"testRecipient": "0x36FdA966CfffF8a9Cdc814f546db0e6378bFef35", "testRecipient": "0x36FdA966CfffF8a9Cdc814f546db0e6378bFef35",
"interchainAccountRouter": "0xE0Be420779cAd6E2bEA1E4F7C02F996D9ED1fCB5",
"interchainQueryRouter": "0x234b19282985882d6d6fd54dEBa272271f4eb784" "interchainQueryRouter": "0x234b19282985882d6d6fd54dEBa272271f4eb784"
}, },
"optimism": { "optimism": {
@ -143,7 +137,6 @@
"multisigIsm": "0xAab1D11E2063Bae5EB01fa946cA8d2FDe3db05D5", "multisigIsm": "0xAab1D11E2063Bae5EB01fa946cA8d2FDe3db05D5",
"create2Factory": "0xc97D8e6f57b0d64971453dDc6EB8483fec9d163a", "create2Factory": "0xc97D8e6f57b0d64971453dDc6EB8483fec9d163a",
"testRecipient": "0x36FdA966CfffF8a9Cdc814f546db0e6378bFef35", "testRecipient": "0x36FdA966CfffF8a9Cdc814f546db0e6378bFef35",
"interchainAccountRouter": "0xE0Be420779cAd6E2bEA1E4F7C02F996D9ED1fCB5",
"interchainQueryRouter": "0x234b19282985882d6d6fd54dEBa272271f4eb784" "interchainQueryRouter": "0x234b19282985882d6d6fd54dEBa272271f4eb784"
}, },
"moonbeam": { "moonbeam": {
@ -164,7 +157,6 @@
"multisigIsm": "0xf3b1F415740A26568C45b1c771A737E31C198F09", "multisigIsm": "0xf3b1F415740A26568C45b1c771A737E31C198F09",
"create2Factory": "0xc97D8e6f57b0d64971453dDc6EB8483fec9d163a", "create2Factory": "0xc97D8e6f57b0d64971453dDc6EB8483fec9d163a",
"testRecipient": "0x36FdA966CfffF8a9Cdc814f546db0e6378bFef35", "testRecipient": "0x36FdA966CfffF8a9Cdc814f546db0e6378bFef35",
"interchainAccountRouter": "0xE0Be420779cAd6E2bEA1E4F7C02F996D9ED1fCB5",
"interchainQueryRouter": "0x234b19282985882d6d6fd54dEBa272271f4eb784" "interchainQueryRouter": "0x234b19282985882d6d6fd54dEBa272271f4eb784"
}, },
"gnosis": { "gnosis": {

@ -1,53 +1,53 @@
{ {
"test1": { "test1": {
"storageGasOracle": "0xDc64a140Aa3E981100a9becA4E685f962f0cF6C9", "storageGasOracle": "0x4ed7c70F96B99c776995fB64377f0d4aB3B0e1C1",
"validatorAnnounce": "0x0DCd1Bf9A1b36cE34237eEaFef220932846BCD82", "validatorAnnounce": "0x0165878A594ca255338adfa4d48449f69242Eb8F",
"proxyAdmin": "0xCf7Ed3AccA5a467e9e704C703E8D87F634fB0Fc9", "proxyAdmin": "0x59b670e9fA9D0A427751Af201D676719a970857b",
"mailbox": { "mailbox": {
"kind": "Transparent", "kind": "Transparent",
"proxy": "0xA51c1fc2f0D1a1b8494Ed1FE312d7C3a78Ed91C0", "proxy": "0x5FC8d32690cc91D4c39d9d3abcBD16989F875707",
"implementation": "0xB7f8BC63BbcaD18155201308C8f3540b07f84F5e" "implementation": "0xDc64a140Aa3E981100a9becA4E685f962f0cF6C9"
}, },
"interchainGasPaymaster": { "interchainGasPaymaster": {
"kind": "Transparent", "kind": "Transparent",
"proxy": "0x0165878A594ca255338adfa4d48449f69242Eb8F", "proxy": "0xa85233C63b9Ee964Add6F2cffe00Fd84eb32338f",
"implementation": "0x5FC8d32690cc91D4c39d9d3abcBD16989F875707" "implementation": "0x322813Fd9A801c5507c9de605d63CEA4f2CE6c44"
}, },
"defaultIsmInterchainGasPaymaster": "0x2279B7A0a67DB372996a5FaB50D91eAA73d2eBe6", "defaultIsmInterchainGasPaymaster": "0x7a2088a1bFc9d81c55368AE168C2C02570cB814F",
"multisigIsm": "0x5FbDB2315678afecb367f032d93F642f64180aa3" "multisigIsm": "0x5FbDB2315678afecb367f032d93F642f64180aa3"
}, },
"test2": { "test2": {
"storageGasOracle": "0x68B1D87F95878fE05B998F19b66F4baba5De1aed", "storageGasOracle": "0xE6E340D132b5f46d1e472DebcD681B2aBc16e57E",
"validatorAnnounce": "0x09635F643e140090A9A8Dcd712eD6285858ceBef", "validatorAnnounce": "0x0DCd1Bf9A1b36cE34237eEaFef220932846BCD82",
"proxyAdmin": "0x9A9f2CCfdE556A7E9Ff0848998Aa4a0CFD8863AE", "proxyAdmin": "0x67d269191c92Caf3cD7723F116c85e6E9bf55933",
"mailbox": { "mailbox": {
"kind": "Transparent", "kind": "Transparent",
"proxy": "0x7a2088a1bFc9d81c55368AE168C2C02570cB814F", "proxy": "0xA51c1fc2f0D1a1b8494Ed1FE312d7C3a78Ed91C0",
"implementation": "0x4A679253410272dd5232B3Ff7cF5dbB88f295319" "implementation": "0xB7f8BC63BbcaD18155201308C8f3540b07f84F5e"
}, },
"interchainGasPaymaster": { "interchainGasPaymaster": {
"kind": "Transparent", "kind": "Transparent",
"proxy": "0xc6e7DF5E7b4f2A278906862b61205850344D4e7d", "proxy": "0x84eA74d481Ee0A5332c457a4d796187F6Ba67fEB",
"implementation": "0x3Aa5ebB10DC797CAC828524e59A333d0A371443c" "implementation": "0xc3e53F4d16Ae77Db1c982e75a937B9f60FE63690"
}, },
"defaultIsmInterchainGasPaymaster": "0x4ed7c70F96B99c776995fB64377f0d4aB3B0e1C1", "defaultIsmInterchainGasPaymaster": "0xa82fF9aFd8f496c3d6ac40E2a0F282E47488CFc9",
"multisigIsm": "0x9A676e781A523b5d0C0e43731313A708CB607508" "multisigIsm": "0xa513E6E4b8f2a923D98304ec87F64353C4D5C853"
}, },
"test3": { "test3": {
"storageGasOracle": "0x84eA74d481Ee0A5332c457a4d796187F6Ba67fEB", "storageGasOracle": "0x95401dc811bb5740090279Ba06cfA8fcF6113778",
"validatorAnnounce": "0x4826533B4897376654Bb4d4AD88B7faFD0C98528", "validatorAnnounce": "0xc6e7DF5E7b4f2A278906862b61205850344D4e7d",
"proxyAdmin": "0xc3e53F4d16Ae77Db1c982e75a937B9f60FE63690", "proxyAdmin": "0xf5059a5D33d5853360D16C683c16e67980206f36",
"mailbox": { "mailbox": {
"kind": "Transparent", "kind": "Transparent",
"proxy": "0x70e0bA845a1A0F2DA3359C97E0285013525FFC49", "proxy": "0x3Aa5ebB10DC797CAC828524e59A333d0A371443c",
"implementation": "0x998abeb3E57409262aE5b751f60747921B33613E" "implementation": "0x68B1D87F95878fE05B998F19b66F4baba5De1aed"
}, },
"interchainGasPaymaster": { "interchainGasPaymaster": {
"kind": "Transparent", "kind": "Transparent",
"proxy": "0xa82fF9aFd8f496c3d6ac40E2a0F282E47488CFc9", "proxy": "0x70e0bA845a1A0F2DA3359C97E0285013525FFC49",
"implementation": "0x9E545E3C0baAB3E08CdfD552C960A1050f373042" "implementation": "0x998abeb3E57409262aE5b751f60747921B33613E"
}, },
"defaultIsmInterchainGasPaymaster": "0x851356ae760d987E095750cCeb3bC6014560891C", "defaultIsmInterchainGasPaymaster": "0x99bbA657f2BbC93c02D617f8bA121cB8Fc104Acf",
"multisigIsm": "0xc5a5C42992dECbae36851359345FE25997F5C42d" "multisigIsm": "0x9A676e781A523b5d0C0e43731313A708CB607508"
} }
} }

@ -40,13 +40,7 @@ export class HyperlaneCoreChecker extends HyperlaneAppChecker<
async checkDomainOwnership(chain: ChainName): Promise<void> { async checkDomainOwnership(chain: ChainName): Promise<void> {
const config = this.configMap[chain]; const config = this.configMap[chain];
if (config.owner) { if (config.owner) {
const contracts = this.app.getContracts(chain); return this.checkOwnership(chain, config.owner);
const ownables = [
contracts.proxyAdmin,
contracts.mailbox.contract,
contracts.multisigIsm,
];
return this.checkOwnership(chain, config.owner, ownables);
} }
} }
@ -118,16 +112,6 @@ export class HyperlaneCoreChecker extends HyperlaneAppChecker<
); );
} }
async checkProxiedContracts(chain: ChainName): Promise<void> {
const contracts = this.app.getContracts(chain);
await this.checkProxiedContract(
chain,
'Mailbox',
contracts.mailbox.addresses,
contracts.proxyAdmin.address,
);
}
async checkValidatorAnnounce(chain: ChainName): Promise<void> { async checkValidatorAnnounce(chain: ChainName): Promise<void> {
const expectedValidators = new Set<string>(); const expectedValidators = new Set<string>();
const remotes = Object.keys(this.configMap).filter((c) => c !== chain); const remotes = Object.keys(this.configMap).filter((c) => c !== chain);

@ -6,11 +6,11 @@ import { utils } from '@hyperlane-xyz/utils';
import { HyperlaneApp } from '../HyperlaneApp'; import { HyperlaneApp } from '../HyperlaneApp';
import { MultiProvider } from '../providers/MultiProvider'; import { MultiProvider } from '../providers/MultiProvider';
import { TransparentProxyAddresses } from '../proxy'; import { ProxiedContract, isProxiedContract } from '../proxy';
import { ChainMap, ChainName } from '../types'; import { ChainMap, ChainName } from '../types';
import { objMap } from '../utils/objects'; import { objMap, promiseObjAll } from '../utils/objects';
import { proxyAdmin, proxyImplementation, proxyViolation } from './proxy'; import { proxyAdmin } from './proxy';
import { import {
BytecodeMismatchViolation, BytecodeMismatchViolation,
CheckerViolation, CheckerViolation,
@ -62,34 +62,36 @@ export abstract class HyperlaneAppChecker<
this.violations.push(violation); this.violations.push(violation);
} }
async checkProxiedContract( async checkProxiedContracts(chain: ChainName): Promise<void> {
chain: ChainName, const expectedAdmin = this.app.getContracts(chain).proxyAdmin.address;
name: string, if (!expectedAdmin) {
proxiedAddress: TransparentProxyAddresses, throw new Error(
proxyAdminAddress?: types.Address, `Checking proxied contracts for ${chain} with no admin provided`,
): Promise<void> {
const provider = this.multiProvider.getProvider(chain);
const implementation = await proxyImplementation(
provider,
proxiedAddress.proxy,
);
if (implementation !== proxiedAddress.implementation) {
this.addViolation(
proxyViolation(chain, name, proxiedAddress, implementation),
); );
} }
if (proxyAdminAddress) { const provider = this.multiProvider.getProvider(chain);
const admin = await proxyAdmin(provider, proxiedAddress.proxy); const isProxied = (
if (admin !== proxyAdminAddress) { _: string,
this.addViolation({ contract: any,
type: ViolationType.ProxyAdmin, ): contract is ProxiedContract<any, any> => {
chain, return isProxiedContract(contract);
name, };
expected: proxyAdminAddress, const proxied = this.app.getFlattenedFilteredContracts(chain, isProxied);
actual: admin, await promiseObjAll(
} as ProxyAdminViolation); objMap(proxied, async (name, contract) => {
} // Check the ProxiedContract's admin matches expectation
} const actualAdmin = await proxyAdmin(provider, contract.address);
if (!utils.eqAddress(actualAdmin, expectedAdmin)) {
this.addViolation({
type: ViolationType.ProxyAdmin,
chain,
name,
expected: expectedAdmin,
actual: actualAdmin,
} as ProxyAdminViolation);
}
}),
);
} }
private removeBytecodeMetadata(bytecode: string): string { private removeBytecodeMetadata(bytecode: string): string {
@ -122,17 +124,24 @@ export abstract class HyperlaneAppChecker<
} }
} }
async checkOwnership( // TODO: Require owner in config if ownables is non-empty
chain: ChainName, async checkOwnership(chain: ChainName, owner: types.Address): Promise<void> {
owner: types.Address, const isOwnable = (_: string, contract: any): contract is Ownable => {
ownables: Ownable[], return (
): Promise<void> { contract !== null &&
await Promise.all( typeof contract === 'object' &&
ownables.map(async (contract) => { contract.owner &&
contract.transferOwnership
);
};
const ownables = this.app.getFlattenedFilteredContracts(chain, isOwnable);
await promiseObjAll(
objMap(ownables, async (name, contract) => {
const actual = await contract.owner(); const actual = await contract.owner();
if (actual.toLowerCase() != owner.toLowerCase()) { if (!utils.eqAddress(actual, owner)) {
const violation: OwnerViolation = { const violation: OwnerViolation = {
chain, chain,
name,
type: ViolationType.Owner, type: ViolationType.Owner,
actual, actual,
expected: owner, expected: owner,

@ -22,6 +22,7 @@ export enum ViolationType {
export interface OwnerViolation extends CheckerViolation { export interface OwnerViolation extends CheckerViolation {
type: ViolationType.Owner; type: ViolationType.Owner;
contract: Ownable; contract: Ownable;
name: string;
} }
export interface ProxyAdminViolation extends CheckerViolation { export interface ProxyAdminViolation extends CheckerViolation {

@ -31,13 +31,7 @@ export class HyperlaneIgpChecker extends HyperlaneAppChecker<
async checkDomainOwnership(chain: ChainName): Promise<void> { async checkDomainOwnership(chain: ChainName): Promise<void> {
const config = this.configMap[chain]; const config = this.configMap[chain];
if (config.owner) { if (config.owner) {
const contracts = this.app.getContracts(chain); return this.checkOwnership(chain, config.owner);
const ownables = [
contracts.proxyAdmin,
contracts.interchainGasPaymaster.contract,
contracts.defaultIsmInterchainGasPaymaster,
];
return this.checkOwnership(chain, config.owner, ownables);
} }
} }
@ -78,16 +72,6 @@ export class HyperlaneIgpChecker extends HyperlaneAppChecker<
); );
} }
async checkProxiedContracts(chain: ChainName): Promise<void> {
const contracts = this.app.getContracts(chain);
await this.checkProxiedContract(
chain,
'InterchainGasPaymaster',
contracts.interchainGasPaymaster.addresses,
contracts.proxyAdmin.address,
);
}
async checkOverheadInterchainGasPaymaster(local: ChainName): Promise<void> { async checkOverheadInterchainGasPaymaster(local: ChainName): Promise<void> {
const coreContracts = this.app.getContracts(local); const coreContracts = this.app.getContracts(local);
const defaultIsmIgp = coreContracts.defaultIsmInterchainGasPaymaster; const defaultIsmIgp = coreContracts.defaultIsmInterchainGasPaymaster;

@ -72,9 +72,9 @@ export {
} from './core/types'; } from './core/types';
export { HyperlaneAppChecker } from './deploy/HyperlaneAppChecker'; export { HyperlaneAppChecker } from './deploy/HyperlaneAppChecker';
export { export {
HyperlaneDeployer,
DeployOptions,
DeployerOptions, DeployerOptions,
DeployOptions,
HyperlaneDeployer,
} from './deploy/HyperlaneDeployer'; } from './deploy/HyperlaneDeployer';
export { ProxyViolation } from './deploy/proxy'; export { ProxyViolation } from './deploy/proxy';
export { export {
@ -110,12 +110,13 @@ export {
OverheadIgpConfig, OverheadIgpConfig,
} from './gas/types'; } from './gas/types';
export { HyperlaneApp } from './HyperlaneApp'; export { HyperlaneApp } from './HyperlaneApp';
export { interchainAccountFactories } from './middleware/account/contracts';
export { InterchainAccount } from './middleware/account/InterchainAccount';
export { InterchainAccountChecker } from './middleware/account/InterchainAccountChecker';
export { export {
InterchainAccountConfig,
InterchainAccountDeployer, InterchainAccountDeployer,
interchainAccountFactories, } from './middleware/account/InterchainAccountDeployer';
InterchainQueryDeployer,
interchainQueryFactories,
} from './middleware/deploy';
export { export {
LiquidityLayerContracts, LiquidityLayerContracts,
liquidityLayerFactories, liquidityLayerFactories,
@ -128,6 +129,13 @@ export {
LiquidityLayerDeployer, LiquidityLayerDeployer,
PortalAdapterConfig, PortalAdapterConfig,
} from './middleware/liquidity-layer/LiquidityLayerRouterDeployer'; } from './middleware/liquidity-layer/LiquidityLayerRouterDeployer';
export { interchainQueryFactories } from './middleware/query/contracts';
export { InterchainQuery } from './middleware/query/InterchainQuery';
export { InterchainQueryChecker } from './middleware/query/InterchainQueryChecker';
export {
InterchainQueryConfig,
InterchainQueryDeployer,
} from './middleware/query/InterchainQueryDeployer';
export { MultiProvider, providerBuilder } from './providers/MultiProvider'; export { MultiProvider, providerBuilder } from './providers/MultiProvider';
export { RetryJsonRpcProvider, RetryProvider } from './providers/RetryProvider'; export { RetryJsonRpcProvider, RetryProvider } from './providers/RetryProvider';
export { export {
@ -140,12 +148,7 @@ export { GasRouterDeployer } from './router/GasRouterDeployer';
export { HyperlaneRouterChecker } from './router/HyperlaneRouterChecker'; export { HyperlaneRouterChecker } from './router/HyperlaneRouterChecker';
export { HyperlaneRouterDeployer } from './router/HyperlaneRouterDeployer'; export { HyperlaneRouterDeployer } from './router/HyperlaneRouterDeployer';
export { GasRouterApp, Router, RouterApp } from './router/RouterApps'; export { GasRouterApp, Router, RouterApp } from './router/RouterApps';
export { export { GasRouterConfig, RouterConfig } from './router/types';
GasRouterConfig,
RouterConfig,
RouterContracts,
RouterFactories,
} from './router/types';
export { export {
createRouterConfigMap, createRouterConfigMap,
deployTestIgpsAndGetRouterConfig, deployTestIgpsAndGetRouterConfig,

@ -0,0 +1,20 @@
import { HyperlaneContracts } from '../contracts';
import { HyperlaneRouterChecker } from '../router/HyperlaneRouterChecker';
import { RouterApp } from '../router/RouterApps';
import { RouterConfig } from '../router/types';
import { ChainName } from '../types';
export abstract class MiddlewareRouterChecker<
MiddlewareRouterApp extends RouterApp<MiddlewareRouterContracts>,
MiddlewareRouterConfig extends RouterConfig,
MiddlewareRouterContracts extends HyperlaneContracts,
> extends HyperlaneRouterChecker<
MiddlewareRouterApp,
MiddlewareRouterConfig,
MiddlewareRouterContracts
> {
async checkChain(chain: ChainName): Promise<void> {
await super.checkChain(chain);
await this.checkProxiedContracts(chain);
}
}

@ -0,0 +1,96 @@
import { ContractFactory, ethers } from 'ethers';
import { ProxyAdmin, Router } from '@hyperlane-xyz/core';
import { MultiProvider } from '../providers/MultiProvider';
import { HyperlaneRouterDeployer } from '../router/HyperlaneRouterDeployer';
import {
ProxiedContracts,
ProxiedFactories,
RouterConfig,
} from '../router/types';
import { ChainMap, ChainName } from '../types';
export abstract class MiddlewareRouterDeployer<
MiddlewareRouterConfig extends RouterConfig,
MiddlewareRouterContracts extends ProxiedContracts,
MiddlewareFactories extends ProxiedFactories,
RouterFactory extends ContractFactory,
> extends HyperlaneRouterDeployer<
MiddlewareRouterConfig,
MiddlewareRouterContracts,
MiddlewareFactories
> {
constructor(
multiProvider: MultiProvider,
configMap: ChainMap<MiddlewareRouterConfig>,
factories: MiddlewareFactories,
protected create2salt = 'middlewarerouter',
) {
super(multiProvider, configMap, factories);
}
constructorArgs(
_chain: ChainName,
_config: MiddlewareRouterConfig,
): Parameters<RouterFactory['deploy']> {
return [] as any;
}
abstract readonly routerContractName: string;
router(contracts: MiddlewareRouterContracts): Router {
return contracts[this.routerContractName].contract;
}
async initializeArgs(
chain: ChainName,
config: MiddlewareRouterConfig,
): Promise<[string, string, string, string]> {
// configure owner as signer for additional initialization steps
// ownership is transferred to config.owner in HyperlaneRouterDeployer.deploy
const owner = await this.multiProvider.getSignerAddress(chain);
return [
config.mailbox,
config.interchainGasPaymaster,
config.interchainSecurityModule ?? ethers.constants.AddressZero,
owner,
];
}
async deployContracts(
chain: ChainName,
config: MiddlewareRouterConfig,
): Promise<MiddlewareRouterContracts> {
const proxyAdmin = (await this.deployContract(
chain,
'proxyAdmin',
[] as any, // generic type inference fails here
)) as ProxyAdmin;
const initArgs = await this.initializeArgs(chain, config);
const proxiedRouter = await this.deployProxiedContract(
chain,
this.routerContractName,
this.constructorArgs(chain, config),
initArgs as any, // generic type inference fails here
proxyAdmin.address,
{
create2Salt: this.create2salt,
},
);
this.logger(`Transferring ownership of proxy admin to ${config.owner}`);
await super.runIfOwner(chain, proxyAdmin, () =>
this.multiProvider.handleTx(
chain,
proxyAdmin.transferOwnership(config.owner),
),
);
const ret: MiddlewareRouterContracts = {
[this.routerContractName]: proxiedRouter,
proxyAdmin,
} as MiddlewareRouterContracts;
return ret;
}
}

@ -0,0 +1,59 @@
import { InterchainAccountRouter } from '@hyperlane-xyz/core';
import {
HyperlaneEnvironment,
hyperlaneEnvironments,
} from '../../consts/environments';
import { HyperlaneAddresses } from '../../contracts';
import { MultiProvider } from '../../providers/MultiProvider';
import { RouterApp } from '../../router/RouterApps';
import { ChainMap, ChainName } from '../../types';
import {
InterchainAccountContracts,
interchainAccountFactories,
} from './contracts';
export type InterchainAccountContractsMap =
ChainMap<InterchainAccountContracts>;
export class InterchainAccount extends RouterApp<InterchainAccountContracts> {
constructor(
contractsMap: InterchainAccountContractsMap,
multiProvider: MultiProvider,
) {
super(contractsMap, multiProvider);
}
router(contracts: InterchainAccountContracts): InterchainAccountRouter {
return contracts.interchainAccountRouter.contract;
}
static fromAddresses(
addresses: ChainMap<HyperlaneAddresses>,
multiProvider: MultiProvider,
): InterchainAccount {
const { contracts, intersectionProvider } =
this.buildContracts<InterchainAccountContracts>(
addresses,
interchainAccountFactories,
multiProvider,
);
return new InterchainAccount(contracts, intersectionProvider);
}
static fromEnvironment<Env extends HyperlaneEnvironment>(
env: Env,
multiProvider: MultiProvider,
): InterchainAccount {
const envAddresses = hyperlaneEnvironments[env];
if (!envAddresses) {
throw new Error(`No addresses found for ${env}`);
}
return InterchainAccount.fromAddresses(envAddresses, multiProvider);
}
getContracts(chain: ChainName): InterchainAccountContracts {
return super.getContracts(chain);
}
}

@ -0,0 +1,11 @@
import { MiddlewareRouterChecker } from '../MiddlewareRouterChecker';
import { InterchainAccount } from './InterchainAccount';
import { InterchainAccountConfig } from './InterchainAccountDeployer';
import { InterchainAccountContracts } from './contracts';
export class InterchainAccountChecker extends MiddlewareRouterChecker<
InterchainAccount,
InterchainAccountConfig,
InterchainAccountContracts
> {}

@ -0,0 +1,113 @@
import {
InterchainAccountRouter,
InterchainAccountRouter__factory,
ProxyAdmin,
TransparentUpgradeableProxy__factory,
} from '@hyperlane-xyz/core';
import { MultiProvider } from '../../providers/MultiProvider';
import { ProxiedContract, ProxyKind } from '../../proxy';
import { RouterConfig } from '../../router/types';
import { ChainMap, ChainName } from '../../types';
import { MiddlewareRouterDeployer } from '../MiddlewareRouterDeployer';
import {
InterchainAccountContracts,
InterchainAccountFactories,
interchainAccountFactories,
} from './contracts';
export type InterchainAccountConfig = RouterConfig;
export class InterchainAccountDeployer extends MiddlewareRouterDeployer<
InterchainAccountConfig,
InterchainAccountContracts,
InterchainAccountFactories,
InterchainAccountRouter__factory
> {
readonly routerContractName = 'interchainAccountRouter';
constructor(
multiProvider: MultiProvider,
configMap: ChainMap<InterchainAccountConfig>,
create2salt = 'accountsrouter',
) {
super(multiProvider, configMap, interchainAccountFactories, create2salt);
}
// The OwnableMulticall implementation has an immutable owner address that
// must be set to the InterchainAccountRouter proxy address. To achieve this, we
// 1. deploy the proxy first with a dummy implementation
// 2. deploy the real InterchainAccountRouter and OwnableMulticall implementation with proxy address
// 3. upgrade the proxy to the real implementation and initialize
async deployContracts(
chain: ChainName,
config: InterchainAccountConfig,
): Promise<InterchainAccountContracts> {
const proxyAdmin = (await this.deployContract(
chain,
'proxyAdmin',
[],
)) as ProxyAdmin;
// adapted from HyperlaneDeployer.deployProxiedContract
const cached = this.deployedContracts[chain]
?.interchainAccountRouter as ProxiedContract<InterchainAccountRouter>;
if (cached && cached.addresses.proxy && cached.addresses.implementation) {
this.logger('Recovered full InterchainAccountRouter');
return {
proxyAdmin,
interchainAccountRouter: cached,
};
}
const deployer = await this.multiProvider.getSignerAddress(chain);
// 1. deploy the proxy first with a dummy implementation (proxy admin contract)
const proxy = await this.deployContractFromFactory(
chain,
new TransparentUpgradeableProxy__factory(),
'TransparentUpgradeableProxy',
[proxyAdmin.address, deployer, '0x'],
{ create2Salt: this.create2salt },
);
// 2. deploy the real InterchainAccountRouter and OwnableMulticall implementation with proxy address
const domainId = this.multiProvider.getDomainId(chain);
const implementation = await this.deployContract(
chain,
'interchainAccountRouter',
[domainId, proxy.address],
);
// 3. upgrade the proxy to the real implementation and initialize
// adapted from HyperlaneDeployer.deployProxy.useCreate2
const initArgs = await this.initializeArgs(chain, config);
const initData =
this.factories.interchainAccountRouter.interface.encodeFunctionData(
'initialize',
initArgs,
);
await super.upgradeAndInitialize(
chain,
proxy,
implementation.address,
initData,
);
await super.changeAdmin(chain, proxy, proxyAdmin.address);
const proxiedRouter = new ProxiedContract(
implementation.attach(proxy.address),
{
kind: ProxyKind.Transparent,
implementation: implementation.address,
proxy: proxy.address,
},
);
return {
proxyAdmin,
interchainAccountRouter: proxiedRouter, // for serialization
};
}
}

@ -7,19 +7,18 @@ import {
TestRecipient__factory, TestRecipient__factory,
} from '@hyperlane-xyz/core'; } from '@hyperlane-xyz/core';
import { Chains } from '../consts/chains'; import { Chains } from '../../consts/chains';
import { TestCoreApp } from '../core/TestCoreApp'; import { TestCoreApp } from '../../core/TestCoreApp';
import { TestCoreDeployer } from '../core/TestCoreDeployer'; import { TestCoreDeployer } from '../../core/TestCoreDeployer';
import { MultiProvider } from '../providers/MultiProvider'; import { MultiProvider } from '../../providers/MultiProvider';
import { RouterConfig } from '../router/types'; import { RouterConfig } from '../../router/types';
import { deployTestIgpsAndGetRouterConfig } from '../test/testUtils'; import { deployTestIgpsAndGetRouterConfig } from '../../test/testUtils';
import { ChainMap } from '../types'; import { ChainMap } from '../../types';
import { objMap, promiseObjAll } from '../utils/objects';
import { import { InterchainAccount } from './InterchainAccount';
InterchainAccountContracts, import { InterchainAccountChecker } from './InterchainAccountChecker';
InterchainAccountDeployer, import { InterchainAccountDeployer } from './InterchainAccountDeployer';
} from './deploy'; import { InterchainAccountContracts } from './contracts';
describe('InterchainAccounts', async () => { describe('InterchainAccounts', async () => {
const localChain = Chains.test1; const localChain = Chains.test1;
@ -54,21 +53,15 @@ describe('InterchainAccounts', async () => {
beforeEach(async () => { beforeEach(async () => {
const deployer = new InterchainAccountDeployer(multiProvider, config); const deployer = new InterchainAccountDeployer(multiProvider, config);
contracts = await deployer.deploy(); contracts = await deployer.deploy();
local = contracts[localChain].interchainAccountRouter.contract;
local = contracts[localChain].router; remote = contracts[remoteChain].interchainAccountRouter.contract;
remote = contracts[remoteChain].router;
}); });
it('deploys and sets configured ISMs', async () => { it('checks', async () => {
const deployedIsms = await promiseObjAll( const app = new InterchainAccount(contracts, multiProvider);
objMap(contracts, (_, c) => c.router.interchainSecurityModule()), const checker = new InterchainAccountChecker(multiProvider, app, config);
); await checker.check();
expect(deployedIsms).to.eql( expect(checker.violations.length).to.eql(0);
objMap(
config,
(_, c) => c.interchainSecurityModule ?? ethers.constants.AddressZero,
),
);
}); });
it('forwards calls from interchain account', async () => { it('forwards calls from interchain account', async () => {

@ -0,0 +1,23 @@
import {
InterchainAccountRouter,
InterchainAccountRouter__factory,
ProxyAdmin,
ProxyAdmin__factory,
} from '@hyperlane-xyz/core';
import { ProxiedContract } from '../../proxy';
export type InterchainAccountFactories = {
interchainAccountRouter: InterchainAccountRouter__factory;
proxyAdmin: ProxyAdmin__factory;
};
export const interchainAccountFactories = {
interchainAccountRouter: new InterchainAccountRouter__factory(),
proxyAdmin: new ProxyAdmin__factory(),
};
export type InterchainAccountContracts = {
interchainAccountRouter: ProxiedContract<InterchainAccountRouter>;
proxyAdmin: ProxyAdmin;
};

@ -1,207 +0,0 @@
import { ethers } from 'ethers';
import {
InterchainAccountRouter,
InterchainAccountRouter__factory,
InterchainQueryRouter,
InterchainQueryRouter__factory,
ProxyAdmin__factory,
TransparentUpgradeableProxy__factory,
} from '@hyperlane-xyz/core';
import { MultiProvider } from '../providers/MultiProvider';
import { ProxiedContract, ProxyKind } from '../proxy';
import { HyperlaneRouterDeployer } from '../router/HyperlaneRouterDeployer';
import {
ProxiedRouterContracts,
ProxiedRouterFactories,
RouterConfig,
} from '../router/types';
import { ChainMap, ChainName } from '../types';
export type InterchainAccountFactories =
ProxiedRouterFactories<InterchainAccountRouter>;
export const interchainAccountFactories: InterchainAccountFactories = {
router: new InterchainAccountRouter__factory(),
proxyAdmin: new ProxyAdmin__factory(),
};
export type InterchainAccountContracts =
ProxiedRouterContracts<InterchainAccountRouter>;
export type InterchainQueryFactories =
ProxiedRouterFactories<InterchainQueryRouter>;
export const interchainQueryFactories: InterchainQueryFactories = {
router: new InterchainQueryRouter__factory(),
proxyAdmin: new ProxyAdmin__factory(),
};
export type InterchainQueryContracts =
ProxiedRouterContracts<InterchainQueryRouter>;
export abstract class MiddlewareRouterDeployer<
MiddlewareRouterConfig extends RouterConfig,
MiddlewareRouterContracts extends ProxiedRouterContracts,
MiddlewareFactories extends ProxiedRouterFactories,
> extends HyperlaneRouterDeployer<
MiddlewareRouterConfig,
MiddlewareRouterContracts,
MiddlewareFactories
> {
constructor(
multiProvider: MultiProvider,
configMap: ChainMap<MiddlewareRouterConfig>,
factories: MiddlewareFactories,
protected create2salt = 'middlewarerouter',
) {
super(multiProvider, configMap, factories);
}
async initializeArgs(
chain: ChainName,
config: MiddlewareRouterConfig,
): Promise<[string, string, string, string]> {
// configure owner as signer for additional initialization steps
// ownership is transferred to config.owner in HyperlaneRouterDeployer.deploy
const owner = await this.multiProvider.getSignerAddress(chain);
return [
config.mailbox,
config.interchainGasPaymaster,
config.interchainSecurityModule ?? ethers.constants.AddressZero,
owner,
];
}
async deployContracts(
chain: ChainName,
config: MiddlewareRouterConfig,
): Promise<MiddlewareRouterContracts> {
const proxyAdmin = await this.deployContract(
chain,
'proxyAdmin',
[] as any, // generic type inference fails here
);
const initArgs = await this.initializeArgs(chain, config);
const proxiedRouter = await this.deployProxiedContract(
chain,
'router',
[] as any, // generic type inference fails here
initArgs as any, // generic type inference fails here
proxyAdmin.address,
{
create2Salt: this.create2salt,
},
);
return {
proxyAdmin,
proxiedRouter,
router: proxiedRouter.contract, // for backwards compatibility
} as any; // generic type inference fails here
}
}
type InterchainAccountConfig = RouterConfig;
export class InterchainAccountDeployer extends MiddlewareRouterDeployer<
InterchainAccountConfig,
InterchainAccountContracts,
InterchainAccountFactories
> {
constructor(
multiProvider: MultiProvider,
configMap: ChainMap<InterchainAccountConfig>,
create2Salt = 'accountsrouter',
) {
super(multiProvider, configMap, interchainAccountFactories, create2Salt);
}
// The OwnableMulticall implementation has an immutable owner address that
// must be set to the InterchainAccountRouter proxy address. To achieve this, we
// 1. deploy the proxy first with a dummy implementation
// 2. deploy the real InterchainAccountRouter and OwnableMulticall implementation with proxy address
// 3. upgrade the proxy to the real implementation and initialize
async deployContracts(
chain: ChainName,
config: InterchainAccountConfig,
): Promise<InterchainAccountContracts> {
const proxyAdmin = await this.deployContract(chain, 'proxyAdmin', []);
// manually recover from cache because cannot use HyperlaneDeployer.deployProxiedContract
const cached = this.deployedContracts[chain]?.proxiedRouter;
if (cached && cached.addresses.proxy && cached.addresses.implementation) {
this.logger('Recovered full InterchainAccountRouter');
return {
proxyAdmin,
proxiedRouter: cached,
router: cached.contract,
};
}
const deployer = await this.multiProvider.getSignerAddress(chain);
// 1. deploy the proxy first with a dummy implementation (proxy admin contract)
const proxy = await this.deployContractFromFactory(
chain,
new TransparentUpgradeableProxy__factory(),
'TransparentUpgradeableProxy',
[proxyAdmin.address, deployer, '0x'],
{ create2Salt: this.create2salt },
);
// 2. deploy the real InterchainAccountRouter and OwnableMulticall implementation with proxy address
const domainId = this.multiProvider.getDomainId(chain);
const implementation = await this.deployContract(chain, 'router', [
domainId,
proxy.address,
]);
// 3. upgrade the proxy to the real implementation and initialize
// adapted from HyperlaneDeployer.deployProxy.useCreate2
const initArgs = await this.initializeArgs(chain, config);
const initData = this.factories.router.interface.encodeFunctionData(
'initialize',
initArgs,
);
await super.upgradeAndInitialize(
chain,
proxy,
implementation.address,
initData,
);
await super.changeAdmin(chain, proxy, proxyAdmin.address);
const proxiedRouter = new ProxiedContract(
implementation.attach(proxy.address),
{
kind: ProxyKind.Transparent,
implementation: implementation.address,
proxy: proxy.address,
},
);
return {
proxyAdmin,
proxiedRouter,
router: proxiedRouter.contract,
};
}
}
type InterchainQueryConfig = RouterConfig;
export class InterchainQueryDeployer extends MiddlewareRouterDeployer<
InterchainQueryConfig,
InterchainQueryContracts,
InterchainQueryFactories
> {
constructor(
multiProvider: MultiProvider,
configMap: ChainMap<InterchainQueryConfig>,
create2salt = 'queryrouter2',
) {
super(multiProvider, configMap, interchainQueryFactories, create2salt);
}
}

@ -2,6 +2,7 @@ import {
CircleBridgeAdapter, CircleBridgeAdapter,
CircleBridgeAdapter__factory, CircleBridgeAdapter__factory,
LiquidityLayerRouter, LiquidityLayerRouter,
LiquidityLayerRouter__factory,
PortalAdapter, PortalAdapter,
PortalAdapter__factory, PortalAdapter__factory,
} from '@hyperlane-xyz/core'; } from '@hyperlane-xyz/core';
@ -10,8 +11,8 @@ import { utils } from '@hyperlane-xyz/utils';
import { MultiProvider } from '../../providers/MultiProvider'; import { MultiProvider } from '../../providers/MultiProvider';
import { RouterConfig } from '../../router/types'; import { RouterConfig } from '../../router/types';
import { ChainMap, ChainName } from '../../types'; import { ChainMap, ChainName } from '../../types';
import { objFilter, objMap } from '../../utils/objects'; import { objMap } from '../../utils/objects';
import { MiddlewareRouterDeployer } from '../deploy'; import { MiddlewareRouterDeployer } from '../MiddlewareRouterDeployer';
import { import {
LiquidityLayerContracts, LiquidityLayerContracts,
@ -54,8 +55,11 @@ export type LiquidityLayerConfig = RouterConfig & BridgeAdapterConfig;
export class LiquidityLayerDeployer extends MiddlewareRouterDeployer< export class LiquidityLayerDeployer extends MiddlewareRouterDeployer<
LiquidityLayerConfig, LiquidityLayerConfig,
LiquidityLayerContracts, LiquidityLayerContracts,
LiquidityLayerFactories LiquidityLayerFactories,
LiquidityLayerRouter__factory
> { > {
readonly routerContractName = 'liquidityLayerRouter';
constructor( constructor(
multiProvider: MultiProvider, multiProvider: MultiProvider,
configMap: ChainMap<LiquidityLayerConfig>, configMap: ChainMap<LiquidityLayerConfig>,
@ -71,23 +75,23 @@ export class LiquidityLayerDeployer extends MiddlewareRouterDeployer<
await super.enrollRemoteRouters(contractsMap); await super.enrollRemoteRouters(contractsMap);
this.logger(`Enroll CircleBridgeAdapters with each other`); this.logger(`Enroll CircleBridgeAdapters with each other`);
// Hack to allow use of super.enrollRemoteRouters
await super.enrollRemoteRouters( await super.enrollRemoteRouters(
objFilter( objMap(contractsMap, (_, contracts) => ({
objMap(contractsMap, (_chain, contracts) => ({ liquidityLayerRouter: {
router: contracts.circleBridgeAdapter, contract: contracts.circleBridgeAdapter,
})), },
(chain, _): _ is { router: CircleBridgeAdapter } => !!_.router, })) as unknown as ChainMap<LiquidityLayerContracts>,
),
); );
this.logger(`Enroll PortalAdapters with each other`); this.logger(`Enroll PortalAdapters with each other`);
// Hack to allow use of super.enrollRemoteRouters
await super.enrollRemoteRouters( await super.enrollRemoteRouters(
objFilter( objMap(contractsMap, (_, contracts) => ({
objMap(contractsMap, (_chain, contracts) => ({ liquidityLayerRouter: {
router: contracts.portalAdapter, contract: contracts.portalAdapter,
})), },
(chain, _): _ is { router: PortalAdapter } => !!_.router, })) as unknown as ChainMap<LiquidityLayerContracts>,
),
); );
} }
@ -97,7 +101,10 @@ export class LiquidityLayerDeployer extends MiddlewareRouterDeployer<
chain: ChainName, chain: ChainName,
config: LiquidityLayerConfig, config: LiquidityLayerConfig,
): Promise<LiquidityLayerContracts> { ): Promise<LiquidityLayerContracts> {
const routerContracts = await super.deployContracts(chain, config); const routerContracts = (await super.deployContracts(
chain,
config,
)) as LiquidityLayerContracts;
const bridgeAdapters: Partial<LiquidityLayerContracts> = {}; const bridgeAdapters: Partial<LiquidityLayerContracts> = {};
@ -106,7 +113,7 @@ export class LiquidityLayerDeployer extends MiddlewareRouterDeployer<
chain, chain,
config.circle, config.circle,
config.owner, config.owner,
routerContracts.router, routerContracts.liquidityLayerRouter.contract,
); );
} }
if (config.portal) { if (config.portal) {
@ -114,14 +121,14 @@ export class LiquidityLayerDeployer extends MiddlewareRouterDeployer<
chain, chain,
config.portal, config.portal,
config.owner, config.owner,
routerContracts.router, routerContracts.liquidityLayerRouter.contract,
); );
} }
return { return {
...routerContracts, ...routerContracts,
...bridgeAdapters, ...bridgeAdapters,
} as any; } as LiquidityLayerContracts;
} }
async deployPortalAdapter( async deployPortalAdapter(

@ -8,28 +8,24 @@ import {
ProxyAdmin__factory, ProxyAdmin__factory,
} from '@hyperlane-xyz/core'; } from '@hyperlane-xyz/core';
import { import { ProxiedContract } from '../../proxy';
ProxiedRouterContracts, import { ProxiedContracts, ProxiedFactories } from '../../router/types';
ProxiedRouterFactories,
} from '../../router/types';
export type LiquidityLayerFactories = export type LiquidityLayerFactories = ProxiedFactories & {
ProxiedRouterFactories<LiquidityLayerRouter> & { liquidityLayerRouter: LiquidityLayerRouter__factory;
circleBridgeAdapter: CircleBridgeAdapter__factory; circleBridgeAdapter: CircleBridgeAdapter__factory;
portalAdapter: PortalAdapter__factory; portalAdapter: PortalAdapter__factory;
}; };
export const liquidityLayerFactories: LiquidityLayerFactories = { export const liquidityLayerFactories: LiquidityLayerFactories = {
router: new LiquidityLayerRouter__factory(),
circleBridgeAdapter: new CircleBridgeAdapter__factory(), circleBridgeAdapter: new CircleBridgeAdapter__factory(),
portalAdapter: new PortalAdapter__factory(), portalAdapter: new PortalAdapter__factory(),
// TODO: where to put these?
proxyAdmin: new ProxyAdmin__factory(), proxyAdmin: new ProxyAdmin__factory(),
liquidityLayerRouter: new LiquidityLayerRouter__factory(), liquidityLayerRouter: new LiquidityLayerRouter__factory(),
}; };
export type LiquidityLayerContracts = export type LiquidityLayerContracts = ProxiedContracts & {
ProxiedRouterContracts<LiquidityLayerRouter> & { liquidityLayerRouter: ProxiedContract<LiquidityLayerRouter>;
circleBridgeAdapter?: CircleBridgeAdapter; circleBridgeAdapter?: CircleBridgeAdapter;
portalAdapter?: PortalAdapter; portalAdapter?: PortalAdapter;
}; };

@ -121,7 +121,8 @@ describe('LiquidityLayerRouter', async () => {
liquidityLayerApp = new LiquidityLayerApp(contracts, multiProvider, config); liquidityLayerApp = new LiquidityLayerApp(contracts, multiProvider, config);
local = liquidityLayerApp.getContracts(localChain).router; local =
liquidityLayerApp.getContracts(localChain).liquidityLayerRouter.contract;
}); });
it('can transfer tokens via Circle', async () => { it('can transfer tokens via Circle', async () => {

@ -0,0 +1,58 @@
import { InterchainQueryRouter } from '@hyperlane-xyz/core';
import {
HyperlaneEnvironment,
hyperlaneEnvironments,
} from '../../consts/environments';
import { HyperlaneAddresses } from '../../contracts';
import { MultiProvider } from '../../providers/MultiProvider';
import { RouterApp } from '../../router/RouterApps';
import { ChainMap, ChainName } from '../../types';
import {
InterchainQueryContracts,
interchainQueryFactories,
} from './contracts';
export type InterchainQueryContractsMap = ChainMap<InterchainQueryContracts>;
export class InterchainQuery extends RouterApp<InterchainQueryContracts> {
constructor(
contractsMap: InterchainQueryContractsMap,
multiProvider: MultiProvider,
) {
super(contractsMap, multiProvider);
}
router(contracts: InterchainQueryContracts): InterchainQueryRouter {
return contracts.interchainQueryRouter.contract;
}
static fromAddresses(
addresses: ChainMap<HyperlaneAddresses>,
multiProvider: MultiProvider,
): InterchainQuery {
const { contracts, intersectionProvider } =
this.buildContracts<InterchainQueryContracts>(
addresses,
interchainQueryFactories,
multiProvider,
);
return new InterchainQuery(contracts, intersectionProvider);
}
static fromEnvironment<Env extends HyperlaneEnvironment>(
env: Env,
multiProvider: MultiProvider,
): InterchainQuery {
const envAddresses = hyperlaneEnvironments[env];
if (!envAddresses) {
throw new Error(`No addresses found for ${env}`);
}
return InterchainQuery.fromAddresses(envAddresses, multiProvider);
}
getContracts(chain: ChainName): InterchainQueryContracts {
return super.getContracts(chain);
}
}

@ -0,0 +1,11 @@
import { MiddlewareRouterChecker } from '../MiddlewareRouterChecker';
import { InterchainQuery } from './InterchainQuery';
import { InterchainQueryConfig } from './InterchainQueryDeployer';
import { InterchainQueryContracts } from './contracts';
export class InterchainQueryChecker extends MiddlewareRouterChecker<
InterchainQuery,
InterchainQueryConfig,
InterchainQueryContracts
> {}

@ -0,0 +1,31 @@
import { InterchainQueryRouter__factory } from '@hyperlane-xyz/core';
import { MultiProvider } from '../../providers/MultiProvider';
import { RouterConfig } from '../../router/types';
import { ChainMap } from '../../types';
import { MiddlewareRouterDeployer } from '../MiddlewareRouterDeployer';
import {
InterchainQueryContracts,
InterchainQueryFactories,
interchainQueryFactories,
} from './contracts';
export type InterchainQueryConfig = RouterConfig;
export class InterchainQueryDeployer extends MiddlewareRouterDeployer<
InterchainQueryConfig,
InterchainQueryContracts,
InterchainQueryFactories,
InterchainQueryRouter__factory
> {
readonly routerContractName = 'interchainQueryRouter';
constructor(
multiProvider: MultiProvider,
configMap: ChainMap<InterchainQueryConfig>,
create2salt = 'queryrouter2',
) {
super(multiProvider, configMap, interchainQueryFactories, create2salt);
}
}

@ -0,0 +1,23 @@
import {
InterchainQueryRouter,
InterchainQueryRouter__factory,
ProxyAdmin,
ProxyAdmin__factory,
} from '@hyperlane-xyz/core';
import { ProxiedContract } from '../../proxy';
export type InterchainQueryFactories = {
interchainQueryRouter: InterchainQueryRouter__factory;
proxyAdmin: ProxyAdmin__factory;
};
export const interchainQueryFactories = {
interchainQueryRouter: new InterchainQueryRouter__factory(),
proxyAdmin: new ProxyAdmin__factory(),
};
export type InterchainQueryContracts = {
interchainQueryRouter: ProxiedContract<InterchainQueryRouter>;
proxyAdmin: ProxyAdmin;
};

@ -9,16 +9,19 @@ import {
} from '@hyperlane-xyz/core'; } from '@hyperlane-xyz/core';
import { utils } from '@hyperlane-xyz/utils'; import { utils } from '@hyperlane-xyz/utils';
import { chainMetadata } from '../consts/chainMetadata'; import { chainMetadata } from '../../consts/chainMetadata';
import { Chains } from '../consts/chains'; import { Chains } from '../../consts/chains';
import { TestCoreApp } from '../core/TestCoreApp'; import { TestCoreApp } from '../../core/TestCoreApp';
import { TestCoreDeployer } from '../core/TestCoreDeployer'; import { TestCoreDeployer } from '../../core/TestCoreDeployer';
import { MultiProvider } from '../providers/MultiProvider'; import { MultiProvider } from '../../providers/MultiProvider';
import { RouterConfig } from '../router/types'; import { RouterConfig } from '../../router/types';
import { deployTestIgpsAndGetRouterConfig } from '../test/testUtils'; import { deployTestIgpsAndGetRouterConfig } from '../../test/testUtils';
import { ChainMap } from '../types'; import { ChainMap } from '../../types';
import { InterchainQueryDeployer } from './deploy'; import { InterchainQuery } from './InterchainQuery';
import { InterchainQueryChecker } from './InterchainQueryChecker';
import { InterchainQueryDeployer } from './InterchainQueryDeployer';
import { InterchainQueryContracts } from './contracts';
describe('InterchainQueryRouter', async () => { describe('InterchainQueryRouter', async () => {
const localChain = Chains.test1; const localChain = Chains.test1;
@ -26,6 +29,7 @@ describe('InterchainQueryRouter', async () => {
const localDomain = chainMetadata[localChain].chainId; const localDomain = chainMetadata[localChain].chainId;
const remoteDomain = chainMetadata[remoteChain].chainId; const remoteDomain = chainMetadata[remoteChain].chainId;
let contracts: ChainMap<InterchainQueryContracts>;
let signer: SignerWithAddress; let signer: SignerWithAddress;
let local: InterchainQueryRouter; let local: InterchainQueryRouter;
let remote: InterchainQueryRouter; let remote: InterchainQueryRouter;
@ -52,14 +56,21 @@ describe('InterchainQueryRouter', async () => {
beforeEach(async () => { beforeEach(async () => {
const InterchainQuery = new InterchainQueryDeployer(multiProvider, config); const InterchainQuery = new InterchainQueryDeployer(multiProvider, config);
const contracts = await InterchainQuery.deploy(); contracts = await InterchainQuery.deploy();
local = contracts[localChain].router; local = contracts[localChain].interchainQueryRouter.contract;
remote = contracts[remoteChain].router; remote = contracts[remoteChain].interchainQueryRouter.contract;
testQuery = await new TestQuery__factory(signer).deploy(local.address); testQuery = await new TestQuery__factory(signer).deploy(local.address);
}); });
it('checks', async () => {
const app = new InterchainQuery(contracts, multiProvider);
const checker = new InterchainQueryChecker(multiProvider, app, config);
await checker.check();
expect(checker.violations.length).to.eql(0);
});
it('completes query round trip and invokes callback', async () => { it('completes query round trip and invokes callback', async () => {
const secret = 123; const secret = 123;
const sender = testQuery.address; const sender = testQuery.address;

@ -59,3 +59,18 @@ export class ProxiedContract<
); );
} }
} }
export function isProxiedContract(
contract: unknown,
): contract is ProxiedContract<any, any> {
// The presence of `implementation` is intentionally not checked
// to allow deploying new implementations by deleting the implementation
// from the artifacts
return (
contract !== null &&
typeof contract === 'object' &&
'addresses' in contract &&
'contract' in contract &&
isProxyAddresses((contract as any).addresses)
);
}

@ -1,23 +1,22 @@
import { debug } from 'debug'; import { debug } from 'debug';
import { GasRouter } from '@hyperlane-xyz/core'; import { HyperlaneFactories } from '../contracts';
import { DeployerOptions } from '../deploy/HyperlaneDeployer'; import { DeployerOptions } from '../deploy/HyperlaneDeployer';
import { MultiProvider } from '../providers/MultiProvider'; import { MultiProvider } from '../providers/MultiProvider';
import { ChainMap } from '../types'; import { ChainMap } from '../types';
import { HyperlaneRouterDeployer } from './HyperlaneRouterDeployer'; import { HyperlaneRouterDeployer } from './HyperlaneRouterDeployer';
import { GasRouterConfig, RouterContracts, RouterFactories } from './types'; import { GasRouterContracts } from './RouterApps';
import { GasRouterConfig } from './types';
export abstract class GasRouterDeployer< export abstract class GasRouterDeployer<
Config extends GasRouterConfig, Config extends GasRouterConfig,
Contracts extends RouterContracts<GasRouter>, Contracts extends GasRouterContracts,
Factories extends RouterFactories<GasRouter>, > extends HyperlaneRouterDeployer<Config, Contracts, HyperlaneFactories> {
> extends HyperlaneRouterDeployer<Config, Contracts, Factories> {
constructor( constructor(
multiProvider: MultiProvider, multiProvider: MultiProvider,
configMap: ChainMap<Config>, configMap: ChainMap<Config>,
factories: Factories, factories: HyperlaneFactories,
options?: DeployerOptions, options?: DeployerOptions,
) { ) {
super(multiProvider, configMap, factories, { super(multiProvider, configMap, factories, {

@ -1,24 +1,22 @@
import { ethers } from 'ethers'; import { ethers } from 'ethers';
import { Ownable } from '@hyperlane-xyz/core';
import { utils } from '@hyperlane-xyz/utils'; import { utils } from '@hyperlane-xyz/utils';
import { HyperlaneApp } from '../HyperlaneApp'; import { HyperlaneContracts } from '../contracts';
import { HyperlaneAppChecker } from '../deploy/HyperlaneAppChecker'; import { HyperlaneAppChecker } from '../deploy/HyperlaneAppChecker';
import { RouterContracts } from '../router/types';
import { ChainName } from '../types'; import { ChainName } from '../types';
import { RouterApp } from './RouterApps';
import { RouterConfig } from './types'; import { RouterConfig } from './types';
export class HyperlaneRouterChecker< export class HyperlaneRouterChecker<
App extends HyperlaneApp<Contracts>, App extends RouterApp<Contracts>,
Config extends RouterConfig, Config extends RouterConfig,
Contracts extends RouterContracts, Contracts extends HyperlaneContracts,
> extends HyperlaneAppChecker<App, Config> { > extends HyperlaneAppChecker<App, Config> {
checkOwnership(chain: ChainName): Promise<void> { checkOwnership(chain: ChainName): Promise<void> {
const owner = this.configMap[chain].owner; const owner = this.configMap[chain].owner;
const ownables = this.ownables(chain); return super.checkOwnership(chain, owner);
return super.checkOwnership(chain, owner, ownables);
} }
async checkChain(chain: ChainName): Promise<void> { async checkChain(chain: ChainName): Promise<void> {
@ -28,7 +26,7 @@ export class HyperlaneRouterChecker<
} }
async checkHyperlaneConnectionClient(chain: ChainName): Promise<void> { async checkHyperlaneConnectionClient(chain: ChainName): Promise<void> {
const router = this.app.getContracts(chain).router; const router = this.app.router(this.app.getContracts(chain));
const mailbox = await router.mailbox(); const mailbox = await router.mailbox();
const igp = await router.interchainGasPaymaster(); const igp = await router.interchainGasPaymaster();
const ism = await router.interchainSecurityModule(); const ism = await router.interchainSecurityModule();
@ -48,19 +46,17 @@ export class HyperlaneRouterChecker<
} }
async checkEnrolledRouters(chain: ChainName): Promise<void> { async checkEnrolledRouters(chain: ChainName): Promise<void> {
const router = this.app.getContracts(chain).router; const router = this.app.router(this.app.getContracts(chain));
await Promise.all( await Promise.all(
this.app.remoteChains(chain).map(async (remoteChain) => { this.app.remoteChains(chain).map(async (remoteChain) => {
const remoteRouter = this.app.getContracts(remoteChain).router; const remoteRouter = this.app.router(
this.app.getContracts(remoteChain),
);
const remoteDomainId = this.multiProvider.getDomainId(remoteChain); const remoteDomainId = this.multiProvider.getDomainId(remoteChain);
const address = await router.routers(remoteDomainId); const address = await router.routers(remoteDomainId);
utils.assert(address === utils.addressToBytes32(remoteRouter.address)); utils.assert(address === utils.addressToBytes32(remoteRouter.address));
}), }),
); );
} }
ownables(chain: ChainName): Ownable[] {
return [this.app.getContracts(chain).router];
}
} }

@ -1,24 +1,22 @@
import { debug } from 'debug'; import { debug } from 'debug';
import { Router } from '@hyperlane-xyz/core';
import { utils } from '@hyperlane-xyz/utils'; import { utils } from '@hyperlane-xyz/utils';
import { HyperlaneContracts, HyperlaneFactories } from '../contracts';
import { import {
DeployerOptions, DeployerOptions,
HyperlaneDeployer, HyperlaneDeployer,
} from '../deploy/HyperlaneDeployer'; } from '../deploy/HyperlaneDeployer';
import { MultiProvider } from '../providers/MultiProvider'; import { MultiProvider } from '../providers/MultiProvider';
import { import { RouterConfig } from '../router/types';
RouterConfig,
RouterContracts,
RouterFactories,
} from '../router/types';
import { ChainMap } from '../types'; import { ChainMap } from '../types';
import { objMap, promiseObjAll } from '../utils/objects'; import { objMap, promiseObjAll } from '../utils/objects';
export abstract class HyperlaneRouterDeployer< export abstract class HyperlaneRouterDeployer<
Config extends RouterConfig, Config extends RouterConfig,
Contracts extends RouterContracts, Contracts extends HyperlaneContracts,
Factories extends RouterFactories, Factories extends HyperlaneFactories,
> extends HyperlaneDeployer<Config, Contracts, Factories> { > extends HyperlaneDeployer<Config, Contracts, Factories> {
constructor( constructor(
multiProvider: MultiProvider, multiProvider: MultiProvider,
@ -32,6 +30,8 @@ export abstract class HyperlaneRouterDeployer<
}); });
} }
abstract router(contracts: Contracts): Router;
async initConnectionClients( async initConnectionClients(
contractsMap: ChainMap<Contracts>, contractsMap: ChainMap<Contracts>,
): Promise<void> { ): Promise<void> {
@ -39,24 +39,20 @@ export abstract class HyperlaneRouterDeployer<
objMap(contractsMap, async (local, contracts) => objMap(contractsMap, async (local, contracts) =>
super.initConnectionClient( super.initConnectionClient(
local, local,
contracts.router, this.router(contracts),
this.configMap[local], this.configMap[local],
), ),
), ),
); );
} }
async enrollRemoteRouters( async enrollRemoteRouters(contractsMap: ChainMap<Contracts>): Promise<void> {
contractsMap: ChainMap<RouterContracts>,
): Promise<void> {
this.logger( this.logger(
`Enrolling deployed routers with each other (if not already)...`, `Enrolling deployed routers with each other (if not already)...`,
); );
// Make all routers aware of each other. // Make all routers aware of each other.
const deployedChains = Object.keys(contractsMap); const deployedChains = Object.keys(contractsMap);
for (const [chain, contracts] of Object.entries<RouterContracts>( for (const [chain, contracts] of Object.entries<Contracts>(contractsMap)) {
contractsMap,
)) {
// only enroll chains which are deployed // only enroll chains which are deployed
const deployedRemoteChains = this.multiProvider const deployedRemoteChains = this.multiProvider
.getRemoteChains(chain) .getRemoteChains(chain)
@ -65,9 +61,9 @@ export abstract class HyperlaneRouterDeployer<
const enrollEntries = await Promise.all( const enrollEntries = await Promise.all(
deployedRemoteChains.map(async (remote) => { deployedRemoteChains.map(async (remote) => {
const remoteDomain = this.multiProvider.getDomainId(remote); const remoteDomain = this.multiProvider.getDomainId(remote);
const current = await contracts.router.routers(remoteDomain); const current = await this.router(contracts).routers(remoteDomain);
const expected = utils.addressToBytes32( const expected = utils.addressToBytes32(
contractsMap[remote].router.address, this.router(contractsMap[remote]).address,
); );
return current !== expected ? [remoteDomain, expected] : undefined; return current !== expected ? [remoteDomain, expected] : undefined;
}), }),
@ -83,14 +79,14 @@ export abstract class HyperlaneRouterDeployer<
return; return;
} }
await super.runIfOwner(chain, contracts.router, async () => { await super.runIfOwner(chain, this.router(contracts), async () => {
const chains = domains.map((id) => this.multiProvider.getChainName(id)); const chains = domains.map((id) => this.multiProvider.getChainName(id));
this.logger( this.logger(
`Enrolling remote routers (${chains.join(', ')}) on ${chain}`, `Enrolling remote routers (${chains.join(', ')}) on ${chain}`,
); );
await this.multiProvider.handleTx( await this.multiProvider.handleTx(
chain, chain,
contracts.router.enrollRemoteRouters( this.router(contracts).enrollRemoteRouters(
domains, domains,
addresses, addresses,
this.multiProvider.getTransactionOverrides(chain), this.multiProvider.getTransactionOverrides(chain),
@ -105,13 +101,13 @@ export abstract class HyperlaneRouterDeployer<
await promiseObjAll( await promiseObjAll(
objMap(contractsMap, async (chain, contracts) => { objMap(contractsMap, async (chain, contracts) => {
const owner = this.configMap[chain].owner; const owner = this.configMap[chain].owner;
const currentOwner = await contracts.router.owner(); const currentOwner = await this.router(contracts).owner();
if (owner != currentOwner) { if (owner != currentOwner) {
this.logger(`Transfer ownership of ${chain}'s router to ${owner}`); this.logger(`Transfer ownership of ${chain}'s router to ${owner}`);
await super.runIfOwner(chain, contracts.router, async () => { await super.runIfOwner(chain, this.router(contracts), async () => {
await this.multiProvider.handleTx( await this.multiProvider.handleTx(
chain, chain,
contracts.router.transferOwnership( this.router(contracts).transferOwnership(
owner, owner,
this.multiProvider.getTransactionOverrides(chain), this.multiProvider.getTransactionOverrides(chain),
), ),

@ -1,35 +1,48 @@
import type { BigNumber } from 'ethers'; import type { BigNumber } from 'ethers';
import { GasRouter } from '@hyperlane-xyz/core'; import { GasRouter, GasRouter__factory, Router } from '@hyperlane-xyz/core';
import type { types } from '@hyperlane-xyz/utils'; import type { types } from '@hyperlane-xyz/utils';
import { HyperlaneApp } from '../HyperlaneApp'; import { HyperlaneApp } from '../HyperlaneApp';
import { HyperlaneContracts } from '../contracts';
import { ChainMap, ChainName } from '../types'; import { ChainMap, ChainName } from '../types';
import { objMap, promiseObjAll } from '../utils/objects'; import { objMap, promiseObjAll } from '../utils/objects';
import { RouterContracts } from './types';
export { Router } from '@hyperlane-xyz/core'; export { Router } from '@hyperlane-xyz/core';
export class RouterApp< export abstract class RouterApp<
Contracts extends RouterContracts, Contracts extends HyperlaneContracts,
> extends HyperlaneApp<Contracts> { > extends HyperlaneApp<Contracts> {
abstract router(contracts: Contracts): Router;
getSecurityModules = (): Promise<ChainMap<types.Address>> => getSecurityModules = (): Promise<ChainMap<types.Address>> =>
promiseObjAll( promiseObjAll(
objMap(this.contractsMap, (_, contracts) => objMap(this.contractsMap, (_, contracts) =>
contracts.router.interchainSecurityModule(), this.router(contracts).interchainSecurityModule(),
), ),
); );
getOwners = (): Promise<ChainMap<types.Address>> => getOwners = (): Promise<ChainMap<types.Address>> =>
promiseObjAll( promiseObjAll(
objMap(this.contractsMap, (_, contracts) => contracts.router.owner()), objMap(this.contractsMap, (_, contracts) =>
this.router(contracts).owner(),
),
); );
} }
export class GasRouterApp< export type GasRouterContracts = {
Contracts extends RouterContracts<GasRouter>, router: GasRouter;
> extends RouterApp<Contracts> { };
export type GasRouterFactories = {
router: GasRouter__factory;
};
export class GasRouterApp extends RouterApp<GasRouterContracts> {
router(contracts: GasRouterContracts): GasRouter {
return contracts.router;
}
async quoteGasPayment( async quoteGasPayment(
origin: ChainName, origin: ChainName,
destination: ChainName, destination: ChainName,

@ -1,39 +0,0 @@
import { BigNumber } from 'ethers';
import { GasRouter } from '@hyperlane-xyz/core';
import { types } from '@hyperlane-xyz/utils';
import { HyperlaneApp } from '../HyperlaneApp';
import { ChainMap, ChainName } from '../types';
import { objMap, promiseObjAll } from '../utils/objects';
import { RouterContracts } from './types';
export class RouterApp<
Contracts extends RouterContracts,
> extends HyperlaneApp<Contracts> {
getSecurityModules = (): Promise<ChainMap<types.Address>> =>
promiseObjAll(
objMap(this.contractsMap, (_, contracts) =>
contracts.router.interchainSecurityModule(),
),
);
getOwners = (): Promise<ChainMap<types.Address>> =>
promiseObjAll(
objMap(this.contractsMap, (_, contracts) => contracts.router.owner()),
);
}
export class GasRouterApp<
Contracts extends RouterContracts<GasRouter>,
> extends RouterApp<Contracts> {
async quoteGasPayment(
origin: ChainName,
destination: ChainName,
): Promise<BigNumber> {
return this.getContracts(origin).router.quoteGasPayment(
this.multiProvider.getDomainId(destination),
);
}
}

@ -1,10 +1,7 @@
import { ethers } from 'ethers'; import { ProxyAdmin, ProxyAdmin__factory } from '@hyperlane-xyz/core';
import { ProxyAdmin, ProxyAdmin__factory, Router } from '@hyperlane-xyz/core';
import type { types } from '@hyperlane-xyz/utils'; import type { types } from '@hyperlane-xyz/utils';
import { HyperlaneContracts, HyperlaneFactories } from '../contracts'; import { HyperlaneContracts, HyperlaneFactories } from '../contracts';
import { ProxiedContract, TransparentProxyAddresses } from '../proxy';
export type OwnableConfig = { export type OwnableConfig = {
owner: types.Address; owner: types.Address;
@ -18,31 +15,13 @@ type GasConfig = {
export type GasRouterConfig = RouterConfig & GasConfig; export type GasRouterConfig = RouterConfig & GasConfig;
export type RouterContracts<RouterContract extends Router = Router> = export type ProxiedFactories = HyperlaneFactories & {
HyperlaneContracts & { proxyAdmin: ProxyAdmin__factory;
router: RouterContract; };
};
export type ProxiedContracts = HyperlaneContracts & {
export type ProxiedRouterContracts<RouterContract extends Router = Router> = proxyAdmin: ProxyAdmin;
RouterContracts<RouterContract> & { };
proxyAdmin: ProxyAdmin;
proxiedRouter: ProxiedContract<RouterContract, TransparentProxyAddresses>;
};
type RouterFactory<RouterContract extends Router = Router> =
ethers.ContractFactory & {
deploy: (...args: any[]) => Promise<RouterContract>;
};
export type RouterFactories<RouterContract extends Router = Router> =
HyperlaneFactories & {
router: RouterFactory<RouterContract>;
};
export type ProxiedRouterFactories<RouterContract extends Router = Router> =
RouterFactories<RouterContract> & {
proxyAdmin: ProxyAdmin__factory;
};
export type ConnectionClientConfig = { export type ConnectionClientConfig = {
mailbox: types.Address; mailbox: types.Address;

@ -1,6 +1,5 @@
import { TestRouter__factory } from '@hyperlane-xyz/core'; import { TestRouter, TestRouter__factory } from '@hyperlane-xyz/core';
import { HyperlaneApp } from '../../HyperlaneApp';
import { chainMetadata } from '../../consts/chainMetadata'; import { chainMetadata } from '../../consts/chainMetadata';
import { Chains } from '../../consts/chains'; import { Chains } from '../../consts/chains';
import { HyperlaneCore } from '../../core/HyperlaneCore'; import { HyperlaneCore } from '../../core/HyperlaneCore';
@ -8,43 +7,56 @@ import { HyperlaneDeployer } from '../../deploy/HyperlaneDeployer';
import { MultiProvider } from '../../providers/MultiProvider'; import { MultiProvider } from '../../providers/MultiProvider';
import { HyperlaneRouterChecker } from '../../router/HyperlaneRouterChecker'; import { HyperlaneRouterChecker } from '../../router/HyperlaneRouterChecker';
import { HyperlaneRouterDeployer } from '../../router/HyperlaneRouterDeployer'; import { HyperlaneRouterDeployer } from '../../router/HyperlaneRouterDeployer';
import { import { RouterApp } from '../../router/RouterApps';
RouterConfig, import { RouterConfig } from '../../router/types';
RouterContracts,
RouterFactories,
} from '../../router/types';
import { ChainMap, ChainName } from '../../types'; import { ChainMap, ChainName } from '../../types';
import { objMap, pick, promiseObjAll } from '../../utils/objects'; import { objMap, pick, promiseObjAll } from '../../utils/objects';
export const alfajoresChainConfig = pick(chainMetadata, [Chains.alfajores]); export const alfajoresChainConfig = pick(chainMetadata, [Chains.alfajores]);
export class EnvSubsetApp extends HyperlaneApp<RouterContracts> {} export type TestRouterContracts = {
router: TestRouter;
};
export type TestRouterFactories = {
router: TestRouter__factory;
};
export const testRouterFactories: TestRouterFactories = {
router: new TestRouter__factory(),
};
export class EnvSubsetApp extends RouterApp<TestRouterContracts> {
router(contracts: TestRouterContracts) {
return contracts.router;
}
}
export class EnvSubsetChecker extends HyperlaneRouterChecker< export class EnvSubsetChecker extends HyperlaneRouterChecker<
EnvSubsetApp, EnvSubsetApp,
RouterConfig, RouterConfig,
RouterContracts TestRouterContracts
> {} > {}
export const envSubsetFactories: RouterFactories = {
router: new TestRouter__factory(),
};
export class EnvSubsetDeployer extends HyperlaneRouterDeployer< export class EnvSubsetDeployer extends HyperlaneRouterDeployer<
RouterConfig, RouterConfig,
RouterContracts, TestRouterContracts,
RouterFactories TestRouterFactories
> { > {
constructor( constructor(
multiProvider: MultiProvider, multiProvider: MultiProvider,
configMap: ChainMap<RouterConfig>, configMap: ChainMap<RouterConfig>,
protected core: HyperlaneCore, protected core: HyperlaneCore,
) { ) {
super(multiProvider, configMap, envSubsetFactories, {}); super(multiProvider, configMap, testRouterFactories, {});
}
router(contracts: TestRouterContracts): TestRouter {
return contracts.router;
} }
// Consider moving this up to HyperlaneRouterDeployer // Consider moving this up to HyperlaneRouterDeployer
async initRouter(contractsMap: ChainMap<RouterContracts>): Promise<void> { async initRouter(contractsMap: ChainMap<TestRouterContracts>): Promise<void> {
this.logger(`Calling initialize on routers...`); this.logger(`Calling initialize on routers...`);
await promiseObjAll( await promiseObjAll(
objMap(contractsMap, async (chain, contracts) => { objMap(contractsMap, async (chain, contracts) => {
@ -53,17 +65,16 @@ export class EnvSubsetDeployer extends HyperlaneRouterDeployer<
const overrides = this.multiProvider.getTransactionOverrides(chain); const overrides = this.multiProvider.getTransactionOverrides(chain);
await this.multiProvider.handleTx( await this.multiProvider.handleTx(
chain, chain,
// @ts-ignore TestRouter does implement this, though Router type does not this.router(contracts).initialize(mailbox, igp, overrides),
contracts.router.initialize(mailbox, igp, overrides),
); );
}), }),
); );
} }
async deploy(): Promise<ChainMap<RouterContracts>> { async deploy(): Promise<ChainMap<TestRouterContracts>> {
const contractsMap = (await HyperlaneDeployer.prototype.deploy.apply( const contractsMap = (await HyperlaneDeployer.prototype.deploy.apply(
this, this,
)) as ChainMap<RouterContracts>; )) as ChainMap<TestRouterContracts>;
await this.initRouter(contractsMap); await this.initRouter(contractsMap);
await this.enrollRemoteRouters(contractsMap); await this.enrollRemoteRouters(contractsMap);
return contractsMap; return contractsMap;

@ -2,11 +2,15 @@ import { buildContracts } from '../../contracts';
import { HyperlaneCore } from '../../core/HyperlaneCore'; import { HyperlaneCore } from '../../core/HyperlaneCore';
import { HyperlaneIgp } from '../../gas/HyperlaneIgp'; import { HyperlaneIgp } from '../../gas/HyperlaneIgp';
import { MultiProvider } from '../../providers/MultiProvider'; import { MultiProvider } from '../../providers/MultiProvider';
import { RouterContracts } from '../../router/types';
import { ChainMap } from '../../types'; import { ChainMap } from '../../types';
import { createRouterConfigMap } from '../testUtils'; import { createRouterConfigMap } from '../testUtils';
import { EnvSubsetApp, EnvSubsetChecker, envSubsetFactories } from './app'; import {
EnvSubsetApp,
EnvSubsetChecker,
TestRouterContracts,
testRouterFactories,
} from './app';
// Copied from output of deploy-single-chain.ts script // Copied from output of deploy-single-chain.ts script
const deploymentAddresses = { const deploymentAddresses = {
@ -23,8 +27,8 @@ async function check() {
const contractsMap = buildContracts( const contractsMap = buildContracts(
deploymentAddresses, deploymentAddresses,
envSubsetFactories, testRouterFactories,
) as ChainMap<RouterContracts>; ) as ChainMap<TestRouterContracts>;
const app = new EnvSubsetApp(contractsMap, multiProvider); const app = new EnvSubsetApp(contractsMap, multiProvider);
const core = HyperlaneCore.fromEnvironment('testnet', multiProvider); const core = HyperlaneCore.fromEnvironment('testnet', multiProvider);
const igp = HyperlaneIgp.fromEnvironment('testnet', multiProvider); const igp = HyperlaneIgp.fromEnvironment('testnet', multiProvider);

@ -5,18 +5,23 @@ import { TestChains } from '../../consts/chains';
import { TestCoreApp } from '../../core/TestCoreApp'; import { TestCoreApp } from '../../core/TestCoreApp';
import { TestCoreDeployer } from '../../core/TestCoreDeployer'; import { TestCoreDeployer } from '../../core/TestCoreDeployer';
import { MultiProvider } from '../../providers/MultiProvider'; import { MultiProvider } from '../../providers/MultiProvider';
import { RouterConfig, RouterContracts } from '../../router/types'; import { RouterConfig } from '../../router/types';
import { ChainMap, ChainName } from '../../types'; import { ChainMap, ChainName } from '../../types';
import { deployTestIgpsAndGetRouterConfig, testCoreConfig } from '../testUtils'; import { deployTestIgpsAndGetRouterConfig, testCoreConfig } from '../testUtils';
import { EnvSubsetApp, EnvSubsetChecker, EnvSubsetDeployer } from './app'; import {
EnvSubsetApp,
EnvSubsetChecker,
EnvSubsetDeployer,
TestRouterContracts,
} from './app';
// Tests deploying the basic EnvSubsetApp to a local hardhat-based test env // Tests deploying the basic EnvSubsetApp to a local hardhat-based test env
describe('deploy app for full test env', async () => { describe('deploy app for full test env', async () => {
let multiProvider: MultiProvider; let multiProvider: MultiProvider;
let config: ChainMap<RouterConfig>; let config: ChainMap<RouterConfig>;
let deployer: EnvSubsetDeployer; let deployer: EnvSubsetDeployer;
let contracts: ChainMap<RouterContracts>; let contracts: ChainMap<TestRouterContracts>;
let app: EnvSubsetApp; let app: EnvSubsetApp;
before(async () => { before(async () => {
@ -46,7 +51,7 @@ describe('deploy app to test env subset', async () => {
let multiProvider: MultiProvider; let multiProvider: MultiProvider;
let config: ChainMap<RouterConfig>; let config: ChainMap<RouterConfig>;
let deployer: EnvSubsetDeployer; let deployer: EnvSubsetDeployer;
let contracts: ChainMap<RouterContracts>; let contracts: ChainMap<TestRouterContracts>;
let app: EnvSubsetApp; let app: EnvSubsetApp;
before(async () => { before(async () => {

@ -1 +1 @@
Subproject commit df21762a269d3d813fa28799a1a0216d5457e008 Subproject commit 306b107e662c4c87e963693bfe29cf2985f3090f
Loading…
Cancel
Save