Remove ProxiedContract and infer types (#2042)

### Description

This PR removes the ProxiedContract type and moves to inferring class
types from the factory type.

### Drive-by changes

None

### Related issues

- Fixes #2037 

### 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?_

Yes


### 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 63558af85d
commit 031f0a9692
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 2
      typescript/helloworld
  2. 6
      typescript/infra/hardhat.config.ts
  3. 3
      typescript/infra/scripts/debug-message.ts
  4. 2
      typescript/infra/scripts/deploy.ts
  5. 2
      typescript/infra/scripts/funding/fund-keys-from-deployer.ts
  6. 2
      typescript/infra/scripts/funding/reclaim-from-igp.ts
  7. 19
      typescript/infra/scripts/helloworld/deploy.ts
  8. 2
      typescript/infra/scripts/helloworld/kathy.ts
  9. 21
      typescript/infra/scripts/helloworld/utils.ts
  10. 9
      typescript/infra/scripts/middleware/circle-relayer.ts
  11. 9
      typescript/infra/scripts/middleware/portal-relayer.ts
  12. 4
      typescript/infra/src/core/deploy.ts
  13. 6
      typescript/infra/src/core/govern.ts
  14. 7
      typescript/infra/src/create2/index.ts
  15. 12
      typescript/infra/src/deploy.ts
  16. 6
      typescript/infra/src/gas/deploy.ts
  17. 6
      typescript/infra/src/gas/govern.ts
  18. 17
      typescript/infra/src/govern/HyperlaneAppGovernor.ts
  19. 7
      typescript/infra/src/testcontracts/testquerysender.ts
  20. 8
      typescript/infra/src/testcontracts/testrecipient.ts
  21. 39
      typescript/infra/test/core.test.ts
  22. 66
      typescript/sdk/src/HyperlaneApp.ts
  23. 9
      typescript/sdk/src/agents/types.ts
  24. 45
      typescript/sdk/src/consts/environments/index.ts
  25. 108
      typescript/sdk/src/consts/environments/mainnet.json
  26. 36
      typescript/sdk/src/consts/environments/test.json
  27. 108
      typescript/sdk/src/consts/environments/testnet.json
  28. 171
      typescript/sdk/src/contracts.ts
  29. 42
      typescript/sdk/src/core/HyperlaneCore.ts
  30. 11
      typescript/sdk/src/core/HyperlaneCoreChecker.ts
  31. 11
      typescript/sdk/src/core/HyperlaneCoreDeployer.ts
  32. 27
      typescript/sdk/src/core/TestCoreApp.ts
  33. 29
      typescript/sdk/src/core/contracts.ts
  34. 4
      typescript/sdk/src/core/testHyperlaneDeploy.hardhat-test.ts
  35. 80
      typescript/sdk/src/deploy/HyperlaneAppChecker.ts
  36. 98
      typescript/sdk/src/deploy/HyperlaneDeployer.ts
  37. 38
      typescript/sdk/src/deploy/proxy.ts
  38. 36
      typescript/sdk/src/gas/HyperlaneIgp.ts
  39. 14
      typescript/sdk/src/gas/HyperlaneIgpChecker.ts
  40. 19
      typescript/sdk/src/gas/HyperlaneIgpDeployer.ts
  41. 26
      typescript/sdk/src/gas/contracts.ts
  42. 37
      typescript/sdk/src/index.ts
  43. 11
      typescript/sdk/src/middleware/MiddlewareRouterChecker.ts
  44. 33
      typescript/sdk/src/middleware/MiddlewareRouterDeployer.ts
  45. 50
      typescript/sdk/src/middleware/account/InterchainAccount.ts
  46. 6
      typescript/sdk/src/middleware/account/InterchainAccountChecker.ts
  47. 32
      typescript/sdk/src/middleware/account/InterchainAccountDeployer.ts
  48. 9
      typescript/sdk/src/middleware/account/accounts.hardhat-test.ts
  49. 14
      typescript/sdk/src/middleware/account/contracts.ts
  50. 11
      typescript/sdk/src/middleware/liquidity-layer/LiquidityLayerApp.ts
  51. 39
      typescript/sdk/src/middleware/liquidity-layer/LiquidityLayerRouterDeployer.ts
  52. 20
      typescript/sdk/src/middleware/liquidity-layer/contracts.ts
  53. 3
      typescript/sdk/src/middleware/liquidity-layer/liquidity-layer.hardhat-test.ts
  54. 49
      typescript/sdk/src/middleware/query/InterchainQuery.ts
  55. 6
      typescript/sdk/src/middleware/query/InterchainQueryChecker.ts
  56. 2
      typescript/sdk/src/middleware/query/InterchainQueryDeployer.ts
  57. 14
      typescript/sdk/src/middleware/query/contracts.ts
  58. 9
      typescript/sdk/src/middleware/query/queries.hardhat-test.ts
  59. 76
      typescript/sdk/src/proxy.ts
  60. 17
      typescript/sdk/src/router/GasRouterDeployer.ts
  61. 6
      typescript/sdk/src/router/HyperlaneRouterChecker.ts
  62. 27
      typescript/sdk/src/router/HyperlaneRouterDeployer.ts
  63. 27
      typescript/sdk/src/router/RouterApps.ts
  64. 8
      typescript/sdk/src/router/types.ts
  65. 7
      typescript/sdk/src/test/envSubsetDeployer/app.ts
  66. 18
      typescript/sdk/src/test/envSubsetDeployer/check-single-chain.ts
  67. 4
      typescript/sdk/src/test/envSubsetDeployer/deploy-single-chain.ts
  68. 11
      typescript/sdk/src/test/testUtils.ts
  69. 2
      typescript/token

@ -1 +1 @@
Subproject commit 591edb07f44e67d95220e6c89d669f11cde68501
Subproject commit f9acb42cfe2154f5b1ee342f3e32aa5689fb00e2

@ -15,7 +15,7 @@ import { sleep } from './src/utils/utils';
const chainSummary = async (core: HyperlaneCore, chain: ChainName) => {
const coreContracts = core.getContracts(chain);
const mailbox = coreContracts.mailbox.contract;
const mailbox = coreContracts.mailbox;
const dispatched = await mailbox.count();
// TODO: Allow processed messages to be filtered by
// origin, possibly sender and recipient.
@ -66,8 +66,8 @@ task('kathy', 'Dispatches random hyperlane messages')
const local = core.chains()[0];
const remote: ChainName = randomElement(core.remoteChains(local));
const remoteId = multiProvider.getDomainId(remote);
const mailbox = core.getContracts(local).mailbox.contract;
const igp = igps.getContracts(local).interchainGasPaymaster.contract;
const mailbox = core.getContracts(local).mailbox;
const igp = igps.getContracts(local).interchainGasPaymaster;
// Send a batch of messages to the destination chain to test
// the relayer submitting only greedily
for (let i = 0; i < 10; i++) {

@ -93,8 +93,7 @@ async function checkMessage(
return;
}
const destinationMailbox =
core.getContracts(destinationChain).mailbox.contract;
const destinationMailbox = core.getContracts(destinationChain).mailbox;
const delivered = await destinationMailbox.delivered(messageId);
if (delivered) {
console.log('Message has already been processed');

@ -49,7 +49,7 @@ async function main() {
multiProvider.setSigner(fork, signer);
}
let deployer: HyperlaneDeployer<any, any, any>;
let deployer: HyperlaneDeployer<any, any>;
if (module === Modules.CORE) {
deployer = new HyperlaneCoreInfraDeployer(
multiProvider,

@ -512,7 +512,7 @@ class ContextFunder {
});
await this.multiProvider.sendTransaction(
chain,
await igp.contract.populateTransaction.claim(),
await igp.populateTransaction.claim(),
);
} else {
log('IGP balance does not exceed claim threshold, skipping', {

@ -38,7 +38,7 @@ async function main() {
if (balance.lt(RECLAIM_BALANCE_THRESHOLD)) {
return 'N/A';
}
const tx = await paymaster.contract.claim();
const tx = await paymaster.claim();
return multiProvider.tryGetExplorerTxUrl(chain, tx);
}),
);

@ -1,15 +1,15 @@
import path from 'path';
import {
HelloWorldContracts,
HelloWorldDeployer,
HelloWorldFactories,
helloWorldFactories,
} from '@hyperlane-xyz/helloworld';
import {
ChainMap,
HyperlaneContractsMap,
HyperlaneCore,
buildContracts,
serializeContracts,
attachContractsMap,
serializeContractsMap,
} from '@hyperlane-xyz/sdk';
import { Contexts } from '../../config/contexts';
@ -45,21 +45,18 @@ async function main() {
context,
);
let previousContracts: ChainMap<HelloWorldContracts> = {};
let contracts: HyperlaneContractsMap<HelloWorldFactories> = {};
let existingVerificationInputs = {};
try {
const addresses = readJSON(dir, 'addresses.json');
previousContracts = buildContracts(
addresses,
helloWorldFactories,
) as ChainMap<HelloWorldContracts>;
contracts = attachContractsMap(addresses, helloWorldFactories);
existingVerificationInputs = readJSON(dir, 'verification.json');
} catch (e) {
console.info(`Could not load previous deployment, file may not exist`);
}
try {
await deployer.deploy(previousContracts);
await deployer.deploy(contracts);
} catch (e) {
console.error(`Encountered error during deploy`);
console.error(e);
@ -68,7 +65,7 @@ async function main() {
writeJSON(
dir,
'addresses.json',
serializeContracts(deployer.deployedContracts),
serializeContractsMap(deployer.deployedContracts),
);
writeJSON(
dir,

@ -447,7 +447,7 @@ async function messageIsProcessed(
destination: ChainName,
message: DispatchedMessage,
): Promise<boolean> {
const destinationMailbox = core.getContracts(destination).mailbox.contract;
const destinationMailbox = core.getContracts(destination).mailbox;
return destinationMailbox.delivered(message.id);
}

@ -1,14 +1,9 @@
import {
HelloWorldApp,
HelloWorldContracts,
helloWorldFactories,
} from '@hyperlane-xyz/helloworld';
import { HelloWorldApp, helloWorldFactories } from '@hyperlane-xyz/helloworld';
import {
AgentConnectionType,
ChainMap,
HyperlaneCore,
MultiProvider,
buildContracts,
attachContractsMap,
} from '@hyperlane-xyz/sdk';
import { Contexts } from '../../config/contexts';
@ -24,20 +19,20 @@ export async function getApp(
keyContext: Contexts = context,
connectionType: AgentConnectionType = AgentConnectionType.Http,
) {
const helloworldConfig = getHelloWorldConfig(coreConfig, context);
const contracts = buildContracts(
helloworldConfig.addresses,
helloWorldFactories,
) as ChainMap<HelloWorldContracts>;
const multiProvider: MultiProvider = await coreConfig.getMultiProvider(
keyContext,
keyRole,
connectionType,
);
const helloworldConfig = getHelloWorldConfig(coreConfig, context);
const contracts = attachContractsMap(
helloworldConfig.addresses,
helloWorldFactories,
);
const core = HyperlaneCore.fromEnvironment(
deployEnvToSdkEnv[coreConfig.environment],
multiProvider,
) as HyperlaneCore;
);
return new HelloWorldApp(core, contracts, multiProvider);
}

@ -1,11 +1,9 @@
import path from 'path';
import {
ChainMap,
Chains,
LiquidityLayerApp,
LiquidityLayerContracts,
buildContracts,
attachContractsMap,
liquidityLayerFactories,
} from '@hyperlane-xyz/sdk';
@ -28,10 +26,7 @@ async function check() {
'middleware/liquidity-layer',
);
const addresses = readJSON(dir, 'addresses.json');
const contracts = buildContracts(
addresses,
liquidityLayerFactories,
) as ChainMap<LiquidityLayerContracts>;
const contracts = attachContractsMap(addresses, liquidityLayerFactories);
const app = new LiquidityLayerApp(
contracts,
multiProvider,

@ -1,10 +1,8 @@
import path from 'path';
import {
ChainMap,
LiquidityLayerApp,
LiquidityLayerContracts,
buildContracts,
attachContractsMap,
liquidityLayerFactories,
} from '@hyperlane-xyz/sdk';
import { error, log } from '@hyperlane-xyz/utils';
@ -28,10 +26,7 @@ async function relayPortalTransfers() {
'middleware/liquidity-layer',
);
const addresses = readJSON(dir, 'addresses.json');
const contracts = buildContracts(
addresses,
liquidityLayerFactories,
) as ChainMap<LiquidityLayerContracts>;
const contracts = attachContractsMap(addresses, liquidityLayerFactories);
const app = new LiquidityLayerApp(
contracts,
multiProvider,

@ -7,8 +7,6 @@ import {
CoreConfig,
HyperlaneCoreDeployer,
MultiProvider,
ProxiedContract,
TransparentProxyAddresses,
} from '@hyperlane-xyz/sdk';
import { DeployOptions } from '@hyperlane-xyz/sdk/dist/deploy/HyperlaneDeployer';
import { types } from '@hyperlane-xyz/utils';
@ -32,7 +30,7 @@ export class HyperlaneCoreInfraDeployer extends HyperlaneCoreDeployer {
defaultIsmAddress: types.Address,
proxyAdmin: types.Address,
deployOpts?: DeployOptions,
): Promise<ProxiedContract<Mailbox, TransparentProxyAddresses>> {
): Promise<Mailbox> {
return super.deployMailbox(chain, defaultIsmAddress, proxyAdmin, {
...deployOpts,
create2Salt: ethers.utils.solidityKeccak256(

@ -9,8 +9,6 @@ import {
MultisigIsmViolation,
MultisigIsmViolationType,
OwnerViolation,
ProxyKind,
ProxyViolation,
ViolationType,
} from '@hyperlane-xyz/sdk';
import { types, utils } from '@hyperlane-xyz/utils';
@ -39,10 +37,6 @@ export class HyperlaneCoreGovernor extends HyperlaneAppGovernor<
this.handleOwnerViolation(violation as OwnerViolation);
break;
}
case ProxyKind.Transparent: {
this.handleProxyViolation(violation as ProxyViolation);
break;
}
default:
throw new Error(`Unsupported violation type ${violation.type}`);
}

@ -1,4 +1,4 @@
import { Create2Factory, Create2Factory__factory } from '@hyperlane-xyz/core';
import { Create2Factory__factory } from '@hyperlane-xyz/core';
import {
ChainName,
HyperlaneDeployer,
@ -10,17 +10,12 @@ export const factories = {
Create2Factory: new Create2Factory__factory(),
};
type Contracts = {
Create2Factory: Create2Factory;
};
// Hardcode the bytecode here to be indpendent of the compiler version
const CREATE2FACTORYBYTECODE =
'0x608060405234801561001057600080fd5b50610640806100206000396000f3fe608060405234801561001057600080fd5b50600436106100415760003560e01c80634af63f0214610046578063c2b1041c14610082578063cf4d643214610095575b600080fd5b610059610054366004610486565b6100a8565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200160405180910390f35b610059610090366004610514565b6100e7565b6100596100a336600461058a565b6101f4565b604080513360208201529081018290526000906100e09084906060015b604051602081830303815290604052805190602001206102c6565b9392505050565b6040805173ffffffffffffffffffffffffffffffffffffffff8416602082015290810182905260009081906060016040516020818303038152906040528051906020012090503081878760405161013f9291906105fa565b6040519081900381206101b49392916020017fff00000000000000000000000000000000000000000000000000000000000000815260609390931b7fffffffffffffffffffffffffffffffffffffffff0000000000000000000000001660018401526015830191909152603582015260550190565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081840301815291905280516020909101209695505050505050565b604080513360208201529081018490526000906102159086906060016100c5565b905060008173ffffffffffffffffffffffffffffffffffffffff1684846040516102409291906105fa565b6000604051808303816000865af19150503d806000811461027d576040519150601f19603f3d011682016040523d82523d6000602084013e610282565b606091505b50509050806102bd576040517f4f77232300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b50949350505050565b60008251600003610303576040517f21744a5900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b818351602085016000f5905073ffffffffffffffffffffffffffffffffffffffff811661035c576040517f4102e83a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8251602084012060405173ffffffffffffffffffffffffffffffffffffffff83169184917f27b8e3132afa95254770e1c1d214eafde52bc47d1b6e1f5dfcbb380c3ca3f53290600090a492915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b600082601f8301126103ec57600080fd5b813567ffffffffffffffff80821115610407576104076103ac565b604051601f83017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f0116810190828211818310171561044d5761044d6103ac565b8160405283815286602085880101111561046657600080fd5b836020870160208301376000602085830101528094505050505092915050565b6000806040838503121561049957600080fd5b823567ffffffffffffffff8111156104b057600080fd5b6104bc858286016103db565b95602094909401359450505050565b60008083601f8401126104dd57600080fd5b50813567ffffffffffffffff8111156104f557600080fd5b60208301915083602082850101111561050d57600080fd5b9250929050565b6000806000806060858703121561052a57600080fd5b843567ffffffffffffffff81111561054157600080fd5b61054d878288016104cb565b909550935050602085013573ffffffffffffffffffffffffffffffffffffffff8116811461057a57600080fd5b9396929550929360400135925050565b600080600080606085870312156105a057600080fd5b843567ffffffffffffffff808211156105b857600080fd5b6105c4888389016103db565b95506020870135945060408701359150808211156105e157600080fd5b506105ee878288016104cb565b95989497509550505050565b818382376000910190815291905056fea2646970667358221220959b7947b895d33da4de69733c07a0543161262edcf0e8d1784935027b47462c64736f6c63430008110033';
export class Create2FactoryDeployer extends HyperlaneDeployer<
any,
Contracts,
typeof factories
> {
constructor(multiProvider: MultiProvider) {

@ -5,11 +5,11 @@ import {
HyperlaneAgentAddresses,
HyperlaneDeployer,
MultiProvider,
attachContractsMap,
buildAgentConfig,
buildContracts,
objMap,
promiseObjAll,
serializeContracts,
serializeContractsMap,
} from '@hyperlane-xyz/sdk';
import { getAgentConfigDirectory } from '../scripts/utils';
@ -27,7 +27,7 @@ export async function writeAgentConfig(
multiProvider: MultiProvider,
environment: DeployEnvironment,
) {
let addresses: ChainMap<HyperlaneAddresses> = {};
let addresses: ChainMap<HyperlaneAddresses<any>> = {};
try {
addresses = readJSONAtPath(addressesPath);
} catch (e) {
@ -52,7 +52,7 @@ export async function writeAgentConfig(
}
export async function deployWithArtifacts(
deployer: HyperlaneDeployer<any, any, any>,
deployer: HyperlaneDeployer<any, any>,
cache: {
addresses: string;
verification: string;
@ -74,7 +74,7 @@ export async function deployWithArtifacts(
console.error('Failed to load cached addresses');
}
const savedContracts = buildContracts(addresses, deployer.factories);
const savedContracts = attachContractsMap(addresses, deployer.factories);
deployer.cacheContracts(savedContracts);
}
@ -92,7 +92,7 @@ export async function deployWithArtifacts(
// cache addresses of deployed contracts
writeMergedJSONAtPath(
cache.addresses,
serializeContracts(deployer.deployedContracts),
serializeContractsMap(deployer.deployedContracts),
);
let savedVerification = {};

@ -13,8 +13,6 @@ import {
HyperlaneIgpDeployer,
MultiProvider,
OverheadIgpConfig,
ProxiedContract,
TransparentProxyAddresses,
} from '@hyperlane-xyz/sdk';
import { types } from '@hyperlane-xyz/utils';
@ -37,9 +35,7 @@ export class HyperlaneIgpInfraDeployer extends HyperlaneIgpDeployer {
proxyAdmin: ProxyAdmin,
storageGasOracle: StorageGasOracle,
deployOpts?: DeployOptions,
): Promise<
ProxiedContract<InterchainGasPaymaster, TransparentProxyAddresses>
> {
): Promise<InterchainGasPaymaster> {
return super.deployInterchainGasPaymaster(
chain,
proxyAdmin,

@ -10,8 +10,6 @@ import {
IgpViolation,
IgpViolationType,
OverheadIgpConfig,
ProxyKind,
ProxyViolation,
} from '@hyperlane-xyz/sdk';
import { types } from '@hyperlane-xyz/utils';
@ -32,10 +30,6 @@ export class HyperlaneIgpGovernor extends HyperlaneAppGovernor<
this.handleIgpViolation(violation as IgpViolation);
break;
}
case ProxyKind.Transparent: {
this.handleProxyViolation(violation as ProxyViolation);
break;
}
default:
throw new Error(`Unsupported violation type ${violation.type}`);
}

@ -3,11 +3,9 @@ import { prompts } from 'prompts';
import {
ChainMap,
ChainName,
CoreContracts,
HyperlaneApp,
HyperlaneAppChecker,
OwnerViolation,
ProxyViolation,
objMap,
} from '@hyperlane-xyz/sdk';
import { types } from '@hyperlane-xyz/utils';
@ -132,21 +130,6 @@ export abstract class HyperlaneAppGovernor<
protected abstract mapViolationsToCalls(): Promise<void>;
handleProxyViolation(violation: ProxyViolation) {
const contracts: CoreContracts =
this.checker.app.contractsMap[violation.chain];
const data = contracts.proxyAdmin.interface.encodeFunctionData('upgrade', [
violation.data.proxyAddresses.proxy,
violation.data.proxyAddresses.implementation,
]);
this.pushCall(violation.chain, {
to: contracts.proxyAdmin.address,
data,
description: `Upgrade proxy ${violation.data.proxyAddresses.proxy} to implementation ${violation.data.proxyAddresses.implementation}`,
});
}
protected async inferCallSubmissionTypes() {
for (const chain of Object.keys(this.calls)) {
for (const call of this.calls[chain]) {

@ -1,4 +1,4 @@
import { TestQuerySender, TestQuerySender__factory } from '@hyperlane-xyz/core';
import { TestQuerySender__factory } from '@hyperlane-xyz/core';
import {
ChainMap,
ChainName,
@ -13,13 +13,8 @@ export const factories = {
type TestQuerySenderConfig = { queryRouterAddress: string };
type Contracts = {
TestQuerySender: TestQuerySender;
};
export class TestQuerySenderDeployer extends HyperlaneDeployer<
TestQuerySenderConfig,
Contracts,
typeof factories
> {
constructor(

@ -1,7 +1,5 @@
import {
TestRecipient,
TestRecipient__factory,
TestTokenRecipient,
TestTokenRecipient__factory,
} from '@hyperlane-xyz/core';
import {
@ -15,14 +13,8 @@ export const factories = {
TestTokenRecipient: new TestTokenRecipient__factory(),
};
type Contracts = {
TestRecipient: TestRecipient;
TestTokenRecipient: TestTokenRecipient;
};
export class TestRecipientDeployer extends HyperlaneDeployer<
any,
Contracts,
typeof factories
> {
constructor(multiProvider: MultiProvider) {

@ -6,13 +6,14 @@ import sinon from 'sinon';
import {
ChainMap,
CoreConfig,
CoreContractsMap,
HyperlaneContractsMap,
HyperlaneCore,
HyperlaneCoreChecker,
MultiProvider,
objMap,
serializeContracts,
serializeContractsMap,
} from '@hyperlane-xyz/sdk';
import { CoreFactories } from '@hyperlane-xyz/sdk/dist/core/contracts';
import { environment as testConfig } from '../config/environments/test';
import { HyperlaneCoreInfraDeployer } from '../src/core/deploy';
@ -24,7 +25,7 @@ describe('core', async () => {
let multiProvider: MultiProvider;
let deployer: HyperlaneCoreInfraDeployer;
let core: HyperlaneCore;
let contracts: CoreContractsMap;
let contracts: HyperlaneContractsMap<CoreFactories>;
let coreConfig: ChainMap<CoreConfig>;
let owners: ChainMap<string>;
@ -48,7 +49,7 @@ describe('core', async () => {
it('writes', async () => {
const base = './test/outputs/core';
writeJSON(base, 'contracts.json', serializeContracts(contracts));
writeJSON(base, 'contracts.json', serializeContractsMap(contracts));
writeJSON(base, 'verification.json', deployer.verificationInputs);
// deployer.writeRustConfigs(base);
});
@ -100,36 +101,6 @@ describe('core', async () => {
});
});
describe('proxy upgrades', async () => {
beforeEach(async () => {
deployer = new HyperlaneCoreInfraDeployer(
multiProvider,
coreConfig,
environment,
);
await deployer.deploy();
});
it('deploys a new implementation if it has been removed from the artifacts', async () => {
// Copy the old addresses
const oldAddresses = {
...deployer.deployedContracts.test2!.mailbox!.addresses,
};
// @ts-ignore
delete deployer.deployedContracts.test2!.mailbox!.addresses
.implementation;
const result = await deployer.deploy();
const newAddresses = result.test2.mailbox.addresses;
// New implementation
expect(newAddresses.implementation).to.not.be.undefined;
expect(newAddresses.implementation).to.not.equal(
oldAddresses.implementation,
);
// Same proxy
expect(newAddresses.proxy).to.equal(oldAddresses.proxy);
});
});
it('checks', async () => {
const joinedConfig = objMap(coreConfig, (chain, config) => ({
...config,

@ -1,23 +1,24 @@
import {
HyperlaneAddresses,
HyperlaneContract,
HyperlaneAddressesMap,
HyperlaneContracts,
HyperlaneContractsMap,
HyperlaneFactories,
buildContracts,
attachContractsMap,
connectContracts,
filterAddressesMap,
serializeContracts,
} from './contracts';
import { MultiProvider } from './providers/MultiProvider';
import { isProxiedContract } from './proxy';
import { ChainMap, ChainName } from './types';
import { ChainName } from './types';
import { MultiGeneric } from './utils/MultiGeneric';
import { objFilter, objMap, pick } from './utils/objects';
import { objMap, pick } from './utils/objects';
export class HyperlaneApp<
Contracts extends HyperlaneContracts,
> extends MultiGeneric<Contracts> {
Factories extends HyperlaneFactories,
> extends MultiGeneric<HyperlaneContracts<Factories>> {
constructor(
public readonly contractsMap: ChainMap<Contracts>,
public readonly contractsMap: HyperlaneContractsMap<Factories>,
public readonly multiProvider: MultiProvider,
) {
const connectedContractsMap = objMap(contractsMap, (chain, contracts) =>
@ -26,39 +27,36 @@ export class HyperlaneApp<
super(connectedContractsMap);
}
static buildContracts<C extends HyperlaneContracts>(
addresses: ChainMap<HyperlaneAddresses>,
factories: HyperlaneFactories,
static fromAddressesMap<F extends HyperlaneFactories>(
addressesMap: HyperlaneAddressesMap<any>,
factories: F,
multiProvider: MultiProvider,
): { contracts: ChainMap<C>; intersectionProvider: MultiProvider } {
const chains = Object.keys(addresses);
const { intersection, multiProvider: intersectionProvider } =
multiProvider.intersect(chains, true);
const intersectionAddresses = pick(addresses, intersection);
const contracts = buildContracts(
intersectionAddresses,
): { contractsMap: HyperlaneContractsMap<F>; multiProvider: MultiProvider } {
// Attaches contracts for each chain for which we have a complete set of
// addresses
const contractsMap = attachContractsMap(
filterAddressesMap(addressesMap, factories),
factories,
) as ChainMap<C>;
return { contracts, intersectionProvider };
}
);
getContracts(chain: ChainName): Contracts {
return this.get(chain);
// Filters out providers for chains for which we don't have a complete set
// of addresses
const intersection = multiProvider.intersect(Object.keys(contractsMap));
// Filters out contracts for chains for which we don't have a provider
const filteredContractsMap = pick(contractsMap, intersection.intersection);
return {
contractsMap: filteredContractsMap,
multiProvider: intersection.multiProvider,
};
}
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;
getContracts(chain: ChainName): HyperlaneContracts<Factories> {
return this.get(chain);
}
getAddresses(chain: ChainName): HyperlaneAddresses {
getAddresses(chain: ChainName): HyperlaneAddresses<Factories> {
return serializeContracts(this.get(chain));
}
}

@ -1,7 +1,6 @@
import { types } from '@hyperlane-xyz/utils';
import { MultiProvider } from '../providers/MultiProvider';
import { getProxyAddress } from '../proxy';
import { ChainMap, ChainName } from '../types';
export type AgentSigner = {
@ -71,11 +70,9 @@ export function buildAgentConfig(
name: chain,
domain: metadata.chainId,
addresses: {
mailbox: getProxyAddress(addresses[chain].mailbox),
interchainGasPaymaster: getProxyAddress(
addresses[chain].interchainGasPaymaster,
),
validatorAnnounce: getProxyAddress(addresses[chain].validatorAnnounce),
mailbox: addresses[chain].mailbox,
interchainGasPaymaster: addresses[chain].interchainGasPaymaster,
validatorAnnounce: addresses[chain].validatorAnnounce,
},
protocol: 'ethereum',
finalityBlocks: metadata.blocks?.reorgPeriod ?? 1,

@ -1,8 +1,4 @@
import { HyperlaneAgentAddresses } from '../../agents/types';
import { CoreAddresses } from '../../core/contracts';
import { IgpAddresses } from '../../gas/contracts';
import { ChainMap, ChainName } from '../../types';
import { objMap } from '../../utils/objects';
import { ChainName } from '../../types';
import mainnet from './mainnet.json';
import test from './test.json';
@ -15,42 +11,3 @@ export type HyperlaneEnvironmentChain<E extends HyperlaneEnvironment> = Extract<
keyof typeof hyperlaneEnvironments[E],
ChainName
>;
// TODO: Add middleware addresses
export type HyperlaneContractAddresses = CoreAddresses & IgpAddresses;
// Export developer-relevant addresses
export const hyperlaneCoreAddresses = objMap(
{ ...testnet, ...mainnet },
(_chain, addresses) => ({
mailbox: addresses.mailbox.proxy,
multisigIsm: addresses.multisigIsm,
proxyAdmin: addresses.proxyAdmin,
validatorAnnounce: addresses.validatorAnnounce,
}),
) as ChainMap<CoreAddresses>;
export const hyperlaneContractAddresses = objMap(
{ ...testnet, ...mainnet },
(_chain, addresses) => ({
mailbox: addresses.mailbox.proxy,
multisigIsm: addresses.multisigIsm,
proxyAdmin: addresses.proxyAdmin,
validatorAnnounce: addresses.validatorAnnounce,
interchainGasPaymaster: addresses.interchainGasPaymaster.proxy,
storageGasOracle: addresses.storageGasOracle,
defaultIsmInterchainGasPaymaster:
addresses.defaultIsmInterchainGasPaymaster,
//interchainAccountRouter: undefined,
//interchainQueryRouter: undefined,
}),
) as ChainMap<HyperlaneContractAddresses>;
export const hyperlaneAgentAddresses = objMap(
{ ...testnet, ...mainnet },
(_chain, addresses) => ({
mailbox: addresses.mailbox.proxy,
validatorAnnounce: addresses.validatorAnnounce,
interchainGasPaymaster: addresses.interchainGasPaymaster.proxy,
}),
) as ChainMap<HyperlaneAgentAddresses>;

@ -3,16 +3,8 @@
"storageGasOracle": "0xD9A9966E7dA9a7f0032bF449FB12696a638E673C",
"validatorAnnounce": "0x9bBdef63594D5FFc2f370Fe52115DdFFe97Bc524",
"proxyAdmin": "0x90f9a2E9eCe93516d65FdaB726a3c62F5960a1b9",
"mailbox": {
"kind": "Transparent",
"proxy": "0x35231d4c2D8B8ADcB5617A638A0c4548684c7C70",
"implementation": "0x3f23f4594e1cCA1734d0A7F15495bF3C4cdb55db"
},
"interchainGasPaymaster": {
"kind": "Transparent",
"proxy": "0x6cA0B6D22da47f091B7613223cD4BB03a2d77918",
"implementation": "0xbdd8eb3884A8F111F338b7784c163DD62d03DaF9"
},
"mailbox": "0x35231d4c2D8B8ADcB5617A638A0c4548684c7C70",
"interchainGasPaymaster": "0x6cA0B6D22da47f091B7613223cD4BB03a2d77918",
"defaultIsmInterchainGasPaymaster": "0x56f52c0A1ddcD557285f7CBc782D3d83096CE1Cc",
"multisigIsm": "0x9bDE63104EE030d9De419EEd6bA7D14b86D6fE3f",
"create2Factory": "0xc97D8e6f57b0d64971453dDc6EB8483fec9d163a",
@ -23,16 +15,8 @@
"storageGasOracle": "0xc9a103990A8dB11b4f627bc5CD1D0c2685484Ec5",
"validatorAnnounce": "0x9bBdef63594D5FFc2f370Fe52115DdFFe97Bc524",
"proxyAdmin": "0x75EE15Ee1B4A75Fa3e2fDF5DF3253c25599cc659",
"mailbox": {
"kind": "Transparent",
"proxy": "0x35231d4c2D8B8ADcB5617A638A0c4548684c7C70",
"implementation": "0xcC48E741996B0d77b38d9dC2bf9217e65E368E06"
},
"interchainGasPaymaster": {
"kind": "Transparent",
"proxy": "0x6cA0B6D22da47f091B7613223cD4BB03a2d77918",
"implementation": "0xbdd8eb3884A8F111F338b7784c163DD62d03DaF9"
},
"mailbox": "0x35231d4c2D8B8ADcB5617A638A0c4548684c7C70",
"interchainGasPaymaster": "0x6cA0B6D22da47f091B7613223cD4BB03a2d77918",
"defaultIsmInterchainGasPaymaster": "0x56f52c0A1ddcD557285f7CBc782D3d83096CE1Cc",
"multisigIsm": "0xec48E52D960E54a179f70907bF28b105813877ee",
"create2Factory": "0xc97D8e6f57b0d64971453dDc6EB8483fec9d163a",
@ -43,16 +27,8 @@
"storageGasOracle": "0x175821F30AdCAA4bbB72Ce98eF76C2E0De2C3f21",
"validatorAnnounce": "0x9bBdef63594D5FFc2f370Fe52115DdFFe97Bc524",
"proxyAdmin": "0xd7CF8c05fd81b8cA7CfF8E6C49B08a9D63265c9B",
"mailbox": {
"kind": "Transparent",
"proxy": "0x35231d4c2D8B8ADcB5617A638A0c4548684c7C70",
"implementation": "0xFB4712576680002C2690f66C0c5eedEa5260DBfB"
},
"interchainGasPaymaster": {
"kind": "Transparent",
"proxy": "0x6cA0B6D22da47f091B7613223cD4BB03a2d77918",
"implementation": "0xbdd8eb3884A8F111F338b7784c163DD62d03DaF9"
},
"mailbox": "0x35231d4c2D8B8ADcB5617A638A0c4548684c7C70",
"interchainGasPaymaster": "0x6cA0B6D22da47f091B7613223cD4BB03a2d77918",
"defaultIsmInterchainGasPaymaster": "0x56f52c0A1ddcD557285f7CBc782D3d83096CE1Cc",
"multisigIsm": "0xeE80ab5B563cB3825133f29502bA34eD3707cb8C",
"create2Factory": "0xc97D8e6f57b0d64971453dDc6EB8483fec9d163a",
@ -63,16 +39,8 @@
"storageGasOracle": "0xA3a24EC5670F1F416AB9fD554FcE2f226AE9D7eB",
"validatorAnnounce": "0x9bBdef63594D5FFc2f370Fe52115DdFFe97Bc524",
"proxyAdmin": "0xC4F7590C5d30BE959225dC75640657954A86b980",
"mailbox": {
"kind": "Transparent",
"proxy": "0x35231d4c2D8B8ADcB5617A638A0c4548684c7C70",
"implementation": "0xd63C65e84059b9d32bc979016bbC2976138da694"
},
"interchainGasPaymaster": {
"kind": "Transparent",
"proxy": "0x6cA0B6D22da47f091B7613223cD4BB03a2d77918",
"implementation": "0xbdd8eb3884A8F111F338b7784c163DD62d03DaF9"
},
"mailbox": "0x35231d4c2D8B8ADcB5617A638A0c4548684c7C70",
"interchainGasPaymaster": "0x6cA0B6D22da47f091B7613223cD4BB03a2d77918",
"defaultIsmInterchainGasPaymaster": "0x56f52c0A1ddcD557285f7CBc782D3d83096CE1Cc",
"multisigIsm": "0x61A80297e77FC5395bd6Ff60EEacf7CD4f18d4a4",
"create2Factory": "0xc97D8e6f57b0d64971453dDc6EB8483fec9d163a",
@ -83,16 +51,8 @@
"storageGasOracle": "0x91d23D603d60445411C06e6443d81395593B7940",
"validatorAnnounce": "0x9bBdef63594D5FFc2f370Fe52115DdFFe97Bc524",
"proxyAdmin": "0x65993Af9D0D3a64ec77590db7ba362D6eB78eF70",
"mailbox": {
"kind": "Transparent",
"proxy": "0x35231d4c2D8B8ADcB5617A638A0c4548684c7C70",
"implementation": "0x961877927Ec6B0a9133DbBb1d0232CB6A5C28b54"
},
"interchainGasPaymaster": {
"kind": "Transparent",
"proxy": "0x6cA0B6D22da47f091B7613223cD4BB03a2d77918",
"implementation": "0xbdd8eb3884A8F111F338b7784c163DD62d03DaF9"
},
"mailbox": "0x35231d4c2D8B8ADcB5617A638A0c4548684c7C70",
"interchainGasPaymaster": "0x6cA0B6D22da47f091B7613223cD4BB03a2d77918",
"defaultIsmInterchainGasPaymaster": "0x56f52c0A1ddcD557285f7CBc782D3d83096CE1Cc",
"multisigIsm": "0x3a579C0bd04FC4C98A8D70EEABD9094e7be4B26D",
"create2Factory": "0xc97D8e6f57b0d64971453dDc6EB8483fec9d163a",
@ -103,16 +63,8 @@
"storageGasOracle": "0xD3805207b65d99C075ceA938Fa7c0587026a5DF5",
"validatorAnnounce": "0x9bBdef63594D5FFc2f370Fe52115DdFFe97Bc524",
"proxyAdmin": "0x80Cebd56A65e46c474a1A101e89E76C4c51D179c",
"mailbox": {
"kind": "Transparent",
"proxy": "0x35231d4c2D8B8ADcB5617A638A0c4548684c7C70",
"implementation": "0x4B5bc88A0D383c3C6E72D9889afaBB12A5dCCCfa"
},
"interchainGasPaymaster": {
"kind": "Transparent",
"proxy": "0x6cA0B6D22da47f091B7613223cD4BB03a2d77918",
"implementation": "0xbdd8eb3884A8F111F338b7784c163DD62d03DaF9"
},
"mailbox": "0x35231d4c2D8B8ADcB5617A638A0c4548684c7C70",
"interchainGasPaymaster": "0x6cA0B6D22da47f091B7613223cD4BB03a2d77918",
"defaultIsmInterchainGasPaymaster": "0x56f52c0A1ddcD557285f7CBc782D3d83096CE1Cc",
"multisigIsm": "0x32B92bd3e5045B67FDD8dbb7A58D25980836d04C",
"create2Factory": "0xc97D8e6f57b0d64971453dDc6EB8483fec9d163a",
@ -123,16 +75,8 @@
"storageGasOracle": "0x27e88AeB8EA4B159d81df06355Ea3d20bEB1de38",
"validatorAnnounce": "0x9bBdef63594D5FFc2f370Fe52115DdFFe97Bc524",
"proxyAdmin": "0xE047cb95FB3b7117989e911c6afb34771183fC35",
"mailbox": {
"kind": "Transparent",
"proxy": "0x35231d4c2D8B8ADcB5617A638A0c4548684c7C70",
"implementation": "0x6989120F7042Df0895dBE856b73A31E4cD0A2Cad"
},
"interchainGasPaymaster": {
"kind": "Transparent",
"proxy": "0x6cA0B6D22da47f091B7613223cD4BB03a2d77918",
"implementation": "0xbdd8eb3884A8F111F338b7784c163DD62d03DaF9"
},
"mailbox": "0x35231d4c2D8B8ADcB5617A638A0c4548684c7C70",
"interchainGasPaymaster": "0x6cA0B6D22da47f091B7613223cD4BB03a2d77918",
"defaultIsmInterchainGasPaymaster": "0x56f52c0A1ddcD557285f7CBc782D3d83096CE1Cc",
"multisigIsm": "0xAab1D11E2063Bae5EB01fa946cA8d2FDe3db05D5",
"create2Factory": "0xc97D8e6f57b0d64971453dDc6EB8483fec9d163a",
@ -143,16 +87,8 @@
"storageGasOracle": "0x448b7ADB0dA36d41AA2AfDc9d63b97541A7b3819",
"validatorAnnounce": "0x9bBdef63594D5FFc2f370Fe52115DdFFe97Bc524",
"proxyAdmin": "0x6A9cdA3dd1F593983BFd142Eb35e6ce4137bd5ce",
"mailbox": {
"kind": "Transparent",
"proxy": "0x35231d4c2D8B8ADcB5617A638A0c4548684c7C70",
"implementation": "0x1747Fa1b94862C8648BF0637767315FD1Fa2106C"
},
"interchainGasPaymaster": {
"kind": "Transparent",
"proxy": "0x6cA0B6D22da47f091B7613223cD4BB03a2d77918",
"implementation": "0xbdd8eb3884A8F111F338b7784c163DD62d03DaF9"
},
"mailbox": "0x35231d4c2D8B8ADcB5617A638A0c4548684c7C70",
"interchainGasPaymaster": "0x6cA0B6D22da47f091B7613223cD4BB03a2d77918",
"defaultIsmInterchainGasPaymaster": "0x56f52c0A1ddcD557285f7CBc782D3d83096CE1Cc",
"multisigIsm": "0xf3b1F415740A26568C45b1c771A737E31C198F09",
"create2Factory": "0xc97D8e6f57b0d64971453dDc6EB8483fec9d163a",
@ -163,16 +99,8 @@
"storageGasOracle": "0x5E01d8F34b629E3f92d69546bbc4142A7Adee7e9",
"validatorAnnounce": "0x9bBdef63594D5FFc2f370Fe52115DdFFe97Bc524",
"proxyAdmin": "0x81a92A1a272cb09d7b4970b07548463dC7aE0cB7",
"mailbox": {
"kind": "Transparent",
"proxy": "0x35231d4c2D8B8ADcB5617A638A0c4548684c7C70",
"implementation": "0x8e1d6B03F7A823e9302c9042cd0d00728F456e70"
},
"interchainGasPaymaster": {
"kind": "Transparent",
"proxy": "0x6cA0B6D22da47f091B7613223cD4BB03a2d77918",
"implementation": "0xbdd8eb3884A8F111F338b7784c163DD62d03DaF9"
},
"mailbox": "0x35231d4c2D8B8ADcB5617A638A0c4548684c7C70",
"interchainGasPaymaster": "0x6cA0B6D22da47f091B7613223cD4BB03a2d77918",
"defaultIsmInterchainGasPaymaster": "0x56f52c0A1ddcD557285f7CBc782D3d83096CE1Cc",
"multisigIsm": "0xC343A7054838FE9F249D7E3Ec1Fa6f1D108694b8",
"create2Factory": "0xc97D8e6f57b0d64971453dDc6EB8483fec9d163a",

@ -3,16 +3,8 @@
"storageGasOracle": "0x4ed7c70F96B99c776995fB64377f0d4aB3B0e1C1",
"validatorAnnounce": "0x0165878A594ca255338adfa4d48449f69242Eb8F",
"proxyAdmin": "0x59b670e9fA9D0A427751Af201D676719a970857b",
"mailbox": {
"kind": "Transparent",
"proxy": "0x5FC8d32690cc91D4c39d9d3abcBD16989F875707",
"implementation": "0xDc64a140Aa3E981100a9becA4E685f962f0cF6C9"
},
"interchainGasPaymaster": {
"kind": "Transparent",
"proxy": "0xa85233C63b9Ee964Add6F2cffe00Fd84eb32338f",
"implementation": "0x322813Fd9A801c5507c9de605d63CEA4f2CE6c44"
},
"mailbox": "0x5FC8d32690cc91D4c39d9d3abcBD16989F875707",
"interchainGasPaymaster": "0xa85233C63b9Ee964Add6F2cffe00Fd84eb32338f",
"defaultIsmInterchainGasPaymaster": "0x7a2088a1bFc9d81c55368AE168C2C02570cB814F",
"multisigIsm": "0x5FbDB2315678afecb367f032d93F642f64180aa3"
},
@ -20,16 +12,8 @@
"storageGasOracle": "0xE6E340D132b5f46d1e472DebcD681B2aBc16e57E",
"validatorAnnounce": "0x0DCd1Bf9A1b36cE34237eEaFef220932846BCD82",
"proxyAdmin": "0x67d269191c92Caf3cD7723F116c85e6E9bf55933",
"mailbox": {
"kind": "Transparent",
"proxy": "0xA51c1fc2f0D1a1b8494Ed1FE312d7C3a78Ed91C0",
"implementation": "0xB7f8BC63BbcaD18155201308C8f3540b07f84F5e"
},
"interchainGasPaymaster": {
"kind": "Transparent",
"proxy": "0x84eA74d481Ee0A5332c457a4d796187F6Ba67fEB",
"implementation": "0xc3e53F4d16Ae77Db1c982e75a937B9f60FE63690"
},
"mailbox": "0xA51c1fc2f0D1a1b8494Ed1FE312d7C3a78Ed91C0",
"interchainGasPaymaster": "0x84eA74d481Ee0A5332c457a4d796187F6Ba67fEB",
"defaultIsmInterchainGasPaymaster": "0xa82fF9aFd8f496c3d6ac40E2a0F282E47488CFc9",
"multisigIsm": "0xa513E6E4b8f2a923D98304ec87F64353C4D5C853"
},
@ -37,16 +21,8 @@
"storageGasOracle": "0x95401dc811bb5740090279Ba06cfA8fcF6113778",
"validatorAnnounce": "0xc6e7DF5E7b4f2A278906862b61205850344D4e7d",
"proxyAdmin": "0xf5059a5D33d5853360D16C683c16e67980206f36",
"mailbox": {
"kind": "Transparent",
"proxy": "0x3Aa5ebB10DC797CAC828524e59A333d0A371443c",
"implementation": "0x68B1D87F95878fE05B998F19b66F4baba5De1aed"
},
"interchainGasPaymaster": {
"kind": "Transparent",
"proxy": "0x70e0bA845a1A0F2DA3359C97E0285013525FFC49",
"implementation": "0x998abeb3E57409262aE5b751f60747921B33613E"
},
"mailbox": "0x3Aa5ebB10DC797CAC828524e59A333d0A371443c",
"interchainGasPaymaster": "0x70e0bA845a1A0F2DA3359C97E0285013525FFC49",
"defaultIsmInterchainGasPaymaster": "0x99bbA657f2BbC93c02D617f8bA121cB8Fc104Acf",
"multisigIsm": "0x9A676e781A523b5d0C0e43731313A708CB607508"
}

@ -3,16 +3,8 @@
"storageGasOracle": "0x2E6a2Caa58a684f6200CEd24be31Eb6DAa154848",
"validatorAnnounce": "0x3Fc742696D5dc9846e04f7A1823D92cb51695f9a",
"proxyAdmin": "0x4e4D563e2cBFC35c4BC16003685443Fae2FA702f",
"mailbox": {
"kind": "Transparent",
"proxy": "0xCC737a94FecaeC165AbCf12dED095BB13F037685",
"implementation": "0x39b3cb005C4225B88A8b3a090563e2e763407222"
},
"interchainGasPaymaster": {
"kind": "Transparent",
"proxy": "0x8f9C3888bFC8a5B25AED115A82eCbb788b196d2a",
"implementation": "0x3DA23FD6844A712692F181C73f5cb606dd51BDe3"
},
"mailbox": "0xCC737a94FecaeC165AbCf12dED095BB13F037685",
"interchainGasPaymaster": "0x8f9C3888bFC8a5B25AED115A82eCbb788b196d2a",
"defaultIsmInterchainGasPaymaster": "0xF90cB82a76492614D07B82a7658917f3aC811Ac1",
"multisigIsm": "0x4D06A1671A2a345B14B15cbD50027979A5D1d8C9",
"create2Factory": "0xc97D8e6f57b0d64971453dDc6EB8483fec9d163a",
@ -24,16 +16,8 @@
"storageGasOracle": "0xd44E79A697136888f0d720Fb6703400a9204FD39",
"validatorAnnounce": "0x3Fc742696D5dc9846e04f7A1823D92cb51695f9a",
"proxyAdmin": "0x13474f85b808034C911B7697dee60B7d8d50ee36",
"mailbox": {
"kind": "Transparent",
"proxy": "0xCC737a94FecaeC165AbCf12dED095BB13F037685",
"implementation": "0x3388A1D46337631F3597d50e98930B52eb9E710E"
},
"interchainGasPaymaster": {
"kind": "Transparent",
"proxy": "0x8f9C3888bFC8a5B25AED115A82eCbb788b196d2a",
"implementation": "0x3DA23FD6844A712692F181C73f5cb606dd51BDe3"
},
"mailbox": "0xCC737a94FecaeC165AbCf12dED095BB13F037685",
"interchainGasPaymaster": "0x8f9C3888bFC8a5B25AED115A82eCbb788b196d2a",
"defaultIsmInterchainGasPaymaster": "0xF90cB82a76492614D07B82a7658917f3aC811Ac1",
"multisigIsm": "0xD713Db664509bd057aC2b378F4B65Db468F634A5",
"create2Factory": "0xc97D8e6f57b0d64971453dDc6EB8483fec9d163a",
@ -45,16 +29,8 @@
"storageGasOracle": "0x8970bdA0B0A01d1bA2656b510B2859560e75a7c5",
"validatorAnnounce": "0x3Fc742696D5dc9846e04f7A1823D92cb51695f9a",
"proxyAdmin": "0x96b49e136581f8dfF370aDB3015D48465572a318",
"mailbox": {
"kind": "Transparent",
"proxy": "0xCC737a94FecaeC165AbCf12dED095BB13F037685",
"implementation": "0x179c2Da65187C2614FbeD3Af8eB3098FEEb0a958"
},
"interchainGasPaymaster": {
"kind": "Transparent",
"proxy": "0x8f9C3888bFC8a5B25AED115A82eCbb788b196d2a",
"implementation": "0x3DA23FD6844A712692F181C73f5cb606dd51BDe3"
},
"mailbox": "0xCC737a94FecaeC165AbCf12dED095BB13F037685",
"interchainGasPaymaster": "0x8f9C3888bFC8a5B25AED115A82eCbb788b196d2a",
"defaultIsmInterchainGasPaymaster": "0xF90cB82a76492614D07B82a7658917f3aC811Ac1",
"multisigIsm": "0xd71f1A64659beC0781b2aa21bc7a72F7290F6Bf3",
"create2Factory": "0xc97D8e6f57b0d64971453dDc6EB8483fec9d163a",
@ -66,16 +42,8 @@
"storageGasOracle": "0x1a75f55e8f574CdB5abb1b2702b9caF2E5F7d4D6",
"validatorAnnounce": "0x3Fc742696D5dc9846e04f7A1823D92cb51695f9a",
"proxyAdmin": "0xfB149BC17dD3FE858fA64D678bA0c706DEac61eE",
"mailbox": {
"kind": "Transparent",
"proxy": "0xCC737a94FecaeC165AbCf12dED095BB13F037685",
"implementation": "0x87891AA323d0c98D9A1F417E9F02219EBc4274CC"
},
"interchainGasPaymaster": {
"kind": "Transparent",
"proxy": "0x8f9C3888bFC8a5B25AED115A82eCbb788b196d2a",
"implementation": "0x3DA23FD6844A712692F181C73f5cb606dd51BDe3"
},
"mailbox": "0xCC737a94FecaeC165AbCf12dED095BB13F037685",
"interchainGasPaymaster": "0x8f9C3888bFC8a5B25AED115A82eCbb788b196d2a",
"defaultIsmInterchainGasPaymaster": "0xF90cB82a76492614D07B82a7658917f3aC811Ac1",
"multisigIsm": "0x34add51924C500b4428067E251168807b3f5faED",
"create2Factory": "0xc97D8e6f57b0d64971453dDc6EB8483fec9d163a",
@ -87,16 +55,8 @@
"storageGasOracle": "0xce8E9D701A1DFfe672c1d8dB20De2B3fa6F4437D",
"validatorAnnounce": "0x3Fc742696D5dc9846e04f7A1823D92cb51695f9a",
"proxyAdmin": "0x8f919348F9C4619A196Acb5e377f49E5E2C0B569",
"mailbox": {
"kind": "Transparent",
"proxy": "0xCC737a94FecaeC165AbCf12dED095BB13F037685",
"implementation": "0x1ADF2D247E08348D18d77e69D5807a413b92Fe8E"
},
"interchainGasPaymaster": {
"kind": "Transparent",
"proxy": "0x8f9C3888bFC8a5B25AED115A82eCbb788b196d2a",
"implementation": "0x3DA23FD6844A712692F181C73f5cb606dd51BDe3"
},
"mailbox": "0xCC737a94FecaeC165AbCf12dED095BB13F037685",
"interchainGasPaymaster": "0x8f9C3888bFC8a5B25AED115A82eCbb788b196d2a",
"defaultIsmInterchainGasPaymaster": "0xF90cB82a76492614D07B82a7658917f3aC811Ac1",
"multisigIsm": "0x32B34F0D86b275b92e9289d9054Db5Ec32d2CC6C",
"create2Factory": "0xc97D8e6f57b0d64971453dDc6EB8483fec9d163a",
@ -108,16 +68,8 @@
"storageGasOracle": "0xAd754Dbc3F725259E49A90CAB347AeC343D432ed",
"validatorAnnounce": "0x3Fc742696D5dc9846e04f7A1823D92cb51695f9a",
"proxyAdmin": "0xEed449c54156163bf50CFf30408975AF43F43115",
"mailbox": {
"kind": "Transparent",
"proxy": "0xCC737a94FecaeC165AbCf12dED095BB13F037685",
"implementation": "0xC1081e289564fd20a4a93C00042692E168Fd0378"
},
"interchainGasPaymaster": {
"kind": "Transparent",
"proxy": "0x8f9C3888bFC8a5B25AED115A82eCbb788b196d2a",
"implementation": "0x3DA23FD6844A712692F181C73f5cb606dd51BDe3"
},
"mailbox": "0xCC737a94FecaeC165AbCf12dED095BB13F037685",
"interchainGasPaymaster": "0x8f9C3888bFC8a5B25AED115A82eCbb788b196d2a",
"defaultIsmInterchainGasPaymaster": "0xF90cB82a76492614D07B82a7658917f3aC811Ac1",
"multisigIsm": "0xec8875C7cE0a814A56654618D366641859F32C7A",
"create2Factory": "0xc97D8e6f57b0d64971453dDc6EB8483fec9d163a",
@ -129,16 +81,8 @@
"storageGasOracle": "0xdE72697715aAeC4CaBbD638C0Aba64488005C64b",
"validatorAnnounce": "0x3Fc742696D5dc9846e04f7A1823D92cb51695f9a",
"proxyAdmin": "0xcD19Ff7306E04EA6b8f4B5Ab1c5A198c186aaB42",
"mailbox": {
"kind": "Transparent",
"proxy": "0xCC737a94FecaeC165AbCf12dED095BB13F037685",
"implementation": "0x2D076fE2370950044572cB168924B8AffDA26689"
},
"interchainGasPaymaster": {
"kind": "Transparent",
"proxy": "0x8f9C3888bFC8a5B25AED115A82eCbb788b196d2a",
"implementation": "0x3DA23FD6844A712692F181C73f5cb606dd51BDe3"
},
"mailbox": "0xCC737a94FecaeC165AbCf12dED095BB13F037685",
"interchainGasPaymaster": "0x8f9C3888bFC8a5B25AED115A82eCbb788b196d2a",
"defaultIsmInterchainGasPaymaster": "0xF90cB82a76492614D07B82a7658917f3aC811Ac1",
"multisigIsm": "0x47384E33E67007B7fE4326fb096Bdf9CbA7AB6E4",
"create2Factory": "0xc97D8e6f57b0d64971453dDc6EB8483fec9d163a",
@ -150,16 +94,8 @@
"storageGasOracle": "0xfFAEF09B3cd11D9b20d1a19bECca54EEC2884766",
"validatorAnnounce": "0x3Fc742696D5dc9846e04f7A1823D92cb51695f9a",
"proxyAdmin": "0xcD19Ff7306E04EA6b8f4B5Ab1c5A198c186aaB42",
"mailbox": {
"kind": "Transparent",
"proxy": "0xCC737a94FecaeC165AbCf12dED095BB13F037685",
"implementation": "0x0840f126eD0302B37d7476A303340a92B9eC0c5b"
},
"interchainGasPaymaster": {
"kind": "Transparent",
"proxy": "0x8f9C3888bFC8a5B25AED115A82eCbb788b196d2a",
"implementation": "0x3DA23FD6844A712692F181C73f5cb606dd51BDe3"
},
"mailbox": "0xCC737a94FecaeC165AbCf12dED095BB13F037685",
"interchainGasPaymaster": "0x8f9C3888bFC8a5B25AED115A82eCbb788b196d2a",
"defaultIsmInterchainGasPaymaster": "0xF90cB82a76492614D07B82a7658917f3aC811Ac1",
"multisigIsm": "0x47384E33E67007B7fE4326fb096Bdf9CbA7AB6E4",
"create2Factory": "0xc97D8e6f57b0d64971453dDc6EB8483fec9d163a",
@ -171,16 +107,8 @@
"storageGasOracle": "0x1D5EbC3e15e9ECDe0e3530C85899556797eeaea5",
"validatorAnnounce": "0x3Fc742696D5dc9846e04f7A1823D92cb51695f9a",
"proxyAdmin": "0x7FE7EA170cf08A25C2ff315814D96D93C311E692",
"mailbox": {
"kind": "Transparent",
"proxy": "0xCC737a94FecaeC165AbCf12dED095BB13F037685",
"implementation": "0x67b4359c407359d260dD04E622af04E7450DD43b"
},
"interchainGasPaymaster": {
"kind": "Transparent",
"proxy": "0x8f9C3888bFC8a5B25AED115A82eCbb788b196d2a",
"implementation": "0xD28d890780A33ec5155f9972ce260c1b611C788b"
},
"mailbox": "0xCC737a94FecaeC165AbCf12dED095BB13F037685",
"interchainGasPaymaster": "0x8f9C3888bFC8a5B25AED115A82eCbb788b196d2a",
"defaultIsmInterchainGasPaymaster": "0xF987d7edcb5890cB321437d8145E3D51131298b6",
"multisigIsm": "0xD3d062a5dcBA85ae863618d4c264d2358300c283",
"testRecipient": "0xBC3cFeca7Df5A45d61BC60E7898E63670e1654aE",

@ -3,46 +3,44 @@ import { ethers } from 'ethers';
import type { types } from '@hyperlane-xyz/utils';
import { MultiProvider } from './providers/MultiProvider';
import { ProxiedContract, ProxyAddresses, isProxyAddresses } from './proxy';
import { ChainMap, Connection } from './types';
import { isObject, objMap } from './utils/objects';
import { objFilter, objMap, pick } from './utils/objects';
export type HyperlaneFactories = {
[key: string]: ethers.ContractFactory;
};
export type HyperlaneContract =
| ethers.Contract
| ProxiedContract<any, any>
| HyperlaneContracts;
export type HyperlaneContracts = {
[key: Exclude<string, 'address'>]: HyperlaneContract;
export type HyperlaneContracts<Factories extends HyperlaneFactories> = {
[Property in keyof Factories]: Awaited<
ReturnType<Factories[Property]['deploy']>
>;
};
export type HyperlaneAddresses = {
[key: string]: types.Address | ProxyAddresses<any> | HyperlaneAddresses;
export type HyperlaneContractsMap<Factories extends HyperlaneFactories> =
ChainMap<HyperlaneContracts<Factories>>;
export type HyperlaneAddresses<Factories extends HyperlaneFactories> = {
[Property in keyof Factories]: types.Address;
};
export function serializeContracts(
contractOrObject: HyperlaneContracts,
max_depth = 5,
): HyperlaneAddresses {
if (max_depth === 0) {
throw new Error('serializeContracts tried to go too deep');
}
export type HyperlaneAddressesMap<Factories extends HyperlaneFactories> =
ChainMap<HyperlaneAddresses<Factories>>;
export function serializeContractsMap<F extends HyperlaneFactories>(
contractsMap: HyperlaneContractsMap<F>,
): HyperlaneAddressesMap<F> {
return objMap(contractsMap, (_, contracts) => {
return serializeContracts(contracts);
});
}
export function serializeContracts<F extends HyperlaneFactories>(
contracts: HyperlaneContracts<F>,
): HyperlaneAddresses<F> {
return objMap(
contractOrObject,
(_, contract: any): string | ProxyAddresses<any> | HyperlaneAddresses => {
if (contract instanceof ProxiedContract) {
return contract.addresses;
} else if (contract.address) {
return contract.address;
} else {
return serializeContracts(contract, max_depth - 1);
}
},
);
contracts,
(_, contract) => contract.address,
) as HyperlaneAddresses<F>;
}
function getFactory(
@ -55,88 +53,61 @@ function getFactory(
return factories[key];
}
function isAddress(addressOrObject: any) {
return (
isProxyAddresses(addressOrObject) || typeof addressOrObject === 'string'
);
export function filterAddresses(
addresses: HyperlaneAddresses<any>,
factories: HyperlaneFactories,
): HyperlaneAddresses<any> {
return pick(addresses, Object.keys(factories));
}
export function filterAddresses(
addressOrObject: HyperlaneAddresses,
contractNames: string[],
max_depth = 5,
): HyperlaneAddresses {
if (max_depth === 0) {
throw new Error('filterAddresses tried to go too deep');
}
const ret: HyperlaneAddresses = {};
for (const key of Object.keys(addressOrObject)) {
if (isAddress(addressOrObject[key]) && contractNames.includes(key)) {
ret[key] = addressOrObject[key];
} else if (isObject(addressOrObject[key])) {
const obj = filterAddresses(
addressOrObject[key] as HyperlaneAddresses,
contractNames,
max_depth - 1,
export function filterAddressesMap<F extends HyperlaneFactories>(
addressesMap: HyperlaneAddressesMap<any>,
factories: F,
): HyperlaneAddressesMap<F> {
const filteredAddressesMap = objMap(addressesMap, (_, addresses) =>
filterAddresses(addresses, factories),
);
return objFilter(
filteredAddressesMap,
(_, addresses): addresses is HyperlaneAddresses<F> => {
return Object.keys(factories).every((contract) =>
Object.keys(addresses).includes(contract),
);
if (Object.keys(obj).length > 0) {
ret[key] = obj;
}
}
}
return ret;
},
);
}
export function buildContracts(
addressOrObject: HyperlaneAddresses,
factories: HyperlaneFactories,
filter = true,
max_depth = 5,
): HyperlaneContracts {
if (max_depth === 0) {
throw new Error('buildContracts tried to go too deep');
}
if (filter) {
addressOrObject = filterAddresses(addressOrObject, Object.keys(factories));
}
return objMap(addressOrObject, (key, address: any) => {
if (isProxyAddresses(address)) {
const contract = getFactory(key, factories).attach(address.proxy);
return new ProxiedContract(contract, address);
} else if (typeof address === 'string') {
return getFactory(key, factories).attach(address);
} else {
return buildContracts(
address as HyperlaneAddresses,
factories,
false,
max_depth - 1,
);
}
});
export function attachContracts<F extends HyperlaneFactories>(
addresses: HyperlaneAddresses<F>,
factories: F,
): HyperlaneContracts<F> {
return objMap(addresses, (key, address: types.Address) => {
return getFactory(key, factories).attach(address);
}) as HyperlaneContracts<F>;
}
export function attachContractsMap<F extends HyperlaneFactories>(
addressesMap: HyperlaneAddressesMap<F>,
factories: F,
): HyperlaneContractsMap<F> {
return objMap(addressesMap, (chain, addresses) =>
attachContracts(addresses, factories),
);
}
export function connectContracts<Contracts extends HyperlaneContracts>(
contractOrObject: Contracts,
export function connectContracts<F extends HyperlaneFactories>(
contracts: HyperlaneContracts<F>,
connection: Connection,
max_depth = 5,
): Contracts {
if (max_depth === 0) {
throw new Error('connectContracts tried to go too deep');
}
return objMap(contractOrObject, (_, contract: any) => {
if (contract.connect) {
return contract.connect(connection);
} else {
return connectContracts(contract, connection, max_depth - 1);
}
}) as Contracts;
): HyperlaneContracts<F> {
return objMap(contracts, (_, contract) =>
contract.connect(connection),
) as HyperlaneContracts<F>;
}
export function connectContractsMap<Contracts extends HyperlaneContracts>(
contractsMap: ChainMap<Contracts>,
export function connectContractsMap<F extends HyperlaneFactories>(
contractsMap: ChainMap<HyperlaneContracts<F>>,
multiProvider: MultiProvider,
): ChainMap<Contracts> {
): ChainMap<HyperlaneContracts<F>> {
return objMap(contractsMap, (chain, contracts) =>
connectContracts(contracts, multiProvider.getSignerOrProvider(chain)),
);

@ -8,13 +8,10 @@ import {
HyperlaneEnvironment,
hyperlaneEnvironments,
} from '../consts/environments';
import { HyperlaneAddresses } from '../contracts';
import { MultiProvider } from '../providers/MultiProvider';
import { ChainMap, ChainName } from '../types';
import { ChainName } from '../types';
import { CoreContracts, coreFactories } from './contracts';
export type CoreContractsMap = ChainMap<CoreContracts>;
import { CoreFactories, coreFactories } from './contracts';
export type DispatchedMessage = {
id: string;
@ -22,24 +19,7 @@ export type DispatchedMessage = {
parsed: types.ParsedMessage;
};
export class HyperlaneCore extends HyperlaneApp<CoreContracts> {
constructor(contractsMap: CoreContractsMap, multiProvider: MultiProvider) {
super(contractsMap, multiProvider);
}
static fromAddresses(
addresses: ChainMap<HyperlaneAddresses>,
multiProvider: MultiProvider,
): HyperlaneCore {
const { contracts, intersectionProvider } =
this.buildContracts<CoreContracts>(
addresses,
coreFactories,
multiProvider,
);
return new HyperlaneCore(contracts, intersectionProvider);
}
export class HyperlaneCore extends HyperlaneApp<CoreFactories> {
static fromEnvironment<Env extends HyperlaneEnvironment>(
env: Env,
multiProvider: MultiProvider,
@ -48,11 +28,15 @@ export class HyperlaneCore extends HyperlaneApp<CoreContracts> {
if (!envAddresses) {
throw new Error(`No addresses found for ${env}`);
}
return HyperlaneCore.fromAddresses(envAddresses, multiProvider);
}
getContracts(chain: ChainName): CoreContracts {
return super.getContracts(chain);
const fromAddressesMap = HyperlaneApp.fromAddressesMap(
envAddresses,
coreFactories,
multiProvider,
);
return new HyperlaneCore(
fromAddressesMap.contractsMap,
fromAddressesMap.multiProvider,
);
}
protected getDestination(message: DispatchedMessage): {
@ -62,7 +46,7 @@ export class HyperlaneCore extends HyperlaneApp<CoreContracts> {
const destinationChain = this.multiProvider.getChainName(
message.parsed.destination,
);
const mailbox = this.getContracts(destinationChain).mailbox.contract;
const mailbox = this.getContracts(destinationChain).mailbox;
return { destinationChain, mailbox };
}

@ -4,6 +4,7 @@ import { utils } from '@hyperlane-xyz/utils';
import { BytecodeHash } from '../consts/bytecode';
import { HyperlaneAppChecker } from '../deploy/HyperlaneAppChecker';
import { proxyImplementation } from '../deploy/proxy';
import { ChainName } from '../types';
import { HyperlaneCore } from './HyperlaneCore';
@ -46,7 +47,7 @@ export class HyperlaneCoreChecker extends HyperlaneAppChecker<
async checkMailbox(chain: ChainName): Promise<void> {
const contracts = this.app.getContracts(chain);
const mailbox = contracts.mailbox.contract;
const mailbox = contracts.mailbox;
const localDomain = await mailbox.localDomain();
utils.assert(localDomain === this.multiProvider.getDomainId(chain));
@ -67,13 +68,17 @@ export class HyperlaneCoreChecker extends HyperlaneAppChecker<
async checkBytecodes(chain: ChainName): Promise<void> {
const contracts = this.app.getContracts(chain);
const mailbox = contracts.mailbox.contract;
const mailbox = contracts.mailbox;
const localDomain = await mailbox.localDomain();
const implementation = await proxyImplementation(
this.multiProvider.getProvider(chain),
mailbox.address,
);
await this.checkBytecode(
chain,
'Mailbox implementation',
contracts.mailbox.addresses.implementation,
implementation,
[
BytecodeHash.MAILBOX_WITHOUT_LOCAL_DOMAIN_BYTE_CODE_HASH,
BytecodeHash.MAILBOX_WITHOUT_LOCAL_DOMAIN_NONZERO_PAUSE_BYTE_CODE_HASH,

@ -9,19 +9,18 @@ import {
} from '@hyperlane-xyz/core';
import { types } from '@hyperlane-xyz/utils';
import { HyperlaneContracts } from '../contracts';
import { DeployOptions, HyperlaneDeployer } from '../deploy/HyperlaneDeployer';
import { MultiProvider } from '../providers/MultiProvider';
import { ProxiedContract, TransparentProxyAddresses } from '../proxy';
import { ChainMap, ChainName } from '../types';
import { objMap } from '../utils/objects';
import { CoreContracts, coreFactories } from './contracts';
import { CoreFactories, coreFactories } from './contracts';
import { CoreConfig } from './types';
export class HyperlaneCoreDeployer extends HyperlaneDeployer<
CoreConfig,
CoreContracts,
typeof coreFactories
CoreFactories
> {
startingBlockNumbers: ChainMap<number | undefined>;
@ -41,7 +40,7 @@ export class HyperlaneCoreDeployer extends HyperlaneDeployer<
defaultIsmAddress: types.Address,
proxyAdmin: types.Address,
deployOpts?: DeployOptions,
): Promise<ProxiedContract<Mailbox, TransparentProxyAddresses>> {
): Promise<Mailbox> {
const domain = this.multiProvider.getDomainId(chain);
const owner = this.configMap[chain].owner;
@ -139,7 +138,7 @@ export class HyperlaneCoreDeployer extends HyperlaneDeployer<
async deployContracts(
chain: ChainName,
config: CoreConfig,
): Promise<CoreContracts> {
): Promise<HyperlaneContracts<CoreFactories>> {
if (config.remove) {
// skip deploying to chains configured to be removed
return undefined as any;

@ -1,27 +1,24 @@
import { ethers } from 'ethers';
import { TestMailbox } from '@hyperlane-xyz/core';
import { TestMailbox, TestMailbox__factory } from '@hyperlane-xyz/core';
import { utils } from '@hyperlane-xyz/utils';
import { ProxiedContract } from '../proxy';
import { HyperlaneContracts } from '../contracts';
import { ChainName } from '../types';
import { HyperlaneCore } from './HyperlaneCore';
import { CoreContracts } from './contracts';
import { coreFactories } from './contracts';
type MockProxyAddresses = {
kind: 'MOCK';
proxy: string;
implementation: string;
};
export type TestCoreContracts = CoreContracts & {
mailbox: ProxiedContract<TestMailbox, MockProxyAddresses>;
export const testCoreFactories = {
...coreFactories,
mailbox: new TestMailbox__factory(),
};
export class TestCoreApp extends HyperlaneCore {
getContracts(chain: ChainName): TestCoreContracts {
return super.getContracts(chain) as TestCoreContracts;
getContracts(chain: ChainName): HyperlaneContracts<typeof testCoreFactories> {
return super.getContracts(chain) as HyperlaneContracts<
typeof testCoreFactories
>;
}
async processMessages(): Promise<
@ -44,7 +41,7 @@ export class TestCoreApp extends HyperlaneCore {
): Promise<Map<ChainName, ethers.providers.TransactionResponse[]>> {
const responses = new Map<ChainName, any>();
const contracts = this.getContracts(origin);
const outbox: TestMailbox = contracts.mailbox.contract;
const outbox = contracts.mailbox as TestMailbox;
const dispatchFilter = outbox.filters.Dispatch();
const dispatches = await outbox.queryFilter(dispatchFilter);
@ -54,7 +51,7 @@ export class TestCoreApp extends HyperlaneCore {
throw new Error('Dispatched message to local domain');
}
const destinationChain = this.multiProvider.getChainName(destination);
const inbox = this.getContracts(destinationChain).mailbox.contract;
const inbox = this.getContracts(destinationChain).mailbox;
const id = utils.messageId(dispatch.args.message);
const delivered = await inbox.delivered(id);
if (!delivered) {

@ -1,40 +1,15 @@
import {
Create2Factory__factory,
InterchainAccountRouter__factory,
InterchainQueryRouter__factory,
LegacyMultisigIsm,
LegacyMultisigIsm__factory,
Mailbox,
Mailbox__factory,
ProxyAdmin,
ProxyAdmin__factory,
ValidatorAnnounce,
ValidatorAnnounce__factory,
} from '@hyperlane-xyz/core';
import { types } from '@hyperlane-xyz/utils';
import { ProxiedContract, TransparentProxyAddresses } from '../proxy';
export type CoreAddresses = {
mailbox: types.Address | TransparentProxyAddresses;
multisigIsm: types.Address;
proxyAdmin: types.Address;
validatorAnnounce: types.Address;
};
export type CoreContracts = {
mailbox: ProxiedContract<Mailbox, TransparentProxyAddresses>;
multisigIsm: LegacyMultisigIsm;
proxyAdmin: ProxyAdmin;
validatorAnnounce: ValidatorAnnounce;
};
export const coreFactories = {
interchainAccountRouter: new InterchainAccountRouter__factory(),
interchainQueryRouter: new InterchainQueryRouter__factory(),
validatorAnnounce: new ValidatorAnnounce__factory(),
create2Factory: new Create2Factory__factory(),
proxyAdmin: new ProxyAdmin__factory(),
multisigIsm: new LegacyMultisigIsm__factory(),
mailbox: new Mailbox__factory(),
};
export type CoreFactories = typeof coreFactories;

@ -31,7 +31,7 @@ describe('TestCoreDeployer', async () => {
testCoreApp = await deployer.deployApp();
const recipient = await new TestRecipient__factory(signer).deploy();
localMailbox = testCoreApp.getContracts(localChain).mailbox.contract;
localMailbox = testCoreApp.getContracts(localChain).mailbox;
const dispatchResponse = localMailbox.dispatch(
multiProvider.getDomainId(remoteChain),
@ -43,7 +43,7 @@ describe('TestCoreDeployer', async () => {
localChain,
dispatchResponse,
);
remoteMailbox = testCoreApp.getContracts(remoteChain).mailbox.contract;
remoteMailbox = testCoreApp.getContracts(remoteChain).mailbox;
await expect(
remoteMailbox.dispatch(
multiProvider.getDomainId(localChain),

@ -1,16 +1,15 @@
import { Contract } from 'ethers';
import { keccak256 } from 'ethers/lib/utils';
import { Ownable } from '@hyperlane-xyz/core';
import type { types } from '@hyperlane-xyz/utils';
import { utils } from '@hyperlane-xyz/utils';
import { HyperlaneApp } from '../HyperlaneApp';
import { MultiProvider } from '../providers/MultiProvider';
import { ProxiedContract, isProxiedContract } from '../proxy';
import { ChainMap, ChainName } from '../types';
import { objMap, promiseObjAll } from '../utils/objects';
import { proxyAdmin } from './proxy';
import { isProxy, proxyAdmin } from './proxy';
import {
BytecodeMismatchViolation,
CheckerViolation,
@ -70,25 +69,22 @@ export abstract class HyperlaneAppChecker<
);
}
const provider = this.multiProvider.getProvider(chain);
const isProxied = (
_: string,
contract: any,
): contract is ProxiedContract<any, any> => {
return isProxiedContract(contract);
};
const proxied = this.app.getFlattenedFilteredContracts(chain, isProxied);
const contracts = this.app.getContracts(chain);
await promiseObjAll(
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);
objMap(contracts, async (name, contract) => {
if (await isProxy(provider, contract.address)) {
// 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);
}
}
}),
);
@ -126,28 +122,30 @@ export abstract class HyperlaneAppChecker<
// TODO: Require owner in config if ownables is non-empty
async checkOwnership(chain: ChainName, owner: types.Address): Promise<void> {
const isOwnable = (_: string, contract: any): contract is Ownable => {
return (
contract !== null &&
typeof contract === 'object' &&
contract.owner &&
contract.transferOwnership
);
const isOwnable = async (contract: Contract): Promise<boolean> => {
try {
await contract.owner();
return true;
} catch (_) {
return false;
}
};
const ownables = this.app.getFlattenedFilteredContracts(chain, isOwnable);
const contracts = this.app.getContracts(chain);
await promiseObjAll(
objMap(ownables, async (name, contract) => {
const actual = await contract.owner();
if (!utils.eqAddress(actual, owner)) {
const violation: OwnerViolation = {
chain,
name,
type: ViolationType.Owner,
actual,
expected: owner,
contract,
};
this.addViolation(violation);
objMap(contracts, async (name, contract) => {
if (await isOwnable(contract)) {
const actual = await contract.owner();
if (!utils.eqAddress(actual, owner)) {
const violation: OwnerViolation = {
chain,
name,
type: ViolationType.Owner,
actual,
expected: owner,
contract,
};
this.addViolation(violation);
}
}
}),
);

@ -1,5 +1,5 @@
import { Debugger, debug } from 'debug';
import { ethers } from 'ethers';
import { Contract, ethers } from 'ethers';
import {
Create2Factory__factory,
@ -13,22 +13,18 @@ import {
import { types, utils } from '@hyperlane-xyz/utils';
import {
HyperlaneContract,
HyperlaneContracts,
HyperlaneContractsMap,
HyperlaneFactories,
connectContractsMap,
serializeContracts,
} from '../contracts';
import { MultiProvider } from '../providers/MultiProvider';
import {
ProxiedContract,
ProxyKind,
TransparentProxyAddresses,
} from '../proxy';
import { ConnectionClientConfig } from '../router/types';
import { ChainMap, ChainName } from '../types';
import { objMap } from '../utils/objects';
import { proxyAdmin } from './proxy';
import { ContractVerificationInput } from './verify/types';
import {
buildVerificationInput,
@ -49,10 +45,9 @@ export const CREATE2FACTORY_ADDRESS =
export abstract class HyperlaneDeployer<
Config,
Contracts extends HyperlaneContracts,
Factories extends HyperlaneFactories,
> {
public deployedContracts: ChainMap<Contracts> = {};
public deployedContracts: HyperlaneContractsMap<Factories> = {};
public verificationInputs: ChainMap<ContractVerificationInput[]>;
protected logger: Debugger;
@ -66,7 +61,7 @@ export abstract class HyperlaneDeployer<
this.logger = options?.logger || debug('hyperlane:AppDeployer');
}
cacheContracts(partialDeployment: ChainMap<Contracts>): void {
cacheContracts(partialDeployment: HyperlaneContractsMap<Factories>): void {
this.deployedContracts = connectContractsMap(
partialDeployment,
this.multiProvider,
@ -76,11 +71,11 @@ export abstract class HyperlaneDeployer<
abstract deployContracts(
chain: ChainName,
config: Config,
): Promise<Contracts>;
): Promise<HyperlaneContracts<Factories>>;
async deploy(
partialDeployment?: ChainMap<Contracts>,
): Promise<ChainMap<Contracts>> {
partialDeployment?: HyperlaneContractsMap<Factories>,
): Promise<HyperlaneContractsMap<Factories>> {
if (partialDeployment) {
this.cacheContracts(partialDeployment);
}
@ -104,9 +99,7 @@ export abstract class HyperlaneDeployer<
// TODO: remove these logs once we have better timeouts
this.logger(
JSON.stringify(
serializeContracts(
(this.deployedContracts[chain] as Contracts) ?? {},
),
serializeContracts(this.deployedContracts[chain] ?? {}),
null,
2,
),
@ -139,11 +132,14 @@ export abstract class HyperlaneDeployer<
protected async runIfAdmin<T>(
chain: ChainName,
proxy: TransparentUpgradeableProxy,
proxy: Contract,
signerAdminFn: () => Promise<T>,
proxyAdminOwnerFn: (proxyAdmin: ProxyAdmin) => Promise<T>,
): Promise<T | undefined> {
const admin = await proxy.callStatic.admin();
const admin = await proxyAdmin(
this.multiProvider.getProvider(chain),
proxy.address,
);
const code = await this.multiProvider.getProvider(chain).getCode(admin);
// if admin is a ProxyAdmin, run the proxyAdminOwnerFn (if deployer is owner)
if (code !== '0x') {
@ -214,7 +210,7 @@ export abstract class HyperlaneDeployer<
deployOpts?: DeployOptions,
): Promise<ReturnType<F['deploy']>> {
const cachedContract = this.deployedContracts[chain]?.[contractName];
if (cachedContract && !(cachedContract instanceof ProxiedContract)) {
if (cachedContract) {
this.logger(
`Recovered ${contractName} on ${chain} ${cachedContract.address}`,
);
@ -308,14 +304,14 @@ export abstract class HyperlaneDeployer<
contractName: K,
args: Parameters<Factories[K]['deploy']>,
deployOpts?: DeployOptions,
): Promise<ReturnType<Factories[K]['deploy']>> {
const contract = await this.deployContractFromFactory(
): Promise<HyperlaneContracts<Factories>[K]> {
const contract = (await this.deployContractFromFactory(
chain,
this.factories[contractName],
contractName.toString(),
args,
deployOpts,
);
)) as HyperlaneContracts<Factories>[K];
this.cacheContract(chain, contractName, contract);
return contract;
}
@ -378,7 +374,7 @@ export abstract class HyperlaneDeployer<
initArgs: Parameters<C['initialize']>,
proxyAdmin: string,
deployOpts?: DeployOptions,
): Promise<ProxiedContract<C, TransparentProxyAddresses>> {
): Promise<C> {
const initData = implementation.interface.encodeFunctionData(
'initialize',
initArgs,
@ -438,25 +434,17 @@ export abstract class HyperlaneDeployer<
);
}
return new ProxiedContract<C, TransparentProxyAddresses>(
implementation.attach(proxy.address) as C,
{
kind: ProxyKind.Transparent,
proxy: proxy.address,
implementation: implementation.address,
},
);
return implementation.attach(proxy.address) as C;
}
private cacheContract<K extends keyof Factories>(
chain: ChainName,
contractName: K,
contract: HyperlaneContract,
contract: HyperlaneContracts<Factories>[K],
) {
if (!this.deployedContracts[chain]) {
this.deployedContracts[chain] = {} as Contracts;
this.deployedContracts[chain] = {} as HyperlaneContracts<Factories>;
}
// @ts-ignore
this.deployedContracts[chain][contractName] = contract;
}
@ -464,29 +452,22 @@ export abstract class HyperlaneDeployer<
* Deploys the Implementation and Proxy for a given contract
*
*/
async deployProxiedContract<
K extends keyof Factories,
C extends Awaited<ReturnType<Factories[K]['deploy']>>,
>(
async deployProxiedContract<K extends keyof Factories>(
chain: ChainName,
contractName: K,
constructorArgs: Parameters<Factories[K]['deploy']>,
initArgs: Parameters<C['initialize']>,
initArgs: Parameters<HyperlaneContracts<Factories>[K]['initialize']>,
proxyAdmin: string,
deployOpts?: DeployOptions,
): Promise<ProxiedContract<C, TransparentProxyAddresses>> {
const cachedProxy = this.deployedContracts[chain]?.[contractName as any];
if (
cachedProxy &&
cachedProxy.addresses.proxy &&
cachedProxy.addresses.implementation
) {
): Promise<HyperlaneContracts<Factories>[K]> {
const cachedProxy = this.deployedContracts[chain]?.[contractName];
if (cachedProxy) {
this.logger(
`Recovered ${contractName.toString()} on ${chain} proxy=${
cachedProxy.addresses.proxy
} implementation=${cachedProxy.addresses.implementation}`,
`Recovered ${contractName as string} on ${chain} ${
cachedProxy.address
}`,
);
return cachedProxy as ProxiedContract<C, TransparentProxyAddresses>;
return cachedProxy;
}
const implementation = await this.deployContract<K>(
@ -495,25 +476,10 @@ export abstract class HyperlaneDeployer<
constructorArgs,
deployOpts,
);
// If the proxy already existed in artifacts but the implementation did not,
// we only deploy the implementation and keep the proxy.
// Changing the proxy's implementation address on-chain is left to
// the govern / checker script
if (cachedProxy && cachedProxy.addresses.proxy) {
this.logger(
`Recovered ${contractName.toString()} on ${chain} proxy=${
cachedProxy.addresses.proxy
}`,
);
cachedProxy.addresses.implementation = implementation.address;
this.cacheContract(chain, contractName, cachedProxy);
return cachedProxy as ProxiedContract<C, TransparentProxyAddresses>;
}
const contract = await this.deployProxy(
chain,
implementation as C,
implementation,
initArgs,
proxyAdmin,
deployOpts,

@ -1,21 +1,7 @@
import { ethers } from 'ethers';
import type { types } from '@hyperlane-xyz/utils';
import { TransparentProxyAddresses } from '../proxy';
import { ChainName } from '../types';
import { CheckerViolation } from './types';
export interface ProxyViolation extends CheckerViolation {
type: TransparentProxyAddresses['kind'];
data: {
proxyAddresses: TransparentProxyAddresses;
name: string;
};
actual: string;
expected: string;
}
import { eqAddress } from '@hyperlane-xyz/utils/dist/src/utils';
export async function proxyImplementation(
provider: ethers.providers.Provider,
@ -41,20 +27,10 @@ export async function proxyAdmin(
return ethers.utils.getAddress(storageValue.slice(26));
}
export function proxyViolation<Chain extends ChainName>(
chain: Chain,
name: string,
proxyAddresses: TransparentProxyAddresses,
actual: types.Address,
): ProxyViolation {
return {
chain,
type: proxyAddresses.kind,
actual,
expected: proxyAddresses.implementation,
data: {
name,
proxyAddresses,
},
};
export async function isProxy(
provider: ethers.providers.Provider,
proxy: types.Address,
): Promise<boolean> {
const admin = await proxyAdmin(provider, proxy);
return !eqAddress(admin, ethers.constants.AddressZero);
}

@ -8,28 +8,12 @@ import {
HyperlaneEnvironment,
hyperlaneEnvironments,
} from '../consts/environments';
import { HyperlaneAddresses } from '../contracts';
import { MultiProvider } from '../providers/MultiProvider';
import { ChainMap, ChainName } from '../types';
import { ChainName } from '../types';
import { IgpContracts, igpFactories } from './contracts';
export type IgpContractsMap = ChainMap<IgpContracts>;
export class HyperlaneIgp extends HyperlaneApp<IgpContracts> {
constructor(contractsMap: IgpContractsMap, multiProvider: MultiProvider) {
super(contractsMap, multiProvider);
}
static fromAddresses(
addresses: ChainMap<HyperlaneAddresses>,
multiProvider: MultiProvider,
): HyperlaneIgp {
const { contracts, intersectionProvider } =
this.buildContracts<IgpContracts>(addresses, igpFactories, multiProvider);
return new HyperlaneIgp(contracts, intersectionProvider);
}
import { IgpFactories, igpFactories } from './contracts';
export class HyperlaneIgp extends HyperlaneApp<IgpFactories> {
static fromEnvironment<Env extends HyperlaneEnvironment>(
env: Env,
multiProvider: MultiProvider,
@ -38,11 +22,15 @@ export class HyperlaneIgp extends HyperlaneApp<IgpContracts> {
if (!envAddresses) {
throw new Error(`No addresses found for ${env}`);
}
return HyperlaneIgp.fromAddresses(envAddresses, multiProvider);
}
getContracts(chain: ChainName): IgpContracts {
return super.getContracts(chain);
const fromAddressesMap = this.fromAddressesMap(
envAddresses,
igpFactories,
multiProvider,
);
return new HyperlaneIgp(
fromAddressesMap.contractsMap,
fromAddressesMap.multiProvider,
);
}
/**

@ -4,6 +4,7 @@ import { types, utils } from '@hyperlane-xyz/utils';
import { BytecodeHash } from '../consts/bytecode';
import { HyperlaneAppChecker } from '../deploy/HyperlaneAppChecker';
import { proxyImplementation } from '../deploy/proxy';
import { ChainName } from '../types';
import { HyperlaneIgp } from './HyperlaneIgp';
@ -43,10 +44,14 @@ export class HyperlaneIgpChecker extends HyperlaneAppChecker<
contracts.interchainGasPaymaster.address,
[BytecodeHash.TRANSPARENT_PROXY_BYTECODE_HASH],
);
const implementation = await proxyImplementation(
this.multiProvider.getProvider(chain),
contracts.interchainGasPaymaster.address,
);
await this.checkBytecode(
chain,
'InterchainGasPaymaster implementation',
contracts.interchainGasPaymaster.addresses.implementation,
implementation,
[
BytecodeHash.INTERCHAIN_GAS_PAYMASTER_BYTECODE_HASH,
BytecodeHash.OWNER_INITIALIZABLE_INTERCHAIN_GAS_PAYMASTER_BYTECODE_HASH,
@ -62,10 +67,7 @@ export class HyperlaneIgpChecker extends HyperlaneAppChecker<
// Remove the address of the wrapped IGP from the bytecode
bytecode.replaceAll(
ethersUtils.defaultAbiCoder
.encode(
['address'],
[contracts.interchainGasPaymaster.addresses.proxy],
)
.encode(['address'], [contracts.interchainGasPaymaster.address])
.slice(2),
'',
),
@ -112,7 +114,7 @@ export class HyperlaneIgpChecker extends HyperlaneAppChecker<
async checkInterchainGasPaymaster(local: ChainName): Promise<void> {
const coreContracts = this.app.getContracts(local);
const igp = coreContracts.interchainGasPaymaster.contract;
const igp = coreContracts.interchainGasPaymaster;
// Construct the violation, updating the actual & expected
// objects as violations are found.

@ -10,19 +10,18 @@ import {
} from '@hyperlane-xyz/core';
import { types, utils } from '@hyperlane-xyz/utils';
import { HyperlaneContracts } from '../contracts';
import { DeployOptions, HyperlaneDeployer } from '../deploy/HyperlaneDeployer';
import { MultiProvider } from '../providers/MultiProvider';
import { ProxiedContract, TransparentProxyAddresses } from '../proxy';
import { ChainMap, ChainName } from '../types';
import { objMap } from '../utils/objects';
import { IgpContracts, igpFactories } from './contracts';
import { IgpFactories, igpFactories } from './contracts';
import { OverheadIgpConfig } from './types';
export class HyperlaneIgpDeployer extends HyperlaneDeployer<
OverheadIgpConfig,
IgpContracts,
typeof igpFactories
IgpFactories
> {
startingBlockNumbers: ChainMap<number | undefined>;
@ -42,9 +41,7 @@ export class HyperlaneIgpDeployer extends HyperlaneDeployer<
proxyAdmin: ProxyAdmin,
storageGasOracle: StorageGasOracle,
deployOpts?: DeployOptions,
): Promise<
ProxiedContract<InterchainGasPaymaster, TransparentProxyAddresses>
> {
): Promise<InterchainGasPaymaster> {
const owner = this.configMap[chain].owner;
const beneficiary = this.configMap[chain].beneficiary;
const igp = await this.deployProxiedContract(
@ -67,7 +64,7 @@ export class HyperlaneIgpDeployer extends HyperlaneDeployer<
for (const remote of remotes) {
const remoteId = this.multiProvider.getDomainId(remote);
const currentGasOracle = await igp.contract.gasOracles(remoteId);
const currentGasOracle = await igp.gasOracles(remoteId);
if (!utils.eqAddress(currentGasOracle, storageGasOracle.address)) {
gasOracleConfigsToSet.push({
remoteDomain: remoteId,
@ -77,10 +74,10 @@ export class HyperlaneIgpDeployer extends HyperlaneDeployer<
}
if (gasOracleConfigsToSet.length > 0) {
await this.runIfOwner(chain, igp.contract, async () =>
await this.runIfOwner(chain, igp, async () =>
this.multiProvider.handleTx(
chain,
igp.contract.setGasOracles(gasOracleConfigsToSet),
igp.setGasOracles(gasOracleConfigsToSet),
),
);
}
@ -152,7 +149,7 @@ export class HyperlaneIgpDeployer extends HyperlaneDeployer<
async deployContracts(
chain: ChainName,
config: OverheadIgpConfig,
): Promise<IgpContracts> {
): Promise<HyperlaneContracts<IgpFactories>> {
const provider = this.multiProvider.getProvider(chain);
const startingBlockNumber = await provider.getBlockNumber();
this.startingBlockNumbers[chain] = startingBlockNumber;

@ -1,33 +1,9 @@
import {
InterchainGasPaymaster,
InterchainGasPaymaster__factory,
OverheadIgp,
OverheadIgp__factory,
ProxyAdmin,
ProxyAdmin__factory,
StorageGasOracle,
StorageGasOracle__factory,
} from '@hyperlane-xyz/core';
import { types } from '@hyperlane-xyz/utils';
import { ProxiedContract, TransparentProxyAddresses } from '../proxy';
export type IgpAddresses = {
proxyAdmin: types.Address;
interchainGasPaymaster: types.Address | TransparentProxyAddresses;
defaultIsmInterchainGasPaymaster: types.Address;
storageGasOracle: types.Address;
};
export type IgpContracts = {
proxyAdmin: ProxyAdmin;
interchainGasPaymaster: ProxiedContract<
InterchainGasPaymaster,
TransparentProxyAddresses
>;
defaultIsmInterchainGasPaymaster: OverheadIgp;
storageGasOracle: StorageGasOracle;
};
export const igpFactories = {
proxyAdmin: new ProxyAdmin__factory(),
@ -35,3 +11,5 @@ export const igpFactories = {
defaultIsmInterchainGasPaymaster: new OverheadIgp__factory(),
storageGasOracle: new StorageGasOracle__factory(),
};
export type IgpFactories = typeof igpFactories;

@ -29,38 +29,33 @@ export {
TestChains,
Testnets,
} from './consts/chains';
export {
hyperlaneAgentAddresses,
HyperlaneContractAddresses,
hyperlaneContractAddresses,
hyperlaneCoreAddresses,
hyperlaneEnvironments,
} from './consts/environments';
export { hyperlaneEnvironments } from './consts/environments';
export { defaultMultisigIsmConfigs } from './consts/multisigIsm';
export {
buildContracts,
attachContracts,
attachContractsMap,
connectContracts,
connectContractsMap,
filterAddresses,
filterAddressesMap,
HyperlaneAddresses,
HyperlaneAddressesMap,
HyperlaneContracts,
HyperlaneContractsMap,
HyperlaneFactories,
serializeContracts,
serializeContractsMap,
} from './contracts';
export { CoreContracts, coreFactories } from './core/contracts';
export { CoreFactories, coreFactories } from './core/contracts';
export {
AnnotatedDispatch,
AnnotatedLifecycleEvent,
HyperlaneLifecyleEvent,
} from './core/events';
export {
CoreContractsMap,
DispatchedMessage,
HyperlaneCore,
} from './core/HyperlaneCore';
export { DispatchedMessage, HyperlaneCore } from './core/HyperlaneCore';
export { HyperlaneCoreChecker } from './core/HyperlaneCoreChecker';
export { HyperlaneCoreDeployer } from './core/HyperlaneCoreDeployer';
export { TestCoreApp, TestCoreContracts } from './core/TestCoreApp';
export { TestCoreApp } from './core/TestCoreApp';
export { TestCoreDeployer } from './core/TestCoreDeployer';
export {
CoreConfig,
@ -76,7 +71,6 @@ export {
DeployOptions,
HyperlaneDeployer,
} from './deploy/HyperlaneDeployer';
export { ProxyViolation } from './deploy/proxy';
export {
CheckerViolation,
OwnerViolation,
@ -117,10 +111,7 @@ export {
InterchainAccountConfig,
InterchainAccountDeployer,
} from './middleware/account/InterchainAccountDeployer';
export {
LiquidityLayerContracts,
liquidityLayerFactories,
} from './middleware/liquidity-layer/contracts';
export { liquidityLayerFactories } from './middleware/liquidity-layer/contracts';
export { LiquidityLayerApp } from './middleware/liquidity-layer/LiquidityLayerApp';
export {
BridgeAdapterConfig,
@ -138,12 +129,6 @@ export {
} from './middleware/query/InterchainQueryDeployer';
export { MultiProvider, providerBuilder } from './providers/MultiProvider';
export { RetryJsonRpcProvider, RetryProvider } from './providers/RetryProvider';
export {
ProxiedContract,
ProxyAddresses,
ProxyKind,
TransparentProxyAddresses,
} from './proxy';
export { GasRouterDeployer } from './router/GasRouterDeployer';
export { HyperlaneRouterChecker } from './router/HyperlaneRouterChecker';
export { HyperlaneRouterDeployer } from './router/HyperlaneRouterDeployer';

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

@ -1,26 +1,17 @@
import { ContractFactory, ethers } from 'ethers';
import { ProxyAdmin, Router } from '@hyperlane-xyz/core';
import { HyperlaneContracts } from '../contracts';
import { MultiProvider } from '../providers/MultiProvider';
import { HyperlaneRouterDeployer } from '../router/HyperlaneRouterDeployer';
import {
ProxiedContracts,
ProxiedFactories,
RouterConfig,
} from '../router/types';
import { Router } from '../router/RouterApps';
import { 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
> {
> extends HyperlaneRouterDeployer<MiddlewareRouterConfig, MiddlewareFactories> {
constructor(
multiProvider: MultiProvider,
configMap: ChainMap<MiddlewareRouterConfig>,
@ -39,8 +30,8 @@ export abstract class MiddlewareRouterDeployer<
abstract readonly routerContractName: string;
router(contracts: MiddlewareRouterContracts): Router {
return contracts[this.routerContractName].contract;
router(contracts: HyperlaneContracts<MiddlewareFactories>): Router {
return contracts[this.routerContractName] as Router;
}
async initializeArgs(
@ -61,12 +52,12 @@ export abstract class MiddlewareRouterDeployer<
async deployContracts(
chain: ChainName,
config: MiddlewareRouterConfig,
): Promise<MiddlewareRouterContracts> {
const proxyAdmin = (await this.deployContract(
): Promise<HyperlaneContracts<MiddlewareFactories>> {
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(
@ -87,10 +78,10 @@ export abstract class MiddlewareRouterDeployer<
proxyAdmin.transferOwnership(config.owner),
),
);
const ret: MiddlewareRouterContracts = {
const ret = {
[this.routerContractName]: proxiedRouter,
proxyAdmin,
} as MiddlewareRouterContracts;
return ret;
};
return ret as HyperlaneContracts<MiddlewareFactories>;
}
}

@ -4,42 +4,20 @@ import {
HyperlaneEnvironment,
hyperlaneEnvironments,
} from '../../consts/environments';
import { HyperlaneAddresses } from '../../contracts';
import { HyperlaneContracts } from '../../contracts';
import { MultiProvider } from '../../providers/MultiProvider';
import { RouterApp } from '../../router/RouterApps';
import { ChainMap, ChainName } from '../../types';
import {
InterchainAccountContracts,
InterchainAccountFactories,
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);
export class InterchainAccount extends RouterApp<InterchainAccountFactories> {
router(
contracts: HyperlaneContracts<InterchainAccountFactories>,
): InterchainAccountRouter {
return contracts.interchainAccountRouter;
}
static fromEnvironment<Env extends HyperlaneEnvironment>(
@ -50,10 +28,14 @@ export class InterchainAccount extends RouterApp<InterchainAccountContracts> {
if (!envAddresses) {
throw new Error(`No addresses found for ${env}`);
}
return InterchainAccount.fromAddresses(envAddresses, multiProvider);
}
getContracts(chain: ChainName): InterchainAccountContracts {
return super.getContracts(chain);
const fromAddressesMap = this.fromAddressesMap(
envAddresses,
interchainAccountFactories,
multiProvider,
);
return new InterchainAccount(
fromAddressesMap.contractsMap,
fromAddressesMap.multiProvider,
);
}
}

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

@ -1,18 +1,15 @@
import {
InterchainAccountRouter,
InterchainAccountRouter__factory,
ProxyAdmin,
TransparentUpgradeableProxy__factory,
} from '@hyperlane-xyz/core';
import { HyperlaneContracts } from '../../contracts';
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';
@ -21,7 +18,6 @@ export type InterchainAccountConfig = RouterConfig;
export class InterchainAccountDeployer extends MiddlewareRouterDeployer<
InterchainAccountConfig,
InterchainAccountContracts,
InterchainAccountFactories,
InterchainAccountRouter__factory
> {
@ -43,18 +39,13 @@ export class InterchainAccountDeployer extends MiddlewareRouterDeployer<
async deployContracts(
chain: ChainName,
config: InterchainAccountConfig,
): Promise<InterchainAccountContracts> {
const proxyAdmin = (await this.deployContract(
chain,
'proxyAdmin',
[],
)) as ProxyAdmin;
): Promise<HyperlaneContracts<InterchainAccountFactories>> {
const proxyAdmin = await this.deployContract(chain, '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');
const cached = this.deployedContracts[chain]?.interchainAccountRouter;
if (cached) {
this.logger('Recovered InterchainAccountRouter');
return {
proxyAdmin,
interchainAccountRouter: cached,
@ -96,18 +87,11 @@ export class InterchainAccountDeployer extends MiddlewareRouterDeployer<
);
await super.changeAdmin(chain, proxy, proxyAdmin.address);
const proxiedRouter = new ProxiedContract(
implementation.attach(proxy.address),
{
kind: ProxyKind.Transparent,
implementation: implementation.address,
proxy: proxy.address,
},
);
const proxiedRouter = implementation.attach(proxy.address);
return {
proxyAdmin,
interchainAccountRouter: proxiedRouter, // for serialization
interchainAccountRouter: proxiedRouter,
};
}
}

@ -8,6 +8,7 @@ import {
} from '@hyperlane-xyz/core';
import { Chains } from '../../consts/chains';
import { HyperlaneContractsMap } from '../../contracts';
import { TestCoreApp } from '../../core/TestCoreApp';
import { TestCoreDeployer } from '../../core/TestCoreDeployer';
import { MultiProvider } from '../../providers/MultiProvider';
@ -18,14 +19,14 @@ import { ChainMap } from '../../types';
import { InterchainAccount } from './InterchainAccount';
import { InterchainAccountChecker } from './InterchainAccountChecker';
import { InterchainAccountDeployer } from './InterchainAccountDeployer';
import { InterchainAccountContracts } from './contracts';
import { InterchainAccountFactories } from './contracts';
describe('InterchainAccounts', async () => {
const localChain = Chains.test1;
const remoteChain = Chains.test2;
let signer: SignerWithAddress;
let contracts: ChainMap<InterchainAccountContracts>;
let contracts: HyperlaneContractsMap<InterchainAccountFactories>;
let local: InterchainAccountRouter;
let remote: InterchainAccountRouter;
let multiProvider: MultiProvider;
@ -53,8 +54,8 @@ describe('InterchainAccounts', async () => {
beforeEach(async () => {
const deployer = new InterchainAccountDeployer(multiProvider, config);
contracts = await deployer.deploy();
local = contracts[localChain].interchainAccountRouter.contract;
remote = contracts[remoteChain].interchainAccountRouter.contract;
local = contracts[localChain].interchainAccountRouter;
remote = contracts[remoteChain].interchainAccountRouter;
});
it('checks', async () => {

@ -1,23 +1,11 @@
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;
};
export type InterchainAccountFactories = typeof interchainAccountFactories;

@ -11,11 +11,12 @@ import { utils } from '@hyperlane-xyz/utils';
import { HyperlaneApp } from '../../HyperlaneApp';
import { Chains } from '../../consts/chains';
import { HyperlaneContracts } from '../../contracts';
import { MultiProvider } from '../../providers/MultiProvider';
import { ChainMap, ChainName } from '../../types';
import { BridgeAdapterConfig } from './LiquidityLayerRouterDeployer';
import { LiquidityLayerContracts } from './contracts';
import { liquidityLayerFactories } from './contracts';
const PORTAL_VAA_SERVICE_TESTNET_BASE_URL =
'https://wormhole-v2-testnet-api.certus.one/v1/signed_vaa/';
@ -54,9 +55,13 @@ interface PortalBridgeMessage {
destination: ChainName;
}
export class LiquidityLayerApp extends HyperlaneApp<LiquidityLayerContracts> {
export class LiquidityLayerApp extends HyperlaneApp<
typeof liquidityLayerFactories
> {
constructor(
public readonly contractsMap: ChainMap<LiquidityLayerContracts>,
public readonly contractsMap: ChainMap<
HyperlaneContracts<typeof liquidityLayerFactories>
>,
public readonly multiProvider: MultiProvider,
public readonly config: ChainMap<BridgeAdapterConfig>,
) {

@ -8,17 +8,14 @@ import {
} from '@hyperlane-xyz/core';
import { utils } from '@hyperlane-xyz/utils';
import { HyperlaneContracts, HyperlaneContractsMap } from '../../contracts';
import { MultiProvider } from '../../providers/MultiProvider';
import { RouterConfig } from '../../router/types';
import { ChainMap, ChainName } from '../../types';
import { objMap } from '../../utils/objects';
import { MiddlewareRouterDeployer } from '../MiddlewareRouterDeployer';
import {
LiquidityLayerContracts,
LiquidityLayerFactories,
liquidityLayerFactories,
} from './contracts';
import { LiquidityLayerFactories, liquidityLayerFactories } from './contracts';
export enum BridgeAdapterType {
Circle = 'Circle',
@ -54,7 +51,6 @@ export type LiquidityLayerConfig = RouterConfig & BridgeAdapterConfig;
export class LiquidityLayerDeployer extends MiddlewareRouterDeployer<
LiquidityLayerConfig,
LiquidityLayerContracts,
LiquidityLayerFactories,
LiquidityLayerRouter__factory
> {
@ -69,7 +65,7 @@ export class LiquidityLayerDeployer extends MiddlewareRouterDeployer<
}
async enrollRemoteRouters(
contractsMap: ChainMap<LiquidityLayerContracts>,
contractsMap: HyperlaneContractsMap<LiquidityLayerFactories>,
): Promise<void> {
this.logger(`Enroll LiquidityLayerRouters with each other`);
await super.enrollRemoteRouters(contractsMap);
@ -78,20 +74,16 @@ export class LiquidityLayerDeployer extends MiddlewareRouterDeployer<
// Hack to allow use of super.enrollRemoteRouters
await super.enrollRemoteRouters(
objMap(contractsMap, (_, contracts) => ({
liquidityLayerRouter: {
contract: contracts.circleBridgeAdapter,
},
})) as unknown as ChainMap<LiquidityLayerContracts>,
liquidityLayerRouter: contracts.circleBridgeAdapter,
})) as unknown as HyperlaneContractsMap<LiquidityLayerFactories>,
);
this.logger(`Enroll PortalAdapters with each other`);
// Hack to allow use of super.enrollRemoteRouters
await super.enrollRemoteRouters(
objMap(contractsMap, (_, contracts) => ({
liquidityLayerRouter: {
contract: contracts.portalAdapter,
},
})) as unknown as ChainMap<LiquidityLayerContracts>,
liquidityLayerRouter: contracts.portalAdapter,
})) as unknown as HyperlaneContractsMap<LiquidityLayerFactories>,
);
}
@ -100,20 +92,19 @@ export class LiquidityLayerDeployer extends MiddlewareRouterDeployer<
async deployContracts(
chain: ChainName,
config: LiquidityLayerConfig,
): Promise<LiquidityLayerContracts> {
const routerContracts = (await super.deployContracts(
chain,
config,
)) as LiquidityLayerContracts;
): Promise<HyperlaneContracts<LiquidityLayerFactories>> {
const routerContracts = await super.deployContracts(chain, config);
const bridgeAdapters: Partial<LiquidityLayerContracts> = {};
const bridgeAdapters: Partial<
HyperlaneContracts<typeof liquidityLayerFactories>
> = {};
if (config.circle) {
bridgeAdapters.circleBridgeAdapter = await this.deployCircleBridgeAdapter(
chain,
config.circle,
config.owner,
routerContracts.liquidityLayerRouter.contract,
routerContracts.liquidityLayerRouter,
);
}
if (config.portal) {
@ -121,14 +112,14 @@ export class LiquidityLayerDeployer extends MiddlewareRouterDeployer<
chain,
config.portal,
config.owner,
routerContracts.liquidityLayerRouter.contract,
routerContracts.liquidityLayerRouter,
);
}
return {
...routerContracts,
...bridgeAdapters,
} as LiquidityLayerContracts;
};
}
async deployPortalAdapter(

@ -1,31 +1,15 @@
import {
CircleBridgeAdapter,
CircleBridgeAdapter__factory,
LiquidityLayerRouter,
LiquidityLayerRouter__factory,
PortalAdapter,
PortalAdapter__factory,
ProxyAdmin__factory,
} from '@hyperlane-xyz/core';
import { ProxiedContract } from '../../proxy';
import { ProxiedContracts, ProxiedFactories } from '../../router/types';
export type LiquidityLayerFactories = ProxiedFactories & {
liquidityLayerRouter: LiquidityLayerRouter__factory;
circleBridgeAdapter: CircleBridgeAdapter__factory;
portalAdapter: PortalAdapter__factory;
};
export const liquidityLayerFactories: LiquidityLayerFactories = {
export const liquidityLayerFactories = {
circleBridgeAdapter: new CircleBridgeAdapter__factory(),
portalAdapter: new PortalAdapter__factory(),
proxyAdmin: new ProxyAdmin__factory(),
liquidityLayerRouter: new LiquidityLayerRouter__factory(),
};
export type LiquidityLayerContracts = ProxiedContracts & {
liquidityLayerRouter: ProxiedContract<LiquidityLayerRouter>;
circleBridgeAdapter?: CircleBridgeAdapter;
portalAdapter?: PortalAdapter;
};
export type LiquidityLayerFactories = typeof liquidityLayerFactories;

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

@ -4,41 +4,20 @@ import {
HyperlaneEnvironment,
hyperlaneEnvironments,
} from '../../consts/environments';
import { HyperlaneAddresses } from '../../contracts';
import { HyperlaneContracts } from '../../contracts';
import { MultiProvider } from '../../providers/MultiProvider';
import { RouterApp } from '../../router/RouterApps';
import { ChainMap, ChainName } from '../../types';
import {
InterchainQueryContracts,
InterchainQueryFactories,
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);
export class InterchainQuery extends RouterApp<InterchainQueryFactories> {
router(
contracts: HyperlaneContracts<InterchainQueryFactories>,
): InterchainQueryRouter {
return contracts.interchainQueryRouter;
}
static fromEnvironment<Env extends HyperlaneEnvironment>(
@ -49,10 +28,14 @@ export class InterchainQuery extends RouterApp<InterchainQueryContracts> {
if (!envAddresses) {
throw new Error(`No addresses found for ${env}`);
}
return InterchainQuery.fromAddresses(envAddresses, multiProvider);
}
getContracts(chain: ChainName): InterchainQueryContracts {
return super.getContracts(chain);
const fromAddressesMap = this.fromAddressesMap(
envAddresses,
interchainQueryFactories,
multiProvider,
);
return new InterchainQuery(
fromAddressesMap.contractsMap,
fromAddressesMap.multiProvider,
);
}
}

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

@ -6,7 +6,6 @@ import { ChainMap } from '../../types';
import { MiddlewareRouterDeployer } from '../MiddlewareRouterDeployer';
import {
InterchainQueryContracts,
InterchainQueryFactories,
interchainQueryFactories,
} from './contracts';
@ -15,7 +14,6 @@ export type InterchainQueryConfig = RouterConfig;
export class InterchainQueryDeployer extends MiddlewareRouterDeployer<
InterchainQueryConfig,
InterchainQueryContracts,
InterchainQueryFactories,
InterchainQueryRouter__factory
> {

@ -1,23 +1,11 @@
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;
};
export type InterchainQueryFactories = typeof interchainQueryFactories;

@ -11,6 +11,7 @@ import { utils } from '@hyperlane-xyz/utils';
import { chainMetadata } from '../../consts/chainMetadata';
import { Chains } from '../../consts/chains';
import { HyperlaneContractsMap } from '../../contracts';
import { TestCoreApp } from '../../core/TestCoreApp';
import { TestCoreDeployer } from '../../core/TestCoreDeployer';
import { MultiProvider } from '../../providers/MultiProvider';
@ -21,7 +22,7 @@ import { ChainMap } from '../../types';
import { InterchainQuery } from './InterchainQuery';
import { InterchainQueryChecker } from './InterchainQueryChecker';
import { InterchainQueryDeployer } from './InterchainQueryDeployer';
import { InterchainQueryContracts } from './contracts';
import { InterchainQueryFactories } from './contracts';
describe('InterchainQueryRouter', async () => {
const localChain = Chains.test1;
@ -29,7 +30,7 @@ describe('InterchainQueryRouter', async () => {
const localDomain = chainMetadata[localChain].chainId;
const remoteDomain = chainMetadata[remoteChain].chainId;
let contracts: ChainMap<InterchainQueryContracts>;
let contracts: HyperlaneContractsMap<InterchainQueryFactories>;
let signer: SignerWithAddress;
let local: InterchainQueryRouter;
let remote: InterchainQueryRouter;
@ -58,8 +59,8 @@ describe('InterchainQueryRouter', async () => {
contracts = await InterchainQuery.deploy();
local = contracts[localChain].interchainQueryRouter.contract;
remote = contracts[remoteChain].interchainQueryRouter.contract;
local = contracts[localChain].interchainQueryRouter;
remote = contracts[remoteChain].interchainQueryRouter;
testQuery = await new TestQuery__factory(signer).deploy(local.address);
});

@ -1,76 +0,0 @@
import { TransactionResponse } from '@ethersproject/abstract-provider';
import { Contract } from 'ethers';
import type { types } from '@hyperlane-xyz/utils';
import { Connection } from './types';
export enum ProxyKind {
Transparent = 'Transparent',
}
export interface ProxyAddresses<Kind extends ProxyKind> {
kind: Kind;
proxy: types.Address;
implementation: types.Address;
}
export function isProxyAddresses(
addresses: unknown,
): addresses is ProxyAddresses<any> {
// The presence of `implementation` is intentionally not checked
// to allow deploying new implementations by deleting the implementation
// from the artifacts
return (
addresses !== null &&
typeof addresses === 'object' &&
'proxy' in addresses &&
'kind' in addresses &&
Object.keys(ProxyKind).includes((addresses as any).kind)
);
}
export function getProxyAddress(
address: types.Address | ProxyAddresses<any>,
): string {
return isProxyAddresses(address) ? address.proxy : address;
}
export type TransparentProxyAddresses = ProxyAddresses<ProxyKind.Transparent>;
export class ProxiedContract<
C extends Contract,
A extends ProxyAddresses<any> = TransparentProxyAddresses,
> {
constructor(public readonly contract: C, public readonly addresses: A) {}
get address(): string {
return this.contract.address;
}
get deployTransaction(): TransactionResponse {
return this.contract.deployTransaction;
}
connect(connection: Connection): ProxiedContract<C, A> {
return new ProxiedContract(
this.contract.connect(connection) as C,
this.addresses,
);
}
}
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,22 +1,21 @@
import { debug } from 'debug';
import { HyperlaneFactories } from '../contracts';
import { HyperlaneContractsMap, HyperlaneFactories } from '../contracts';
import { DeployerOptions } from '../deploy/HyperlaneDeployer';
import { MultiProvider } from '../providers/MultiProvider';
import { ChainMap } from '../types';
import { HyperlaneRouterDeployer } from './HyperlaneRouterDeployer';
import { GasRouterContracts } from './RouterApps';
import { GasRouterConfig } from './types';
export abstract class GasRouterDeployer<
Config extends GasRouterConfig,
Contracts extends GasRouterContracts,
> extends HyperlaneRouterDeployer<Config, Contracts, HyperlaneFactories> {
Factories extends HyperlaneFactories,
> extends HyperlaneRouterDeployer<Config, Factories> {
constructor(
multiProvider: MultiProvider,
configMap: ChainMap<Config>,
factories: HyperlaneFactories,
factories: Factories,
options?: DeployerOptions,
) {
super(multiProvider, configMap, factories, {
@ -25,12 +24,14 @@ export abstract class GasRouterDeployer<
});
}
async enrollRemoteRouters(contractsMap: ChainMap<Contracts>): Promise<void> {
async enrollRemoteRouters(
contractsMap: HyperlaneContractsMap<Factories>,
): Promise<void> {
await super.enrollRemoteRouters(contractsMap);
this.logger(`Setting enrolled router destination gas...`);
for (const [chain, contracts] of Object.entries<Contracts>(contractsMap)) {
const remoteDomains = await contracts.router.domains();
for (const [chain, contracts] of Object.entries(contractsMap)) {
const remoteDomains = await this.router(contracts).domains();
const remoteChains = remoteDomains.map((domain) =>
this.multiProvider.getChainName(domain),
);

@ -2,7 +2,7 @@ import { ethers } from 'ethers';
import { utils } from '@hyperlane-xyz/utils';
import { HyperlaneContracts } from '../contracts';
import { HyperlaneFactories } from '../contracts';
import { HyperlaneAppChecker } from '../deploy/HyperlaneAppChecker';
import { ChainName } from '../types';
@ -10,9 +10,9 @@ import { RouterApp } from './RouterApps';
import { RouterConfig } from './types';
export class HyperlaneRouterChecker<
App extends RouterApp<Contracts>,
Factories extends HyperlaneFactories,
App extends RouterApp<Factories>,
Config extends RouterConfig,
Contracts extends HyperlaneContracts,
> extends HyperlaneAppChecker<App, Config> {
checkOwnership(chain: ChainName): Promise<void> {
const owner = this.configMap[chain].owner;

@ -3,7 +3,11 @@ import { debug } from 'debug';
import { Router } from '@hyperlane-xyz/core';
import { utils } from '@hyperlane-xyz/utils';
import { HyperlaneContracts, HyperlaneFactories } from '../contracts';
import {
HyperlaneContracts,
HyperlaneContractsMap,
HyperlaneFactories,
} from '../contracts';
import {
DeployerOptions,
HyperlaneDeployer,
@ -15,9 +19,8 @@ import { objMap, promiseObjAll } from '../utils/objects';
export abstract class HyperlaneRouterDeployer<
Config extends RouterConfig,
Contracts extends HyperlaneContracts,
Factories extends HyperlaneFactories,
> extends HyperlaneDeployer<Config, Contracts, Factories> {
> extends HyperlaneDeployer<Config, Factories> {
constructor(
multiProvider: MultiProvider,
configMap: ChainMap<Config>,
@ -30,10 +33,10 @@ export abstract class HyperlaneRouterDeployer<
});
}
abstract router(contracts: Contracts): Router;
abstract router(contracts: HyperlaneContracts<Factories>): Router;
async initConnectionClients(
contractsMap: ChainMap<Contracts>,
contractsMap: HyperlaneContractsMap<Factories>,
): Promise<void> {
await promiseObjAll(
objMap(contractsMap, async (local, contracts) =>
@ -46,13 +49,15 @@ export abstract class HyperlaneRouterDeployer<
);
}
async enrollRemoteRouters(contractsMap: ChainMap<Contracts>): Promise<void> {
async enrollRemoteRouters(
contractsMap: HyperlaneContractsMap<Factories>,
): Promise<void> {
this.logger(
`Enrolling deployed routers with each other (if not already)...`,
);
// Make all routers aware of each other.
const deployedChains = Object.keys(contractsMap);
for (const [chain, contracts] of Object.entries<Contracts>(contractsMap)) {
for (const [chain, contracts] of Object.entries(contractsMap)) {
// only enroll chains which are deployed
const deployedRemoteChains = this.multiProvider
.getRemoteChains(chain)
@ -96,7 +101,9 @@ export abstract class HyperlaneRouterDeployer<
}
}
async transferOwnership(contractsMap: ChainMap<Contracts>): Promise<void> {
async transferOwnership(
contractsMap: HyperlaneContractsMap<Factories>,
): Promise<void> {
this.logger(`Transferring ownership of routers...`);
await promiseObjAll(
objMap(contractsMap, async (chain, contracts) => {
@ -119,8 +126,8 @@ export abstract class HyperlaneRouterDeployer<
}
async deploy(
partialDeployment?: ChainMap<Contracts>,
): Promise<ChainMap<Contracts>> {
partialDeployment?: HyperlaneContractsMap<Factories>,
): Promise<HyperlaneContractsMap<Factories>> {
const contractsMap = await super.deploy(partialDeployment);
await this.enrollRemoteRouters(contractsMap);

@ -1,19 +1,19 @@
import type { BigNumber } from 'ethers';
import { GasRouter, GasRouter__factory, Router } from '@hyperlane-xyz/core';
import { GasRouter, Router } from '@hyperlane-xyz/core';
import type { types } from '@hyperlane-xyz/utils';
import { HyperlaneApp } from '../HyperlaneApp';
import { HyperlaneContracts } from '../contracts';
import { HyperlaneContracts, HyperlaneFactories } from '../contracts';
import { ChainMap, ChainName } from '../types';
import { objMap, promiseObjAll } from '../utils/objects';
export { Router } from '@hyperlane-xyz/core';
export abstract class RouterApp<
Contracts extends HyperlaneContracts,
> extends HyperlaneApp<Contracts> {
abstract router(contracts: Contracts): Router;
Factories extends HyperlaneFactories,
> extends HyperlaneApp<Factories> {
abstract router(contracts: HyperlaneContracts<Factories>): Router;
getSecurityModules = (): Promise<ChainMap<types.Address>> =>
promiseObjAll(
@ -30,18 +30,11 @@ export abstract class RouterApp<
);
}
export type GasRouterContracts = {
router: GasRouter;
};
export type GasRouterFactories = {
router: GasRouter__factory;
};
export class GasRouterApp extends RouterApp<GasRouterContracts> {
router(contracts: GasRouterContracts): GasRouter {
return contracts.router;
}
export abstract class GasRouterApp<
Factories extends HyperlaneFactories,
R extends GasRouter,
> extends RouterApp<Factories> {
abstract router(contracts: HyperlaneContracts<Factories>): R;
async quoteGasPayment(
origin: ChainName,

@ -1,7 +1,7 @@
import { ProxyAdmin, ProxyAdmin__factory } from '@hyperlane-xyz/core';
import { ProxyAdmin__factory } from '@hyperlane-xyz/core';
import type { types } from '@hyperlane-xyz/utils';
import { HyperlaneContracts, HyperlaneFactories } from '../contracts';
import { HyperlaneFactories } from '../contracts';
export type OwnableConfig = {
owner: types.Address;
@ -19,10 +19,6 @@ export type ProxiedFactories = HyperlaneFactories & {
proxyAdmin: ProxyAdmin__factory;
};
export type ProxiedContracts = HyperlaneContracts & {
proxyAdmin: ProxyAdmin;
};
export type ConnectionClientConfig = {
mailbox: types.Address;
interchainGasPaymaster: types.Address;

@ -26,21 +26,20 @@ export const testRouterFactories: TestRouterFactories = {
router: new TestRouter__factory(),
};
export class EnvSubsetApp extends RouterApp<TestRouterContracts> {
export class EnvSubsetApp extends RouterApp<typeof testRouterFactories> {
router(contracts: TestRouterContracts) {
return contracts.router;
}
}
export class EnvSubsetChecker extends HyperlaneRouterChecker<
typeof testRouterFactories,
EnvSubsetApp,
RouterConfig,
TestRouterContracts
RouterConfig
> {}
export class EnvSubsetDeployer extends HyperlaneRouterDeployer<
RouterConfig,
TestRouterContracts,
TestRouterFactories
> {
constructor(

@ -1,19 +1,13 @@
import { buildContracts } from '../../contracts';
import { attachContractsMap } from '../../contracts';
import { HyperlaneCore } from '../../core/HyperlaneCore';
import { HyperlaneIgp } from '../../gas/HyperlaneIgp';
import { MultiProvider } from '../../providers/MultiProvider';
import { ChainMap } from '../../types';
import { createRouterConfigMap } from '../testUtils';
import {
EnvSubsetApp,
EnvSubsetChecker,
TestRouterContracts,
testRouterFactories,
} from './app';
import { EnvSubsetApp, EnvSubsetChecker, testRouterFactories } from './app';
// Copied from output of deploy-single-chain.ts script
const deploymentAddresses = {
const deploymentAddressesMap = {
alfajores: {
router: '0x0666AD4F636210B6a418f97790b7BAABAC54b9A4',
},
@ -25,10 +19,10 @@ async function check() {
console.info('Preparing utilities');
const multiProvider = new MultiProvider();
const contractsMap = buildContracts(
deploymentAddresses,
const contractsMap = attachContractsMap(
deploymentAddressesMap,
testRouterFactories,
) as ChainMap<TestRouterContracts>;
);
const app = new EnvSubsetApp(contractsMap, multiProvider);
const core = HyperlaneCore.fromEnvironment('testnet', multiProvider);
const igp = HyperlaneIgp.fromEnvironment('testnet', multiProvider);

@ -1,5 +1,5 @@
import { Chains } from '../../consts/chains';
import { serializeContracts } from '../../contracts';
import { serializeContractsMap } from '../../contracts';
import { HyperlaneCore } from '../../core/HyperlaneCore';
import { HyperlaneIgp } from '../../gas/HyperlaneIgp';
import { MultiProvider } from '../../providers/MultiProvider';
@ -26,7 +26,7 @@ async function main() {
console.info('Starting deployment');
const deployer = new EnvSubsetDeployer(multiProvider, config, core);
const chainToContracts = await deployer.deploy();
const addresses = serializeContracts(chainToContracts);
const addresses = serializeContractsMap(chainToContracts);
console.info('===Contract Addresses===');
console.info(JSON.stringify(addresses));
}

@ -7,9 +7,10 @@ import {
import { types } from '@hyperlane-xyz/utils';
import { chainMetadata } from '../consts/chainMetadata';
import { CoreContracts } from '../core/contracts';
import { HyperlaneContractsMap } from '../contracts';
import { CoreFactories } from '../core/contracts';
import { CoreConfig } from '../core/types';
import { IgpContracts } from '../gas/contracts';
import { IgpFactories } from '../gas/contracts';
import {
CoinGeckoInterface,
CoinGeckoResponse,
@ -23,8 +24,8 @@ import { objMap } from '../utils/objects';
export function createRouterConfigMap(
owner: types.Address,
coreContracts: ChainMap<CoreContracts>,
igpContracts: ChainMap<IgpContracts>,
coreContracts: HyperlaneContractsMap<CoreFactories>,
igpContracts: HyperlaneContractsMap<IgpFactories>,
): ChainMap<RouterConfig> {
return objMap(coreContracts, (chain, contracts) => {
return {
@ -39,7 +40,7 @@ export function createRouterConfigMap(
export async function deployTestIgpsAndGetRouterConfig(
multiProvider: MultiProvider,
owner: types.Address,
coreContracts: ChainMap<CoreContracts>,
coreContracts: HyperlaneContractsMap<CoreFactories>,
): Promise<ChainMap<RouterConfig>> {
const igps: ChainMap<TestInterchainGasPaymaster> = {};
for (const chain of multiProvider.getKnownChainNames()) {

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