fix: `testRecipient` CLI bug (#3138)

### Description

- we were recovering `TestRecipient` from sdk artifacts which means the
deployer won't have ownership. So, I added a optional `shouldRecover`
boolean which I turned off for TestRecipient deployer (this is only for
our artifacts, if they have their own testRecipient, it will still
recover that if provided)
- moved `TestRecipientDeployer` from cli to sdk and removed duplicated
code from infra

### Drive-by changes

None

### Related issues

- fixes https://github.com/hyperlane-xyz/issues/issues/895

### Backward compatibility

Yes

### Testing

Manual (between anvil1 and optimismgoerli)
pull/3142/head
Kunal Arora 11 months ago committed by GitHub
parent d3d7ad7f97
commit 67a6d971ed
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 7
      .changeset/dirty-ears-push.md
  2. 6
      typescript/cli/src/deploy/core.ts
  3. 4
      typescript/infra/scripts/deploy.ts
  4. 36
      typescript/infra/src/deployment/testcontracts/testrecipient.ts
  5. 38
      typescript/sdk/src/core/TestRecipientDeployer.ts
  6. 29
      typescript/sdk/src/deploy/HyperlaneDeployer.ts
  7. 4
      typescript/sdk/src/index.ts

@ -0,0 +1,7 @@
---
'@hyperlane-xyz/infra': patch
'@hyperlane-xyz/cli': patch
'@hyperlane-xyz/sdk': patch
---
Added `shouldRecover` flag to deployContractFromFactory so that the `TestRecipientDeployer` can deploy new contracts if it's not the owner of the prior deployments (We were recovering the SDK artifacts which meant the deployer won't be able to set the ISM as they needed)

