Skip to content

Commit

Permalink
Implement NULL metadata relaying in the SDK/CLI (#3604)
Browse files Browse the repository at this point in the history
### Description

- Add NULL self relay to core app
- Add self relay to send message command

### Drive-by changes

- Migrate to assert util in ISM Factory
- Default to `HYP_KEY` in shared key option

### Related issues

- Fixes #3608
- Fixes #3609
- Fixes #3452

### Backward compatibility

Yes

### Testing

Manual


https://github.com/hyperlane-xyz/hyperlane-monorepo/assets/3020995/e44683c3-bca4-41d5-a4c7-45718f05edf4


https://github.com/hyperlane-xyz/hyperlane-monorepo/assets/3020995/50565be1-d266-4d2d-ae27-5fbb5539b93f
  • Loading branch information
yorhodes authored Apr 15, 2024
1 parent c7007b0 commit 917266d
Show file tree
Hide file tree
Showing 14 changed files with 227 additions and 47 deletions.
6 changes: 6 additions & 0 deletions .changeset/four-brooms-develop.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
'@hyperlane-xyz/cli': minor
'@hyperlane-xyz/sdk': minor
---

Add --self-relay to CLI commands
5 changes: 2 additions & 3 deletions typescript/cli/src/commands/deploy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import { runCoreDeploy } from '../deploy/core.js';
import { evaluateIfDryRunFailure, verifyAnvil } from '../deploy/dry-run.js';
import { runWarpRouteDeploy } from '../deploy/warp.js';
import { log, logGray } from '../logger.js';
import { ENV } from '../utils/env.js';

import {
AgentCommandOptions,
Expand Down Expand Up @@ -91,7 +90,7 @@ const coreCommand: CommandModule = {
'dry-run': dryRunOption,
}),
handler: async (argv: any) => {
const key: string = argv.key || ENV.HYP_KEY;
const key: string | undefined = argv.key;
const chainConfigPath: string = argv.chains;
const outPath: string = argv.out;
const chains: string[] | undefined = argv.targets
Expand Down Expand Up @@ -146,7 +145,7 @@ const warpCommand: CommandModule = {
yes: skipConfirmationOption,
}),
handler: async (argv: any) => {
const key: string = argv.key || ENV.HYP_KEY;
const key: string | undefined = argv.key;
const chainConfigPath: string = argv.chains;
const warpRouteDeploymentConfigPath: string | undefined = argv.config;
const coreArtifactsPath: string | undefined = argv.core;
Expand Down
3 changes: 3 additions & 0 deletions typescript/cli/src/commands/options.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ import { Options } from 'yargs';

import { LogFormat, LogLevel } from '@hyperlane-xyz/utils';

import { ENV } from '../utils/env.js';

export const logFormatCommandOption: Options = {
type: 'string',
description: 'Log output format',
Expand Down Expand Up @@ -81,6 +83,7 @@ export const keyCommandOption: Options = {
description: `Default: A hex private key or seed phrase for transaction signing, or use the HYP_KEY env var.
Dry-run: An address to simulate transaction signing on a forked network, or use the HYP_KEY env var.`,
alias: 'k',
default: ENV.HYP_KEY,
};

export const chainsCommandOption: Options = {
Expand Down
19 changes: 15 additions & 4 deletions typescript/cli/src/commands/send.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import { CommandModule, Options } from 'yargs';
import { log } from '../logger.js';
import { sendTestMessage } from '../send/message.js';
import { sendTestTransfer } from '../send/transfer.js';
import { ENV } from '../utils/env.js';

import {
chainsCommandOption,
Expand All @@ -28,10 +27,17 @@ export const sendCommand: CommandModule = {
handler: () => log('Command required'),
};

export const selfrelay: Options = {
type: 'boolean',
description: 'Relay message on destination chain',
default: false,
alias: ['s', 'sr'],
};

/**
* Message command
*/
const messageOptions: { [k: string]: Options } = {
export const messageOptions: { [k: string]: Options } = {
key: keyCommandOption,
origin: {
type: 'string',
Expand All @@ -48,6 +54,7 @@ const messageOptions: { [k: string]: Options } = {
description: 'Timeout in seconds',
default: 5 * 60,
},
'self-relay': selfrelay,
quick: {
type: 'boolean',
description: 'Skip wait for message to be delivered',
Expand All @@ -68,14 +75,15 @@ const messageCommand: CommandModule = {
},
}),
handler: async (argv: any) => {
const key: string = argv.key || ENV.HYP_KEY;
const key: string | undefined = argv.key;
const chainConfigPath: string = argv.chains;
const coreArtifactsPath: string | undefined = argv.core;
const origin: string | undefined = argv.origin;
const destination: string | undefined = argv.destination;
const timeoutSec: number = argv.timeout;
const skipWaitForDelivery: boolean = argv.quick;
const messageBody: string = argv.messageBody;
const selfRelay: boolean = argv['selfrelay'];
await sendTestMessage({
key,
chainConfigPath,
Expand All @@ -85,6 +93,7 @@ const messageCommand: CommandModule = {
messageBody: ethers.utils.hexlify(ethers.utils.toUtf8Bytes(messageBody)),
timeoutSec,
skipWaitForDelivery,
selfRelay,
});
process.exit(0);
},
Expand Down Expand Up @@ -115,7 +124,7 @@ const transferCommand: CommandModule = {
},
}),
handler: async (argv: any) => {
const key: string = argv.key || ENV.HYP_KEY;
const key: string | undefined = argv.key;
const chainConfigPath: string = argv.chains;
const coreArtifactsPath: string | undefined = argv.core;
const warpConfigPath: string = argv.warp;
Expand All @@ -126,6 +135,7 @@ const transferCommand: CommandModule = {
const wei: string = argv.wei;
const recipient: string | undefined = argv.recipient;
const skipWaitForDelivery: boolean = argv.quick;
const selfRelay: boolean = argv['self-relay'];
await sendTestTransfer({
key,
chainConfigPath,
Expand All @@ -138,6 +148,7 @@ const transferCommand: CommandModule = {
recipient,
timeoutSec,
skipWaitForDelivery,
selfRelay,
});
process.exit(0);
},
Expand Down
16 changes: 9 additions & 7 deletions typescript/cli/src/commands/status.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,34 +2,36 @@ import { CommandModule } from 'yargs';

import { checkMessageStatus } from '../status/message.js';

import { chainsCommandOption, coreArtifactsOption } from './options.js';
import { messageOptions } from './send.js';

export const statusCommand: CommandModule = {
command: 'status',
describe: 'Check status of a message',
builder: (yargs) =>
yargs.options({
...messageOptions,
id: {
type: 'string',
description: 'Message ID',
},
destination: {
type: 'string',
description: 'Destination chain name',
},
chains: chainsCommandOption,
core: coreArtifactsOption,
}),
handler: async (argv: any) => {
const chainConfigPath: string = argv.chains;
const coreArtifactsPath: string | undefined = argv.core;
const messageId: string | undefined = argv.id;
const destination: string | undefined = argv.destination;
const origin: string | undefined = argv.origin;
const selfRelay: boolean = argv['self-relay'];
const key: string | undefined = argv.key;

await checkMessageStatus({
chainConfigPath,
coreArtifactsPath,
messageId,
destination,
origin,
selfRelay,
key,
});
process.exit(0);
},
Expand Down
2 changes: 1 addition & 1 deletion typescript/cli/src/deploy/core.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ export async function runCoreDeploy({
skipConfirmation,
dryRun,
}: {
key: string;
key?: string;
chainConfigPath: string;
chains?: ChainName[];
ismConfigPath?: string;
Expand Down
2 changes: 1 addition & 1 deletion typescript/cli/src/deploy/warp.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ export async function runWarpRouteDeploy({
outPath,
skipConfirmation,
}: {
key: string;
key?: string;
chainConfigPath: string;
warpRouteDeploymentConfigPath?: string;
coreArtifactsPath?: string;
Expand Down
13 changes: 12 additions & 1 deletion typescript/cli/src/send/message.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,15 +23,17 @@ export async function sendTestMessage({
messageBody,
timeoutSec,
skipWaitForDelivery,
selfRelay,
}: {
key: string;
key?: string;
chainConfigPath: string;
coreArtifactsPath?: string;
origin?: ChainName;
destination?: ChainName;
messageBody: string;
timeoutSec: number;
skipWaitForDelivery: boolean;
selfRelay?: boolean;
}) {
const { signer, multiProvider, customChains, coreArtifacts } =
await getContext({
Expand Down Expand Up @@ -71,6 +73,7 @@ export async function sendTestMessage({
multiProvider,
coreArtifacts,
skipWaitForDelivery,
selfRelay,
}),
timeoutSec * 1000,
'Timed out waiting for messages to be delivered',
Expand All @@ -84,13 +87,15 @@ async function executeDelivery({
multiProvider,
coreArtifacts,
skipWaitForDelivery,
selfRelay,
}: {
origin: ChainName;
destination: ChainName;
messageBody: string;
multiProvider: MultiProvider;
coreArtifacts?: HyperlaneContractsMap<any>;
skipWaitForDelivery: boolean;
selfRelay?: boolean;
}) {
const mergedContractAddrs = getMergedContractAddresses(coreArtifacts);
const core = HyperlaneCore.fromAddressesMap(
Expand Down Expand Up @@ -146,6 +151,12 @@ async function executeDelivery({
logBlue(`Sent message from ${origin} to ${recipient} on ${destination}.`);
logBlue(`Message ID: ${message.id}`);
log(`Message: ${JSON.stringify(message)}`);

if (selfRelay) {
await core.relayMessage(message);
logGreen('Message was self-relayed!');
return;
}
} catch (e) {
errorRed(
`Encountered error sending message from ${origin} to ${destination}`,
Expand Down
13 changes: 12 additions & 1 deletion typescript/cli/src/send/transfer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,9 @@ export async function sendTestTransfer({
recipient,
timeoutSec,
skipWaitForDelivery,
selfRelay,
}: {
key: string;
key?: string;
chainConfigPath: string;
coreArtifactsPath?: string;
warpConfigPath: string;
Expand All @@ -44,6 +45,7 @@ export async function sendTestTransfer({
recipient?: string;
timeoutSec: number;
skipWaitForDelivery: boolean;
selfRelay?: boolean;
}) {
const { signer, multiProvider, customChains, coreArtifacts, warpCoreConfig } =
await getContext({
Expand Down Expand Up @@ -88,6 +90,7 @@ export async function sendTestTransfer({
multiProvider,
coreArtifacts,
skipWaitForDelivery,
selfRelay,
}),
timeoutSec * 1000,
'Timed out waiting for messages to be delivered',
Expand All @@ -105,6 +108,7 @@ async function executeDelivery({
signer,
coreArtifacts,
skipWaitForDelivery,
selfRelay,
}: {
origin: ChainName;
destination: ChainName;
Expand All @@ -116,6 +120,7 @@ async function executeDelivery({
signer: ethers.Signer;
coreArtifacts?: HyperlaneContractsMap<any>;
skipWaitForDelivery: boolean;
selfRelay?: boolean;
}) {
const signerAddress = await signer.getAddress();
recipient ||= signerAddress;
Expand Down Expand Up @@ -196,6 +201,12 @@ async function executeDelivery({
logBlue(`Sent message from ${origin} to ${recipient} on ${destination}.`);
logBlue(`Message ID: ${message.id}`);

if (selfRelay) {
await core.relayMessage(message);
logGreen('Message was self-relayed!');
return;
}

if (skipWaitForDelivery) return;

// Max wait 10 minutes
Expand Down
28 changes: 26 additions & 2 deletions typescript/cli/src/status/message.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,24 @@ export async function checkMessageStatus({
coreArtifactsPath,
messageId,
destination,
origin,
selfRelay,
key,
}: {
chainConfigPath: string;
coreArtifactsPath?: string;
messageId?: string;
destination?: ChainName;
origin?: ChainName;
selfRelay?: boolean;
key?: string;
}) {
const keyConfig = selfRelay ? { key } : undefined;

const { multiProvider, customChains, coreArtifacts } = await getContext({
chainConfigPath,
coreConfig: { coreArtifactsPath },
keyConfig,
});

if (!destination) {
Expand All @@ -45,7 +54,22 @@ export async function checkMessageStatus({
const delivered = await mailbox.delivered(messageId);
if (delivered) {
logGreen(`Message ${messageId} was delivered`);
} else {
logBlue(`Message ${messageId} was not yet delivered`);
return;
}
logBlue(`Message ${messageId} was not yet delivered`);

if (selfRelay) {
// TODO: implement option for tx receipt input
if (!origin) {
origin = await runSingleChainSelectionStep(
customChains,
'Select the origin chain',
);
}

const receipt = await core.getDispatchTx(origin, messageId);
const messages = core.getDispatchedMessages(receipt);
await core.relayMessage(messages[0]);
logGreen(`Message ${messageId} was self-relayed!`);
}
}
Loading

0 comments on commit 917266d

Please sign in to comment.