chore: Upgrade to ESlint 9 and forbid import cycles (#4897)

### Description

- Upgrade from eslint 8 -> 9
- Forbid import cycles and self imports
- Fix lint errors caught by v9 but not v8
- Include utils package in CI linting

**No semantic changes, just some shuffling of things around to avoid
cycles**

Fixes https://github.com/hyperlane-xyz/hyperlane-monorepo/issues/4898


https://github.com/import-js/eslint-plugin-import/blob/main/docs/rules/no-cycle.md

https://github.com/import-js/eslint-plugin-import/blob/main/docs/rules/no-self-import.md
pull/4824/merge
J M Rossy 5 days ago committed by GitHub
parent d51815760b
commit fa6d5f5c63
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 5
      .changeset/spotty-pumpkins-buy.md
  2. 5
      .changeset/yellow-baboons-kneel.md
  3. 4
      .eslintignore
  4. 65
      .eslintrc
  5. 6
      .github/workflows/test.yml
  6. 115
      eslint.config.mjs
  7. 10
      package.json
  8. 6
      typescript/ccip-server/.eslintrc
  9. 17
      typescript/ccip-server/eslint.config.mjs
  10. 3
      typescript/ccip-server/package.json
  11. 14
      typescript/ccip-server/src/server.ts
  12. 4
      typescript/ccip-server/src/services/LightClientService.ts
  13. 8
      typescript/ccip-server/src/services/ProofsService.ts
  14. 9
      typescript/ccip-server/tsconfig.json
  15. 2
      typescript/cli/.eslintignore
  16. 6
      typescript/cli/.eslintrc
  17. 20
      typescript/cli/eslint.config.mjs
  18. 11
      typescript/cli/package.json
  19. 2
      typescript/cli/src/avs/check.ts
  20. 1
      typescript/cli/src/check/warp.ts
  21. 2
      typescript/cli/src/commands/relayer.ts
  22. 2
      typescript/cli/src/commands/warp.ts
  23. 2
      typescript/cli/src/config/agent.ts
  24. 9
      typescript/cli/src/config/submit.ts
  25. 2
      typescript/cli/src/deploy/core.ts
  26. 3
      typescript/cli/src/deploy/dry-run.ts
  27. 4
      typescript/cli/src/deploy/utils.ts
  28. 5
      typescript/cli/src/deploy/warp.ts
  29. 2
      typescript/cli/src/read/warp.ts
  30. 2
      typescript/cli/src/status/message.ts
  31. 2
      typescript/cli/src/utils/env.ts
  32. 6
      typescript/cli/src/utils/files.ts
  33. 43
      typescript/cli/src/utils/input.ts
  34. 35
      typescript/cli/src/utils/warp.ts
  35. 4
      typescript/cli/src/validator/preFlightCheck.ts
  36. 5
      typescript/helloworld/.eslintignore
  37. 39
      typescript/helloworld/.eslintrc
  38. 17
      typescript/helloworld/eslint.config.mjs
  39. 13
      typescript/helloworld/package.json
  40. 7
      typescript/sdk/.eslintrc
  41. 25
      typescript/sdk/eslint.config.mjs
  42. 10
      typescript/sdk/package.json
  43. 5
      typescript/sdk/src/consts/.eslintrc
  44. 1
      typescript/sdk/src/consts/multisigIsmVerifyCosts.ts
  45. 4
      typescript/sdk/src/core/CoreDeployer.hardhat-test.ts
  46. 5
      typescript/sdk/src/core/EvmCoreModule.ts
  47. 8
      typescript/sdk/src/core/HyperlaneRelayer.ts
  48. 4
      typescript/sdk/src/core/schemas.ts
  49. 2
      typescript/sdk/src/deploy/HyperlaneDeployer.ts
  50. 5
      typescript/sdk/src/deploy/verify/.eslintrc
  51. 2
      typescript/sdk/src/deploy/verify/ContractVerifier.ts
  52. 1
      typescript/sdk/src/gas/adapters/serialization.ts
  53. 2
      typescript/sdk/src/gas/types.ts
  54. 1
      typescript/sdk/src/hook/EvmHookModule.hardhat-test.ts
  55. 2
      typescript/sdk/src/hook/EvmHookModule.ts
  56. 1
      typescript/sdk/src/hook/EvmHookReader.test.ts
  57. 4
      typescript/sdk/src/hook/EvmHookReader.ts
  58. 96
      typescript/sdk/src/hook/schemas.ts
  59. 97
      typescript/sdk/src/hook/types.ts
  60. 7
      typescript/sdk/src/index.ts
  61. 1
      typescript/sdk/src/ism/EvmIsmModule.hardhat-test.ts
  62. 2
      typescript/sdk/src/ism/EvmIsmModule.ts
  63. 8
      typescript/sdk/src/ism/EvmIsmReader.ts
  64. 2
      typescript/sdk/src/ism/HyperlaneIsmFactory.ts
  65. 7
      typescript/sdk/src/ism/metadata/aggregation.ts
  66. 10
      typescript/sdk/src/ism/metadata/arbL2ToL1.hardhat-test.ts
  67. 2
      typescript/sdk/src/ism/metadata/arbL2ToL1.ts
  68. 6
      typescript/sdk/src/ism/metadata/builder.hardhat-test.ts
  69. 86
      typescript/sdk/src/ism/metadata/builder.ts
  70. 41
      typescript/sdk/src/ism/metadata/decode.ts
  71. 2
      typescript/sdk/src/ism/metadata/multisig.ts
  72. 2
      typescript/sdk/src/ism/metadata/null.ts
  73. 9
      typescript/sdk/src/ism/metadata/routing.ts
  74. 32
      typescript/sdk/src/ism/metadata/types.ts
  75. 103
      typescript/sdk/src/ism/schemas.ts
  76. 3
      typescript/sdk/src/ism/types.test.ts
  77. 110
      typescript/sdk/src/ism/types.ts
  78. 2
      typescript/sdk/src/ism/utils.ts
  79. 5
      typescript/sdk/src/middleware/liquidity-layer/.eslintrc
  80. 27
      typescript/sdk/src/middleware/liquidity-layer/LiquidityLayerApp.ts
  81. 4
      typescript/sdk/src/providers/SmartProvider/SmartProvider.ts
  82. 3
      typescript/sdk/src/providers/transactions/submitter/builder/TxSubmitterBuilder.ts
  83. 43
      typescript/sdk/src/router/schemas.ts
  84. 49
      typescript/sdk/src/router/types.ts
  85. 2
      typescript/sdk/src/token/EvmERC20WarpRouteReader.ts
  86. 2
      typescript/sdk/src/token/adapters/CosmWasmTokenAdapter.test.ts
  87. 2
      typescript/sdk/src/token/checker.ts
  88. 1
      typescript/sdk/src/token/deploy.ts
  89. 2
      typescript/sdk/src/token/schemas.ts
  90. 5
      typescript/sdk/src/utils/.eslintrc
  91. 2
      typescript/sdk/src/utils/gnosisSafe.js
  92. 2
      typescript/sdk/src/utils/logUtils.ts
  93. 1
      typescript/sdk/src/utils/sealevelSerialization.ts
  94. 3
      typescript/utils/eslint.config.mjs
  95. 8
      typescript/utils/package.json
  96. 12
      typescript/utils/src/addresses.ts
  97. 2
      typescript/utils/src/amount.ts
  98. 4
      typescript/utils/src/base64.ts
  99. 4
      typescript/utils/src/big-numbers.ts
  100. 2
      typescript/utils/src/env.ts
  101. Some files were not shown because too many files have changed in this diff Show More

@ -0,0 +1,5 @@
---
'@hyperlane-xyz/utils': minor
---
Add toUpperCamelCase and deepFind functionss

@ -0,0 +1,5 @@
---
'@hyperlane-xyz/sdk': minor
---
Add decodeIsmMetadata function

@ -1,4 +0,0 @@
node_modules
dist
coverage
*.cts

@ -1,65 +0,0 @@
{
"env": {
"node": true,
"browser": true,
"es2021": true
},
"root": true,
"parser": "@typescript-eslint/parser",
"parserOptions": {
"ecmaVersion": 12,
"sourceType": "module",
"project": "./tsconfig.json"
},
"plugins": ["@typescript-eslint","jest"],
"extends": [
"eslint:recommended",
"plugin:@typescript-eslint/recommended",
"prettier"
],
"rules": {
"no-console": ["error"],
"no-eval": ["error"],
"no-extra-boolean-cast": ["error"],
"no-ex-assign": ["error"],
"no-constant-condition": ["off"],
"no-return-await": ["error"],
"no-restricted-imports": ["error", {
"name": "console",
"message": "Please use a logger and/or the utils' package assert"
}, {
"name": "fs",
"message": "Avoid use of node-specific libraries"
}],
"guard-for-in": ["error"],
"@typescript-eslint/ban-ts-comment": ["off"],
"@typescript-eslint/explicit-module-boundary-types": ["off"],
"@typescript-eslint/no-explicit-any": ["off"],
"@typescript-eslint/no-floating-promises": ["error"],
"@typescript-eslint/no-non-null-assertion": ["off"],
"@typescript-eslint/no-require-imports": ["warn"],
"@typescript-eslint/no-unused-vars": [
"error",
{
"argsIgnorePattern": "^_",
"varsIgnorePattern": "^_",
"caughtErrorsIgnorePattern": "^_"
}
],
"@typescript-eslint/ban-types": [
"error",
{
"types": {
// Unban the {} type which is a useful shorthand for non-nullish value
"{}": false
},
"extendDefaults": true
}
],
"jest/no-disabled-tests": "warn",
"jest/no-focused-tests": "error",
"jest/no-identical-title": "error",
"jest/prefer-to-have-length": "warn",
"jest/valid-expect": "error"
}
}

@ -73,6 +73,12 @@ jobs:
key: ${{ runner.os }}-yarn-4.5.1-cache-${{ hashFiles('./yarn.lock') }}
fail-on-cache-miss: true
# Build required before linting or the intra-monorepo package cycle checking won't work
- name: yarn-build
uses: ./.github/actions/yarn-build-with-cache
with:
ref: ${{ github.event.pull_request.head.sha || github.sha }}
- name: lint
run: yarn lint

@ -0,0 +1,115 @@
import { FlatCompat } from '@eslint/eslintrc';
import js from '@eslint/js';
import typescriptEslint from '@typescript-eslint/eslint-plugin';
import tsParser from '@typescript-eslint/parser';
import importPlugin from 'eslint-plugin-import';
import jest from 'eslint-plugin-jest';
import globals from 'globals';
import path from 'node:path';
import { fileURLToPath } from 'node:url';
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
export const compat = new FlatCompat({
baseDirectory: __dirname,
recommendedConfig: js.configs.recommended,
allConfig: js.configs.all,
});
export default [
{
ignores: [
'**/node_modules',
'**/dist',
'**/coverage',
'**/*.cjs',
'**/*.cts',
'**/*.mjs',
'jest.config.js',
],
},
...compat.extends(
'eslint:recommended',
'plugin:import/recommended',
'plugin:import/typescript',
'plugin:@typescript-eslint/recommended',
'prettier',
),
{
plugins: {
import: importPlugin,
'@typescript-eslint': typescriptEslint,
jest,
},
languageOptions: {
globals: {
...globals.node,
...globals.browser,
},
parser: tsParser,
ecmaVersion: 12,
sourceType: 'module',
parserOptions: {
project: './tsconfig.json',
},
},
settings: {
'import/resolver': {
typescript: true,
node: true,
},
},
rules: {
'guard-for-in': ['error'],
'import/no-cycle': ['error'],
'import/no-self-import': ['error'],
'import/no-named-as-default-member': ['off'],
'no-console': ['error'],
'no-eval': ['error'],
'no-extra-boolean-cast': ['error'],
'no-ex-assign': ['error'],
'no-constant-condition': ['off'],
'no-return-await': ['error'],
'no-restricted-imports': [
'error',
{
name: 'console',
message: 'Please use a logger and/or the utils package assert',
},
{
name: 'fs',
message: 'Avoid use of node-specific libraries',
},
],
'@typescript-eslint/ban-ts-comment': ['off'],
'@typescript-eslint/explicit-module-boundary-types': ['off'],
'@typescript-eslint/no-explicit-any': ['off'],
'@typescript-eslint/no-floating-promises': ['error'],
'@typescript-eslint/no-non-null-assertion': ['off'],
'@typescript-eslint/no-require-imports': ['warn'],
'@typescript-eslint/no-unused-expressions': ['off'],
'@typescript-eslint/no-empty-object-type': ['off'],
'@typescript-eslint/no-unused-vars': [
'error',
{
argsIgnorePattern: '^_',
varsIgnorePattern: '^_',
caughtErrorsIgnorePattern: '^_',
},
],
'jest/no-disabled-tests': 'warn',
'jest/no-focused-tests': 'error',
'jest/no-identical-title': 'error',
'jest/prefer-to-have-length': 'warn',
'jest/valid-expect': 'error',
},
},
];

@ -3,11 +3,14 @@
"description": "A yarn workspace of core Hyperlane packages",
"version": "0.0.0",
"devDependencies": {
"@eslint/js": "^9.15.0",
"@trivago/prettier-plugin-sort-imports": "^4.2.1",
"@typescript-eslint/eslint-plugin": "^7.4.0",
"@typescript-eslint/parser": "^7.4.0",
"eslint": "^8.57.0",
"@typescript-eslint/eslint-plugin": "^8.1.6",
"@typescript-eslint/parser": "^8.1.6",
"eslint": "^9.15.0",
"eslint-config-prettier": "^9.1.0",
"eslint-import-resolver-typescript": "^3.6.3",
"eslint-plugin-import": "^2.31.0",
"eslint-plugin-jest": "^28.2.0",
"husky": "^8.0.0",
"lint-staged": "^12.4.3",
@ -41,6 +44,7 @@
"async": "^2.6.4",
"fetch-ponyfill": "^7.1",
"flat": "^5.0.2",
"globals": "^14.0.0",
"lodash": "^4.17.21",
"recursive-readdir": "^2.2.3",
"underscore": "^1.13",

@ -1,6 +0,0 @@
{
"rules": {
"no-console": ["off"]
}
}

@ -0,0 +1,17 @@
import MonorepoDefaults from '../../eslint.config.mjs';
export default [
...MonorepoDefaults,
{
files: ['./src/**/*.ts'],
},
{
rules: {
'no-console': ['off'],
'no-restricted-imports': ['off'],
},
},
{
ignores: ['**/__mocks__/*','**/tests/*',]
}
];

@ -12,9 +12,11 @@
"node": ">=16"
},
"scripts": {
"build": "tsc -p tsconfig.json",
"start": "tsx src/server.ts",
"dev": "nodemon src/server.ts",
"test": "jest",
"lint": "eslint -c ./eslint.config.mjs",
"prettier": "prettier --write ./src/* ./tests/"
},
"author": "brolee",
@ -22,6 +24,7 @@
"devDependencies": {
"@jest/globals": "^29.7.0",
"@types/node": "^16.9.1",
"eslint": "^9.15.0",
"jest": "^29.7.0",
"nodemon": "^3.0.3",
"prettier": "^2.8.8",

@ -6,12 +6,14 @@ import { ProofsService } from './services/ProofsService';
// Initialize Services
const proofsService = new ProofsService(
config.LIGHT_CLIENT_ADDR,
config.RPC_ADDRESS,
config.STEP_FN_ID,
config.CHAIN_ID,
config.SUCCINCT_PLATFORM_URL,
config.SUCCINCT_API_KEY,
{
lightClientAddress: config.LIGHT_CLIENT_ADDR,
stepFunctionId: config.STEP_FN_ID,
platformUrl: config.SUCCINCT_PLATFORM_URL,
apiKey: config.SUCCINCT_API_KEY,
},
{ url: config.RPC_ADDRESS, chainId: config.CHAIN_ID },
{ url: `${config.SERVER_URL_PREFIX}:${config.SERVER_PORT}` },
);
// Initialize Server and add Service handlers

@ -27,8 +27,8 @@ class LightClientService {
* @param slot
* @returns
*/
async getSyncCommitteePoseidons(slot: bigint): Promise<string> {
return await this.lightClientContract.syncCommitteePoseidons(
getSyncCommitteePoseidons(slot: bigint): Promise<string> {
return this.lightClientContract.syncCommitteePoseidons(
this.getSyncCommitteePeriod(slot),
);
}

@ -4,8 +4,7 @@ import { TelepathyCcipReadIsmAbi } from '../abis/TelepathyCcipReadIsmAbi';
import { HyperlaneService } from './HyperlaneService';
import { LightClientService, SuccinctConfig } from './LightClientService';
import { RPCService } from './RPCService';
import { ProofResult } from './RPCService';
import { ProofResult, RPCService } from './RPCService';
import { ProofStatus } from './common/ProofStatusEnum';
type RPCConfig = {
@ -100,10 +99,7 @@ class ProofsService {
);
const slot = await this.lightClientService.calculateSlot(BigInt(timestamp));
const syncCommitteePoseidon = ''; // TODO get from LC
return await this.lightClientService.requestProof(
syncCommitteePoseidon,
slot,
);
return this.lightClientService.requestProof(syncCommitteePoseidon, slot);
}
/**

@ -0,0 +1,9 @@
{
"extends": "../tsconfig.json",
"compilerOptions": {
"outDir": "./dist/",
"rootDir": "./src"
},
"exclude": ["./node_modules/", "./dist/"],
"include": ["./src/*.ts"]
}

@ -1,2 +0,0 @@
node_modules
dist

@ -1,6 +0,0 @@
{
"rules": {
"no-console": ["off"],
"no-restricted-imports": ["off"]
}
}

@ -0,0 +1,20 @@
import MonorepoDefaults from '../../eslint.config.mjs';
export default [
...MonorepoDefaults,
{
files: ['./src/**/*.ts', './cli.ts', './env.ts'],
},
{
rules: {
'no-console': ['off'],
'no-restricted-imports': ['off'],
},
},
{
ignores: ['./src/tests/**/*.ts'],
rules: {
'import/no-cycle': ['off'],
},
},
];

@ -26,18 +26,21 @@
"zx": "^8.1.4"
},
"devDependencies": {
"@eslint/js": "^9.15.0",
"@ethersproject/abi": "*",
"@ethersproject/providers": "*",
"@types/chai-as-promised": "^8",
"@types/mocha": "^10.0.1",
"@types/node": "^18.14.5",
"@types/yargs": "^17.0.24",
"@typescript-eslint/eslint-plugin": "^7.4.0",
"@typescript-eslint/parser": "^7.4.0",
"@typescript-eslint/eslint-plugin": "^8.1.6",
"@typescript-eslint/parser": "^8.1.6",
"chai": "^4.5.0",
"chai-as-promised": "^8.0.0",
"eslint": "^8.57.0",
"eslint": "^9.15.0",
"eslint-config-prettier": "^9.1.0",
"eslint-import-resolver-typescript": "^3.6.3",
"eslint-plugin-import": "^2.31.0",
"mocha": "^10.2.0",
"prettier": "^2.8.8",
"typescript": "5.3.3"
@ -47,7 +50,7 @@
"build": "yarn version:update && tsc",
"dev": "yarn version:update && tsc --watch",
"clean": "rm -rf ./dist",
"lint": "eslint . --ext .ts",
"lint": "eslint -c ./eslint.config.mjs",
"prettier": "prettier --write ./src ./examples",
"test:ci": "yarn mocha --config .mocharc.json",
"test:e2e": "./scripts/run-e2e-test.sh",

@ -429,7 +429,7 @@ const getEcdsaStakeRegistryAddress = (
): Address | undefined => {
try {
return avsAddresses[chain]['ecdsaStakeRegistry'];
} catch (err) {
} catch {
topLevelErrors.push(
` EcdsaStakeRegistry address not found for ${chain}`,
);

@ -4,7 +4,6 @@ import { WarpRouteDeployConfig, normalizeConfig } from '@hyperlane-xyz/sdk';
import { ObjectDiff, diffObjMerge } from '@hyperlane-xyz/utils';
import { log, logGreen } from '../logger.js';
import '../utils/output.js';
import { formatYamlViolationsOutput } from '../utils/output.js';
export async function runWarpRouteCheck({

@ -9,7 +9,7 @@ import { Address } from '@hyperlane-xyz/utils';
import { CommandModuleWithContext } from '../context/types.js';
import { log } from '../logger.js';
import { tryReadJson, writeJson } from '../utils/files.js';
import { getWarpCoreConfigOrExit } from '../utils/input.js';
import { getWarpCoreConfigOrExit } from '../utils/warp.js';
import {
agentTargetsCommandOption,

@ -23,8 +23,8 @@ import {
removeEndingSlash,
writeYamlOrJson,
} from '../utils/files.js';
import { getWarpCoreConfigOrExit } from '../utils/input.js';
import { selectRegistryWarpRoute } from '../utils/tokens.js';
import { getWarpCoreConfigOrExit } from '../utils/warp.js';
import { runVerifyWarpRoute } from '../verify/warp.js';
import {

@ -99,7 +99,7 @@ async function getStartBlocks(
try {
const deployedBlock = await mailbox.deployedBlock();
return deployedBlock.toNumber();
} catch (err) {
} catch {
errorRed(
`❌ Failed to get deployed block to set an index for ${chain}, this is potentially an issue with rpc provider or a misconfiguration`,
);

@ -3,9 +3,8 @@ import { stringify as yamlStringify } from 'yaml';
import {
AnnotatedEV5Transaction,
SubmissionStrategy,
getChainIdFromTxs,
} from '@hyperlane-xyz/sdk';
import { assert, errorToString } from '@hyperlane-xyz/utils';
import { ProtocolType, assert, errorToString } from '@hyperlane-xyz/utils';
import { WriteCommandContext } from '../context/types.js';
import { logGray, logRed } from '../logger.js';
@ -27,17 +26,15 @@ export async function runSubmit({
receiptsFilepath: string;
submissionStrategy: SubmissionStrategy;
}) {
const { chainMetadata, multiProvider } = context;
const { multiProvider } = context;
assert(
submissionStrategy,
'Submission strategy required to submit transactions.\nPlease create a submission strategy. See examples in cli/examples/submit/strategy/*.',
);
const transactions = getTransactions(transactionsFilepath);
const chainId = getChainIdFromTxs(transactions);
const protocol = chainMetadata[chainId].protocol;
const submitterBuilder = await getSubmitterBuilder<typeof protocol>({
const submitterBuilder = await getSubmitterBuilder<ProtocolType>({
submissionStrategy,
multiProvider,
});

@ -1,12 +1,12 @@
import { stringify as yamlStringify } from 'yaml';
import { buildArtifact as coreBuildArtifact } from '@hyperlane-xyz/core/buildArtifact.js';
import { DeployedCoreAddresses } from '@hyperlane-xyz/sdk';
import {
ChainMap,
ChainName,
ContractVerifier,
CoreConfig,
DeployedCoreAddresses,
EvmCoreModule,
ExplorerLicenseType,
} from '@hyperlane-xyz/sdk';

@ -5,12 +5,11 @@ import {
resetFork,
setFork,
} from '@hyperlane-xyz/sdk';
import { toUpperCamelCase } from '@hyperlane-xyz/utils';
import { logGray, logGreen, warnYellow } from '../logger.js';
import { ENV } from '../utils/env.js';
import { toUpperCamelCase } from './utils.js';
/**
* Forks a provided network onto MultiProvider
* @param multiProvider the MultiProvider to be prepared

@ -169,10 +169,6 @@ export async function completeDeploy(
if (isDryRun) await completeDryRun(command);
}
export function toUpperCamelCase(string: string) {
return string.charAt(0).toUpperCase() + string.slice(1);
}
function transformChainMetadataForDisplay(chainMetadata: ChainMetadata) {
return {
Name: chainMetadata.name,

@ -955,7 +955,7 @@ async function getWarpApplySubmitter({
context: WriteCommandContext;
strategyUrl?: string;
}): Promise<TxSubmitterBuilder<ProtocolType>> {
const { chainMetadata, multiProvider } = context;
const { multiProvider } = context;
const submissionStrategy: SubmissionStrategy = strategyUrl
? readChainSubmissionStrategy(strategyUrl)[chain]
@ -966,8 +966,7 @@ async function getWarpApplySubmitter({
},
};
const protocol = chainMetadata[chain].protocol;
return getSubmitterBuilder<typeof protocol>({
return getSubmitterBuilder<ProtocolType>({
submissionStrategy,
multiProvider,
});

@ -15,7 +15,7 @@ import { isAddressEvm, objMap, promiseObjAll } from '@hyperlane-xyz/utils';
import { CommandContext } from '../context/types.js';
import { logGray, logRed, logTable } from '../logger.js';
import { getWarpCoreConfigOrExit } from '../utils/input.js';
import { getWarpCoreConfigOrExit } from '../utils/warp.js';
export async function runWarpRouteRead({
context,

@ -52,7 +52,7 @@ export async function checkMessageStatus({
} else {
try {
dispatchedReceipt = await core.getDispatchTx(origin, messageId);
} catch (e) {
} catch {
logRed(`Failed to infer dispatch transaction for message ${messageId}`);
dispatchTx = await input({

@ -1,4 +1,4 @@
import z from 'zod';
import { z } from 'zod';
const envScheme = z.object({
HYP_KEY: z.string().optional(),

@ -42,7 +42,7 @@ export function isFile(filepath: string) {
if (!filepath) return false;
try {
return fs.existsSync(filepath) && fs.lstatSync(filepath).isFile();
} catch (error) {
} catch {
log(`Error checking for file: ${filepath}`);
return false;
}
@ -70,7 +70,7 @@ export function readJson<T>(filepath: string): T {
export function tryReadJson<T>(filepath: string): T | null {
try {
return readJson(filepath) as T;
} catch (error) {
} catch {
return null;
}
}
@ -98,7 +98,7 @@ export function readYaml<T>(filepath: string): T {
export function tryReadYamlAtPath<T>(filepath: string): T | null {
try {
return readYaml(filepath);
} catch (error) {
} catch {
return null;
}
}

@ -19,19 +19,13 @@ import ansiEscapes from 'ansi-escapes';
import chalk from 'chalk';
import { ProxyAdmin__factory } from '@hyperlane-xyz/core';
import {
ChainName,
DeployedOwnableConfig,
WarpCoreConfig,
} from '@hyperlane-xyz/sdk';
import { ChainName, DeployedOwnableConfig } from '@hyperlane-xyz/sdk';
import { Address, isAddress, rootLogger } from '@hyperlane-xyz/utils';
import { readWarpCoreConfig } from '../config/warp.js';
import { CommandContext } from '../context/types.js';
import { logGray, logRed } from '../logger.js';
import { logGray } from '../logger.js';
import { indentYamlOrJson } from './files.js';
import { selectRegistryWarpRoute } from './tokens.js';
export async function detectAndConfirmOrPrompt(
detect: () => Promise<string | undefined>,
@ -52,8 +46,9 @@ export async function detectAndConfirmOrPrompt(
return detectedValue;
}
}
// eslint-disable-next-line no-empty
} catch (e) {}
} catch {
// Fallback to input prompt
}
return input({ message: `${prompt} ${label}:`, default: detectedValue });
}
@ -136,34 +131,6 @@ export async function setProxyAdminConfig(
}
}
/**
* Gets a {@link WarpCoreConfig} based on the provided path or prompts the user to choose one:
* - if `symbol` is provided the user will have to select one of the available warp routes.
* - if `warp` is provided the config will be read by the provided file path.
* - if none is provided the CLI will exit.
*/
export async function getWarpCoreConfigOrExit({
context,
symbol,
warp,
}: {
context: CommandContext;
symbol?: string;
warp?: string;
}): Promise<WarpCoreConfig> {
let warpCoreConfig: WarpCoreConfig;
if (symbol) {
warpCoreConfig = await selectRegistryWarpRoute(context.registry, symbol);
} else if (warp) {
warpCoreConfig = readWarpCoreConfig(warp);
} else {
logRed(`Please specify either a symbol or warp config`);
process.exit(0);
}
return warpCoreConfig;
}
/**
* Searchable checkbox code
*

@ -0,0 +1,35 @@
import { WarpCoreConfig } from '@hyperlane-xyz/sdk';
import { readWarpCoreConfig } from '../config/warp.js';
import { CommandContext } from '../context/types.js';
import { logRed } from '../logger.js';
import { selectRegistryWarpRoute } from './tokens.js';
/**
* Gets a {@link WarpCoreConfig} based on the provided path or prompts the user to choose one:
* - if `symbol` is provided the user will have to select one of the available warp routes.
* - if `warp` is provided the config will be read by the provided file path.
* - if none is provided the CLI will exit.
*/
export async function getWarpCoreConfigOrExit({
context,
symbol,
warp,
}: {
context: CommandContext;
symbol?: string;
warp?: string;
}): Promise<WarpCoreConfig> {
let warpCoreConfig: WarpCoreConfig;
if (symbol) {
warpCoreConfig = await selectRegistryWarpRoute(context.registry, symbol);
} else if (warp) {
warpCoreConfig = readWarpCoreConfig(warp);
} else {
logRed(`Please specify either a symbol or warp config`);
process.exit(0);
}
return warpCoreConfig;
}

@ -44,7 +44,7 @@ export const checkValidatorSetup = async (
try {
validatorStorageLocations =
await validatorAnnounce.getAnnouncedStorageLocations(validatorsArray);
} catch (e) {
} catch {
errorSet.add('Failed to read announced storage locations on chain.');
}
@ -64,7 +64,7 @@ export const checkValidatorSetup = async (
let s3Validator: S3Validator;
try {
s3Validator = await S3Validator.fromStorageLocation(s3StorageLocation);
} catch (e) {
} catch {
errorRed(
`❌ Failed to fetch storage locations for validator ${validator}, this may be due to the storage location not being an S3 bucket\n\n`,
);

@ -1,5 +0,0 @@
node_modules
dist
coverage
src/types
hardhat.config.ts

@ -1,39 +0,0 @@
{
"env": {
"node": true,
"browser": true,
"es2021": true
},
"root": true,
"parser": "@typescript-eslint/parser",
"parserOptions": {
"ecmaVersion": 12,
"sourceType": "module",
"project": "./tsconfig.json"
},
"plugins": ["@typescript-eslint"],
"extends": [
"eslint:recommended",
"plugin:@typescript-eslint/recommended",
"prettier"
],
"rules": {
"no-eval": ["error"],
"no-ex-assign": ["error"],
"no-constant-condition": ["off"],
"@typescript-eslint/ban-ts-comment": ["off"],
"@typescript-eslint/explicit-module-boundary-types": ["off"],
"@typescript-eslint/no-explicit-any": ["off"],
"@typescript-eslint/no-floating-promises": ["error"],
"@typescript-eslint/no-non-null-assertion": ["off"],
"@typescript-eslint/no-require-imports": ["warn"],
"@typescript-eslint/no-unused-vars": [
"error",
{
"argsIgnorePattern": "^_",
"varsIgnorePattern": "^_",
"caughtErrorsIgnorePattern": "^_"
}
]
}
}

@ -0,0 +1,17 @@
import MonorepoDefaults from '../../eslint.config.mjs';
export default [
...MonorepoDefaults,
{
files: ['./src/**/*.ts'],
},
{
ignores: ["**/src/types/*"],
},
{
ignores: ['./src/scripts'],
rules: {
'no-console': ['off'],
},
},
];

@ -10,17 +10,20 @@
"ethers": "^5.7.2"
},
"devDependencies": {
"@eslint/js": "^9.15.0",
"@nomiclabs/hardhat-ethers": "^2.2.3",
"@nomiclabs/hardhat-waffle": "^2.0.6",
"@trivago/prettier-plugin-sort-imports": "^4.2.1",
"@typechain/ethers-v5": "^11.1.2",
"@typechain/ethers-v6": "^0.5.1",
"@typechain/hardhat": "^9.1.0",
"@typescript-eslint/eslint-plugin": "^7.4.0",
"@typescript-eslint/parser": "^7.4.0",
"@typescript-eslint/eslint-plugin": "^8.1.6",
"@typescript-eslint/parser": "^8.1.6",
"chai": "4.5.0",
"eslint": "^8.57.0",
"eslint": "^9.15.0",
"eslint-config-prettier": "^9.1.0",
"eslint-import-resolver-typescript": "^3.6.3",
"eslint-plugin-import": "^2.31.0",
"ethereum-waffle": "^4.0.10",
"hardhat": "^2.22.2",
"hardhat-gas-reporter": "^1.0.9",
@ -56,7 +59,9 @@
"build": "yarn hardhat-esm compile && tsc",
"clean": "yarn hardhat-esm clean && rm -rf dist cache src/types",
"coverage": "yarn hardhat-esm coverage",
"lint": "solhint contracts/**/*.sol && eslint . --ext .ts",
"lint": "yarn lint:sol && yarn lint:ts",
"lint:sol": "solhint contracts/**/*.sol",
"lint:ts": "eslint -c ./eslint.config.mjs",
"hardhat-esm": "NODE_OPTIONS='--experimental-loader ts-node/esm/transpile-only --no-warnings=ExperimentalWarning' hardhat --config hardhat.config.cts",
"prettier": "prettier --write ./contracts ./src",
"test": "yarn hardhat-esm test ./src/test/**/*.test.ts",

@ -1,7 +0,0 @@
{
"rules": {
"@typescript-eslint/explicit-module-boundary-types": ["warn", {
"allowArgumentsExplicitlyTypedAsAny": true
}]
}
}

@ -0,0 +1,25 @@
import MonorepoDefaults from '../../eslint.config.mjs';
export default [
...MonorepoDefaults,
{
files: ['./src/**/*.ts'],
rules: {
'@typescript-eslint/explicit-module-boundary-types': [
'warn',
{
allowArgumentsExplicitlyTypedAsAny: true,
},
],
},
},
{
ignores: ['./src/ism/metadata/**/*.ts'],
rules: {
'import/no-cycle': ['off'],
},
},
{
ignores: ['src/**/*.js'],
},
];

@ -24,6 +24,7 @@
"zod": "^3.21.2"
},
"devDependencies": {
"@eslint/js": "^9.15.0",
"@nomiclabs/hardhat-ethers": "^2.2.3",
"@nomiclabs/hardhat-waffle": "^2.0.6",
"@types/mocha": "^10.0.1",
@ -31,9 +32,14 @@
"@types/sinon": "^17.0.1",
"@types/sinon-chai": "^3.2.12",
"@types/ws": "^8.5.5",
"@typescript-eslint/eslint-plugin": "^8.1.6",
"@typescript-eslint/parser": "^8.1.6",
"chai": "4.5.0",
"dotenv": "^10.0.0",
"eslint": "^8.57.0",
"eslint": "^9.15.0",
"eslint-config-prettier": "^9.1.0",
"eslint-import-resolver-typescript": "^3.6.3",
"eslint-plugin-import": "^2.31.0",
"ethereum-waffle": "^4.0.10",
"hardhat": "^2.22.2",
"mocha": "^10.2.0",
@ -70,7 +76,7 @@
"dev": "tsc --watch",
"check": "tsc --noEmit",
"clean": "rm -rf ./dist ./cache",
"lint": "eslint src --ext .ts",
"lint": "eslint -c ./eslint.config.mjs",
"prepublishOnly": "yarn build",
"prettier": "prettier --write ./src",
"test": "yarn test:unit && yarn test:hardhat && yarn test:foundry",

@ -1,5 +0,0 @@
{
"rules": {
"sort-keys": ["error"]
}
}

@ -1,4 +1,3 @@
/* eslint-disable sort-keys */
export const multisigIsmVerifyCosts = {
'1': {
'1': 151966,

@ -195,7 +195,7 @@ describe('core', async () => {
try {
await deployer.deploy(coreConfig);
// eslint-disable-next-line no-empty
} catch (e: any) {}
} catch {}
});
afterEach(async () => {
@ -252,7 +252,7 @@ describe('core', async () => {
deployer.chainTimeoutMs = 1;
try {
await deployer.deploy(coreConfig);
} catch (e: any) {
} catch {
// TODO: figure out how to test specific error case
// expect(e.message).to.include('Timed out in 1ms');
}

@ -21,8 +21,6 @@ import {
HyperlaneAddresses,
HyperlaneContractsMap,
} from '../contracts/types.js';
import { DeployedCoreAddresses } from '../core/schemas.js';
import { CoreConfig } from '../core/types.js';
import { HyperlaneProxyFactoryDeployer } from '../deploy/HyperlaneProxyFactoryDeployer.js';
import {
ProxyFactoryFactories,
@ -47,7 +45,8 @@ import { EvmCoreReader } from './EvmCoreReader.js';
import { EvmIcaModule } from './EvmIcaModule.js';
import { HyperlaneCoreDeployer } from './HyperlaneCoreDeployer.js';
import { CoreFactories } from './contracts.js';
import { CoreConfigSchema } from './schemas.js';
import { CoreConfigSchema, DeployedCoreAddresses } from './schemas.js';
import { CoreConfig } from './types.js';
export class EvmCoreModule extends HyperlaneModule<
ProtocolType.Ethereum,

@ -17,10 +17,10 @@ import {
} from '@hyperlane-xyz/utils';
import { DerivedHookConfig, EvmHookReader } from '../hook/EvmHookReader.js';
import { HookConfigSchema } from '../hook/schemas.js';
import { HookConfigSchema } from '../hook/types.js';
import { DerivedIsmConfig, EvmIsmReader } from '../ism/EvmIsmReader.js';
import { BaseMetadataBuilder } from '../ism/metadata/builder.js';
import { IsmConfigSchema } from '../ism/schemas.js';
import { IsmConfigSchema } from '../ism/types.js';
import { MultiProvider } from '../providers/MultiProvider.js';
import { ChainName } from '../types.js';
@ -307,7 +307,7 @@ export class HyperlaneRelayer {
// TODO: handle batching
await this.relayMessage(dispatchReceipt, undefined, dispatchMsg);
} catch (error) {
} catch {
this.logger.error(
`Failed to relay message ${id} (attempt #${attempts + 1})`,
);
@ -320,7 +320,7 @@ export class HyperlaneRelayer {
}
}
protected whitelistChains() {
protected whitelistChains(): string[] | undefined {
return this.whitelist ? Object.keys(this.whitelist) : undefined;
}

@ -1,8 +1,8 @@
import { z } from 'zod';
import { ProxyFactoryFactoriesSchema } from '../deploy/schemas.js';
import { HookConfigSchema } from '../hook/schemas.js';
import { IsmConfigSchema } from '../ism/schemas.js';
import { HookConfigSchema } from '../hook/types.js';
import { IsmConfigSchema } from '../ism/types.js';
import { DeployedOwnableSchema, OwnableSchema } from '../schemas.js';
export const CoreConfigSchema = OwnableSchema.extend({

@ -29,7 +29,7 @@ import {
HyperlaneFactories,
} from '../contracts/types.js';
import { HookConfig } from '../hook/types.js';
import { HyperlaneIsmFactory } from '../ism/HyperlaneIsmFactory.js';
import type { HyperlaneIsmFactory } from '../ism/HyperlaneIsmFactory.js';
import { IsmConfig } from '../ism/types.js';
import { moduleMatchesConfig } from '../ism/utils.js';
import { InterchainAccount } from '../middleware/account/InterchainAccount.js';

@ -1,5 +0,0 @@
{
"rules": {
"no-console": ["off"]
}
}

@ -183,7 +183,7 @@ export class ContractVerifier {
'Parsing response from explorer...',
);
responseJson = JSON.parse(responseTextString);
} catch (error) {
} catch {
verificationLogger.trace(
{
failure: response.statusText,

@ -1,4 +1,3 @@
/* eslint-disable @typescript-eslint/explicit-module-boundary-types */
import { PublicKey } from '@solana/web3.js';
import { Domain } from '@hyperlane-xyz/utils';

@ -5,7 +5,7 @@ import { InterchainGasPaymaster } from '@hyperlane-xyz/core';
import type { Address } from '@hyperlane-xyz/utils';
import type { CheckerViolation } from '../deploy/types.js';
import { IgpSchema } from '../hook/schemas.js';
import { IgpSchema } from '../hook/types.js';
import { ChainMap } from '../types.js';
export type IgpConfig = z.infer<typeof IgpSchema>;

@ -1,4 +1,3 @@
/* eslint-disable no-console */
import { expect } from 'chai';
import { Signer } from 'ethers';
import hre from 'hardhat';

@ -56,13 +56,13 @@ import { normalizeConfig } from '../utils/ism.js';
import { EvmHookReader } from './EvmHookReader.js';
import { DeployedHook, HookFactories, hookFactories } from './contracts.js';
import { HookConfigSchema } from './schemas.js';
import {
AggregationHookConfig,
ArbL2ToL1HookConfig,
DomainRoutingHookConfig,
FallbackRoutingHookConfig,
HookConfig,
HookConfigSchema,
HookType,
IgpHookConfig,
MUTABLE_HOOK_TYPE,

@ -148,7 +148,6 @@ describe('EvmHookReader', () => {
expect(config).to.deep.equal(hookConfig);
});
// eslint-disable-next-line @typescript-eslint/no-empty-function
it('should derive op stack config correctly', async () => {
const mockAddress = randomAddress();
const mockOwner = randomAddress();

@ -269,7 +269,7 @@ export class EvmHookReader extends HyperlaneReader implements HookReader {
this.provider,
);
return oracle.owner();
} catch (error) {
} catch {
this.logger.debug(
'Domain not configured on IGP Hook',
domainId,
@ -451,7 +451,7 @@ export class EvmHookReader extends HyperlaneReader implements HookReader {
if (domainHook !== ethers.constants.AddressZero) {
domainHooks[chainName] = await this.deriveHookConfig(domainHook);
}
} catch (error) {
} catch {
this.logger.debug(
`Domain not configured on ${hook.constructor.name}`,
domainId,

@ -1,96 +0,0 @@
import { z } from 'zod';
import { StorageGasOracleConfigSchema } from '../gas/oracle/types.js';
import { ZHash } from '../metadata/customZodTypes.js';
import { OwnableSchema, PausableSchema } from '../schemas.js';
import {
AggregationHookConfig,
DomainRoutingHookConfig,
FallbackRoutingHookConfig,
HookType,
} from './types.js';
export const ProtocolFeeSchema = OwnableSchema.extend({
type: z.literal(HookType.PROTOCOL_FEE),
beneficiary: z.string(),
maxProtocolFee: z.string(),
protocolFee: z.string(),
});
export const MerkleTreeSchema = z.object({
type: z.literal(HookType.MERKLE_TREE),
});
export const PausableHookSchema = PausableSchema.extend({
type: z.literal(HookType.PAUSABLE),
});
export const OpStackHookSchema = OwnableSchema.extend({
type: z.literal(HookType.OP_STACK),
nativeBridge: z.string(),
destinationChain: z.string(),
});
export const ArbL2ToL1HookSchema = z.object({
type: z.literal(HookType.ARB_L2_TO_L1),
arbSys: z
.string()
.describe(
'precompile for sending messages to L1, interface here: https://github.com/OffchainLabs/nitro-contracts/blob/90037b996509312ef1addb3f9352457b8a99d6a6/src/precompiles/ArbSys.sol#L12',
),
bridge: z
.string()
.optional()
.describe(
'address of the bridge contract on L1, optional only needed for non @arbitrum/sdk chains',
),
destinationChain: z.string(),
childHook: z.lazy((): z.ZodSchema => HookConfigSchema),
});
export const IgpSchema = OwnableSchema.extend({
type: z.literal(HookType.INTERCHAIN_GAS_PAYMASTER),
beneficiary: z.string(),
oracleKey: z.string(),
overhead: z.record(z.number()),
oracleConfig: z.record(StorageGasOracleConfigSchema),
});
export const DomainRoutingHookConfigSchema: z.ZodSchema<DomainRoutingHookConfig> =
z.lazy(() =>
OwnableSchema.extend({
type: z.literal(HookType.ROUTING),
domains: z.record(HookConfigSchema),
}),
);
export const FallbackRoutingHookConfigSchema: z.ZodSchema<FallbackRoutingHookConfig> =
z.lazy(() =>
OwnableSchema.extend({
type: z.literal(HookType.FALLBACK_ROUTING),
domains: z.record(HookConfigSchema),
fallback: HookConfigSchema,
}),
);
export const AggregationHookConfigSchema: z.ZodSchema<AggregationHookConfig> =
z.lazy(() =>
z.object({
type: z.literal(HookType.AGGREGATION),
hooks: z.array(HookConfigSchema),
}),
);
export const HookConfigSchema = z.union([
ZHash,
ProtocolFeeSchema,
PausableHookSchema,
OpStackHookSchema,
MerkleTreeSchema,
IgpSchema,
DomainRoutingHookConfigSchema,
FallbackRoutingHookConfigSchema,
AggregationHookConfigSchema,
ArbL2ToL1HookSchema,
]);

@ -1,18 +1,11 @@
import { z } from 'zod';
import { OwnableConfig } from '../deploy/types.js';
import { StorageGasOracleConfigSchema } from '../gas/oracle/types.js';
import { ZHash } from '../metadata/customZodTypes.js';
import { OwnableSchema, PausableSchema } from '../schemas.js';
import { ChainMap } from '../types.js';
import {
ArbL2ToL1HookSchema,
HookConfigSchema,
IgpSchema,
MerkleTreeSchema,
OpStackHookSchema,
PausableHookSchema,
ProtocolFeeSchema,
} from './schemas.js';
// As found in IPostDispatchHook.sol
export enum OnchainHookType {
UNUSED,
@ -75,3 +68,87 @@ export const MUTABLE_HOOK_TYPE = [
HookType.FALLBACK_ROUTING,
HookType.PAUSABLE,
];
export const ProtocolFeeSchema = OwnableSchema.extend({
type: z.literal(HookType.PROTOCOL_FEE),
beneficiary: z.string(),
maxProtocolFee: z.string(),
protocolFee: z.string(),
});
export const MerkleTreeSchema = z.object({
type: z.literal(HookType.MERKLE_TREE),
});
export const PausableHookSchema = PausableSchema.extend({
type: z.literal(HookType.PAUSABLE),
});
export const OpStackHookSchema = OwnableSchema.extend({
type: z.literal(HookType.OP_STACK),
nativeBridge: z.string(),
destinationChain: z.string(),
});
export const ArbL2ToL1HookSchema = z.object({
type: z.literal(HookType.ARB_L2_TO_L1),
arbSys: z
.string()
.describe(
'precompile for sending messages to L1, interface here: https://github.com/OffchainLabs/nitro-contracts/blob/90037b996509312ef1addb3f9352457b8a99d6a6/src/precompiles/ArbSys.sol#L12',
),
bridge: z
.string()
.optional()
.describe(
'address of the bridge contract on L1, optional only needed for non @arbitrum/sdk chains',
),
destinationChain: z.string(),
childHook: z.lazy((): z.ZodSchema => HookConfigSchema),
});
export const IgpSchema = OwnableSchema.extend({
type: z.literal(HookType.INTERCHAIN_GAS_PAYMASTER),
beneficiary: z.string(),
oracleKey: z.string(),
overhead: z.record(z.number()),
oracleConfig: z.record(StorageGasOracleConfigSchema),
});
export const DomainRoutingHookConfigSchema: z.ZodSchema<DomainRoutingHookConfig> =
z.lazy(() =>
OwnableSchema.extend({
type: z.literal(HookType.ROUTING),
domains: z.record(HookConfigSchema),
}),
);
export const FallbackRoutingHookConfigSchema: z.ZodSchema<FallbackRoutingHookConfig> =
z.lazy(() =>
OwnableSchema.extend({
type: z.literal(HookType.FALLBACK_ROUTING),
domains: z.record(HookConfigSchema),
fallback: HookConfigSchema,
}),
);
export const AggregationHookConfigSchema: z.ZodSchema<AggregationHookConfig> =
z.lazy(() =>
z.object({
type: z.literal(HookType.AGGREGATION),
hooks: z.array(HookConfigSchema),
}),
);
export const HookConfigSchema = z.union([
ZHash,
ProtocolFeeSchema,
PausableHookSchema,
OpStackHookSchema,
MerkleTreeSchema,
IgpSchema,
DomainRoutingHookConfigSchema,
FallbackRoutingHookConfigSchema,
AggregationHookConfigSchema,
ArbL2ToL1HookSchema,
]);

@ -135,12 +135,12 @@ export {
} from './gas/types.js';
export { EvmHookReader } from './hook/EvmHookReader.js';
export { HyperlaneHookDeployer } from './hook/HyperlaneHookDeployer.js';
export { HookConfigSchema } from './hook/schemas.js';
export {
AggregationHookConfig,
DomainRoutingHookConfig,
FallbackRoutingHookConfig,
HookConfig,
HookConfigSchema,
HookType,
IgpHookConfig,
MerkleTreeHookConfig,
@ -150,6 +150,7 @@ export {
} from './hook/types.js';
export { DerivedIsmConfig, EvmIsmReader } from './ism/EvmIsmReader.js';
export { HyperlaneIsmFactory } from './ism/HyperlaneIsmFactory.js';
export { decodeIsmMetadata } from './ism/metadata/decode.js';
export {
buildAggregationIsmConfigs,
buildMultisigIsmConfigs,
@ -522,8 +523,8 @@ export {
AggregationIsmConfigSchema,
IsmConfigSchema,
MultisigIsmConfigSchema,
} from './ism/schemas.js';
export { MailboxClientConfigSchema as mailboxClientConfigSchema } from './router/schemas.js';
} from './ism/types.js';
export { MailboxClientConfigSchema as mailboxClientConfigSchema } from './router/types.js';
export {
CollateralConfig,
NativeConfig,

@ -1,4 +1,3 @@
/* eslint-disable no-console */
import assert from 'assert';
import { expect } from 'chai';
import { Signer } from 'ethers';

@ -28,10 +28,10 @@ import { normalizeConfig } from '../utils/ism.js';
import { EvmIsmReader } from './EvmIsmReader.js';
import { HyperlaneIsmFactory } from './HyperlaneIsmFactory.js';
import { IsmConfigSchema } from './schemas.js';
import {
DeployedIsm,
IsmConfig,
IsmConfigSchema,
IsmType,
MUTABLE_ISM_TYPE,
RoutingIsmConfig,

@ -158,7 +158,7 @@ export class EvmIsmReader extends HyperlaneReader implements IsmReader {
let ismType = IsmType.FALLBACK_ROUTING;
try {
await ism.mailbox();
} catch (error) {
} catch {
ismType = IsmType.ROUTING;
this.logger.debug(
'Error accessing mailbox property, implying this is not a fallback routing ISM.',
@ -248,7 +248,7 @@ export class EvmIsmReader extends HyperlaneReader implements IsmReader {
relayer,
type: IsmType.TRUSTED_RELAYER,
};
} catch (error) {
} catch {
this.logger.debug(
'Error accessing "trustedRelayer" property, implying this is not a Trusted Relayer ISM.',
address,
@ -266,7 +266,7 @@ export class EvmIsmReader extends HyperlaneReader implements IsmReader {
type: IsmType.PAUSABLE,
paused,
};
} catch (error) {
} catch {
this.logger.debug(
'Error accessing "paused" property, implying this is not a Pausable ISM.',
address,
@ -283,7 +283,7 @@ export class EvmIsmReader extends HyperlaneReader implements IsmReader {
origin: address,
nativeBridge: '', // no way to extract native bridge from the ism
};
} catch (error) {
} catch {
this.logger.debug(
'Error accessing "VERIFIED_MASK_INDEX" property, implying this is not an OP Stack ISM.',
address,

@ -466,7 +466,7 @@ export class HyperlaneIsmFactory extends HyperlaneApp<ProxyFactoryFactories> {
.map((log) => {
try {
return domainRoutingIsmFactory.interface.parseLog(log);
} catch (e) {
} catch {
return undefined;
}
})

@ -10,12 +10,13 @@ import {
import { DerivedIsmConfig } from '../EvmIsmReader.js';
import { AggregationIsmConfig, IsmType } from '../types.js';
import type { BaseMetadataBuilder } from './builder.js';
import { decodeIsmMetadata } from './decode.js';
import {
BaseMetadataBuilder,
MetadataBuilder,
MetadataContext,
StructuredMetadata,
} from './builder.js';
} from './types.js';
// null indicates that metadata is NOT INCLUDED for this submodule
// empty or 0x string indicates that metadata is INCLUDED but NULL
@ -137,7 +138,7 @@ export class AggregationMetadataBuilder implements MetadataBuilder {
const range = this.metadataRange(metadata, index);
if (range.start == 0) return null;
if (typeof ism === 'string') return range.encoded;
return BaseMetadataBuilder.decode(range.encoded, {
return decodeIsmMetadata(range.encoded, {
...context,
ism: ism as DerivedIsmConfig,
});

@ -16,8 +16,12 @@ import {
MockArbSys__factory,
TestRecipient,
} from '@hyperlane-xyz/core';
import { Address, WithAddress, objMap } from '@hyperlane-xyz/utils';
import { bytes32ToAddress } from '@hyperlane-xyz/utils';
import {
Address,
WithAddress,
bytes32ToAddress,
objMap,
} from '@hyperlane-xyz/utils';
import { testChains } from '../../consts/testChains.js';
import {
@ -38,7 +42,7 @@ import { HyperlaneIsmFactory } from '../HyperlaneIsmFactory.js';
import { ArbL2ToL1IsmConfig } from '../types.js';
import { ArbL2ToL1MetadataBuilder } from './arbL2ToL1.js';
import { MetadataContext } from './builder.js';
import { MetadataContext } from './types.js';
describe('ArbL2ToL1MetadataBuilder', () => {
const origin: ChainName = 'test4';

@ -20,7 +20,7 @@ import { ArbL2ToL1HookConfig } from '../../hook/types.js';
import { findMatchingLogEvents } from '../../utils/logUtils.js';
import { ArbL2ToL1IsmConfig, IsmType } from '../types.js';
import { MetadataBuilder, MetadataContext } from './builder.js';
import type { MetadataBuilder, MetadataContext } from './types.js';
export type NitroChildToParentTransactionEvent = EventArgs<L2ToL1TxEvent>;
export type ArbL2ToL1Metadata = Omit<

@ -39,7 +39,9 @@ import { EvmIsmReader } from '../EvmIsmReader.js';
import { randomIsmConfig } from '../HyperlaneIsmFactory.hardhat-test.js';
import { HyperlaneIsmFactory } from '../HyperlaneIsmFactory.js';
import { BaseMetadataBuilder, MetadataContext } from './builder.js';
import { BaseMetadataBuilder } from './builder.js';
import { decodeIsmMetadata } from './decode.js';
import { MetadataContext } from './types.js';
const MAX_ISM_DEPTH = 5;
const MAX_NUM_VALIDATORS = 10;
@ -198,7 +200,7 @@ describe('BaseMetadataBuilder', () => {
});
it(`should decode metadata for random ism config (${i})`, async () => {
BaseMetadataBuilder.decode(metadata, context);
decodeIsmMetadata(metadata, context);
});
}
});

@ -1,53 +1,30 @@
/* eslint-disable no-case-declarations */
import { TransactionReceipt } from '@ethersproject/providers';
import { WithAddress, assert, rootLogger } from '@hyperlane-xyz/utils';
import {
WithAddress,
assert,
deepFind,
rootLogger,
} from '@hyperlane-xyz/utils';
import { deepFind } from '../../../../utils/dist/objects.js';
import { HyperlaneCore } from '../../core/HyperlaneCore.js';
import { DispatchedMessage } from '../../core/types.js';
import { DerivedHookConfig } from '../../hook/EvmHookReader.js';
import {
ArbL2ToL1HookConfig,
HookType,
MerkleTreeHookConfig,
} from '../../hook/types.js';
import { MultiProvider } from '../../providers/MultiProvider.js';
import { DerivedIsmConfig } from '../EvmIsmReader.js';
import { IsmType } from '../types.js';
import {
AggregationMetadata,
AggregationMetadataBuilder,
} from './aggregation.js';
import { ArbL2ToL1Metadata, ArbL2ToL1MetadataBuilder } from './arbL2ToL1.js';
import { MultisigMetadata, MultisigMetadataBuilder } from './multisig.js';
import { NullMetadata, NullMetadataBuilder } from './null.js';
import {
DefaultFallbackRoutingMetadataBuilder,
RoutingMetadata,
} from './routing.js';
export type StructuredMetadata =
| NullMetadata
| MultisigMetadata
| ArbL2ToL1Metadata
| AggregationMetadata<any>
| RoutingMetadata<any>;
export interface MetadataContext<
IsmContext = DerivedIsmConfig,
HookContext = DerivedHookConfig,
> {
message: DispatchedMessage;
dispatchTx: TransactionReceipt;
ism: IsmContext;
hook: HookContext;
}
export interface MetadataBuilder {
build(context: MetadataContext): Promise<string>;
}
import { AggregationMetadataBuilder } from './aggregation.js';
import { ArbL2ToL1MetadataBuilder } from './arbL2ToL1.js';
import { decodeIsmMetadata } from './decode.js';
import { MultisigMetadataBuilder } from './multisig.js';
import { NullMetadataBuilder } from './null.js';
import { DefaultFallbackRoutingMetadataBuilder } from './routing.js';
import type {
MetadataBuilder,
MetadataContext,
StructuredMetadata,
} from './types.js';
export class BaseMetadataBuilder implements MetadataBuilder {
public nullMetadataBuilder: NullMetadataBuilder;
@ -91,6 +68,7 @@ export class BaseMetadataBuilder implements MetadataBuilder {
if (typeof hook === 'string') {
throw new Error('Hook context must be an object (for multisig ISM)');
}
// eslint-disable-next-line no-case-declarations
const merkleTreeHook = deepFind(
hook,
(v): v is WithAddress<MerkleTreeHookConfig> =>
@ -137,32 +115,6 @@ export class BaseMetadataBuilder implements MetadataBuilder {
metadata: string,
context: MetadataContext,
): StructuredMetadata {
const { ism } = context;
switch (ism.type) {
case IsmType.TRUSTED_RELAYER:
return NullMetadataBuilder.decode(ism);
case IsmType.MERKLE_ROOT_MULTISIG:
case IsmType.MESSAGE_ID_MULTISIG:
return MultisigMetadataBuilder.decode(metadata, ism.type);
case IsmType.AGGREGATION:
return AggregationMetadataBuilder.decode(metadata, { ...context, ism });
case IsmType.ROUTING:
return DefaultFallbackRoutingMetadataBuilder.decode(metadata, {
...context,
ism,
});
case IsmType.ARB_L2_TO_L1:
return ArbL2ToL1MetadataBuilder.decode(metadata, {
...context,
ism,
});
default:
throw new Error(`Unsupported ISM type: ${ism.type}`);
}
return decodeIsmMetadata(metadata, context);
}
}

@ -0,0 +1,41 @@
import { IsmType } from '../types.js';
import { AggregationMetadataBuilder } from './aggregation.js';
import { ArbL2ToL1MetadataBuilder } from './arbL2ToL1.js';
import { MultisigMetadataBuilder } from './multisig.js';
import { NullMetadataBuilder } from './null.js';
import { DefaultFallbackRoutingMetadataBuilder } from './routing.js';
import { MetadataContext, StructuredMetadata } from './types.js';
export function decodeIsmMetadata(
metadata: string,
context: MetadataContext,
): StructuredMetadata {
const { ism } = context;
switch (ism.type) {
case IsmType.TRUSTED_RELAYER:
return NullMetadataBuilder.decode(ism);
case IsmType.MERKLE_ROOT_MULTISIG:
case IsmType.MESSAGE_ID_MULTISIG:
return MultisigMetadataBuilder.decode(metadata, ism.type);
case IsmType.AGGREGATION:
return AggregationMetadataBuilder.decode(metadata, { ...context, ism });
case IsmType.ROUTING:
return DefaultFallbackRoutingMetadataBuilder.decode(metadata, {
...context,
ism,
});
case IsmType.ARB_L2_TO_L1:
return ArbL2ToL1MetadataBuilder.decode(metadata, {
...context,
ism,
});
default:
throw new Error(`Unsupported ISM type: ${ism.type}`);
}
}

@ -26,7 +26,7 @@ import { MerkleTreeHookConfig } from '../../hook/types.js';
import { ChainName } from '../../types.js';
import { IsmType, MultisigIsmConfig } from '../types.js';
import { MetadataBuilder, MetadataContext } from './builder.js';
import type { MetadataBuilder, MetadataContext } from './types.js';
interface MessageIdMultisigMetadata {
type: IsmType.MESSAGE_ID_MULTISIG;

@ -3,7 +3,7 @@ import { WithAddress, assert, eqAddress } from '@hyperlane-xyz/utils';
import { MultiProvider } from '../../providers/MultiProvider.js';
import { IsmType, NullIsmConfig } from '../types.js';
import { MetadataBuilder, MetadataContext } from './builder.js';
import type { MetadataBuilder, MetadataContext } from './types.js';
export const NULL_METADATA = '0x';

@ -5,12 +5,13 @@ import { ChainName } from '../../types.js';
import { DerivedIsmConfig, EvmIsmReader } from '../EvmIsmReader.js';
import { IsmType, RoutingIsmConfig } from '../types.js';
import {
BaseMetadataBuilder,
import type { BaseMetadataBuilder } from './builder.js';
import { decodeIsmMetadata } from './decode.js';
import type {
MetadataBuilder,
MetadataContext,
StructuredMetadata,
} from './builder.js';
} from './types.js';
export type RoutingMetadata<T> = {
type: IsmType.ROUTING;
@ -45,7 +46,7 @@ export class RoutingMetadataBuilder implements MetadataBuilder {
const originMetadata =
typeof ism === 'string'
? metadata
: BaseMetadataBuilder.decode(metadata, {
: decodeIsmMetadata(metadata, {
...context,
ism: ism as DerivedIsmConfig,
});

@ -0,0 +1,32 @@
import type { providers } from 'ethers';
import type { DispatchedMessage } from '../../core/types.js';
import type { DerivedHookConfig } from '../../hook/EvmHookReader.js';
import type { DerivedIsmConfig } from '../EvmIsmReader.js';
import type { AggregationMetadata } from './aggregation.js';
import type { ArbL2ToL1Metadata } from './arbL2ToL1.js';
import type { MultisigMetadata } from './multisig.js';
import type { NullMetadata } from './null.js';
import type { RoutingMetadata } from './routing.js';
export type StructuredMetadata =
| NullMetadata
| MultisigMetadata
| ArbL2ToL1Metadata
| AggregationMetadata<any>
| RoutingMetadata<any>;
export interface MetadataContext<
IsmContext = DerivedIsmConfig,
HookContext = DerivedHookConfig,
> {
message: DispatchedMessage;
dispatchTx: providers.TransactionReceipt;
ism: IsmContext;
hook: HookContext;
}
export interface MetadataBuilder {
build(context: MetadataContext): Promise<string>;
}

@ -1,103 +0,0 @@
import { z } from 'zod';
import { ZHash } from '../metadata/customZodTypes.js';
import { OwnableSchema, PausableSchema } from '../schemas.js';
import { AggregationIsmConfig, IsmType, RoutingIsmConfig } from './types.js';
const ValidatorInfoSchema = z.object({
signingAddress: ZHash,
weight: z.number(),
});
export const TestIsmConfigSchema = z.object({
type: z.literal(IsmType.TEST_ISM),
});
export const MultisigConfigSchema = z.object({
validators: z.array(ZHash),
threshold: z.number(),
});
export const WeightedMultisigConfigSchema = z.object({
validators: z.array(ValidatorInfoSchema),
thresholdWeight: z.number(),
});
export const TrustedRelayerIsmConfigSchema = z.object({
type: z.literal(IsmType.TRUSTED_RELAYER),
relayer: z.string(),
});
export const OpStackIsmConfigSchema = z.object({
type: z.literal(IsmType.OP_STACK),
origin: z.string(),
nativeBridge: z.string(),
});
export const ArbL2ToL1IsmConfigSchema = z.object({
type: z.literal(IsmType.ARB_L2_TO_L1),
bridge: z.string(),
});
export const PausableIsmConfigSchema = PausableSchema.and(
z.object({
type: z.literal(IsmType.PAUSABLE),
}),
);
export const MultisigIsmConfigSchema = MultisigConfigSchema.and(
z.object({
type: z.union([
z.literal(IsmType.MERKLE_ROOT_MULTISIG),
z.literal(IsmType.MESSAGE_ID_MULTISIG),
z.literal(IsmType.STORAGE_MERKLE_ROOT_MULTISIG),
z.literal(IsmType.STORAGE_MESSAGE_ID_MULTISIG),
]),
}),
);
export const WeightedMultisigIsmConfigSchema = WeightedMultisigConfigSchema.and(
z.object({
type: z.union([
z.literal(IsmType.WEIGHTED_MERKLE_ROOT_MULTISIG),
z.literal(IsmType.WEIGHTED_MESSAGE_ID_MULTISIG),
]),
}),
);
export const RoutingIsmConfigSchema: z.ZodSchema<RoutingIsmConfig> = z.lazy(
() =>
OwnableSchema.extend({
type: z.union([
z.literal(IsmType.ROUTING),
z.literal(IsmType.FALLBACK_ROUTING),
]),
domains: z.record(IsmConfigSchema),
}),
);
export const AggregationIsmConfigSchema: z.ZodSchema<AggregationIsmConfig> = z
.lazy(() =>
z.object({
type: z.literal(IsmType.AGGREGATION),
modules: z.array(IsmConfigSchema),
threshold: z.number(),
}),
)
.refine((data) => data.threshold <= data.modules.length, {
message: 'Threshold must be less than or equal to the number of modules',
});
export const IsmConfigSchema = z.union([
ZHash,
TestIsmConfigSchema,
OpStackIsmConfigSchema,
PausableIsmConfigSchema,
TrustedRelayerIsmConfigSchema,
MultisigIsmConfigSchema,
WeightedMultisigIsmConfigSchema,
RoutingIsmConfigSchema,
AggregationIsmConfigSchema,
ArbL2ToL1IsmConfigSchema,
]);

@ -1,8 +1,7 @@
import { expect } from 'chai';
import { ethers } from 'ethers';
import { AggregationIsmConfigSchema } from './schemas.js';
import { IsmType } from './types.js';
import { AggregationIsmConfigSchema, IsmType } from './types.js';
const SOME_ADDRESS = ethers.Wallet.createRandom().address;
describe('AggregationIsmConfigSchema refine', () => {

@ -15,19 +15,10 @@ import {
import type { Address, Domain, ValueOf } from '@hyperlane-xyz/utils';
import { OwnableConfig } from '../deploy/types.js';
import { ZHash } from '../metadata/customZodTypes.js';
import { OwnableSchema, PausableSchema } from '../schemas.js';
import { ChainMap } from '../types.js';
import {
ArbL2ToL1IsmConfigSchema,
IsmConfigSchema,
MultisigIsmConfigSchema,
OpStackIsmConfigSchema,
PausableIsmConfigSchema,
TestIsmConfigSchema,
TrustedRelayerIsmConfigSchema,
WeightedMultisigIsmConfigSchema,
} from './schemas.js';
// this enum should match the IInterchainSecurityModule.sol enum
// meant for the relayer
export enum ModuleType {
@ -167,3 +158,100 @@ export type RoutingIsmDelta = {
owner?: Address; // is the owner different
mailbox?: Address; // is the mailbox different (only for fallback routing)
};
const ValidatorInfoSchema = z.object({
signingAddress: ZHash,
weight: z.number(),
});
export const TestIsmConfigSchema = z.object({
type: z.literal(IsmType.TEST_ISM),
});
export const MultisigConfigSchema = z.object({
validators: z.array(ZHash),
threshold: z.number(),
});
export const WeightedMultisigConfigSchema = z.object({
validators: z.array(ValidatorInfoSchema),
thresholdWeight: z.number(),
});
export const TrustedRelayerIsmConfigSchema = z.object({
type: z.literal(IsmType.TRUSTED_RELAYER),
relayer: z.string(),
});
export const OpStackIsmConfigSchema = z.object({
type: z.literal(IsmType.OP_STACK),
origin: z.string(),
nativeBridge: z.string(),
});
export const ArbL2ToL1IsmConfigSchema = z.object({
type: z.literal(IsmType.ARB_L2_TO_L1),
bridge: z.string(),
});
export const PausableIsmConfigSchema = PausableSchema.and(
z.object({
type: z.literal(IsmType.PAUSABLE),
}),
);
export const MultisigIsmConfigSchema = MultisigConfigSchema.and(
z.object({
type: z.union([
z.literal(IsmType.MERKLE_ROOT_MULTISIG),
z.literal(IsmType.MESSAGE_ID_MULTISIG),
z.literal(IsmType.STORAGE_MERKLE_ROOT_MULTISIG),
z.literal(IsmType.STORAGE_MESSAGE_ID_MULTISIG),
]),
}),
);
export const WeightedMultisigIsmConfigSchema = WeightedMultisigConfigSchema.and(
z.object({
type: z.union([
z.literal(IsmType.WEIGHTED_MERKLE_ROOT_MULTISIG),
z.literal(IsmType.WEIGHTED_MESSAGE_ID_MULTISIG),
]),
}),
);
export const RoutingIsmConfigSchema: z.ZodSchema<RoutingIsmConfig> = z.lazy(
() =>
OwnableSchema.extend({
type: z.union([
z.literal(IsmType.ROUTING),
z.literal(IsmType.FALLBACK_ROUTING),
]),
domains: z.record(IsmConfigSchema),
}),
);
export const AggregationIsmConfigSchema: z.ZodSchema<AggregationIsmConfig> = z
.lazy(() =>
z.object({
type: z.literal(IsmType.AGGREGATION),
modules: z.array(IsmConfigSchema),
threshold: z.number(),
}),
)
.refine((data) => data.threshold <= data.modules.length, {
message: 'Threshold must be less than or equal to the number of modules',
});
export const IsmConfigSchema = z.union([
ZHash,
TestIsmConfigSchema,
OpStackIsmConfigSchema,
PausableIsmConfigSchema,
TrustedRelayerIsmConfigSchema,
MultisigIsmConfigSchema,
WeightedMultisigIsmConfigSchema,
RoutingIsmConfigSchema,
AggregationIsmConfigSchema,
ArbL2ToL1IsmConfigSchema,
]);

@ -270,7 +270,7 @@ export async function moduleMatchesConfig(
let mailboxAddress;
try {
mailboxAddress = await client.mailbox();
} catch (error) {
} catch {
matches = false;
break;
}

@ -1,5 +0,0 @@
{
"rules": {
"no-console": ["off"]
}
}

@ -11,6 +11,7 @@ import {
addressToBytes32,
ensure0x,
eqAddress,
rootLogger,
strip0x,
} from '@hyperlane-xyz/utils';
@ -23,6 +24,8 @@ import { fetchWithTimeout } from '../../utils/fetch.js';
import { BridgeAdapterConfig } from './LiquidityLayerRouterDeployer.js';
import { liquidityLayerFactories } from './contracts.js';
const logger = rootLogger.child({ module: 'LiquidityLayerApp' });
const PORTAL_VAA_SERVICE_TESTNET_BASE_URL =
'https://wormhole-v2-testnet-api.certus.one/v1/signed_vaa/';
const CIRCLE_ATTESTATIONS_TESTNET_BASE_URL =
@ -77,7 +80,7 @@ export class LiquidityLayerApp extends HyperlaneApp<
}
async fetchCircleMessageTransactions(chain: ChainName): Promise<string[]> {
console.log(`Fetch circle messages for ${chain}`);
logger.info(`Fetch circle messages for ${chain}`);
const url = new URL(this.multiProvider.getExplorerApiUrl(chain));
url.searchParams.set('module', 'logs');
url.searchParams.set('action', 'getLogs');
@ -140,7 +143,7 @@ export class LiquidityLayerApp extends HyperlaneApp<
chain: ChainName,
txHash: string,
): Promise<CircleBridgeMessage[]> {
console.debug(`Parse Circle messages for chain ${chain} ${txHash}`);
logger.debug(`Parse Circle messages for chain ${chain} ${txHash}`);
const provider = this.multiProvider.getProvider(chain);
const receipt = await provider.getTransactionReceipt(txHash);
const matchingLogs = receipt.logs
@ -207,7 +210,7 @@ export class LiquidityLayerApp extends HyperlaneApp<
await destinationPortalAdapter.portalTransfersProcessed(transferId);
if (!eqAddress(transferTokenAddress, ethers.constants.AddressZero)) {
console.log(
logger.info(
`Transfer with nonce ${message.nonce} from ${message.origin} to ${message.destination} already processed`,
);
return;
@ -229,11 +232,11 @@ export class LiquidityLayerApp extends HyperlaneApp<
).then((response) => response.json());
if (vaa.code && vaa.code === PORTAL_VAA_SERVICE_SUCCESS_CODE) {
console.log(`VAA not yet found for nonce ${message.nonce}`);
logger.info(`VAA not yet found for nonce ${message.nonce}`);
return;
}
console.debug(
logger.debug(
`Complete portal transfer for nonce ${message.nonce} on ${message.destination}`,
);
@ -246,10 +249,10 @@ export class LiquidityLayerApp extends HyperlaneApp<
);
} catch (error: any) {
if (error?.error?.reason?.includes('no wrapper for this token')) {
console.log(
logger.info(
'No wrapper for this token, you should register the token at https://wormhole-foundation.github.io/example-token-bridge-ui/#/register',
);
console.log(message);
logger.info(message);
return;
}
throw error;
@ -268,11 +271,11 @@ export class LiquidityLayerApp extends HyperlaneApp<
const alreadyProcessed = await transmitter.usedNonces(message.nonceHash);
if (alreadyProcessed) {
console.log(`Message sent on ${message.txHash} was already processed`);
logger.info(`Message sent on ${message.txHash} was already processed`);
return;
}
console.log(`Attempt Circle message delivery`, JSON.stringify(message));
logger.info(`Attempt Circle message delivery`, JSON.stringify(message));
const messageHash = ethers.utils.keccak256(message.message);
const baseurl = this.multiProvider.getChainMetadata(message.chain).isTestnet
@ -282,19 +285,19 @@ export class LiquidityLayerApp extends HyperlaneApp<
const attestations = await attestationsB.json();
if (attestations.status !== 'complete') {
console.log(
logger.info(
`Attestations not available for message nonce ${message.nonce} on ${message.txHash}`,
);
return;
}
console.log(`Ready to submit attestations for message ${message.nonce}`);
logger.info(`Ready to submit attestations for message ${message.nonce}`);
const tx = await transmitter.receiveMessage(
message.message,
attestations.attestation,
);
console.log(
logger.info(
`Submitted attestations in ${this.multiProvider.tryGetExplorerTxUrl(
message.remoteChain,
tx,

@ -1,5 +1,5 @@
import { BigNumber, errors as EthersError, providers, utils } from 'ethers';
import pino, { Logger } from 'pino';
import { Logger, pino } from 'pino';
import {
raceWithContext,
@ -126,7 +126,7 @@ export class HyperlaneSmartProvider
async getPriorityFee(): Promise<BigNumber> {
try {
return BigNumber.from(await this.perform('maxPriorityFeePerGas', {}));
} catch (error) {
} catch {
return BigNumber.from('1500000000');
}
}

@ -1,7 +1,6 @@
import { Logger } from 'pino';
import { Annotated, rootLogger } from '@hyperlane-xyz/utils';
import { ProtocolType } from '@hyperlane-xyz/utils';
import { Annotated, ProtocolType, rootLogger } from '@hyperlane-xyz/utils';
import {
ProtocolTypedReceipt,

@ -1,43 +0,0 @@
import { z } from 'zod';
import { HookConfigSchema } from '../hook/schemas.js';
import { IsmConfigSchema } from '../ism/schemas.js';
import { ZHash } from '../metadata/customZodTypes.js';
import { DeployedOwnableSchema, OwnableSchema } from '../schemas.js';
export const MailboxClientConfigSchema = OwnableSchema.extend({
mailbox: ZHash,
hook: HookConfigSchema.optional(),
interchainSecurityModule: IsmConfigSchema.optional(),
});
export const ForeignDeploymentConfigSchema = z.object({
foreignDeployment: z.string().optional(),
});
const RemoteRouterDomain = z.string();
const RemoteRouterRouter = z.string().startsWith('0x');
export const RemoteRoutersSchema = z.record(
RemoteRouterDomain,
RemoteRouterRouter,
);
export const RouterConfigSchema = MailboxClientConfigSchema.merge(
ForeignDeploymentConfigSchema,
).merge(
z.object({
remoteRouters: RemoteRoutersSchema.optional(),
proxyAdmin: DeployedOwnableSchema.optional(),
}),
);
const DestinationGasDomain = z.string();
const DestinationGasAmount = z.string(); // This must be a string type to match Ether's type
export const DestinationGasSchema = z.record(
DestinationGasDomain,
DestinationGasAmount,
);
export const GasRouterConfigSchema = RouterConfigSchema.extend({
gas: z.number().optional(),
destinationGas: DestinationGasSchema.optional(),
});

@ -11,16 +11,12 @@ import { Address, AddressBytes32 } from '@hyperlane-xyz/utils';
import { HyperlaneFactories } from '../contracts/types.js';
import { UpgradeConfig } from '../deploy/proxy.js';
import { CheckerViolation } from '../deploy/types.js';
import { HookConfigSchema } from '../hook/types.js';
import { IsmConfigSchema } from '../ism/types.js';
import { ZHash } from '../metadata/customZodTypes.js';
import { DeployedOwnableSchema, OwnableSchema } from '../schemas.js';
import { ChainMap } from '../types.js';
import {
DestinationGasSchema,
GasRouterConfigSchema,
MailboxClientConfigSchema,
RemoteRoutersSchema,
RouterConfigSchema,
} from './schemas.js';
export type RouterAddress = {
router: Address;
};
@ -68,3 +64,40 @@ export interface RouterViolation extends CheckerViolation {
export type RemoteRouters = z.infer<typeof RemoteRoutersSchema>;
export type DestinationGas = z.infer<typeof DestinationGasSchema>;
export const MailboxClientConfigSchema = OwnableSchema.extend({
mailbox: ZHash,
hook: HookConfigSchema.optional(),
interchainSecurityModule: IsmConfigSchema.optional(),
});
export const ForeignDeploymentConfigSchema = z.object({
foreignDeployment: z.string().optional(),
});
const RemoteRouterDomain = z.string();
const RemoteRouterRouter = z.string().startsWith('0x');
export const RemoteRoutersSchema = z.record(
RemoteRouterDomain,
RemoteRouterRouter,
);
export const RouterConfigSchema = MailboxClientConfigSchema.merge(
ForeignDeploymentConfigSchema,
).merge(
z.object({
remoteRouters: RemoteRoutersSchema.optional(),
proxyAdmin: DeployedOwnableSchema.optional(),
}),
);
const DestinationGasDomain = z.string();
const DestinationGasAmount = z.string(); // This must be a string type to match Ether's type
export const DestinationGasSchema = z.record(
DestinationGasDomain,
DestinationGasAmount,
);
export const GasRouterConfigSchema = RouterConfigSchema.extend({
gas: z.number().optional(),
destinationGas: DestinationGasSchema.optional(),
});

@ -124,7 +124,7 @@ export class EvmERC20WarpRouteReader extends HyperlaneReader {
const warpRoute = factory.connect(warpRouteAddress, this.provider);
await warpRoute[method]();
return tokenType as TokenType;
} catch (e) {
} catch {
continue;
} finally {
this.setSmartProviderLogLevel(getLogLevel()); // returns to original level defined by rootLogger

@ -1,5 +1,3 @@
/* eslint-disable @typescript-eslint/explicit-module-boundary-types */
/* eslint-disable no-console */
import {
CosmWasmClient,

@ -73,7 +73,7 @@ export class HypERC20Checker extends ProxiedRouterChecker<
from: await this.multiProvider.getSignerAddress(chain),
value: BigNumber.from(1),
});
} catch (e) {
} catch {
const violation: TokenMismatchViolation = {
type: 'deployed token not payable',
chain,

@ -1,4 +1,3 @@
/* eslint-disable @typescript-eslint/explicit-module-boundary-types */
import { constants } from 'ethers';
import {

@ -2,7 +2,7 @@ import { z } from 'zod';
import { objMap } from '@hyperlane-xyz/utils';
import { GasRouterConfigSchema } from '../router/schemas.js';
import { GasRouterConfigSchema } from '../router/types.js';
import { isCompliant } from '../utils/schemas.js';
import { TokenType } from './config.js';

@ -1,5 +0,0 @@
{
"rules": {
"@typescript-eslint/explicit-module-boundary-types": ["off"]
}
}

@ -103,7 +103,7 @@ export async function canProposeSafeTransactions(
let safeService;
try {
safeService = getSafeService(chain, multiProvider);
} catch (e) {
} catch {
return false;
}
const safe = await getSafe(chain, multiProvider, safeAddress);

@ -10,7 +10,7 @@ export function findMatchingLogEvents(
.map((log) => {
try {
return iface.parseLog(log);
} catch (e) {
} catch {
return undefined;
}
})

@ -10,7 +10,6 @@ export class SealevelAccountDataWrapper<T> {
initialized!: boolean;
discriminator?: unknown;
data!: T;
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
constructor(public readonly fields: any) {
Object.assign(this, fields);
}

@ -0,0 +1,3 @@
import MonorepoDefaults from '../../eslint.config.mjs';
export default [...MonorepoDefaults, { files: ['./src/**/*.ts'] }];

@ -12,11 +12,18 @@
"yaml": "2.4.5"
},
"devDependencies": {
"@eslint/js": "^9.15.0",
"@types/lodash-es": "^4.17.12",
"@types/mocha": "^10.0.1",
"@types/sinon": "^17.0.1",
"@types/sinon-chai": "^3.2.12",
"@typescript-eslint/eslint-plugin": "^8.1.6",
"@typescript-eslint/parser": "^8.1.6",
"chai": "4.5.0",
"eslint": "^9.15.0",
"eslint-config-prettier": "^9.1.0",
"eslint-import-resolver-typescript": "^3.6.3",
"eslint-plugin-import": "^2.31.0",
"mocha": "^10.2.0",
"prettier": "^2.8.8",
"sinon": "^13.0.2",
@ -36,6 +43,7 @@
"build": "tsc",
"clean": "rm -rf ./dist",
"check": "tsc --noEmit",
"lint": "eslint -c ./eslint.config.mjs",
"prettier": "prettier --write ./src",
"test": "mocha --config .mocharc.json './src/**/*.test.ts'",
"test:ci": "yarn test"

@ -80,7 +80,7 @@ export function isValidAddressEvm(address: Address) {
try {
const isValid = address && ethersUtils.isAddress(address);
return !!isValid;
} catch (error) {
} catch {
return false;
}
}
@ -90,7 +90,7 @@ export function isValidAddressSealevel(address: Address) {
try {
const isValid = address && new PublicKey(address).toBase58();
return !!isValid;
} catch (error) {
} catch {
return false;
}
}
@ -104,7 +104,7 @@ export function isValidAddressCosmos(address: Address) {
COSMOS_FACTORY_TOKEN_REGEX.test(address) ||
fromBech32(address));
return !!isValid;
} catch (error) {
} catch {
return false;
}
}
@ -126,7 +126,7 @@ export function normalizeAddressEvm(address: Address) {
if (isZeroishAddress(address)) return address;
try {
return ethersUtils.getAddress(address);
} catch (error) {
} catch {
return address;
}
}
@ -135,7 +135,7 @@ export function normalizeAddressSealevel(address: Address) {
if (isZeroishAddress(address)) return address;
try {
return new PublicKey(address).toBase58();
} catch (error) {
} catch {
return address;
}
}
@ -144,7 +144,7 @@ export function normalizeAddressCosmos(address: Address) {
if (isZeroishAddress(address)) return address;
try {
return normalizeBech32(address);
} catch (error) {
} catch {
return address;
}
}

@ -82,7 +82,7 @@ export function tryParseAmount(
const parsed = BigNumber(value);
if (!parsed || parsed.isNaN() || !parsed.isFinite()) return null;
else return parsed;
} catch (error) {
} catch {
return null;
}
}

@ -4,7 +4,7 @@ export function toBase64(data: any): string | undefined {
try {
if (!data) throw new Error('No data to encode');
return btoa(JSON.stringify(data));
} catch (error) {
} catch {
rootLogger.error('Unable to serialize + encode data to base64', data);
return undefined;
}
@ -15,7 +15,7 @@ export function fromBase64<T>(data: string | string[]): T | undefined {
if (!data) throw new Error('No data to decode');
const msg = Array.isArray(data) ? data[0] : data;
return JSON.parse(atob(msg));
} catch (error) {
} catch {
rootLogger.error('Unable to decode + deserialize data from base64', data);
return undefined;
}

@ -15,7 +15,7 @@ export function isBigNumberish(
try {
const val = BigNumber(value!);
return !val.isNaN() && val.isFinite() && BigNumber.isBigNumber(val);
} catch (error) {
} catch {
return false;
}
}
@ -28,7 +28,7 @@ export function isBigNumberish(
export function isZeroish(value: BigNumber.Value): boolean {
try {
return BigNumber(value).isZero();
} catch (error) {
} catch {
return false;
}
}

@ -3,7 +3,7 @@
export function safelyAccessEnvVar(name: string, toLowerCase = false) {
try {
return toLowerCase ? process.env[name]?.toLowerCase() : process.env[name];
} catch (error) {
} catch {
return undefined;
}
}

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save