@ -21,6 +21,8 @@ import {
MultiProvider, MultiProvider,
MultisigConfig, MultisigConfig,
RoutingIsmConfig, RoutingIsmConfig,
TestRecipientConfig,
TestRecipientDeployer,
buildAgentConfig, buildAgentConfig,
buildAggregationIsmConfigs, buildAggregationIsmConfigs,
defaultMultisigConfigs, defaultMultisigConfigs,
@ -47,10 +49,6 @@ import {
writeJson, writeJson,
} from '../utils/files.js'; } from '../utils/files.js';
import {
TestRecipientConfig,
TestRecipientDeployer,
} from './TestRecipientDeployer.js';
import { import {
isISMConfig, isISMConfig,
isZODISMConfig, isZODISMConfig,

@ -24,7 +24,6 @@ import { Contexts } from '../config/contexts';
import { deployEnvToSdkEnv } from '../src/config/environment'; import { deployEnvToSdkEnv } from '../src/config/environment';
import { deployWithArtifacts } from '../src/deployment/deploy'; import { deployWithArtifacts } from '../src/deployment/deploy';
import { TestQuerySenderDeployer } from '../src/deployment/testcontracts/testquerysender'; import { TestQuerySenderDeployer } from '../src/deployment/testcontracts/testquerysender';
import { TestRecipientDeployer } from '../src/deployment/testcontracts/testrecipient';
import { impersonateAccount, useLocalProvider } from '../src/utils/fork'; import { impersonateAccount, useLocalProvider } from '../src/utils/fork';
import { import {
@ -138,8 +137,7 @@ async function main() {
); );
deployer = new LiquidityLayerDeployer(multiProvider); deployer = new LiquidityLayerDeployer(multiProvider);
} else if (module === Modules.TEST_RECIPIENT) { } else if (module === Modules.TEST_RECIPIENT) {
config = objMap(envConfig.core, (_chain) => true); throw new Error('Test recipient is not supported. Use CLI instead.');
deployer = new TestRecipientDeployer(multiProvider);
} else if (module === Modules.TEST_QUERY_SENDER) { } else if (module === Modules.TEST_QUERY_SENDER) {
// Get query router addresses // Get query router addresses
const queryAddresses = getAddresses( const queryAddresses = getAddresses(

@ -1,36 +0,0 @@
import {
TestRecipient__factory,
TestTokenRecipient__factory,
} from '@hyperlane-xyz/core';
import {
ChainName,
HyperlaneDeployer,
MultiProvider,
} from '@hyperlane-xyz/sdk';
export const TEST_RECIPIENT_DEPLOYER_FACTORIES = {
TestRecipient: new TestRecipient__factory(),
TestTokenRecipient: new TestTokenRecipient__factory(),
};
export class TestRecipientDeployer extends HyperlaneDeployer<
never,
typeof TEST_RECIPIENT_DEPLOYER_FACTORIES
> {
constructor(multiProvider: MultiProvider) {
super(multiProvider, TEST_RECIPIENT_DEPLOYER_FACTORIES);
}
async deployContracts(chain: ChainName) {
const TestRecipient = await this.deployContract(chain, 'TestRecipient', []);
const TestTokenRecipient = await this.deployContract(
chain,
'TestTokenRecipient',
[],
);
return {
TestRecipient,
TestTokenRecipient,
};
}
}

@ -1,13 +1,12 @@
import debug from 'debug'; import debug from 'debug';
import { TestRecipient, TestRecipient__factory } from '@hyperlane-xyz/core'; import { TestRecipient, TestRecipient__factory } from '@hyperlane-xyz/core';
import {
ChainName,
HyperlaneDeployer,
MultiProvider,
} from '@hyperlane-xyz/sdk';
import { Address, eqAddress } from '@hyperlane-xyz/utils'; import { Address, eqAddress } from '@hyperlane-xyz/utils';
import { HyperlaneDeployer } from '../deploy/HyperlaneDeployer';
import { MultiProvider } from '../providers/MultiProvider';
import { ChainName } from '../types';
export type TestRecipientConfig = { export type TestRecipientConfig = {
interchainSecurityModule: Address; interchainSecurityModule: Address;
}; };
@ -39,7 +38,28 @@ export class TestRecipientDeployer extends HyperlaneDeployer<
chain: ChainName, chain: ChainName,
config: TestRecipientConfig, config: TestRecipientConfig,
): Promise<TestRecipientContracts> { ): Promise<TestRecipientContracts> {
const testRecipient = await this.deployContract(chain, 'testRecipient', []); const predeployed = this.readCache(
chain,
this.factories['testRecipient'],
'testRecipient',
);
let usePreviousDeployment = false;
if (
predeployed &&
eqAddress(
await predeployed.owner(),
await this.multiProvider.getSignerAddress(chain),
)
) {
usePreviousDeployment = true;
}
const testRecipient = await this.deployContract(
chain,
'testRecipient',
[],
undefined,
usePreviousDeployment,
);
try { try {
this.logger(`Checking ISM ${chain}`); this.logger(`Checking ISM ${chain}`);
const ism = await testRecipient.interchainSecurityModule(); const ism = await testRecipient.interchainSecurityModule();
@ -51,7 +71,11 @@ export class TestRecipientDeployer extends HyperlaneDeployer<
const tx = testRecipient.setInterchainSecurityModule( const tx = testRecipient.setInterchainSecurityModule(
config.interchainSecurityModule, config.interchainSecurityModule,
); );
await this.multiProvider.handleTx(chain, tx); await this.runIfOwner(
chain,
testRecipient,
async () => await this.multiProvider.handleTx(chain, tx),
);
} }
} catch (error) { } catch (error) {
this.logger(`Failed to check/update ISM for ${chain}: ${error}`); this.logger(`Failed to check/update ISM for ${chain}: ${error}`);

@ -300,20 +300,23 @@ export abstract class HyperlaneDeployer<
contractName: string, contractName: string,
constructorArgs: Parameters<F['deploy']>, constructorArgs: Parameters<F['deploy']>,
initializeArgs?: Parameters<Awaited<ReturnType<F['deploy']>>['initialize']>, initializeArgs?: Parameters<Awaited<ReturnType<F['deploy']>>['initialize']>,
shouldRecover = true,
): Promise<ReturnType<F['deploy']>> { ): Promise<ReturnType<F['deploy']>> {
const cachedContract = this.readCache(chain, factory, contractName); if (shouldRecover) {
if (cachedContract) { const cachedContract = this.readCache(chain, factory, contractName);
if (this.recoverVerificationInputs) { if (cachedContract) {
const recoveredInputs = await this.recoverVerificationArtifacts( if (this.recoverVerificationInputs) {
chain, const recoveredInputs = await this.recoverVerificationArtifacts(
contractName, chain,
cachedContract, contractName,
constructorArgs, cachedContract,
initializeArgs, constructorArgs,
); initializeArgs,
this.addVerificationArtifacts(chain, recoveredInputs); );
this.addVerificationArtifacts(chain, recoveredInputs);
}
return cachedContract;
} }
return cachedContract;
} }
this.logger(`Deploy ${contractName} on ${chain}`); this.logger(`Deploy ${contractName} on ${chain}`);
@ -347,6 +350,7 @@ export abstract class HyperlaneDeployer<
initializeArgs?: Parameters< initializeArgs?: Parameters<
Awaited<ReturnType<Factories[K]['deploy']>>['initialize'] Awaited<ReturnType<Factories[K]['deploy']>>['initialize']
>, >,
shouldRecover = true,
): Promise<HyperlaneContracts<Factories>[K]> { ): Promise<HyperlaneContracts<Factories>[K]> {
const contract = await this.deployContractFromFactory( const contract = await this.deployContractFromFactory(
chain, chain,
@ -354,6 +358,7 @@ export abstract class HyperlaneDeployer<
contractName.toString(), contractName.toString(),
constructorArgs, constructorArgs,
initializeArgs, initializeArgs,
shouldRecover,
); );
this.writeCache(chain, contractName, contract.address); this.writeCache(chain, contractName, contract.address);
return contract; return contract;

@ -59,6 +59,10 @@ export { HyperlaneCoreDeployer } from './core/HyperlaneCoreDeployer';
export { MultiProtocolCore } from './core/MultiProtocolCore'; export { MultiProtocolCore } from './core/MultiProtocolCore';
export { TestCoreApp } from './core/TestCoreApp'; export { TestCoreApp } from './core/TestCoreApp';
export { TestCoreDeployer } from './core/TestCoreDeployer'; export { TestCoreDeployer } from './core/TestCoreDeployer';
export {
TestRecipientConfig,
TestRecipientDeployer,
} from './core/TestRecipientDeployer';
export { EvmCoreAdapter } from './core/adapters/EvmCoreAdapter'; export { EvmCoreAdapter } from './core/adapters/EvmCoreAdapter';
export { SealevelCoreAdapter } from './core/adapters/SealevelCoreAdapter'; export { SealevelCoreAdapter } from './core/adapters/SealevelCoreAdapter';
export { ICoreAdapter } from './core/adapters/types'; export { ICoreAdapter } from './core/adapters/types';

Loading…
Cancel
Save