Skip to content
Open
Show file tree
Hide file tree
Changes from 12 commits
Commits
Show all changes
64 commits
Select commit Hold shift + click to select a range
dedaa34
merge with main repo latest changes
mortezashojaei Oct 16, 2024
4f541e3
Merge remote-tracking branch 'origin-root/main'
mortezashojaei Oct 22, 2024
f10e542
Merge remote-tracking branch 'origin-root/main'
mortezashojaei Oct 25, 2024
36e2b00
Merge remote-tracking branch 'origin-root/main'
mortezashojaei Oct 28, 2024
ba0d6ea
feat: Singe/MultiVM signer strategy
ljankovic-txfusion Nov 7, 2024
2bf349b
feat: Deployment strategies & refactoring
ljankovic-txfusion Nov 8, 2024
9c43d1c
fix: e2e test working
ljankovic-txfusion Nov 11, 2024
3602abd
chore: add comments & minor refactoring
ljankovic-txfusion Nov 11, 2024
ce81b48
chore: minor fixes
ljankovic-txfusion Nov 12, 2024
ff2b4c9
Merge remote-tracking branch 'origin-root/main'
ljankovic-txfusion Nov 12, 2024
af97d7f
Merge remote-tracking branch 'origin-root/main'
ljankovic-txfusion Nov 12, 2024
e4839a1
perf: removed unused code and refactoring
ljankovic-txfusion Nov 12, 2024
4abd806
feat: masked pk, refactoring
ljankovic-txfusion Nov 13, 2024
188dced
feat: MultiChainHandler support to extract chains from WarpCoreConfig…
ljankovic-txfusion Nov 14, 2024
0b92c68
chore: refactoring & adding comments
ljankovic-txfusion Nov 15, 2024
ea205dc
Merge remote-tracking branch 'origin/main' into feat/key-command
ljankovic-txfusion Nov 15, 2024
ac6d5c1
feat: relay command chain resolver strategy & refactoring
ljankovic-txfusion Nov 15, 2024
925621c
feat: Signer strategy based on chain's protocol/tech stack
ljankovic-txfusion Nov 18, 2024
a0ea88b
chore: minor refactoring
ljankovic-txfusion Nov 18, 2024
f030f23
Merge remote-tracking branch 'origin/main' into feat/key-command
ljankovic-txfusion Nov 18, 2024
52efa81
add: strategy types for submitter
ljankovic-txfusion Nov 18, 2024
12679af
chore: following naming conventions & comments
ljankovic-txfusion Nov 18, 2024
b7d439b
feat: requiresKey options on strategy `read` command
ljankovic-txfusion Nov 19, 2024
24b9d7a
chore: revert MessageOptionsArgTypes origin & destination optionality
ljankovic-txfusion Nov 19, 2024
60a2ae2
feat: strategy init chain agnostic
ljankovic-txfusion Nov 20, 2024
884db14
feat: logging private key source
ljankovic-txfusion Nov 20, 2024
2cc7ca4
chore: MultiProtocolSignerOptions refactor
ljankovic-txfusion Nov 20, 2024
d7326a6
docs(changeset): Added strategy management CLI commands and MultiProt…
ljankovic-txfusion Nov 20, 2024
6561504
refactor: improve signer management in warp route deploy config creation
ljankovic-txfusion Nov 21, 2024
e532b1a
refactor: improve strategy config handling and type safety & sensitiv…
ljankovic-txfusion Nov 22, 2024
afb3b21
refactor: sensitive key function name
ljankovic-txfusion Nov 22, 2024
fc1188a
docs(changeset): Added `isPrivateKeyEvm` function for validating EVM …
ljankovic-txfusion Nov 22, 2024
366aab5
refactor: simplify address validation and reorganize chain utils
ljankovic-txfusion Nov 22, 2024
0b793c7
chore: change cli changeset to minor
ljankovic-txfusion Nov 22, 2024
24b0c55
refactor: update SignerConfig address type to use Address from hyperl…
ljankovic-txfusion Nov 25, 2024
2076ef6
refactor: move CommandType enum to signCommands.ts
ljankovic-txfusion Nov 25, 2024
e61baff
fix: passed key used for setting signer
ljankovic-txfusion Nov 25, 2024
2d08d1e
Merge remote-tracking branch 'origin/main' into feat/key-command
mortezashojaei Nov 27, 2024
92115c0
fix: update getWarpCoreConfigOrExit import on MultiChainResolver
mortezashojaei Nov 27, 2024
c6cc7e9
Merge remote-tracking branch 'origin-root/main'
mortezashojaei Nov 27, 2024
0c8dc01
Merge remote-tracking branch 'origin-root/main' into feat/key-command
mortezashojaei Nov 27, 2024
ccc7df6
fix: no-unused-vars linting issues
mortezashojaei Nov 27, 2024
bdf0107
minor: remove catch unused param
mortezashojaei Nov 27, 2024
e13e08a
Merge branch 'hyperlane-xyz:main' into main
mshojaei-txfusion Nov 28, 2024
0546e10
Merge branch 'hyperlane-xyz:main' into main
mshojaei-txfusion Nov 28, 2024
2ee37d4
Merge branch 'hyperlane-xyz:main' into main
mshojaei-txfusion Nov 28, 2024
7770bd7
Merge branch 'hyperlane-xyz:main' into main
mshojaei-txfusion Nov 29, 2024
21758af
fix: read multiProtocolSigner from sginer middleware on warp init
mortezashojaei Nov 29, 2024
38310f8
refactor: standardize signer address handling on context
mortezashojaei Dec 4, 2024
6e437c7
feat(cli): Add 'check' command to SIGN_COMMANDS and use signer for co…
mortezashojaei Dec 4, 2024
4820623
fix: handle warp check as a sign command on signer strategies
mortezashojaei Dec 4, 2024
3146e93
fix: handle warp read and warp check as sign command temporary
mortezashojaei Dec 4, 2024
fa2b0e8
chore: fix typo
mortezashojaei Dec 5, 2024
7d6a156
Merge branch 'hyperlane-xyz:main' into main
mshojaei-txfusion Dec 5, 2024
b90d0f7
Merge branch 'hyperlane-xyz:main' into main
mshojaei-txfusion Dec 5, 2024
80533e1
Merge branch 'main' into feat/key-command
mortezashojaei Dec 5, 2024
4e3b65c
chore: modify type of signer on context
mortezashojaei Dec 5, 2024
e5a63c9
fix: remove unused variables
mortezashojaei Dec 6, 2024
c33d90f
Merge branch 'hyperlane-xyz:main' into main
mshojaei-txfusion Dec 6, 2024
7bf044f
Merge branch 'main' into feat/key-command
mortezashojaei Dec 6, 2024
96322c5
fix: resolve chais when there is remoteIcaRouters on core apply
mortezashojaei Dec 6, 2024
1eb69e9
refactor(resolver): enhance core apply chains resolution with EvmCore…
mortezashojaei Dec 6, 2024
676f22a
Merge branch 'main' of github.com:hyperlane-xyz/hyperlane-monorepo in…
ljankovic-txfusion Dec 10, 2024
bae0f81
feat(sdk): add optional userAddress and privateKey to JsonRpcTxSubmit…
ljankovic-txfusion Dec 10, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"type": "node",
"request": "launch",
"name": "Launch Program",
"skipFiles": ["<node_internals>/**"],
"program": "$${workspaceFolder}/**/*.ts",
"outFiles": ["${workspaceFolder}/**/*.js"]
}
]
}
5 changes: 4 additions & 1 deletion typescript/cli/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,11 @@ import { registryCommand } from './src/commands/registry.js';
import { relayerCommand } from './src/commands/relayer.js';
import { sendCommand } from './src/commands/send.js';
import { statusCommand } from './src/commands/status.js';
import { strategyCommand } from './src/commands/strategy.js';
import { submitCommand } from './src/commands/submit.js';
import { validatorCommand } from './src/commands/validator.js';
import { warpCommand } from './src/commands/warp.js';
import { contextMiddleware } from './src/context/context.js';
import { contextMiddleware, signerMiddleware } from './src/context/context.js';
import { configureLogger, errorRed } from './src/logger.js';
import { checkVersion } from './src/utils/version-check.js';
import { VERSION } from './src/version.js';
Expand Down Expand Up @@ -55,6 +56,7 @@ try {
configureLogger(argv.log as LogFormat, argv.verbosity as LogLevel);
},
contextMiddleware,
signerMiddleware,
])
.command(avsCommand)
.command(configCommand)
Expand All @@ -69,6 +71,7 @@ try {
.command(submitCommand)
.command(validatorCommand)
.command(warpCommand)
.command(strategyCommand)
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can we alphabetize this?

.version(VERSION)
.demandCommand()
.strict()
Expand Down
8 changes: 8 additions & 0 deletions typescript/cli/src/commands/options.ts
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ export const DEFAULT_WARP_ROUTE_DEPLOYMENT_CONFIG_PATH =
'./configs/warp-route-deployment.yaml';

export const DEFAULT_CORE_DEPLOYMENT_CONFIG_PATH = './configs/core-config.yaml';
export const DEFAULT_STRATEGY_CONFIG_PATH = `${os.homedir()}/.hyperlane/strategies/default-strategy.yaml`;

export const warpDeploymentConfigCommandOption: Options = {
type: 'string',
Expand Down Expand Up @@ -127,6 +128,13 @@ export const chainTargetsCommandOption: Options = {
alias: 'c',
};

export const strategyConfigUrlCommandOption: Options = {
type: 'string',
description: 'A path to a JSON or YAML file with a strategy config.',
default: DEFAULT_STRATEGY_CONFIG_PATH,
alias: 's',
};

export const outputFileCommandOption = (
defaultPath?: string,
demandOption = false,
Expand Down
4 changes: 2 additions & 2 deletions typescript/cli/src/commands/send.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,8 @@ export const messageOptions: { [k: string]: Options } = {
};

export interface MessageOptionsArgTypes {
origin?: string;
destination?: string;
origin: string;
destination: string;
timeout: number;
quick: boolean;
relay: boolean;
Expand Down
2 changes: 1 addition & 1 deletion typescript/cli/src/commands/signCommands.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// Commands that send tx and require a key to sign.
// It's useful to have this listed here so the context
// middleware can request keys up front when required.
export const SIGN_COMMANDS = ['deploy', 'send', 'status', 'submit'];
export const SIGN_COMMANDS = ['deploy', 'send', 'status', 'apply'];

export function isSignCommand(argv: any): boolean {
return (
Expand Down
207 changes: 207 additions & 0 deletions typescript/cli/src/commands/strategy.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,207 @@
// import { input, select } from '@inquirer/prompts';
import { input, select } from '@inquirer/prompts';
import { ethers } from 'ethers';
import { stringify as yamlStringify } from 'yaml';
import { CommandModule } from 'yargs';

import {
ChainSubmissionStrategy,
ChainSubmissionStrategySchema,
TxSubmitterType,
} from '@hyperlane-xyz/sdk';
import { ProtocolType, assert } from '@hyperlane-xyz/utils';

import { CommandModuleWithWriteContext } from '../context/types.js';
import {
errorRed,
log,
logBlue,
logCommandHeader,
logGreen,
} from '../logger.js';
import { runSingleChainSelectionStep } from '../utils/chains.js';
import {
indentYamlOrJson,
readYamlOrJson,
writeYamlOrJson,
} from '../utils/files.js';

import {
DEFAULT_STRATEGY_CONFIG_PATH,
outputFileCommandOption,
} from './options.js';

/**
* Parent command
*/
export const strategyCommand: CommandModule = {
command: 'strategy',
describe: 'Manage Hyperlane deployment strategies',
builder: (yargs) => yargs.command(init).version(false).demandCommand(),
handler: () => log('Command required'),
};

export const init: CommandModuleWithWriteContext<{
chain: string;
config: string;
}> = {
command: 'init',
describe: 'Initiates strategy',
builder: {
config: outputFileCommandOption(
DEFAULT_STRATEGY_CONFIG_PATH,
false,
'The path to output a Strategy Config JSON or YAML file.',
),
type: {
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do we need this? users are prompted to select a set, but in this case we also allow users to enter their own type (i believe this will fail for unsupported submitter types)?

i suggest we just stick to 1: prompt users to select

type: 'string',
description:
'Type of submitter (jsonRpc, impersonatedAccount, gnosisSafe, gnosisSafeTxBuilder)',
},
safeAddress: {
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

since it looks like we prompt these based on the type, do we need this?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You are right!

type: 'string',
description:
'Safe address (required for gnosisSafe and gnosisSafeTxBuilder types)',
},
userAddress: {
type: 'string',
description: 'User address (required for impersonatedAccount type)',
},
},
handler: async ({
context,
type: inputType,
safeAddress: inputSafeAddress,
userAddress: inputUserAddress,
}) => {
logCommandHeader(`Hyperlane Key Init`);
let defaultStrategy;
try {
defaultStrategy = await readYamlOrJson(DEFAULT_STRATEGY_CONFIG_PATH);
} catch (e) {
defaultStrategy = writeYamlOrJson(
DEFAULT_STRATEGY_CONFIG_PATH,
{},
'yaml',
);
}

const chain = await runSingleChainSelectionStep(context.chainMetadata);
const chainProtocol = context.chainMetadata[chain].protocol;
assert(chainProtocol === ProtocolType.Ethereum, 'Incompatible protocol');
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is it because we only use ethers?

wondering if we should use MultiProtocolProvider here.


// If type wasn't provided via command line, prompt for it
const type =
inputType ||
(await select({
message: 'Enter the type of submitter',
choices: Object.values(TxSubmitterType).map((value) => ({
name: value,
value: value,
})),
}));

const submitter: any = {
type: type,
};

// Configure submitter based on type
switch (type) {
case TxSubmitterType.JSON_RPC:
submitter.privateKey = await input({
message: 'Enter your private key',
validate: (pk) => isValidPrivateKey(pk),
});
submitter.chain = chain;
break;

case TxSubmitterType.IMPERSONATED_ACCOUNT:
submitter.userAddress =
inputUserAddress ||
(await input({
message: 'Enter the user address to impersonate',
validate: (address) => {
try {
return ethers.utils.isAddress(address)
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we have an isAddress() util

? true
: 'Invalid Ethereum address';
} catch {
return 'Invalid Ethereum address';
}
},
}));
assert(
submitter.userAddress,
'User address is required for impersonated account',
);
break;

case TxSubmitterType.GNOSIS_SAFE:
case TxSubmitterType.GNOSIS_TX_BUILDER:
submitter.safeAddress =
inputSafeAddress ||
(await input({
message: 'Enter the Safe address',
validate: (address) => {
try {
return ethers.utils.isAddress(address)
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we have an isAddress() util

? true
: 'Invalid Safe address';
} catch {
return 'Invalid Safe address';
}
},
}));
assert(
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

don't need to assert since user has entered it above

submitter.safeAddress,
'Safe address is required for Gnosis Safe',
);
submitter.chain = chain;

if (type === TxSubmitterType.GNOSIS_TX_BUILDER) {
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do we need this? already inside of case TxSubmitterType.GNOSIS_TX_BUILDER

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On lines 139 & 140 we handle gnosis safe and tx builder(uses 1.0 as the default version):

      case TxSubmitterType.GNOSIS_SAFE:
      case TxSubmitterType.GNOSIS_TX_BUILDER:

submitter.version = await input({
message: 'Enter the Safe version (default: 1.0)',
default: '1.0',
});
}
break;

default:
throw new Error(`Unsupported submitter type: ${type}`);
}

const result: ChainSubmissionStrategy = {
...defaultStrategy, // if there are changes in ChainSubmissionStrategy, the defaultStrategy may no longer be compatible
[chain]: {
submitter: submitter,
},
};

try {
const strategyConfig = ChainSubmissionStrategySchema.parse(result);
logBlue(
`Strategy config is valid, writing to file ${DEFAULT_STRATEGY_CONFIG_PATH}:\n`,
);
log(indentYamlOrJson(yamlStringify(strategyConfig, null, 2), 4));

writeYamlOrJson(DEFAULT_STRATEGY_CONFIG_PATH, strategyConfig);
logGreen('✅ Successfully created new key config.');
} catch (e) {
errorRed(
`Key config is invalid, please check the submitter configuration.`,
);
throw e;
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no need to rethrow. just let parse() do it

}
process.exit(0);
},
};

function isValidPrivateKey(privateKey: string): boolean {
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

could be useful in other places. consider moving to utils

try {
// Attempt to create a Wallet instance with the private key
const wallet = new ethers.Wallet(privateKey);
return wallet.privateKey === privateKey;
} catch (error) {
return false;
}
}
16 changes: 16 additions & 0 deletions typescript/cli/src/config/strategy.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import {
ChainSubmissionStrategy,
ChainSubmissionStrategySchema,
} from '@hyperlane-xyz/sdk';
import { assert } from '@hyperlane-xyz/utils';

import { readYamlOrJson } from '../utils/files.js';

export async function readDefaultStrategyConfig(
filePath: string,
): Promise<ChainSubmissionStrategy> {
const config = readYamlOrJson(filePath);
assert(config, `No default strategy config found at ${filePath}`);
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no need to assert, readYamlOrJson will throw


return ChainSubmissionStrategySchema.parse(config);
}
Loading