Skip to content

Commit

Permalink
fix:use custom hook for sending test messages in the CLI (#3178)
Browse files Browse the repository at this point in the history
### Description

- Saving the deployed top-level hook address if the deployer is not the
owner of the mailbox
- CLI command for sending messages uses the custom hook if present in
the artifacts

### Drive-by changes

None

### Related issues


### Backward compatibility

Yes

### Testing

Manual
  • Loading branch information
aroralanuk authored Jan 25, 2024
1 parent 0e8e169 commit 0d5a751
Show file tree
Hide file tree
Showing 5 changed files with 68 additions and 21 deletions.
1 change: 1 addition & 0 deletions typescript/cli/ci-test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ echo "Sending test message"
yarn workspace @hyperlane-xyz/cli run hyperlane send message \
--origin anvil1 \
--destination anvil2 \
--messageBody "Howdy!" \
--chains ./examples/anvil-chains.yaml \
--core $CORE_ARTIFACTS_PATH \
--quick \
Expand Down
13 changes: 12 additions & 1 deletion typescript/cli/src/commands/send.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { ethers } from 'ethers';
import { CommandModule, Options } from 'yargs';

import { TokenType } from '@hyperlane-xyz/sdk';
Expand Down Expand Up @@ -57,7 +58,15 @@ const messageOptions: { [k: string]: Options } = {
const messageCommand: CommandModule = {
command: 'message',
describe: 'Send a test message to a remote chain',
builder: (yargs) => yargs.options(messageOptions),
builder: (yargs) =>
yargs.options({
...messageOptions,
messageBody: {
type: 'string',
description: 'Optional Message body',
default: 'Hello!',
},
}),
handler: async (argv: any) => {
const key: string = argv.key || process.env.HYP_KEY;
const chainConfigPath: string = argv.chains;
Expand All @@ -66,12 +75,14 @@ const messageCommand: CommandModule = {
const destination: string | undefined = argv.destination;
const timeoutSec: number = argv.timeout;
const skipWaitForDelivery: boolean = argv.quick;
const messageBody: string = argv.messageBody;
await sendTestMessage({
key,
chainConfigPath,
coreArtifactsPath,
origin,
destination,
messageBody: ethers.utils.hexlify(ethers.utils.toUtf8Bytes(messageBody)),
timeoutSec,
skipWaitForDelivery,
});
Expand Down
35 changes: 28 additions & 7 deletions typescript/cli/src/send/message.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,13 @@ import { getContext, getMergedContractAddresses } from '../context.js';
import { runPreflightChecks } from '../deploy/utils.js';
import { runSingleChainSelectionStep } from '../utils/chains.js';

const MESSAGE_BODY = '0x48656c6c6f21'; // Hello!'

export async function sendTestMessage({
key,
chainConfigPath,
coreArtifactsPath,
origin,
destination,
messageBody,
timeoutSec,
skipWaitForDelivery,
}: {
Expand All @@ -30,6 +29,7 @@ export async function sendTestMessage({
coreArtifactsPath?: string;
origin?: ChainName;
destination?: ChainName;
messageBody: string;
timeoutSec: number;
skipWaitForDelivery: boolean;
}) {
Expand Down Expand Up @@ -67,6 +67,7 @@ export async function sendTestMessage({
executeDelivery({
origin,
destination,
messageBody,
multiProvider,
coreArtifacts,
skipWaitForDelivery,
Expand All @@ -79,12 +80,14 @@ export async function sendTestMessage({
async function executeDelivery({
origin,
destination,
messageBody,
multiProvider,
coreArtifacts,
skipWaitForDelivery,
}: {
origin: ChainName;
destination: ChainName;
messageBody: string;
multiProvider: MultiProvider;
coreArtifacts?: HyperlaneContractsMap<any>;
skipWaitForDelivery: boolean;
Expand All @@ -96,6 +99,14 @@ async function executeDelivery({
);
const mailbox = core.getContracts(origin).mailbox;

let hook = mergedContractAddrs[origin]?.customHook;
if (hook) {
logBlue(`Using custom hook ${hook} for ${origin} -> ${destination}`);
} else {
hook = await mailbox.defaultHook();
logBlue(`Using default hook ${hook} for ${origin} -> ${destination}`);
}

const destinationDomain = multiProvider.getDomainId(destination);
let txReceipt: ethers.ContractReceipt;
try {
Expand All @@ -106,19 +117,29 @@ async function executeDelivery({
const formattedRecipient = addressToBytes32(recipient);

log('Getting gas quote');
const value = await mailbox['quoteDispatch(uint32,bytes32,bytes)'](
const value = await mailbox[
'quoteDispatch(uint32,bytes32,bytes,bytes,address)'
](
destinationDomain,
formattedRecipient,
MESSAGE_BODY,
messageBody,
ethers.utils.hexlify([]),
hook,
);
log(`Paying for gas with ${value} wei`);

log('Dispatching message');
const messageTx = await mailbox['dispatch(uint32,bytes32,bytes)'](
const messageTx = await mailbox[
'dispatch(uint32,bytes32,bytes,bytes,address)'
](
destinationDomain,
formattedRecipient,
MESSAGE_BODY,
{ value },
messageBody,
ethers.utils.hexlify([]),
hook,
{
value,
},
);
txReceipt = await multiProvider.handleTx(origin, messageTx);
const message = core.getDispatchedMessages(txReceipt)[0];
Expand Down
14 changes: 9 additions & 5 deletions typescript/sdk/src/core/HyperlaneCoreDeployer.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
import debug from 'debug';

import { Mailbox, ValidatorAnnounce } from '@hyperlane-xyz/core';
import {
IPostDispatchHook,
Mailbox,
ValidatorAnnounce,
} from '@hyperlane-xyz/core';
import { Address } from '@hyperlane-xyz/utils';

import { HyperlaneContracts } from '../contracts/types';
Expand Down Expand Up @@ -100,8 +104,8 @@ export class HyperlaneCoreDeployer extends HyperlaneDeployer<
mailbox.initialize(
config.owner,
defaultIsm,
defaultHook,
requiredHook,
defaultHook.address,
requiredHook.address,
this.multiProvider.getTransactionOverrides(chain),
),
);
Expand Down Expand Up @@ -165,7 +169,7 @@ export class HyperlaneCoreDeployer extends HyperlaneDeployer<
chain: ChainName,
config: HookConfig,
coreAddresses: Partial<CoreAddresses>,
): Promise<Address> {
): Promise<IPostDispatchHook> {
const hooks = await this.hookDeployer.deployContracts(
chain,
config,
Expand All @@ -176,7 +180,7 @@ export class HyperlaneCoreDeployer extends HyperlaneDeployer<
this.hookDeployer.deployedContracts[chain],
this.hookDeployer.verificationInputs[chain],
);
return hooks[config.type].address;
return hooks[config.type];
}

async deployIsm(
Expand Down
26 changes: 18 additions & 8 deletions typescript/sdk/src/deploy/HyperlaneDeployer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ import { Debugger, debug } from 'debug';
import { Contract, PopulatedTransaction, ethers } from 'ethers';

import {
IPostDispatchHook,
IPostDispatchHook__factory,
ITransparentUpgradeableProxy,
MailboxClient,
Ownable,
Expand Down Expand Up @@ -240,27 +242,32 @@ export abstract class HyperlaneDeployer<
protected async configureHook<C extends Ownable>(
chain: ChainName,
contract: C,
targetHook: Address,
targetHook: IPostDispatchHook,
getHook: (contract: C) => Promise<Address>,
setHook: (contract: C, hook: Address) => Promise<PopulatedTransaction>,
): Promise<void> {
const configuredHook = await getHook(contract);
if (!eqAddress(targetHook, configuredHook)) {
await this.runIfOwner(chain, contract, async () => {
if (!eqAddress(targetHook.address, configuredHook)) {
const result = await this.runIfOwner(chain, contract, async () => {
this.logger(
`Set hook on ${chain} to ${targetHook}, currently is ${configuredHook}`,
`Set hook on ${chain} to ${targetHook.address}, currently is ${configuredHook}`,
);
await this.multiProvider.sendTransaction(
chain,
setHook(contract, targetHook),
setHook(contract, targetHook.address),
);
const actualHook = await getHook(contract);
if (!eqAddress(targetHook, actualHook)) {
if (!eqAddress(targetHook.address, actualHook)) {
throw new Error(
`Set hook failed on ${chain}, wanted ${targetHook}, got ${actualHook}`,
`Set hook failed on ${chain}, wanted ${targetHook.address}, got ${actualHook}`,
);
}
return true;
});
// if the signer is not the owner, saving the hook address in the artifacts for later use for sending test messages, etc
if (!result) {
this.addDeployedContracts(chain, { customHook: targetHook });
}
}
}

Expand All @@ -274,7 +281,10 @@ export abstract class HyperlaneDeployer<
await this.configureHook(
local,
client,
config.hook,
IPostDispatchHook__factory.connect(
config.hook,
this.multiProvider.getSignerOrProvider(local),
),
(_client) => _client.hook(),
(_client, _hook) => _client.populateTransaction.setHook(_hook),
);
Expand Down

0 comments on commit 0d5a751

Please sign in to comment.