Skip to content

Commit

Permalink
feat: hyperlane warp send all chains (#5118)
Browse files Browse the repository at this point in the history
### Description
Update `hyperlane warp send` to send a round trip transfer to all chains
in WarpCoreConfig, if `--origin` and/or `--destination` is not provided.

### Backward compatibility
Yes

### Testing
Manual
  • Loading branch information
ltyu authored Jan 7, 2025
1 parent 71aefa0 commit 3c4bc1c
Show file tree
Hide file tree
Showing 4 changed files with 72 additions and 42 deletions.
5 changes: 5 additions & 0 deletions .changeset/lovely-snakes-cross.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@hyperlane-xyz/cli': minor
---

Update hyperlane warp send to send a round trip transfer to all chains in WarpCoreConfig, if --origin and/or --destination is not provided.
4 changes: 4 additions & 0 deletions typescript/cli/src/commands/send.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,10 @@ export const messageSendOptions: { [k: string]: Options } = {
type: 'string',
description: 'Destination chain to send message to',
},
'round-trip': {
type: 'boolean',
description: 'Send test transfers to all chains in WarpCoreConfig',
},
};

export interface MessageOptionsArgTypes {
Expand Down
41 changes: 37 additions & 4 deletions typescript/cli/src/commands/warp.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { stringify as yamlStringify } from 'yaml';
import { CommandModule } from 'yargs';

import { ChainSubmissionStrategySchema } from '@hyperlane-xyz/sdk';
import { ChainName, ChainSubmissionStrategySchema } from '@hyperlane-xyz/sdk';
import { objFilter } from '@hyperlane-xyz/utils';

import { runWarpRouteCheck } from '../check/warp.js';
import {
Expand All @@ -14,9 +15,10 @@ import {
} from '../context/types.js';
import { evaluateIfDryRunFailure } from '../deploy/dry-run.js';
import { runWarpRouteApply, runWarpRouteDeploy } from '../deploy/warp.js';
import { log, logCommandHeader, logGreen } from '../logger.js';
import { log, logBlue, logCommandHeader, logGreen } from '../logger.js';
import { runWarpRouteRead } from '../read/warp.js';
import { sendTestTransfer } from '../send/transfer.js';
import { runSingleChainSelectionStep } from '../utils/chains.js';
import {
indentYamlOrJson,
readYamlOrJson,
Expand Down Expand Up @@ -275,24 +277,55 @@ const send: CommandModuleWithWriteContext<
warp,
amount,
recipient,
roundTrip,
}) => {
const warpCoreConfig = await getWarpCoreConfigOrExit({
symbol,
warp,
context,
});

let chains: ChainName[] = warpCoreConfig.tokens.map((t) => t.chainName);
if (roundTrip) {
// Appends the reverse of the array, excluding the 1st (e.g. [1,2,3] becomes [1,2,3,2,1])
const reversed = [...chains].reverse().slice(1, chains.length + 1); // We make a copy because .reverse() is mutating
chains.push(...reversed);
} else {
// Assume we want to use use `--origin` and `--destination` params, prompt as needed.
const chainMetadata = objFilter(
context.chainMetadata,
(key, _metadata): _metadata is any => chains.includes(key),
);

if (!origin)
origin = await runSingleChainSelectionStep(
chainMetadata,
'Select the origin chain:',
);

if (!destination)
destination = await runSingleChainSelectionStep(
chainMetadata,
'Select the destination chain:',
);

chains = chains.filter((c) => c === origin || c === destination);
}

logBlue(`🚀 Sending a message for chains: ${chains.join(' ➡️ ')}`);
await sendTestTransfer({
context,
warpCoreConfig,
origin,
destination,
chains,
amount,
recipient,
timeoutSec: timeout,
skipWaitForDelivery: quick,
selfRelay: relay,
});
logGreen(
`✅ Successfully sent messages for chains: ${chains.join(' ➡️ ')}`,
);
process.exit(0);
},
};
Expand Down
64 changes: 26 additions & 38 deletions typescript/cli/src/send/transfer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ import { MINIMUM_TEST_SEND_GAS } from '../consts.js';
import { WriteCommandContext } from '../context/types.js';
import { runPreflightChecksForChains } from '../deploy/utils.js';
import { log, logBlue, logGreen, logRed } from '../logger.js';
import { runSingleChainSelectionStep } from '../utils/chains.js';
import { indentYamlOrJson } from '../utils/files.js';
import { stubMerkleTreeConfig } from '../utils/relay.js';
import { runTokenSelectionStep } from '../utils/tokens.js';
Expand All @@ -30,8 +29,7 @@ export const WarpSendLogs = {
export async function sendTestTransfer({
context,
warpCoreConfig,
origin,
destination,
chains,
amount,
recipient,
timeoutSec,
Expand All @@ -40,51 +38,41 @@ export async function sendTestTransfer({
}: {
context: WriteCommandContext;
warpCoreConfig: WarpCoreConfig;
origin?: ChainName; // resolved in signerMiddleware
destination?: ChainName; // resolved in signerMiddleware
chains: ChainName[];
amount: string;
recipient?: string;
timeoutSec: number;
skipWaitForDelivery: boolean;
selfRelay?: boolean;
}) {
const { chainMetadata } = context;

if (!origin) {
origin = await runSingleChainSelectionStep(
chainMetadata,
'Select the origin chain:',
);
}

if (!destination) {
destination = await runSingleChainSelectionStep(
chainMetadata,
'Select the destination chain:',
);
}

await runPreflightChecksForChains({
context,
chains: [origin, destination],
chainsToGasCheck: [origin],
chains,
minGas: MINIMUM_TEST_SEND_GAS,
});

await timeout(
executeDelivery({
context,
origin,
destination,
warpCoreConfig,
amount,
recipient,
skipWaitForDelivery,
selfRelay,
}),
timeoutSec * 1000,
'Timed out waiting for messages to be delivered',
);
for (let i = 0; i < chains.length; i++) {
const origin = chains[i];
const destination = chains[i + 1];

if (destination) {
logBlue(`Sending a message from ${origin} to ${destination}`);
await timeout(
executeDelivery({
context,
origin,
destination,
warpCoreConfig,
amount,
recipient,
skipWaitForDelivery,
selfRelay,
}),
timeoutSec * 1000,
'Timed out waiting for messages to be delivered',
);
}
}
}

async function executeDelivery({
Expand Down Expand Up @@ -199,5 +187,5 @@ async function executeDelivery({

// Max wait 10 minutes
await core.waitForMessageProcessed(transferTxReceipt, 10000, 60);
logGreen(`Transfer sent to destination chain!`);
logGreen(`Transfer sent to ${destination} chain!`);
}

0 comments on commit 3c4bc1c

Please sign in to comment.