From 9a329710509e66d66566c6ce429eae5ce441846f Mon Sep 17 00:00:00 2001 From: Yorke Rhodes Date: Tue, 16 Apr 2024 11:56:56 -0400 Subject: [PATCH 01/16] Remove accidental .only and update lint rules (#3614) ### Description Removal accidental .only ### Drive-by Update lint rules --- .eslintrc | 9 +- package.json | 3 +- solidity/.solhint.json | 4 +- solidity/package.json | 2 +- typescript/helloworld/package.json | 2 +- typescript/sdk/src/ism/read.test.ts | 2 +- yarn.lock | 260 ++++++++++++++++++++++++++-- 7 files changed, 263 insertions(+), 19 deletions(-) diff --git a/.eslintrc b/.eslintrc index 0855bdf61b..0fffcede50 100644 --- a/.eslintrc +++ b/.eslintrc @@ -11,7 +11,7 @@ "sourceType": "module", "project": "./tsconfig.json" }, - "plugins": ["@typescript-eslint"], + "plugins": ["@typescript-eslint","jest"], "extends": [ "eslint:recommended", "plugin:@typescript-eslint/recommended", @@ -47,6 +47,11 @@ }, "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" } } \ No newline at end of file diff --git a/package.json b/package.json index 5d838c09ef..344b1f87d1 100644 --- a/package.json +++ b/package.json @@ -6,8 +6,9 @@ "@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", + "eslint": "^9.0.0", "eslint-config-prettier": "^9.1.0", + "eslint-plugin-jest": "^28.2.0", "husky": "^8.0.0", "lint-staged": "^12.4.3", "prettier": "^2.8.8", diff --git a/solidity/.solhint.json b/solidity/.solhint.json index 2cb9a69a67..a4cc08a3bc 100644 --- a/solidity/.solhint.json +++ b/solidity/.solhint.json @@ -10,7 +10,9 @@ "var-name-mixedcase": "off", "func-name-mixedcase": "off", "reason-string": ["warn",{"maxLength":64}], - "prettier/prettier": "error" + "prettier/prettier": "error", + "custom-errors": "off", + "gas-custom-errors": "off" }, "plugins": ["prettier"] } diff --git a/solidity/package.json b/solidity/package.json index 5cf9a39852..976c6c625f 100644 --- a/solidity/package.json +++ b/solidity/package.json @@ -22,7 +22,7 @@ "hardhat-gas-reporter": "^1.0.9", "prettier": "^2.8.8", "prettier-plugin-solidity": "^1.1.3", - "solhint": "^4.0.0", + "solhint": "^4.5.4", "solhint-plugin-prettier": "^0.0.5", "solidity-coverage": "^0.8.3", "ts-generator": "^0.1.1", diff --git a/typescript/helloworld/package.json b/typescript/helloworld/package.json index 67f563c9fb..1805b5f33f 100644 --- a/typescript/helloworld/package.json +++ b/typescript/helloworld/package.json @@ -24,7 +24,7 @@ "hardhat-gas-reporter": "^1.0.9", "prettier": "^2.8.8", "prettier-plugin-solidity": "^1.1.3", - "solhint": "^4.0.0", + "solhint": "^4.5.4", "solhint-plugin-prettier": "^0.0.5", "solidity-coverage": "^0.8.3", "ts-node": "^10.8.0", diff --git a/typescript/sdk/src/ism/read.test.ts b/typescript/sdk/src/ism/read.test.ts index 7bb15b1746..3790d3137e 100644 --- a/typescript/sdk/src/ism/read.test.ts +++ b/typescript/sdk/src/ism/read.test.ts @@ -30,7 +30,7 @@ import { TestIsmConfig, } from './types.js'; -describe.only('EvmIsmReader', () => { +describe('EvmIsmReader', () => { let evmIsmReader: EvmIsmReader; let multiProvider: MultiProvider; let sandbox: sinon.SinonSandbox; diff --git a/yarn.lock b/yarn.lock index b32d882f73..27c1bad3a6 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3786,6 +3786,23 @@ __metadata: languageName: node linkType: hard +"@eslint/eslintrc@npm:^3.0.2": + version: 3.0.2 + resolution: "@eslint/eslintrc@npm:3.0.2" + dependencies: + ajv: "npm:^6.12.4" + debug: "npm:^4.3.2" + espree: "npm:^10.0.1" + globals: "npm:^14.0.0" + ignore: "npm:^5.2.0" + import-fresh: "npm:^3.2.1" + js-yaml: "npm:^4.1.0" + minimatch: "npm:^3.1.2" + strip-json-comments: "npm:^3.1.1" + checksum: 04e3d7de2b16fd59ba8985ecd6922eb488e630f94e4433858567a8a6c99b478bb7b47854b166b830b44905759547d0a03654eb1265952c812d5d1d70e3e4ccf9 + languageName: node + linkType: hard + "@eslint/js@npm:8.57.0": version: 8.57.0 resolution: "@eslint/js@npm:8.57.0" @@ -3793,6 +3810,13 @@ __metadata: languageName: node linkType: hard +"@eslint/js@npm:9.0.0": + version: 9.0.0 + resolution: "@eslint/js@npm:9.0.0" + checksum: b14b20af72410ef53e3e77e7d83cc1d6e6554b0092ceb9f969d25d765f4d775b4be32b0cd99bbfd6ce72eb2e4fb6b39b42a159b31909fbe1b3a5e88d75211687 + languageName: node + linkType: hard + "@eth-optimism/contracts-bedrock@npm:0.16.2": version: 0.16.2 resolution: "@eth-optimism/contracts-bedrock@npm:0.16.2" @@ -4874,6 +4898,17 @@ __metadata: languageName: node linkType: hard +"@humanwhocodes/config-array@npm:^0.12.3": + version: 0.12.3 + resolution: "@humanwhocodes/config-array@npm:0.12.3" + dependencies: + "@humanwhocodes/object-schema": "npm:^2.0.3" + debug: "npm:^4.3.1" + minimatch: "npm:^3.0.5" + checksum: b05f528c110aa1657d95d213e4ad2662f4161e838806af01a4d3f3b6ee3878d9b6f87d1b10704917f5c2f116757cb5c818480c32c4c4c6f84fe775a170b5f758 + languageName: node + linkType: hard + "@humanwhocodes/module-importer@npm:^1.0.1": version: 1.0.1 resolution: "@humanwhocodes/module-importer@npm:1.0.1" @@ -4888,6 +4923,13 @@ __metadata: languageName: node linkType: hard +"@humanwhocodes/object-schema@npm:^2.0.3": + version: 2.0.3 + resolution: "@humanwhocodes/object-schema@npm:2.0.3" + checksum: 05bb99ed06c16408a45a833f03a732f59bf6184795d4efadd33238ff8699190a8c871ad1121241bb6501589a9598dc83bf25b99dcbcf41e155cdf36e35e937a3 + languageName: node + linkType: hard + "@hyperlane-xyz/ccip-server@workspace:typescript/ccip-server": version: 0.0.0-use.local resolution: "@hyperlane-xyz/ccip-server@workspace:typescript/ccip-server" @@ -4961,7 +5003,7 @@ __metadata: hardhat-gas-reporter: "npm:^1.0.9" prettier: "npm:^2.8.8" prettier-plugin-solidity: "npm:^1.1.3" - solhint: "npm:^4.0.0" + solhint: "npm:^4.5.4" solhint-plugin-prettier: "npm:^0.0.5" solidity-coverage: "npm:^0.8.3" ts-generator: "npm:^0.1.1" @@ -5014,7 +5056,7 @@ __metadata: hardhat-gas-reporter: "npm:^1.0.9" prettier: "npm:^2.8.8" prettier-plugin-solidity: "npm:^1.1.3" - solhint: "npm:^4.0.0" + solhint: "npm:^4.5.4" solhint-plugin-prettier: "npm:^0.0.5" solidity-coverage: "npm:^0.8.3" ts-node: "npm:^10.8.0" @@ -5085,8 +5127,9 @@ __metadata: "@trivago/prettier-plugin-sort-imports": "npm:^4.2.1" "@typescript-eslint/eslint-plugin": "npm:^7.4.0" "@typescript-eslint/parser": "npm:^7.4.0" - eslint: "npm:^8.57.0" + eslint: "npm:^9.0.0" eslint-config-prettier: "npm:^9.1.0" + eslint-plugin-jest: "npm:^28.2.0" husky: "npm:^8.0.0" lint-staged: "npm:^12.4.3" prettier: "npm:^2.8.8" @@ -7600,7 +7643,7 @@ __metadata: languageName: node linkType: hard -"@solidity-parser/parser@npm:^0.16.0, @solidity-parser/parser@npm:^0.16.2": +"@solidity-parser/parser@npm:^0.16.2": version: 0.16.2 resolution: "@solidity-parser/parser@npm:0.16.2" dependencies: @@ -7609,6 +7652,13 @@ __metadata: languageName: node linkType: hard +"@solidity-parser/parser@npm:^0.18.0": + version: 0.18.0 + resolution: "@solidity-parser/parser@npm:0.18.0" + checksum: 3b600b584f49bd84d6d27aeeb453c49c279df49324e104bda00d12cd3b26f18cb6230ff63db6a0ba1f383868620d318b15b7417a92aa8c580099449adaa13d76 + languageName: node + linkType: hard + "@stablelib/aead@npm:^1.0.1": version: 1.0.1 resolution: "@stablelib/aead@npm:1.0.1" @@ -8628,6 +8678,16 @@ __metadata: languageName: node linkType: hard +"@typescript-eslint/scope-manager@npm:6.21.0": + version: 6.21.0 + resolution: "@typescript-eslint/scope-manager@npm:6.21.0" + dependencies: + "@typescript-eslint/types": "npm:6.21.0" + "@typescript-eslint/visitor-keys": "npm:6.21.0" + checksum: fe91ac52ca8e09356a71dc1a2f2c326480f3cccfec6b2b6d9154c1a90651ab8ea270b07c67df5678956c3bbf0bbe7113ab68f68f21b20912ea528b1214197395 + languageName: node + linkType: hard + "@typescript-eslint/scope-manager@npm:7.4.0": version: 7.4.0 resolution: "@typescript-eslint/scope-manager@npm:7.4.0" @@ -8655,6 +8715,13 @@ __metadata: languageName: node linkType: hard +"@typescript-eslint/types@npm:6.21.0": + version: 6.21.0 + resolution: "@typescript-eslint/types@npm:6.21.0" + checksum: e26da86d6f36ca5b6ef6322619f8ec55aabcd7d43c840c977ae13ae2c964c3091fc92eb33730d8be08927c9de38466c5323e78bfb270a9ff1d3611fe821046c5 + languageName: node + linkType: hard + "@typescript-eslint/types@npm:7.4.0": version: 7.4.0 resolution: "@typescript-eslint/types@npm:7.4.0" @@ -8662,6 +8729,25 @@ __metadata: languageName: node linkType: hard +"@typescript-eslint/typescript-estree@npm:6.21.0": + version: 6.21.0 + resolution: "@typescript-eslint/typescript-estree@npm:6.21.0" + dependencies: + "@typescript-eslint/types": "npm:6.21.0" + "@typescript-eslint/visitor-keys": "npm:6.21.0" + debug: "npm:^4.3.4" + globby: "npm:^11.1.0" + is-glob: "npm:^4.0.3" + minimatch: "npm:9.0.3" + semver: "npm:^7.5.4" + ts-api-utils: "npm:^1.0.1" + peerDependenciesMeta: + typescript: + optional: true + checksum: b32fa35fca2a229e0f5f06793e5359ff9269f63e9705e858df95d55ca2cd7fdb5b3e75b284095a992c48c5fc46a1431a1a4b6747ede2dd08929dc1cbacc589b8 + languageName: node + linkType: hard + "@typescript-eslint/typescript-estree@npm:7.4.0": version: 7.4.0 resolution: "@typescript-eslint/typescript-estree@npm:7.4.0" @@ -8698,6 +8784,33 @@ __metadata: languageName: node linkType: hard +"@typescript-eslint/utils@npm:^6.0.0": + version: 6.21.0 + resolution: "@typescript-eslint/utils@npm:6.21.0" + dependencies: + "@eslint-community/eslint-utils": "npm:^4.4.0" + "@types/json-schema": "npm:^7.0.12" + "@types/semver": "npm:^7.5.0" + "@typescript-eslint/scope-manager": "npm:6.21.0" + "@typescript-eslint/types": "npm:6.21.0" + "@typescript-eslint/typescript-estree": "npm:6.21.0" + semver: "npm:^7.5.4" + peerDependencies: + eslint: ^7.0.0 || ^8.0.0 + checksum: b404a2c55a425a79d054346ae123087d30c7ecf7ed7abcf680c47bf70c1de4fabadc63434f3f460b2fa63df76bc9e4a0b9fa2383bb8a9fcd62733fb5c4e4f3e3 + languageName: node + linkType: hard + +"@typescript-eslint/visitor-keys@npm:6.21.0": + version: 6.21.0 + resolution: "@typescript-eslint/visitor-keys@npm:6.21.0" + dependencies: + "@typescript-eslint/types": "npm:6.21.0" + eslint-visitor-keys: "npm:^3.4.1" + checksum: 30422cdc1e2ffad203df40351a031254b272f9c6f2b7e02e9bfa39e3fc2c7b1c6130333b0057412968deda17a3a68a578a78929a8139c6acef44d9d841dc72e1 + languageName: node + linkType: hard + "@typescript-eslint/visitor-keys@npm:7.4.0": version: 7.4.0 resolution: "@typescript-eslint/visitor-keys@npm:7.4.0" @@ -9659,7 +9772,7 @@ __metadata: languageName: node linkType: hard -"antlr4@npm:^4.11.0": +"antlr4@npm:^4.13.1-patch-1": version: 4.13.1 resolution: "antlr4@npm:4.13.1" checksum: b17ee045cf30c7cec563f3ce81dc8bffd2c17b546646cd76e7b5f4cc4b676a1960c1a8a9aea53769947b0c6de70ed2aea73431e76c3840ab3b69cf3de5f1fc89 @@ -12725,6 +12838,24 @@ __metadata: languageName: node linkType: hard +"eslint-plugin-jest@npm:^28.2.0": + version: 28.2.0 + resolution: "eslint-plugin-jest@npm:28.2.0" + dependencies: + "@typescript-eslint/utils": "npm:^6.0.0" + peerDependencies: + "@typescript-eslint/eslint-plugin": ^6.0.0 || ^7.0.0 + eslint: ^7.0.0 || ^8.0.0 || ^9.0.0 + jest: "*" + peerDependenciesMeta: + "@typescript-eslint/eslint-plugin": + optional: true + jest: + optional: true + checksum: 029a3d140a561d941580cbfee15ccacf4584971975f61111f07b87f01bf64c9739607cbe8e6fd3888429179ea8fd733e655ccd87b3b83b3b5cee2187e2355a4e + languageName: node + linkType: hard + "eslint-scope@npm:^7.2.2": version: 7.2.2 resolution: "eslint-scope@npm:7.2.2" @@ -12735,6 +12866,16 @@ __metadata: languageName: node linkType: hard +"eslint-scope@npm:^8.0.1": + version: 8.0.1 + resolution: "eslint-scope@npm:8.0.1" + dependencies: + esrecurse: "npm:^4.3.0" + estraverse: "npm:^5.2.0" + checksum: 458513863d3c79005b599f40250437bddba923f18549058ea45820a8d3d4bbc67fe292751d522a0cab69dd01fe211ffde5c1a5fc867e86f2d28727b1d61610da + languageName: node + linkType: hard + "eslint-visitor-keys@npm:^3.3.0": version: 3.3.0 resolution: "eslint-visitor-keys@npm:3.3.0" @@ -12756,6 +12897,13 @@ __metadata: languageName: node linkType: hard +"eslint-visitor-keys@npm:^4.0.0": + version: 4.0.0 + resolution: "eslint-visitor-keys@npm:4.0.0" + checksum: c7617166e6291a15ce2982b5c4b9cdfb6409f5c14562712d12e2584480cdf18609694b21d7dad35b02df0fa2cd037505048ded54d2f405c64f600949564eb334 + languageName: node + linkType: hard + "eslint@npm:^8.57.0": version: 8.57.0 resolution: "eslint@npm:8.57.0" @@ -12804,6 +12952,61 @@ __metadata: languageName: node linkType: hard +"eslint@npm:^9.0.0": + version: 9.0.0 + resolution: "eslint@npm:9.0.0" + dependencies: + "@eslint-community/eslint-utils": "npm:^4.2.0" + "@eslint-community/regexpp": "npm:^4.6.1" + "@eslint/eslintrc": "npm:^3.0.2" + "@eslint/js": "npm:9.0.0" + "@humanwhocodes/config-array": "npm:^0.12.3" + "@humanwhocodes/module-importer": "npm:^1.0.1" + "@nodelib/fs.walk": "npm:^1.2.8" + ajv: "npm:^6.12.4" + chalk: "npm:^4.0.0" + cross-spawn: "npm:^7.0.2" + debug: "npm:^4.3.2" + escape-string-regexp: "npm:^4.0.0" + eslint-scope: "npm:^8.0.1" + eslint-visitor-keys: "npm:^4.0.0" + espree: "npm:^10.0.1" + esquery: "npm:^1.4.2" + esutils: "npm:^2.0.2" + fast-deep-equal: "npm:^3.1.3" + file-entry-cache: "npm:^8.0.0" + find-up: "npm:^5.0.0" + glob-parent: "npm:^6.0.2" + graphemer: "npm:^1.4.0" + ignore: "npm:^5.2.0" + imurmurhash: "npm:^0.1.4" + is-glob: "npm:^4.0.0" + is-path-inside: "npm:^3.0.3" + json-stable-stringify-without-jsonify: "npm:^1.0.1" + levn: "npm:^0.4.1" + lodash.merge: "npm:^4.6.2" + minimatch: "npm:^3.1.2" + natural-compare: "npm:^1.4.0" + optionator: "npm:^0.9.3" + strip-ansi: "npm:^6.0.1" + text-table: "npm:^0.2.0" + bin: + eslint: bin/eslint.js + checksum: 5cf03e14eb114f95bc4e553c8ae2da65ec09d519779beb08e326d98518bce647ce9c8bf3467bcea4cab35a2657cc3a8e945717e784afa4b1bdb9d1ecd9173ba0 + languageName: node + linkType: hard + +"espree@npm:^10.0.1": + version: 10.0.1 + resolution: "espree@npm:10.0.1" + dependencies: + acorn: "npm:^8.11.3" + acorn-jsx: "npm:^5.3.2" + eslint-visitor-keys: "npm:^4.0.0" + checksum: 557d6cfb4894b1489effcaed8702682086033f8a2449568933bc59493734733d750f2a87907ba575844d3933340aea2d84288f5e67020c6152f6fd18a86497b2 + languageName: node + linkType: hard + "espree@npm:^9.6.0, espree@npm:^9.6.1": version: 9.6.1 resolution: "espree@npm:9.6.1" @@ -13557,6 +13760,15 @@ __metadata: languageName: node linkType: hard +"file-entry-cache@npm:^8.0.0": + version: 8.0.0 + resolution: "file-entry-cache@npm:8.0.0" + dependencies: + flat-cache: "npm:^4.0.0" + checksum: afe55c4de4e0d226a23c1eae62a7219aafb390859122608a89fa4df6addf55c7fd3f1a2da6f5b41e7cdff496e4cf28bbd215d53eab5c817afa96d2b40c81bfb0 + languageName: node + linkType: hard + "file-uri-to-path@npm:1.0.0": version: 1.0.0 resolution: "file-uri-to-path@npm:1.0.0" @@ -13662,6 +13874,16 @@ __metadata: languageName: node linkType: hard +"flat-cache@npm:^4.0.0": + version: 4.0.1 + resolution: "flat-cache@npm:4.0.1" + dependencies: + flatted: "npm:^3.2.9" + keyv: "npm:^4.5.4" + checksum: 58ce851d9045fffc7871ce2bd718bc485ad7e777bf748c054904b87c351ff1080c2c11da00788d78738bfb51b71e4d5ea12d13b98eb36e3358851ffe495b62dc + languageName: node + linkType: hard + "flat@npm:^5.0.2": version: 5.0.2 resolution: "flat@npm:5.0.2" @@ -13678,6 +13900,13 @@ __metadata: languageName: node linkType: hard +"flatted@npm:^3.2.9": + version: 3.3.1 + resolution: "flatted@npm:3.3.1" + checksum: 7b8376061d5be6e0d3658bbab8bde587647f68797cf6bfeae9dea0e5137d9f27547ab92aaff3512dd9d1299086a6d61be98e9d48a56d17531b634f77faadbc49 + languageName: node + linkType: hard + "fmix@npm:^0.1.0": version: 0.1.0 resolution: "fmix@npm:0.1.0" @@ -14413,6 +14642,13 @@ __metadata: languageName: node linkType: hard +"globals@npm:^14.0.0": + version: 14.0.0 + resolution: "globals@npm:14.0.0" + checksum: 03939c8af95c6df5014b137cac83aa909090c3a3985caef06ee9a5a669790877af8698ab38007e4c0186873adc14c0b13764acc754b16a754c216cc56aa5f021 + languageName: node + linkType: hard + "globalthis@npm:^1.0.1, globalthis@npm:^1.0.3": version: 1.0.3 resolution: "globalthis@npm:1.0.3" @@ -16787,7 +17023,7 @@ __metadata: languageName: node linkType: hard -"keyv@npm:^4.5.3": +"keyv@npm:^4.5.3, keyv@npm:^4.5.4": version: 4.5.4 resolution: "keyv@npm:4.5.4" dependencies: @@ -21374,13 +21610,13 @@ __metadata: languageName: node linkType: hard -"solhint@npm:^4.0.0": - version: 4.0.0 - resolution: "solhint@npm:4.0.0" +"solhint@npm:^4.5.4": + version: 4.5.4 + resolution: "solhint@npm:4.5.4" dependencies: - "@solidity-parser/parser": "npm:^0.16.0" + "@solidity-parser/parser": "npm:^0.18.0" ajv: "npm:^6.12.6" - antlr4: "npm:^4.11.0" + antlr4: "npm:^4.13.1-patch-1" ast-parents: "npm:^0.0.1" chalk: "npm:^4.1.2" commander: "npm:^10.0.0" @@ -21402,7 +21638,7 @@ __metadata: optional: true bin: solhint: solhint.js - checksum: 41e01c292ea16d9b1303d689c6381426aa845697911edd915ccf4019b58fae499af4ee7c47aa2c83601535f3824a1d27220735aa8e35816e03768518ccb18fb6 + checksum: 0d839f4c81b83ec2fa9db5003971623b4ca6895348d55874bd9189c4af06c8c5328789410a2859496b7cbdee0ed0321694d63d83f5c94955f4d00bc15e317e41 languageName: node linkType: hard From 2b3f75836a70617e2a977d93ab3f483587901823 Mon Sep 17 00:00:00 2001 From: J M Rossy Date: Tue, 16 Apr 2024 13:04:40 -0400 Subject: [PATCH 02/16] Add objLength and isObjEmpty util fns (#3605) ### Description Add `objLength` and `isObjEmpty` utils ### Related issues Fixes https://github.com/hyperlane-xyz/issues/issues/1199 ### Backward compatibility Yes --- .changeset/poor-kings-fold.md | 5 +++++ typescript/utils/src/index.ts | 2 ++ typescript/utils/src/objects.ts | 8 ++++++++ 3 files changed, 15 insertions(+) create mode 100644 .changeset/poor-kings-fold.md diff --git a/.changeset/poor-kings-fold.md b/.changeset/poor-kings-fold.md new file mode 100644 index 0000000000..4f24dc3f9e --- /dev/null +++ b/.changeset/poor-kings-fold.md @@ -0,0 +1,5 @@ +--- +'@hyperlane-xyz/utils': patch +--- + +Add objLength and isObjEmpty utils diff --git a/typescript/utils/src/index.ts b/typescript/utils/src/index.ts index 7af1f93abf..8c965bad82 100644 --- a/typescript/utils/src/index.ts +++ b/typescript/utils/src/index.ts @@ -100,9 +100,11 @@ export { deepCopy, deepEquals, invertKeysAndValues, + isObjEmpty, isObject, objFilter, objKeys, + objLength, objMap, objMapEntries, objMerge, diff --git a/typescript/utils/src/objects.ts b/typescript/utils/src/objects.ts index 6e8a2386cb..9f3dd466cf 100644 --- a/typescript/utils/src/objects.ts +++ b/typescript/utils/src/objects.ts @@ -17,6 +17,14 @@ export function objKeys(obj: Record): T[] { return Object.keys(obj) as T[]; } +export function objLength(obj: Record) { + return Object.keys(obj).length; +} + +export function isObjEmpty(obj: Record) { + return objLength(obj) === 0; +} + export function objMapEntries< M extends Record, K extends keyof M, From aea79c686ebd31d4ef250aea7d7c5d0b1eda7e7f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noah=20Bayindirli=20=F0=9F=A5=82?= Date: Tue, 16 Apr 2024 15:48:03 -0400 Subject: [PATCH 03/16] feat: add dry-run support for warp deploy + gas stats (#3586) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ### Description * New feature to allow users to dry-run the warp deploy script against a forked (base/origin) network of their choice * To run: `yarn build && yarn hyperlane deploy warp --dry-run` || `yarn build && yarn hyperlane deploy warp -d` * Externally enables: `hyperlane deploy warp --dry-run` || `hyperlane deploy warp -d` * Also adds gas usage util for both warp & core deployments in all contexts, e.g. * When running a vanilla core deploy, for example, between alfajores and fuji, you will now see: ``` ⛽️ Gas Usage Statistics - Gas required for core deploy on alfajores: 0.0058686745 CELO - Gas required for core deploy on fuji: 0.0239308515 AVAX ``` ### Drive-by changes * None ### Related issues * Fixes https://github.com/hyperlane-xyz/issues/issues/819 ### Backward compatibility * Yes ### Testing * Note: `hl` == `yarn build && yarn hyperlane`. The below tests are only a sample and are not inclusive. #### Manual Testing * With `anvil` NOT running in separate instance: * `hl deploy warp -d` * Throws: ``` Error: No active anvil node detected. Please run `anvil` in a separate instance. ``` * With `anvil` running in separate instance: * `hl deploy warp -d -k c0052e22df5d1f4ae7c51e254Xx00Xx0eb833453eaed6301xXxxx8a30d92d10a` (any private key) * Throws `Error: Invalid address length. Please ensure you are passing an address and not a private key.` * `hl deploy warp -d -k 0x16F4898F47c085C41d7Cc6b1dc0xX0xXX017dcBb` (any public address) * Output: ``` 🔎 Verifying anvil node is running... ✅ Successfully verified anvil node is running Using warp route deployment config at ./configs/warp-route-deployment.yaml No chain config file provided ? Do you want to use some core deployment address artifacts? This is required for PI chains (non-core chains). no Forking alfajores for dry-run... ✅ Successfully forked alfajores for dry-run Impersonating account (0x16F4898F47c085C41d7Cc6b1dc72B91EA617dcBb)... ✅ Successfully impersonated account (0x16F4898F47c085C41d7Cc6b1dc72B91EA617dcBb) ... ✅ Hyp token deployments complete Writing deployment artifacts Deployment is complete! Contract address artifacts are in artifacts/dry-run_warp-route-deployment-2024-04-16-12-27-02.json Warp config is in artifacts/dry-run_warp-config-2024-04-16-12-27-02.json ⛽️ Gas Usage Statistics - Gas required for warp dry-run on alfajores: 0.013310162514578124 CELO Resetting forked network... ✅ Successfully reset forked network ✅ Warp dry-run completed successfully ``` #### CI Testing * Successful CI-backed integration/regression testing via `ci-test.sh` --- .changeset/early-crabs-float.md | 5 ++ rust/.gitignore | 1 + typescript/cli/ci-test.sh | 35 +++++++- .../cli/examples/dry-run/anvil-chains.yaml | 17 ++++ typescript/cli/examples/dry-run/ism.yaml | 8 ++ .../dry-run/warp-route-deployment.yaml | 5 ++ typescript/cli/src/commands/deploy.ts | 45 ++++++++--- typescript/cli/src/commands/options.ts | 3 +- typescript/cli/src/deploy/core.ts | 52 ++++++------ typescript/cli/src/deploy/dry-run.ts | 20 ++++- typescript/cli/src/deploy/utils.ts | 71 ++++++++++++++-- typescript/cli/src/deploy/warp.ts | 81 +++++++++++++++---- typescript/cli/src/utils/files.ts | 16 ++++ typescript/cli/src/utils/fork.ts | 8 +- 14 files changed, 300 insertions(+), 67 deletions(-) create mode 100644 .changeset/early-crabs-float.md create mode 100644 typescript/cli/examples/dry-run/anvil-chains.yaml create mode 100644 typescript/cli/examples/dry-run/ism.yaml create mode 100644 typescript/cli/examples/dry-run/warp-route-deployment.yaml diff --git a/.changeset/early-crabs-float.md b/.changeset/early-crabs-float.md new file mode 100644 index 0000000000..2caae83a36 --- /dev/null +++ b/.changeset/early-crabs-float.md @@ -0,0 +1,5 @@ +--- +'@hyperlane-xyz/cli': minor +--- + +Adds single-chain dry-run support for deploying warp routes & gas estimation for core and warp route dry-run deployments. diff --git a/rust/.gitignore b/rust/.gitignore index ffe12328db..dcdf8bcd72 100644 --- a/rust/.gitignore +++ b/rust/.gitignore @@ -4,3 +4,4 @@ relayerdb kathydb hyperlane_db config/test_config.json +validator_db_anvil* diff --git a/typescript/cli/ci-test.sh b/typescript/cli/ci-test.sh index a62d2e0169..987862cfee 100755 --- a/typescript/cli/ci-test.sh +++ b/typescript/cli/ci-test.sh @@ -29,6 +29,7 @@ _main() { DEPLOYER=$(cast rpc eth_accounts | jq -r '.[0]'); run_hyperlane_deploy_core_dry_run; + run_hyperlane_deploy_warp_dry_run; reset_anvil; @@ -124,12 +125,16 @@ kill_anvil() { } run_hyperlane_deploy_core_dry_run() { + if [ "$TEST_TYPE" == $TEST_TYPE_PI_CORE ]; then + return; + fi + BEFORE_CORE_DRY_RUN=$(cast balance $DEPLOYER --rpc-url http://127.0.0.1:${CHAIN1_PORT}); echo -e "\nDry-running contract deployments to Alfajores" yarn workspace @hyperlane-xyz/cli run hyperlane deploy core --dry-run \ --targets alfajores \ - --chains ${EXAMPLES_PATH}/anvil-chains.yaml \ + --chains ${EXAMPLES_PATH}/dry-run/anvil-chains.yaml \ --artifacts /tmp/empty-artifacts.json \ $(if [ "$HOOK_FLAG" == "true" ]; then echo "--hook ${EXAMPLES_PATH}/hooks.yaml"; fi) \ --ism ${EXAMPLES_PATH}/ism.yaml \ @@ -150,6 +155,33 @@ run_hyperlane_deploy_core_dry_run() { AGENT_CONFIG_FILENAME=`ls -t1 /tmp | grep agent-config | head -1` } +run_hyperlane_deploy_warp_dry_run() { + if [ "$TEST_TYPE" == $TEST_TYPE_PI_CORE ]; then + return; + fi + + BEFORE_WARP_DRY_RUN=$(cast balance $DEPLOYER --rpc-url http://127.0.0.1:${CHAIN1_PORT}); + + echo -e "\nDry-running warp route deployments to Alfajores" + yarn workspace @hyperlane-xyz/cli run hyperlane deploy warp --dry-run \ + --chains ${EXAMPLES_PATH}/dry-run/anvil-chains.yaml \ + --core $CORE_ARTIFACTS_PATH \ + --config ${EXAMPLES_PATH}/dry-run/warp-route-deployment.yaml \ + --out /tmp \ + --key 0xfaD1C94469700833717Fa8a3017278BC1cA8031C \ + --yes + + AFTER_WARP_DRY_RUN=$(cast balance $DEPLOYER --rpc-url http://127.0.0.1:${CHAIN1_PORT}) + GAS_PRICE=$(cast gas-price --rpc-url http://127.0.0.1:${CHAIN1_PORT}) + WARP_MIN_GAS=$(bc <<< "($BEFORE_WARP_DRY_RUN - $AFTER_WARP_DRY_RUN) / $GAS_PRICE") + echo "Gas used: $WARP_MIN_GAS" + + WARP_ARTIFACTS_PATH=`find /tmp/dry-run_warp-route-deployment* -type f -exec ls -t1 {} + | head -1` + echo "Warp dry-run artifacts:" + echo $WARP_ARTIFACTS_PATH + cat $WARP_ARTIFACTS_PATH +} + run_hyperlane_deploy_core() { BEFORE_CORE=$(cast balance $DEPLOYER --rpc-url http://127.0.0.1:${CHAIN1_PORT}); @@ -346,4 +378,5 @@ run_hyperlane_status() { } _main "$@"; + exit; diff --git a/typescript/cli/examples/dry-run/anvil-chains.yaml b/typescript/cli/examples/dry-run/anvil-chains.yaml new file mode 100644 index 0000000000..f8169f4791 --- /dev/null +++ b/typescript/cli/examples/dry-run/anvil-chains.yaml @@ -0,0 +1,17 @@ +anvil: + chainId: 31337 + domainId: 31337 + name: anvil + protocol: ethereum + rpcUrls: + - http: http://127.0.0.1:8545 + nativeToken: + name: Ether + symbol: ETH + decimals: 18 +alfajores: + rpcUrls: + - http: https://alfajores-forno.celo-testnet.org + blocks: + confirmations: 1 + estimateBlockTime: 1 diff --git a/typescript/cli/examples/dry-run/ism.yaml b/typescript/cli/examples/dry-run/ism.yaml new file mode 100644 index 0000000000..a9d20e6135 --- /dev/null +++ b/typescript/cli/examples/dry-run/ism.yaml @@ -0,0 +1,8 @@ +anvil: + threshold: 1 + validators: + - '0xa0ee7a142d267c1f36714e4a8f75612f20a79720' +alfajores: + threshold: 1 + validators: + - '0xa0ee7a142d267c1f36714e4a8f75612f20a79720' diff --git a/typescript/cli/examples/dry-run/warp-route-deployment.yaml b/typescript/cli/examples/dry-run/warp-route-deployment.yaml new file mode 100644 index 0000000000..203abe6748 --- /dev/null +++ b/typescript/cli/examples/dry-run/warp-route-deployment.yaml @@ -0,0 +1,5 @@ +base: + chainName: alfajores + type: native +synthetics: + - chainName: fuji diff --git a/typescript/cli/src/commands/deploy.ts b/typescript/cli/src/commands/deploy.ts index 9357ce4dfc..b14c6e5cc2 100644 --- a/typescript/cli/src/commands/deploy.ts +++ b/typescript/cli/src/commands/deploy.ts @@ -25,11 +25,18 @@ import { warpConfigCommandOption, } from './options.js'; +export enum Command { + DEPLOY = 'deploy', + KURTOSIS_AGENTS = 'kurtosis-agents', + CORE = 'core', + WARP = 'warp', +} + /** * Parent command */ export const deployCommand: CommandModule = { - command: 'deploy', + command: Command.DEPLOY, describe: 'Permissionlessly deploy a Hyperlane contracts or extensions', builder: (yargs) => yargs @@ -45,7 +52,7 @@ export const deployCommand: CommandModule = { * Agent command */ const agentCommand: CommandModule = { - command: 'kurtosis-agents', + command: Command.KURTOSIS_AGENTS, describe: 'Deploy Hyperlane agents with Kurtosis', builder: (yargs) => yargs.options({ @@ -75,7 +82,7 @@ const agentCommand: CommandModule = { * Core command */ const coreCommand: CommandModule = { - command: 'core', + command: Command.CORE, describe: 'Deploy core Hyperlane contracts', builder: (yargs) => yargs.options({ @@ -133,7 +140,7 @@ const coreCommand: CommandModule = { * Warp command */ const warpCommand: CommandModule = { - command: 'warp', + command: Command.WARP, describe: 'Deploy Warp Route contracts', builder: (yargs) => yargs.options({ @@ -143,6 +150,7 @@ const warpCommand: CommandModule = { out: outDirCommandOption, key: keyCommandOption, yes: skipConfirmationOption, + 'dry-run': dryRunOption, }), handler: async (argv: any) => { const key: string | undefined = argv.key; @@ -151,14 +159,27 @@ const warpCommand: CommandModule = { const coreArtifactsPath: string | undefined = argv.core; const outPath: string = argv.out; const skipConfirmation: boolean = argv.yes; - await runWarpRouteDeploy({ - key, - chainConfigPath, - warpRouteDeploymentConfigPath, - coreArtifactsPath, - outPath, - skipConfirmation, - }); + const dryRun: boolean = argv.dryRun; + + logGray(`Hyperlane warp route deployment${dryRun ? ' dry-run' : ''}`); + logGray('------------------------------------------------'); + + if (dryRun) await verifyAnvil(); + + try { + await runWarpRouteDeploy({ + key, + chainConfigPath, + warpRouteDeploymentConfigPath, + coreArtifactsPath, + outPath, + skipConfirmation, + dryRun, + }); + } catch (error: any) { + evaluateIfDryRunFailure(error, dryRun); + throw error; + } process.exit(0); }, }; diff --git a/typescript/cli/src/commands/options.ts b/typescript/cli/src/commands/options.ts index aaf3e48429..9bb0c954b0 100644 --- a/typescript/cli/src/commands/options.ts +++ b/typescript/cli/src/commands/options.ts @@ -40,6 +40,7 @@ export type WarpCommandOptions = CommandOptions & { out: Options; key: Options; yes: Options; + 'dry-run': Options; }; export const coreTargetsCommandOption: Options = { @@ -144,5 +145,5 @@ export const dryRunOption: Options = { description: 'Simulate deployment on forked network. Please ensure an anvil node instance is running during execution via `anvil`.', default: false, - alias: 'd', + alias: ['d', 'dr'], }; diff --git a/typescript/cli/src/deploy/core.ts b/typescript/cli/src/deploy/core.ts index f2d3178c18..67032d23e7 100644 --- a/typescript/cli/src/deploy/core.ts +++ b/typescript/cli/src/deploy/core.ts @@ -29,6 +29,7 @@ import { } from '@hyperlane-xyz/sdk'; import { Address, objFilter, objMerge } from '@hyperlane-xyz/utils'; +import { Command } from '../commands/deploy.js'; import { runDeploymentArtifactStep } from '../config/artifacts.js'; import { presetHookConfigs, readHooksConfigMap } from '../config/hooks.js'; import { readIsmConfig } from '../config/ism.js'; @@ -50,16 +51,17 @@ import { } from '../logger.js'; import { runMultiChainSelectionStep } from '../utils/chains.js'; import { - ArtifactsFile, + getArtifactsFiles, prepNewArtifactsFiles, runFileSelectionStep, writeJson, } from '../utils/files.js'; -import { resetFork } from '../utils/fork.js'; import { + completeDeploy, isISMConfig, isZODISMConfig, + prepareDeploy, runPreflightChecksForChains, } from './utils.js'; @@ -146,9 +148,25 @@ export async function runCoreDeploy({ ...deploymentParams, minGas: MINIMUM_CORE_DEPLOY_GAS, }); + + const userAddress = dryRun ? key! : await signer.getAddress(); + + const initialBalances = await prepareDeploy( + multiProvider, + userAddress, + chains, + ); + await executeDeploy(deploymentParams); - if (dryRun) await resetFork(); + await completeDeploy( + Command.CORE, + initialBalances, + multiProvider, + userAddress, + chains, + dryRun, + ); } function runArtifactStep( @@ -305,7 +323,13 @@ async function executeDeploy({ const [contractsFilePath, agentFilePath] = prepNewArtifactsFiles( outPath, - getArtifactsFiles(dryRun), + getArtifactsFiles( + [ + { filename: 'core-deployment', description: 'Contract addresses' }, + { filename: 'agent-config', description: 'Agent configs' }, + ], + dryRun, + ), ); const owner = await signer.getAddress(); @@ -367,7 +391,7 @@ async function executeDeploy({ } artifacts = objMerge(artifacts, isms); artifacts = writeMergedAddresses(contractsFilePath, artifacts, coreContracts); - logGreen('Core contracts deployed'); + logGreen('✅ Core contracts deployed'); log('Writing agent configs'); await writeAgentConfig(agentFilePath, artifacts, chains, multiProvider); @@ -378,24 +402,6 @@ async function executeDeploy({ logBlue(`Agent configs are in ${agentFilePath}`); } -/** - * Retrieves artifacts file metadata for the current command. - * @param dryRun whether or not the current command is being dry-run - * @returns the artifacts files - */ -function getArtifactsFiles(dryRun: boolean): Array { - const coreDeploymentFile = { - filename: dryRun ? 'dry-run_core-deployment' : 'core-deployment', - description: 'Contract addresses', - }; - const agentConfigFile = { - filename: dryRun ? 'dry-run_agent-config' : 'agent-config', - description: 'Agent configs', - }; - - return [coreDeploymentFile, agentConfigFile]; -} - function buildIsmConfig( owner: Address, local: ChainName, diff --git a/typescript/cli/src/deploy/dry-run.ts b/typescript/cli/src/deploy/dry-run.ts index a4da84d12a..be2663cde9 100644 --- a/typescript/cli/src/deploy/dry-run.ts +++ b/typescript/cli/src/deploy/dry-run.ts @@ -1,7 +1,15 @@ import { MultiProvider } from '@hyperlane-xyz/sdk'; +import { Command } from '../commands/deploy.js'; import { logGray, logGreen, warnYellow } from '../logger.js'; -import { ANVIL_RPC_METHODS, getLocalProvider, setFork } from '../utils/fork.js'; +import { + ANVIL_RPC_METHODS, + getLocalProvider, + resetFork, + setFork, +} from '../utils/fork.js'; + +import { toUpperCamelCase } from './utils.js'; /** * Forks a provided network onto MultiProvider @@ -23,7 +31,7 @@ export async function forkNetworkToMultiProvider( * Ensures an anvil node is running locally. */ export async function verifyAnvil() { - logGray('Verifying anvil node is running...'); + logGray('🔎 Verifying anvil node is running...'); const provider = getLocalProvider(); try { @@ -34,7 +42,7 @@ export async function verifyAnvil() { \tPlease run \`anvil\` in a separate instance.`); } - logGreen('Successfully verified anvil node is running ✅'); + logGreen('✅ Successfully verified anvil node is running'); } /** @@ -48,3 +56,9 @@ export function evaluateIfDryRunFailure(error: any, dryRun: boolean) { '⛔️ [dry-run] The current RPC may not support forking. Please consider using a different RPC provider.', ); } + +export async function completeDryRun(command: Command) { + await resetFork(); + + logGreen(`✅ ${toUpperCamelCase(command)} dry-run completed successfully`); +} diff --git a/typescript/cli/src/deploy/utils.ts b/typescript/cli/src/deploy/utils.ts index e73be5dffa..0e1a6e2973 100644 --- a/typescript/cli/src/deploy/utils.ts +++ b/typescript/cli/src/deploy/utils.ts @@ -1,4 +1,4 @@ -import { ethers } from 'ethers'; +import { BigNumber, ethers } from 'ethers'; import { ChainMap, @@ -7,13 +7,17 @@ import { MultiProvider, MultisigConfig, } from '@hyperlane-xyz/sdk'; -import { ProtocolType } from '@hyperlane-xyz/utils'; +import { Address, ProtocolType } from '@hyperlane-xyz/utils'; +import { Command } from '../commands/deploy.js'; import { parseIsmConfig } from '../config/ism.js'; -import { log, logGreen } from '../logger.js'; +import { log, logGreen, logPink } from '../logger.js'; import { assertGasBalances } from '../utils/balances.js'; +import { getLocalProvider } from '../utils/fork.js'; import { assertSigner } from '../utils/keys.js'; +import { completeDryRun } from './dry-run.js'; + export async function runPreflightChecks({ origin, remotes, @@ -32,11 +36,11 @@ export async function runPreflightChecks({ log('Running pre-flight checks...'); if (!origin || !remotes?.length) throw new Error('Invalid chain selection'); - logGreen('Chain selections are valid ✅'); + logGreen('✅ Chain selections are valid'); if (remotes.includes(origin)) throw new Error('Origin and remotes must be distinct'); - logGreen('Origin and remote are distinct ✅'); + logGreen('✅ Origin and remote are distinct'); return runPreflightChecksForChains({ chains: [origin, ...remotes], @@ -71,10 +75,10 @@ export async function runPreflightChecksForChains({ if (metadata.protocol !== ProtocolType.Ethereum) throw new Error('Only Ethereum chains are supported for now'); } - logGreen('Chains are valid ✅'); + logGreen('✅ Chains are valid'); assertSigner(signer); - logGreen('Signer is valid ✅'); + logGreen('✅ Signer is valid'); await assertGasBalances( multiProvider, @@ -82,7 +86,7 @@ export async function runPreflightChecksForChains({ chainsToGasCheck ?? chains, minGas, ); - logGreen('Balances are sufficient ✅'); + logGreen('✅ Balances are sufficient'); } // from parsed types @@ -96,3 +100,54 @@ export function isISMConfig( export function isZODISMConfig(filepath: string): boolean { return parseIsmConfig(filepath).success; } + +export async function prepareDeploy( + multiProvider: MultiProvider, + userAddress: Address, + chains: ChainName[], + dryRun: boolean = false, +): Promise> { + const initialBalances: Record = {}; + await Promise.all( + chains.map(async (chain: ChainName) => { + const provider = dryRun + ? getLocalProvider() + : multiProvider.getProvider(chain); + const currentBalance = await provider.getBalance(userAddress); + initialBalances[chain] = currentBalance; + }), + ); + return initialBalances; +} + +export async function completeDeploy( + command: Command, + initialBalances: Record, + multiProvider: MultiProvider, + userAddress: Address, + chains: ChainName[], + dryRun: boolean = false, +) { + if (chains.length > 0) logPink(`⛽️ Gas Usage Statistics`); + for (const chain of chains) { + const provider = dryRun + ? getLocalProvider() + : multiProvider.getProvider(chain); + const currentBalance = await provider.getBalance(userAddress); + const balanceDelta = initialBalances[chain].sub(currentBalance); + if (dryRun && balanceDelta.lt(0)) break; + logPink( + `\t- Gas required for ${command} ${ + dryRun ? 'dry-run' : 'deploy' + } on ${chain}: ${ethers.utils.formatEther(balanceDelta)} ${ + multiProvider.getChainMetadata(chain).nativeToken?.symbol + }`, + ); + } + + if (dryRun) await completeDryRun(command); +} + +export function toUpperCamelCase(string: string) { + return string.charAt(0).toUpperCase() + string.slice(1); +} diff --git a/typescript/cli/src/deploy/warp.ts b/typescript/cli/src/deploy/warp.ts index 4af7972015..57e98754e8 100644 --- a/typescript/cli/src/deploy/warp.ts +++ b/typescript/cli/src/deploy/warp.ts @@ -22,21 +22,27 @@ import { } from '@hyperlane-xyz/sdk'; import { Address, ProtocolType, objMap } from '@hyperlane-xyz/utils'; +import { Command } from '../commands/deploy.js'; import { WarpRouteDeployConfig, readWarpRouteDeployConfig, } from '../config/warp.js'; import { MINIMUM_WARP_DEPLOY_GAS } from '../consts.js'; -import { getContext, getMergedContractAddresses } from '../context.js'; +import { + getContext, + getDryRunContext, + getMergedContractAddresses, +} from '../context.js'; import { log, logBlue, logGray, logGreen } from '../logger.js'; import { + getArtifactsFiles, isFile, prepNewArtifactsFiles, runFileSelectionStep, writeJson, } from '../utils/files.js'; -import { runPreflightChecks } from './utils.js'; +import { completeDeploy, prepareDeploy, runPreflightChecks } from './utils.js'; export async function runWarpRouteDeploy({ key, @@ -45,6 +51,7 @@ export async function runWarpRouteDeploy({ coreArtifactsPath, outPath, skipConfirmation, + dryRun, }: { key?: string; chainConfigPath: string; @@ -52,14 +59,8 @@ export async function runWarpRouteDeploy({ coreArtifactsPath?: string; outPath: string; skipConfirmation: boolean; + dryRun: boolean; }) { - const { multiProvider, signer, coreArtifacts } = await getContext({ - chainConfigPath, - coreConfig: { coreArtifactsPath }, - keyConfig: { key }, - skipConfirmation, - }); - if ( !warpRouteDeploymentConfigPath || !isFile(warpRouteDeploymentConfigPath) @@ -80,6 +81,21 @@ export async function runWarpRouteDeploy({ warpRouteDeploymentConfigPath, ); + const { multiProvider, signer, coreArtifacts } = dryRun + ? await getDryRunContext({ + chainConfigPath, + chains: [warpRouteConfig.base.chainName], + coreConfig: { coreArtifactsPath }, + keyConfig: { key }, + skipConfirmation, + }) + : await getContext({ + chainConfigPath, + coreConfig: { coreArtifactsPath }, + keyConfig: { key }, + skipConfirmation, + }); + const configs = await runBuildConfigStep({ warpRouteConfig, coreArtifacts, @@ -94,6 +110,7 @@ export async function runWarpRouteDeploy({ multiProvider, outPath, skipConfirmation, + dryRun, }; logBlue('Warp route deployment plan'); @@ -103,7 +120,26 @@ export async function runWarpRouteDeploy({ ...deploymentParams, minGas: MINIMUM_WARP_DEPLOY_GAS, }); + + const userAddress = dryRun ? key! : await signer.getAddress(); + const chains = [deploymentParams.origin, ...configs.remotes]; + + const initialBalances = await prepareDeploy( + multiProvider, + userAddress, + chains, + ); + await executeDeploy(deploymentParams); + + await completeDeploy( + Command.WARP, + initialBalances, + multiProvider, + userAddress, + chains, + dryRun, + ); } async function runBuildConfigStep({ @@ -219,6 +255,7 @@ interface DeployParams { multiProvider: MultiProvider; outPath: string; skipConfirmation: boolean; + dryRun: boolean; } async function runDeployPlanStep({ @@ -253,17 +290,31 @@ async function executeDeploy(params: DeployParams) { const { configMap, isNft, multiProvider, outPath } = params; - const [contractsFilePath, tokenConfigPath] = prepNewArtifactsFiles(outPath, [ - { filename: 'warp-route-deployment', description: 'Contract addresses' }, - { filename: 'warp-config', description: 'Warp config' }, - ]); + const [contractsFilePath, tokenConfigPath] = prepNewArtifactsFiles( + outPath, + getArtifactsFiles( + [ + { + filename: 'warp-route-deployment', + description: 'Contract addresses', + }, + { filename: 'warp-config', description: 'Warp config' }, + ], + params.dryRun, + ), + ); const deployer = isNft ? new HypERC721Deployer(multiProvider) : new HypERC20Deployer(multiProvider); - const deployedContracts = await deployer.deploy(configMap); - logGreen('Hyp token deployments complete'); + const config = params.dryRun + ? { [params.origin]: configMap[params.origin] } + : configMap; + + const deployedContracts = await deployer.deploy(config); + + logGreen('✅ Hyp token deployments complete'); log('Writing deployment artifacts'); writeTokenDeploymentArtifacts(contractsFilePath, deployedContracts, params); diff --git a/typescript/cli/src/utils/files.ts b/typescript/cli/src/utils/files.ts index 8f06c51c9a..ea70b5dc6a 100644 --- a/typescript/cli/src/utils/files.ts +++ b/typescript/cli/src/utils/files.ts @@ -163,6 +163,22 @@ export function prepNewArtifactsFiles( return newPaths; } +/** + * Retrieves artifacts file metadata for the current command. + * @param dryRun whether or not the current command is being dry-run + * @returns the artifacts files + */ +export function getArtifactsFiles( + defaultFiles: ArtifactsFile[], + dryRun: boolean = false, +): Array { + if (dryRun) + defaultFiles.map((defaultFile: ArtifactsFile) => { + defaultFile.filename = `dry-run_${defaultFile.filename}`; + }); + return defaultFiles; +} + export async function runFileSelectionStep( folderPath: string, description: string, diff --git a/typescript/cli/src/utils/fork.ts b/typescript/cli/src/utils/fork.ts index 460d1477ae..49979a9114 100644 --- a/typescript/cli/src/utils/fork.ts +++ b/typescript/cli/src/utils/fork.ts @@ -33,7 +33,7 @@ export const resetFork = async () => { }, ]); - logGreen(`Successfully reset forked network ✅`); + logGreen(`✅ Successfully reset forked network`); }; /** @@ -60,7 +60,7 @@ export const setFork = async ( multiProvider.setProvider(chain, provider); - logGreen(`Successfully forked ${chain} for dry-run ✅`); + logGreen(`✅ Successfully forked ${chain} for dry-run`); }; /** @@ -76,7 +76,7 @@ export const impersonateAccount = async ( const provider = getLocalProvider(); await provider.send(ANVIL_RPC_METHODS.IMPERSONATE_ACCOUNT, [address]); - logGreen(`Successfully impersonated account (${address}) ✅`); + logGreen(`✅ Successfully impersonated account (${address})`); return provider.getSigner(address); }; @@ -99,7 +99,7 @@ export const stopImpersonatingAccount = async (address: Address) => { ]); logGreen( - `Successfully stopped account impersonation for address (${address}) ✅`, + `✅ Successfully stopped account impersonation for address (${address})`, ); }; From f4626eb4fe139624cfd676b4fd7499bd2b2a79e6 Mon Sep 17 00:00:00 2001 From: Daniel Savu <23065004+daniel-savu@users.noreply.github.com> Date: Wed, 17 Apr 2024 12:47:37 +0100 Subject: [PATCH 04/16] Allow protocol-specific indexing (#3544) ### Description - Generalizes contract syncer hashmaps to store trait objects instead of concrete structs, since both `SequencedDataContractSync` and `WatermarkContractSync` implement `ContractSyncer` - The nice thing this enables is being able to instantiate a different type of syncer for the same contract, for different chain protocols (e.g. for IGP, we can use a sequenced syncer on sealevel and cosmwasm, and a watermark syncer on EVM). - The problem is that `ContractSyncer` is implemented on different trait bounds on `SequencedDataContractSync` and `WatermarkContractSync`. Most notably, the `SequencedDataContractSync` impl bounds the indexed type by the `Sequenced` trait. This means that if a type is to be indexed by more than one syncer strategy, it needs to implement the union of bounds of those strategies - **Blocker:** In the IGP, this means that `InterchainGasPayment` needs to implement `Sequenced` and we have no obvious way of getting that just from the type. Even if the sequence is derived from the type, it has to be a sensible value, since indexing reliability depends on it. - Similar to the point above, we now have `contract_syncs`, a single function that instantiates contract syncs for all chains. Since `contract_syncs` must be able to build a `ContractSyncer` trait obj for all syncer types, it bounds both `T` (the indexed type) and `D` (the log store type) with a union of bounds, so it may be too strict for some types in the future. - The scraper now uses forward-backward indexing instead of just forward indexing, because that simplified the refactor - there's now a convenience trait called `TryFromWithMetrics` that allows adding this bound: `SequenceIndexer: TryFromWithMetrics,`. This isn't really extendable if we use non-sequence indexers, but it's fine for now since this is used everywhere - replaces the macro-based contract syncer builder with generic fns Still todo: - add new `IndexingDecorator` struct that can wrap `InterchainGasPayment`, so we can use sequence-aware indexing for the IGP - remove sequence logic from the watermark cursor ### Drive-by changes ### Related issues ### Backward compatibility ### Testing --- rust/agents/relayer/src/relayer.rs | 49 +- rust/agents/scraper/src/agent.rs | 117 +++-- rust/agents/validator/src/validator.rs | 13 +- .../src/contract_sync/cursors/mod.rs | 443 ++---------------- .../src/contract_sync/cursors/rate_limited.rs | 421 +++++++++++++++++ rust/hyperlane-base/src/contract_sync/mod.rs | 101 ++-- .../src/db/rocks/hyperlane_db.rs | 14 + rust/hyperlane-base/src/settings/base.rs | 162 ++++--- rust/hyperlane-base/src/settings/chains.rs | 54 ++- rust/hyperlane-core/src/traits/indexer.rs | 3 + rust/hyperlane-core/src/types/mod.rs | 8 +- rust/sealevel/client/src/main.rs | 2 +- rust/utils/run-locally/src/solana.rs | 5 +- 13 files changed, 803 insertions(+), 589 deletions(-) create mode 100644 rust/hyperlane-base/src/contract_sync/cursors/rate_limited.rs diff --git a/rust/agents/relayer/src/relayer.rs b/rust/agents/relayer/src/relayer.rs index 0aa22be1f8..b0fae81421 100644 --- a/rust/agents/relayer/src/relayer.rs +++ b/rust/agents/relayer/src/relayer.rs @@ -12,8 +12,7 @@ use hyperlane_base::{ db::{HyperlaneRocksDB, DB}, metrics::{AgentMetrics, MetricsUpdater}, settings::ChainConf, - BaseAgent, ChainMetrics, ContractSyncMetrics, CoreMetrics, HyperlaneAgentCore, - SequencedDataContractSync, WatermarkContractSync, + BaseAgent, ChainMetrics, ContractSyncMetrics, ContractSyncer, CoreMetrics, HyperlaneAgentCore, }; use hyperlane_core::{ HyperlaneDomain, HyperlaneMessage, InterchainGasPayment, MerkleTreeInsertion, MpmcChannel, @@ -60,15 +59,14 @@ pub struct Relayer { destination_chains: HashMap, #[as_ref] core: HyperlaneAgentCore, - message_syncs: HashMap>>, + message_syncs: HashMap>>, interchain_gas_payment_syncs: - HashMap>>, + HashMap>>, /// Context data for each (origin, destination) chain pair a message can be /// sent between msg_ctxs: HashMap>, prover_syncs: HashMap>>, - merkle_tree_hook_syncs: - HashMap>>, + merkle_tree_hook_syncs: HashMap>>, dbs: HashMap, whitelist: Arc, blacklist: Arc, @@ -133,35 +131,46 @@ impl BaseAgent for Relayer { let contract_sync_metrics = Arc::new(ContractSyncMetrics::new(&core_metrics)); let message_syncs = settings - .build_message_indexers( + .contract_syncs::( settings.origin_chains.iter(), &core_metrics, &contract_sync_metrics, dbs.iter() - .map(|(d, db)| (d.clone(), Arc::new(db.clone()) as _)) + .map(|(d, db)| (d.clone(), Arc::new(db.clone()))) .collect(), ) - .await?; + .await? + .into_iter() + .map(|(k, v)| (k, v as _)) + .collect(); + let interchain_gas_payment_syncs = settings - .build_interchain_gas_payment_indexers( + .contract_syncs::( settings.origin_chains.iter(), &core_metrics, &contract_sync_metrics, dbs.iter() - .map(|(d, db)| (d.clone(), Arc::new(db.clone()) as _)) + .map(|(d, db)| (d.clone(), Arc::new(db.clone()))) .collect(), ) - .await?; + .await? + .into_iter() + .map(|(k, v)| (k, v as _)) + .collect(); + let merkle_tree_hook_syncs = settings - .build_merkle_tree_hook_indexers( + .contract_syncs::( settings.origin_chains.iter(), &core_metrics, &contract_sync_metrics, dbs.iter() - .map(|(d, db)| (d.clone(), Arc::new(db.clone()) as _)) + .map(|(d, db)| (d.clone(), Arc::new(db.clone()))) .collect(), ) - .await?; + .await? + .into_iter() + .map(|(k, v)| (k, v as _)) + .collect(); let whitelist = Arc::new(settings.whitelist); let blacklist = Arc::new(settings.blacklist); @@ -341,9 +350,7 @@ impl Relayer { async fn run_message_sync(&self, origin: &HyperlaneDomain) -> Instrumented> { let index_settings = self.as_ref().settings.chains[origin.name()].index_settings(); let contract_sync = self.message_syncs.get(origin).unwrap().clone(); - let cursor = contract_sync - .forward_backward_message_sync_cursor(index_settings) - .await; + let cursor = contract_sync.cursor(index_settings).await; tokio::spawn(async move { contract_sync .clone() @@ -363,7 +370,7 @@ impl Relayer { .get(origin) .unwrap() .clone(); - let cursor = contract_sync.rate_limited_cursor(index_settings).await; + let cursor = contract_sync.cursor(index_settings).await; tokio::spawn(async move { contract_sync.clone().sync("gas_payments", cursor).await }) .instrument(info_span!("ContractSync")) } @@ -374,9 +381,7 @@ impl Relayer { ) -> Instrumented> { let index_settings = self.as_ref().settings.chains[origin.name()].index.clone(); let contract_sync = self.merkle_tree_hook_syncs.get(origin).unwrap().clone(); - let cursor = contract_sync - .forward_backward_message_sync_cursor(index_settings) - .await; + let cursor = contract_sync.cursor(index_settings).await; tokio::spawn(async move { contract_sync.clone().sync("merkle_tree_hook", cursor).await }) .instrument(info_span!("ContractSync")) } diff --git a/rust/agents/scraper/src/agent.rs b/rust/agents/scraper/src/agent.rs index 7aa5cf6b14..cc113cacfd 100644 --- a/rust/agents/scraper/src/agent.rs +++ b/rust/agents/scraper/src/agent.rs @@ -5,9 +5,9 @@ use derive_more::AsRef; use futures::future::try_join_all; use hyperlane_base::{ metrics::AgentMetrics, settings::IndexSettings, BaseAgent, ChainMetrics, ContractSyncMetrics, - CoreMetrics, HyperlaneAgentCore, MetricsUpdater, + ContractSyncer, CoreMetrics, HyperlaneAgentCore, MetricsUpdater, }; -use hyperlane_core::HyperlaneDomain; +use hyperlane_core::{Delivery, HyperlaneDomain, HyperlaneMessage, InterchainGasPayment}; use tokio::task::JoinHandle; use tracing::{info_span, instrument::Instrumented, trace, Instrument}; @@ -173,41 +173,6 @@ impl Scraper { } } -/// Create a function to spawn task that syncs contract events -macro_rules! spawn_sync_task { - ($name:ident, $cursor: ident, $label:literal) => { - async fn $name( - &self, - domain: HyperlaneDomain, - metrics: Arc, - contract_sync_metrics: Arc, - db: HyperlaneSqlDb, - index_settings: IndexSettings, - ) -> Instrumented> { - let sync = self - .as_ref() - .settings - .$name( - &domain, - &metrics.clone(), - &contract_sync_metrics.clone(), - Arc::new(db.clone()), - ) - .await - .unwrap(); - let cursor = sync - .$cursor(index_settings.clone()) - .await; - tokio::spawn(async move { - sync - .sync($label, cursor) - .await - }) - .instrument(info_span!("ChainContractSync", chain=%domain.name(), event=$label)) - } - } -} - impl Scraper { async fn build_message_indexer( &self, @@ -220,39 +185,69 @@ impl Scraper { let sync = self .as_ref() .settings - .build_message_indexer( + .sequenced_contract_sync::( &domain, &metrics.clone(), &contract_sync_metrics.clone(), - Arc::new(db.clone()), + db.into(), ) .await .unwrap(); - let latest_nonce = self - .scrapers - .get(&domain.id()) - .unwrap() - .db - .last_message_nonce() - .await - .unwrap_or(None) - .unwrap_or(0); - let cursor = sync - .forward_message_sync_cursor(index_settings.clone(), latest_nonce.saturating_sub(1)) - .await; + let cursor = sync.cursor(index_settings.clone()).await; tokio::spawn(async move { sync.sync("message_dispatch", cursor).await }).instrument( info_span!("ChainContractSync", chain=%domain.name(), event="message_dispatch"), ) } - spawn_sync_task!( - build_delivery_indexer, - rate_limited_cursor, - "message_delivery" - ); - spawn_sync_task!( - build_interchain_gas_payment_indexer, - rate_limited_cursor, - "gas_payment" - ); + async fn build_delivery_indexer( + &self, + domain: HyperlaneDomain, + metrics: Arc, + contract_sync_metrics: Arc, + db: HyperlaneSqlDb, + index_settings: IndexSettings, + ) -> Instrumented> { + let sync = self + .as_ref() + .settings + .watermark_contract_sync::( + &domain, + &metrics.clone(), + &contract_sync_metrics.clone(), + Arc::new(db.clone()) as _, + ) + .await + .unwrap(); + + let label = "message_delivery"; + let cursor = sync.cursor(index_settings.clone()).await; + tokio::spawn(async move { sync.sync(label, cursor).await }) + .instrument(info_span!("ChainContractSync", chain=%domain.name(), event=label)) + } + + async fn build_interchain_gas_payment_indexer( + &self, + domain: HyperlaneDomain, + metrics: Arc, + contract_sync_metrics: Arc, + db: HyperlaneSqlDb, + index_settings: IndexSettings, + ) -> Instrumented> { + let sync = self + .as_ref() + .settings + .watermark_contract_sync::( + &domain, + &metrics.clone(), + &contract_sync_metrics.clone(), + Arc::new(db.clone()), + ) + .await + .unwrap(); + + let label = "gas_payment"; + let cursor = sync.cursor(index_settings.clone()).await; + tokio::spawn(async move { sync.sync(label, cursor).await }) + .instrument(info_span!("ChainContractSync", chain=%domain.name(), event=label)) + } } diff --git a/rust/agents/validator/src/validator.rs b/rust/agents/validator/src/validator.rs index 00b9d1baad..8d28980098 100644 --- a/rust/agents/validator/src/validator.rs +++ b/rust/agents/validator/src/validator.rs @@ -13,7 +13,7 @@ use hyperlane_base::{ db::{HyperlaneRocksDB, DB}, metrics::AgentMetrics, settings::ChainConf, - BaseAgent, ChainMetrics, CheckpointSyncer, ContractSyncMetrics, CoreMetrics, + BaseAgent, ChainMetrics, CheckpointSyncer, ContractSyncMetrics, ContractSyncer, CoreMetrics, HyperlaneAgentCore, MetricsUpdater, SequencedDataContractSync, }; @@ -97,14 +97,13 @@ impl BaseAgent for Validator { let contract_sync_metrics = Arc::new(ContractSyncMetrics::new(&metrics)); let merkle_tree_hook_sync = settings - .build_merkle_tree_hook_indexer( + .sequenced_contract_sync::( &settings.origin_chain, &metrics, &contract_sync_metrics, - Arc::new(msg_db.clone()), + msg_db.clone().into(), ) - .await? - .into(); + .await?; Ok(Self { origin_chain: settings.origin_chain, @@ -208,9 +207,7 @@ impl Validator { let index_settings = self.as_ref().settings.chains[self.origin_chain.name()].index_settings(); let contract_sync = self.merkle_tree_hook_sync.clone(); - let cursor = contract_sync - .forward_backward_message_sync_cursor(index_settings) - .await; + let cursor = contract_sync.cursor(index_settings).await; tokio::spawn(async move { contract_sync.clone().sync("merkle_tree_hook", cursor).await; }) diff --git a/rust/hyperlane-base/src/contract_sync/cursors/mod.rs b/rust/hyperlane-base/src/contract_sync/cursors/mod.rs index e5f3e9aa2c..546616f4f3 100644 --- a/rust/hyperlane-base/src/contract_sync/cursors/mod.rs +++ b/rust/hyperlane-base/src/contract_sync/cursors/mod.rs @@ -1,427 +1,62 @@ -use std::{ - fmt::Debug, - ops::RangeInclusive, - sync::Arc, - time::{Duration, Instant}, -}; - -use async_trait::async_trait; -use derive_new::new; -use eyre::Result; -use hyperlane_core::{ - ChainCommunicationError, ContractSyncCursor, CursorAction, HyperlaneWatermarkedLogStore, - IndexMode, Indexer, LogMeta, SequenceAwareIndexer, -}; -use tokio::time::sleep; -use tracing::warn; - -use crate::contract_sync::eta_calculator::SyncerEtaCalculator; - pub(crate) mod sequence_aware; -pub(crate) use sequence_aware::{ - ForwardBackwardSequenceAwareSyncCursor, ForwardSequenceAwareSyncCursor, +use hyperlane_core::{ + Delivery, HyperlaneDomainProtocol, HyperlaneMessage, InterchainGasPayment, MerkleTreeInsertion, }; +pub(crate) use sequence_aware::ForwardBackwardSequenceAwareSyncCursor; -/// Time window for the moving average used in the eta calculator in seconds. -const ETA_TIME_WINDOW: f64 = 2. * 60.; +pub(crate) mod rate_limited; +pub(crate) use rate_limited::RateLimitedContractSyncCursor; -const MAX_SEQUENCE_RANGE: u32 = 20; - -#[derive(Debug, new)] -pub(crate) struct SyncState { - chunk_size: u32, - /// The starting block for the cursor - start_block: u32, - /// The next block that should be indexed. - next_block: u32, - mode: IndexMode, - /// The next sequence index that the cursor is looking for. - /// In the EVM, this is used for optimizing indexing, - /// because it's cheaper to make read calls for the sequence index than - /// to call `eth_getLogs` with a block range. - /// In Sealevel, historic queries aren't supported, so the sequence field - /// is used to query storage in sequence. - next_sequence: u32, - direction: SyncDirection, +pub enum CursorType { + SequenceAware, + RateLimited, } -impl SyncState { - async fn get_next_range( - &mut self, - max_sequence: Option, - tip: u32, - ) -> Result>> { - // We attempt to index a range of blocks that is as large as possible. - let range = match self.mode { - IndexMode::Block => self.block_range(tip), - IndexMode::Sequence => { - let max_sequence = max_sequence.ok_or_else(|| { - ChainCommunicationError::from_other_str( - "Sequence indexing requires a max sequence", - ) - })?; - if let Some(range) = self.sequence_range(max_sequence)? { - range - } else { - return Ok(None); - } - } - }; - if range.is_empty() { - return Ok(None); - } - Ok(Some(range)) - } - - fn block_range(&self, tip: u32) -> RangeInclusive { - let (from, to) = match self.direction { - SyncDirection::Forward => { - let from = self.next_block; - let mut to = from + self.chunk_size; - to = u32::min(to, tip); - (from, to) - } - SyncDirection::Backward => { - let to = self.next_block; - let from = to.saturating_sub(self.chunk_size); - (from, to) - } - }; - from..=to - } - - /// Returns the next sequence range to index. - /// - /// # Arguments - /// - /// * `tip` - The current tip of the chain. - /// * `max_sequence` - The maximum sequence that should be indexed. - /// `max_sequence` is the exclusive upper bound of the range to be indexed. - /// (e.g. `0..max_sequence`) - fn sequence_range(&self, max_sequence: u32) -> Result>> { - let (from, to) = match self.direction { - SyncDirection::Forward => { - let sequence_start = self.next_sequence; - let mut sequence_end = sequence_start + MAX_SEQUENCE_RANGE; - if self.next_sequence >= max_sequence { - return Ok(None); - } - sequence_end = u32::min(sequence_end, max_sequence.saturating_sub(1)); - (sequence_start, sequence_end) - } - SyncDirection::Backward => { - let sequence_end = self.next_sequence; - let sequence_start = sequence_end.saturating_sub(MAX_SEQUENCE_RANGE); - (sequence_start, sequence_end) - } - }; - Ok(Some(from..=to)) - } - - fn update_range(&mut self, range: RangeInclusive) { - match self.direction { - SyncDirection::Forward => match self.mode { - IndexMode::Block => { - self.next_block = *range.end() + 1; - } - IndexMode::Sequence => { - self.next_sequence = *range.end() + 1; - } - }, - SyncDirection::Backward => match self.mode { - IndexMode::Block => { - self.next_block = range.start().saturating_sub(1); - } - IndexMode::Sequence => { - self.next_sequence = range.start().saturating_sub(1); - } - }, - } - } +pub trait Indexable { + fn indexing_cursor(domain: HyperlaneDomainProtocol) -> CursorType; } -#[allow(dead_code)] -#[derive(Debug)] -pub enum SyncDirection { - Forward, - Backward, -} - -/// Tool for handling the logic of what the next block range that should be -/// queried is and also handling rate limiting. Rate limiting is automatically -/// performed by `next_action`. -pub(crate) struct RateLimitedContractSyncCursor { - indexer: Arc>, - db: Arc>, - tip: u32, - max_sequence: Option, - last_tip_update: Instant, - eta_calculator: SyncerEtaCalculator, - sync_state: SyncState, -} - -impl RateLimitedContractSyncCursor { - /// Construct a new contract sync helper. - pub async fn new( - indexer: Arc>, - db: Arc>, - chunk_size: u32, - initial_height: u32, - mode: IndexMode, - ) -> Result { - let (max_sequence, tip) = indexer.latest_sequence_count_and_tip().await?; - Ok(Self { - indexer, - db, - tip, - max_sequence, - last_tip_update: Instant::now(), - eta_calculator: SyncerEtaCalculator::new(initial_height, tip, ETA_TIME_WINDOW), - sync_state: SyncState::new( - chunk_size, - initial_height, - initial_height, - mode, - Default::default(), - // The rate limited cursor currently only syncs in the forward direction. - SyncDirection::Forward, - ), - }) - } - - /// Wait based on how close we are to the tip and update the tip, - /// i.e. the highest block we may scrape. - async fn get_rate_limit(&mut self) -> Result> { - if self.sync_state.next_block + self.sync_state.chunk_size < self.tip { - // If doing the full chunk wouldn't exceed the already known tip we do not need to rate limit. - Ok(None) - } else { - // We are within one chunk size of the known tip. - // If it's been fewer than 30s since the last tip update, sleep for a bit until we're ready to fetch the next tip. - if let Some(sleep_time) = - Duration::from_secs(30).checked_sub(self.last_tip_update.elapsed()) - { - return Ok(Some(sleep_time)); - } - match self.indexer.get_finalized_block_number().await { - Ok(tip) => { - // we retrieved a new tip value, go ahead and update. - self.last_tip_update = Instant::now(); - self.tip = tip; - Ok(None) - } - Err(e) => { - warn!(error = %e, "Failed to get next block range because we could not get the current tip"); - // we are failing to make a basic query, we should wait before retrying. - sleep(Duration::from_secs(10)).await; - Err(e.into()) - } - } +impl Indexable for HyperlaneMessage { + fn indexing_cursor(domain: HyperlaneDomainProtocol) -> CursorType { + match domain { + HyperlaneDomainProtocol::Ethereum => CursorType::SequenceAware, + HyperlaneDomainProtocol::Fuel => todo!(), + HyperlaneDomainProtocol::Sealevel => CursorType::SequenceAware, + HyperlaneDomainProtocol::Cosmos => CursorType::SequenceAware, } } - - fn sync_end(&self) -> Result { - match self.sync_state.mode { - IndexMode::Block => Ok(self.tip), - IndexMode::Sequence => self - .max_sequence - .ok_or(eyre::eyre!("Sequence indexing requires a max sequence",)), - } - } - - fn sync_position(&self) -> u32 { - match self.sync_state.mode { - IndexMode::Block => self.sync_state.next_block, - IndexMode::Sequence => self.sync_state.next_sequence, - } - } - - fn sync_step(&self) -> u32 { - match self.sync_state.mode { - IndexMode::Block => self.sync_state.chunk_size, - IndexMode::Sequence => MAX_SEQUENCE_RANGE, - } - } - - async fn get_next_range(&mut self) -> Result>> { - let (max_sequence, tip) = self.indexer.latest_sequence_count_and_tip().await?; - self.tip = tip; - self.max_sequence = max_sequence; - - self.sync_state.get_next_range(max_sequence, tip).await - } - - fn sync_eta(&mut self) -> Result { - let sync_end = self.sync_end()?; - let to = u32::min(sync_end, self.sync_position() + self.sync_step()); - let from = self.sync_position(); - let eta = if to < sync_end { - self.eta_calculator.calculate(from, sync_end) - } else { - Duration::from_secs(0) - }; - Ok(eta) - } } -#[async_trait] -impl ContractSyncCursor for RateLimitedContractSyncCursor -where - T: Send + Debug + 'static, -{ - async fn next_action(&mut self) -> Result<(CursorAction, Duration)> { - let eta = self.sync_eta()?; - - let rate_limit = self.get_rate_limit().await?; - if let Some(rate_limit) = rate_limit { - return Ok((CursorAction::Sleep(rate_limit), eta)); - } - - if let Some(range) = self.get_next_range().await? { - return Ok((CursorAction::Query(range), eta)); - } else { - // TODO: Define the sleep time from interval flag - return Ok((CursorAction::Sleep(Duration::from_secs(5)), eta)); +impl Indexable for InterchainGasPayment { + fn indexing_cursor(domain: HyperlaneDomainProtocol) -> CursorType { + match domain { + HyperlaneDomainProtocol::Ethereum => CursorType::RateLimited, + HyperlaneDomainProtocol::Fuel => todo!(), + HyperlaneDomainProtocol::Sealevel => CursorType::RateLimited, + HyperlaneDomainProtocol::Cosmos => CursorType::RateLimited, } } - - fn latest_queried_block(&self) -> u32 { - self.sync_state.next_block.saturating_sub(1) - } - - async fn update(&mut self, _: Vec<(T, LogMeta)>, range: RangeInclusive) -> Result<()> { - // Store a relatively conservative view of the high watermark, which should allow a single watermark to be - // safely shared across multiple cursors, so long as they are running sufficiently in sync - self.db - .store_high_watermark(u32::max( - self.sync_state.start_block, - self.sync_state - .next_block - .saturating_sub(self.sync_state.chunk_size), - )) - .await?; - self.sync_state.update_range(range); - Ok(()) - } } -#[cfg(test)] -pub(crate) mod test { - use super::*; - use hyperlane_core::{ChainResult, HyperlaneLogStore}; - use mockall::{self, Sequence}; - - const CHUNK_SIZE: u32 = 10; - const INITIAL_HEIGHT: u32 = 0; - - mockall::mock! { - pub Indexer {} - - impl Debug for Indexer { - fn fmt<'a>(&self, f: &mut std::fmt::Formatter<'a>) -> std::fmt::Result; - } - - #[async_trait] - impl Indexer<()> for Indexer { - async fn fetch_logs(&self, range: RangeInclusive) -> ChainResult>; - async fn get_finalized_block_number(&self) -> ChainResult; - } - - #[async_trait] - impl SequenceAwareIndexer<()> for Indexer { - async fn latest_sequence_count_and_tip(&self) -> ChainResult<(Option, u32)>; - } - } - - mockall::mock! { - pub Db {} - - impl Debug for Db { - fn fmt<'a>(&self, f: &mut std::fmt::Formatter<'a>) -> std::fmt::Result; - } - - #[async_trait] - impl HyperlaneLogStore<()> for Db { - async fn store_logs(&self, logs: &[((), LogMeta)]) -> Result; - } - - #[async_trait] - impl HyperlaneWatermarkedLogStore<()> for Db { - async fn retrieve_high_watermark(&self) -> Result>; - async fn store_high_watermark(&self, block_number: u32) -> Result<()>; +impl Indexable for MerkleTreeInsertion { + fn indexing_cursor(domain: HyperlaneDomainProtocol) -> CursorType { + match domain { + HyperlaneDomainProtocol::Ethereum => CursorType::SequenceAware, + HyperlaneDomainProtocol::Fuel => todo!(), + HyperlaneDomainProtocol::Sealevel => CursorType::SequenceAware, + HyperlaneDomainProtocol::Cosmos => CursorType::SequenceAware, } } +} - async fn mock_rate_limited_cursor( - custom_chain_tips: Option>, - ) -> RateLimitedContractSyncCursor<()> { - let mut seq = Sequence::new(); - let mut indexer = MockIndexer::new(); - match custom_chain_tips { - Some(chain_tips) => { - for tip in chain_tips { - indexer - .expect_latest_sequence_count_and_tip() - .times(1) - .in_sequence(&mut seq) - .returning(move || Ok((None, tip))); - } - } - None => { - indexer - .expect_latest_sequence_count_and_tip() - .returning(move || Ok((None, 100))); - } +impl Indexable for Delivery { + fn indexing_cursor(domain: HyperlaneDomainProtocol) -> CursorType { + match domain { + HyperlaneDomainProtocol::Ethereum => CursorType::RateLimited, + HyperlaneDomainProtocol::Fuel => todo!(), + HyperlaneDomainProtocol::Sealevel => CursorType::RateLimited, + HyperlaneDomainProtocol::Cosmos => CursorType::RateLimited, } - - let mut db = MockDb::new(); - db.expect_store_high_watermark().returning(|_| Ok(())); - let chunk_size = CHUNK_SIZE; - let initial_height = INITIAL_HEIGHT; - let mode = IndexMode::Block; - RateLimitedContractSyncCursor::new( - Arc::new(indexer), - Arc::new(db), - chunk_size, - initial_height, - mode, - ) - .await - .unwrap() - } - - #[tokio::test] - async fn test_next_action_retries_if_update_isnt_called() { - let mut cursor = mock_rate_limited_cursor(None).await; - let (action_1, _) = cursor.next_action().await.unwrap(); - let (action_2, _) = cursor.next_action().await.unwrap(); - - // Calling next_action without updating the cursor should return the same action - assert!(matches!(action_1, action_2)); - } - - #[tokio::test] - async fn test_next_action_changes_if_update_is_called() { - let mut cursor = mock_rate_limited_cursor(None).await; - let (action_1, _) = cursor.next_action().await.unwrap(); - - let range = match action_1 { - CursorAction::Query(range) => range, - _ => panic!("Expected Query action"), - }; - cursor.update(vec![], range.clone()).await.unwrap(); - - let (action_3, _) = cursor.next_action().await.unwrap(); - let expected_range = range.end() + 1..=(range.end() + CHUNK_SIZE); - assert!(matches!(action_3, CursorAction::Query(expected_range))); - } - - #[tokio::test] - async fn test_next_action_sleeps_if_tip_is_not_updated() { - let chain_tips = vec![10]; - let mut cursor = mock_rate_limited_cursor(Some(chain_tips)).await; - let (action, _) = cursor.next_action().await.unwrap(); - assert!(matches!(action, CursorAction::Sleep(_))); } } diff --git a/rust/hyperlane-base/src/contract_sync/cursors/rate_limited.rs b/rust/hyperlane-base/src/contract_sync/cursors/rate_limited.rs new file mode 100644 index 0000000000..b3476db646 --- /dev/null +++ b/rust/hyperlane-base/src/contract_sync/cursors/rate_limited.rs @@ -0,0 +1,421 @@ +use std::{ + fmt::Debug, + ops::RangeInclusive, + sync::Arc, + time::{Duration, Instant}, +}; + +use async_trait::async_trait; +use derive_new::new; +use eyre::Result; +use hyperlane_core::{ + ChainCommunicationError, ContractSyncCursor, CursorAction, HyperlaneWatermarkedLogStore, + IndexMode, Indexer, LogMeta, SequenceAwareIndexer, +}; +use tokio::time::sleep; +use tracing::warn; + +use crate::contract_sync::eta_calculator::SyncerEtaCalculator; + +/// Time window for the moving average used in the eta calculator in seconds. +const ETA_TIME_WINDOW: f64 = 2. * 60.; + +const MAX_SEQUENCE_RANGE: u32 = 20; + +#[derive(Debug, new)] +pub(crate) struct SyncState { + chunk_size: u32, + /// The starting block for the cursor + start_block: u32, + /// The next block that should be indexed. + next_block: u32, + mode: IndexMode, + /// The next sequence index that the cursor is looking for. + /// In the EVM, this is used for optimizing indexing, + /// because it's cheaper to make read calls for the sequence index than + /// to call `eth_getLogs` with a block range. + /// In Sealevel, historic queries aren't supported, so the sequence field + /// is used to query storage in sequence. + next_sequence: u32, + direction: SyncDirection, +} + +impl SyncState { + async fn get_next_range( + &mut self, + max_sequence: Option, + tip: u32, + ) -> Result>> { + // We attempt to index a range of blocks that is as large as possible. + let range = match self.mode { + IndexMode::Block => self.block_range(tip), + IndexMode::Sequence => { + let max_sequence = max_sequence.ok_or_else(|| { + ChainCommunicationError::from_other_str( + "Sequence indexing requires a max sequence", + ) + })?; + if let Some(range) = self.sequence_range(max_sequence)? { + range + } else { + return Ok(None); + } + } + }; + if range.is_empty() { + return Ok(None); + } + Ok(Some(range)) + } + + fn block_range(&self, tip: u32) -> RangeInclusive { + let (from, to) = match self.direction { + SyncDirection::Forward => { + let from = self.next_block; + let mut to = from + self.chunk_size; + to = u32::min(to, tip); + (from, to) + } + SyncDirection::Backward => { + let to = self.next_block; + let from = to.saturating_sub(self.chunk_size); + (from, to) + } + }; + from..=to + } + + /// Returns the next sequence range to index. + /// + /// # Arguments + /// + /// * `tip` - The current tip of the chain. + /// * `max_sequence` - The maximum sequence that should be indexed. + /// `max_sequence` is the exclusive upper bound of the range to be indexed. + /// (e.g. `0..max_sequence`) + fn sequence_range(&self, max_sequence: u32) -> Result>> { + let (from, to) = match self.direction { + SyncDirection::Forward => { + let sequence_start = self.next_sequence; + let mut sequence_end = sequence_start + MAX_SEQUENCE_RANGE; + if self.next_sequence >= max_sequence { + return Ok(None); + } + sequence_end = u32::min(sequence_end, max_sequence.saturating_sub(1)); + (sequence_start, sequence_end) + } + SyncDirection::Backward => { + let sequence_end = self.next_sequence; + let sequence_start = sequence_end.saturating_sub(MAX_SEQUENCE_RANGE); + (sequence_start, sequence_end) + } + }; + Ok(Some(from..=to)) + } + + fn update_range(&mut self, range: RangeInclusive) { + match self.direction { + SyncDirection::Forward => match self.mode { + IndexMode::Block => { + self.next_block = *range.end() + 1; + } + IndexMode::Sequence => { + self.next_sequence = *range.end() + 1; + } + }, + SyncDirection::Backward => match self.mode { + IndexMode::Block => { + self.next_block = range.start().saturating_sub(1); + } + IndexMode::Sequence => { + self.next_sequence = range.start().saturating_sub(1); + } + }, + } + } +} + +#[allow(dead_code)] +#[derive(Debug)] +pub enum SyncDirection { + Forward, + Backward, +} + +/// Tool for handling the logic of what the next block range that should be +/// queried is and also handling rate limiting. Rate limiting is automatically +/// performed by `next_action`. +pub(crate) struct RateLimitedContractSyncCursor { + indexer: Arc>, + db: Arc>, + tip: u32, + max_sequence: Option, + last_tip_update: Instant, + eta_calculator: SyncerEtaCalculator, + sync_state: SyncState, +} + +impl RateLimitedContractSyncCursor { + /// Construct a new contract sync helper. + pub async fn new( + indexer: Arc>, + db: Arc>, + chunk_size: u32, + initial_height: u32, + mode: IndexMode, + ) -> Result { + let (max_sequence, tip) = indexer.latest_sequence_count_and_tip().await?; + Ok(Self { + indexer, + db, + tip, + max_sequence, + last_tip_update: Instant::now(), + eta_calculator: SyncerEtaCalculator::new(initial_height, tip, ETA_TIME_WINDOW), + sync_state: SyncState::new( + chunk_size, + initial_height, + initial_height, + mode, + Default::default(), + // The rate limited cursor currently only syncs in the forward direction. + SyncDirection::Forward, + ), + }) + } + + /// Wait based on how close we are to the tip and update the tip, + /// i.e. the highest block we may scrape. + async fn get_rate_limit(&mut self) -> Result> { + if self.sync_state.next_block + self.sync_state.chunk_size < self.tip { + // If doing the full chunk wouldn't exceed the already known tip we do not need to rate limit. + Ok(None) + } else { + // We are within one chunk size of the known tip. + // If it's been fewer than 30s since the last tip update, sleep for a bit until we're ready to fetch the next tip. + if let Some(sleep_time) = + Duration::from_secs(30).checked_sub(self.last_tip_update.elapsed()) + { + return Ok(Some(sleep_time)); + } + match self.indexer.get_finalized_block_number().await { + Ok(tip) => { + // we retrieved a new tip value, go ahead and update. + self.last_tip_update = Instant::now(); + self.tip = tip; + Ok(None) + } + Err(e) => { + warn!(error = %e, "Failed to get next block range because we could not get the current tip"); + // we are failing to make a basic query, we should wait before retrying. + sleep(Duration::from_secs(10)).await; + Err(e.into()) + } + } + } + } + + fn sync_end(&self) -> Result { + match self.sync_state.mode { + IndexMode::Block => Ok(self.tip), + IndexMode::Sequence => self + .max_sequence + .ok_or(eyre::eyre!("Sequence indexing requires a max sequence",)), + } + } + + fn sync_position(&self) -> u32 { + match self.sync_state.mode { + IndexMode::Block => self.sync_state.next_block, + IndexMode::Sequence => self.sync_state.next_sequence, + } + } + + fn sync_step(&self) -> u32 { + match self.sync_state.mode { + IndexMode::Block => self.sync_state.chunk_size, + IndexMode::Sequence => MAX_SEQUENCE_RANGE, + } + } + + async fn get_next_range(&mut self) -> Result>> { + let (max_sequence, tip) = self.indexer.latest_sequence_count_and_tip().await?; + self.tip = tip; + self.max_sequence = max_sequence; + + self.sync_state.get_next_range(max_sequence, tip).await + } + + fn sync_eta(&mut self) -> Result { + let sync_end = self.sync_end()?; + let to = u32::min(sync_end, self.sync_position() + self.sync_step()); + let from = self.sync_position(); + let eta = if to < sync_end { + self.eta_calculator.calculate(from, sync_end) + } else { + Duration::from_secs(0) + }; + Ok(eta) + } +} + +#[async_trait] +impl ContractSyncCursor for RateLimitedContractSyncCursor +where + T: Send + Debug + 'static, +{ + async fn next_action(&mut self) -> Result<(CursorAction, Duration)> { + let eta = self.sync_eta()?; + + let rate_limit = self.get_rate_limit().await?; + if let Some(rate_limit) = rate_limit { + return Ok((CursorAction::Sleep(rate_limit), eta)); + } + + if let Some(range) = self.get_next_range().await? { + return Ok((CursorAction::Query(range), eta)); + } else { + // TODO: Define the sleep time from interval flag + return Ok((CursorAction::Sleep(Duration::from_secs(5)), eta)); + } + } + + fn latest_queried_block(&self) -> u32 { + self.sync_state.next_block.saturating_sub(1) + } + + async fn update(&mut self, _: Vec<(T, LogMeta)>, range: RangeInclusive) -> Result<()> { + // Store a relatively conservative view of the high watermark, which should allow a single watermark to be + // safely shared across multiple cursors, so long as they are running sufficiently in sync + self.db + .store_high_watermark(u32::max( + self.sync_state.start_block, + self.sync_state + .next_block + .saturating_sub(self.sync_state.chunk_size), + )) + .await?; + self.sync_state.update_range(range); + Ok(()) + } +} + +#[cfg(test)] +pub(crate) mod test { + use super::*; + use hyperlane_core::{ChainResult, HyperlaneLogStore}; + use mockall::{self, Sequence}; + + const CHUNK_SIZE: u32 = 10; + const INITIAL_HEIGHT: u32 = 0; + + mockall::mock! { + pub Indexer {} + + impl Debug for Indexer { + fn fmt<'a>(&self, f: &mut std::fmt::Formatter<'a>) -> std::fmt::Result; + } + + #[async_trait] + impl Indexer<()> for Indexer { + async fn fetch_logs(&self, range: RangeInclusive) -> ChainResult>; + async fn get_finalized_block_number(&self) -> ChainResult; + } + + #[async_trait] + impl SequenceAwareIndexer<()> for Indexer { + async fn latest_sequence_count_and_tip(&self) -> ChainResult<(Option, u32)>; + } + } + + mockall::mock! { + pub Db {} + + impl Debug for Db { + fn fmt<'a>(&self, f: &mut std::fmt::Formatter<'a>) -> std::fmt::Result; + } + + #[async_trait] + impl HyperlaneLogStore<()> for Db { + async fn store_logs(&self, logs: &[((), LogMeta)]) -> Result; + } + + #[async_trait] + impl HyperlaneWatermarkedLogStore<()> for Db { + async fn retrieve_high_watermark(&self) -> Result>; + async fn store_high_watermark(&self, block_number: u32) -> Result<()>; + } + } + + async fn mock_rate_limited_cursor( + custom_chain_tips: Option>, + ) -> RateLimitedContractSyncCursor<()> { + let mut seq = Sequence::new(); + let mut indexer = MockIndexer::new(); + match custom_chain_tips { + Some(chain_tips) => { + for tip in chain_tips { + indexer + .expect_latest_sequence_count_and_tip() + .times(1) + .in_sequence(&mut seq) + .returning(move || Ok((None, tip))); + } + } + None => { + indexer + .expect_latest_sequence_count_and_tip() + .returning(move || Ok((None, 100))); + } + } + + let mut db = MockDb::new(); + db.expect_store_high_watermark().returning(|_| Ok(())); + let chunk_size = CHUNK_SIZE; + let initial_height = INITIAL_HEIGHT; + let mode = IndexMode::Block; + RateLimitedContractSyncCursor::new( + Arc::new(indexer), + Arc::new(db), + chunk_size, + initial_height, + mode, + ) + .await + .unwrap() + } + + #[tokio::test] + async fn test_next_action_retries_if_update_isnt_called() { + let mut cursor = mock_rate_limited_cursor(None).await; + let (action_1, _) = cursor.next_action().await.unwrap(); + let (action_2, _) = cursor.next_action().await.unwrap(); + + // Calling next_action without updating the cursor should return the same action + assert!(matches!(action_1, action_2)); + } + + #[tokio::test] + async fn test_next_action_changes_if_update_is_called() { + let mut cursor = mock_rate_limited_cursor(None).await; + let (action_1, _) = cursor.next_action().await.unwrap(); + + let range = match action_1 { + CursorAction::Query(range) => range, + _ => panic!("Expected Query action"), + }; + cursor.update(vec![], range.clone()).await.unwrap(); + + let (action_3, _) = cursor.next_action().await.unwrap(); + let expected_range = range.end() + 1..=(range.end() + CHUNK_SIZE); + assert!(matches!(action_3, CursorAction::Query(expected_range))); + } + + #[tokio::test] + async fn test_next_action_sleeps_if_tip_is_not_updated() { + let chain_tips = vec![10]; + let mut cursor = mock_rate_limited_cursor(Some(chain_tips)).await; + let (action, _) = cursor.next_action().await.unwrap(); + assert!(matches!(action, CursorAction::Sleep(_))); + } +} diff --git a/rust/hyperlane-base/src/contract_sync/mod.rs b/rust/hyperlane-base/src/contract_sync/mod.rs index d07aedf36d..1770ee7939 100644 --- a/rust/hyperlane-base/src/contract_sync/mod.rs +++ b/rust/hyperlane-base/src/contract_sync/mod.rs @@ -2,6 +2,7 @@ use std::{ collections::HashSet, fmt::Debug, hash::Hash, marker::PhantomData, sync::Arc, time::Duration, }; +use axum::async_trait; use cursors::*; use derive_new::new; use hyperlane_core::{ @@ -15,11 +16,11 @@ use tracing::{debug, info, warn}; use crate::settings::IndexSettings; -mod cursors; +pub(crate) mod cursors; mod eta_calculator; mod metrics; -use cursors::{ForwardBackwardSequenceAwareSyncCursor, ForwardSequenceAwareSyncCursor}; +use cursors::ForwardBackwardSequenceAwareSyncCursor; const SLEEP_DURATION: Duration = Duration::from_secs(5); @@ -37,15 +38,21 @@ pub struct ContractSync, I: Indexer> { impl ContractSync where - T: Debug + Send + Sync + Clone + Eq + Hash + 'static, - D: HyperlaneLogStore + 'static, - I: Indexer + Clone + 'static, + D: HyperlaneLogStore, + I: Indexer + 'static, { /// The domain that this ContractSync is running on pub fn domain(&self) -> &HyperlaneDomain { &self.domain } +} +impl ContractSync +where + T: Debug + Send + Sync + Clone + Eq + Hash + 'static, + D: HyperlaneLogStore, + I: Indexer + 'static, +{ /// Sync logs and write them to the LogStore #[tracing::instrument(name = "ContractSync", fields(domain=self.domain().name()), skip(self, cursor))] pub async fn sync(&self, label: &'static str, mut cursor: Box>) { @@ -117,18 +124,36 @@ where } } +/// A ContractSync for syncing events using a SequenceAwareIndexer +pub type SequenceAwareContractSync = ContractSync>>; + +/// Log store for the watermark cursor +pub type WatermarkLogStore = Arc>; + /// A ContractSync for syncing events using a RateLimitedContractSyncCursor pub type WatermarkContractSync = - ContractSync>, Arc>>; -impl WatermarkContractSync + SequenceAwareContractSync>>; + +/// Abstraction over a contract syncer that can also be converted into a cursor +#[async_trait] +pub trait ContractSyncer: Send + Sync { + /// Returns a new cursor to be used for syncing events from the indexer + async fn cursor(&self, index_settings: IndexSettings) -> Box>; + + /// Syncs events from the indexer using the provided cursor + async fn sync(&self, label: &'static str, cursor: Box>); + + /// The domain of this syncer + fn domain(&self) -> &HyperlaneDomain; +} + +#[async_trait] +impl ContractSyncer for WatermarkContractSync where - T: Debug + Send + Sync + Clone + 'static, + T: Debug + Send + Sync + Clone + Eq + Hash + 'static, { /// Returns a new cursor to be used for syncing events from the indexer based on time - pub async fn rate_limited_cursor( - &self, - index_settings: IndexSettings, - ) -> Box> { + async fn cursor(&self, index_settings: IndexSettings) -> Box> { let watermark = self.db.retrieve_high_watermark().await.unwrap(); let index_settings = IndexSettings { from: watermark.unwrap_or(index_settings.from), @@ -147,36 +172,30 @@ where .unwrap(), ) } + + async fn sync(&self, label: &'static str, cursor: Box>) { + ContractSync::sync(self, label, cursor).await; + } + + fn domain(&self) -> &HyperlaneDomain { + ContractSync::domain(self) + } } +/// Log store for sequence aware cursors +pub type SequenceAwareLogStore = Arc>; + /// A ContractSync for syncing messages using a SequenceSyncCursor -pub type SequencedDataContractSync = ContractSync< - T, - Arc>, - Arc>, ->; -impl SequencedDataContractSync { - /// Returns a new cursor to be used for syncing dispatched messages from the indexer - pub async fn forward_message_sync_cursor( - &self, - index_settings: IndexSettings, - next_nonce: u32, - ) -> Box> { - Box::new(ForwardSequenceAwareSyncCursor::new( - index_settings.chunk_size, - self.indexer.clone(), - Arc::new(self.db.clone()), - next_nonce, - index_settings.from, - index_settings.mode, - )) - } +pub type SequencedDataContractSync = + SequenceAwareContractSync>>; +#[async_trait] +impl ContractSyncer for SequencedDataContractSync +where + T: Sequenced + Debug + Clone + Eq + Hash, +{ /// Returns a new cursor to be used for syncing dispatched messages from the indexer - pub async fn forward_backward_message_sync_cursor( - &self, - index_settings: IndexSettings, - ) -> Box> { + async fn cursor(&self, index_settings: IndexSettings) -> Box> { Box::new( ForwardBackwardSequenceAwareSyncCursor::new( self.indexer.clone(), @@ -188,4 +207,12 @@ impl SequencedDataContractSync { .unwrap(), ) } + + async fn sync(&self, label: &'static str, cursor: Box>) { + ContractSync::sync(self, label, cursor).await; + } + + fn domain(&self) -> &HyperlaneDomain { + ContractSync::domain(self) + } } diff --git a/rust/hyperlane-base/src/db/rocks/hyperlane_db.rs b/rust/hyperlane-base/src/db/rocks/hyperlane_db.rs index acb73ff1fa..76151b7428 100644 --- a/rust/hyperlane-base/src/db/rocks/hyperlane_db.rs +++ b/rust/hyperlane-base/src/db/rocks/hyperlane_db.rs @@ -311,6 +311,20 @@ impl HyperlaneSequenceAwareIndexerStoreReader for Hyperlane } } +// TODO: replace this blanket implementation to be able to do sequence-aware indexing +#[async_trait] +impl HyperlaneSequenceAwareIndexerStoreReader for HyperlaneRocksDB { + /// Gets data by its sequence. + async fn retrieve_by_sequence(&self, _sequence: u32) -> Result> { + Ok(None) + } + + /// Gets the block number at which the log occurred. + async fn retrieve_log_block_number_by_sequence(&self, _sequence: u32) -> Result> { + Ok(None) + } +} + /// Note that for legacy reasons this watermark may be shared across multiple cursors, some of which may not have anything to do with gas payments /// The high watermark cursor is relatively conservative in writing block numbers, so this shouldn't result in any events being missed. #[async_trait] diff --git a/rust/hyperlane-base/src/settings/base.rs b/rust/hyperlane-base/src/settings/base.rs index 2899b99a39..71edb198fc 100644 --- a/rust/hyperlane-base/src/settings/base.rs +++ b/rust/hyperlane-base/src/settings/base.rs @@ -1,20 +1,23 @@ -use std::{collections::HashMap, fmt::Debug, sync::Arc}; +use std::{collections::HashMap, fmt::Debug, hash::Hash, sync::Arc}; use eyre::{eyre, Context, Result}; use futures_util::future::try_join_all; use hyperlane_core::{ - Delivery, HyperlaneChain, HyperlaneDomain, HyperlaneMessage, HyperlaneProvider, - HyperlaneSequenceAwareIndexerStore, HyperlaneWatermarkedLogStore, InterchainGasPaymaster, - InterchainGasPayment, Mailbox, MerkleTreeHook, MerkleTreeInsertion, MultisigIsm, - ValidatorAnnounce, H256, + HyperlaneChain, HyperlaneDomain, HyperlaneLogStore, HyperlaneProvider, + HyperlaneSequenceAwareIndexerStoreReader, HyperlaneWatermarkedLogStore, InterchainGasPaymaster, + Mailbox, MerkleTreeHook, MultisigIsm, SequenceAwareIndexer, Sequenced, ValidatorAnnounce, H256, }; use crate::{ + cursors::{CursorType, Indexable}, settings::{chains::ChainConf, trace::TracingConfig}, - ContractSync, ContractSyncMetrics, CoreMetrics, HyperlaneAgentCore, SequencedDataContractSync, - Server, WatermarkContractSync, + ContractSync, ContractSyncMetrics, ContractSyncer, CoreMetrics, HyperlaneAgentCore, + SequenceAwareLogStore, SequencedDataContractSync, Server, WatermarkContractSync, + WatermarkLogStore, }; +use super::TryFromWithMetrics; + /// Settings. Usually this should be treated as a base config and used as /// follows: /// @@ -139,48 +142,7 @@ macro_rules! build_contract_fns { }; } -/// Generate a call to ChainSetup for the given builder -macro_rules! build_indexer_fns { - ($singular:ident, $plural:ident -> $db:ty, $ret:ty) => { - /// Delegates building to ChainSetup - pub async fn $singular( - &self, - domain: &HyperlaneDomain, - metrics: &CoreMetrics, - sync_metrics: &ContractSyncMetrics, - db: Arc<$db>, - ) -> eyre::Result> { - let setup = self.chain_setup(domain)?; - let indexer = setup.$singular(metrics).await?; - let sync: $ret = ContractSync::new( - domain.clone(), - db.clone(), - indexer.into(), - sync_metrics.clone(), - ); - - Ok(Box::new(sync)) - } - - /// Builds a contract for each domain - pub async fn $plural( - &self, - domains: impl Iterator, - metrics: &CoreMetrics, - sync_metrics: &ContractSyncMetrics, - dbs: HashMap>, - ) -> Result>> { - try_join_all( - domains - .map(|d| self.$singular(d, metrics, sync_metrics, dbs.get(d).unwrap().clone())), - ) - .await? - .into_iter() - .map(|i| Ok((i.domain().clone(), Arc::from(i)))) - .collect() - } - }; -} +type SequenceIndexer = Arc>; impl Settings { build_contract_fns!(build_interchain_gas_paymaster, build_interchain_gas_paymasters -> dyn InterchainGasPaymaster); @@ -188,8 +150,102 @@ impl Settings { build_contract_fns!(build_merkle_tree_hook, build_merkle_tree_hooks -> dyn MerkleTreeHook); build_contract_fns!(build_validator_announce, build_validator_announces -> dyn ValidatorAnnounce); build_contract_fns!(build_provider, build_providers -> dyn HyperlaneProvider); - build_indexer_fns!(build_delivery_indexer, build_delivery_indexers -> dyn HyperlaneWatermarkedLogStore, WatermarkContractSync); - build_indexer_fns!(build_message_indexer, build_message_indexers -> dyn HyperlaneSequenceAwareIndexerStore, SequencedDataContractSync); - build_indexer_fns!(build_interchain_gas_payment_indexer, build_interchain_gas_payment_indexers -> dyn HyperlaneWatermarkedLogStore, WatermarkContractSync); - build_indexer_fns!(build_merkle_tree_hook_indexer, build_merkle_tree_hook_indexers -> dyn HyperlaneSequenceAwareIndexerStore, SequencedDataContractSync); + + /// Build a contract sync for type `T` using log store `D` + pub async fn sequenced_contract_sync( + &self, + domain: &HyperlaneDomain, + metrics: &CoreMetrics, + sync_metrics: &ContractSyncMetrics, + db: Arc, + ) -> eyre::Result>> + where + T: Sequenced + Debug, + SequenceIndexer: TryFromWithMetrics, + D: HyperlaneLogStore + HyperlaneSequenceAwareIndexerStoreReader + 'static, + { + let setup = self.chain_setup(domain)?; + // Currently, all indexers are of the `SequenceIndexer` type + let indexer = SequenceIndexer::::try_from_with_metrics(setup, metrics).await?; + Ok(Arc::new(ContractSync::new( + domain.clone(), + db.clone() as SequenceAwareLogStore<_>, + indexer, + sync_metrics.clone(), + ))) + } + + /// Build a contract sync for type `T` using log store `D` + pub async fn watermark_contract_sync( + &self, + domain: &HyperlaneDomain, + metrics: &CoreMetrics, + sync_metrics: &ContractSyncMetrics, + db: Arc, + ) -> eyre::Result>> + where + T: Debug, + SequenceIndexer: TryFromWithMetrics, + D: HyperlaneLogStore + HyperlaneWatermarkedLogStore + 'static, + { + let setup = self.chain_setup(domain)?; + // Currently, all indexers are of the `SequenceIndexer` type + let indexer = SequenceIndexer::::try_from_with_metrics(setup, metrics).await?; + Ok(Arc::new(ContractSync::new( + domain.clone(), + db.clone() as WatermarkLogStore<_>, + indexer, + sync_metrics.clone(), + ))) + } + + /// Build multiple contract syncs. + /// All contracts have to implement both sequenced and + /// watermark trait bounds + pub async fn contract_syncs( + &self, + domains: impl Iterator, + metrics: &CoreMetrics, + sync_metrics: &ContractSyncMetrics, + dbs: HashMap>, + ) -> Result>>> + where + T: Indexable + Sequenced + Debug + Send + Sync + Clone + Eq + Hash + 'static, + SequenceIndexer: TryFromWithMetrics, + D: HyperlaneLogStore + + HyperlaneSequenceAwareIndexerStoreReader + + HyperlaneWatermarkedLogStore + + 'static, + { + // TODO: parallelize these calls again + let mut syncs = vec![]; + for domain in domains { + let sync = match T::indexing_cursor(domain.domain_protocol()) { + CursorType::SequenceAware => self + .sequenced_contract_sync( + domain, + metrics, + sync_metrics, + dbs.get(domain).unwrap().clone(), + ) + .await + .map(|r| r as Arc>)?, + CursorType::RateLimited => self + .watermark_contract_sync( + domain, + metrics, + sync_metrics, + dbs.get(domain).unwrap().clone(), + ) + .await + .map(|r| r as Arc>)?, + }; + syncs.push(sync); + } + + syncs + .into_iter() + .map(|i| Ok((i.domain().clone(), i))) + .collect() + } } diff --git a/rust/hyperlane-base/src/settings/chains.rs b/rust/hyperlane-base/src/settings/chains.rs index c8e66f66a6..1d2c4eded7 100644 --- a/rust/hyperlane-base/src/settings/chains.rs +++ b/rust/hyperlane-base/src/settings/chains.rs @@ -1,6 +1,7 @@ +use axum::async_trait; use ethers::prelude::Selector; use h_cosmos::CosmosProvider; -use std::collections::HashMap; +use std::{collections::HashMap, sync::Arc}; use eyre::{eyre, Context, Result}; @@ -28,6 +29,13 @@ use crate::{ use super::ChainSigner; +/// A trait for converting to a type from a chain configuration with metrics +#[async_trait] +pub trait TryFromWithMetrics: Sized { + /// Try to convert the chain configuration into the type + async fn try_from_with_metrics(conf: &ChainConf, metrics: &CoreMetrics) -> Result; +} + /// A chain setup is a domain ID, an address on that chain (where the mailbox is /// deployed) and details for connecting to the chain API. #[derive(Clone, Debug)] @@ -50,6 +58,50 @@ pub struct ChainConf { pub index: IndexSettings, } +/// A sequence-aware indexer for messages +pub type MessageIndexer = Arc>; + +/// A sequence-aware indexer for deliveries +pub type DeliveryIndexer = Arc>; + +/// A sequence-aware indexer for interchain gas payments +pub type IgpIndexer = Arc>; + +/// A sequence-aware indexer for merkle tree hooks +pub type MerkleTreeHookIndexer = Arc>; + +#[async_trait] +impl TryFromWithMetrics for MessageIndexer { + async fn try_from_with_metrics(conf: &ChainConf, metrics: &CoreMetrics) -> Result { + conf.build_message_indexer(metrics).await.map(Into::into) + } +} + +#[async_trait] +impl TryFromWithMetrics for DeliveryIndexer { + async fn try_from_with_metrics(conf: &ChainConf, metrics: &CoreMetrics) -> Result { + conf.build_delivery_indexer(metrics).await.map(Into::into) + } +} + +#[async_trait] +impl TryFromWithMetrics for IgpIndexer { + async fn try_from_with_metrics(conf: &ChainConf, metrics: &CoreMetrics) -> Result { + conf.build_interchain_gas_payment_indexer(metrics) + .await + .map(Into::into) + } +} + +#[async_trait] +impl TryFromWithMetrics for MerkleTreeHookIndexer { + async fn try_from_with_metrics(conf: &ChainConf, metrics: &CoreMetrics) -> Result { + conf.build_merkle_tree_hook_indexer(metrics) + .await + .map(Into::into) + } +} + /// A connection to _some_ blockchain. #[derive(Clone, Debug)] pub enum ChainConnectionConf { diff --git a/rust/hyperlane-core/src/traits/indexer.rs b/rust/hyperlane-core/src/traits/indexer.rs index db93dedf88..17bcf97585 100644 --- a/rust/hyperlane-core/src/traits/indexer.rs +++ b/rust/hyperlane-core/src/traits/indexer.rs @@ -36,6 +36,9 @@ pub trait Indexer: Send + Sync + Debug { } /// Interface for indexing data in sequence. +/// SequenceAwareIndexer is an umbrella trait for all indexers types (sequence-aware and rate-limited). +/// The rate-limited indexer doesn't need `SequenceAwareIndexer`, so impls of `SequenceAwareIndexer` just return nullish values. +/// TODO: Refactor such that indexers aren't required to implement `SequenceAwareIndexer` #[async_trait] #[auto_impl(&, Box, Arc)] pub trait SequenceAwareIndexer: Indexer { diff --git a/rust/hyperlane-core/src/types/mod.rs b/rust/hyperlane-core/src/types/mod.rs index 9c3c11cd4a..2f348c7224 100644 --- a/rust/hyperlane-core/src/types/mod.rs +++ b/rust/hyperlane-core/src/types/mod.rs @@ -15,7 +15,7 @@ pub use log_metadata::*; pub use merkle_tree::*; pub use message::*; -use crate::{Decode, Encode, HyperlaneProtocolError}; +use crate::{Decode, Encode, HyperlaneProtocolError, Sequenced}; mod announcement; mod chain_data; @@ -131,6 +131,12 @@ pub struct InterchainGasPayment { pub gas_amount: U256, } +impl Sequenced for InterchainGasPayment { + fn sequence(&self) -> u32 { + Default::default() + } +} + /// Amount of gas spent attempting to send the message. #[derive(Debug, Copy, Clone)] pub struct InterchainGasExpenditure { diff --git a/rust/sealevel/client/src/main.rs b/rust/sealevel/client/src/main.rs index 74e3de7203..a4693fb6f1 100644 --- a/rust/sealevel/client/src/main.rs +++ b/rust/sealevel/client/src/main.rs @@ -709,7 +709,7 @@ fn main() { (Pubkey::from_str(&keypair_path).unwrap(), None) }; - let commitment = CommitmentConfig::processed(); + let commitment = CommitmentConfig::confirmed(); let mut instructions = vec![]; if cli.compute_budget != DEFAULT_INSTRUCTION_COMPUTE_UNIT_LIMIT { diff --git a/rust/utils/run-locally/src/solana.rs b/rust/utils/run-locally/src/solana.rs index 8e78b0bbdf..bf5b7d4176 100644 --- a/rust/utils/run-locally/src/solana.rs +++ b/rust/utils/run-locally/src/solana.rs @@ -309,7 +309,10 @@ pub fn initiate_solana_hyperlane_transfer( .run_with_output() .join(); - let message_id = get_message_id_from_logs(output).expect("failed to get message id from logs"); + let message_id = get_message_id_from_logs(output.clone()) + .unwrap_or_else(|| panic!("failed to get message id from logs: {:?}", output)); + + log!("found message id: {}", message_id); sealevel_client(&solana_cli_tools_path, &solana_config_path) .cmd("igp") .cmd("pay-for-gas") From 700240eb8a30b2d4503df27def59c0f5d75e1106 Mon Sep 17 00:00:00 2001 From: Trevor Porter Date: Wed, 17 Apr 2024 14:51:51 +0100 Subject: [PATCH 05/16] Ancient8 new ism, misc infra fixes (#3606) ### Description - Deploys ancient8 with a new ISM where we are not quorum - Pulls out warp config to live in a single file / function so that deploy.ts and check-deploy.ts are in sync. Otherwise fork.sh is broken for warp routes - Shuffles around the aw multisig serialization stuff - now they're segmented by environment and context and are written to `config/{env}/aw-validators/{context}.json`. This was in response to some confusing merging logic, see https://discord.com/channels/935678348330434570/1228377321082327141/1229464197297868910 ### Drive-by changes Needed to specify pino to work in pretty mode for warp monitoring :/ this is necessary because pino doesn't work otherwise. After #3582 we should change this ### Related issues ### Backward compatibility ### Testing --- .../m20230309_000001_create_table_domain.rs | 8 ++ .../config/environments/mainnet3/agent.ts | 41 +++++----- .../mainnet3/aw-validators/hyperlane.json} | 48 ----------- .../mainnet3/aw-validators/rc.json} | 62 -------------- .../environments/mainnet3/warp/addresses.json | 3 +- .../warp/ancient8-USDC-deployments.yaml | 22 +++++ .../mainnet3/warp/verification.json | 12 +++ .../testnet4/aw-validators/hyperlane.json | 50 ++++++++++++ .../testnet4/aw-validators/rc.json | 44 ++++++++++ .../environments/testnet4/validators.ts | 29 ------- typescript/infra/config/warp.ts | 81 +++++++++++++++++++ .../helm/warp-routes/templates/_helpers.tpl | 3 + typescript/infra/scripts/agent-utils.ts | 22 ++++- typescript/infra/scripts/check-deploy.ts | 35 +++----- typescript/infra/scripts/deploy.ts | 44 +--------- .../scripts/middleware/circle-relayer.ts | 8 +- .../scripts/middleware/portal-relayer.ts | 8 +- typescript/infra/scripts/warp-routes/helm.ts | 10 ++- typescript/infra/src/agents/index.ts | 13 +-- typescript/infra/src/agents/key-utils.ts | 41 ++++------ typescript/infra/src/utils/utils.ts | 7 +- typescript/sdk/src/consts/multisigIsm.ts | 8 +- 22 files changed, 323 insertions(+), 276 deletions(-) rename typescript/infra/config/{aw-multisig-hyperlane.json => environments/mainnet3/aw-validators/hyperlane.json} (70%) rename typescript/infra/config/{aw-multisig-rc.json => environments/mainnet3/aw-validators/rc.json} (64%) create mode 100644 typescript/infra/config/environments/mainnet3/warp/ancient8-USDC-deployments.yaml create mode 100644 typescript/infra/config/environments/testnet4/aw-validators/hyperlane.json create mode 100644 typescript/infra/config/environments/testnet4/aw-validators/rc.json create mode 100644 typescript/infra/config/warp.ts diff --git a/rust/agents/scraper/migration/src/m20230309_000001_create_table_domain.rs b/rust/agents/scraper/migration/src/m20230309_000001_create_table_domain.rs index 8d97a7e8e1..1ce834bc54 100644 --- a/rust/agents/scraper/migration/src/m20230309_000001_create_table_domain.rs +++ b/rust/agents/scraper/migration/src/m20230309_000001_create_table_domain.rs @@ -22,6 +22,14 @@ const DOMAINS: &[RawDomain] = &[ is_test_net: true, is_deprecated: false, }, + RawDomain { + name: "ancient8", + token: "ETH", + domain: 888888888, + chain_id: 888888888, + is_test_net: false, + is_deprecated: false, + }, RawDomain { name: "arbitrum", token: "ETH", diff --git a/typescript/infra/config/environments/mainnet3/agent.ts b/typescript/infra/config/environments/mainnet3/agent.ts index d4b60eb96a..a470caea86 100644 --- a/typescript/infra/config/environments/mainnet3/agent.ts +++ b/typescript/infra/config/environments/mainnet3/agent.ts @@ -88,7 +88,7 @@ export const hyperlaneContextAgentChainConfig: AgentChainConfig = { }, [Role.Scraper]: { [Chains.arbitrum]: true, - [Chains.ancient8]: false, + [Chains.ancient8]: true, [Chains.avalanche]: true, [Chains.bsc]: true, [Chains.celo]: true, @@ -143,11 +143,20 @@ const hyperlane: RootAgentConfig = { tag: '2a16200-20240408-214947', }, gasPaymentEnforcement: [ - // Temporary measure to ensure all inEVM warp route messages are delivered - - // we saw some issues with IGP indexing. + // To cover ourselves against IGP indexing issues and to ensure Nexus + // users have the best possible experience, we whitelist messages between + // warp routes that we know are certainly paying for gas. { type: GasPaymentEnforcementPolicyType.None, - matchingList: routerMatchingList(injectiveInevmInjAddresses), + matchingList: [ + ...routerMatchingList(injectiveInevmInjAddresses), + ...matchingList(inevmEthereumUsdcAddresses), + ...matchingList(inevmEthereumUsdtAddresses), + ...routerMatchingList(victionEthereumEthAddresses), + ...routerMatchingList(victionEthereumUsdcAddresses), + ...routerMatchingList(victionEthereumUsdtAddresses), + ...routerMatchingList(ancient8EthereumUsdcAddresses), + ], }, { type: GasPaymentEnforcementPolicyType.None, @@ -199,7 +208,7 @@ const hyperlane: RootAgentConfig = { validators: { docker: { repo, - tag: 'c1da894-20240321-175000', + tag: '2a16200-20240408-214947', }, rpcConsensusType: RpcConsensusType.Quorum, chains: validatorChainConfig(Contexts.Hyperlane), @@ -208,7 +217,7 @@ const hyperlane: RootAgentConfig = { rpcConsensusType: RpcConsensusType.Fallback, docker: { repo, - tag: 'ae0990a-20240313-215426', + tag: '2a16200-20240408-214947', }, }, }; @@ -222,7 +231,7 @@ const releaseCandidate: RootAgentConfig = { rpcConsensusType: RpcConsensusType.Fallback, docker: { repo, - tag: 'a72c3cf-20240314-173418', + tag: '2a16200-20240408-214947', }, whitelist: releaseCandidateHelloworldMatchingList, gasPaymentEnforcement, @@ -234,7 +243,7 @@ const releaseCandidate: RootAgentConfig = { validators: { docker: { repo, - tag: 'ae0990a-20240313-215426', + tag: '2a16200-20240408-214947', }, rpcConsensusType: RpcConsensusType.Quorum, chains: validatorChainConfig(Contexts.ReleaseCandidate), @@ -258,24 +267,14 @@ const neutron: RootAgentConfig = { rpcConsensusType: RpcConsensusType.Fallback, docker: { repo, - tag: 'a72c3cf-20240314-173418', + tag: '2a16200-20240408-214947', }, gasPaymentEnforcement: [ { type: GasPaymentEnforcementPolicyType.None, matchingList: [ - { - originDomain: getDomainId(chainMetadata.neutron), - destinationDomain: getDomainId(chainMetadata.mantapacific), - senderAddress: '*', - recipientAddress: '*', - }, - { - originDomain: getDomainId(chainMetadata.neutron), - destinationDomain: getDomainId(chainMetadata.arbitrum), - senderAddress: '*', - recipientAddress: '*', - }, + ...routerMatchingList(mantaTIAAddresses), + ...routerMatchingList(arbitrumTIAAddresses), ], }, ...gasPaymentEnforcement, diff --git a/typescript/infra/config/aw-multisig-hyperlane.json b/typescript/infra/config/environments/mainnet3/aw-validators/hyperlane.json similarity index 70% rename from typescript/infra/config/aw-multisig-hyperlane.json rename to typescript/infra/config/environments/mainnet3/aw-validators/hyperlane.json index 0cd93086dc..e0603dfdeb 100644 --- a/typescript/infra/config/aw-multisig-hyperlane.json +++ b/typescript/infra/config/environments/mainnet3/aw-validators/hyperlane.json @@ -1,11 +1,4 @@ { - "alfajores": { - "validators": [ - "0x2233a5ce12f814bd64c9cdd73410bb8693124d40", - "0xba279f965489d90f90490e3c49e860e0b43c2ae6", - "0x86485dcec5f7bb8478dd251676372d054dea6653" - ] - }, "ancient8": { "validators": ["0xbb5842ae0e05215b53df4787a29144efb7e67551"] }, @@ -37,13 +30,6 @@ "0x03047213365800f065356b4a2fe97c3c3a52296a" ] }, - "bsctestnet": { - "validators": [ - "0x242d8a855a8c932dec51f7999ae7d1e48b10c95e", - "0xf620f5e3d25a3ae848fec74bccae5de3edcd8796", - "0x1f030345963c54ff8229720dd3a711c15c554aeb" - ] - }, "celo": { "validators": [ "0x63478422679303c3e4fc611b771fa4a707ef7f4a", @@ -51,9 +37,6 @@ "0x7bf30afcb6a7d92146d5a910ea4c154fba38d25e" ] }, - "eclipsetestnet": { - "validators": ["0xf344f34abca9a444545b5295066348a0ae22dda3"] - }, "ethereum": { "validators": [ "0x03c842db86a6a3e524d4a6615390c1ea8e2b9541", @@ -61,13 +44,6 @@ "0x749d6e7ad949e522c92181dc77f7bbc1c5d71506" ] }, - "fuji": { - "validators": [ - "0xd8154f73d04cc7f7f0c332793692e6e6f6b2402e", - "0x895ae30bc83ff1493b9cf7781b0b813d23659857", - "0x43e915573d9f1383cbf482049e4a012290759e7f" - ] - }, "gnosis": { "validators": [ "0xd4df66a859585678f2ea8357161d896be19cc1ca", @@ -113,13 +89,6 @@ "0x779a17e035018396724a6dec8a59bda1b5adf738" ] }, - "plumetestnet": { - "validators": [ - "0xe765a214849f3ecdf00793b97d00422f2d408ea6", - "0xb59998f71efc65190a85ac5e81b66bd72a192a3b", - "0xc906470a73e6b5aad65a4ceb4acd73e3eaf80e2c" - ] - }, "polygon": { "validators": [ "0x12ecb319c7f4e8ac5eb5226662aeb8528c5cefac", @@ -141,23 +110,6 @@ "0x7210fa0a6be39a75cb14d682ebfb37e2b53ecbe5" ] }, - "scrollsepolia": { - "validators": [ - "0xbe18dbd758afb367180260b524e6d4bcd1cb6d05", - "0x9a11ed23ae962974018ab45bc133caabff7b3271", - "0x7867bea3c9761fe64e6d124b171f91fd5dd79644" - ] - }, - "sepolia": { - "validators": [ - "0xb22b65f202558adf86a8bb2847b76ae1036686a5", - "0x469f0940684d147defc44f3647146cb90dd0bc8e", - "0xd3c75dcf15056012a4d74c483a0c6ea11d8c2b83" - ] - }, - "solanatestnet": { - "validators": ["0xd4ce8fa138d4e083fc0e480cca0dbfa4f5f30bd5"] - }, "viction": { "validators": ["0x1f87c368f8e05a85ef9126d984a980a20930cb9c"] } diff --git a/typescript/infra/config/aw-multisig-rc.json b/typescript/infra/config/environments/mainnet3/aw-validators/rc.json similarity index 64% rename from typescript/infra/config/aw-multisig-rc.json rename to typescript/infra/config/environments/mainnet3/aw-validators/rc.json index 076251aeb7..7c65389fc4 100644 --- a/typescript/infra/config/aw-multisig-rc.json +++ b/typescript/infra/config/environments/mainnet3/aw-validators/rc.json @@ -1,11 +1,4 @@ { - "alfajores": { - "validators": [ - "0x2233a5ce12f814bd64c9cdd73410bb8693124d40", - "0xba279f965489d90f90490e3c49e860e0b43c2ae6", - "0x86485dcec5f7bb8478dd251676372d054dea6653" - ] - }, "ancient8": { "validators": ["0xaae4d879a04e3d8b956eb4ffbefd57fdbed09cae"] }, @@ -37,13 +30,6 @@ "0x50ff94984161976a13e9ec3b2a7647da5319448f" ] }, - "bsctestnet": { - "validators": [ - "0x242d8a855a8c932dec51f7999ae7d1e48b10c95e", - "0xf620f5e3d25a3ae848fec74bccae5de3edcd8796", - "0x1f030345963c54ff8229720dd3a711c15c554aeb" - ] - }, "celo": { "validators": [ "0xb51768c1388e976486a43dbbbbf9ce04cf45e990", @@ -51,9 +37,6 @@ "0xd796c1d4fcfb3c63acfa6e4113aa6ae1399b337c" ] }, - "eclipsetestnet": { - "validators": ["0xf344f34abca9a444545b5295066348a0ae22dda3"] - }, "ethereum": { "validators": [ "0x0580884289890805802012b9872afa5ae41a5fa6", @@ -61,13 +44,6 @@ "0x87cf8a85465118aff9ec728ca157798201b1e368" ] }, - "fuji": { - "validators": [ - "0xd8154f73d04cc7f7f0c332793692e6e6f6b2402e", - "0x895ae30bc83ff1493b9cf7781b0b813d23659857", - "0x43e915573d9f1383cbf482049e4a012290759e7f" - ] - }, "gnosis": { "validators": [ "0xd5122daa0c3dfc94a825ae928f3ea138cdb6a2e1", @@ -82,13 +58,6 @@ "0xe83d36fd00d9ef86243d9f7147b29e98d11df0ee" ] }, - "injective": { - "validators": [ - "0xbfb8911b72cfb138c7ce517c57d9c691535dc517", - "0x6faa139c33a7e6f53cb101f6b2ae392298283ed2", - "0x0115e3a66820fb99da30d30e2ce52a453ba99d92" - ] - }, "mantapacific": { "validators": [ "0x84fcb05e6e5961df2dfd9f36e8f2b3e87ede7d76", @@ -103,13 +72,6 @@ "0xcaa9c6e6efa35e4a8b47565f3ce98845fa638bf3" ] }, - "mumbai": { - "validators": [ - "0xebc301013b6cd2548e347c28d2dc43ec20c068f2", - "0x315db9868fc8813b221b1694f8760ece39f45447", - "0x17517c98358c5937c5d9ee47ce1f5b4c2b7fc9f5" - ] - }, "neutron": { "validators": [ "0x307a8fe091b8273c7ce3d277b161b4a2167279b1", @@ -124,13 +86,6 @@ "0x2d58cdb2bed9aac57b488b1bad06839ddc280a78" ] }, - "plumetestnet": { - "validators": [ - "0xe765a214849f3ecdf00793b97d00422f2d408ea6", - "0xb59998f71efc65190a85ac5e81b66bd72a192a3b", - "0xc906470a73e6b5aad65a4ceb4acd73e3eaf80e2c" - ] - }, "polygon": { "validators": [ "0xf0a990959f833ccde624c8bcd4c7669286a57a0f", @@ -152,23 +107,6 @@ "0x07c2f32a402543badc3141f6b98969d75ef2ac28" ] }, - "scrollsepolia": { - "validators": [ - "0xbe18dbd758afb367180260b524e6d4bcd1cb6d05", - "0x9a11ed23ae962974018ab45bc133caabff7b3271", - "0x7867bea3c9761fe64e6d124b171f91fd5dd79644" - ] - }, - "sepolia": { - "validators": [ - "0xb22b65f202558adf86a8bb2847b76ae1036686a5", - "0x469f0940684d147defc44f3647146cb90dd0bc8e", - "0xd3c75dcf15056012a4d74c483a0c6ea11d8c2b83" - ] - }, - "solanatestnet": { - "validators": ["0xd4ce8fa138d4e083fc0e480cca0dbfa4f5f30bd5"] - }, "viction": { "validators": [ "0xe858971cd865b11d3e8fb6b6af72db0d85881baf", diff --git a/typescript/infra/config/environments/mainnet3/warp/addresses.json b/typescript/infra/config/environments/mainnet3/warp/addresses.json index 74ba3a5929..feb5836384 100644 --- a/typescript/infra/config/environments/mainnet3/warp/addresses.json +++ b/typescript/infra/config/environments/mainnet3/warp/addresses.json @@ -5,6 +5,7 @@ }, "ethereum": { "HypERC20Collateral": "0x8b4192B9Ad1fCa440A5808641261e5289e6de95D", - "collateral": "0x8b4192B9Ad1fCa440A5808641261e5289e6de95D" + "collateral": "0x8b4192B9Ad1fCa440A5808641261e5289e6de95D", + "proxyAdmin": "0x7d0c8b23c5b35091972023ccc689cfedcd881c7d" } } diff --git a/typescript/infra/config/environments/mainnet3/warp/ancient8-USDC-deployments.yaml b/typescript/infra/config/environments/mainnet3/warp/ancient8-USDC-deployments.yaml new file mode 100644 index 0000000000..07be060273 --- /dev/null +++ b/typescript/infra/config/environments/mainnet3/warp/ancient8-USDC-deployments.yaml @@ -0,0 +1,22 @@ +# Configs and artifacts for the deployment of Hyperlane Warp Routes +# Between ancient8 and Ethereum +description: Hyperlane Warp Route artifacts +timestamp: '2024-04-15T16:00:00.000Z' +deployer: Abacus Works (Hyperlane) +data: + config: + ethereum: + protocolType: ethereum + type: collateral + hypAddress: '0x8b4192B9Ad1fCa440A5808641261e5289e6de95D' + tokenAddress: '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48' # USDC + name: USDC + symbol: USDC + decimals: 6 + ancient8: + protocolType: ethereum + type: synthetic + hypAddress: '0x97423A68BAe94b5De52d767a17aBCc54c157c0E5' + name: USDC + symbol: USDC + decimals: 6 diff --git a/typescript/infra/config/environments/mainnet3/warp/verification.json b/typescript/infra/config/environments/mainnet3/warp/verification.json index e77c33a7df..48f75ae1d8 100644 --- a/typescript/infra/config/environments/mainnet3/warp/verification.json +++ b/typescript/infra/config/environments/mainnet3/warp/verification.json @@ -23,6 +23,18 @@ "constructorArguments": "0000000000000000000000009fa986acb22953c504fcf5985dfa476d481c3b1b000000000000000000000000db670e1a1e312bf17425b08ce55bdf2cd8f8ed5400000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000144e80a7c79000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba000000000000000000000000000000000000000000000000000000000000000855534420436f696e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004555344430000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", "isProxy": true, "name": "TransparentUpgradeableProxy" + }, + { + "address": "0x086eF95a2F74582Ee30E7D698518a872fb18301f", + "constructorArguments": "", + "isProxy": false, + "name": "ProxyAdmin" + }, + { + "address": "0x8358D8291e3bEDb04804975eEa0fe9fe0fAfB147", + "constructorArguments": "", + "isProxy": false, + "name": "ProxyAdmin" } ], "arbitrum": [ diff --git a/typescript/infra/config/environments/testnet4/aw-validators/hyperlane.json b/typescript/infra/config/environments/testnet4/aw-validators/hyperlane.json new file mode 100644 index 0000000000..cc2846ca39 --- /dev/null +++ b/typescript/infra/config/environments/testnet4/aw-validators/hyperlane.json @@ -0,0 +1,50 @@ +{ + "alfajores": { + "validators": [ + "0x2233a5ce12f814bd64c9cdd73410bb8693124d40", + "0xba279f965489d90f90490e3c49e860e0b43c2ae6", + "0x86485dcec5f7bb8478dd251676372d054dea6653" + ] + }, + "bsctestnet": { + "validators": [ + "0x242d8a855a8c932dec51f7999ae7d1e48b10c95e", + "0xf620f5e3d25a3ae848fec74bccae5de3edcd8796", + "0x1f030345963c54ff8229720dd3a711c15c554aeb" + ] + }, + "eclipsetestnet": { + "validators": ["0xf344f34abca9a444545b5295066348a0ae22dda3"] + }, + "fuji": { + "validators": [ + "0xd8154f73d04cc7f7f0c332793692e6e6f6b2402e", + "0x895ae30bc83ff1493b9cf7781b0b813d23659857", + "0x43e915573d9f1383cbf482049e4a012290759e7f" + ] + }, + "plumetestnet": { + "validators": [ + "0xe765a214849f3ecdf00793b97d00422f2d408ea6", + "0xb59998f71efc65190a85ac5e81b66bd72a192a3b", + "0xc906470a73e6b5aad65a4ceb4acd73e3eaf80e2c" + ] + }, + "scrollsepolia": { + "validators": [ + "0xbe18dbd758afb367180260b524e6d4bcd1cb6d05", + "0x9a11ed23ae962974018ab45bc133caabff7b3271", + "0x7867bea3c9761fe64e6d124b171f91fd5dd79644" + ] + }, + "sepolia": { + "validators": [ + "0xb22b65f202558adf86a8bb2847b76ae1036686a5", + "0x469f0940684d147defc44f3647146cb90dd0bc8e", + "0xd3c75dcf15056012a4d74c483a0c6ea11d8c2b83" + ] + }, + "solanatestnet": { + "validators": ["0xd4ce8fa138d4e083fc0e480cca0dbfa4f5f30bd5"] + } +} diff --git a/typescript/infra/config/environments/testnet4/aw-validators/rc.json b/typescript/infra/config/environments/testnet4/aw-validators/rc.json new file mode 100644 index 0000000000..bcecd3ec6d --- /dev/null +++ b/typescript/infra/config/environments/testnet4/aw-validators/rc.json @@ -0,0 +1,44 @@ +{ + "alfajores": { + "validators": [ + "0xace978aaa61d9ee44fe3ab147fd227e0e66b8909", + "0x6c8bfdfb8c40aba10cc9fb2cf0e3e856e0e5dbb3", + "0x54c65eb7677e6086cdde3d5ccef89feb2103a11d" + ] + }, + "bsctestnet": { + "validators": [ + "0x6353c7402626054c824bd0eca721f82b725e2b4d", + "0xcb5be62b19c52b78cd3993c71c3fa74d821475ae", + "0xc50ddb8f03133611853b7f03ffe0a8098e08ae15" + ] + }, + "fuji": { + "validators": [ + "0xfc419f9ba3c56c55e28844ade491d428f5a77d55", + "0x0a636e76df4124b092cabb4321d6aaef9defb514", + "0xbf86037899efe97bca4cea865607e10b849b5878" + ] + }, + "plumetestnet": { + "validators": [ + "0xe6e6aeecbf7755cdbc50c2683df9f2d100f6399d", + "0x27946c13a475233a3b1eb47f0bd0f7cdec3a3983", + "0x2596413213368475c96ddfb1ae26666d22093a8b" + ] + }, + "scrollsepolia": { + "validators": [ + "0x50d939d66f114350f322eb8b2e9f01fbc401d4c9", + "0x10fa7a657a06a47bcca1bacc436d61619e5d104c", + "0xa0f1cf3b23bd0f8a5e2ad438657097b8287816b4" + ] + }, + "sepolia": { + "validators": [ + "0x49f253c0dab33be1573d6c2769b3d9e584d91f82", + "0x13b51805e9af68e154778d973165f32e10b7446b", + "0x7f699c3fc3de4928f1c0abfba1eac3fbb5a00d1b" + ] + } +} diff --git a/typescript/infra/config/environments/testnet4/validators.ts b/typescript/infra/config/environments/testnet4/validators.ts index c02745280d..d4e4be74aa 100644 --- a/typescript/infra/config/environments/testnet4/validators.ts +++ b/typescript/infra/config/environments/testnet4/validators.ts @@ -131,35 +131,6 @@ export const validatorChainConfig = ( 'plumetestnet', ), }, - injective: { - interval: 5, - reorgPeriod: getReorgPeriod(chainMetadata.injective), - validators: validatorsConfig( - { - [Contexts.Hyperlane]: ['0x10686BEe585491A0DA5bfCd5ABfbB95Ab4d6c86d'], - [Contexts.ReleaseCandidate]: [], - [Contexts.Neutron]: [], - }, - 'injective', - ), - }, - // proteustestnet: { - // interval: 5, - // reorgPeriod: getReorgPeriod(chainMetadata.proteustestnet), - // validators: validatorsConfig( - // { - // [Contexts.Hyperlane]: [ - // '0x79fc73656abb9eeaa5ee853c4569124f5bdaf9d8', - // '0x72840388d5ab57323bc4f6e6d3ddedfd5cc911f0', - // '0xd4b2a50c53fc6614bb3cd3198e0fdc03f5da973f', - // ], - // [Contexts.ReleaseCandidate]: [ - // '0xc2ccc4eab0e8d441235d661e39341ae16c3bf8cd', - // ], - // }, - // 'proteustestnet', - // ), - // }, solanatestnet: { interval: 1, reorgPeriod: getReorgPeriod(chainMetadata.solanatestnet), diff --git a/typescript/infra/config/warp.ts b/typescript/infra/config/warp.ts new file mode 100644 index 0000000000..831b7cafe4 --- /dev/null +++ b/typescript/infra/config/warp.ts @@ -0,0 +1,81 @@ +import { ethers } from 'ethers'; + +import { + ChainMap, + ERC20RouterConfig, + HyperlaneCore, + HyperlaneIsmFactory, + MultiProvider, + RouterConfig, + TokenConfig, + TokenType, + buildAggregationIsmConfigs, + defaultMultisigConfigs, +} from '@hyperlane-xyz/sdk'; + +import { Modules, getAddresses } from '../scripts/agent-utils'; +import { + EnvironmentConfig, + deployEnvToSdkEnv, +} from '../src/config/environment'; +import { tokens } from '../src/config/warp'; + +import { DEPLOYER } from './environments/mainnet3/owners'; + +export async function getWarpConfig( + multiProvider: MultiProvider, + envConfig: EnvironmentConfig, +): Promise> { + const core = HyperlaneCore.fromEnvironment( + deployEnvToSdkEnv[envConfig.environment], + multiProvider, + ); + const ismFactory = HyperlaneIsmFactory.fromAddressesMap( + getAddresses(envConfig.environment, Modules.PROXY_FACTORY), + multiProvider, + ); + + const owner = DEPLOYER; + + // "Manually" deploying an ISM because the warp deployer doesn't support + // ISM objects at the moment, and the deploy involves strictly recoverable ISMs. + const ism = await ismFactory.deploy({ + destination: 'ethereum', + config: buildAggregationIsmConfigs( + 'ethereum', + ['ancient8'], + defaultMultisigConfigs, + ).ancient8, + }); + + const routerConfig = core.getRouterConfig(envConfig.owners); + + const ethereum: TokenConfig & RouterConfig = { + ...routerConfig.ethereum, + type: TokenType.collateral, + token: tokens.ethereum.USDC, + interchainSecurityModule: ism.address, + // This hook was recovered from running the deploy script + // for the hook module. The hook configuration is the Ethereum + // default hook for the Ancient8 remote (no routing). + hook: '0x19b2cF952b70b217c90FC408714Fbc1acD29A6A8', + owner, + }; + + // @ts-ignore - The types as they stand require a synthetic to specify + // TokenMetadata, but in practice these are actually inferred from a + // collateral config. To avoid needing to specify the TokenMetadata, just + // ts-ignore for synthetic tokens. + const ancient8: TokenConfig & RouterConfig = { + ...routerConfig.ancient8, + type: TokenType.synthetic, + // Uses the default ISM + interchainSecurityModule: ethers.constants.AddressZero, + owner, + }; + + return { + ethereum, + ancient8, + }; +} diff --git a/typescript/infra/helm/warp-routes/templates/_helpers.tpl b/typescript/infra/helm/warp-routes/templates/_helpers.tpl index f4359eaf07..29afca86f6 100644 --- a/typescript/infra/helm/warp-routes/templates/_helpers.tpl +++ b/typescript/infra/helm/warp-routes/templates/_helpers.tpl @@ -58,6 +58,9 @@ The warp-routes container - name: warp-routes image: {{ .Values.image.repository }}:{{ .Values.image.tag }} imagePullPolicy: IfNotPresent + env: + - name: LOG_FORMAT + value: pretty command: - ./node_modules/.bin/tsx - ./typescript/infra/scripts/warp-routes/monitor-warp-routes-balances.ts diff --git a/typescript/infra/scripts/agent-utils.ts b/typescript/infra/scripts/agent-utils.ts index 1ea2658571..74cfe023a8 100644 --- a/typescript/infra/scripts/agent-utils.ts +++ b/typescript/infra/scripts/agent-utils.ts @@ -1,4 +1,5 @@ -import path from 'path'; +import path, { dirname, join } from 'path'; +import { fileURLToPath } from 'url'; import yargs, { Argv } from 'yargs'; import { @@ -40,6 +41,7 @@ import { Role } from '../src/roles.js'; import { assertContext, assertRole, + getInfraPath, readJSON, readJSONAtPath, } from '../src/utils/utils.js'; @@ -266,7 +268,11 @@ export function ensureValidatorConfigConsistency(agentConfig: RootAgentConfig) { ); if (symDiff.size > 0) { throw new Error( - `Validator config invalid. Validator context chain names: ${validatorContextChainNames}, validator config chains: ${validatorConfigChains}, diff: ${symDiff}`, + `Validator config invalid.\nValidator context chain names: ${[ + ...validatorContextChainNames, + ]}\nValidator config chains: ${[...validatorConfigChains]}\nDiff: ${[ + ...symDiff, + ]}`, ); } } @@ -430,3 +436,15 @@ export function getValidatorsByChain( } return validators; } + +export function getAWValidatorsPath( + environment: DeployEnvironment, + context: Contexts, +) { + return join( + getInfraPath(), + getEnvironmentDirectory(environment), + 'aw-validators', + `${context}.json`, + ); +} diff --git a/typescript/infra/scripts/check-deploy.ts b/typescript/infra/scripts/check-deploy.ts index 54b553b0a7..81720905ad 100644 --- a/typescript/infra/scripts/check-deploy.ts +++ b/typescript/infra/scripts/check-deploy.ts @@ -16,6 +16,7 @@ import { } from '@hyperlane-xyz/sdk'; import { Contexts } from '../config/contexts.js'; +import { getWarpConfig } from '../config/warp.js'; import { deployEnvToSdkEnv } from '../src/config/environment.js'; import { HyperlaneAppGovernor } from '../src/govern/HyperlaneAppGovernor.js'; import { HyperlaneCoreGovernor } from '../src/govern/HyperlaneCoreGovernor.js'; @@ -43,8 +44,8 @@ function getArgs() { async function check() { const { fork, govern, module, environment, context } = await getArgs(); - const config = getEnvironmentConfig(environment); - let multiProvider = await config.getMultiProvider(); + const envConfig = getEnvironmentConfig(environment); + let multiProvider = await envConfig.getMultiProvider(); // must rotate to forked provider before building core contracts if (fork) { @@ -58,7 +59,7 @@ async function check() { const owner = await resolveOrDeployAccountOwner( multiProvider, fork, - config.core[fork].owner, + envConfig.core[fork].owner, ); const signer = await impersonateAccount(owner, 1e18); @@ -69,7 +70,7 @@ async function check() { const env = deployEnvToSdkEnv[environment]; const core = HyperlaneCore.fromEnvironment(env, multiProvider); const ismFactory = HyperlaneIsmFactory.fromEnvironment(env, multiProvider); - const routerConfig = core.getRouterConfig(config.owners); + const routerConfig = core.getRouterConfig(envConfig.owners); const ica = InterchainAccount.fromEnvironment(env, multiProvider); let governor: HyperlaneAppGovernor; @@ -77,13 +78,13 @@ async function check() { const checker = new HyperlaneCoreChecker( multiProvider, core, - config.core, + envConfig.core, ismFactory, ); governor = new HyperlaneCoreGovernor(checker); } else if (module === Modules.INTERCHAIN_GAS_PAYMASTER) { const igp = HyperlaneIgp.fromEnvironment(env, multiProvider); - const checker = new HyperlaneIgpChecker(multiProvider, igp, config.igp); + const checker = new HyperlaneIgpChecker(multiProvider, igp, envConfig.igp); governor = new HyperlaneIgpGovernor(checker); } else if (module === Modules.INTERCHAIN_ACCOUNTS) { const checker = new InterchainAccountChecker( @@ -102,7 +103,7 @@ async function check() { governor = new ProxiedRouterGovernor(checker); } else if (module === Modules.HELLO_WORLD) { const app = await getHelloWorldApp( - config, + envConfig, context, Role.Deployer, Contexts.Hyperlane, // Owner should always be from the hyperlane context @@ -116,25 +117,7 @@ async function check() { ); governor = new ProxiedRouterGovernor(checker); } else if (module === Modules.WARP) { - // test config - const plumetestnet = { - ...routerConfig.plumetestnet, - type: TokenType.synthetic, - name: 'Wrapped Ether', - symbol: 'WETH', - decimals: 18, - totalSupply: '0', - gas: 0, - }; - const sepolia = { - ...routerConfig.sepolia, - type: TokenType.native, - gas: 0, - }; - const config = { - plumetestnet, - sepolia, - }; + const config = await getWarpConfig(multiProvider, envConfig); const addresses = getAddresses(environment, Modules.WARP); const filteredAddresses = Object.keys(addresses) // filter out changes not in config .filter((key) => key in config) diff --git a/typescript/infra/scripts/deploy.ts b/typescript/infra/scripts/deploy.ts index 6431b32d13..7d3d451972 100644 --- a/typescript/infra/scripts/deploy.ts +++ b/typescript/infra/scripts/deploy.ts @@ -21,7 +21,6 @@ import { InterchainQueryDeployer, LiquidityLayerDeployer, TestRecipientDeployer, - TokenType, hyperlaneEnvironments, } from '@hyperlane-xyz/sdk'; import { objMap } from '@hyperlane-xyz/utils'; @@ -29,8 +28,8 @@ import { objMap } from '@hyperlane-xyz/utils'; import { Contexts } from '../config/contexts.js'; import { core as coreConfig } from '../config/environments/mainnet3/core.js'; import { DEPLOYER } from '../config/environments/mainnet3/owners.js'; +import { getWarpConfig } from '../config/warp.js'; import { deployEnvToSdkEnv } from '../src/config/environment.js'; -import { tokens } from '../src/config/warp.js'; import { deployWithArtifacts } from '../src/deployment/deploy.js'; import { TestQuerySenderDeployer } from '../src/deployment/testcontracts/testquerysender.js'; import { @@ -120,48 +119,11 @@ async function main() { contractVerifier, ); } else if (module === Modules.WARP) { - const core = HyperlaneCore.fromEnvironment(env, multiProvider); const ismFactory = HyperlaneIsmFactory.fromAddressesMap( - getAddresses(environment, Modules.PROXY_FACTORY), + getAddresses(envConfig.environment, Modules.PROXY_FACTORY), multiProvider, ); - const routerConfig = core.getRouterConfig(envConfig.owners); - - const ethereum = { - ...routerConfig.ethereum, - type: TokenType.collateral, - token: tokens.ethereum.USDC, - // Really, this should be an object config from something like: - // buildAggregationIsmConfigs( - // 'ethereum', - // ['ancient8'], - // defaultMultisigConfigs, - // ).ancient8 - // However ISM objects are no longer able to be passed directly to the warp route - // deployer. As a temporary workaround, I'm using an ISM address from a previous - // ethereum <> ancient8 warp route deployment: - // $ cast call 0x9f5cF636b4F2DC6D83c9d21c8911876C235DbC9f 'interchainSecurityModule()(address)' --rpc-url https://rpc.ankr.com/eth - // 0xD17B4100cC66A2F1B9a452007ff26365aaeB7EC3 - interchainSecurityModule: '0xD17B4100cC66A2F1B9a452007ff26365aaeB7EC3', - // This hook was recovered from running the deploy script - // for the hook module. The hook configuration is the Ethereum - // default hook for the Ancient8 remote (no routing). - hook: '0x19b2cF952b70b217c90FC408714Fbc1acD29A6A8', - owner: DEPLOYER, - }; - - const ancient8 = { - ...routerConfig.ancient8, - type: TokenType.synthetic, - // Uses the default ISM - interchainSecurityModule: ethers.constants.AddressZero, - owner: DEPLOYER, - }; - - config = { - ethereum, - ancient8, - }; + config = await getWarpConfig(multiProvider, envConfig); deployer = new HypERC20Deployer( multiProvider, ismFactory, diff --git a/typescript/infra/scripts/middleware/circle-relayer.ts b/typescript/infra/scripts/middleware/circle-relayer.ts index 18bc68774b..b125a2eeb4 100644 --- a/typescript/infra/scripts/middleware/circle-relayer.ts +++ b/typescript/infra/scripts/middleware/circle-relayer.ts @@ -1,5 +1,4 @@ -import { dirname, join } from 'path'; -import { fileURLToPath } from 'url'; +import { join } from 'path'; import { LiquidityLayerApp, @@ -9,7 +8,7 @@ import { } from '@hyperlane-xyz/sdk'; import { objFilter, sleep } from '@hyperlane-xyz/utils'; -import { readJSON } from '../../src/utils/utils.js'; +import { getInfraPath, readJSON } from '../../src/utils/utils.js'; import { getArgs, getEnvironmentDirectory } from '../agent-utils.js'; import { getEnvironmentConfig } from '../core-utils.js'; @@ -23,8 +22,7 @@ async function check() { const multiProvider = await config.getMultiProvider(); const dir = join( - dirname(fileURLToPath(import.meta.url)), - '../../', + getInfraPath(), getEnvironmentDirectory(environment), 'middleware/liquidity-layer', ); diff --git a/typescript/infra/scripts/middleware/portal-relayer.ts b/typescript/infra/scripts/middleware/portal-relayer.ts index ed3a8e09bd..27e327fcec 100644 --- a/typescript/infra/scripts/middleware/portal-relayer.ts +++ b/typescript/infra/scripts/middleware/portal-relayer.ts @@ -1,5 +1,4 @@ -import { dirname, join } from 'path'; -import { fileURLToPath } from 'url'; +import { join } from 'path'; import { LiquidityLayerApp, @@ -9,7 +8,7 @@ import { import { rootLogger, sleep } from '@hyperlane-xyz/utils'; import { bridgeAdapterConfigs } from '../../config/environments/testnet4/token-bridge.js'; -import { readJSON } from '../../src/utils/utils.js'; +import { getInfraPath, readJSON } from '../../src/utils/utils.js'; import { getArgs, getEnvironmentDirectory } from '../agent-utils.js'; import { getEnvironmentConfig } from '../core-utils.js'; @@ -20,8 +19,7 @@ async function relayPortalTransfers() { const config = getEnvironmentConfig(environment); const multiProvider = await config.getMultiProvider(); const dir = join( - dirname(fileURLToPath(import.meta.url)), - '../../', + getInfraPath(), getEnvironmentDirectory(environment), 'middleware/liquidity-layer', ); diff --git a/typescript/infra/scripts/warp-routes/helm.ts b/typescript/infra/scripts/warp-routes/helm.ts index fa0cfb0c62..24905cbe7f 100644 --- a/typescript/infra/scripts/warp-routes/helm.ts +++ b/typescript/infra/scripts/warp-routes/helm.ts @@ -1,3 +1,5 @@ +import path from 'path'; + import { DeployEnvironment } from '../../src/config/environment.js'; import { HelmCommand, helmifyValues } from '../../src/utils/helm.js'; import { execCmd } from '../../src/utils/utils.js'; @@ -27,12 +29,16 @@ function getHelmReleaseName(route: string): string { } function getWarpRoutesHelmValues(configFilePath: string) { + // The path should be relative to the monorepo root + const pathRelativeToMonorepoRoot = configFilePath.includes('typescript/infra') + ? configFilePath + : path.join('typescript/infra', configFilePath); const values = { image: { repository: 'gcr.io/abacus-labs-dev/hyperlane-monorepo', - tag: '09344fc-20240321-203114', + tag: '135e6a8-20240415-135635', }, - configFilePath: configFilePath, + configFilePath: pathRelativeToMonorepoRoot, }; return helmifyValues(values); } diff --git a/typescript/infra/src/agents/index.ts b/typescript/infra/src/agents/index.ts index 186d35934a..6105536dc4 100644 --- a/typescript/infra/src/agents/index.ts +++ b/typescript/infra/src/agents/index.ts @@ -1,6 +1,5 @@ import fs from 'fs'; -import { dirname, join } from 'path'; -import { fileURLToPath } from 'url'; +import { join } from 'path'; import { ChainName, RpcConsensusType, chainMetadata } from '@hyperlane-xyz/sdk'; @@ -23,13 +22,17 @@ import { buildHelmChartDependencies, helmifyValues, } from '../utils/helm.js'; -import { execCmd, isEthereumProtocolChain } from '../utils/utils.js'; +import { + execCmd, + getInfraPath, + isEthereumProtocolChain, +} from '../utils/utils.js'; import { AgentGCPKey } from './gcp.js'; const HELM_CHART_PATH = join( - dirname(fileURLToPath(import.meta.url)), - '/../../../../rust/helm/hyperlane-agent/', + getInfraPath(), + '/../../rust/helm/hyperlane-agent/', ); if (!fs.existsSync(HELM_CHART_PATH + 'Chart.yaml')) diff --git a/typescript/infra/src/agents/key-utils.ts b/typescript/infra/src/agents/key-utils.ts index 256a24e6b9..e9d352e137 100644 --- a/typescript/infra/src/agents/key-utils.ts +++ b/typescript/infra/src/agents/key-utils.ts @@ -4,21 +4,20 @@ import { fileURLToPath } from 'url'; import { ChainMap, ChainName } from '@hyperlane-xyz/sdk'; import { Address, objMap, rootLogger } from '@hyperlane-xyz/utils'; -import localAWMultisigAddresses from '../../config/aw-multisig-hyperlane.json'; -// AW - Abacus Works import { Contexts } from '../../config/contexts.js'; import { helloworld } from '../../config/environments/helloworld.js'; import localKathyAddresses from '../../config/kathy.json'; import localRelayerAddresses from '../../config/relayer.json'; +import { getAWValidatorsPath } from '../../scripts/agent-utils.js'; import { getJustHelloWorldConfig } from '../../scripts/helloworld/utils.js'; import { AgentContextConfig, RootAgentConfig } from '../config/agent/agent'; import { DeployEnvironment } from '../config/environment'; import { Role } from '../roles.js'; import { execCmd, + getInfraPath, isEthereumProtocolChain, readJSON, - writeJSON, writeJsonAtPath, } from '../utils/utils.js'; @@ -34,8 +33,6 @@ export const relayerAddresses: LocalRoleAddresses = localRelayerAddresses as LocalRoleAddresses; export const kathyAddresses: LocalRoleAddresses = localKathyAddresses as LocalRoleAddresses; -export const awMultisigAddresses: ChainMap<{ validators: Address[] }> = - localAWMultisigAddresses as ChainMap<{ validators: Address[] }>; const debugLog = rootLogger.child({ module: 'infra:agents:key:utils' }).debug; @@ -44,10 +41,7 @@ export interface KeyAsAddress { address: string; } -const CONFIG_DIRECTORY_PATH = join( - dirname(fileURLToPath(import.meta.url)), - '../../config', -); +const CONFIG_DIRECTORY_PATH = join(getInfraPath(), 'config'); // ================== // Functions for getting keys @@ -435,10 +429,13 @@ async function persistAddressesLocally( relayerAddresses, ); - await persistValidatorAddressesToLocalArtifacts( - agentConfig.context, - multisigValidatorKeys, - ); + if (Object.keys(multisigValidatorKeys).length > 0) { + await persistValidatorAddressesToLocalArtifacts( + agentConfig.runEnv, + agentConfig.context, + multisigValidatorKeys, + ); + } } // non-validator roles @@ -452,29 +449,21 @@ export async function persistRoleAddressesToLocalArtifacts( addresses[environment][context] = updated; // Resolve the relative path - const filePath = join( - dirname(fileURLToPath(import.meta.url)), - `../../config/${role}.json`, - ); + const filePath = join(getInfraPath(), `config/${role}.json`); writeJsonAtPath(filePath, addresses); } // maintaining the multisigIsm schema sans threshold export async function persistValidatorAddressesToLocalArtifacts( + environment: DeployEnvironment, context: Contexts, fetchedValidatorAddresses: ChainMap<{ validators: Address[] }>, ) { - for (const chain of Object.keys(fetchedValidatorAddresses)) { - awMultisigAddresses[chain] = { - validators: fetchedValidatorAddresses[chain].validators, // fresh from aws - }; - } // Write the updated object back to the file - writeJSON( - CONFIG_DIRECTORY_PATH, - `aw-multisig-${context}.json`, - awMultisigAddresses, + writeJsonAtPath( + getAWValidatorsPath(environment, context), + fetchedValidatorAddresses, ); } diff --git a/typescript/infra/src/utils/utils.ts b/typescript/infra/src/utils/utils.ts index 8061ed75e6..ef908f9f2d 100644 --- a/typescript/infra/src/utils/utils.ts +++ b/typescript/infra/src/utils/utils.ts @@ -4,7 +4,8 @@ import { exec } from 'child_process'; import { ethers } from 'ethers'; import fs from 'fs'; import stringify from 'json-stable-stringify'; -import path from 'path'; +import path, { dirname, join } from 'path'; +import { fileURLToPath } from 'url'; import { parse as yamlParse } from 'yaml'; import { @@ -264,3 +265,7 @@ export function isEthereumProtocolChain(chainName: ChainName) { if (!chainMetadata[chainName]) throw new Error(`Unknown chain ${chainName}`); return chainMetadata[chainName].protocol === ProtocolType.Ethereum; } + +export function getInfraPath() { + return join(dirname(fileURLToPath(import.meta.url)), '../../'); +} diff --git a/typescript/sdk/src/consts/multisigIsm.ts b/typescript/sdk/src/consts/multisigIsm.ts index 1a63efe9e8..914e24ad9d 100644 --- a/typescript/sdk/src/consts/multisigIsm.ts +++ b/typescript/sdk/src/consts/multisigIsm.ts @@ -12,8 +12,12 @@ export const defaultMultisigConfigs: ChainMap = { }, ancient8: { - threshold: 1, - validators: ['0xbb5842ae0e05215b53df4787a29144efb7e67551'], + threshold: 2, + validators: [ + '0xbb5842ae0e05215b53df4787a29144efb7e67551', + '0xa5a56e97fb46f0ac3a3d261e404acb998d9a6969', // coin98 + '0x95c7bf235837cb5a609fe6c95870410b9f68bcff', // ancient8 + ], }, arbitrum: { From 6c42a6458dd3bfe0dc542833c38e5f959be316ab Mon Sep 17 00:00:00 2001 From: Trevor Porter Date: Thu, 18 Apr 2024 13:54:31 +0100 Subject: [PATCH 06/16] Deploy RC relayer for extra throughput (#3620) ### Description See https://discord.com/channels/935678348330434570/1230452070696484956 for context. General idea as a stopgap is to run a relayer concurrent with the Hyperlane one ### Drive-by changes ### Related issues ### Backward compatibility ### Testing --- .../config/environments/mainnet3/agent.ts | 131 +++++++++--------- typescript/infra/src/agents/gcp.ts | 2 +- 2 files changed, 65 insertions(+), 68 deletions(-) diff --git a/typescript/infra/config/environments/mainnet3/agent.ts b/typescript/infra/config/environments/mainnet3/agent.ts index a470caea86..68d212ca28 100644 --- a/typescript/infra/config/environments/mainnet3/agent.ts +++ b/typescript/infra/config/environments/mainnet3/agent.ts @@ -126,11 +126,69 @@ const contextBase = { } as const; const gasPaymentEnforcement: GasPaymentEnforcement[] = [ + // To cover ourselves against IGP indexing issues and to ensure Nexus + // users have the best possible experience, we whitelist messages between + // warp routes that we know are certainly paying for gas. + { + type: GasPaymentEnforcementPolicyType.None, + matchingList: [ + ...routerMatchingList(injectiveInevmInjAddresses), + ...matchingList(inevmEthereumUsdcAddresses), + ...matchingList(inevmEthereumUsdtAddresses), + ...routerMatchingList(victionEthereumEthAddresses), + ...routerMatchingList(victionEthereumUsdcAddresses), + ...routerMatchingList(victionEthereumUsdtAddresses), + ...routerMatchingList(ancient8EthereumUsdcAddresses), + ], + }, + { + type: GasPaymentEnforcementPolicyType.None, + matchingList: matchingList(inevmEthereumUsdcAddresses), + }, + { + type: GasPaymentEnforcementPolicyType.None, + matchingList: matchingList(inevmEthereumUsdtAddresses), + }, { type: GasPaymentEnforcementPolicyType.OnChainFeeQuoting, }, ]; +const metricAppContexts = [ + { + name: 'helloworld', + matchingList: routerMatchingList(helloWorld[Contexts.Hyperlane].addresses), + }, + { + name: 'injective_inevm_inj', + matchingList: routerMatchingList(injectiveInevmInjAddresses), + }, + { + name: 'inevm_ethereum_usdc', + matchingList: matchingList(inevmEthereumUsdcAddresses), + }, + { + name: 'inevm_ethereum_usdt', + matchingList: matchingList(inevmEthereumUsdtAddresses), + }, + { + name: 'viction_ethereum_eth', + matchingList: routerMatchingList(victionEthereumEthAddresses), + }, + { + name: 'viction_ethereum_usdc', + matchingList: routerMatchingList(victionEthereumUsdcAddresses), + }, + { + name: 'viction_ethereum_usdt', + matchingList: routerMatchingList(victionEthereumUsdtAddresses), + }, + { + name: 'ancient8_ethereum_usdc', + matchingList: routerMatchingList(ancient8EthereumUsdcAddresses), + }, +]; + const hyperlane: RootAgentConfig = { ...contextBase, context: Contexts.Hyperlane, @@ -142,68 +200,8 @@ const hyperlane: RootAgentConfig = { repo, tag: '2a16200-20240408-214947', }, - gasPaymentEnforcement: [ - // To cover ourselves against IGP indexing issues and to ensure Nexus - // users have the best possible experience, we whitelist messages between - // warp routes that we know are certainly paying for gas. - { - type: GasPaymentEnforcementPolicyType.None, - matchingList: [ - ...routerMatchingList(injectiveInevmInjAddresses), - ...matchingList(inevmEthereumUsdcAddresses), - ...matchingList(inevmEthereumUsdtAddresses), - ...routerMatchingList(victionEthereumEthAddresses), - ...routerMatchingList(victionEthereumUsdcAddresses), - ...routerMatchingList(victionEthereumUsdtAddresses), - ...routerMatchingList(ancient8EthereumUsdcAddresses), - ], - }, - { - type: GasPaymentEnforcementPolicyType.None, - matchingList: matchingList(inevmEthereumUsdcAddresses), - }, - { - type: GasPaymentEnforcementPolicyType.None, - matchingList: matchingList(inevmEthereumUsdtAddresses), - }, - ...gasPaymentEnforcement, - ], - metricAppContexts: [ - { - name: 'helloworld', - matchingList: routerMatchingList( - helloWorld[Contexts.Hyperlane].addresses, - ), - }, - { - name: 'injective_inevm_inj', - matchingList: routerMatchingList(injectiveInevmInjAddresses), - }, - { - name: 'inevm_ethereum_usdc', - matchingList: matchingList(inevmEthereumUsdcAddresses), - }, - { - name: 'inevm_ethereum_usdt', - matchingList: matchingList(inevmEthereumUsdtAddresses), - }, - { - name: 'viction_ethereum_eth', - matchingList: routerMatchingList(victionEthereumEthAddresses), - }, - { - name: 'viction_ethereum_usdc', - matchingList: routerMatchingList(victionEthereumUsdcAddresses), - }, - { - name: 'viction_ethereum_usdt', - matchingList: routerMatchingList(victionEthereumUsdtAddresses), - }, - { - name: 'ancient8_ethereum_usdc', - matchingList: routerMatchingList(ancient8EthereumUsdcAddresses), - }, - ], + gasPaymentEnforcement: gasPaymentEnforcement, + metricAppContexts, }, validators: { docker: { @@ -233,12 +231,11 @@ const releaseCandidate: RootAgentConfig = { repo, tag: '2a16200-20240408-214947', }, - whitelist: releaseCandidateHelloworldMatchingList, + // We're temporarily (ab)using the RC relayer as a way to increase + // message throughput. + // whitelist: releaseCandidateHelloworldMatchingList, gasPaymentEnforcement, - transactionGasLimit: 750000, - // Skipping arbitrum because the gas price estimates are inclusive of L1 - // fees which leads to wildly off predictions. - skipTransactionGasLimitFor: [chainMetadata.arbitrum.name], + metricAppContexts, }, validators: { docker: { diff --git a/typescript/infra/src/agents/gcp.ts b/typescript/infra/src/agents/gcp.ts index 782c34631d..f7041e6462 100644 --- a/typescript/infra/src/agents/gcp.ts +++ b/typescript/infra/src/agents/gcp.ts @@ -123,7 +123,7 @@ export class AgentGCPKey extends CloudAgentKey { ); // TODO support other prefixes? // https://cosmosdrops.io/en/tools/bech32-converter is useful for converting to other prefixes. - return pubkeyToAddress(encodedPubkey, 'neutron'); + return pubkeyToAddress(encodedPubkey, 'inj'); } default: this.logger.debug(`Unsupported protocol: ${protocol}`); From a91677a3daa7c0c1c9c191515910f40290fbf036 Mon Sep 17 00:00:00 2001 From: Lee <6251863+ltyu@users.noreply.github.com> Date: Thu, 18 Apr 2024 15:55:24 -0400 Subject: [PATCH 07/16] Return entire deployedContracts object (#3617) ### Description Returns the deployedContracts object in token deployer ### Drive-by changes ### Related issues - Fixes #3585 ### Backward compatibility ### Testing None --------- Co-authored-by: Yorke Rhodes --- typescript/sdk/src/token/deploy.ts | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/typescript/sdk/src/token/deploy.ts b/typescript/sdk/src/token/deploy.ts index 1d28f8da1c..d23038cecf 100644 --- a/typescript/sdk/src/token/deploy.ts +++ b/typescript/sdk/src/token/deploy.ts @@ -104,7 +104,7 @@ export class HypERC20Deployer extends GasRouterDeployer< } async initializeArgs(_: ChainName, config: HypERC20Config): Promise { - // ISM config can be an object, but is not supported right now + // ISM config can be an object, but is not supported right now. if (typeof config.interchainSecurityModule === 'object') { throw new Error('Token deployer does not support ISM objects currently'); } @@ -205,11 +205,13 @@ export class HypERC20Deployer extends GasRouterDeployer< } async deployContracts(chain: ChainName, config: HypERC20Config) { - const { [this.routerContractKey(config)]: router } = - await super.deployContracts(chain, config); - - await this.configureClient(chain, router as MailboxClient, config); - return { [config.type]: router } as any; + const deployedContracts = await super.deployContracts(chain, config); + const router = deployedContracts[this.routerContractKey(config)]; + await this.configureClient(chain, router, config); + return { + [config.type]: router, + ...deployedContracts, + } as any; } async buildTokenMetadata( From e10735a71860bdefcc9cd6ff27e5c973a44bed9f Mon Sep 17 00:00:00 2001 From: Yorke Rhodes Date: Sat, 20 Apr 2024 02:15:58 -0400 Subject: [PATCH 08/16] Fix solidity coverage (#3640) --- solidity/coverage.sh | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/solidity/coverage.sh b/solidity/coverage.sh index 567dd7f044..bd9a3e232d 100755 --- a/solidity/coverage.sh +++ b/solidity/coverage.sh @@ -1,7 +1,10 @@ #!/bin/bash # generates lcov.info -forge coverage --report lcov --no-match-test testFork +forge coverage \ + --report lcov \ + --no-match-test testFork \ + --ir-minimum # https://github.com/foundry-rs/foundry/issues/3357 if ! command -v lcov &>/dev/null; then echo "lcov is not installed. Installing..." @@ -10,14 +13,16 @@ fi lcov --version -# forge does not instrument libraries https://github.com/foundry-rs/foundry/issues/4854 -EXCLUDE="*test* *mock* *node_modules* $(grep -r 'library' contracts -l)" -lcov --rc lcov_branch_coverage=1 \ +# exclude FastTokenRouter until https://github.com/hyperlane-xyz/hyperlane-monorepo/issues/2806 +EXCLUDE="*test* *mock* *node_modules* *FastHyp*" +lcov \ + --rc lcov_branch_coverage=1 \ + --remove lcov.info $EXCLUDE \ --output-file forge-pruned-lcov.info \ - --remove lcov.info $EXCLUDE if [ "$CI" != "true" ]; then - genhtml --rc lcov_branch_coverage=1 \ - --output-directory coverage forge-pruned-lcov.info \ - && open coverage/index.html + genhtml forge-pruned-lcov.info \ + --rc lcov_branch_coverage=1 \ + --output-directory coverage + open coverage/index.html fi From 450e8e0d5531f3fc44f2c1b98195e2743ac5e223 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noah=20Bayindirli=20=F0=9F=A5=82?= Date: Mon, 22 Apr 2024 13:36:35 -0400 Subject: [PATCH 09/16] migrate fork util to SDK (#3625) ### Description * Migrates fork util to SDK ### Drive-by changes * None ### Related issues - Fixes https://github.com/hyperlane-xyz/hyperlane-monorepo/issues/3624 ### Backward compatibility * Yes ### Testing * Manual on core & warp --- .changeset/nice-pianos-tease.md | 6 +++ typescript/cli/src/deploy/dry-run.ts | 13 +++--- typescript/cli/src/deploy/utils.ts | 7 +-- typescript/cli/src/utils/keys.ts | 3 +- typescript/sdk/src/index.ts | 8 ++++ typescript/{cli => sdk}/src/utils/fork.ts | 55 +++++++++++++---------- 6 files changed, 58 insertions(+), 34 deletions(-) create mode 100644 .changeset/nice-pianos-tease.md rename typescript/{cli => sdk}/src/utils/fork.ts (63%) diff --git a/.changeset/nice-pianos-tease.md b/.changeset/nice-pianos-tease.md new file mode 100644 index 0000000000..6c8fafbf1f --- /dev/null +++ b/.changeset/nice-pianos-tease.md @@ -0,0 +1,6 @@ +--- +'@hyperlane-xyz/cli': minor +'@hyperlane-xyz/sdk': minor +--- + +Migrate fork util from CLI to SDK. Anvil IP & Port are now optionally passed into fork util by client. diff --git a/typescript/cli/src/deploy/dry-run.ts b/typescript/cli/src/deploy/dry-run.ts index be2663cde9..6da1d78c66 100644 --- a/typescript/cli/src/deploy/dry-run.ts +++ b/typescript/cli/src/deploy/dry-run.ts @@ -1,13 +1,14 @@ -import { MultiProvider } from '@hyperlane-xyz/sdk'; - -import { Command } from '../commands/deploy.js'; -import { logGray, logGreen, warnYellow } from '../logger.js'; import { ANVIL_RPC_METHODS, + MultiProvider, getLocalProvider, resetFork, setFork, -} from '../utils/fork.js'; +} from '@hyperlane-xyz/sdk'; + +import { Command } from '../commands/deploy.js'; +import { logGray, logGreen, warnYellow } from '../logger.js'; +import { ENV } from '../utils/env.js'; import { toUpperCamelCase } from './utils.js'; @@ -33,7 +34,7 @@ export async function forkNetworkToMultiProvider( export async function verifyAnvil() { logGray('🔎 Verifying anvil node is running...'); - const provider = getLocalProvider(); + const provider = getLocalProvider(ENV.ANVIL_IP_ADDR, ENV.ANVIL_PORT); try { await provider.send(ANVIL_RPC_METHODS.NODE_INFO, []); } catch (error: any) { diff --git a/typescript/cli/src/deploy/utils.ts b/typescript/cli/src/deploy/utils.ts index 0e1a6e2973..5a41a39b0c 100644 --- a/typescript/cli/src/deploy/utils.ts +++ b/typescript/cli/src/deploy/utils.ts @@ -6,6 +6,7 @@ import { IsmConfig, MultiProvider, MultisigConfig, + getLocalProvider, } from '@hyperlane-xyz/sdk'; import { Address, ProtocolType } from '@hyperlane-xyz/utils'; @@ -13,7 +14,7 @@ import { Command } from '../commands/deploy.js'; import { parseIsmConfig } from '../config/ism.js'; import { log, logGreen, logPink } from '../logger.js'; import { assertGasBalances } from '../utils/balances.js'; -import { getLocalProvider } from '../utils/fork.js'; +import { ENV } from '../utils/env.js'; import { assertSigner } from '../utils/keys.js'; import { completeDryRun } from './dry-run.js'; @@ -111,7 +112,7 @@ export async function prepareDeploy( await Promise.all( chains.map(async (chain: ChainName) => { const provider = dryRun - ? getLocalProvider() + ? getLocalProvider(ENV.ANVIL_IP_ADDR, ENV.ANVIL_PORT) : multiProvider.getProvider(chain); const currentBalance = await provider.getBalance(userAddress); initialBalances[chain] = currentBalance; @@ -131,7 +132,7 @@ export async function completeDeploy( if (chains.length > 0) logPink(`⛽️ Gas Usage Statistics`); for (const chain of chains) { const provider = dryRun - ? getLocalProvider() + ? getLocalProvider(ENV.ANVIL_IP_ADDR, ENV.ANVIL_PORT) : multiProvider.getProvider(chain); const currentBalance = await provider.getBalance(userAddress); const balanceDelta = initialBalances[chain].sub(currentBalance); diff --git a/typescript/cli/src/utils/keys.ts b/typescript/cli/src/utils/keys.ts index 37721917ba..7f5b6f6b05 100644 --- a/typescript/cli/src/utils/keys.ts +++ b/typescript/cli/src/utils/keys.ts @@ -1,12 +1,11 @@ import { input } from '@inquirer/prompts'; import { ethers, providers } from 'ethers'; +import { impersonateAccount } from '@hyperlane-xyz/sdk'; import { Address, ensure0x } from '@hyperlane-xyz/utils'; import { ContextSettings, KeyConfig } from '../context.js'; -import { impersonateAccount } from './fork.js'; - const ETHEREUM_ADDRESS_LENGTH = 42; const DEFAULT_KEY_TYPE = 'private key'; const IMPERSONATED_KEY_TYPE = 'address'; diff --git a/typescript/sdk/src/index.ts b/typescript/sdk/src/index.ts index 45b2f9d49e..869b63d5af 100644 --- a/typescript/sdk/src/index.ts +++ b/typescript/sdk/src/index.ts @@ -442,6 +442,14 @@ export { } from './types.js'; export { MultiGeneric } from './utils/MultiGeneric.js'; export { filterByChains } from './utils/filter.js'; +export { + ANVIL_RPC_METHODS, + resetFork, + setFork, + impersonateAccount, + stopImpersonatingAccount, + getLocalProvider, +} from './utils/fork.js'; export { multisigIsmVerificationCost } from './utils/ism.js'; export { SealevelAccountDataWrapper, diff --git a/typescript/cli/src/utils/fork.ts b/typescript/sdk/src/utils/fork.ts similarity index 63% rename from typescript/cli/src/utils/fork.ts rename to typescript/sdk/src/utils/fork.ts index 49979a9114..38660a6c50 100644 --- a/typescript/cli/src/utils/fork.ts +++ b/typescript/sdk/src/utils/fork.ts @@ -1,12 +1,11 @@ import { providers } from 'ethers'; -import { ChainName, MultiProvider } from '@hyperlane-xyz/sdk'; -import { Address, isValidAddressEvm } from '@hyperlane-xyz/utils'; +import { Address, isValidAddressEvm, rootLogger } from '@hyperlane-xyz/utils'; -import { logGray, logGreen } from '../logger.js'; -import { warnYellow } from '../logger.js'; +import { MultiProvider } from '../providers/MultiProvider.js'; +import { ChainName } from '../types.js'; -import { ENV } from './env.js'; +const logger = rootLogger.child({ module: 'fork-utils' }); const ENDPOINT_PREFIX = 'http'; const DEFAULT_ANVIL_ENDPOINT = 'http://127.0.0.1:8545'; @@ -19,12 +18,12 @@ export enum ANVIL_RPC_METHODS { } /** - * Resets the local node to it's original start (anvil [31337] at block zero). + * Resets the local node to it's original state (anvil [31337] at block zero). */ -export const resetFork = async () => { - logGray(`Resetting forked network...`); +export const resetFork = async (anvilIPAddr?: string, anvilPort?: number) => { + logger.info(`Resetting forked network...`); - const provider = getLocalProvider(); + const provider = getLocalProvider(anvilIPAddr, anvilPort); await provider.send(ANVIL_RPC_METHODS.RESET, [ { forking: { @@ -33,7 +32,7 @@ export const resetFork = async () => { }, ]); - logGreen(`✅ Successfully reset forked network`); + logger.info(`✅ Successfully reset forked network`); }; /** @@ -44,10 +43,12 @@ export const resetFork = async () => { export const setFork = async ( multiProvider: MultiProvider, chain: ChainName | number, + anvilIPAddr?: string, + anvilPort?: number, ) => { - logGray(`Forking ${chain} for dry-run...`); + logger.info(`Forking ${chain} for dry-run...`); - const provider = getLocalProvider(); + const provider = getLocalProvider(anvilIPAddr, anvilPort); const currentChainMetadata = multiProvider.metadata[chain]; await provider.send(ANVIL_RPC_METHODS.RESET, [ @@ -60,7 +61,7 @@ export const setFork = async ( multiProvider.setProvider(chain, provider); - logGreen(`✅ Successfully forked ${chain} for dry-run`); + logger.info(`✅ Successfully forked ${chain} for dry-run`); }; /** @@ -70,13 +71,15 @@ export const setFork = async ( */ export const impersonateAccount = async ( address: Address, + anvilIPAddr?: string, + anvilPort?: number, ): Promise => { - logGray(`Impersonating account (${address})...`); + logger.info(`Impersonating account (${address})...`); - const provider = getLocalProvider(); + const provider = getLocalProvider(anvilIPAddr, anvilPort); await provider.send(ANVIL_RPC_METHODS.IMPERSONATE_ACCOUNT, [address]); - logGreen(`✅ Successfully impersonated account (${address})`); + logger.info(`✅ Successfully impersonated account (${address})`); return provider.getSigner(address); }; @@ -85,20 +88,24 @@ export const impersonateAccount = async ( * Stops account impersonation. * @param address the address to stop impersonating */ -export const stopImpersonatingAccount = async (address: Address) => { - logGray(`Stopping account impersonation for address (${address})...`); +export const stopImpersonatingAccount = async ( + address: Address, + anvilIPAddr?: string, + anvilPort?: number, +) => { + logger.info(`Stopping account impersonation for address (${address})...`); if (isValidAddressEvm(address)) throw new Error( `Cannot stop account impersonation: invalid address format: ${address}`, ); - const provider = getLocalProvider(); + const provider = getLocalProvider(anvilIPAddr, anvilPort); await provider.send(ANVIL_RPC_METHODS.STOP_IMPERSONATING_ACCOUNT, [ address.substring(2), ]); - logGreen( + logger.info( `✅ Successfully stopped account impersonation for address (${address})`, ); }; @@ -109,14 +116,16 @@ export const stopImpersonatingAccount = async (address: Address) => { * @returns a local JSON-RPC provider */ export const getLocalProvider = ( + anvilIPAddr?: string, + anvilPort?: number, urlOverride?: string, ): providers.JsonRpcProvider => { let envUrl; - if (ENV.ANVIL_IP_ADDR && ENV.ANVIL_PORT) - envUrl = `${ENDPOINT_PREFIX}${ENV.ANVIL_IP_ADDR}:${ENV.ANVIL_PORT}`; + if (anvilIPAddr && anvilPort) + envUrl = `${ENDPOINT_PREFIX}${anvilIPAddr}:${anvilPort}`; if (urlOverride && !urlOverride.startsWith(ENDPOINT_PREFIX)) { - warnYellow( + logger.warn( `⚠️ Provided URL override (${urlOverride}) does not begin with ${ENDPOINT_PREFIX}. Defaulting to ${ envUrl ?? DEFAULT_ANVIL_ENDPOINT }`, From 2e439423e743694226e877fe3c63d664684083d2 Mon Sep 17 00:00:00 2001 From: Nam Chu Hoai Date: Mon, 22 Apr 2024 14:26:54 -0400 Subject: [PATCH 10/16] Allow gasLimit overrides in the SDK/CLI for deploy txs (#3622) ### Description Small PR to actually allow overrides of gasLimit --------- Co-authored-by: Yorke Rhodes --- .changeset/khaki-days-float.md | 5 +++++ typescript/sdk/src/providers/MultiProvider.ts | 6 ++++-- 2 files changed, 9 insertions(+), 2 deletions(-) create mode 100644 .changeset/khaki-days-float.md diff --git a/.changeset/khaki-days-float.md b/.changeset/khaki-days-float.md new file mode 100644 index 0000000000..0c98ce9582 --- /dev/null +++ b/.changeset/khaki-days-float.md @@ -0,0 +1,5 @@ +--- +"@hyperlane-xyz/sdk": patch +--- + +Allow gasLimit overrides in the SDK/CLI for deploy txs diff --git a/typescript/sdk/src/providers/MultiProvider.ts b/typescript/sdk/src/providers/MultiProvider.ts index 572cf929a2..219a73f5c9 100644 --- a/typescript/sdk/src/providers/MultiProvider.ts +++ b/typescript/sdk/src/providers/MultiProvider.ts @@ -302,15 +302,17 @@ export class MultiProvider extends ChainMetadataManager { const contractFactory = await factory.connect(signer); // estimate gas - const deployTx = contractFactory.getDeployTransaction(...params, overrides); + const deployTx = contractFactory.getDeployTransaction(...params); const gasEstimated = await signer.estimateGas(deployTx); // deploy with 10% buffer on gas limit const contract = await contractFactory.deploy(...params, { - ...overrides, gasLimit: gasEstimated.add(gasEstimated.div(10)), // 10% buffer + ...overrides, }); + this.logger.trace({ transaction: deployTx }, `Deploying contract`); + // wait for deploy tx to be confirmed await this.handleTx(chainNameOrId, contract.deployTransaction); From f2cb6ebc1b75612cb22b5135dd0ad1f133b3a197 Mon Sep 17 00:00:00 2001 From: Daniel Savu <23065004+daniel-savu@users.noreply.github.com> Date: Tue, 23 Apr 2024 11:42:45 +0100 Subject: [PATCH 11/16] refactor: organize files in `hyperlane-ethereum` (#3633) ### Description Some cleanup along my way to integrating with `Multicall3` in hyp-ethereum. - Categorizes most files from `src` into `ism`, `contracts`, `signer` modules - Renames the previous `contracts` dir (that held the abi interfaces) to `interfaces`, so we can use `contracts` for the actual contracts (e.g. mailbox, igp) --- rust/chains/hyperlane-ethereum/.gitignore | 2 +- rust/chains/hyperlane-ethereum/build.rs | 2 +- .../src/{ => contracts}/interchain_gas.rs | 7 +-- .../src/{ => contracts}/mailbox.rs | 13 ++-- .../src/{ => contracts}/merkle_tree_hook.rs | 5 +- .../hyperlane-ethereum/src/contracts/mod.rs | 9 +++ .../src/{ => contracts}/validator_announce.rs | 7 +-- .../src/{ => ism}/aggregation_ism.rs | 7 +-- .../src/{ => ism}/ccip_read_ism.rs | 7 +-- .../{ => ism}/interchain_security_module.rs | 7 +-- rust/chains/hyperlane-ethereum/src/ism/mod.rs | 10 ++++ .../src/{ => ism}/multisig_ism.rs | 7 +-- .../src/{ => ism}/routing_ism.rs | 9 +-- rust/chains/hyperlane-ethereum/src/lib.rs | 60 ++----------------- .../hyperlane-ethereum/src/rpc_clients/mod.rs | 4 +- .../src/{ => rpc_clients}/provider.rs | 0 .../src/{ => rpc_clients}/trait_builder.rs | 4 +- .../src/{signers.rs => signer/mod.rs} | 5 +- .../singleton.rs} | 0 19 files changed, 67 insertions(+), 98 deletions(-) rename rust/chains/hyperlane-ethereum/src/{ => contracts}/interchain_gas.rs (96%) rename rust/chains/hyperlane-ethereum/src/{ => contracts}/mailbox.rs (97%) rename rust/chains/hyperlane-ethereum/src/{ => contracts}/merkle_tree_hook.rs (97%) create mode 100644 rust/chains/hyperlane-ethereum/src/contracts/mod.rs rename rust/chains/hyperlane-ethereum/src/{ => contracts}/validator_announce.rs (96%) rename rust/chains/hyperlane-ethereum/src/{ => ism}/aggregation_ism.rs (93%) rename rust/chains/hyperlane-ethereum/src/{ => ism}/ccip_read_ism.rs (93%) rename rust/chains/hyperlane-ethereum/src/{ => ism}/interchain_security_module.rs (94%) create mode 100644 rust/chains/hyperlane-ethereum/src/ism/mod.rs rename rust/chains/hyperlane-ethereum/src/{ => ism}/multisig_ism.rs (94%) rename rust/chains/hyperlane-ethereum/src/{ => ism}/routing_ism.rs (91%) rename rust/chains/hyperlane-ethereum/src/{ => rpc_clients}/provider.rs (100%) rename rust/chains/hyperlane-ethereum/src/{ => rpc_clients}/trait_builder.rs (98%) rename rust/chains/hyperlane-ethereum/src/{signers.rs => signer/mod.rs} (98%) rename rust/chains/hyperlane-ethereum/src/{singleton_signer.rs => signer/singleton.rs} (100%) diff --git a/rust/chains/hyperlane-ethereum/.gitignore b/rust/chains/hyperlane-ethereum/.gitignore index 7040d337ab..87b67b9b1f 100644 --- a/rust/chains/hyperlane-ethereum/.gitignore +++ b/rust/chains/hyperlane-ethereum/.gitignore @@ -1 +1 @@ -src/contracts \ No newline at end of file +src/interfaces \ No newline at end of file diff --git a/rust/chains/hyperlane-ethereum/build.rs b/rust/chains/hyperlane-ethereum/build.rs index 7f51f3a29c..d1b3fe9607 100644 --- a/rust/chains/hyperlane-ethereum/build.rs +++ b/rust/chains/hyperlane-ethereum/build.rs @@ -1,3 +1,3 @@ fn main() { - abigen::generate_bindings_for_dir("./abis", "./src/contracts", abigen::BuildType::Ethers); + abigen::generate_bindings_for_dir("./abis", "./src/interfaces", abigen::BuildType::Ethers); } diff --git a/rust/chains/hyperlane-ethereum/src/interchain_gas.rs b/rust/chains/hyperlane-ethereum/src/contracts/interchain_gas.rs similarity index 96% rename from rust/chains/hyperlane-ethereum/src/interchain_gas.rs rename to rust/chains/hyperlane-ethereum/src/contracts/interchain_gas.rs index eb19e7def4..c51e8d0ef3 100644 --- a/rust/chains/hyperlane-ethereum/src/interchain_gas.rs +++ b/rust/chains/hyperlane-ethereum/src/contracts/interchain_gas.rs @@ -14,11 +14,10 @@ use hyperlane_core::{ }; use tracing::instrument; -use crate::contracts::i_interchain_gas_paymaster::{ +use crate::interfaces::i_interchain_gas_paymaster::{ IInterchainGasPaymaster as EthereumInterchainGasPaymasterInternal, IINTERCHAINGASPAYMASTER_ABI, }; -use crate::trait_builder::BuildableWithProvider; -use crate::{ConnectionConf, EthereumProvider}; +use crate::{BuildableWithProvider, ConnectionConf, EthereumProvider}; impl Display for EthereumInterchainGasPaymasterInternal where @@ -224,6 +223,6 @@ impl HyperlaneAbi for EthereumInterchainGasPaymasterAbi { const SELECTOR_SIZE_BYTES: usize = 4; fn fn_map() -> HashMap, &'static str> { - super::extract_fn_map(&IINTERCHAINGASPAYMASTER_ABI) + crate::extract_fn_map(&IINTERCHAINGASPAYMASTER_ABI) } } diff --git a/rust/chains/hyperlane-ethereum/src/mailbox.rs b/rust/chains/hyperlane-ethereum/src/contracts/mailbox.rs similarity index 97% rename from rust/chains/hyperlane-ethereum/src/mailbox.rs rename to rust/chains/hyperlane-ethereum/src/contracts/mailbox.rs index dab1424b34..3b030fbd32 100644 --- a/rust/chains/hyperlane-ethereum/src/mailbox.rs +++ b/rust/chains/hyperlane-ethereum/src/contracts/mailbox.rs @@ -19,11 +19,12 @@ use hyperlane_core::{ TxCostEstimate, TxOutcome, H160, H256, U256, }; -use crate::contracts::arbitrum_node_interface::ArbitrumNodeInterface; -use crate::contracts::i_mailbox::{IMailbox as EthereumMailboxInternal, ProcessCall, IMAILBOX_ABI}; -use crate::trait_builder::BuildableWithProvider; +use crate::interfaces::arbitrum_node_interface::ArbitrumNodeInterface; +use crate::interfaces::i_mailbox::{ + IMailbox as EthereumMailboxInternal, ProcessCall, IMAILBOX_ABI, +}; use crate::tx::{call_with_lag, fill_tx_gas_params, report_tx}; -use crate::{ConnectionConf, EthereumProvider, TransactionOverrides}; +use crate::{BuildableWithProvider, ConnectionConf, EthereumProvider, TransactionOverrides}; impl std::fmt::Display for EthereumMailboxInternal where @@ -420,7 +421,7 @@ impl HyperlaneAbi for EthereumMailboxAbi { const SELECTOR_SIZE_BYTES: usize = 4; fn fn_map() -> HashMap, &'static str> { - super::extract_fn_map(&IMAILBOX_ABI) + crate::extract_fn_map(&IMAILBOX_ABI) } } @@ -438,7 +439,7 @@ mod test { TxCostEstimate, H160, H256, U256, }; - use crate::{ConnectionConf, EthereumMailbox, RpcConnectionConf}; + use crate::{contracts::EthereumMailbox, ConnectionConf, RpcConnectionConf}; /// An amount of gas to add to the estimated gas const GAS_ESTIMATE_BUFFER: u32 = 50000; diff --git a/rust/chains/hyperlane-ethereum/src/merkle_tree_hook.rs b/rust/chains/hyperlane-ethereum/src/contracts/merkle_tree_hook.rs similarity index 97% rename from rust/chains/hyperlane-ethereum/src/merkle_tree_hook.rs rename to rust/chains/hyperlane-ethereum/src/contracts/merkle_tree_hook.rs index a39b07018a..f920c28ccc 100644 --- a/rust/chains/hyperlane-ethereum/src/merkle_tree_hook.rs +++ b/rust/chains/hyperlane-ethereum/src/contracts/merkle_tree_hook.rs @@ -14,10 +14,9 @@ use hyperlane_core::{ MerkleTreeInsertion, SequenceAwareIndexer, H256, }; -use crate::contracts::merkle_tree_hook::{MerkleTreeHook as MerkleTreeHookContract, Tree}; -use crate::trait_builder::BuildableWithProvider; +use crate::interfaces::merkle_tree_hook::{MerkleTreeHook as MerkleTreeHookContract, Tree}; use crate::tx::call_with_lag; -use crate::{ConnectionConf, EthereumProvider}; +use crate::{BuildableWithProvider, ConnectionConf, EthereumProvider}; // We don't need the reverse of this impl, so it's ok to disable the clippy lint #[allow(clippy::from_over_into)] diff --git a/rust/chains/hyperlane-ethereum/src/contracts/mod.rs b/rust/chains/hyperlane-ethereum/src/contracts/mod.rs new file mode 100644 index 0000000000..2b85733f69 --- /dev/null +++ b/rust/chains/hyperlane-ethereum/src/contracts/mod.rs @@ -0,0 +1,9 @@ +pub use {interchain_gas::*, mailbox::*, merkle_tree_hook::*, validator_announce::*}; + +mod interchain_gas; + +mod mailbox; + +mod merkle_tree_hook; + +mod validator_announce; diff --git a/rust/chains/hyperlane-ethereum/src/validator_announce.rs b/rust/chains/hyperlane-ethereum/src/contracts/validator_announce.rs similarity index 96% rename from rust/chains/hyperlane-ethereum/src/validator_announce.rs rename to rust/chains/hyperlane-ethereum/src/contracts/validator_announce.rs index b4c93e078f..2d9fa3f68d 100644 --- a/rust/chains/hyperlane-ethereum/src/validator_announce.rs +++ b/rust/chains/hyperlane-ethereum/src/contracts/validator_announce.rs @@ -13,12 +13,11 @@ use hyperlane_core::{ use tracing::{instrument, log::trace}; use crate::{ - contracts::i_validator_announce::{ + interfaces::i_validator_announce::{ IValidatorAnnounce as EthereumValidatorAnnounceInternal, IVALIDATORANNOUNCE_ABI, }, - trait_builder::BuildableWithProvider, tx::{fill_tx_gas_params, report_tx}, - ConnectionConf, EthereumProvider, + BuildableWithProvider, ConnectionConf, EthereumProvider, }; impl std::fmt::Display for EthereumValidatorAnnounceInternal @@ -176,6 +175,6 @@ impl HyperlaneAbi for EthereumValidatorAnnounceAbi { const SELECTOR_SIZE_BYTES: usize = 4; fn fn_map() -> HashMap, &'static str> { - super::extract_fn_map(&IVALIDATORANNOUNCE_ABI) + crate::extract_fn_map(&IVALIDATORANNOUNCE_ABI) } } diff --git a/rust/chains/hyperlane-ethereum/src/aggregation_ism.rs b/rust/chains/hyperlane-ethereum/src/ism/aggregation_ism.rs similarity index 93% rename from rust/chains/hyperlane-ethereum/src/aggregation_ism.rs rename to rust/chains/hyperlane-ethereum/src/ism/aggregation_ism.rs index 3cfcf1b3a4..56e2bd7228 100644 --- a/rust/chains/hyperlane-ethereum/src/aggregation_ism.rs +++ b/rust/chains/hyperlane-ethereum/src/ism/aggregation_ism.rs @@ -13,11 +13,10 @@ use hyperlane_core::{ HyperlaneDomain, HyperlaneMessage, HyperlaneProvider, RawHyperlaneMessage, H256, }; -use crate::contracts::i_aggregation_ism::{ +use crate::interfaces::i_aggregation_ism::{ IAggregationIsm as EthereumAggregationIsmInternal, IAGGREGATIONISM_ABI, }; -use crate::trait_builder::BuildableWithProvider; -use crate::{ConnectionConf, EthereumProvider}; +use crate::{BuildableWithProvider, ConnectionConf, EthereumProvider}; pub struct AggregationIsmBuilder {} @@ -113,6 +112,6 @@ impl HyperlaneAbi for EthereumAggregationIsmAbi { const SELECTOR_SIZE_BYTES: usize = 4; fn fn_map() -> HashMap, &'static str> { - super::extract_fn_map(&IAGGREGATIONISM_ABI) + crate::extract_fn_map(&IAGGREGATIONISM_ABI) } } diff --git a/rust/chains/hyperlane-ethereum/src/ccip_read_ism.rs b/rust/chains/hyperlane-ethereum/src/ism/ccip_read_ism.rs similarity index 93% rename from rust/chains/hyperlane-ethereum/src/ccip_read_ism.rs rename to rust/chains/hyperlane-ethereum/src/ism/ccip_read_ism.rs index 82845fac58..682def774f 100644 --- a/rust/chains/hyperlane-ethereum/src/ccip_read_ism.rs +++ b/rust/chains/hyperlane-ethereum/src/ism/ccip_read_ism.rs @@ -13,11 +13,10 @@ use hyperlane_core::{ HyperlaneDomain, HyperlaneProvider, H256, }; -pub use crate::contracts::i_ccip_read_ism::{ +pub use crate::interfaces::i_ccip_read_ism::{ ICcipReadIsm as EthereumCcipReadIsmInternal, OffchainLookup, ICCIPREADISM_ABI, }; -use crate::trait_builder::BuildableWithProvider; -use crate::{ConnectionConf, EthereumProvider}; +use crate::{BuildableWithProvider, ConnectionConf, EthereumProvider}; pub struct CcipReadIsmBuilder {} @@ -105,6 +104,6 @@ impl HyperlaneAbi for EthereumCcipReadIsmAbi { const SELECTOR_SIZE_BYTES: usize = 4; fn fn_map() -> HashMap, &'static str> { - super::extract_fn_map(&ICCIPREADISM_ABI) + crate::extract_fn_map(&ICCIPREADISM_ABI) } } diff --git a/rust/chains/hyperlane-ethereum/src/interchain_security_module.rs b/rust/chains/hyperlane-ethereum/src/ism/interchain_security_module.rs similarity index 94% rename from rust/chains/hyperlane-ethereum/src/interchain_security_module.rs rename to rust/chains/hyperlane-ethereum/src/ism/interchain_security_module.rs index e477502172..614b85547c 100644 --- a/rust/chains/hyperlane-ethereum/src/interchain_security_module.rs +++ b/rust/chains/hyperlane-ethereum/src/ism/interchain_security_module.rs @@ -16,12 +16,11 @@ use hyperlane_core::{ }; use num_traits::cast::FromPrimitive; -use crate::contracts::i_interchain_security_module::{ +use crate::interfaces::i_interchain_security_module::{ IInterchainSecurityModule as EthereumInterchainSecurityModuleInternal, IINTERCHAINSECURITYMODULE_ABI, }; -use crate::trait_builder::BuildableWithProvider; -use crate::{ConnectionConf, EthereumProvider}; +use crate::{BuildableWithProvider, ConnectionConf, EthereumProvider}; pub struct InterchainSecurityModuleBuilder {} @@ -135,6 +134,6 @@ impl HyperlaneAbi for EthereumInterchainSecurityModuleAbi { const SELECTOR_SIZE_BYTES: usize = 4; fn fn_map() -> HashMap, &'static str> { - super::extract_fn_map(&IINTERCHAINSECURITYMODULE_ABI) + crate::extract_fn_map(&IINTERCHAINSECURITYMODULE_ABI) } } diff --git a/rust/chains/hyperlane-ethereum/src/ism/mod.rs b/rust/chains/hyperlane-ethereum/src/ism/mod.rs new file mode 100644 index 0000000000..5dc146d86c --- /dev/null +++ b/rust/chains/hyperlane-ethereum/src/ism/mod.rs @@ -0,0 +1,10 @@ +pub use { + aggregation_ism::*, ccip_read_ism::*, interchain_security_module::*, multisig_ism::*, + routing_ism::*, +}; + +mod aggregation_ism; +mod ccip_read_ism; +mod interchain_security_module; +mod multisig_ism; +mod routing_ism; diff --git a/rust/chains/hyperlane-ethereum/src/multisig_ism.rs b/rust/chains/hyperlane-ethereum/src/ism/multisig_ism.rs similarity index 94% rename from rust/chains/hyperlane-ethereum/src/multisig_ism.rs rename to rust/chains/hyperlane-ethereum/src/ism/multisig_ism.rs index 9571f6fb7a..19aecf464c 100644 --- a/rust/chains/hyperlane-ethereum/src/multisig_ism.rs +++ b/rust/chains/hyperlane-ethereum/src/ism/multisig_ism.rs @@ -13,11 +13,10 @@ use hyperlane_core::{ HyperlaneMessage, HyperlaneProvider, MultisigIsm, RawHyperlaneMessage, H256, }; -use crate::contracts::i_multisig_ism::{ +use crate::interfaces::i_multisig_ism::{ IMultisigIsm as EthereumMultisigIsmInternal, IMULTISIGISM_ABI, }; -use crate::trait_builder::BuildableWithProvider; -use crate::{ConnectionConf, EthereumProvider}; +use crate::{BuildableWithProvider, ConnectionConf, EthereumProvider}; impl std::fmt::Display for EthereumMultisigIsmInternal where @@ -119,6 +118,6 @@ impl HyperlaneAbi for EthereumMultisigIsmAbi { const SELECTOR_SIZE_BYTES: usize = 4; fn fn_map() -> HashMap, &'static str> { - super::extract_fn_map(&IMULTISIGISM_ABI) + crate::extract_fn_map(&IMULTISIGISM_ABI) } } diff --git a/rust/chains/hyperlane-ethereum/src/routing_ism.rs b/rust/chains/hyperlane-ethereum/src/ism/routing_ism.rs similarity index 91% rename from rust/chains/hyperlane-ethereum/src/routing_ism.rs rename to rust/chains/hyperlane-ethereum/src/ism/routing_ism.rs index f884dcf693..23e92014ed 100644 --- a/rust/chains/hyperlane-ethereum/src/routing_ism.rs +++ b/rust/chains/hyperlane-ethereum/src/ism/routing_ism.rs @@ -13,9 +13,10 @@ use hyperlane_core::{ HyperlaneMessage, HyperlaneProvider, RawHyperlaneMessage, RoutingIsm, H256, }; -use crate::contracts::i_routing_ism::{IRoutingIsm as EthereumRoutingIsmInternal, IROUTINGISM_ABI}; -use crate::trait_builder::BuildableWithProvider; -use crate::{ConnectionConf, EthereumProvider}; +use crate::interfaces::i_routing_ism::{ + IRoutingIsm as EthereumRoutingIsmInternal, IROUTINGISM_ABI, +}; +use crate::{BuildableWithProvider, ConnectionConf, EthereumProvider}; pub struct RoutingIsmBuilder {} @@ -104,6 +105,6 @@ impl HyperlaneAbi for EthereumRoutingIsmAbi { const SELECTOR_SIZE_BYTES: usize = 4; fn fn_map() -> HashMap, &'static str> { - super::extract_fn_map(&IROUTINGISM_ABI) + crate::extract_fn_map(&IROUTINGISM_ABI) } } diff --git a/rust/chains/hyperlane-ethereum/src/lib.rs b/rust/chains/hyperlane-ethereum/src/lib.rs index 90ec70c019..bf02f4a699 100644 --- a/rust/chains/hyperlane-ethereum/src/lib.rs +++ b/rust/chains/hyperlane-ethereum/src/lib.rs @@ -8,71 +8,21 @@ use std::collections::HashMap; use ethers::abi::FunctionExt; use ethers::prelude::{abi, Lazy, Middleware}; -#[cfg(not(doctest))] -pub use self::{ - aggregation_ism::*, ccip_read_ism::*, config::*, config::*, interchain_gas::*, - interchain_gas::*, interchain_security_module::*, interchain_security_module::*, mailbox::*, - mailbox::*, merkle_tree_hook::*, multisig_ism::*, provider::*, routing_ism::*, rpc_clients::*, - signers::*, singleton_signer::*, trait_builder::*, validator_announce::*, -}; +pub use self::{config::*, contracts::*, ism::*, rpc_clients::*, signer::*}; -#[cfg(not(doctest))] mod tx; -/// Mailbox abi -#[cfg(not(doctest))] -mod mailbox; - -#[cfg(not(doctest))] -mod trait_builder; - -/// Provider abi -#[cfg(not(doctest))] -mod provider; - -/// InterchainGasPaymaster abi -#[cfg(not(doctest))] -mod interchain_gas; - -/// interchain_security_module abi -#[cfg(not(doctest))] -mod interchain_security_module; - -/// Merkle tree hook abi -#[cfg(not(doctest))] -mod merkle_tree_hook; - -/// MultisigIsm abi -#[cfg(not(doctest))] -mod multisig_ism; - -/// RoutingIsm abi -#[cfg(not(doctest))] -mod routing_ism; - -/// CcipReadIsm abi -#[cfg(not(doctest))] -mod ccip_read_ism; - -/// ValidatorAnnounce abi -#[cfg(not(doctest))] -mod validator_announce; +mod contracts; -/// AggregationIsm abi -#[cfg(not(doctest))] -mod aggregation_ism; +mod ism; /// Generated contract bindings. -#[cfg(not(doctest))] -mod contracts; +mod interfaces; /// Ethers JSONRPC Client implementations mod rpc_clients; -mod signers; - -#[cfg(not(doctest))] -mod singleton_signer; +mod signer; mod config; mod error; diff --git a/rust/chains/hyperlane-ethereum/src/rpc_clients/mod.rs b/rust/chains/hyperlane-ethereum/src/rpc_clients/mod.rs index 9a97d7b3d9..d7cdb80cd4 100644 --- a/rust/chains/hyperlane-ethereum/src/rpc_clients/mod.rs +++ b/rust/chains/hyperlane-ethereum/src/rpc_clients/mod.rs @@ -1,10 +1,12 @@ use ethers::providers::HttpClientError; use tracing::{info, trace, warn}; -pub use self::{fallback::*, retrying::*}; +pub use self::{fallback::*, provider::*, retrying::*, trait_builder::*}; mod fallback; +mod provider; mod retrying; +mod trait_builder; enum CategorizedResponse { IsOk(R), diff --git a/rust/chains/hyperlane-ethereum/src/provider.rs b/rust/chains/hyperlane-ethereum/src/rpc_clients/provider.rs similarity index 100% rename from rust/chains/hyperlane-ethereum/src/provider.rs rename to rust/chains/hyperlane-ethereum/src/rpc_clients/provider.rs diff --git a/rust/chains/hyperlane-ethereum/src/trait_builder.rs b/rust/chains/hyperlane-ethereum/src/rpc_clients/trait_builder.rs similarity index 98% rename from rust/chains/hyperlane-ethereum/src/trait_builder.rs rename to rust/chains/hyperlane-ethereum/src/rpc_clients/trait_builder.rs index e81412a8b2..04894aa496 100644 --- a/rust/chains/hyperlane-ethereum/src/trait_builder.rs +++ b/rust/chains/hyperlane-ethereum/src/rpc_clients/trait_builder.rs @@ -23,8 +23,8 @@ use hyperlane_core::{ ChainCommunicationError, ChainResult, ContractLocator, HyperlaneDomain, KnownHyperlaneDomain, }; -use crate::{signers::Signers, ConnectionConf, RetryingProvider}; -use crate::{EthereumFallbackProvider, RpcConnectionConf}; +use crate::signer::Signers; +use crate::{ConnectionConf, EthereumFallbackProvider, RetryingProvider, RpcConnectionConf}; // This should be whatever the prometheus scrape interval is const HTTP_CLIENT_TIMEOUT: Duration = Duration::from_secs(60); diff --git a/rust/chains/hyperlane-ethereum/src/signers.rs b/rust/chains/hyperlane-ethereum/src/signer/mod.rs similarity index 98% rename from rust/chains/hyperlane-ethereum/src/signers.rs rename to rust/chains/hyperlane-ethereum/src/signer/mod.rs index 7165cd1bc1..5dbac122e4 100644 --- a/rust/chains/hyperlane-ethereum/src/signers.rs +++ b/rust/chains/hyperlane-ethereum/src/signer/mod.rs @@ -8,6 +8,9 @@ use hyperlane_core::{ HyperlaneSigner, HyperlaneSignerError, Signature as HyperlaneSignature, H160, H256, }; +mod singleton; +pub use singleton::*; + /// Ethereum-supported signer types #[derive(Debug, Clone)] pub enum Signers { @@ -120,7 +123,7 @@ mod test { Checkpoint, CheckpointWithMessageId, HyperlaneSigner, HyperlaneSignerExt, H256, }; - use crate::signers::Signers; + use super::Signers; #[test] fn it_sign() { diff --git a/rust/chains/hyperlane-ethereum/src/singleton_signer.rs b/rust/chains/hyperlane-ethereum/src/signer/singleton.rs similarity index 100% rename from rust/chains/hyperlane-ethereum/src/singleton_signer.rs rename to rust/chains/hyperlane-ethereum/src/signer/singleton.rs From 6f35e4ce58a1295c368bb9d603ccc2ce04f00323 Mon Sep 17 00:00:00 2001 From: Trevor Porter Date: Wed, 24 Apr 2024 11:04:34 +0100 Subject: [PATCH 12/16] Ancient8 key funder; add inevm claim threshold (#3619) ### Description ### Drive-by changes ### Related issues ### Backward compatibility ### Testing --- typescript/infra/config/environments/mainnet3/funding.ts | 3 ++- typescript/infra/scripts/funding/fund-keys-from-deployer.ts | 2 ++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/typescript/infra/config/environments/mainnet3/funding.ts b/typescript/infra/config/environments/mainnet3/funding.ts index e1f2aab8c2..cf4d8d9d3c 100644 --- a/typescript/infra/config/environments/mainnet3/funding.ts +++ b/typescript/infra/config/environments/mainnet3/funding.ts @@ -9,7 +9,7 @@ import { environment } from './chains.js'; export const keyFunderConfig: KeyFunderConfig = { docker: { repo: 'gcr.io/abacus-labs-dev/hyperlane-monorepo', - tag: 'b0811ba-20240411-151216', + tag: '5d1391c-20240418-100607', }, // We're currently using the same deployer/key funder key as mainnet2. // To minimize nonce clobbering we offset the key funder cron @@ -41,6 +41,7 @@ export const keyFunderConfig: KeyFunderConfig = { optimism: '0.5', polygonzkevm: '0.5', scroll: '0.5', + ancient8: '0.5', }, desiredKathyBalancePerChain: { arbitrum: '0.1', diff --git a/typescript/infra/scripts/funding/fund-keys-from-deployer.ts b/typescript/infra/scripts/funding/fund-keys-from-deployer.ts index 968d7472ac..7a5364366f 100644 --- a/typescript/infra/scripts/funding/fund-keys-from-deployer.ts +++ b/typescript/infra/scripts/funding/fund-keys-from-deployer.ts @@ -107,6 +107,7 @@ const RC_FUNDING_DISCOUNT_DENOMINATOR = ethers.BigNumber.from(10); const igpClaimThresholdPerChain: ChainMap = { celo: '5', alfajores: '1', + ancient8: '0.1', avalanche: '2', fuji: '1', ethereum: '0.4', @@ -123,6 +124,7 @@ const igpClaimThresholdPerChain: ChainMap = { scroll: '0.1', polygonzkevm: '0.1', plumetestnet: '0.1', + inevm: '20', // unused test1: '0', test2: '0', From 811ecfbbafbfd117307b611f974a4fc650830bf0 Mon Sep 17 00:00:00 2001 From: Lee <6251863+ltyu@users.noreply.github.com> Date: Wed, 24 Apr 2024 11:08:56 -0400 Subject: [PATCH 13/16] Derive CoreConfig from Mailbox address (#3657) ### Description Creates a new class to derive CoreConfig from Mailbox and their respective hooks and isms ### Drive-by changes ### Related issues - Fixes #3578 ### Backward compatibility Yes ### Testing Unit Tests through CoreDeployer.hardhat-test.ts --- .changeset/afraid-dryers-grab.md | 5 ++ typescript/sdk/src/consts/crud.ts | 1 + .../sdk/src/core/CoreDeployer.hardhat-test.ts | 70 ++++++++++++++++++- typescript/sdk/src/core/read.ts | 61 ++++++++++++++++ typescript/sdk/src/hook/read.ts | 5 +- typescript/sdk/src/index.ts | 1 + typescript/sdk/src/ism/read.ts | 5 +- 7 files changed, 142 insertions(+), 6 deletions(-) create mode 100644 .changeset/afraid-dryers-grab.md create mode 100644 typescript/sdk/src/consts/crud.ts create mode 100644 typescript/sdk/src/core/read.ts diff --git a/.changeset/afraid-dryers-grab.md b/.changeset/afraid-dryers-grab.md new file mode 100644 index 0000000000..ba3d7b1cba --- /dev/null +++ b/.changeset/afraid-dryers-grab.md @@ -0,0 +1,5 @@ +--- +'@hyperlane-xyz/sdk': minor +--- + +Add EvmCoreReader, minor updates. diff --git a/typescript/sdk/src/consts/crud.ts b/typescript/sdk/src/consts/crud.ts new file mode 100644 index 0000000000..62e6c801cc --- /dev/null +++ b/typescript/sdk/src/consts/crud.ts @@ -0,0 +1 @@ +export const DEFAULT_CONTRACT_READ_CONCURRENCY = 20; diff --git a/typescript/sdk/src/core/CoreDeployer.hardhat-test.ts b/typescript/sdk/src/core/CoreDeployer.hardhat-test.ts index fb58ef0881..8062134823 100644 --- a/typescript/sdk/src/core/CoreDeployer.hardhat-test.ts +++ b/typescript/sdk/src/core/CoreDeployer.hardhat-test.ts @@ -8,7 +8,9 @@ import { objMap, promiseObjAll } from '@hyperlane-xyz/utils'; import { TestChains } from '../consts/chains.js'; import { HyperlaneContractsMap } from '../contracts/types.js'; import { HyperlaneProxyFactoryDeployer } from '../deploy/HyperlaneProxyFactoryDeployer.js'; +import { HookConfig } from '../hook/types.js'; import { HyperlaneIsmFactory } from '../ism/HyperlaneIsmFactory.js'; +import { DerivedIsmConfigWithAddress } from '../ism/read.js'; import { AggregationIsmConfig, IsmType } from '../ism/types.js'; import { MultiProvider } from '../providers/MultiProvider.js'; import { testCoreConfig } from '../test/testUtils.js'; @@ -18,6 +20,7 @@ import { HyperlaneCore } from './HyperlaneCore.js'; import { HyperlaneCoreChecker } from './HyperlaneCoreChecker.js'; import { HyperlaneCoreDeployer } from './HyperlaneCoreDeployer.js'; import { CoreFactories } from './contracts.js'; +import { EvmCoreReader } from './read.js'; import { CoreConfig } from './types.js'; describe('core', async () => { @@ -38,9 +41,7 @@ describe('core', async () => { const ismFactories = await proxyFactoryDeployer.deploy(coreConfig); ismFactory = new HyperlaneIsmFactory(ismFactories, multiProvider); deployer = new HyperlaneCoreDeployer(multiProvider, ismFactory); - }); - it('deploys', async () => { contracts = await deployer.deploy(coreConfig); core = new HyperlaneCore(contracts, multiProvider); }); @@ -120,6 +121,71 @@ describe('core', async () => { }); }); + describe('CoreConfigReader', async () => { + beforeEach(async () => { + contracts = await deployer.deploy(coreConfig); + }); + + async function deriveCoreConfig(chainName: string, mailboxAddress: string) { + return await new EvmCoreReader(multiProvider, chainName).deriveCoreConfig( + mailboxAddress, + ); + } + it('should derive defaultIsm correctly', async () => { + await promiseObjAll( + objMap(contracts, async (chainName, contract) => { + const coreConfigOnChain = await deriveCoreConfig( + chainName, + contract.mailbox.address, + ); + + // Cast because we don't expect the 'string' type + const defaultIsmOnchain = + coreConfigOnChain.defaultIsm as DerivedIsmConfigWithAddress; + const defaultIsmTest = coreConfig[chainName] + .defaultIsm as DerivedIsmConfigWithAddress; + + expect(defaultIsmOnchain.type).to.be.equal(defaultIsmTest.type); + }), + ); + }); + it('should derive defaultHook correctly', async () => { + await promiseObjAll( + objMap(contracts, async (chainName, contract) => { + const coreConfigOnChain = await deriveCoreConfig( + chainName, + contract.mailbox.address, + ); + + // Cast because we don't expect the 'string' type + const defaultHookOnchain = + coreConfigOnChain.defaultHook as HookConfig; + const defaultHookTest = coreConfig[chainName] + .defaultHook as HookConfig; + + expect(defaultHookOnchain.type).to.be.equal(defaultHookTest.type); + }), + ); + }); + it('should derive requiredHook correctly', async () => { + await promiseObjAll( + objMap(contracts, async (chainName, contract) => { + const coreConfigOnChain = await deriveCoreConfig( + chainName, + contract.mailbox.address, + ); + const requiredHookOnchain = coreConfigOnChain.requiredHook; + const requiredHookTest = coreConfig[chainName].requiredHook; + + // Test all the fields + objMap(requiredHookTest, (key, value) => { + expect(requiredHookOnchain[key]).to.be.equal(value); + }); + }), + ); + }); + }); + describe('failure modes', async () => { beforeEach(async () => { deployer = new HyperlaneCoreDeployer(multiProvider, ismFactory); diff --git a/typescript/sdk/src/core/read.ts b/typescript/sdk/src/core/read.ts new file mode 100644 index 0000000000..31b1291a38 --- /dev/null +++ b/typescript/sdk/src/core/read.ts @@ -0,0 +1,61 @@ +import { providers } from 'ethers'; + +import { Mailbox__factory } from '@hyperlane-xyz/core'; +import { Address, objMap, promiseObjAll } from '@hyperlane-xyz/utils'; + +import { DEFAULT_CONTRACT_READ_CONCURRENCY } from '../consts/crud.js'; +import { EvmHookReader } from '../hook/read.js'; +import { EvmIsmReader } from '../ism/read.js'; +import { MultiProvider } from '../providers/MultiProvider.js'; +import { ChainName } from '../types.js'; + +import { CoreConfig } from './types.js'; + +interface CoreReader { + deriveCoreConfig(address: Address): Promise; +} + +export class EvmCoreReader implements CoreReader { + provider: providers.Provider; + evmHookReader: EvmHookReader; + evmIsmReader: EvmIsmReader; + constructor( + protected readonly multiProvider: MultiProvider, + protected readonly chain: ChainName, + protected readonly concurrency: number = DEFAULT_CONTRACT_READ_CONCURRENCY, + ) { + this.provider = this.multiProvider.getProvider(chain); + this.evmHookReader = new EvmHookReader(multiProvider, chain, concurrency); + this.evmIsmReader = new EvmIsmReader(multiProvider, chain, concurrency); + } + + /** + * Derives the core configuration for a given Mailbox address. + * + * @param address - The address of the Mailbox contract. + * @returns A promise that resolves to the CoreConfig object, containing the owner, default ISM, default Hook, and required Hook configurations. + */ + async deriveCoreConfig(address: Address): Promise { + const mailbox = Mailbox__factory.connect(address, this.provider); + const [defaultIsm, defaultHook, requiredHook] = await Promise.all([ + mailbox.defaultIsm(), + mailbox.defaultHook(), + mailbox.requiredHook(), + ]); + + // Parallelize each configuration request + const results = await promiseObjAll( + objMap( + { + owner: mailbox.owner(), + defaultIsm: this.evmIsmReader.deriveIsmConfig(defaultIsm), + defaultHook: this.evmHookReader.deriveHookConfig(defaultHook), + requiredHook: this.evmHookReader.deriveHookConfig(requiredHook), + }, + async (_, readerCall) => readerCall, + ), + ); + + return results as CoreConfig; + } +} diff --git a/typescript/sdk/src/hook/read.ts b/typescript/sdk/src/hook/read.ts index 2a5850e322..a53e14a9e5 100644 --- a/typescript/sdk/src/hook/read.ts +++ b/typescript/sdk/src/hook/read.ts @@ -24,6 +24,7 @@ import { rootLogger, } from '@hyperlane-xyz/utils'; +import { DEFAULT_CONTRACT_READ_CONCURRENCY } from '../consts/crud.js'; import { MultiProvider } from '../providers/MultiProvider.js'; import { ChainName } from '../types.js'; @@ -74,8 +75,8 @@ export class EvmHookReader implements HookReader { constructor( protected readonly multiProvider: MultiProvider, - chain: ChainName, - protected readonly concurrency: number = 20, + protected readonly chain: ChainName, + protected readonly concurrency: number = DEFAULT_CONTRACT_READ_CONCURRENCY, ) { this.provider = this.multiProvider.getProvider(chain); } diff --git a/typescript/sdk/src/index.ts b/typescript/sdk/src/index.ts index 869b63d5af..8b4db7aa75 100644 --- a/typescript/sdk/src/index.ts +++ b/typescript/sdk/src/index.ts @@ -132,6 +132,7 @@ export { } from './gas/types.js'; export { HyperlaneHookDeployer } from './hook/HyperlaneHookDeployer.js'; export { EvmHookReader } from './hook/read.js'; +export { EvmCoreReader } from './core/read.js'; export { AggregationHookConfig, DomainRoutingHookConfig, diff --git a/typescript/sdk/src/ism/read.ts b/typescript/sdk/src/ism/read.ts index 81f2d0bc7b..8ab38b18aa 100644 --- a/typescript/sdk/src/ism/read.ts +++ b/typescript/sdk/src/ism/read.ts @@ -19,6 +19,7 @@ import { rootLogger, } from '@hyperlane-xyz/utils'; +import { DEFAULT_CONTRACT_READ_CONCURRENCY } from '../consts/crud.js'; import { MultiProvider } from '../providers/MultiProvider.js'; import { ChainName } from '../types.js'; @@ -63,8 +64,8 @@ export class EvmIsmReader implements IsmReader { constructor( protected readonly multiProvider: MultiProvider, - chain: ChainName, - protected readonly concurrency: number = 20, + protected readonly chain: ChainName, + protected readonly concurrency: number = DEFAULT_CONTRACT_READ_CONCURRENCY, ) { this.provider = this.multiProvider.getProvider(chain); } From f8b6ea467a169044257fb1247688b55ea6dbc78f Mon Sep 17 00:00:00 2001 From: Lee <6251863+ltyu@users.noreply.github.com> Date: Wed, 24 Apr 2024 16:22:37 -0400 Subject: [PATCH 14/16] CLI warp route deploys do not support ISM configuration (#3611) ### Description This PR fixes multiple related issues (see Related issues). The primary changes are 1) Update the warp-route-deployment.yaml to a more sensible [schema](https://github.com/hyperlane-xyz/hyperlane-monorepo/blob/75d590eff85d03b7a8bf408838bd9e93aac15134/typescript/cli/examples/fork/warp-route-deployment.yaml). This schema _sets_ us up to allow multi-chain collateral deployments 2) Use zod to define and validate schemas 3) Removes [intermediary config objects](https://github.com/hyperlane-xyz/hyperlane-monorepo/blob/6c42a6458dd3bfe0dc542833c38e5f959be316ab/typescript/cli/src/deploy/warp.ts#L176-L214), and completely rely on warp config file ### Drive-by changes - Updates dry run to allow a user to specify what chain to do a dry run on: `hyperlane deploy warp -d sepolia` ### Related issues - Fixes #3479 - Fixes #3135 - Fixes #3188 ### Backward compatibility **Not backwards compatible, warp route schema has changed** ### Testing Manual - used `sh ci-test.sh pi_with_core_chain` to test out create ERC20, ERC721, CollateralVault, Native warp configs - used `sh ci-test.sh pi_with_core_chain` to test out deploy ERC20, ERC721, CollateralVault, Native warp configs Unit Tests - Unit tests added to test out some business logic related to the schema fields --- .changeset/blue-eyes-hunt.md | 6 + typescript/cli/ci-test.sh | 6 +- .../dry-run/warp-route-deployment.yaml | 7 +- .../examples/fork/warp-route-deployment.yaml | 26 ++- .../cli/examples/warp-route-deployment.yaml | 27 ++- typescript/cli/src/commands/deploy.ts | 4 +- typescript/cli/src/commands/options.ts | 5 +- typescript/cli/src/config/warp.ts | 97 +++------- typescript/cli/src/deploy/core.ts | 6 +- typescript/cli/src/deploy/dry-run.ts | 4 +- typescript/cli/src/deploy/utils.ts | 2 +- typescript/cli/src/deploy/warp.ts | 178 ++++++++---------- typescript/cli/src/tests/deployTestErc20.ts | 12 +- typescript/cli/src/utils/files.ts | 2 +- typescript/sdk/src/core/HyperlaneCore.ts | 11 +- typescript/sdk/src/deploy/schemas.ts | 9 + typescript/sdk/src/deploy/types.ts | 12 +- typescript/sdk/src/index.ts | 10 + typescript/sdk/src/ism/schemas.test.ts | 21 +++ typescript/sdk/src/ism/schemas.ts | 80 ++++++++ .../sdk/src/middleware/account/schemas.ts | 12 ++ typescript/sdk/src/router/schemas.ts | 21 +++ typescript/sdk/src/router/types.ts | 23 +-- typescript/sdk/src/token/config.ts | 7 +- .../sdk/src/token/deploy.hardhat-test.ts | 8 +- typescript/sdk/src/token/schemas.test.ts | 93 +++++++++ typescript/sdk/src/token/schemas.ts | 74 ++++++++ typescript/sdk/src/token/types.ts | 9 + 28 files changed, 533 insertions(+), 239 deletions(-) create mode 100644 .changeset/blue-eyes-hunt.md create mode 100644 typescript/sdk/src/deploy/schemas.ts create mode 100644 typescript/sdk/src/ism/schemas.test.ts create mode 100644 typescript/sdk/src/ism/schemas.ts create mode 100644 typescript/sdk/src/middleware/account/schemas.ts create mode 100644 typescript/sdk/src/router/schemas.ts create mode 100644 typescript/sdk/src/token/schemas.test.ts create mode 100644 typescript/sdk/src/token/schemas.ts create mode 100644 typescript/sdk/src/token/types.ts diff --git a/.changeset/blue-eyes-hunt.md b/.changeset/blue-eyes-hunt.md new file mode 100644 index 0000000000..f1fd110ecf --- /dev/null +++ b/.changeset/blue-eyes-hunt.md @@ -0,0 +1,6 @@ +--- +'@hyperlane-xyz/cli': minor +'@hyperlane-xyz/sdk': minor +--- + +Update the warp-route-deployment.yaml to a more sensible schema. This schema sets us up to allow multi-chain collateral deployments. Removes intermediary config objects by using zod instead. diff --git a/typescript/cli/ci-test.sh b/typescript/cli/ci-test.sh index 987862cfee..27a31f23aa 100755 --- a/typescript/cli/ci-test.sh +++ b/typescript/cli/ci-test.sh @@ -132,7 +132,8 @@ run_hyperlane_deploy_core_dry_run() { BEFORE_CORE_DRY_RUN=$(cast balance $DEPLOYER --rpc-url http://127.0.0.1:${CHAIN1_PORT}); echo -e "\nDry-running contract deployments to Alfajores" - yarn workspace @hyperlane-xyz/cli run hyperlane deploy core --dry-run \ + yarn workspace @hyperlane-xyz/cli run hyperlane deploy core \ + --dry-run alfajores \ --targets alfajores \ --chains ${EXAMPLES_PATH}/dry-run/anvil-chains.yaml \ --artifacts /tmp/empty-artifacts.json \ @@ -163,7 +164,8 @@ run_hyperlane_deploy_warp_dry_run() { BEFORE_WARP_DRY_RUN=$(cast balance $DEPLOYER --rpc-url http://127.0.0.1:${CHAIN1_PORT}); echo -e "\nDry-running warp route deployments to Alfajores" - yarn workspace @hyperlane-xyz/cli run hyperlane deploy warp --dry-run \ + yarn workspace @hyperlane-xyz/cli run hyperlane deploy warp \ + --dry-run alfajores \ --chains ${EXAMPLES_PATH}/dry-run/anvil-chains.yaml \ --core $CORE_ARTIFACTS_PATH \ --config ${EXAMPLES_PATH}/dry-run/warp-route-deployment.yaml \ diff --git a/typescript/cli/examples/dry-run/warp-route-deployment.yaml b/typescript/cli/examples/dry-run/warp-route-deployment.yaml index 203abe6748..0c05f1c3d3 100644 --- a/typescript/cli/examples/dry-run/warp-route-deployment.yaml +++ b/typescript/cli/examples/dry-run/warp-route-deployment.yaml @@ -1,5 +1,4 @@ -base: - chainName: alfajores +alfajores: type: native -synthetics: - - chainName: fuji +fuji: + type: synthetic diff --git a/typescript/cli/examples/fork/warp-route-deployment.yaml b/typescript/cli/examples/fork/warp-route-deployment.yaml index 95755bd191..7aa1ff621a 100644 --- a/typescript/cli/examples/fork/warp-route-deployment.yaml +++ b/typescript/cli/examples/fork/warp-route-deployment.yaml @@ -10,17 +10,25 @@ # fastCollateral # fastSynthetic --- -base: - chainName: anvil +anvil: type: native - # address: 0x123... # Required for collateral types + # token: "0x123" # Collateral/vault address. Required for collateral types + # owner: "0x123" # Optional owner address for synthetic token + # mailbox: "0x123" # mailbox address route + # interchainGasPaymaster: "0x123" # Optional interchainGasPaymaster address # isNft: true # If the token is an NFT (ERC721), set to true - # owner: 0x123 # Optional owner address for synthetic token - # mailbox: 0x123 # Optional mailbox address route - # interchainGasPaymaster: 0x123 # Optional interchainGasPaymaster address -synthetics: - - chainName: ethereum - # You can optionally set the token metadata, otherwise the base token's will be used + # You can optionally set the token metadata + # name: "MyCollateralToken" + # symbol: "MCT" + # totalSupply: 10000000 + +ethereum: + type: synthetic + # token: "0x123" # Collateral/vault address. Required for collateral types + # owner: "0x123" # Optional owner address for synthetic token + # mailbox: "0x123" # mailbox address route + # interchainGasPaymaster: "0x123" # Optional interchainGasPaymaster address + # You can optionally set the token metadata # name: "MySyntheticToken" # symbol: "MST" # totalSupply: 10000000 diff --git a/typescript/cli/examples/warp-route-deployment.yaml b/typescript/cli/examples/warp-route-deployment.yaml index d1d61fea31..2bad109404 100644 --- a/typescript/cli/examples/warp-route-deployment.yaml +++ b/typescript/cli/examples/warp-route-deployment.yaml @@ -4,24 +4,31 @@ # Token Types: # native # collateral -# collateralVault # synthetic # collateralUri # syntheticUri # fastCollateral # fastSynthetic --- -base: - chainName: anvil1 +anvil1: type: native - # address: 0x123... # Required for collateral types. For collateralVault types, specifies the ERC4626 vault to deposit collateral into + # token: "0x123" # Collateral/vault address. Required for collateral types + # owner: "0x123" # Optional owner address for synthetic token + # mailbox: "0x123" # mailbox address route + # interchainGasPaymaster: "0x123" # Optional interchainGasPaymaster address # isNft: true # If the token is an NFT (ERC721), set to true - # owner: 0x123 # Optional owner address for synthetic token - # mailbox: 0x123 # Optional mailbox address route - # interchainGasPaymaster: 0x123 # Optional interchainGasPaymaster address -synthetics: - - chainName: anvil2 - # You can optionally set the token metadata, otherwise the base token's will be used + # You can optionally set the token metadata + # name: "MyCollateralToken" + # symbol: "MCT" + # totalSupply: 10000000 + +anvil2: + type: synthetic + # token: "0x123" # Collateral/vault address. Required for collateral types + # owner: "0x123" # Optional owner address for synthetic token + # mailbox: "0x123" # mailbox address route + # interchainGasPaymaster: "0x123" # Optional interchainGasPaymaster address + # You can optionally set the token metadata # name: "MySyntheticToken" # symbol: "MST" # totalSupply: 10000000 diff --git a/typescript/cli/src/commands/deploy.ts b/typescript/cli/src/commands/deploy.ts index b14c6e5cc2..4f53bd295a 100644 --- a/typescript/cli/src/commands/deploy.ts +++ b/typescript/cli/src/commands/deploy.ts @@ -107,7 +107,7 @@ const coreCommand: CommandModule = { const ismConfigPath: string = argv.ism; const hookConfigPath: string = argv.hook; const skipConfirmation: boolean = argv.yes; - const dryRun: boolean = argv.dryRun; + const dryRun: string = argv.dryRun; logGray( `Hyperlane permissionless core deployment${dryRun ? ' dry-run' : ''}`, @@ -159,7 +159,7 @@ const warpCommand: CommandModule = { const coreArtifactsPath: string | undefined = argv.core; const outPath: string = argv.out; const skipConfirmation: boolean = argv.yes; - const dryRun: boolean = argv.dryRun; + const dryRun: string = argv.dryRun; logGray(`Hyperlane warp route deployment${dryRun ? ' dry-run' : ''}`); logGray('------------------------------------------------'); diff --git a/typescript/cli/src/commands/options.ts b/typescript/cli/src/commands/options.ts index 9bb0c954b0..90aa53e1ff 100644 --- a/typescript/cli/src/commands/options.ts +++ b/typescript/cli/src/commands/options.ts @@ -141,9 +141,8 @@ export const skipConfirmationOption: Options = { }; export const dryRunOption: Options = { - type: 'boolean', + type: 'string', description: - 'Simulate deployment on forked network. Please ensure an anvil node instance is running during execution via `anvil`.', - default: false, + 'Chain name to fork and simulate deployment. Please ensure an anvil node instance is running during execution via `anvil`.', alias: ['d', 'dr'], }; diff --git a/typescript/cli/src/config/warp.ts b/typescript/cli/src/config/warp.ts index b64545145d..832e9f47c8 100644 --- a/typescript/cli/src/config/warp.ts +++ b/typescript/cli/src/config/warp.ts @@ -1,8 +1,11 @@ import { confirm, input } from '@inquirer/prompts'; import { ethers } from 'ethers'; -import { z } from 'zod'; -import { TokenType, ZHash } from '@hyperlane-xyz/sdk'; +import { + TokenType, + WarpRouteDeployConfig, + WarpRouteDeployConfigSchema, +} from '@hyperlane-xyz/sdk'; import { errorRed, logBlue, logGreen } from '../logger.js'; import { @@ -13,63 +16,6 @@ import { FileFormat, readYamlOrJson, writeYamlOrJson } from '../utils/files.js'; import { readChainConfigsIfExists } from './chain.js'; -const ConnectionConfigSchema = { - mailbox: ZHash.optional(), - interchainSecurityModule: ZHash.optional(), - foreignDeployment: z.string().optional(), -}; - -export const WarpRouteDeployConfigSchema = z.object({ - base: z - .object({ - type: z - .literal(TokenType.native) - .or(z.literal(TokenType.collateral)) - .or(z.literal(TokenType.collateralVault)), - chainName: z.string(), - address: ZHash.optional(), - isNft: z.boolean().optional(), - name: z.string().optional(), - symbol: z.string().optional(), - decimals: z.number().optional(), - ...ConnectionConfigSchema, - }) - .refine( - (data) => { - // For collateralVault Warp Routes, address will specify the vault - if ( - data.type === TokenType.collateralVault && - data.address === ethers.constants.AddressZero - ) - return false; - - return true; - }, - { - message: 'Vault address is required when type is collateralVault', - path: ['address'], - }, - ), - synthetics: z - .array( - z.object({ - chainName: z.string(), - name: z.string().optional(), - symbol: z.string().optional(), - totalSupply: z.number().optional(), - ...ConnectionConfigSchema, - }), - ) - .nonempty(), -}); - -type InferredType = z.infer; -// A workaround for Zod's terrible typing for nonEmpty arrays -export type WarpRouteDeployConfig = { - base: InferredType['base']; - synthetics: Array; -}; - export function readWarpRouteDeployConfig(filePath: string) { const config = readYamlOrJson(filePath); if (!config) @@ -133,23 +79,28 @@ export async function createWarpRouteDeployConfig({ ); // TODO add more prompts here to support customizing the token metadata - let baseType: TokenType; + let result: WarpRouteDeployConfig; if (isNative) { - baseType = TokenType.native; + result = { + [baseChain]: { + type: TokenType.native, + }, + }; } else { - baseType = isYieldBearing - ? TokenType.collateralVault - : TokenType.collateral; + result = { + [baseChain]: { + type: isYieldBearing ? TokenType.collateralVault : TokenType.collateral, + token: baseAddress, + isNft, + }, + }; } - const result: WarpRouteDeployConfig = { - base: { - chainName: baseChain, - type: baseType, - address: baseAddress, - isNft, - }, - synthetics: syntheticChains.map((chain) => ({ chainName: chain })), - }; + + syntheticChains.map((chain) => { + result[chain] = { + type: TokenType.synthetic, + }; + }); if (isValidWarpRouteDeployConfig(result)) { logGreen(`Warp Route config is valid, writing to file ${outPath}`); diff --git a/typescript/cli/src/deploy/core.ts b/typescript/cli/src/deploy/core.ts index 67032d23e7..68eb805511 100644 --- a/typescript/cli/src/deploy/core.ts +++ b/typescript/cli/src/deploy/core.ts @@ -87,12 +87,12 @@ export async function runCoreDeploy({ artifactsPath?: string; outPath: string; skipConfirmation: boolean; - dryRun: boolean; + dryRun: string; }) { const context = dryRun ? await getDryRunContext({ chainConfigPath, - chains, + chains: [dryRun], keyConfig: { key }, skipConfirmation, }) @@ -280,7 +280,7 @@ interface DeployParams { hooksConfig?: ChainMap; outPath: string; skipConfirmation: boolean; - dryRun: boolean; + dryRun: string; } async function runDeployPlanStep({ diff --git a/typescript/cli/src/deploy/dry-run.ts b/typescript/cli/src/deploy/dry-run.ts index 6da1d78c66..2bd1ece82e 100644 --- a/typescript/cli/src/deploy/dry-run.ts +++ b/typescript/cli/src/deploy/dry-run.ts @@ -49,9 +49,9 @@ export async function verifyAnvil() { /** * Evaluates if an error is related to the current dry-run. * @param error the thrown error - * @param dryRun whether or not the current command is being dry-run + * @param dryRun the chain name to execute the dry-run on */ -export function evaluateIfDryRunFailure(error: any, dryRun: boolean) { +export function evaluateIfDryRunFailure(error: any, dryRun: string) { if (dryRun && error.message.includes('call revert exception')) warnYellow( '⛔️ [dry-run] The current RPC may not support forking. Please consider using a different RPC provider.', diff --git a/typescript/cli/src/deploy/utils.ts b/typescript/cli/src/deploy/utils.ts index 5a41a39b0c..3919aacca7 100644 --- a/typescript/cli/src/deploy/utils.ts +++ b/typescript/cli/src/deploy/utils.ts @@ -127,7 +127,7 @@ export async function completeDeploy( multiProvider: MultiProvider, userAddress: Address, chains: ChainName[], - dryRun: boolean = false, + dryRun: string, ) { if (chains.length > 0) logPink(`⛽️ Gas Usage Statistics`); for (const chain of chains) { diff --git a/typescript/cli/src/deploy/warp.ts b/typescript/cli/src/deploy/warp.ts index 57e98754e8..2b6b083111 100644 --- a/typescript/cli/src/deploy/warp.ts +++ b/typescript/cli/src/deploy/warp.ts @@ -12,21 +12,23 @@ import { MinimalTokenMetadata, MultiProtocolProvider, MultiProvider, - RouterConfig, TOKEN_TYPE_TO_STANDARD, TokenConfig, TokenFactories, + TokenRouterConfig, TokenType, WarpCoreConfig, + WarpRouteDeployConfig, getTokenConnectionId, + isCollateralConfig, + isNativeConfig, + isSyntheticConfig, } from '@hyperlane-xyz/sdk'; +import { RouterConfig } from '@hyperlane-xyz/sdk'; import { Address, ProtocolType, objMap } from '@hyperlane-xyz/utils'; import { Command } from '../commands/deploy.js'; -import { - WarpRouteDeployConfig, - readWarpRouteDeployConfig, -} from '../config/warp.js'; +import { readWarpRouteDeployConfig } from '../config/warp.js'; import { MINIMUM_WARP_DEPLOY_GAS } from '../consts.js'; import { getContext, @@ -59,7 +61,7 @@ export async function runWarpRouteDeploy({ coreArtifactsPath?: string; outPath: string; skipConfirmation: boolean; - dryRun: boolean; + dryRun: string; }) { if ( !warpRouteDeploymentConfigPath || @@ -84,7 +86,7 @@ export async function runWarpRouteDeploy({ const { multiProvider, signer, coreArtifacts } = dryRun ? await getDryRunContext({ chainConfigPath, - chains: [warpRouteConfig.base.chainName], + chains: [dryRun], coreConfig: { coreArtifactsPath }, keyConfig: { key }, skipConfirmation, @@ -156,69 +158,54 @@ async function runBuildConfigStep({ skipConfirmation: boolean; }) { log('Assembling token configs'); - const { base, synthetics } = warpRouteConfig; - const { type: baseType, chainName: baseChainName, isNft } = base; - const owner = await signer.getAddress(); - const baseMetadata = await fetchBaseTokenMetadata(base, multiProvider); - - log( - `Using base token metadata: Name: ${baseMetadata.name}, Symbol: ${baseMetadata.symbol}, Decimals: ${baseMetadata.decimals}`, - ); - - const mergedContractAddrs = getMergedContractAddresses( - coreArtifacts, - Object.keys(warpRouteConfig), - ); - - // Create configs that coalesce together values from the config file, - // the artifacts, and the SDK as a fallback - const configMap: ChainMap = { - [baseChainName]: { - type: baseType, - token: - baseType === TokenType.collateral || - baseType === TokenType.collateralVault - ? base.address! - : ethers.constants.AddressZero, - owner, - mailbox: base.mailbox || mergedContractAddrs[baseChainName]?.mailbox, - interchainSecurityModule: - base.interchainSecurityModule || - mergedContractAddrs[baseChainName]?.interchainSecurityModule || - mergedContractAddrs[baseChainName]?.multisigIsm, - // ismFactory: mergedContractAddrs[baseChainName].domainRoutingIsmFactory, // TODO fix when updating from routingIsm - foreignDeployment: base.foreignDeployment, - name: baseMetadata.name, - symbol: baseMetadata.symbol, - decimals: baseMetadata.decimals, - }, - }; - - for (const synthetic of synthetics) { - const sChainName = synthetic.chainName; - configMap[sChainName] = { - type: TokenType.synthetic, - name: synthetic.name || baseMetadata.name, - symbol: synthetic.symbol || baseMetadata.symbol, - totalSupply: synthetic.totalSupply || 0, - owner, - mailbox: synthetic.mailbox || mergedContractAddrs[sChainName].mailbox, - interchainSecurityModule: - synthetic.interchainSecurityModule || - mergedContractAddrs[sChainName]?.interchainSecurityModule || - mergedContractAddrs[sChainName]?.multisigIsm, - // ismFactory: mergedContractAddrs[sChainName].domainRoutingIsmFactory, // TODO fix - foreignDeployment: synthetic.foreignDeployment, - }; - } - - // Request input for any address fields that are missing const requiredRouterFields: Array = ['mailbox']; - let hasShownInfo = false; - for (const [chain, token] of Object.entries(configMap)) { + const remotes: string[] = []; + + /// @dev This will keep track of the base collateral metadata which can get overwritten if there are multiple collaterals. + /// These 'base' variables are used to derive synthetic fields + /// @todo Remove this artifact when multi-collateral is enabled + let baseChainName = ''; + let baseMetadata = {} as MinimalTokenMetadata; + // Create config that coalesce together values from the config file, + for (const [chain, config] of Object.entries(warpRouteConfig)) { + const mergedContractAddrs = getMergedContractAddresses( + coreArtifacts, + Object.keys(warpRouteConfig), + ); + // the artifacts, and the SDK as a fallback + config.owner = owner; + config.mailbox = config.mailbox || mergedContractAddrs[chain]?.mailbox; + config.interchainSecurityModule = + config.interchainSecurityModule || + mergedContractAddrs[chain]?.interchainSecurityModule || + mergedContractAddrs[chain]?.multisigIsm; + // config.ismFactory: mergedContractAddrs[baseChainName].domainRoutingIsmFactory, // TODO fix when updating from routingIsm + + if (isCollateralConfig(config) || isNativeConfig(config)) { + // Store the base metadata + baseChainName = chain; + baseMetadata = await fetchBaseTokenMetadata(chain, config, multiProvider); + log( + `Using token metadata: Name: ${baseMetadata.name}, Symbol: ${baseMetadata.symbol}, Decimals: ${baseMetadata.decimals}`, + ); + if (isCollateralConfig(config)) { + config.name = baseMetadata.name; + config.symbol = baseMetadata.symbol; + config.decimals = baseMetadata.decimals; + } + } else if (isSyntheticConfig(config)) { + // Use the config, or baseMetadata + config.name = config.name || baseMetadata.name; + config.symbol = config.symbol || baseMetadata.symbol; + config.totalSupply = config.totalSupply || 0; + remotes.push(chain); + } + + let hasShownInfo = false; + // Request input for any address fields that are missing for (const field of requiredRouterFields) { - if (token[field]) continue; + if (config[field]) continue; if (skipConfirmation) throw new Error(`Field ${field} for token on ${chain} required`); if (!hasShownInfo) { @@ -228,26 +215,24 @@ async function runBuildConfigStep({ hasShownInfo = true; } const value = await input({ - message: `Enter ${field} for ${getTokenName(token)} token on ${chain}`, + message: `Enter ${field} for ${getTokenName(config)} token on ${chain}`, }); if (!value) throw new Error(`Field ${field} required`); - token[field] = value.trim(); + config[field] = value.trim(); } } log('Token configs ready'); return { - configMap, - metadata: baseMetadata, + configMap: warpRouteConfig, origin: baseChainName, - remotes: synthetics.map(({ chainName }) => chainName), - isNft: !!isNft, + metadata: baseMetadata, + remotes, }; } interface DeployParams { - configMap: ChainMap; - isNft: boolean; + configMap: WarpRouteDeployConfig; metadata: MinimalTokenMetadata; origin: ChainName; remotes: ChainName[]; @@ -255,12 +240,11 @@ interface DeployParams { multiProvider: MultiProvider; outPath: string; skipConfirmation: boolean; - dryRun: boolean; + dryRun: string; } async function runDeployPlanStep({ configMap, - isNft, origin, remotes, signer, @@ -268,6 +252,7 @@ async function runDeployPlanStep({ }: DeployParams) { const address = await signer.getAddress(); const baseToken = configMap[origin]; + const baseName = getTokenName(baseToken); logBlue('\nDeployment plan'); logGray('==============='); @@ -275,7 +260,7 @@ async function runDeployPlanStep({ log(`Transaction signer and owner of new contracts will be ${address}`); log(`Deploying a warp route with a base of ${baseName} token on ${origin}`); log(`Connecting it to new synthetic tokens on ${remotes.join(', ')}`); - log(`Using token standard ${isNft ? 'ERC721' : 'ERC20'}`); + log(`Using token standard ${configMap.isNft ? 'ERC721' : 'ERC20'}`); if (skipConfirmation) return; @@ -288,7 +273,7 @@ async function runDeployPlanStep({ async function executeDeploy(params: DeployParams) { logBlue('All systems ready, captain! Beginning deployment...'); - const { configMap, isNft, multiProvider, outPath } = params; + const { configMap, multiProvider, outPath } = params; const [contractsFilePath, tokenConfigPath] = prepNewArtifactsFiles( outPath, @@ -304,7 +289,7 @@ async function executeDeploy(params: DeployParams) { ), ); - const deployer = isNft + const deployer = configMap.isNft ? new HypERC721Deployer(multiProvider) : new HypERC20Deployer(multiProvider); @@ -312,7 +297,9 @@ async function executeDeploy(params: DeployParams) { ? { [params.origin]: configMap[params.origin] } : configMap; - const deployedContracts = await deployer.deploy(config); + const deployedContracts = await deployer.deploy( + config as ChainMap, + ); /// @todo remove ChainMap once Hyperlane deployers are refactored logGreen('✅ Hyp token deployments complete'); @@ -326,37 +313,30 @@ async function executeDeploy(params: DeployParams) { } async function fetchBaseTokenMetadata( - base: WarpRouteDeployConfig['base'], + chain: string, + config: TokenRouterConfig, multiProvider: MultiProvider, ): Promise { - const { type, name, symbol, chainName, address, decimals } = base; - - // Skip fetching metadata if it's already provided in the config - if (name && symbol && decimals) { - return { name, symbol, decimals }; - } - - if (type === TokenType.native) { + if (config.type === TokenType.native) { // If it's a native token, use the chain's native token metadata - const chainNativeToken = - multiProvider.getChainMetadata(chainName).nativeToken; + const chainNativeToken = multiProvider.getChainMetadata(chain).nativeToken; if (chainNativeToken) return chainNativeToken; - else throw new Error(`No native token metadata for ${chainName}`); + else throw new Error(`No native token metadata for ${chain}`); } else if ( - base.type === TokenType.collateralVault || - (base.type === TokenType.collateral && address) + config.type === TokenType.collateralVault || + config.type === TokenType.collateral ) { // If it's a collateral type, use a TokenAdapter to query for its metadata - log(`Fetching token metadata for ${address} on ${chainName}`); + log(`Fetching token metadata for ${config.token} on ${chain}`); const adapter = new EvmTokenAdapter( - chainName, + chain, MultiProtocolProvider.fromMultiProvider(multiProvider), - { token: address as string }, + { token: config.token }, ); return adapter.getMetadata(); } else { throw new Error( - `Unsupported token: ${base.type}. Consider setting token metadata in your deployment config.`, + `Unsupported token: ${config.type}. Consider setting token metadata in your deployment config.`, ); } } diff --git a/typescript/cli/src/tests/deployTestErc20.ts b/typescript/cli/src/tests/deployTestErc20.ts index 5e2c47166d..517668a599 100644 --- a/typescript/cli/src/tests/deployTestErc20.ts +++ b/typescript/cli/src/tests/deployTestErc20.ts @@ -2,9 +2,7 @@ import { Wallet, providers } from 'ethers'; import fs from 'fs'; import { ERC20Test__factory } from '@hyperlane-xyz/core'; -import { TokenType } from '@hyperlane-xyz/sdk'; - -import { WarpRouteDeployConfig } from '../config/warp.js'; +import { TokenType, WarpRouteDeployConfig } from '@hyperlane-xyz/sdk'; async function deployERC20() { const [rpcUrl, chain1, chain2, privateKey, outPath] = process.argv.slice(2); @@ -22,12 +20,12 @@ async function deployERC20() { console.log('Test ERC20 contract deployed', contract.address); const warpDeploymentConfig: WarpRouteDeployConfig = { - base: { - chainName: chain1, + [chain1]: { type: TokenType.collateral, - address: contract.address, + token: contract.address, + isNft: false, }, - synthetics: [{ chainName: chain2 }], + [chain2]: { type: TokenType.synthetic }, }; console.log('Writing deployment config to', outPath); diff --git a/typescript/cli/src/utils/files.ts b/typescript/cli/src/utils/files.ts index ea70b5dc6a..2c79ac73ed 100644 --- a/typescript/cli/src/utils/files.ts +++ b/typescript/cli/src/utils/files.ts @@ -170,7 +170,7 @@ export function prepNewArtifactsFiles( */ export function getArtifactsFiles( defaultFiles: ArtifactsFile[], - dryRun: boolean = false, + dryRun: string = '', ): Array { if (dryRun) defaultFiles.map((defaultFile: ArtifactsFile) => { diff --git a/typescript/sdk/src/core/HyperlaneCore.ts b/typescript/sdk/src/core/HyperlaneCore.ts index fbd5e16a64..c38d013a3e 100644 --- a/typescript/sdk/src/core/HyperlaneCore.ts +++ b/typescript/sdk/src/core/HyperlaneCore.ts @@ -61,10 +61,13 @@ export class HyperlaneCore extends HyperlaneApp { owners: Address | ChainMap, ): ChainMap => { // get config - const config = objMap(this.contractsMap, (chain, contracts) => ({ - mailbox: contracts.mailbox.address, - owner: typeof owners === 'string' ? owners : owners[chain].owner, - })); + const config = objMap( + this.contractsMap, + (chain, contracts): RouterConfig => ({ + mailbox: contracts.mailbox.address, + owner: typeof owners === 'string' ? owners : owners[chain].owner, + }), + ); // filter for EVM chains return objFilter( config, diff --git a/typescript/sdk/src/deploy/schemas.ts b/typescript/sdk/src/deploy/schemas.ts new file mode 100644 index 0000000000..7d965f0bc1 --- /dev/null +++ b/typescript/sdk/src/deploy/schemas.ts @@ -0,0 +1,9 @@ +import { z } from 'zod'; + +import { AccountConfigSchema } from '../middleware/account/schemas.js'; + +export const OwnerSchema = z.union([z.string(), AccountConfigSchema]); + +export const OwnableConfigSchema = z.object({ + owner: OwnerSchema, +}); diff --git a/typescript/sdk/src/deploy/types.ts b/typescript/sdk/src/deploy/types.ts index 8afeb0c19f..084979d0e5 100644 --- a/typescript/sdk/src/deploy/types.ts +++ b/typescript/sdk/src/deploy/types.ts @@ -1,4 +1,5 @@ import type { Contract } from 'ethers'; +import { z } from 'zod'; import type { AccessControl, @@ -12,10 +13,17 @@ import { AccountConfig } from '../middleware/account/types.js'; import { MultiProvider } from '../providers/MultiProvider.js'; import type { ChainName } from '../types.js'; +import { OwnableConfigSchema } from './schemas.js'; + export type Owner = Address | AccountConfig; -export type OwnableConfig = { - owner: Owner; +/** + * @remarks ownerOverrides is added outside of the Schema because zod handle generics in a weird way (uses functions) + * @see https://stackoverflow.com/questions/74907523/creating-zod-schema-for-generic-interface + */ +export type OwnableConfig = z.infer< + typeof OwnableConfigSchema +> & { ownerOverrides?: Partial>; }; diff --git a/typescript/sdk/src/index.ts b/typescript/sdk/src/index.ts index 8b4db7aa75..9c34e5620e 100644 --- a/typescript/sdk/src/index.ts +++ b/typescript/sdk/src/index.ts @@ -426,6 +426,8 @@ export { TokenMetadata, TokenType, isCollateralConfig, + isSyntheticConfig, + isNativeConfig, isUriConfig, } from './token/config.js'; export { @@ -470,3 +472,11 @@ export { WarpTxCategory, WarpTypedTransaction, } from './warp/types.js'; + +export { MailboxClientConfigSchema as mailboxClientConfigSchema } from './router/schemas.js'; +export { + WarpRouteDeployConfigSchema, + TokenRouterConfigSchema as tokenRouterConfigSchema, +} from './token/schemas.js'; +export { AggregationIsmConfigSchema } from './ism/schemas.js'; +export { WarpRouteDeployConfig, TokenRouterConfig } from './token/types.js'; diff --git a/typescript/sdk/src/ism/schemas.test.ts b/typescript/sdk/src/ism/schemas.test.ts new file mode 100644 index 0000000000..db44109034 --- /dev/null +++ b/typescript/sdk/src/ism/schemas.test.ts @@ -0,0 +1,21 @@ +import { expect } from 'chai'; +import { ethers } from 'ethers'; + +import { AggregationIsmConfigSchema } from '@hyperlane-xyz/sdk'; + +import { IsmType } from './types.js'; + +const SOME_ADDRESS = ethers.Wallet.createRandom().address; +describe('AggregationIsmConfigSchema refine', () => { + it('should require threshold to be below modules length', () => { + const IsmConfig = { + type: IsmType.AGGREGATION, + modules: [SOME_ADDRESS], + threshold: 100, + }; + expect(AggregationIsmConfigSchema.safeParse(IsmConfig).success).to.be.false; + + IsmConfig.threshold = 0; + expect(AggregationIsmConfigSchema.safeParse(IsmConfig).success).to.be.true; + }); +}); diff --git a/typescript/sdk/src/ism/schemas.ts b/typescript/sdk/src/ism/schemas.ts new file mode 100644 index 0000000000..f07df3f256 --- /dev/null +++ b/typescript/sdk/src/ism/schemas.ts @@ -0,0 +1,80 @@ +import { z } from 'zod'; + +import { OwnableConfigSchema } from '../deploy/schemas.js'; +import { ZHash } from '../index.js'; + +import { AggregationIsmConfig, IsmConfig, IsmType } from './types.js'; + +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 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 PausableIsmConfigSchema = OwnableConfigSchema.and( + z.object({ + type: z.literal(IsmType.PAUSABLE), + paused: z.boolean().optional(), + }), +); + +export const MultisigIsmConfigSchema = MultisigConfigSchema.and( + z.object({ + type: z.union([ + z.literal(IsmType.MERKLE_ROOT_MULTISIG), + z.literal(IsmType.MESSAGE_ID_MULTISIG), + ]), + }), +); + +export const RoutingIsmConfigSchema = OwnableConfigSchema.and( + z.object({ + type: z.union([ + z.literal(IsmType.ROUTING), + z.literal(IsmType.FALLBACK_ROUTING), + ]), + domains: z.record(z.string(), z.nativeEnum(IsmType)), + }), +); + +export const AggregationIsmConfigSchema: z.ZodSchema = + z.lazy(() => + z + .object({ + type: z.literal(IsmType.AGGREGATION), + modules: z.array(IsmConfigSchema), + threshold: z.number(), + }) + .refine((data) => { + if (data.threshold > data.modules.length) return false; + + return true; + }), + ); + +export const IsmConfigSchema: z.ZodSchema = z.lazy(() => + z.union([ + z.string(), + TestIsmConfigSchema, + OpStackIsmConfigSchema, + PausableIsmConfigSchema, + TrustedRelayerIsmConfigSchema, + MultisigIsmConfigSchema, + RoutingIsmConfigSchema, + AggregationIsmConfigSchema, + ]), +); diff --git a/typescript/sdk/src/middleware/account/schemas.ts b/typescript/sdk/src/middleware/account/schemas.ts new file mode 100644 index 0000000000..fd0e91d2ce --- /dev/null +++ b/typescript/sdk/src/middleware/account/schemas.ts @@ -0,0 +1,12 @@ +import { z } from 'zod'; + +import { ZHash } from '../../index.js'; +import { ZChainName } from '../../metadata/customZodTypes.js'; + +export const AccountConfigSchema = z.object({ + origin: ZChainName, + owner: ZHash, + localRouter: ZHash.optional(), + routerOverride: ZHash.optional(), + ismOverride: ZHash.optional(), +}); diff --git a/typescript/sdk/src/router/schemas.ts b/typescript/sdk/src/router/schemas.ts new file mode 100644 index 0000000000..e186c4e1cf --- /dev/null +++ b/typescript/sdk/src/router/schemas.ts @@ -0,0 +1,21 @@ +import { z } from 'zod'; + +import { OwnableConfigSchema } from '../deploy/schemas.js'; +import { ZHash } from '../index.js'; +import { IsmConfigSchema } from '../ism/schemas.js'; + +export const ForeignDeploymentConfigSchema = z.object({ + foreignDeployment: z.string().optional(), +}); + +export const MailboxClientConfigSchema = z.object({ + mailbox: ZHash, + hook: ZHash.optional(), + interchainSecurityModule: IsmConfigSchema.optional(), +}); + +export const routerConfigSchema = MailboxClientConfigSchema.merge( + OwnableConfigSchema, +) + .merge(ForeignDeploymentConfigSchema) + .deepPartial(); diff --git a/typescript/sdk/src/router/types.ts b/typescript/sdk/src/router/types.ts index ff59002256..f1c7ab4480 100644 --- a/typescript/sdk/src/router/types.ts +++ b/typescript/sdk/src/router/types.ts @@ -1,23 +1,29 @@ +import { z } from 'zod'; + import { MailboxClient, ProxyAdmin__factory, Router, TimelockController__factory, } from '@hyperlane-xyz/core'; -import type { Address } from '@hyperlane-xyz/utils'; +import type { Address } from '../../../utils/dist/index.js'; import { HyperlaneFactories } from '../contracts/types.js'; import { UpgradeConfig } from '../deploy/proxy.js'; import { CheckerViolation, OwnableConfig } from '../deploy/types.js'; -import { IsmConfig } from '../ism/types.js'; + +import { + ForeignDeploymentConfigSchema, + MailboxClientConfigSchema, +} from './schemas.js'; export type RouterAddress = { router: Address; }; -export type ForeignDeploymentConfig = { - foreignDeployment?: Address; -}; +export type ForeignDeploymentConfig = z.infer< + typeof ForeignDeploymentConfigSchema +>; export type RouterConfig = MailboxClientConfig & OwnableConfig & @@ -42,13 +48,8 @@ export const proxiedFactories: ProxiedFactories = { }; // TODO: merge with kunal's hook deployer -type HookConfig = Address; -export type MailboxClientConfig = { - mailbox: Address; - hook?: HookConfig; - interchainSecurityModule?: IsmConfig; -}; +export type MailboxClientConfig = z.infer; export enum ClientViolationType { InterchainSecurityModule = 'ClientIsm', diff --git a/typescript/sdk/src/token/config.ts b/typescript/sdk/src/token/config.ts index d1ffc9d69f..ca1436878f 100644 --- a/typescript/sdk/src/token/config.ts +++ b/typescript/sdk/src/token/config.ts @@ -1,7 +1,10 @@ import { ethers } from 'ethers'; +import z from 'zod'; import { GasRouterConfig } from '../router/types.js'; +import { SyntheticConfigSchema } from './schemas.js'; + export enum TokenType { synthetic = 'synthetic', fastSynthetic = 'fastSynthetic', @@ -34,9 +37,7 @@ export const isTokenMetadata = (metadata: any): metadata is TokenMetadata => export const isErc20Metadata = (metadata: any): metadata is ERC20Metadata => metadata.decimals && isTokenMetadata(metadata); -export type SyntheticConfig = TokenMetadata & { - type: TokenType.synthetic | TokenType.syntheticUri | TokenType.fastSynthetic; -}; +export type SyntheticConfig = z.infer; export type CollateralConfig = { type: | TokenType.collateral diff --git a/typescript/sdk/src/token/deploy.hardhat-test.ts b/typescript/sdk/src/token/deploy.hardhat-test.ts index 4bf3af167c..00eddd1c7d 100644 --- a/typescript/sdk/src/token/deploy.hardhat-test.ts +++ b/typescript/sdk/src/token/deploy.hardhat-test.ts @@ -6,19 +6,21 @@ import { objMap } from '@hyperlane-xyz/utils'; import { TestCoreApp } from '../core/TestCoreApp.js'; import { TestCoreDeployer } from '../core/TestCoreDeployer.js'; import { HyperlaneProxyFactoryDeployer } from '../deploy/HyperlaneProxyFactoryDeployer.js'; +import { RouterConfig } from '../index.js'; import { HyperlaneIsmFactory } from '../ism/HyperlaneIsmFactory.js'; import { MultiProvider } from '../providers/MultiProvider.js'; import { ChainMap } from '../types.js'; -import { ERC20RouterConfig, HypERC20Config, TokenType } from './config.js'; +import { HypERC20Config, TokenConfig, TokenType } from './config.js'; import { HypERC20Deployer } from './deploy.js'; +import { WarpRouteDeployConfig } from './types.js'; describe('TokenDeployer', async () => { let signer: SignerWithAddress; let deployer: HypERC20Deployer; let multiProvider: MultiProvider; let coreApp: TestCoreApp; - let config: ChainMap; + let config: WarpRouteDeployConfig; before(async () => { [signer] = await hre.ethers.getSigners(); @@ -49,6 +51,6 @@ describe('TokenDeployer', async () => { }); it('deploys', async () => { - await deployer.deploy(config); + await deployer.deploy(config as ChainMap); }); }); diff --git a/typescript/sdk/src/token/schemas.test.ts b/typescript/sdk/src/token/schemas.test.ts new file mode 100644 index 0000000000..394b4c9fb2 --- /dev/null +++ b/typescript/sdk/src/token/schemas.test.ts @@ -0,0 +1,93 @@ +import { expect } from 'chai'; +import { ethers } from 'ethers'; +import { constants } from 'ethers'; + +import { TokenType, WarpRouteDeployConfigSchema } from '@hyperlane-xyz/sdk'; + +const SOME_ADDRESS = ethers.Wallet.createRandom().address; +const COLLATERAL_TYPES = [ + TokenType.collateral, + TokenType.collateralUri, + TokenType.fastCollateral, + TokenType.collateralVault, +]; + +const NON_COLLATERAL_TYPES = [ + TokenType.synthetic, + TokenType.syntheticUri, + TokenType.fastSynthetic, + TokenType.native, +]; + +describe('WarpRouteDeployConfigSchema refine', () => { + it('should require type address', () => { + const config: any = { + arbitrum: { + type: TokenType.collateral, + token: SOME_ADDRESS, + }, + }; + expect(WarpRouteDeployConfigSchema.safeParse(config).success).to.be.true; + delete config.arbitrum.type; + expect(WarpRouteDeployConfigSchema.safeParse(config).success).to.be.false; + }); + + it('should require token address', () => { + const config: any = { + arbitrum: { + type: TokenType.collateral, + token: SOME_ADDRESS, + }, + }; + expect(WarpRouteDeployConfigSchema.safeParse(config).success).to.be.true; + delete config.arbitrum.token; + expect(WarpRouteDeployConfigSchema.safeParse(config).success).to.be.false; + }); + + it('should allow mailbox to be optional', () => { + const config: any = { + arbitrum: { + type: TokenType.collateral, + token: constants.AddressZero, + mailbox: SOME_ADDRESS, + }, + }; + expect(WarpRouteDeployConfigSchema.safeParse(config).success).to.be.true; + delete config.arbitrum.mailbox; + expect(WarpRouteDeployConfigSchema.safeParse(config).success).to.be.true; + }); + + it('should throw if collateral type and token is empty', async () => { + for (const type of COLLATERAL_TYPES) { + const config: any = { + arbitrum: { + type, + mailbox: SOME_ADDRESS, + name: 'Arby Coin', + symbol: 'ARBY', + totalSupply: '10000', + }, + }; + expect(WarpRouteDeployConfigSchema.safeParse(config).success).to.be.false; + + // Set to some address + config.arbitrum.token = SOME_ADDRESS; + expect(WarpRouteDeployConfigSchema.safeParse(config).success).to.be.true; + } + }); + + it('should succeed if non-collateral type and token is empty', async () => { + for (const type of NON_COLLATERAL_TYPES) { + const config: any = { + arbitrum: { + type, + mailbox: SOME_ADDRESS, + name: 'Arby Coin', + symbol: 'ARBY', + totalSupply: '10000', + }, + }; + expect(WarpRouteDeployConfigSchema.safeParse(config).success).to.be.true; + } + }); +}); diff --git a/typescript/sdk/src/token/schemas.ts b/typescript/sdk/src/token/schemas.ts new file mode 100644 index 0000000000..2890261a57 --- /dev/null +++ b/typescript/sdk/src/token/schemas.ts @@ -0,0 +1,74 @@ +import { z } from 'zod'; + +import { routerConfigSchema } from '../router/schemas.js'; + +import { TokenType } from './config.js'; + +export const TokenMetadataSchema = z.object({ + name: z.string(), + symbol: z.string(), + totalSupply: z.string().or(z.number()), +}); + +export const TokenDecimalsSchema = z.object({ + decimals: z.number(), + scale: z.number().optional(), +}); + +export const ERC20MetadataSchema = + TokenMetadataSchema.merge(TokenDecimalsSchema).partial(); + +export const ERC721MetadataSchema = z.object({ + isNft: z.boolean().optional(), +}); + +export const CollateralConfigSchema = ERC721MetadataSchema.merge( + ERC20MetadataSchema, +).merge( + z.object({ + type: z.enum([ + TokenType.collateral, + TokenType.collateralUri, + TokenType.fastCollateral, + TokenType.collateralVault, + ]), + token: z.string(), + }), +); + +export const NativeConfigSchema = TokenDecimalsSchema.partial().merge( + z.object({ + type: z.enum([TokenType.native]), + }), +); + +export const SyntheticConfigSchema = TokenMetadataSchema.partial().merge( + z.object({ + type: z.enum([ + TokenType.synthetic, + TokenType.syntheticUri, + TokenType.fastSynthetic, + ]), + }), +); + +/** + * @remarks + * The discriminatedUnion is basically a switch statement for zod schemas + * It uses the 'type' key to pick from the array of schemas to validate + */ +export const TokenConfigSchema = z.discriminatedUnion('type', [ + NativeConfigSchema, + CollateralConfigSchema, + SyntheticConfigSchema, +]); + +export const TokenRouterConfigSchema = z.intersection( + TokenConfigSchema, + routerConfigSchema, +); + +export const WarpRouteDeployConfigSchema = z.record( + z.string(), + TokenRouterConfigSchema, +); diff --git a/typescript/sdk/src/token/types.ts b/typescript/sdk/src/token/types.ts new file mode 100644 index 0000000000..0d0a70800f --- /dev/null +++ b/typescript/sdk/src/token/types.ts @@ -0,0 +1,9 @@ +import { z } from 'zod'; + +import { + TokenRouterConfigSchema, + WarpRouteDeployConfigSchema, +} from './schemas.js'; + +export type TokenRouterConfig = z.infer; +export type WarpRouteDeployConfig = z.infer; From d6f25ed03544639c2694b64d080878b90a47d59f Mon Sep 17 00:00:00 2001 From: Trevor Porter Date: Thu, 25 Apr 2024 14:50:25 +0100 Subject: [PATCH 15/16] Deploy to Mode & Blast (#3653) ### Description ### Drive-by changes ### Related issues ### Backward compatibility ### Testing --- .../m20230309_000001_create_table_domain.rs | 16 + rust/config/mainnet_config.json | 108 + .../config/environments/mainnet3/agent.ts | 24 +- .../mainnet3/aw-validators/hyperlane.json | 6 + .../mainnet3/aw-validators/rc.json | 6 + .../mainnet3/core/verification.json | 2054 ++++++++++++++--- .../config/environments/mainnet3/funding.ts | 2 + .../environments/mainnet3/gasPrices.json | 2 + .../mainnet3/ism/verification.json | 1304 +++++++++-- .../environments/mainnet3/tokenPrices.json | 2 + .../environments/mainnet3/validators.ts | 30 +- .../infra/scripts/announce-validators.ts | 28 +- typescript/infra/src/agents/gcp.ts | 2 +- typescript/infra/src/deployment/deploy.ts | 9 +- typescript/sdk/src/consts/chainMetadata.ts | 64 +- typescript/sdk/src/consts/chains.ts | 6 +- .../sdk/src/consts/environments/mainnet.json | 196 +- typescript/sdk/src/consts/multisigIsm.ts | 10 + 18 files changed, 3328 insertions(+), 541 deletions(-) diff --git a/rust/agents/scraper/migration/src/m20230309_000001_create_table_domain.rs b/rust/agents/scraper/migration/src/m20230309_000001_create_table_domain.rs index 1ce834bc54..305f43badc 100644 --- a/rust/agents/scraper/migration/src/m20230309_000001_create_table_domain.rs +++ b/rust/agents/scraper/migration/src/m20230309_000001_create_table_domain.rs @@ -54,6 +54,14 @@ const DOMAINS: &[RawDomain] = &[ is_test_net: false, is_deprecated: false, }, + RawDomain { + name: "blast", + token: "ETH", + domain: 81457, + chain_id: 81457, + is_test_net: false, + is_deprecated: false, + }, RawDomain { name: "bsc", token: "BNB", @@ -110,6 +118,14 @@ const DOMAINS: &[RawDomain] = &[ is_test_net: false, is_deprecated: false, }, + RawDomain { + name: "mode", + token: "ETH", + domain: 34443, + chain_id: 34443, + is_test_net: false, + is_deprecated: false, + }, RawDomain { name: "moonbasealpha", token: "DEV", diff --git a/rust/config/mainnet_config.json b/rust/config/mainnet_config.json index 8e9162b73d..94384f7bcf 100644 --- a/rust/config/mainnet_config.json +++ b/rust/config/mainnet_config.json @@ -220,6 +220,63 @@ "storageGasOracle": "0xBF12ef4B9f307463D3FB59c3604F294dDCe287E2", "validatorAnnounce": "0x182E8d7c5F1B06201b102123FC7dF0EaeB445a7B" }, + "blast": { + "blockExplorers": [ + { + "apiUrl": "https://api.blastscan.io/api", + "family": "etherscan", + "name": "Blast Explorer", + "url": "https://blastscan.io" + }, + { + "apiUrl": "https://api.routescan.io/v2/network/mainnet/evm/81457/etherscan/api", + "family": "routescan", + "name": "Blast Explorer", + "url": "https://blastexplorer.io" + } + ], + "blocks": { + "confirmations": 1, + "estimateBlockTime": 2, + "reorgPeriod": 1 + }, + "chainId": 81457, + "displayName": "Blast", + "domainId": 81457, + "domainRoutingIsmFactory": "0x2f2aFaE1139Ce54feFC03593FeE8AB2aDF4a85A7", + "fallbackRoutingHook": "0x6Fae4D9935E2fcb11fC79a64e917fb2BF14DaFaa", + "gasCurrencyCoinGeckoId": "ethereum", + "index": { + "from": 2496427 + }, + "interchainGasPaymaster": "0xB3fCcD379ad66CED0c91028520C64226611A48c9", + "interchainSecurityModule": "0xfeBe2fB33d203B43D763f119874574c33326d545", + "mailbox": "0x3a867fCfFeC2B790970eeBDC9023E75B0a172aa7", + "merkleTreeHook": "0xC9B8ea6230d6687a4b13fD3C0b8f0Ec607B26465", + "name": "blast", + "nativeToken": { + "decimals": 18, + "name": "Ether", + "symbol": "ETH" + }, + "pausableHook": "0xE0C452DDA7506f0F4dE5C8C1d383F7aD866eA4F0", + "protocol": "ethereum", + "protocolFee": "0x12582c7B0f43c6A667CBaA7fA8b112F7fb1E69F0", + "proxyAdmin": "0xeA87ae93Fa0019a82A727bfd3eBd1cFCa8f64f1D", + "rpcUrls": [ + { + "http": "https://rpc.blast.io" + } + ], + "staticAggregationHookFactory": "0x4Ed7d626f1E96cD1C0401607Bf70D95243E3dEd1", + "staticAggregationIsmFactory": "0x0761b0827849abbf7b0cC09CE14e1C93D87f5004", + "staticMerkleRootMultisigIsmFactory": "0xEb9FcFDC9EfDC17c1EC5E1dc085B98485da213D6", + "staticMessageIdMultisigIsmFactory": "0x1052eF3419f26Bec74Ed7CEf4a4FA6812Bc09908", + "storageGasOracle": "0xBDa330Ea8F3005C421C8088e638fBB64fA71b9e0", + "technicalStack": "other", + "testRecipient": "0x17E216fBb22dF4ef8A6640ae9Cb147C92710ac84", + "validatorAnnounce": "0xFC62DeF1f08793aBf0E67f69257c6be258194F72" + }, "bsc": { "aggregationHook": "0x402Fc106576462a892355d69ACF03D46A888ae88", "blockExplorers": [ @@ -608,6 +665,57 @@ "testTokenRecipient": "0x5060eCD5dFAD300A90592C04e504600A7cdcF70b", "validatorAnnounce": "0x2fa5F5C96419C222cDbCeC797D696e6cE428A7A9" }, + "mode": { + "blockExplorers": [ + { + "apiUrl": "https://explorer.mode.network/api", + "family": "blockscout", + "name": "Mode Explorer", + "url": "https://explorer.mode.network" + } + ], + "blocks": { + "confirmations": 1, + "estimateBlockTime": 2, + "reorgPeriod": 1 + }, + "chainId": 34443, + "displayName": "Mode", + "domainId": 34443, + "domainRoutingIsmFactory": "0x1052eF3419f26Bec74Ed7CEf4a4FA6812Bc09908", + "fallbackRoutingHook": "0x8F1E22d309baa69D398a03cc88E9b46037e988AA", + "gasCurrencyCoinGeckoId": "ethereum", + "index": { + "from": 6817759 + }, + "interchainGasPaymaster": "0x931dFCc8c1141D6F532FD023bd87DAe0080c835d", + "interchainSecurityModule": "0x8dfE6790DbB2Ecc1bEdb0eECfc1Ff467Ae5d8C89", + "mailbox": "0x2f2aFaE1139Ce54feFC03593FeE8AB2aDF4a85A7", + "merkleTreeHook": "0xE2ee936bEa8e42671c400aC96dE198E06F2bA2A6", + "name": "mode", + "nativeToken": { + "decimals": 18, + "name": "Ether", + "symbol": "ETH" + }, + "pausableHook": "0xA1ac41d8A663fd317cc3BD94C7de92dC4BA4a882", + "protocol": "ethereum", + "protocolFee": "0xea820f9BCFD5E16a0dd42071EB61A29874Ad81A4", + "proxyAdmin": "0x0761b0827849abbf7b0cC09CE14e1C93D87f5004", + "rpcUrls": [ + { + "http": "https://mainnet.mode.network" + } + ], + "staticAggregationHookFactory": "0xEb9FcFDC9EfDC17c1EC5E1dc085B98485da213D6", + "staticAggregationIsmFactory": "0x8F7454AC98228f3504Bb91eA3D8Adafe6406110A", + "staticMerkleRootMultisigIsmFactory": "0x2C1FAbEcd7bFBdEBF27CcdB67baADB38b6Df90fC", + "staticMessageIdMultisigIsmFactory": "0x8b83fefd896fAa52057798f6426E9f0B080FCCcE", + "storageGasOracle": "0xC9B8ea6230d6687a4b13fD3C0b8f0Ec607B26465", + "technicalStack": "other", + "testRecipient": "0x12582c7B0f43c6A667CBaA7fA8b112F7fb1E69F0", + "validatorAnnounce": "0x48083C69f5a42c6B69ABbAd48AE195BD36770ee2" + }, "moonbeam": { "aggregationHook": "0x23cca255aE83F57F39EAf9D14fB9FdaDF22D5863", "blockExplorers": [ diff --git a/typescript/infra/config/environments/mainnet3/agent.ts b/typescript/infra/config/environments/mainnet3/agent.ts index 68d212ca28..64373713cc 100644 --- a/typescript/infra/config/environments/mainnet3/agent.ts +++ b/typescript/infra/config/environments/mainnet3/agent.ts @@ -49,16 +49,18 @@ export const hyperlaneContextAgentChainConfig: AgentChainConfig = { [Chains.arbitrum]: true, [Chains.ancient8]: true, [Chains.avalanche]: true, + [Chains.base]: true, + [Chains.blast]: true, [Chains.bsc]: true, [Chains.celo]: true, [Chains.ethereum]: true, [Chains.neutron]: true, [Chains.mantapacific]: true, + [Chains.mode]: true, [Chains.moonbeam]: true, [Chains.optimism]: true, [Chains.polygon]: true, [Chains.gnosis]: true, - [Chains.base]: true, [Chains.scroll]: true, [Chains.polygonzkevm]: true, [Chains.injective]: true, @@ -69,17 +71,19 @@ export const hyperlaneContextAgentChainConfig: AgentChainConfig = { [Chains.arbitrum]: true, [Chains.ancient8]: true, [Chains.avalanche]: true, + [Chains.base]: true, + [Chains.blast]: true, [Chains.bsc]: true, [Chains.celo]: true, [Chains.ethereum]: true, // At the moment, we only relay between Neutron and Manta Pacific on the neutron context. [Chains.neutron]: false, [Chains.mantapacific]: false, + [Chains.mode]: true, [Chains.moonbeam]: true, [Chains.optimism]: true, [Chains.polygon]: true, [Chains.gnosis]: true, - [Chains.base]: true, [Chains.scroll]: true, [Chains.polygonzkevm]: true, [Chains.injective]: true, @@ -90,17 +94,19 @@ export const hyperlaneContextAgentChainConfig: AgentChainConfig = { [Chains.arbitrum]: true, [Chains.ancient8]: true, [Chains.avalanche]: true, + [Chains.base]: true, + [Chains.blast]: true, [Chains.bsc]: true, [Chains.celo]: true, [Chains.ethereum]: true, // Cannot scrape non-EVM chains [Chains.neutron]: false, [Chains.mantapacific]: true, + [Chains.mode]: true, [Chains.moonbeam]: true, [Chains.optimism]: true, [Chains.polygon]: true, [Chains.gnosis]: true, - [Chains.base]: true, [Chains.scroll]: true, [Chains.polygonzkevm]: true, // Cannot scrape non-EVM chains @@ -198,7 +204,7 @@ const hyperlane: RootAgentConfig = { rpcConsensusType: RpcConsensusType.Fallback, docker: { repo, - tag: '2a16200-20240408-214947', + tag: 'a2d6af6-20240422-164135', }, gasPaymentEnforcement: gasPaymentEnforcement, metricAppContexts, @@ -206,7 +212,7 @@ const hyperlane: RootAgentConfig = { validators: { docker: { repo, - tag: '2a16200-20240408-214947', + tag: 'a2d6af6-20240422-164135', }, rpcConsensusType: RpcConsensusType.Quorum, chains: validatorChainConfig(Contexts.Hyperlane), @@ -215,7 +221,7 @@ const hyperlane: RootAgentConfig = { rpcConsensusType: RpcConsensusType.Fallback, docker: { repo, - tag: '2a16200-20240408-214947', + tag: 'a2d6af6-20240422-164135', }, }, }; @@ -229,7 +235,7 @@ const releaseCandidate: RootAgentConfig = { rpcConsensusType: RpcConsensusType.Fallback, docker: { repo, - tag: '2a16200-20240408-214947', + tag: 'a2d6af6-20240422-164135', }, // We're temporarily (ab)using the RC relayer as a way to increase // message throughput. @@ -240,7 +246,7 @@ const releaseCandidate: RootAgentConfig = { validators: { docker: { repo, - tag: '2a16200-20240408-214947', + tag: 'a2d6af6-20240422-164135', }, rpcConsensusType: RpcConsensusType.Quorum, chains: validatorChainConfig(Contexts.ReleaseCandidate), @@ -264,7 +270,7 @@ const neutron: RootAgentConfig = { rpcConsensusType: RpcConsensusType.Fallback, docker: { repo, - tag: '2a16200-20240408-214947', + tag: 'a2d6af6-20240422-164135', }, gasPaymentEnforcement: [ { diff --git a/typescript/infra/config/environments/mainnet3/aw-validators/hyperlane.json b/typescript/infra/config/environments/mainnet3/aw-validators/hyperlane.json index e0603dfdeb..550918b8de 100644 --- a/typescript/infra/config/environments/mainnet3/aw-validators/hyperlane.json +++ b/typescript/infra/config/environments/mainnet3/aw-validators/hyperlane.json @@ -23,6 +23,9 @@ "0xb144bb2f599a5af095bc30367856f27ea8a8adc7" ] }, + "blast": { + "validators": ["0xf20c0b09f597597c8d2430d3d72dfddaf09177d1"] + }, "bsc": { "validators": [ "0x570af9b7b36568c8877eebba6c6727aa9dab7268", @@ -68,6 +71,9 @@ "0x5dda0c4cf18de3b3ab637f8df82b24921082b54c" ] }, + "mode": { + "validators": ["0x7eb2e1920a4166c19d6884c1cec3d2cf356fc9b7"] + }, "moonbeam": { "validators": [ "0x2225e2f4e9221049456da93b71d2de41f3b6b2a8", diff --git a/typescript/infra/config/environments/mainnet3/aw-validators/rc.json b/typescript/infra/config/environments/mainnet3/aw-validators/rc.json index 7c65389fc4..112dc4a777 100644 --- a/typescript/infra/config/environments/mainnet3/aw-validators/rc.json +++ b/typescript/infra/config/environments/mainnet3/aw-validators/rc.json @@ -23,6 +23,9 @@ "0xed7703e06572768bb09e03d88e6b788d8800b9fb" ] }, + "blast": { + "validators": ["0x5b32f226e472da6ca19abfe1a29d5d28102a2d1a"] + }, "bsc": { "validators": [ "0x911dfcc19dd5b723e84be452f6af52adef020bc8", @@ -65,6 +68,9 @@ "0x4cfccfd66dbb702b643b56f6986a928ed1b50c7e" ] }, + "mode": { + "validators": ["0x2f04ed30b1c27ef8e9e6acd360728d9bd5c3a9e2"] + }, "moonbeam": { "validators": [ "0x75e3cd4e909089ae6c9f3a42b1468b33eec84161", diff --git a/typescript/infra/config/environments/mainnet3/core/verification.json b/typescript/infra/config/environments/mainnet3/core/verification.json index 27608742b6..929e42aa30 100644 --- a/typescript/infra/config/environments/mainnet3/core/verification.json +++ b/typescript/infra/config/environments/mainnet3/core/verification.json @@ -1171,634 +1171,2150 @@ "name": "PausableHook" } ], - "bsc": [ + "blast": [ { - "address": "0xBFA300164A04437D64Afda390736e6DC45096da1", - "constructorArguments": "0000000000000000000000000000000000000000000000000000000000000038", + "address": "0xeA87ae93Fa0019a82A727bfd3eBd1cFCa8f64f1D", + "constructorArguments": "", "isProxy": false, - "name": "Mailbox" - }, - { - "address": "0x2971b9Aec44bE4eb673DF1B88cDB57b96eefe8a4", - "constructorArguments": "000000000000000000000000bfa300164a04437d64afda390736e6dc45096da100000000000000000000000065993af9d0d3a64ec77590db7ba362d6eb78ef7000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000000", - "isProxy": true, - "name": "TransparentUpgradeableProxy" + "name": "ProxyAdmin" }, { - "address": "0xBFA300164A04437D64Afda390736e6DC45096da1", - "constructorArguments": "0000000000000000000000000000000000000000000000000000000000000038", + "address": "0x3a464f746D23Ab22155710f44dB16dcA53e0775E", + "constructorArguments": "0000000000000000000000000000000000000000000000000000000000013e31", "isProxy": false, "name": "Mailbox" }, { - "address": "0x2971b9Aec44bE4eb673DF1B88cDB57b96eefe8a4", - "constructorArguments": "000000000000000000000000bfa300164a04437d64afda390736e6dc45096da100000000000000000000000065993af9d0d3a64ec77590db7ba362d6eb78ef7000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000000", + "address": "0x3a867fCfFeC2B790970eeBDC9023E75B0a172aa7", + "constructorArguments": "0000000000000000000000003a464f746d23ab22155710f44db16dca53e0775e000000000000000000000000ea87ae93fa0019a82a727bfd3ebd1cfca8f64f1d00000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000000", "isProxy": true, "name": "TransparentUpgradeableProxy" }, { - "address": "0xA8Aa5f14a5463a78E45CC068F11c867949F3E367", - "constructorArguments": "000000000000000000000000000000000000000000000000000000003b9aca000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba", + "address": "0x8F1E22d309baa69D398a03cc88E9b46037e988AA", + "constructorArguments": "000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba", "isProxy": false, - "name": "ProtocolFee" + "name": "PausableIsm" }, { - "address": "0x7024078130D9c2100fEA474DAD009C2d1703aCcd", - "constructorArguments": "0000000000000000000000002971b9aec44be4eb673df1b88cdb57b96eefe8a4", + "address": "0xC9B8ea6230d6687a4b13fD3C0b8f0Ec607B26465", + "constructorArguments": "0000000000000000000000003a867fcffec2b790970eebdc9023e75b0a172aa7", "isProxy": false, - "name": "ValidatorAnnounce" + "name": "MerkleTreeHook" }, { - "address": "0xA8Aa5f14a5463a78E45CC068F11c867949F3E367", - "constructorArguments": "000000000000000000000000000000000000000000000000000000003b9aca000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba", + "address": "0x6Fae4D9935E2fcb11fC79a64e917fb2BF14DaFaa", + "constructorArguments": "0000000000000000000000003a867fcffec2b790970eebdc9023e75b0a172aa7000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba000000000000000000000000c9b8ea6230d6687a4b13fd3c0b8f0ec607b26465", "isProxy": false, - "name": "ProtocolFee" + "name": "FallbackRoutingHook" }, { - "address": "0x7024078130D9c2100fEA474DAD009C2d1703aCcd", - "constructorArguments": "0000000000000000000000002971b9aec44be4eb673df1b88cdb57b96eefe8a4", + "address": "0xE0C452DDA7506f0F4dE5C8C1d383F7aD866eA4F0", + "constructorArguments": "", "isProxy": false, - "name": "ValidatorAnnounce" - } - ], - "celo": [ + "name": "PausableHook" + }, { - "address": "0x0564ECF87C9Be194BbCDB8BC606132b163F76DeD", - "constructorArguments": "000000000000000000000000000000000000000000000000000000000000a4ec", + "address": "0xBDa330Ea8F3005C421C8088e638fBB64fA71b9e0", + "constructorArguments": "", "isProxy": false, - "name": "Mailbox" + "name": "StorageGasOracle" }, { - "address": "0x50da3B3907A08a24fe4999F4Dcf337E8dC7954bb", - "constructorArguments": "0000000000000000000000000564ecf87c9be194bbcdb8bc606132b163f76ded00000000000000000000000090f9a2e9ece93516d65fdab726a3c62f5960a1b900000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000000", + "address": "0x2Fa570E83009eaEef3a1cbd496a9a30F05266634", + "constructorArguments": "", + "isProxy": false, + "name": "InterchainGasPaymaster" + }, + { + "address": "0xB3fCcD379ad66CED0c91028520C64226611A48c9", + "constructorArguments": "0000000000000000000000002fa570e83009eaeef3a1cbd496a9a30f05266634000000000000000000000000ea87ae93fa0019a82a727bfd3ebd1cfca8f64f1d00000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000044485cc955000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba00000000000000000000000000000000000000000000000000000000", "isProxy": true, "name": "TransparentUpgradeableProxy" }, { - "address": "0x04dB778f05854f26E67e0a66b740BBbE9070D366", - "constructorArguments": "00000000000000000000000050da3b3907a08a24fe4999f4dcf337e8dc7954bb", + "address": "0xBDa330Ea8F3005C421C8088e638fBB64fA71b9e0", + "constructorArguments": "", "isProxy": false, - "name": "MerkleTreeHook" + "name": "StorageGasOracle" }, { - "address": "0x819b9E7D55E2E679d02d023559cB9d583F427078", + "address": "0x2Fa570E83009eaEef3a1cbd496a9a30F05266634", "constructorArguments": "", "isProxy": false, "name": "InterchainGasPaymaster" }, { - "address": "0x571f1435613381208477ac5d6974310d88AC7cB7", - "constructorArguments": "000000000000000000000000819b9e7d55e2e679d02d023559cb9d583f42707800000000000000000000000090f9a2e9ece93516d65fdab726a3c62f5960a1b900000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000044485cc955000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba00000000000000000000000000000000000000000000000000000000", + "address": "0xB3fCcD379ad66CED0c91028520C64226611A48c9", + "constructorArguments": "0000000000000000000000002fa570e83009eaeef3a1cbd496a9a30f05266634000000000000000000000000ea87ae93fa0019a82a727bfd3ebd1cfca8f64f1d00000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000044485cc955000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba00000000000000000000000000000000000000000000000000000000", "isProxy": true, "name": "TransparentUpgradeableProxy" }, { - "address": "0x04dB778f05854f26E67e0a66b740BBbE9070D366", - "constructorArguments": "00000000000000000000000050da3b3907a08a24fe4999f4dcf337e8dc7954bb", + "address": "0xBDa330Ea8F3005C421C8088e638fBB64fA71b9e0", + "constructorArguments": "", "isProxy": false, - "name": "MerkleTreeHook" + "name": "StorageGasOracle" }, { - "address": "0x819b9E7D55E2E679d02d023559cB9d583F427078", + "address": "0x2Fa570E83009eaEef3a1cbd496a9a30F05266634", "constructorArguments": "", "isProxy": false, "name": "InterchainGasPaymaster" }, { - "address": "0x571f1435613381208477ac5d6974310d88AC7cB7", - "constructorArguments": "000000000000000000000000819b9e7d55e2e679d02d023559cb9d583f42707800000000000000000000000090f9a2e9ece93516d65fdab726a3c62f5960a1b900000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000044485cc955000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba00000000000000000000000000000000000000000000000000000000", + "address": "0xB3fCcD379ad66CED0c91028520C64226611A48c9", + "constructorArguments": "0000000000000000000000002fa570e83009eaeef3a1cbd496a9a30f05266634000000000000000000000000ea87ae93fa0019a82a727bfd3ebd1cfca8f64f1d00000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000044485cc955000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba00000000000000000000000000000000000000000000000000000000", "isProxy": true, "name": "TransparentUpgradeableProxy" }, { - "address": "0x89886d431f9c3eEE64DCD6dAbA3f7D689D98D899", - "constructorArguments": "000000000000000000000000000000000000000000000000000000003b9aca000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba", - "isProxy": false, - "name": "ProtocolFee" - }, - { - "address": "0xCeF677b65FDaA6804d4403083bb12B8dB3991FE1", - "constructorArguments": "00000000000000000000000050da3b3907a08a24fe4999f4dcf337e8dc7954bb", + "address": "0xBDa330Ea8F3005C421C8088e638fBB64fA71b9e0", + "constructorArguments": "", "isProxy": false, - "name": "ValidatorAnnounce" + "name": "StorageGasOracle" }, { - "address": "0x0564ECF87C9Be194BbCDB8BC606132b163F76DeD", - "constructorArguments": "000000000000000000000000000000000000000000000000000000000000a4ec", + "address": "0x2Fa570E83009eaEef3a1cbd496a9a30F05266634", + "constructorArguments": "", "isProxy": false, - "name": "Mailbox" + "name": "InterchainGasPaymaster" }, { - "address": "0x50da3B3907A08a24fe4999F4Dcf337E8dC7954bb", - "constructorArguments": "0000000000000000000000000564ecf87c9be194bbcdb8bc606132b163f76ded00000000000000000000000090f9a2e9ece93516d65fdab726a3c62f5960a1b900000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000000", + "address": "0xB3fCcD379ad66CED0c91028520C64226611A48c9", + "constructorArguments": "0000000000000000000000002fa570e83009eaeef3a1cbd496a9a30f05266634000000000000000000000000ea87ae93fa0019a82a727bfd3ebd1cfca8f64f1d00000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000044485cc955000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba00000000000000000000000000000000000000000000000000000000", "isProxy": true, "name": "TransparentUpgradeableProxy" }, { - "address": "0x04dB778f05854f26E67e0a66b740BBbE9070D366", - "constructorArguments": "00000000000000000000000050da3b3907a08a24fe4999f4dcf337e8dc7954bb", + "address": "0xBDa330Ea8F3005C421C8088e638fBB64fA71b9e0", + "constructorArguments": "", "isProxy": false, - "name": "MerkleTreeHook" + "name": "StorageGasOracle" }, { - "address": "0x819b9E7D55E2E679d02d023559cB9d583F427078", + "address": "0x2Fa570E83009eaEef3a1cbd496a9a30F05266634", "constructorArguments": "", "isProxy": false, "name": "InterchainGasPaymaster" }, { - "address": "0x571f1435613381208477ac5d6974310d88AC7cB7", - "constructorArguments": "000000000000000000000000819b9e7d55e2e679d02d023559cb9d583f42707800000000000000000000000090f9a2e9ece93516d65fdab726a3c62f5960a1b900000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000044485cc955000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba00000000000000000000000000000000000000000000000000000000", + "address": "0xB3fCcD379ad66CED0c91028520C64226611A48c9", + "constructorArguments": "0000000000000000000000002fa570e83009eaeef3a1cbd496a9a30f05266634000000000000000000000000ea87ae93fa0019a82a727bfd3ebd1cfca8f64f1d00000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000044485cc955000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba00000000000000000000000000000000000000000000000000000000", "isProxy": true, "name": "TransparentUpgradeableProxy" }, { - "address": "0x04dB778f05854f26E67e0a66b740BBbE9070D366", - "constructorArguments": "00000000000000000000000050da3b3907a08a24fe4999f4dcf337e8dc7954bb", + "address": "0xBDa330Ea8F3005C421C8088e638fBB64fA71b9e0", + "constructorArguments": "", "isProxy": false, - "name": "MerkleTreeHook" + "name": "StorageGasOracle" }, { - "address": "0x819b9E7D55E2E679d02d023559cB9d583F427078", + "address": "0x2Fa570E83009eaEef3a1cbd496a9a30F05266634", "constructorArguments": "", "isProxy": false, "name": "InterchainGasPaymaster" }, { - "address": "0x571f1435613381208477ac5d6974310d88AC7cB7", - "constructorArguments": "000000000000000000000000819b9e7d55e2e679d02d023559cb9d583f42707800000000000000000000000090f9a2e9ece93516d65fdab726a3c62f5960a1b900000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000044485cc955000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba00000000000000000000000000000000000000000000000000000000", + "address": "0xB3fCcD379ad66CED0c91028520C64226611A48c9", + "constructorArguments": "0000000000000000000000002fa570e83009eaeef3a1cbd496a9a30f05266634000000000000000000000000ea87ae93fa0019a82a727bfd3ebd1cfca8f64f1d00000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000044485cc955000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba00000000000000000000000000000000000000000000000000000000", "isProxy": true, "name": "TransparentUpgradeableProxy" }, { - "address": "0x89886d431f9c3eEE64DCD6dAbA3f7D689D98D899", - "constructorArguments": "000000000000000000000000000000000000000000000000000000003b9aca000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba", + "address": "0xBDa330Ea8F3005C421C8088e638fBB64fA71b9e0", + "constructorArguments": "", "isProxy": false, - "name": "ProtocolFee" + "name": "StorageGasOracle" }, { - "address": "0xCeF677b65FDaA6804d4403083bb12B8dB3991FE1", - "constructorArguments": "00000000000000000000000050da3b3907a08a24fe4999f4dcf337e8dc7954bb", - "isProxy": false, - "name": "ValidatorAnnounce" - } - ], - "ethereum": [ - { - "address": "0x7b4D881c122a5e61adCFfb56A2e3CE9927D53455", - "constructorArguments": "0000000000000000000000000000000000000000000000000000000000000001", + "address": "0x2Fa570E83009eaEef3a1cbd496a9a30F05266634", + "constructorArguments": "", "isProxy": false, - "name": "Mailbox" + "name": "InterchainGasPaymaster" }, { - "address": "0xc005dc82818d67AF737725bD4bf75435d065D239", - "constructorArguments": "0000000000000000000000007b4d881c122a5e61adcffb56a2e3ce9927d5345500000000000000000000000075ee15ee1b4a75fa3e2fdf5df3253c25599cc65900000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000000", + "address": "0xB3fCcD379ad66CED0c91028520C64226611A48c9", + "constructorArguments": "0000000000000000000000002fa570e83009eaeef3a1cbd496a9a30f05266634000000000000000000000000ea87ae93fa0019a82a727bfd3ebd1cfca8f64f1d00000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000044485cc955000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba00000000000000000000000000000000000000000000000000000000", "isProxy": true, "name": "TransparentUpgradeableProxy" }, { - "address": "0x48e6c30B97748d1e2e03bf3e9FbE3890ca5f8CCA", - "constructorArguments": "000000000000000000000000c005dc82818d67af737725bd4bf75435d065d239", + "address": "0xBDa330Ea8F3005C421C8088e638fBB64fA71b9e0", + "constructorArguments": "", "isProxy": false, - "name": "MerkleTreeHook" + "name": "StorageGasOracle" }, { - "address": "0x1008FAbD07aBd93a7D9bB81803a89cC3a834E1A9", + "address": "0x2Fa570E83009eaEef3a1cbd496a9a30F05266634", "constructorArguments": "", "isProxy": false, "name": "InterchainGasPaymaster" }, { - "address": "0x9e6B1022bE9BBF5aFd152483DAD9b88911bC8611", - "constructorArguments": "0000000000000000000000001008fabd07abd93a7d9bb81803a89cc3a834e1a900000000000000000000000075ee15ee1b4a75fa3e2fdf5df3253c25599cc65900000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000044485cc955000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba00000000000000000000000000000000000000000000000000000000", + "address": "0xB3fCcD379ad66CED0c91028520C64226611A48c9", + "constructorArguments": "0000000000000000000000002fa570e83009eaeef3a1cbd496a9a30f05266634000000000000000000000000ea87ae93fa0019a82a727bfd3ebd1cfca8f64f1d00000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000044485cc955000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba00000000000000000000000000000000000000000000000000000000", "isProxy": true, "name": "TransparentUpgradeableProxy" }, { - "address": "0x48e6c30B97748d1e2e03bf3e9FbE3890ca5f8CCA", - "constructorArguments": "000000000000000000000000c005dc82818d67af737725bd4bf75435d065d239", + "address": "0xBDa330Ea8F3005C421C8088e638fBB64fA71b9e0", + "constructorArguments": "", "isProxy": false, - "name": "MerkleTreeHook" + "name": "StorageGasOracle" }, { - "address": "0x1008FAbD07aBd93a7D9bB81803a89cC3a834E1A9", + "address": "0x2Fa570E83009eaEef3a1cbd496a9a30F05266634", "constructorArguments": "", "isProxy": false, "name": "InterchainGasPaymaster" }, { - "address": "0x9e6B1022bE9BBF5aFd152483DAD9b88911bC8611", - "constructorArguments": "0000000000000000000000001008fabd07abd93a7d9bb81803a89cc3a834e1a900000000000000000000000075ee15ee1b4a75fa3e2fdf5df3253c25599cc65900000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000044485cc955000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba00000000000000000000000000000000000000000000000000000000", + "address": "0xB3fCcD379ad66CED0c91028520C64226611A48c9", + "constructorArguments": "0000000000000000000000002fa570e83009eaeef3a1cbd496a9a30f05266634000000000000000000000000ea87ae93fa0019a82a727bfd3ebd1cfca8f64f1d00000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000044485cc955000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba00000000000000000000000000000000000000000000000000000000", "isProxy": true, "name": "TransparentUpgradeableProxy" }, { - "address": "0x8B05BF30F6247a90006c5837eA63C7905D79e6d8", - "constructorArguments": "000000000000000000000000000000000000000000000000000000003b9aca000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba", - "isProxy": false, - "name": "ProtocolFee" - }, - { - "address": "0xCe74905e51497b4adD3639366708b821dcBcff96", - "constructorArguments": "000000000000000000000000c005dc82818d67af737725bd4bf75435d065d239", + "address": "0xBDa330Ea8F3005C421C8088e638fBB64fA71b9e0", + "constructorArguments": "", "isProxy": false, - "name": "ValidatorAnnounce" + "name": "StorageGasOracle" }, { - "address": "0x7b4D881c122a5e61adCFfb56A2e3CE9927D53455", - "constructorArguments": "0000000000000000000000000000000000000000000000000000000000000001", + "address": "0x2Fa570E83009eaEef3a1cbd496a9a30F05266634", + "constructorArguments": "", "isProxy": false, - "name": "Mailbox" + "name": "InterchainGasPaymaster" }, { - "address": "0xc005dc82818d67AF737725bD4bf75435d065D239", - "constructorArguments": "0000000000000000000000007b4d881c122a5e61adcffb56a2e3ce9927d5345500000000000000000000000075ee15ee1b4a75fa3e2fdf5df3253c25599cc65900000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000000", + "address": "0xB3fCcD379ad66CED0c91028520C64226611A48c9", + "constructorArguments": "0000000000000000000000002fa570e83009eaeef3a1cbd496a9a30f05266634000000000000000000000000ea87ae93fa0019a82a727bfd3ebd1cfca8f64f1d00000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000044485cc955000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba00000000000000000000000000000000000000000000000000000000", "isProxy": true, "name": "TransparentUpgradeableProxy" }, { - "address": "0x48e6c30B97748d1e2e03bf3e9FbE3890ca5f8CCA", - "constructorArguments": "000000000000000000000000c005dc82818d67af737725bd4bf75435d065d239", + "address": "0xBDa330Ea8F3005C421C8088e638fBB64fA71b9e0", + "constructorArguments": "", "isProxy": false, - "name": "MerkleTreeHook" + "name": "StorageGasOracle" }, { - "address": "0x1008FAbD07aBd93a7D9bB81803a89cC3a834E1A9", + "address": "0x2Fa570E83009eaEef3a1cbd496a9a30F05266634", "constructorArguments": "", "isProxy": false, "name": "InterchainGasPaymaster" }, { - "address": "0x9e6B1022bE9BBF5aFd152483DAD9b88911bC8611", - "constructorArguments": "0000000000000000000000001008fabd07abd93a7d9bb81803a89cc3a834e1a900000000000000000000000075ee15ee1b4a75fa3e2fdf5df3253c25599cc65900000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000044485cc955000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba00000000000000000000000000000000000000000000000000000000", + "address": "0xB3fCcD379ad66CED0c91028520C64226611A48c9", + "constructorArguments": "0000000000000000000000002fa570e83009eaeef3a1cbd496a9a30f05266634000000000000000000000000ea87ae93fa0019a82a727bfd3ebd1cfca8f64f1d00000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000044485cc955000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba00000000000000000000000000000000000000000000000000000000", "isProxy": true, "name": "TransparentUpgradeableProxy" }, { - "address": "0x48e6c30B97748d1e2e03bf3e9FbE3890ca5f8CCA", - "constructorArguments": "000000000000000000000000c005dc82818d67af737725bd4bf75435d065d239", + "address": "0xBDa330Ea8F3005C421C8088e638fBB64fA71b9e0", + "constructorArguments": "", "isProxy": false, - "name": "MerkleTreeHook" + "name": "StorageGasOracle" }, { - "address": "0x1008FAbD07aBd93a7D9bB81803a89cC3a834E1A9", + "address": "0x2Fa570E83009eaEef3a1cbd496a9a30F05266634", "constructorArguments": "", "isProxy": false, "name": "InterchainGasPaymaster" }, { - "address": "0x9e6B1022bE9BBF5aFd152483DAD9b88911bC8611", - "constructorArguments": "0000000000000000000000001008fabd07abd93a7d9bb81803a89cc3a834e1a900000000000000000000000075ee15ee1b4a75fa3e2fdf5df3253c25599cc65900000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000044485cc955000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba00000000000000000000000000000000000000000000000000000000", + "address": "0xB3fCcD379ad66CED0c91028520C64226611A48c9", + "constructorArguments": "0000000000000000000000002fa570e83009eaeef3a1cbd496a9a30f05266634000000000000000000000000ea87ae93fa0019a82a727bfd3ebd1cfca8f64f1d00000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000044485cc955000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba00000000000000000000000000000000000000000000000000000000", "isProxy": true, "name": "TransparentUpgradeableProxy" }, { - "address": "0x8B05BF30F6247a90006c5837eA63C7905D79e6d8", - "constructorArguments": "000000000000000000000000000000000000000000000000000000003b9aca000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba", + "address": "0xBDa330Ea8F3005C421C8088e638fBB64fA71b9e0", + "constructorArguments": "", "isProxy": false, - "name": "ProtocolFee" + "name": "StorageGasOracle" }, { - "address": "0xCe74905e51497b4adD3639366708b821dcBcff96", - "constructorArguments": "000000000000000000000000c005dc82818d67af737725bd4bf75435d065d239", + "address": "0x2Fa570E83009eaEef3a1cbd496a9a30F05266634", + "constructorArguments": "", "isProxy": false, - "name": "ValidatorAnnounce" + "name": "InterchainGasPaymaster" }, { - "address": "0x571f1435613381208477ac5d6974310d88AC7cB7", - "constructorArguments": "000000000000000000000000c005dc82818d67af737725bd4bf75435d065d239000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba00000000000000000000000048e6c30b97748d1e2e03bf3e9fbe3890ca5f8cca", - "isProxy": false, - "name": "FallbackRoutingHook" + "address": "0xB3fCcD379ad66CED0c91028520C64226611A48c9", + "constructorArguments": "0000000000000000000000002fa570e83009eaeef3a1cbd496a9a30f05266634000000000000000000000000ea87ae93fa0019a82a727bfd3ebd1cfca8f64f1d00000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000044485cc955000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba00000000000000000000000000000000000000000000000000000000", + "isProxy": true, + "name": "TransparentUpgradeableProxy" }, { - "address": "0x3A66Dc852e56d3748838b3C27CF381105b83705b", + "address": "0xBDa330Ea8F3005C421C8088e638fBB64fA71b9e0", "constructorArguments": "", "isProxy": false, - "name": "PausableHook" + "name": "StorageGasOracle" }, { - "address": "0x571f1435613381208477ac5d6974310d88AC7cB7", - "constructorArguments": "000000000000000000000000c005dc82818d67af737725bd4bf75435d065d239000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba00000000000000000000000048e6c30b97748d1e2e03bf3e9fbe3890ca5f8cca", + "address": "0x2Fa570E83009eaEef3a1cbd496a9a30F05266634", + "constructorArguments": "", "isProxy": false, - "name": "FallbackRoutingHook" + "name": "InterchainGasPaymaster" }, { - "address": "0x3A66Dc852e56d3748838b3C27CF381105b83705b", - "constructorArguments": "", - "isProxy": false, - "name": "PausableHook" + "address": "0xB3fCcD379ad66CED0c91028520C64226611A48c9", + "constructorArguments": "0000000000000000000000002fa570e83009eaeef3a1cbd496a9a30f05266634000000000000000000000000ea87ae93fa0019a82a727bfd3ebd1cfca8f64f1d00000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000044485cc955000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba00000000000000000000000000000000000000000000000000000000", + "isProxy": true, + "name": "TransparentUpgradeableProxy" }, { - "address": "0x571f1435613381208477ac5d6974310d88AC7cB7", - "constructorArguments": "000000000000000000000000c005dc82818d67af737725bd4bf75435d065d239000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba00000000000000000000000048e6c30b97748d1e2e03bf3e9fbe3890ca5f8cca", + "address": "0xBDa330Ea8F3005C421C8088e638fBB64fA71b9e0", + "constructorArguments": "", "isProxy": false, - "name": "FallbackRoutingHook" + "name": "StorageGasOracle" }, { - "address": "0x3A66Dc852e56d3748838b3C27CF381105b83705b", + "address": "0x2Fa570E83009eaEef3a1cbd496a9a30F05266634", "constructorArguments": "", "isProxy": false, - "name": "PausableHook" + "name": "InterchainGasPaymaster" }, { - "address": "0x571f1435613381208477ac5d6974310d88AC7cB7", - "constructorArguments": "000000000000000000000000c005dc82818d67af737725bd4bf75435d065d239000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba00000000000000000000000048e6c30b97748d1e2e03bf3e9fbe3890ca5f8cca", - "isProxy": false, - "name": "FallbackRoutingHook" + "address": "0xB3fCcD379ad66CED0c91028520C64226611A48c9", + "constructorArguments": "0000000000000000000000002fa570e83009eaeef3a1cbd496a9a30f05266634000000000000000000000000ea87ae93fa0019a82a727bfd3ebd1cfca8f64f1d00000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000044485cc955000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba00000000000000000000000000000000000000000000000000000000", + "isProxy": true, + "name": "TransparentUpgradeableProxy" }, { - "address": "0x3A66Dc852e56d3748838b3C27CF381105b83705b", + "address": "0xBDa330Ea8F3005C421C8088e638fBB64fA71b9e0", "constructorArguments": "", "isProxy": false, - "name": "PausableHook" - } - ], - "gnosis": [ + "name": "StorageGasOracle" + }, { - "address": "0x53642476e24E28c3218E8Da44eDEBB4adB9DE13e", - "constructorArguments": "0000000000000000000000000000000000000000000000000000000000000064", + "address": "0x2Fa570E83009eaEef3a1cbd496a9a30F05266634", + "constructorArguments": "", "isProxy": false, - "name": "Mailbox" + "name": "InterchainGasPaymaster" }, { - "address": "0xaD09d78f4c6b9dA2Ae82b1D34107802d380Bb74f", - "constructorArguments": "00000000000000000000000053642476e24e28c3218e8da44edebb4adb9de13e00000000000000000000000081a92a1a272cb09d7b4970b07548463dc7ae0cb700000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000000", + "address": "0xB3fCcD379ad66CED0c91028520C64226611A48c9", + "constructorArguments": "0000000000000000000000002fa570e83009eaeef3a1cbd496a9a30f05266634000000000000000000000000ea87ae93fa0019a82a727bfd3ebd1cfca8f64f1d00000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000044485cc955000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba00000000000000000000000000000000000000000000000000000000", "isProxy": true, "name": "TransparentUpgradeableProxy" }, { - "address": "0x53642476e24E28c3218E8Da44eDEBB4adB9DE13e", - "constructorArguments": "0000000000000000000000000000000000000000000000000000000000000064", + "address": "0xBDa330Ea8F3005C421C8088e638fBB64fA71b9e0", + "constructorArguments": "", "isProxy": false, - "name": "Mailbox" + "name": "StorageGasOracle" }, { - "address": "0xaD09d78f4c6b9dA2Ae82b1D34107802d380Bb74f", - "constructorArguments": "00000000000000000000000053642476e24e28c3218e8da44edebb4adb9de13e00000000000000000000000081a92a1a272cb09d7b4970b07548463dc7ae0cb700000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000000", + "address": "0x2Fa570E83009eaEef3a1cbd496a9a30F05266634", + "constructorArguments": "", + "isProxy": false, + "name": "InterchainGasPaymaster" + }, + { + "address": "0xB3fCcD379ad66CED0c91028520C64226611A48c9", + "constructorArguments": "0000000000000000000000002fa570e83009eaeef3a1cbd496a9a30f05266634000000000000000000000000ea87ae93fa0019a82a727bfd3ebd1cfca8f64f1d00000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000044485cc955000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba00000000000000000000000000000000000000000000000000000000", "isProxy": true, "name": "TransparentUpgradeableProxy" }, { - "address": "0x9c2214467Daf9e2e1F45b36d08ce0b9C65BFeA88", - "constructorArguments": "000000000000000000000000000000000000000000000000000000003b9aca000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba", + "address": "0xBDa330Ea8F3005C421C8088e638fBB64fA71b9e0", + "constructorArguments": "", "isProxy": false, - "name": "ProtocolFee" + "name": "StorageGasOracle" }, { - "address": "0x9c2214467Daf9e2e1F45b36d08ce0b9C65BFeA88", - "constructorArguments": "000000000000000000000000000000000000000000000000000000003b9aca000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba", + "address": "0x2Fa570E83009eaEef3a1cbd496a9a30F05266634", + "constructorArguments": "", "isProxy": false, - "name": "ProtocolFee" + "name": "InterchainGasPaymaster" }, { - "address": "0x87ED6926abc9E38b9C7C19f835B41943b622663c", - "constructorArguments": "000000000000000000000000ad09d78f4c6b9da2ae82b1d34107802d380bb74f", - "isProxy": false, - "name": "ValidatorAnnounce" + "address": "0xB3fCcD379ad66CED0c91028520C64226611A48c9", + "constructorArguments": "0000000000000000000000002fa570e83009eaeef3a1cbd496a9a30f05266634000000000000000000000000ea87ae93fa0019a82a727bfd3ebd1cfca8f64f1d00000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000044485cc955000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba00000000000000000000000000000000000000000000000000000000", + "isProxy": true, + "name": "TransparentUpgradeableProxy" }, { - "address": "0x24f5E353dD03E103Ba2372F7D6FC0cf3A66f849c", - "constructorArguments": "000000000000000000000000ad09d78f4c6b9da2ae82b1d34107802d380bb74f000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba0000000000000000000000002684c6f89e901987e1fdb7649dc5be0c57c61645", + "address": "0xBDa330Ea8F3005C421C8088e638fBB64fA71b9e0", + "constructorArguments": "", "isProxy": false, - "name": "FallbackRoutingHook" + "name": "StorageGasOracle" }, { - "address": "0xf728C884De5275a608dEC222dACd0f2BF2E23AB6", + "address": "0x2Fa570E83009eaEef3a1cbd496a9a30F05266634", "constructorArguments": "", "isProxy": false, - "name": "PausableHook" + "name": "InterchainGasPaymaster" }, { - "address": "0x24f5E353dD03E103Ba2372F7D6FC0cf3A66f849c", - "constructorArguments": "000000000000000000000000ad09d78f4c6b9da2ae82b1d34107802d380bb74f000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba0000000000000000000000002684c6f89e901987e1fdb7649dc5be0c57c61645", + "address": "0xB3fCcD379ad66CED0c91028520C64226611A48c9", + "constructorArguments": "0000000000000000000000002fa570e83009eaeef3a1cbd496a9a30f05266634000000000000000000000000ea87ae93fa0019a82a727bfd3ebd1cfca8f64f1d00000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000044485cc955000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba00000000000000000000000000000000000000000000000000000000", + "isProxy": true, + "name": "TransparentUpgradeableProxy" + }, + { + "address": "0xC9B8ea6230d6687a4b13fD3C0b8f0Ec607B26465", + "constructorArguments": "0000000000000000000000003a867fcffec2b790970eebdc9023e75b0a172aa7", + "isProxy": false, + "name": "MerkleTreeHook" + }, + { + "address": "0x6Fae4D9935E2fcb11fC79a64e917fb2BF14DaFaa", + "constructorArguments": "0000000000000000000000003a867fcffec2b790970eebdc9023e75b0a172aa7000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba000000000000000000000000c9b8ea6230d6687a4b13fd3c0b8f0ec607b26465", "isProxy": false, "name": "FallbackRoutingHook" }, { - "address": "0xf728C884De5275a608dEC222dACd0f2BF2E23AB6", + "address": "0xE0C452DDA7506f0F4dE5C8C1d383F7aD866eA4F0", "constructorArguments": "", "isProxy": false, "name": "PausableHook" }, { - "address": "0x24f5E353dD03E103Ba2372F7D6FC0cf3A66f849c", - "constructorArguments": "000000000000000000000000ad09d78f4c6b9da2ae82b1d34107802d380bb74f000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba0000000000000000000000002684c6f89e901987e1fdb7649dc5be0c57c61645", + "address": "0xBDa330Ea8F3005C421C8088e638fBB64fA71b9e0", + "constructorArguments": "", "isProxy": false, - "name": "FallbackRoutingHook" + "name": "StorageGasOracle" }, { - "address": "0xf728C884De5275a608dEC222dACd0f2BF2E23AB6", + "address": "0x2Fa570E83009eaEef3a1cbd496a9a30F05266634", "constructorArguments": "", "isProxy": false, - "name": "PausableHook" + "name": "InterchainGasPaymaster" }, { - "address": "0x24f5E353dD03E103Ba2372F7D6FC0cf3A66f849c", - "constructorArguments": "000000000000000000000000ad09d78f4c6b9da2ae82b1d34107802d380bb74f000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba0000000000000000000000002684c6f89e901987e1fdb7649dc5be0c57c61645", + "address": "0xB3fCcD379ad66CED0c91028520C64226611A48c9", + "constructorArguments": "0000000000000000000000002fa570e83009eaeef3a1cbd496a9a30f05266634000000000000000000000000ea87ae93fa0019a82a727bfd3ebd1cfca8f64f1d00000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000044485cc955000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba00000000000000000000000000000000000000000000000000000000", + "isProxy": true, + "name": "TransparentUpgradeableProxy" + }, + { + "address": "0xBDa330Ea8F3005C421C8088e638fBB64fA71b9e0", + "constructorArguments": "", "isProxy": false, - "name": "FallbackRoutingHook" + "name": "StorageGasOracle" }, { - "address": "0xf728C884De5275a608dEC222dACd0f2BF2E23AB6", + "address": "0x2Fa570E83009eaEef3a1cbd496a9a30F05266634", "constructorArguments": "", "isProxy": false, - "name": "PausableHook" - } - ], - "inevm": [ + "name": "InterchainGasPaymaster" + }, { - "address": "0x0761b0827849abbf7b0cC09CE14e1C93D87f5004", + "address": "0xB3fCcD379ad66CED0c91028520C64226611A48c9", + "constructorArguments": "0000000000000000000000002fa570e83009eaeef3a1cbd496a9a30f05266634000000000000000000000000ea87ae93fa0019a82a727bfd3ebd1cfca8f64f1d00000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000044485cc955000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba00000000000000000000000000000000000000000000000000000000", + "isProxy": true, + "name": "TransparentUpgradeableProxy" + }, + { + "address": "0xBDa330Ea8F3005C421C8088e638fBB64fA71b9e0", "constructorArguments": "", "isProxy": false, - "name": "ProxyAdmin" + "name": "StorageGasOracle" }, { - "address": "0x4Ed7d626f1E96cD1C0401607Bf70D95243E3dEd1", - "constructorArguments": "00000000000000000000000000000000000000000000000000000000000009dd", + "address": "0x2Fa570E83009eaEef3a1cbd496a9a30F05266634", + "constructorArguments": "", "isProxy": false, - "name": "Mailbox" + "name": "InterchainGasPaymaster" }, { - "address": "0x2f2aFaE1139Ce54feFC03593FeE8AB2aDF4a85A7", - "constructorArguments": "0000000000000000000000004ed7d626f1e96cd1c0401607bf70d95243e3ded10000000000000000000000000761b0827849abbf7b0cc09ce14e1c93d87f500400000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000000", + "address": "0xB3fCcD379ad66CED0c91028520C64226611A48c9", + "constructorArguments": "0000000000000000000000002fa570e83009eaeef3a1cbd496a9a30f05266634000000000000000000000000ea87ae93fa0019a82a727bfd3ebd1cfca8f64f1d00000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000044485cc955000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba00000000000000000000000000000000000000000000000000000000", "isProxy": true, "name": "TransparentUpgradeableProxy" }, { - "address": "0x0972954923a1e2b2aAb04Fa0c4a0797e5989Cd65", - "constructorArguments": "0000000000000000000000002f2afae1139ce54fefc03593fee8ab2adf4a85a7", + "address": "0xBDa330Ea8F3005C421C8088e638fBB64fA71b9e0", + "constructorArguments": "", "isProxy": false, - "name": "MerkleTreeHook" + "name": "StorageGasOracle" }, { - "address": "0x6119E37Bd66406A1Db74920aC79C15fB8411Ba76", + "address": "0x2Fa570E83009eaEef3a1cbd496a9a30F05266634", + "constructorArguments": "", + "isProxy": false, + "name": "InterchainGasPaymaster" + }, + { + "address": "0xB3fCcD379ad66CED0c91028520C64226611A48c9", + "constructorArguments": "0000000000000000000000002fa570e83009eaeef3a1cbd496a9a30f05266634000000000000000000000000ea87ae93fa0019a82a727bfd3ebd1cfca8f64f1d00000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000044485cc955000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba00000000000000000000000000000000000000000000000000000000", + "isProxy": true, + "name": "TransparentUpgradeableProxy" + }, + { + "address": "0xBDa330Ea8F3005C421C8088e638fBB64fA71b9e0", "constructorArguments": "", "isProxy": false, "name": "StorageGasOracle" }, { - "address": "0x481171eb1aad17eDE6a56005B7F1aB00C581ef13", + "address": "0x2Fa570E83009eaEef3a1cbd496a9a30F05266634", "constructorArguments": "", "isProxy": false, "name": "InterchainGasPaymaster" }, { - "address": "0x19dc38aeae620380430C200a6E990D5Af5480117", - "constructorArguments": "000000000000000000000000481171eb1aad17ede6a56005b7f1ab00c581ef130000000000000000000000000761b0827849abbf7b0cc09ce14e1c93d87f500400000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000044485cc955000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba00000000000000000000000000000000000000000000000000000000", + "address": "0xB3fCcD379ad66CED0c91028520C64226611A48c9", + "constructorArguments": "0000000000000000000000002fa570e83009eaeef3a1cbd496a9a30f05266634000000000000000000000000ea87ae93fa0019a82a727bfd3ebd1cfca8f64f1d00000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000044485cc955000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba00000000000000000000000000000000000000000000000000000000", "isProxy": true, "name": "TransparentUpgradeableProxy" }, { - "address": "0x0972954923a1e2b2aAb04Fa0c4a0797e5989Cd65", - "constructorArguments": "0000000000000000000000002f2afae1139ce54fefc03593fee8ab2adf4a85a7", + "address": "0xBDa330Ea8F3005C421C8088e638fBB64fA71b9e0", + "constructorArguments": "", "isProxy": false, - "name": "MerkleTreeHook" + "name": "StorageGasOracle" }, { - "address": "0x6119E37Bd66406A1Db74920aC79C15fB8411Ba76", + "address": "0x2Fa570E83009eaEef3a1cbd496a9a30F05266634", + "constructorArguments": "", + "isProxy": false, + "name": "InterchainGasPaymaster" + }, + { + "address": "0xB3fCcD379ad66CED0c91028520C64226611A48c9", + "constructorArguments": "0000000000000000000000002fa570e83009eaeef3a1cbd496a9a30f05266634000000000000000000000000ea87ae93fa0019a82a727bfd3ebd1cfca8f64f1d00000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000044485cc955000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba00000000000000000000000000000000000000000000000000000000", + "isProxy": true, + "name": "TransparentUpgradeableProxy" + }, + { + "address": "0xBDa330Ea8F3005C421C8088e638fBB64fA71b9e0", "constructorArguments": "", "isProxy": false, "name": "StorageGasOracle" }, { - "address": "0x481171eb1aad17eDE6a56005B7F1aB00C581ef13", + "address": "0x2Fa570E83009eaEef3a1cbd496a9a30F05266634", "constructorArguments": "", "isProxy": false, "name": "InterchainGasPaymaster" }, { - "address": "0x19dc38aeae620380430C200a6E990D5Af5480117", - "constructorArguments": "000000000000000000000000481171eb1aad17ede6a56005b7f1ab00c581ef130000000000000000000000000761b0827849abbf7b0cc09ce14e1c93d87f500400000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000044485cc955000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba00000000000000000000000000000000000000000000000000000000", + "address": "0xB3fCcD379ad66CED0c91028520C64226611A48c9", + "constructorArguments": "0000000000000000000000002fa570e83009eaeef3a1cbd496a9a30f05266634000000000000000000000000ea87ae93fa0019a82a727bfd3ebd1cfca8f64f1d00000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000044485cc955000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba00000000000000000000000000000000000000000000000000000000", "isProxy": true, "name": "TransparentUpgradeableProxy" }, { - "address": "0x0D63128D887159d63De29497dfa45AFc7C699AE4", - "constructorArguments": "000000000000000000000000000000000000000000000000000000003b9aca000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba", + "address": "0xBDa330Ea8F3005C421C8088e638fBB64fA71b9e0", + "constructorArguments": "", "isProxy": false, - "name": "ProtocolFee" + "name": "StorageGasOracle" }, { - "address": "0x15ab173bDB6832f9b64276bA128659b0eD77730B", - "constructorArguments": "0000000000000000000000002f2afae1139ce54fefc03593fee8ab2adf4a85a7", + "address": "0x2Fa570E83009eaEef3a1cbd496a9a30F05266634", + "constructorArguments": "", "isProxy": false, - "name": "ValidatorAnnounce" + "name": "InterchainGasPaymaster" + }, + { + "address": "0xB3fCcD379ad66CED0c91028520C64226611A48c9", + "constructorArguments": "0000000000000000000000002fa570e83009eaeef3a1cbd496a9a30f05266634000000000000000000000000ea87ae93fa0019a82a727bfd3ebd1cfca8f64f1d00000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000044485cc955000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba00000000000000000000000000000000000000000000000000000000", + "isProxy": true, + "name": "TransparentUpgradeableProxy" }, { "address": "0xBDa330Ea8F3005C421C8088e638fBB64fA71b9e0", "constructorArguments": "", "isProxy": false, - "name": "PausableHook" + "name": "StorageGasOracle" + }, + { + "address": "0x2Fa570E83009eaEef3a1cbd496a9a30F05266634", + "constructorArguments": "", + "isProxy": false, + "name": "InterchainGasPaymaster" + }, + { + "address": "0xB3fCcD379ad66CED0c91028520C64226611A48c9", + "constructorArguments": "0000000000000000000000002fa570e83009eaeef3a1cbd496a9a30f05266634000000000000000000000000ea87ae93fa0019a82a727bfd3ebd1cfca8f64f1d00000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000044485cc955000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba00000000000000000000000000000000000000000000000000000000", + "isProxy": true, + "name": "TransparentUpgradeableProxy" }, { "address": "0xBDa330Ea8F3005C421C8088e638fBB64fA71b9e0", "constructorArguments": "", "isProxy": false, - "name": "PausableHook" - } - ], - "mantapacific": [ + "name": "StorageGasOracle" + }, { - "address": "0x2f2aFaE1139Ce54feFC03593FeE8AB2aDF4a85A7", + "address": "0x2Fa570E83009eaEef3a1cbd496a9a30F05266634", "constructorArguments": "", "isProxy": false, - "name": "ProxyAdmin" + "name": "InterchainGasPaymaster" }, { - "address": "0xeA87ae93Fa0019a82A727bfd3eBd1cFCa8f64f1D", - "constructorArguments": "00000000000000000000000000000000000000000000000000000000000000a9", + "address": "0xB3fCcD379ad66CED0c91028520C64226611A48c9", + "constructorArguments": "0000000000000000000000002fa570e83009eaeef3a1cbd496a9a30f05266634000000000000000000000000ea87ae93fa0019a82a727bfd3ebd1cfca8f64f1d00000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000044485cc955000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba00000000000000000000000000000000000000000000000000000000", + "isProxy": true, + "name": "TransparentUpgradeableProxy" + }, + { + "address": "0xBDa330Ea8F3005C421C8088e638fBB64fA71b9e0", + "constructorArguments": "", "isProxy": false, - "name": "Mailbox" + "name": "StorageGasOracle" }, { - "address": "0x3a464f746D23Ab22155710f44dB16dcA53e0775E", - "constructorArguments": "000000000000000000000000ea87ae93fa0019a82a727bfd3ebd1cfca8f64f1d0000000000000000000000002f2afae1139ce54fefc03593fee8ab2adf4a85a700000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000000", + "address": "0x2Fa570E83009eaEef3a1cbd496a9a30F05266634", + "constructorArguments": "", + "isProxy": false, + "name": "InterchainGasPaymaster" + }, + { + "address": "0xB3fCcD379ad66CED0c91028520C64226611A48c9", + "constructorArguments": "0000000000000000000000002fa570e83009eaeef3a1cbd496a9a30f05266634000000000000000000000000ea87ae93fa0019a82a727bfd3ebd1cfca8f64f1d00000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000044485cc955000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba00000000000000000000000000000000000000000000000000000000", "isProxy": true, "name": "TransparentUpgradeableProxy" }, { - "address": "0x149db7afD694722747035d5AEC7007ccb6F8f112", - "constructorArguments": "0000000000000000000000003a464f746d23ab22155710f44db16dca53e0775e", + "address": "0xBDa330Ea8F3005C421C8088e638fBB64fA71b9e0", + "constructorArguments": "", "isProxy": false, - "name": "MerkleTreeHook" + "name": "StorageGasOracle" }, { - "address": "0x19dc38aeae620380430C200a6E990D5Af5480117", + "address": "0x2Fa570E83009eaEef3a1cbd496a9a30F05266634", + "constructorArguments": "", + "isProxy": false, + "name": "InterchainGasPaymaster" + }, + { + "address": "0xB3fCcD379ad66CED0c91028520C64226611A48c9", + "constructorArguments": "0000000000000000000000002fa570e83009eaeef3a1cbd496a9a30f05266634000000000000000000000000ea87ae93fa0019a82a727bfd3ebd1cfca8f64f1d00000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000044485cc955000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba00000000000000000000000000000000000000000000000000000000", + "isProxy": true, + "name": "TransparentUpgradeableProxy" + }, + { + "address": "0xBDa330Ea8F3005C421C8088e638fBB64fA71b9e0", "constructorArguments": "", "isProxy": false, "name": "StorageGasOracle" }, { - "address": "0xBF12ef4B9f307463D3FB59c3604F294dDCe287E2", + "address": "0x2Fa570E83009eaEef3a1cbd496a9a30F05266634", "constructorArguments": "", "isProxy": false, "name": "InterchainGasPaymaster" }, { - "address": "0x0D63128D887159d63De29497dfa45AFc7C699AE4", - "constructorArguments": "000000000000000000000000bf12ef4b9f307463d3fb59c3604f294ddce287e20000000000000000000000002f2afae1139ce54fefc03593fee8ab2adf4a85a700000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000044485cc955000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba00000000000000000000000000000000000000000000000000000000", + "address": "0xB3fCcD379ad66CED0c91028520C64226611A48c9", + "constructorArguments": "0000000000000000000000002fa570e83009eaeef3a1cbd496a9a30f05266634000000000000000000000000ea87ae93fa0019a82a727bfd3ebd1cfca8f64f1d00000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000044485cc955000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba00000000000000000000000000000000000000000000000000000000", "isProxy": true, "name": "TransparentUpgradeableProxy" }, { - "address": "0x149db7afD694722747035d5AEC7007ccb6F8f112", - "constructorArguments": "0000000000000000000000003a464f746d23ab22155710f44db16dca53e0775e", + "address": "0xBDa330Ea8F3005C421C8088e638fBB64fA71b9e0", + "constructorArguments": "", "isProxy": false, - "name": "MerkleTreeHook" + "name": "StorageGasOracle" }, { - "address": "0x19dc38aeae620380430C200a6E990D5Af5480117", + "address": "0x2Fa570E83009eaEef3a1cbd496a9a30F05266634", + "constructorArguments": "", + "isProxy": false, + "name": "InterchainGasPaymaster" + }, + { + "address": "0xB3fCcD379ad66CED0c91028520C64226611A48c9", + "constructorArguments": "0000000000000000000000002fa570e83009eaeef3a1cbd496a9a30f05266634000000000000000000000000ea87ae93fa0019a82a727bfd3ebd1cfca8f64f1d00000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000044485cc955000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba00000000000000000000000000000000000000000000000000000000", + "isProxy": true, + "name": "TransparentUpgradeableProxy" + }, + { + "address": "0xBDa330Ea8F3005C421C8088e638fBB64fA71b9e0", "constructorArguments": "", "isProxy": false, "name": "StorageGasOracle" }, { - "address": "0xBF12ef4B9f307463D3FB59c3604F294dDCe287E2", + "address": "0x2Fa570E83009eaEef3a1cbd496a9a30F05266634", "constructorArguments": "", "isProxy": false, "name": "InterchainGasPaymaster" }, { - "address": "0x0D63128D887159d63De29497dfa45AFc7C699AE4", - "constructorArguments": "000000000000000000000000bf12ef4b9f307463d3fb59c3604f294ddce287e20000000000000000000000002f2afae1139ce54fefc03593fee8ab2adf4a85a700000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000044485cc955000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba00000000000000000000000000000000000000000000000000000000", + "address": "0xB3fCcD379ad66CED0c91028520C64226611A48c9", + "constructorArguments": "0000000000000000000000002fa570e83009eaeef3a1cbd496a9a30f05266634000000000000000000000000ea87ae93fa0019a82a727bfd3ebd1cfca8f64f1d00000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000044485cc955000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba00000000000000000000000000000000000000000000000000000000", "isProxy": true, "name": "TransparentUpgradeableProxy" }, { - "address": "0xd83A4F747fE80Ed98839e05079B1B7Fe037b1638", - "constructorArguments": "000000000000000000000000000000000000000000000000000000003b9aca000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba", + "address": "0xBDa330Ea8F3005C421C8088e638fBB64fA71b9e0", + "constructorArguments": "", "isProxy": false, - "name": "ProtocolFee" + "name": "StorageGasOracle" }, { - "address": "0x2fa5F5C96419C222cDbCeC797D696e6cE428A7A9", - "constructorArguments": "0000000000000000000000003a464f746d23ab22155710f44db16dca53e0775e", + "address": "0x2Fa570E83009eaEef3a1cbd496a9a30F05266634", + "constructorArguments": "", "isProxy": false, - "name": "ValidatorAnnounce" + "name": "InterchainGasPaymaster" }, { - "address": "0xD1E267d2d7876e97E217BfE61c34AB50FEF52807", - "constructorArguments": "0000000000000000000000003a464f746d23ab22155710f44db16dca53e0775e000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba000000000000000000000000149db7afd694722747035d5aec7007ccb6f8f112", + "address": "0xB3fCcD379ad66CED0c91028520C64226611A48c9", + "constructorArguments": "0000000000000000000000002fa570e83009eaeef3a1cbd496a9a30f05266634000000000000000000000000ea87ae93fa0019a82a727bfd3ebd1cfca8f64f1d00000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000044485cc955000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba00000000000000000000000000000000000000000000000000000000", + "isProxy": true, + "name": "TransparentUpgradeableProxy" + }, + { + "address": "0xBDa330Ea8F3005C421C8088e638fBB64fA71b9e0", + "constructorArguments": "", "isProxy": false, - "name": "FallbackRoutingHook" + "name": "StorageGasOracle" }, { - "address": "0x7556a0E61d577D921Cba8Fca0d7D6299d36E607E", + "address": "0x2Fa570E83009eaEef3a1cbd496a9a30F05266634", "constructorArguments": "", "isProxy": false, - "name": "PausableHook" + "name": "InterchainGasPaymaster" }, { - "address": "0xD1E267d2d7876e97E217BfE61c34AB50FEF52807", - "constructorArguments": "0000000000000000000000003a464f746d23ab22155710f44db16dca53e0775e000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba000000000000000000000000149db7afd694722747035d5aec7007ccb6f8f112", + "address": "0xB3fCcD379ad66CED0c91028520C64226611A48c9", + "constructorArguments": "0000000000000000000000002fa570e83009eaeef3a1cbd496a9a30f05266634000000000000000000000000ea87ae93fa0019a82a727bfd3ebd1cfca8f64f1d00000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000044485cc955000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba00000000000000000000000000000000000000000000000000000000", + "isProxy": true, + "name": "TransparentUpgradeableProxy" + }, + { + "address": "0xBDa330Ea8F3005C421C8088e638fBB64fA71b9e0", + "constructorArguments": "", "isProxy": false, - "name": "FallbackRoutingHook" + "name": "StorageGasOracle" }, { - "address": "0x7556a0E61d577D921Cba8Fca0d7D6299d36E607E", + "address": "0x2Fa570E83009eaEef3a1cbd496a9a30F05266634", "constructorArguments": "", "isProxy": false, - "name": "PausableHook" + "name": "InterchainGasPaymaster" + }, + { + "address": "0xB3fCcD379ad66CED0c91028520C64226611A48c9", + "constructorArguments": "0000000000000000000000002fa570e83009eaeef3a1cbd496a9a30f05266634000000000000000000000000ea87ae93fa0019a82a727bfd3ebd1cfca8f64f1d00000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000044485cc955000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba00000000000000000000000000000000000000000000000000000000", + "isProxy": true, + "name": "TransparentUpgradeableProxy" + }, + { + "address": "0xBDa330Ea8F3005C421C8088e638fBB64fA71b9e0", + "constructorArguments": "", + "isProxy": false, + "name": "StorageGasOracle" + }, + { + "address": "0x2Fa570E83009eaEef3a1cbd496a9a30F05266634", + "constructorArguments": "", + "isProxy": false, + "name": "InterchainGasPaymaster" + }, + { + "address": "0xB3fCcD379ad66CED0c91028520C64226611A48c9", + "constructorArguments": "0000000000000000000000002fa570e83009eaeef3a1cbd496a9a30f05266634000000000000000000000000ea87ae93fa0019a82a727bfd3ebd1cfca8f64f1d00000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000044485cc955000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba00000000000000000000000000000000000000000000000000000000", + "isProxy": true, + "name": "TransparentUpgradeableProxy" + }, + { + "address": "0x12582c7B0f43c6A667CBaA7fA8b112F7fb1E69F0", + "constructorArguments": "000000000000000000000000000000000000000000000000000000003b9aca000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba", + "isProxy": false, + "name": "ProtocolFee" + }, + { + "address": "0xFC62DeF1f08793aBf0E67f69257c6be258194F72", + "constructorArguments": "0000000000000000000000003a867fcffec2b790970eebdc9023e75b0a172aa7", + "isProxy": false, + "name": "ValidatorAnnounce" + } + ], + "bsc": [ + { + "address": "0xBFA300164A04437D64Afda390736e6DC45096da1", + "constructorArguments": "0000000000000000000000000000000000000000000000000000000000000038", + "isProxy": false, + "name": "Mailbox" + }, + { + "address": "0x2971b9Aec44bE4eb673DF1B88cDB57b96eefe8a4", + "constructorArguments": "000000000000000000000000bfa300164a04437d64afda390736e6dc45096da100000000000000000000000065993af9d0d3a64ec77590db7ba362d6eb78ef7000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000000", + "isProxy": true, + "name": "TransparentUpgradeableProxy" + }, + { + "address": "0xBFA300164A04437D64Afda390736e6DC45096da1", + "constructorArguments": "0000000000000000000000000000000000000000000000000000000000000038", + "isProxy": false, + "name": "Mailbox" + }, + { + "address": "0x2971b9Aec44bE4eb673DF1B88cDB57b96eefe8a4", + "constructorArguments": "000000000000000000000000bfa300164a04437d64afda390736e6dc45096da100000000000000000000000065993af9d0d3a64ec77590db7ba362d6eb78ef7000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000000", + "isProxy": true, + "name": "TransparentUpgradeableProxy" + }, + { + "address": "0xA8Aa5f14a5463a78E45CC068F11c867949F3E367", + "constructorArguments": "000000000000000000000000000000000000000000000000000000003b9aca000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba", + "isProxy": false, + "name": "ProtocolFee" + }, + { + "address": "0x7024078130D9c2100fEA474DAD009C2d1703aCcd", + "constructorArguments": "0000000000000000000000002971b9aec44be4eb673df1b88cdb57b96eefe8a4", + "isProxy": false, + "name": "ValidatorAnnounce" + }, + { + "address": "0xA8Aa5f14a5463a78E45CC068F11c867949F3E367", + "constructorArguments": "000000000000000000000000000000000000000000000000000000003b9aca000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba", + "isProxy": false, + "name": "ProtocolFee" + }, + { + "address": "0x7024078130D9c2100fEA474DAD009C2d1703aCcd", + "constructorArguments": "0000000000000000000000002971b9aec44be4eb673df1b88cdb57b96eefe8a4", + "isProxy": false, + "name": "ValidatorAnnounce" + } + ], + "celo": [ + { + "address": "0x0564ECF87C9Be194BbCDB8BC606132b163F76DeD", + "constructorArguments": "000000000000000000000000000000000000000000000000000000000000a4ec", + "isProxy": false, + "name": "Mailbox" + }, + { + "address": "0x50da3B3907A08a24fe4999F4Dcf337E8dC7954bb", + "constructorArguments": "0000000000000000000000000564ecf87c9be194bbcdb8bc606132b163f76ded00000000000000000000000090f9a2e9ece93516d65fdab726a3c62f5960a1b900000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000000", + "isProxy": true, + "name": "TransparentUpgradeableProxy" + }, + { + "address": "0x04dB778f05854f26E67e0a66b740BBbE9070D366", + "constructorArguments": "00000000000000000000000050da3b3907a08a24fe4999f4dcf337e8dc7954bb", + "isProxy": false, + "name": "MerkleTreeHook" + }, + { + "address": "0x819b9E7D55E2E679d02d023559cB9d583F427078", + "constructorArguments": "", + "isProxy": false, + "name": "InterchainGasPaymaster" + }, + { + "address": "0x571f1435613381208477ac5d6974310d88AC7cB7", + "constructorArguments": "000000000000000000000000819b9e7d55e2e679d02d023559cb9d583f42707800000000000000000000000090f9a2e9ece93516d65fdab726a3c62f5960a1b900000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000044485cc955000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba00000000000000000000000000000000000000000000000000000000", + "isProxy": true, + "name": "TransparentUpgradeableProxy" + }, + { + "address": "0x04dB778f05854f26E67e0a66b740BBbE9070D366", + "constructorArguments": "00000000000000000000000050da3b3907a08a24fe4999f4dcf337e8dc7954bb", + "isProxy": false, + "name": "MerkleTreeHook" + }, + { + "address": "0x819b9E7D55E2E679d02d023559cB9d583F427078", + "constructorArguments": "", + "isProxy": false, + "name": "InterchainGasPaymaster" + }, + { + "address": "0x571f1435613381208477ac5d6974310d88AC7cB7", + "constructorArguments": "000000000000000000000000819b9e7d55e2e679d02d023559cb9d583f42707800000000000000000000000090f9a2e9ece93516d65fdab726a3c62f5960a1b900000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000044485cc955000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba00000000000000000000000000000000000000000000000000000000", + "isProxy": true, + "name": "TransparentUpgradeableProxy" + }, + { + "address": "0x89886d431f9c3eEE64DCD6dAbA3f7D689D98D899", + "constructorArguments": "000000000000000000000000000000000000000000000000000000003b9aca000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba", + "isProxy": false, + "name": "ProtocolFee" + }, + { + "address": "0xCeF677b65FDaA6804d4403083bb12B8dB3991FE1", + "constructorArguments": "00000000000000000000000050da3b3907a08a24fe4999f4dcf337e8dc7954bb", + "isProxy": false, + "name": "ValidatorAnnounce" + }, + { + "address": "0x0564ECF87C9Be194BbCDB8BC606132b163F76DeD", + "constructorArguments": "000000000000000000000000000000000000000000000000000000000000a4ec", + "isProxy": false, + "name": "Mailbox" + }, + { + "address": "0x50da3B3907A08a24fe4999F4Dcf337E8dC7954bb", + "constructorArguments": "0000000000000000000000000564ecf87c9be194bbcdb8bc606132b163f76ded00000000000000000000000090f9a2e9ece93516d65fdab726a3c62f5960a1b900000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000000", + "isProxy": true, + "name": "TransparentUpgradeableProxy" + }, + { + "address": "0x04dB778f05854f26E67e0a66b740BBbE9070D366", + "constructorArguments": "00000000000000000000000050da3b3907a08a24fe4999f4dcf337e8dc7954bb", + "isProxy": false, + "name": "MerkleTreeHook" + }, + { + "address": "0x819b9E7D55E2E679d02d023559cB9d583F427078", + "constructorArguments": "", + "isProxy": false, + "name": "InterchainGasPaymaster" + }, + { + "address": "0x571f1435613381208477ac5d6974310d88AC7cB7", + "constructorArguments": "000000000000000000000000819b9e7d55e2e679d02d023559cb9d583f42707800000000000000000000000090f9a2e9ece93516d65fdab726a3c62f5960a1b900000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000044485cc955000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba00000000000000000000000000000000000000000000000000000000", + "isProxy": true, + "name": "TransparentUpgradeableProxy" + }, + { + "address": "0x04dB778f05854f26E67e0a66b740BBbE9070D366", + "constructorArguments": "00000000000000000000000050da3b3907a08a24fe4999f4dcf337e8dc7954bb", + "isProxy": false, + "name": "MerkleTreeHook" + }, + { + "address": "0x819b9E7D55E2E679d02d023559cB9d583F427078", + "constructorArguments": "", + "isProxy": false, + "name": "InterchainGasPaymaster" + }, + { + "address": "0x571f1435613381208477ac5d6974310d88AC7cB7", + "constructorArguments": "000000000000000000000000819b9e7d55e2e679d02d023559cb9d583f42707800000000000000000000000090f9a2e9ece93516d65fdab726a3c62f5960a1b900000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000044485cc955000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba00000000000000000000000000000000000000000000000000000000", + "isProxy": true, + "name": "TransparentUpgradeableProxy" + }, + { + "address": "0x89886d431f9c3eEE64DCD6dAbA3f7D689D98D899", + "constructorArguments": "000000000000000000000000000000000000000000000000000000003b9aca000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba", + "isProxy": false, + "name": "ProtocolFee" + }, + { + "address": "0xCeF677b65FDaA6804d4403083bb12B8dB3991FE1", + "constructorArguments": "00000000000000000000000050da3b3907a08a24fe4999f4dcf337e8dc7954bb", + "isProxy": false, + "name": "ValidatorAnnounce" + } + ], + "ethereum": [ + { + "address": "0x7b4D881c122a5e61adCFfb56A2e3CE9927D53455", + "constructorArguments": "0000000000000000000000000000000000000000000000000000000000000001", + "isProxy": false, + "name": "Mailbox" + }, + { + "address": "0xc005dc82818d67AF737725bD4bf75435d065D239", + "constructorArguments": "0000000000000000000000007b4d881c122a5e61adcffb56a2e3ce9927d5345500000000000000000000000075ee15ee1b4a75fa3e2fdf5df3253c25599cc65900000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000000", + "isProxy": true, + "name": "TransparentUpgradeableProxy" + }, + { + "address": "0x48e6c30B97748d1e2e03bf3e9FbE3890ca5f8CCA", + "constructorArguments": "000000000000000000000000c005dc82818d67af737725bd4bf75435d065d239", + "isProxy": false, + "name": "MerkleTreeHook" + }, + { + "address": "0x1008FAbD07aBd93a7D9bB81803a89cC3a834E1A9", + "constructorArguments": "", + "isProxy": false, + "name": "InterchainGasPaymaster" + }, + { + "address": "0x9e6B1022bE9BBF5aFd152483DAD9b88911bC8611", + "constructorArguments": "0000000000000000000000001008fabd07abd93a7d9bb81803a89cc3a834e1a900000000000000000000000075ee15ee1b4a75fa3e2fdf5df3253c25599cc65900000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000044485cc955000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba00000000000000000000000000000000000000000000000000000000", + "isProxy": true, + "name": "TransparentUpgradeableProxy" + }, + { + "address": "0x48e6c30B97748d1e2e03bf3e9FbE3890ca5f8CCA", + "constructorArguments": "000000000000000000000000c005dc82818d67af737725bd4bf75435d065d239", + "isProxy": false, + "name": "MerkleTreeHook" + }, + { + "address": "0x1008FAbD07aBd93a7D9bB81803a89cC3a834E1A9", + "constructorArguments": "", + "isProxy": false, + "name": "InterchainGasPaymaster" + }, + { + "address": "0x9e6B1022bE9BBF5aFd152483DAD9b88911bC8611", + "constructorArguments": "0000000000000000000000001008fabd07abd93a7d9bb81803a89cc3a834e1a900000000000000000000000075ee15ee1b4a75fa3e2fdf5df3253c25599cc65900000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000044485cc955000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba00000000000000000000000000000000000000000000000000000000", + "isProxy": true, + "name": "TransparentUpgradeableProxy" + }, + { + "address": "0x8B05BF30F6247a90006c5837eA63C7905D79e6d8", + "constructorArguments": "000000000000000000000000000000000000000000000000000000003b9aca000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba", + "isProxy": false, + "name": "ProtocolFee" + }, + { + "address": "0xCe74905e51497b4adD3639366708b821dcBcff96", + "constructorArguments": "000000000000000000000000c005dc82818d67af737725bd4bf75435d065d239", + "isProxy": false, + "name": "ValidatorAnnounce" + }, + { + "address": "0x7b4D881c122a5e61adCFfb56A2e3CE9927D53455", + "constructorArguments": "0000000000000000000000000000000000000000000000000000000000000001", + "isProxy": false, + "name": "Mailbox" + }, + { + "address": "0xc005dc82818d67AF737725bD4bf75435d065D239", + "constructorArguments": "0000000000000000000000007b4d881c122a5e61adcffb56a2e3ce9927d5345500000000000000000000000075ee15ee1b4a75fa3e2fdf5df3253c25599cc65900000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000000", + "isProxy": true, + "name": "TransparentUpgradeableProxy" + }, + { + "address": "0x48e6c30B97748d1e2e03bf3e9FbE3890ca5f8CCA", + "constructorArguments": "000000000000000000000000c005dc82818d67af737725bd4bf75435d065d239", + "isProxy": false, + "name": "MerkleTreeHook" + }, + { + "address": "0x1008FAbD07aBd93a7D9bB81803a89cC3a834E1A9", + "constructorArguments": "", + "isProxy": false, + "name": "InterchainGasPaymaster" + }, + { + "address": "0x9e6B1022bE9BBF5aFd152483DAD9b88911bC8611", + "constructorArguments": "0000000000000000000000001008fabd07abd93a7d9bb81803a89cc3a834e1a900000000000000000000000075ee15ee1b4a75fa3e2fdf5df3253c25599cc65900000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000044485cc955000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba00000000000000000000000000000000000000000000000000000000", + "isProxy": true, + "name": "TransparentUpgradeableProxy" + }, + { + "address": "0x48e6c30B97748d1e2e03bf3e9FbE3890ca5f8CCA", + "constructorArguments": "000000000000000000000000c005dc82818d67af737725bd4bf75435d065d239", + "isProxy": false, + "name": "MerkleTreeHook" + }, + { + "address": "0x1008FAbD07aBd93a7D9bB81803a89cC3a834E1A9", + "constructorArguments": "", + "isProxy": false, + "name": "InterchainGasPaymaster" + }, + { + "address": "0x9e6B1022bE9BBF5aFd152483DAD9b88911bC8611", + "constructorArguments": "0000000000000000000000001008fabd07abd93a7d9bb81803a89cc3a834e1a900000000000000000000000075ee15ee1b4a75fa3e2fdf5df3253c25599cc65900000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000044485cc955000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba00000000000000000000000000000000000000000000000000000000", + "isProxy": true, + "name": "TransparentUpgradeableProxy" + }, + { + "address": "0x8B05BF30F6247a90006c5837eA63C7905D79e6d8", + "constructorArguments": "000000000000000000000000000000000000000000000000000000003b9aca000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba", + "isProxy": false, + "name": "ProtocolFee" + }, + { + "address": "0xCe74905e51497b4adD3639366708b821dcBcff96", + "constructorArguments": "000000000000000000000000c005dc82818d67af737725bd4bf75435d065d239", + "isProxy": false, + "name": "ValidatorAnnounce" + }, + { + "address": "0x571f1435613381208477ac5d6974310d88AC7cB7", + "constructorArguments": "000000000000000000000000c005dc82818d67af737725bd4bf75435d065d239000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba00000000000000000000000048e6c30b97748d1e2e03bf3e9fbe3890ca5f8cca", + "isProxy": false, + "name": "FallbackRoutingHook" + }, + { + "address": "0x3A66Dc852e56d3748838b3C27CF381105b83705b", + "constructorArguments": "", + "isProxy": false, + "name": "PausableHook" + }, + { + "address": "0x571f1435613381208477ac5d6974310d88AC7cB7", + "constructorArguments": "000000000000000000000000c005dc82818d67af737725bd4bf75435d065d239000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba00000000000000000000000048e6c30b97748d1e2e03bf3e9fbe3890ca5f8cca", + "isProxy": false, + "name": "FallbackRoutingHook" + }, + { + "address": "0x3A66Dc852e56d3748838b3C27CF381105b83705b", + "constructorArguments": "", + "isProxy": false, + "name": "PausableHook" + }, + { + "address": "0x571f1435613381208477ac5d6974310d88AC7cB7", + "constructorArguments": "000000000000000000000000c005dc82818d67af737725bd4bf75435d065d239000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba00000000000000000000000048e6c30b97748d1e2e03bf3e9fbe3890ca5f8cca", + "isProxy": false, + "name": "FallbackRoutingHook" + }, + { + "address": "0x3A66Dc852e56d3748838b3C27CF381105b83705b", + "constructorArguments": "", + "isProxy": false, + "name": "PausableHook" + }, + { + "address": "0x571f1435613381208477ac5d6974310d88AC7cB7", + "constructorArguments": "000000000000000000000000c005dc82818d67af737725bd4bf75435d065d239000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba00000000000000000000000048e6c30b97748d1e2e03bf3e9fbe3890ca5f8cca", + "isProxy": false, + "name": "FallbackRoutingHook" + }, + { + "address": "0x3A66Dc852e56d3748838b3C27CF381105b83705b", + "constructorArguments": "", + "isProxy": false, + "name": "PausableHook" + } + ], + "gnosis": [ + { + "address": "0x53642476e24E28c3218E8Da44eDEBB4adB9DE13e", + "constructorArguments": "0000000000000000000000000000000000000000000000000000000000000064", + "isProxy": false, + "name": "Mailbox" + }, + { + "address": "0xaD09d78f4c6b9dA2Ae82b1D34107802d380Bb74f", + "constructorArguments": "00000000000000000000000053642476e24e28c3218e8da44edebb4adb9de13e00000000000000000000000081a92a1a272cb09d7b4970b07548463dc7ae0cb700000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000000", + "isProxy": true, + "name": "TransparentUpgradeableProxy" + }, + { + "address": "0x53642476e24E28c3218E8Da44eDEBB4adB9DE13e", + "constructorArguments": "0000000000000000000000000000000000000000000000000000000000000064", + "isProxy": false, + "name": "Mailbox" + }, + { + "address": "0xaD09d78f4c6b9dA2Ae82b1D34107802d380Bb74f", + "constructorArguments": "00000000000000000000000053642476e24e28c3218e8da44edebb4adb9de13e00000000000000000000000081a92a1a272cb09d7b4970b07548463dc7ae0cb700000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000000", + "isProxy": true, + "name": "TransparentUpgradeableProxy" + }, + { + "address": "0x9c2214467Daf9e2e1F45b36d08ce0b9C65BFeA88", + "constructorArguments": "000000000000000000000000000000000000000000000000000000003b9aca000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba", + "isProxy": false, + "name": "ProtocolFee" + }, + { + "address": "0x9c2214467Daf9e2e1F45b36d08ce0b9C65BFeA88", + "constructorArguments": "000000000000000000000000000000000000000000000000000000003b9aca000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba", + "isProxy": false, + "name": "ProtocolFee" + }, + { + "address": "0x87ED6926abc9E38b9C7C19f835B41943b622663c", + "constructorArguments": "000000000000000000000000ad09d78f4c6b9da2ae82b1d34107802d380bb74f", + "isProxy": false, + "name": "ValidatorAnnounce" + }, + { + "address": "0x24f5E353dD03E103Ba2372F7D6FC0cf3A66f849c", + "constructorArguments": "000000000000000000000000ad09d78f4c6b9da2ae82b1d34107802d380bb74f000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba0000000000000000000000002684c6f89e901987e1fdb7649dc5be0c57c61645", + "isProxy": false, + "name": "FallbackRoutingHook" + }, + { + "address": "0xf728C884De5275a608dEC222dACd0f2BF2E23AB6", + "constructorArguments": "", + "isProxy": false, + "name": "PausableHook" + }, + { + "address": "0x24f5E353dD03E103Ba2372F7D6FC0cf3A66f849c", + "constructorArguments": "000000000000000000000000ad09d78f4c6b9da2ae82b1d34107802d380bb74f000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba0000000000000000000000002684c6f89e901987e1fdb7649dc5be0c57c61645", + "isProxy": false, + "name": "FallbackRoutingHook" + }, + { + "address": "0xf728C884De5275a608dEC222dACd0f2BF2E23AB6", + "constructorArguments": "", + "isProxy": false, + "name": "PausableHook" + }, + { + "address": "0x24f5E353dD03E103Ba2372F7D6FC0cf3A66f849c", + "constructorArguments": "000000000000000000000000ad09d78f4c6b9da2ae82b1d34107802d380bb74f000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba0000000000000000000000002684c6f89e901987e1fdb7649dc5be0c57c61645", + "isProxy": false, + "name": "FallbackRoutingHook" + }, + { + "address": "0xf728C884De5275a608dEC222dACd0f2BF2E23AB6", + "constructorArguments": "", + "isProxy": false, + "name": "PausableHook" + }, + { + "address": "0x24f5E353dD03E103Ba2372F7D6FC0cf3A66f849c", + "constructorArguments": "000000000000000000000000ad09d78f4c6b9da2ae82b1d34107802d380bb74f000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba0000000000000000000000002684c6f89e901987e1fdb7649dc5be0c57c61645", + "isProxy": false, + "name": "FallbackRoutingHook" + }, + { + "address": "0xf728C884De5275a608dEC222dACd0f2BF2E23AB6", + "constructorArguments": "", + "isProxy": false, + "name": "PausableHook" + } + ], + "inevm": [ + { + "address": "0x0761b0827849abbf7b0cC09CE14e1C93D87f5004", + "constructorArguments": "", + "isProxy": false, + "name": "ProxyAdmin" + }, + { + "address": "0x4Ed7d626f1E96cD1C0401607Bf70D95243E3dEd1", + "constructorArguments": "00000000000000000000000000000000000000000000000000000000000009dd", + "isProxy": false, + "name": "Mailbox" + }, + { + "address": "0x2f2aFaE1139Ce54feFC03593FeE8AB2aDF4a85A7", + "constructorArguments": "0000000000000000000000004ed7d626f1e96cd1c0401607bf70d95243e3ded10000000000000000000000000761b0827849abbf7b0cc09ce14e1c93d87f500400000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000000", + "isProxy": true, + "name": "TransparentUpgradeableProxy" + }, + { + "address": "0x0972954923a1e2b2aAb04Fa0c4a0797e5989Cd65", + "constructorArguments": "0000000000000000000000002f2afae1139ce54fefc03593fee8ab2adf4a85a7", + "isProxy": false, + "name": "MerkleTreeHook" + }, + { + "address": "0x6119E37Bd66406A1Db74920aC79C15fB8411Ba76", + "constructorArguments": "", + "isProxy": false, + "name": "StorageGasOracle" + }, + { + "address": "0x481171eb1aad17eDE6a56005B7F1aB00C581ef13", + "constructorArguments": "", + "isProxy": false, + "name": "InterchainGasPaymaster" + }, + { + "address": "0x19dc38aeae620380430C200a6E990D5Af5480117", + "constructorArguments": "000000000000000000000000481171eb1aad17ede6a56005b7f1ab00c581ef130000000000000000000000000761b0827849abbf7b0cc09ce14e1c93d87f500400000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000044485cc955000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba00000000000000000000000000000000000000000000000000000000", + "isProxy": true, + "name": "TransparentUpgradeableProxy" + }, + { + "address": "0x0972954923a1e2b2aAb04Fa0c4a0797e5989Cd65", + "constructorArguments": "0000000000000000000000002f2afae1139ce54fefc03593fee8ab2adf4a85a7", + "isProxy": false, + "name": "MerkleTreeHook" + }, + { + "address": "0x6119E37Bd66406A1Db74920aC79C15fB8411Ba76", + "constructorArguments": "", + "isProxy": false, + "name": "StorageGasOracle" + }, + { + "address": "0x481171eb1aad17eDE6a56005B7F1aB00C581ef13", + "constructorArguments": "", + "isProxy": false, + "name": "InterchainGasPaymaster" + }, + { + "address": "0x19dc38aeae620380430C200a6E990D5Af5480117", + "constructorArguments": "000000000000000000000000481171eb1aad17ede6a56005b7f1ab00c581ef130000000000000000000000000761b0827849abbf7b0cc09ce14e1c93d87f500400000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000044485cc955000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba00000000000000000000000000000000000000000000000000000000", + "isProxy": true, + "name": "TransparentUpgradeableProxy" + }, + { + "address": "0x0D63128D887159d63De29497dfa45AFc7C699AE4", + "constructorArguments": "000000000000000000000000000000000000000000000000000000003b9aca000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba", + "isProxy": false, + "name": "ProtocolFee" + }, + { + "address": "0x15ab173bDB6832f9b64276bA128659b0eD77730B", + "constructorArguments": "0000000000000000000000002f2afae1139ce54fefc03593fee8ab2adf4a85a7", + "isProxy": false, + "name": "ValidatorAnnounce" + }, + { + "address": "0xBDa330Ea8F3005C421C8088e638fBB64fA71b9e0", + "constructorArguments": "", + "isProxy": false, + "name": "PausableHook" + }, + { + "address": "0xBDa330Ea8F3005C421C8088e638fBB64fA71b9e0", + "constructorArguments": "", + "isProxy": false, + "name": "PausableHook" + } + ], + "mantapacific": [ + { + "address": "0x2f2aFaE1139Ce54feFC03593FeE8AB2aDF4a85A7", + "constructorArguments": "", + "isProxy": false, + "name": "ProxyAdmin" + }, + { + "address": "0xeA87ae93Fa0019a82A727bfd3eBd1cFCa8f64f1D", + "constructorArguments": "00000000000000000000000000000000000000000000000000000000000000a9", + "isProxy": false, + "name": "Mailbox" + }, + { + "address": "0x3a464f746D23Ab22155710f44dB16dcA53e0775E", + "constructorArguments": "000000000000000000000000ea87ae93fa0019a82a727bfd3ebd1cfca8f64f1d0000000000000000000000002f2afae1139ce54fefc03593fee8ab2adf4a85a700000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000000", + "isProxy": true, + "name": "TransparentUpgradeableProxy" + }, + { + "address": "0x149db7afD694722747035d5AEC7007ccb6F8f112", + "constructorArguments": "0000000000000000000000003a464f746d23ab22155710f44db16dca53e0775e", + "isProxy": false, + "name": "MerkleTreeHook" + }, + { + "address": "0x19dc38aeae620380430C200a6E990D5Af5480117", + "constructorArguments": "", + "isProxy": false, + "name": "StorageGasOracle" + }, + { + "address": "0xBF12ef4B9f307463D3FB59c3604F294dDCe287E2", + "constructorArguments": "", + "isProxy": false, + "name": "InterchainGasPaymaster" + }, + { + "address": "0x0D63128D887159d63De29497dfa45AFc7C699AE4", + "constructorArguments": "000000000000000000000000bf12ef4b9f307463d3fb59c3604f294ddce287e20000000000000000000000002f2afae1139ce54fefc03593fee8ab2adf4a85a700000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000044485cc955000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba00000000000000000000000000000000000000000000000000000000", + "isProxy": true, + "name": "TransparentUpgradeableProxy" + }, + { + "address": "0x149db7afD694722747035d5AEC7007ccb6F8f112", + "constructorArguments": "0000000000000000000000003a464f746d23ab22155710f44db16dca53e0775e", + "isProxy": false, + "name": "MerkleTreeHook" + }, + { + "address": "0x19dc38aeae620380430C200a6E990D5Af5480117", + "constructorArguments": "", + "isProxy": false, + "name": "StorageGasOracle" + }, + { + "address": "0xBF12ef4B9f307463D3FB59c3604F294dDCe287E2", + "constructorArguments": "", + "isProxy": false, + "name": "InterchainGasPaymaster" + }, + { + "address": "0x0D63128D887159d63De29497dfa45AFc7C699AE4", + "constructorArguments": "000000000000000000000000bf12ef4b9f307463d3fb59c3604f294ddce287e20000000000000000000000002f2afae1139ce54fefc03593fee8ab2adf4a85a700000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000044485cc955000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba00000000000000000000000000000000000000000000000000000000", + "isProxy": true, + "name": "TransparentUpgradeableProxy" + }, + { + "address": "0xd83A4F747fE80Ed98839e05079B1B7Fe037b1638", + "constructorArguments": "000000000000000000000000000000000000000000000000000000003b9aca000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba", + "isProxy": false, + "name": "ProtocolFee" + }, + { + "address": "0x2fa5F5C96419C222cDbCeC797D696e6cE428A7A9", + "constructorArguments": "0000000000000000000000003a464f746d23ab22155710f44db16dca53e0775e", + "isProxy": false, + "name": "ValidatorAnnounce" + }, + { + "address": "0xD1E267d2d7876e97E217BfE61c34AB50FEF52807", + "constructorArguments": "0000000000000000000000003a464f746d23ab22155710f44db16dca53e0775e000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba000000000000000000000000149db7afd694722747035d5aec7007ccb6f8f112", + "isProxy": false, + "name": "FallbackRoutingHook" + }, + { + "address": "0x7556a0E61d577D921Cba8Fca0d7D6299d36E607E", + "constructorArguments": "", + "isProxy": false, + "name": "PausableHook" + }, + { + "address": "0xD1E267d2d7876e97E217BfE61c34AB50FEF52807", + "constructorArguments": "0000000000000000000000003a464f746d23ab22155710f44db16dca53e0775e000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba000000000000000000000000149db7afd694722747035d5aec7007ccb6f8f112", + "isProxy": false, + "name": "FallbackRoutingHook" + }, + { + "address": "0x7556a0E61d577D921Cba8Fca0d7D6299d36E607E", + "constructorArguments": "", + "isProxy": false, + "name": "PausableHook" + } + ], + "mode": [ + { + "address": "0x0761b0827849abbf7b0cC09CE14e1C93D87f5004", + "constructorArguments": "", + "isProxy": false, + "name": "ProxyAdmin" + }, + { + "address": "0x4Ed7d626f1E96cD1C0401607Bf70D95243E3dEd1", + "constructorArguments": "000000000000000000000000000000000000000000000000000000000000868b", + "isProxy": false, + "name": "Mailbox" + }, + { + "address": "0x2f2aFaE1139Ce54feFC03593FeE8AB2aDF4a85A7", + "constructorArguments": "0000000000000000000000004ed7d626f1e96cd1c0401607bf70d95243e3ded10000000000000000000000000761b0827849abbf7b0cc09ce14e1c93d87f500400000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000000", + "isProxy": true, + "name": "TransparentUpgradeableProxy" + }, + { + "address": "0x61DDB465eEA5bc3708Cf8B53156aC91a77A2f029", + "constructorArguments": "000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba", + "isProxy": false, + "name": "PausableIsm" + }, + { + "address": "0xE2ee936bEa8e42671c400aC96dE198E06F2bA2A6", + "constructorArguments": "0000000000000000000000002f2afae1139ce54fefc03593fee8ab2adf4a85a7", + "isProxy": false, + "name": "MerkleTreeHook" + }, + { + "address": "0x8F1E22d309baa69D398a03cc88E9b46037e988AA", + "constructorArguments": "0000000000000000000000002f2afae1139ce54fefc03593fee8ab2adf4a85a7000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba000000000000000000000000e2ee936bea8e42671c400ac96de198e06f2ba2a6", + "isProxy": false, + "name": "FallbackRoutingHook" + }, + { + "address": "0xA1ac41d8A663fd317cc3BD94C7de92dC4BA4a882", + "constructorArguments": "", + "isProxy": false, + "name": "PausableHook" + }, + { + "address": "0xC9B8ea6230d6687a4b13fD3C0b8f0Ec607B26465", + "constructorArguments": "", + "isProxy": false, + "name": "StorageGasOracle" + }, + { + "address": "0xE0C452DDA7506f0F4dE5C8C1d383F7aD866eA4F0", + "constructorArguments": "", + "isProxy": false, + "name": "InterchainGasPaymaster" + }, + { + "address": "0x931dFCc8c1141D6F532FD023bd87DAe0080c835d", + "constructorArguments": "000000000000000000000000e0c452dda7506f0f4de5c8c1d383f7ad866ea4f00000000000000000000000000761b0827849abbf7b0cc09ce14e1c93d87f500400000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000044485cc955000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba00000000000000000000000000000000000000000000000000000000", + "isProxy": true, + "name": "TransparentUpgradeableProxy" + }, + { + "address": "0xC9B8ea6230d6687a4b13fD3C0b8f0Ec607B26465", + "constructorArguments": "", + "isProxy": false, + "name": "StorageGasOracle" + }, + { + "address": "0xE0C452DDA7506f0F4dE5C8C1d383F7aD866eA4F0", + "constructorArguments": "", + "isProxy": false, + "name": "InterchainGasPaymaster" + }, + { + "address": "0x931dFCc8c1141D6F532FD023bd87DAe0080c835d", + "constructorArguments": "000000000000000000000000e0c452dda7506f0f4de5c8c1d383f7ad866ea4f00000000000000000000000000761b0827849abbf7b0cc09ce14e1c93d87f500400000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000044485cc955000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba00000000000000000000000000000000000000000000000000000000", + "isProxy": true, + "name": "TransparentUpgradeableProxy" + }, + { + "address": "0xC9B8ea6230d6687a4b13fD3C0b8f0Ec607B26465", + "constructorArguments": "", + "isProxy": false, + "name": "StorageGasOracle" + }, + { + "address": "0xE0C452DDA7506f0F4dE5C8C1d383F7aD866eA4F0", + "constructorArguments": "", + "isProxy": false, + "name": "InterchainGasPaymaster" + }, + { + "address": "0x931dFCc8c1141D6F532FD023bd87DAe0080c835d", + "constructorArguments": "000000000000000000000000e0c452dda7506f0f4de5c8c1d383f7ad866ea4f00000000000000000000000000761b0827849abbf7b0cc09ce14e1c93d87f500400000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000044485cc955000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba00000000000000000000000000000000000000000000000000000000", + "isProxy": true, + "name": "TransparentUpgradeableProxy" + }, + { + "address": "0xC9B8ea6230d6687a4b13fD3C0b8f0Ec607B26465", + "constructorArguments": "", + "isProxy": false, + "name": "StorageGasOracle" + }, + { + "address": "0xE0C452DDA7506f0F4dE5C8C1d383F7aD866eA4F0", + "constructorArguments": "", + "isProxy": false, + "name": "InterchainGasPaymaster" + }, + { + "address": "0x931dFCc8c1141D6F532FD023bd87DAe0080c835d", + "constructorArguments": "000000000000000000000000e0c452dda7506f0f4de5c8c1d383f7ad866ea4f00000000000000000000000000761b0827849abbf7b0cc09ce14e1c93d87f500400000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000044485cc955000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba00000000000000000000000000000000000000000000000000000000", + "isProxy": true, + "name": "TransparentUpgradeableProxy" + }, + { + "address": "0xC9B8ea6230d6687a4b13fD3C0b8f0Ec607B26465", + "constructorArguments": "", + "isProxy": false, + "name": "StorageGasOracle" + }, + { + "address": "0xE0C452DDA7506f0F4dE5C8C1d383F7aD866eA4F0", + "constructorArguments": "", + "isProxy": false, + "name": "InterchainGasPaymaster" + }, + { + "address": "0x931dFCc8c1141D6F532FD023bd87DAe0080c835d", + "constructorArguments": "000000000000000000000000e0c452dda7506f0f4de5c8c1d383f7ad866ea4f00000000000000000000000000761b0827849abbf7b0cc09ce14e1c93d87f500400000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000044485cc955000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba00000000000000000000000000000000000000000000000000000000", + "isProxy": true, + "name": "TransparentUpgradeableProxy" + }, + { + "address": "0xC9B8ea6230d6687a4b13fD3C0b8f0Ec607B26465", + "constructorArguments": "", + "isProxy": false, + "name": "StorageGasOracle" + }, + { + "address": "0xE0C452DDA7506f0F4dE5C8C1d383F7aD866eA4F0", + "constructorArguments": "", + "isProxy": false, + "name": "InterchainGasPaymaster" + }, + { + "address": "0x931dFCc8c1141D6F532FD023bd87DAe0080c835d", + "constructorArguments": "000000000000000000000000e0c452dda7506f0f4de5c8c1d383f7ad866ea4f00000000000000000000000000761b0827849abbf7b0cc09ce14e1c93d87f500400000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000044485cc955000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba00000000000000000000000000000000000000000000000000000000", + "isProxy": true, + "name": "TransparentUpgradeableProxy" + }, + { + "address": "0xC9B8ea6230d6687a4b13fD3C0b8f0Ec607B26465", + "constructorArguments": "", + "isProxy": false, + "name": "StorageGasOracle" + }, + { + "address": "0xE0C452DDA7506f0F4dE5C8C1d383F7aD866eA4F0", + "constructorArguments": "", + "isProxy": false, + "name": "InterchainGasPaymaster" + }, + { + "address": "0x931dFCc8c1141D6F532FD023bd87DAe0080c835d", + "constructorArguments": "000000000000000000000000e0c452dda7506f0f4de5c8c1d383f7ad866ea4f00000000000000000000000000761b0827849abbf7b0cc09ce14e1c93d87f500400000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000044485cc955000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba00000000000000000000000000000000000000000000000000000000", + "isProxy": true, + "name": "TransparentUpgradeableProxy" + }, + { + "address": "0xC9B8ea6230d6687a4b13fD3C0b8f0Ec607B26465", + "constructorArguments": "", + "isProxy": false, + "name": "StorageGasOracle" + }, + { + "address": "0xE0C452DDA7506f0F4dE5C8C1d383F7aD866eA4F0", + "constructorArguments": "", + "isProxy": false, + "name": "InterchainGasPaymaster" + }, + { + "address": "0x931dFCc8c1141D6F532FD023bd87DAe0080c835d", + "constructorArguments": "000000000000000000000000e0c452dda7506f0f4de5c8c1d383f7ad866ea4f00000000000000000000000000761b0827849abbf7b0cc09ce14e1c93d87f500400000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000044485cc955000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba00000000000000000000000000000000000000000000000000000000", + "isProxy": true, + "name": "TransparentUpgradeableProxy" + }, + { + "address": "0xC9B8ea6230d6687a4b13fD3C0b8f0Ec607B26465", + "constructorArguments": "", + "isProxy": false, + "name": "StorageGasOracle" + }, + { + "address": "0xE0C452DDA7506f0F4dE5C8C1d383F7aD866eA4F0", + "constructorArguments": "", + "isProxy": false, + "name": "InterchainGasPaymaster" + }, + { + "address": "0x931dFCc8c1141D6F532FD023bd87DAe0080c835d", + "constructorArguments": "000000000000000000000000e0c452dda7506f0f4de5c8c1d383f7ad866ea4f00000000000000000000000000761b0827849abbf7b0cc09ce14e1c93d87f500400000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000044485cc955000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba00000000000000000000000000000000000000000000000000000000", + "isProxy": true, + "name": "TransparentUpgradeableProxy" + }, + { + "address": "0xC9B8ea6230d6687a4b13fD3C0b8f0Ec607B26465", + "constructorArguments": "", + "isProxy": false, + "name": "StorageGasOracle" + }, + { + "address": "0xE0C452DDA7506f0F4dE5C8C1d383F7aD866eA4F0", + "constructorArguments": "", + "isProxy": false, + "name": "InterchainGasPaymaster" + }, + { + "address": "0x931dFCc8c1141D6F532FD023bd87DAe0080c835d", + "constructorArguments": "000000000000000000000000e0c452dda7506f0f4de5c8c1d383f7ad866ea4f00000000000000000000000000761b0827849abbf7b0cc09ce14e1c93d87f500400000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000044485cc955000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba00000000000000000000000000000000000000000000000000000000", + "isProxy": true, + "name": "TransparentUpgradeableProxy" + }, + { + "address": "0xC9B8ea6230d6687a4b13fD3C0b8f0Ec607B26465", + "constructorArguments": "", + "isProxy": false, + "name": "StorageGasOracle" + }, + { + "address": "0xE0C452DDA7506f0F4dE5C8C1d383F7aD866eA4F0", + "constructorArguments": "", + "isProxy": false, + "name": "InterchainGasPaymaster" + }, + { + "address": "0x931dFCc8c1141D6F532FD023bd87DAe0080c835d", + "constructorArguments": "000000000000000000000000e0c452dda7506f0f4de5c8c1d383f7ad866ea4f00000000000000000000000000761b0827849abbf7b0cc09ce14e1c93d87f500400000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000044485cc955000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba00000000000000000000000000000000000000000000000000000000", + "isProxy": true, + "name": "TransparentUpgradeableProxy" + }, + { + "address": "0xC9B8ea6230d6687a4b13fD3C0b8f0Ec607B26465", + "constructorArguments": "", + "isProxy": false, + "name": "StorageGasOracle" + }, + { + "address": "0xE0C452DDA7506f0F4dE5C8C1d383F7aD866eA4F0", + "constructorArguments": "", + "isProxy": false, + "name": "InterchainGasPaymaster" + }, + { + "address": "0x931dFCc8c1141D6F532FD023bd87DAe0080c835d", + "constructorArguments": "000000000000000000000000e0c452dda7506f0f4de5c8c1d383f7ad866ea4f00000000000000000000000000761b0827849abbf7b0cc09ce14e1c93d87f500400000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000044485cc955000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba00000000000000000000000000000000000000000000000000000000", + "isProxy": true, + "name": "TransparentUpgradeableProxy" + }, + { + "address": "0xC9B8ea6230d6687a4b13fD3C0b8f0Ec607B26465", + "constructorArguments": "", + "isProxy": false, + "name": "StorageGasOracle" + }, + { + "address": "0xE0C452DDA7506f0F4dE5C8C1d383F7aD866eA4F0", + "constructorArguments": "", + "isProxy": false, + "name": "InterchainGasPaymaster" + }, + { + "address": "0x931dFCc8c1141D6F532FD023bd87DAe0080c835d", + "constructorArguments": "000000000000000000000000e0c452dda7506f0f4de5c8c1d383f7ad866ea4f00000000000000000000000000761b0827849abbf7b0cc09ce14e1c93d87f500400000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000044485cc955000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba00000000000000000000000000000000000000000000000000000000", + "isProxy": true, + "name": "TransparentUpgradeableProxy" + }, + { + "address": "0xC9B8ea6230d6687a4b13fD3C0b8f0Ec607B26465", + "constructorArguments": "", + "isProxy": false, + "name": "StorageGasOracle" + }, + { + "address": "0xE0C452DDA7506f0F4dE5C8C1d383F7aD866eA4F0", + "constructorArguments": "", + "isProxy": false, + "name": "InterchainGasPaymaster" + }, + { + "address": "0x931dFCc8c1141D6F532FD023bd87DAe0080c835d", + "constructorArguments": "000000000000000000000000e0c452dda7506f0f4de5c8c1d383f7ad866ea4f00000000000000000000000000761b0827849abbf7b0cc09ce14e1c93d87f500400000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000044485cc955000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba00000000000000000000000000000000000000000000000000000000", + "isProxy": true, + "name": "TransparentUpgradeableProxy" + }, + { + "address": "0xC9B8ea6230d6687a4b13fD3C0b8f0Ec607B26465", + "constructorArguments": "", + "isProxy": false, + "name": "StorageGasOracle" + }, + { + "address": "0xE0C452DDA7506f0F4dE5C8C1d383F7aD866eA4F0", + "constructorArguments": "", + "isProxy": false, + "name": "InterchainGasPaymaster" + }, + { + "address": "0x931dFCc8c1141D6F532FD023bd87DAe0080c835d", + "constructorArguments": "000000000000000000000000e0c452dda7506f0f4de5c8c1d383f7ad866ea4f00000000000000000000000000761b0827849abbf7b0cc09ce14e1c93d87f500400000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000044485cc955000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba00000000000000000000000000000000000000000000000000000000", + "isProxy": true, + "name": "TransparentUpgradeableProxy" + }, + { + "address": "0xC9B8ea6230d6687a4b13fD3C0b8f0Ec607B26465", + "constructorArguments": "", + "isProxy": false, + "name": "StorageGasOracle" + }, + { + "address": "0xE0C452DDA7506f0F4dE5C8C1d383F7aD866eA4F0", + "constructorArguments": "", + "isProxy": false, + "name": "InterchainGasPaymaster" + }, + { + "address": "0x931dFCc8c1141D6F532FD023bd87DAe0080c835d", + "constructorArguments": "000000000000000000000000e0c452dda7506f0f4de5c8c1d383f7ad866ea4f00000000000000000000000000761b0827849abbf7b0cc09ce14e1c93d87f500400000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000044485cc955000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba00000000000000000000000000000000000000000000000000000000", + "isProxy": true, + "name": "TransparentUpgradeableProxy" + }, + { + "address": "0xC9B8ea6230d6687a4b13fD3C0b8f0Ec607B26465", + "constructorArguments": "", + "isProxy": false, + "name": "StorageGasOracle" + }, + { + "address": "0xE0C452DDA7506f0F4dE5C8C1d383F7aD866eA4F0", + "constructorArguments": "", + "isProxy": false, + "name": "InterchainGasPaymaster" + }, + { + "address": "0x931dFCc8c1141D6F532FD023bd87DAe0080c835d", + "constructorArguments": "000000000000000000000000e0c452dda7506f0f4de5c8c1d383f7ad866ea4f00000000000000000000000000761b0827849abbf7b0cc09ce14e1c93d87f500400000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000044485cc955000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba00000000000000000000000000000000000000000000000000000000", + "isProxy": true, + "name": "TransparentUpgradeableProxy" + }, + { + "address": "0xC9B8ea6230d6687a4b13fD3C0b8f0Ec607B26465", + "constructorArguments": "", + "isProxy": false, + "name": "StorageGasOracle" + }, + { + "address": "0xE0C452DDA7506f0F4dE5C8C1d383F7aD866eA4F0", + "constructorArguments": "", + "isProxy": false, + "name": "InterchainGasPaymaster" + }, + { + "address": "0x931dFCc8c1141D6F532FD023bd87DAe0080c835d", + "constructorArguments": "000000000000000000000000e0c452dda7506f0f4de5c8c1d383f7ad866ea4f00000000000000000000000000761b0827849abbf7b0cc09ce14e1c93d87f500400000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000044485cc955000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba00000000000000000000000000000000000000000000000000000000", + "isProxy": true, + "name": "TransparentUpgradeableProxy" + }, + { + "address": "0xC9B8ea6230d6687a4b13fD3C0b8f0Ec607B26465", + "constructorArguments": "", + "isProxy": false, + "name": "StorageGasOracle" + }, + { + "address": "0xE0C452DDA7506f0F4dE5C8C1d383F7aD866eA4F0", + "constructorArguments": "", + "isProxy": false, + "name": "InterchainGasPaymaster" + }, + { + "address": "0x931dFCc8c1141D6F532FD023bd87DAe0080c835d", + "constructorArguments": "000000000000000000000000e0c452dda7506f0f4de5c8c1d383f7ad866ea4f00000000000000000000000000761b0827849abbf7b0cc09ce14e1c93d87f500400000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000044485cc955000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba00000000000000000000000000000000000000000000000000000000", + "isProxy": true, + "name": "TransparentUpgradeableProxy" + }, + { + "address": "0xE2ee936bEa8e42671c400aC96dE198E06F2bA2A6", + "constructorArguments": "0000000000000000000000002f2afae1139ce54fefc03593fee8ab2adf4a85a7", + "isProxy": false, + "name": "MerkleTreeHook" + }, + { + "address": "0x8F1E22d309baa69D398a03cc88E9b46037e988AA", + "constructorArguments": "0000000000000000000000002f2afae1139ce54fefc03593fee8ab2adf4a85a7000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba000000000000000000000000e2ee936bea8e42671c400ac96de198e06f2ba2a6", + "isProxy": false, + "name": "FallbackRoutingHook" + }, + { + "address": "0xA1ac41d8A663fd317cc3BD94C7de92dC4BA4a882", + "constructorArguments": "", + "isProxy": false, + "name": "PausableHook" + }, + { + "address": "0xC9B8ea6230d6687a4b13fD3C0b8f0Ec607B26465", + "constructorArguments": "", + "isProxy": false, + "name": "StorageGasOracle" + }, + { + "address": "0xE0C452DDA7506f0F4dE5C8C1d383F7aD866eA4F0", + "constructorArguments": "", + "isProxy": false, + "name": "InterchainGasPaymaster" + }, + { + "address": "0x931dFCc8c1141D6F532FD023bd87DAe0080c835d", + "constructorArguments": "000000000000000000000000e0c452dda7506f0f4de5c8c1d383f7ad866ea4f00000000000000000000000000761b0827849abbf7b0cc09ce14e1c93d87f500400000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000044485cc955000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba00000000000000000000000000000000000000000000000000000000", + "isProxy": true, + "name": "TransparentUpgradeableProxy" + }, + { + "address": "0xC9B8ea6230d6687a4b13fD3C0b8f0Ec607B26465", + "constructorArguments": "", + "isProxy": false, + "name": "StorageGasOracle" + }, + { + "address": "0xE0C452DDA7506f0F4dE5C8C1d383F7aD866eA4F0", + "constructorArguments": "", + "isProxy": false, + "name": "InterchainGasPaymaster" + }, + { + "address": "0x931dFCc8c1141D6F532FD023bd87DAe0080c835d", + "constructorArguments": "000000000000000000000000e0c452dda7506f0f4de5c8c1d383f7ad866ea4f00000000000000000000000000761b0827849abbf7b0cc09ce14e1c93d87f500400000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000044485cc955000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba00000000000000000000000000000000000000000000000000000000", + "isProxy": true, + "name": "TransparentUpgradeableProxy" + }, + { + "address": "0xC9B8ea6230d6687a4b13fD3C0b8f0Ec607B26465", + "constructorArguments": "", + "isProxy": false, + "name": "StorageGasOracle" + }, + { + "address": "0xE0C452DDA7506f0F4dE5C8C1d383F7aD866eA4F0", + "constructorArguments": "", + "isProxy": false, + "name": "InterchainGasPaymaster" + }, + { + "address": "0x931dFCc8c1141D6F532FD023bd87DAe0080c835d", + "constructorArguments": "000000000000000000000000e0c452dda7506f0f4de5c8c1d383f7ad866ea4f00000000000000000000000000761b0827849abbf7b0cc09ce14e1c93d87f500400000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000044485cc955000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba00000000000000000000000000000000000000000000000000000000", + "isProxy": true, + "name": "TransparentUpgradeableProxy" + }, + { + "address": "0xC9B8ea6230d6687a4b13fD3C0b8f0Ec607B26465", + "constructorArguments": "", + "isProxy": false, + "name": "StorageGasOracle" + }, + { + "address": "0xE0C452DDA7506f0F4dE5C8C1d383F7aD866eA4F0", + "constructorArguments": "", + "isProxy": false, + "name": "InterchainGasPaymaster" + }, + { + "address": "0x931dFCc8c1141D6F532FD023bd87DAe0080c835d", + "constructorArguments": "000000000000000000000000e0c452dda7506f0f4de5c8c1d383f7ad866ea4f00000000000000000000000000761b0827849abbf7b0cc09ce14e1c93d87f500400000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000044485cc955000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba00000000000000000000000000000000000000000000000000000000", + "isProxy": true, + "name": "TransparentUpgradeableProxy" + }, + { + "address": "0xC9B8ea6230d6687a4b13fD3C0b8f0Ec607B26465", + "constructorArguments": "", + "isProxy": false, + "name": "StorageGasOracle" + }, + { + "address": "0xE0C452DDA7506f0F4dE5C8C1d383F7aD866eA4F0", + "constructorArguments": "", + "isProxy": false, + "name": "InterchainGasPaymaster" + }, + { + "address": "0x931dFCc8c1141D6F532FD023bd87DAe0080c835d", + "constructorArguments": "000000000000000000000000e0c452dda7506f0f4de5c8c1d383f7ad866ea4f00000000000000000000000000761b0827849abbf7b0cc09ce14e1c93d87f500400000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000044485cc955000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba00000000000000000000000000000000000000000000000000000000", + "isProxy": true, + "name": "TransparentUpgradeableProxy" + }, + { + "address": "0xC9B8ea6230d6687a4b13fD3C0b8f0Ec607B26465", + "constructorArguments": "", + "isProxy": false, + "name": "StorageGasOracle" + }, + { + "address": "0xE0C452DDA7506f0F4dE5C8C1d383F7aD866eA4F0", + "constructorArguments": "", + "isProxy": false, + "name": "InterchainGasPaymaster" + }, + { + "address": "0x931dFCc8c1141D6F532FD023bd87DAe0080c835d", + "constructorArguments": "000000000000000000000000e0c452dda7506f0f4de5c8c1d383f7ad866ea4f00000000000000000000000000761b0827849abbf7b0cc09ce14e1c93d87f500400000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000044485cc955000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba00000000000000000000000000000000000000000000000000000000", + "isProxy": true, + "name": "TransparentUpgradeableProxy" + }, + { + "address": "0xC9B8ea6230d6687a4b13fD3C0b8f0Ec607B26465", + "constructorArguments": "", + "isProxy": false, + "name": "StorageGasOracle" + }, + { + "address": "0xE0C452DDA7506f0F4dE5C8C1d383F7aD866eA4F0", + "constructorArguments": "", + "isProxy": false, + "name": "InterchainGasPaymaster" + }, + { + "address": "0x931dFCc8c1141D6F532FD023bd87DAe0080c835d", + "constructorArguments": "000000000000000000000000e0c452dda7506f0f4de5c8c1d383f7ad866ea4f00000000000000000000000000761b0827849abbf7b0cc09ce14e1c93d87f500400000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000044485cc955000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba00000000000000000000000000000000000000000000000000000000", + "isProxy": true, + "name": "TransparentUpgradeableProxy" + }, + { + "address": "0xC9B8ea6230d6687a4b13fD3C0b8f0Ec607B26465", + "constructorArguments": "", + "isProxy": false, + "name": "StorageGasOracle" + }, + { + "address": "0xE0C452DDA7506f0F4dE5C8C1d383F7aD866eA4F0", + "constructorArguments": "", + "isProxy": false, + "name": "InterchainGasPaymaster" + }, + { + "address": "0x931dFCc8c1141D6F532FD023bd87DAe0080c835d", + "constructorArguments": "000000000000000000000000e0c452dda7506f0f4de5c8c1d383f7ad866ea4f00000000000000000000000000761b0827849abbf7b0cc09ce14e1c93d87f500400000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000044485cc955000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba00000000000000000000000000000000000000000000000000000000", + "isProxy": true, + "name": "TransparentUpgradeableProxy" + }, + { + "address": "0xC9B8ea6230d6687a4b13fD3C0b8f0Ec607B26465", + "constructorArguments": "", + "isProxy": false, + "name": "StorageGasOracle" + }, + { + "address": "0xE0C452DDA7506f0F4dE5C8C1d383F7aD866eA4F0", + "constructorArguments": "", + "isProxy": false, + "name": "InterchainGasPaymaster" + }, + { + "address": "0x931dFCc8c1141D6F532FD023bd87DAe0080c835d", + "constructorArguments": "000000000000000000000000e0c452dda7506f0f4de5c8c1d383f7ad866ea4f00000000000000000000000000761b0827849abbf7b0cc09ce14e1c93d87f500400000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000044485cc955000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba00000000000000000000000000000000000000000000000000000000", + "isProxy": true, + "name": "TransparentUpgradeableProxy" + }, + { + "address": "0xC9B8ea6230d6687a4b13fD3C0b8f0Ec607B26465", + "constructorArguments": "", + "isProxy": false, + "name": "StorageGasOracle" + }, + { + "address": "0xE0C452DDA7506f0F4dE5C8C1d383F7aD866eA4F0", + "constructorArguments": "", + "isProxy": false, + "name": "InterchainGasPaymaster" + }, + { + "address": "0x931dFCc8c1141D6F532FD023bd87DAe0080c835d", + "constructorArguments": "000000000000000000000000e0c452dda7506f0f4de5c8c1d383f7ad866ea4f00000000000000000000000000761b0827849abbf7b0cc09ce14e1c93d87f500400000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000044485cc955000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba00000000000000000000000000000000000000000000000000000000", + "isProxy": true, + "name": "TransparentUpgradeableProxy" + }, + { + "address": "0xC9B8ea6230d6687a4b13fD3C0b8f0Ec607B26465", + "constructorArguments": "", + "isProxy": false, + "name": "StorageGasOracle" + }, + { + "address": "0xE0C452DDA7506f0F4dE5C8C1d383F7aD866eA4F0", + "constructorArguments": "", + "isProxy": false, + "name": "InterchainGasPaymaster" + }, + { + "address": "0x931dFCc8c1141D6F532FD023bd87DAe0080c835d", + "constructorArguments": "000000000000000000000000e0c452dda7506f0f4de5c8c1d383f7ad866ea4f00000000000000000000000000761b0827849abbf7b0cc09ce14e1c93d87f500400000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000044485cc955000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba00000000000000000000000000000000000000000000000000000000", + "isProxy": true, + "name": "TransparentUpgradeableProxy" + }, + { + "address": "0xC9B8ea6230d6687a4b13fD3C0b8f0Ec607B26465", + "constructorArguments": "", + "isProxy": false, + "name": "StorageGasOracle" + }, + { + "address": "0xE0C452DDA7506f0F4dE5C8C1d383F7aD866eA4F0", + "constructorArguments": "", + "isProxy": false, + "name": "InterchainGasPaymaster" + }, + { + "address": "0x931dFCc8c1141D6F532FD023bd87DAe0080c835d", + "constructorArguments": "000000000000000000000000e0c452dda7506f0f4de5c8c1d383f7ad866ea4f00000000000000000000000000761b0827849abbf7b0cc09ce14e1c93d87f500400000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000044485cc955000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba00000000000000000000000000000000000000000000000000000000", + "isProxy": true, + "name": "TransparentUpgradeableProxy" + }, + { + "address": "0xC9B8ea6230d6687a4b13fD3C0b8f0Ec607B26465", + "constructorArguments": "", + "isProxy": false, + "name": "StorageGasOracle" + }, + { + "address": "0xE0C452DDA7506f0F4dE5C8C1d383F7aD866eA4F0", + "constructorArguments": "", + "isProxy": false, + "name": "InterchainGasPaymaster" + }, + { + "address": "0x931dFCc8c1141D6F532FD023bd87DAe0080c835d", + "constructorArguments": "000000000000000000000000e0c452dda7506f0f4de5c8c1d383f7ad866ea4f00000000000000000000000000761b0827849abbf7b0cc09ce14e1c93d87f500400000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000044485cc955000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba00000000000000000000000000000000000000000000000000000000", + "isProxy": true, + "name": "TransparentUpgradeableProxy" + }, + { + "address": "0xC9B8ea6230d6687a4b13fD3C0b8f0Ec607B26465", + "constructorArguments": "", + "isProxy": false, + "name": "StorageGasOracle" + }, + { + "address": "0xE0C452DDA7506f0F4dE5C8C1d383F7aD866eA4F0", + "constructorArguments": "", + "isProxy": false, + "name": "InterchainGasPaymaster" + }, + { + "address": "0x931dFCc8c1141D6F532FD023bd87DAe0080c835d", + "constructorArguments": "000000000000000000000000e0c452dda7506f0f4de5c8c1d383f7ad866ea4f00000000000000000000000000761b0827849abbf7b0cc09ce14e1c93d87f500400000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000044485cc955000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba00000000000000000000000000000000000000000000000000000000", + "isProxy": true, + "name": "TransparentUpgradeableProxy" + }, + { + "address": "0xC9B8ea6230d6687a4b13fD3C0b8f0Ec607B26465", + "constructorArguments": "", + "isProxy": false, + "name": "StorageGasOracle" + }, + { + "address": "0xE0C452DDA7506f0F4dE5C8C1d383F7aD866eA4F0", + "constructorArguments": "", + "isProxy": false, + "name": "InterchainGasPaymaster" + }, + { + "address": "0x931dFCc8c1141D6F532FD023bd87DAe0080c835d", + "constructorArguments": "000000000000000000000000e0c452dda7506f0f4de5c8c1d383f7ad866ea4f00000000000000000000000000761b0827849abbf7b0cc09ce14e1c93d87f500400000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000044485cc955000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba00000000000000000000000000000000000000000000000000000000", + "isProxy": true, + "name": "TransparentUpgradeableProxy" + }, + { + "address": "0xC9B8ea6230d6687a4b13fD3C0b8f0Ec607B26465", + "constructorArguments": "", + "isProxy": false, + "name": "StorageGasOracle" + }, + { + "address": "0xE0C452DDA7506f0F4dE5C8C1d383F7aD866eA4F0", + "constructorArguments": "", + "isProxy": false, + "name": "InterchainGasPaymaster" + }, + { + "address": "0x931dFCc8c1141D6F532FD023bd87DAe0080c835d", + "constructorArguments": "000000000000000000000000e0c452dda7506f0f4de5c8c1d383f7ad866ea4f00000000000000000000000000761b0827849abbf7b0cc09ce14e1c93d87f500400000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000044485cc955000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba00000000000000000000000000000000000000000000000000000000", + "isProxy": true, + "name": "TransparentUpgradeableProxy" + }, + { + "address": "0xC9B8ea6230d6687a4b13fD3C0b8f0Ec607B26465", + "constructorArguments": "", + "isProxy": false, + "name": "StorageGasOracle" + }, + { + "address": "0xE0C452DDA7506f0F4dE5C8C1d383F7aD866eA4F0", + "constructorArguments": "", + "isProxy": false, + "name": "InterchainGasPaymaster" + }, + { + "address": "0x931dFCc8c1141D6F532FD023bd87DAe0080c835d", + "constructorArguments": "000000000000000000000000e0c452dda7506f0f4de5c8c1d383f7ad866ea4f00000000000000000000000000761b0827849abbf7b0cc09ce14e1c93d87f500400000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000044485cc955000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba00000000000000000000000000000000000000000000000000000000", + "isProxy": true, + "name": "TransparentUpgradeableProxy" + }, + { + "address": "0xC9B8ea6230d6687a4b13fD3C0b8f0Ec607B26465", + "constructorArguments": "", + "isProxy": false, + "name": "StorageGasOracle" + }, + { + "address": "0xE0C452DDA7506f0F4dE5C8C1d383F7aD866eA4F0", + "constructorArguments": "", + "isProxy": false, + "name": "InterchainGasPaymaster" + }, + { + "address": "0x931dFCc8c1141D6F532FD023bd87DAe0080c835d", + "constructorArguments": "000000000000000000000000e0c452dda7506f0f4de5c8c1d383f7ad866ea4f00000000000000000000000000761b0827849abbf7b0cc09ce14e1c93d87f500400000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000044485cc955000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba00000000000000000000000000000000000000000000000000000000", + "isProxy": true, + "name": "TransparentUpgradeableProxy" + }, + { + "address": "0xC9B8ea6230d6687a4b13fD3C0b8f0Ec607B26465", + "constructorArguments": "", + "isProxy": false, + "name": "StorageGasOracle" + }, + { + "address": "0xE0C452DDA7506f0F4dE5C8C1d383F7aD866eA4F0", + "constructorArguments": "", + "isProxy": false, + "name": "InterchainGasPaymaster" + }, + { + "address": "0x931dFCc8c1141D6F532FD023bd87DAe0080c835d", + "constructorArguments": "000000000000000000000000e0c452dda7506f0f4de5c8c1d383f7ad866ea4f00000000000000000000000000761b0827849abbf7b0cc09ce14e1c93d87f500400000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000044485cc955000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba00000000000000000000000000000000000000000000000000000000", + "isProxy": true, + "name": "TransparentUpgradeableProxy" + }, + { + "address": "0xea820f9BCFD5E16a0dd42071EB61A29874Ad81A4", + "constructorArguments": "000000000000000000000000000000000000000000000000000000003b9aca000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba", + "isProxy": false, + "name": "ProtocolFee" + }, + { + "address": "0x48083C69f5a42c6B69ABbAd48AE195BD36770ee2", + "constructorArguments": "0000000000000000000000002f2afae1139ce54fefc03593fee8ab2adf4a85a7", + "isProxy": false, + "name": "ValidatorAnnounce" } ], "moonbeam": [ diff --git a/typescript/infra/config/environments/mainnet3/funding.ts b/typescript/infra/config/environments/mainnet3/funding.ts index cf4d8d9d3c..64cf0fd66c 100644 --- a/typescript/infra/config/environments/mainnet3/funding.ts +++ b/typescript/infra/config/environments/mainnet3/funding.ts @@ -28,10 +28,12 @@ export const keyFunderConfig: KeyFunderConfig = { desiredBalancePerChain: { avalanche: '5', bsc: '5', + blast: '0.2', celo: '3', ethereum: '0.5', gnosis: '5', inevm: '3', + mode: '0.2', moonbeam: '5', polygon: '20', viction: '3', diff --git a/typescript/infra/config/environments/mainnet3/gasPrices.json b/typescript/infra/config/environments/mainnet3/gasPrices.json index 66c9fbb0ba..da4e21d7f9 100644 --- a/typescript/infra/config/environments/mainnet3/gasPrices.json +++ b/typescript/infra/config/environments/mainnet3/gasPrices.json @@ -2,10 +2,12 @@ "ancient8": "1", "arbitrum": "0.1", "avalanche": "43.212830197", + "blast": "0.1", "bsc": "1.350070319", "celo": "10.0", "ethereum": "26.346912847", "mantapacific": "0.100000057", + "mode": "0.1", "moonbeam": "125.0", "optimism": "0.003225814", "polygon": "61.601287856", diff --git a/typescript/infra/config/environments/mainnet3/ism/verification.json b/typescript/infra/config/environments/mainnet3/ism/verification.json index 60a4cdf11b..fbbaaf72dc 100644 --- a/typescript/infra/config/environments/mainnet3/ism/verification.json +++ b/typescript/infra/config/environments/mainnet3/ism/verification.json @@ -54,6 +54,126 @@ "isProxy": false, "name": "DomainRoutingIsmFactory" }, + { + "address": "0x12Ed1BbA182CbC63692F813651BD493B7445C874", + "constructorArguments": "", + "isProxy": true, + "name": "DomaingRoutingIsm" + }, + { + "address": "0x4725F7b8037513915aAf6D6CBDE2920E28540dDc", + "constructorArguments": "", + "isProxy": true, + "name": "StaticMerkleRootMultisigIsm" + }, + { + "address": "0xAF03386044373E2fe26C5b1dCedF5a7e854a7a3F", + "constructorArguments": "", + "isProxy": true, + "name": "StaticMessageIdMultisigIsm" + }, + { + "address": "0x882CD0C5D50b6dD74b36Da4BDb059507fddEDdf2", + "constructorArguments": "", + "isProxy": true, + "name": "StaticAggregationIsm" + }, + { + "address": "0x19930232E9aFC4f4F09d09fe2375680fAc2100D0", + "constructorArguments": "", + "isProxy": true, + "name": "StaticAggregationHook" + }, + { + "address": "0x12Ed1BbA182CbC63692F813651BD493B7445C874", + "constructorArguments": "", + "isProxy": true, + "name": "DomaingRoutingIsm" + }, + { + "address": "0x4725F7b8037513915aAf6D6CBDE2920E28540dDc", + "constructorArguments": "", + "isProxy": true, + "name": "StaticMerkleRootMultisigIsm" + }, + { + "address": "0xAF03386044373E2fe26C5b1dCedF5a7e854a7a3F", + "constructorArguments": "", + "isProxy": true, + "name": "StaticMessageIdMultisigIsm" + }, + { + "address": "0x882CD0C5D50b6dD74b36Da4BDb059507fddEDdf2", + "constructorArguments": "", + "isProxy": true, + "name": "StaticAggregationIsm" + }, + { + "address": "0x19930232E9aFC4f4F09d09fe2375680fAc2100D0", + "constructorArguments": "", + "isProxy": true, + "name": "StaticAggregationHook" + }, + { + "address": "0x12Ed1BbA182CbC63692F813651BD493B7445C874", + "constructorArguments": "", + "isProxy": true, + "name": "DomaingRoutingIsm" + }, + { + "address": "0x4725F7b8037513915aAf6D6CBDE2920E28540dDc", + "constructorArguments": "", + "isProxy": true, + "name": "StaticMerkleRootMultisigIsm" + }, + { + "address": "0xAF03386044373E2fe26C5b1dCedF5a7e854a7a3F", + "constructorArguments": "", + "isProxy": true, + "name": "StaticMessageIdMultisigIsm" + }, + { + "address": "0x882CD0C5D50b6dD74b36Da4BDb059507fddEDdf2", + "constructorArguments": "", + "isProxy": true, + "name": "StaticAggregationIsm" + }, + { + "address": "0x19930232E9aFC4f4F09d09fe2375680fAc2100D0", + "constructorArguments": "", + "isProxy": true, + "name": "StaticAggregationHook" + }, + { + "address": "0x12Ed1BbA182CbC63692F813651BD493B7445C874", + "constructorArguments": "", + "isProxy": true, + "name": "DomaingRoutingIsm" + }, + { + "address": "0x4725F7b8037513915aAf6D6CBDE2920E28540dDc", + "constructorArguments": "", + "isProxy": true, + "name": "StaticMerkleRootMultisigIsm" + }, + { + "address": "0xAF03386044373E2fe26C5b1dCedF5a7e854a7a3F", + "constructorArguments": "", + "isProxy": true, + "name": "StaticMessageIdMultisigIsm" + }, + { + "address": "0x882CD0C5D50b6dD74b36Da4BDb059507fddEDdf2", + "constructorArguments": "", + "isProxy": true, + "name": "StaticAggregationIsm" + }, + { + "address": "0x19930232E9aFC4f4F09d09fe2375680fAc2100D0", + "constructorArguments": "", + "isProxy": true, + "name": "StaticAggregationHook" + }, { "address": "0x12Ed1BbA182CbC63692F813651BD493B7445C874", "constructorArguments": "", @@ -63,356 +183,776 @@ ], "arbitrum": [ { - "address": "0x3C330D4A2e2b8443AFaB8E326E64ab4251B7Eae0", + "address": "0x3C330D4A2e2b8443AFaB8E326E64ab4251B7Eae0", + "constructorArguments": "", + "isProxy": false, + "name": "StaticMerkleRootMultisigIsmFactory" + }, + { + "address": "0xEbA276cdC61D4BC954E80985aC8FD71453fDab8e", + "constructorArguments": "", + "isProxy": true, + "name": "StaticMerkleRootMultisigIsm" + }, + { + "address": "0x12Df53079d399a47e9E730df095b712B0FDFA791", + "constructorArguments": "", + "isProxy": false, + "name": "StaticMessageIdMultisigIsmFactory" + }, + { + "address": "0xfD122f59ee8073528Cc5d36D5cc1451Bf1aF6923", + "constructorArguments": "", + "isProxy": true, + "name": "StaticMessageIdMultisigIsm" + }, + { + "address": "0xD4883084389fC1Eeb4dAfB2ADcFc36B711c310EB", + "constructorArguments": "", + "isProxy": false, + "name": "StaticAggregationIsmFactory" + }, + { + "address": "0xBbc6e404F8d841560261b036cA3468B55CB9f566", + "constructorArguments": "", + "isProxy": true, + "name": "StaticAggregationIsm" + }, + { + "address": "0x9B5f440bBb64Fee337F37e03362b628711Ea09C7", + "constructorArguments": "", + "isProxy": false, + "name": "StaticAggregationHookFactory" + }, + { + "address": "0x97c5dC51adAa04B3BefE63F4e62e4778219D9426", + "constructorArguments": "", + "isProxy": true, + "name": "StaticAggregationHook" + }, + { + "address": "0xC020F8A7b00178dFA0fcC75C159e14b79F8e5c63", + "constructorArguments": "", + "isProxy": false, + "name": "DomainRoutingIsmFactory" + }, + { + "address": "0xc0Ce143F44ADc65d35fB0d24436Eaa953380dF97", + "constructorArguments": "", + "isProxy": true, + "name": "DomaingRoutingIsm" + }, + { + "address": "0xEbA276cdC61D4BC954E80985aC8FD71453fDab8e", + "constructorArguments": "", + "isProxy": true, + "name": "StaticMerkleRootMultisigIsm" + }, + { + "address": "0xfD122f59ee8073528Cc5d36D5cc1451Bf1aF6923", + "constructorArguments": "", + "isProxy": true, + "name": "StaticMessageIdMultisigIsm" + }, + { + "address": "0xBbc6e404F8d841560261b036cA3468B55CB9f566", + "constructorArguments": "", + "isProxy": true, + "name": "StaticAggregationIsm" + }, + { + "address": "0x97c5dC51adAa04B3BefE63F4e62e4778219D9426", + "constructorArguments": "", + "isProxy": true, + "name": "StaticAggregationHook" + }, + { + "address": "0xc0Ce143F44ADc65d35fB0d24436Eaa953380dF97", + "constructorArguments": "", + "isProxy": true, + "name": "DomaingRoutingIsm" + }, + { + "address": "0xEbA276cdC61D4BC954E80985aC8FD71453fDab8e", + "constructorArguments": "", + "isProxy": true, + "name": "StaticMerkleRootMultisigIsm" + }, + { + "address": "0xfD122f59ee8073528Cc5d36D5cc1451Bf1aF6923", + "constructorArguments": "", + "isProxy": true, + "name": "StaticMessageIdMultisigIsm" + }, + { + "address": "0xBbc6e404F8d841560261b036cA3468B55CB9f566", + "constructorArguments": "", + "isProxy": true, + "name": "StaticAggregationIsm" + }, + { + "address": "0x97c5dC51adAa04B3BefE63F4e62e4778219D9426", + "constructorArguments": "", + "isProxy": true, + "name": "StaticAggregationHook" + }, + { + "address": "0xa2931C37957f3079d3B21b877d56E1db930e02a5", + "constructorArguments": "", + "isProxy": false, + "name": "DomainRoutingIsmFactory" + }, + { + "address": "0xF5C9D13D0a3308a06375fD09CACE3a6120711206", + "constructorArguments": "", + "isProxy": true, + "name": "DomaingRoutingIsm" + }, + { + "address": "0xEbA276cdC61D4BC954E80985aC8FD71453fDab8e", + "constructorArguments": "", + "isProxy": true, + "name": "StaticMerkleRootMultisigIsm" + }, + { + "address": "0xfD122f59ee8073528Cc5d36D5cc1451Bf1aF6923", + "constructorArguments": "", + "isProxy": true, + "name": "StaticMessageIdMultisigIsm" + }, + { + "address": "0xBbc6e404F8d841560261b036cA3468B55CB9f566", + "constructorArguments": "", + "isProxy": true, + "name": "StaticAggregationIsm" + }, + { + "address": "0x97c5dC51adAa04B3BefE63F4e62e4778219D9426", + "constructorArguments": "", + "isProxy": true, + "name": "StaticAggregationHook" + }, + { + "address": "0xF5C9D13D0a3308a06375fD09CACE3a6120711206", + "constructorArguments": "", + "isProxy": true, + "name": "DomaingRoutingIsm" + }, + { + "address": "0xEbA276cdC61D4BC954E80985aC8FD71453fDab8e", + "constructorArguments": "", + "isProxy": true, + "name": "StaticMerkleRootMultisigIsm" + }, + { + "address": "0xfD122f59ee8073528Cc5d36D5cc1451Bf1aF6923", + "constructorArguments": "", + "isProxy": true, + "name": "StaticMessageIdMultisigIsm" + }, + { + "address": "0xBbc6e404F8d841560261b036cA3468B55CB9f566", + "constructorArguments": "", + "isProxy": true, + "name": "StaticAggregationIsm" + }, + { + "address": "0x97c5dC51adAa04B3BefE63F4e62e4778219D9426", + "constructorArguments": "", + "isProxy": true, + "name": "StaticAggregationHook" + }, + { + "address": "0xF5C9D13D0a3308a06375fD09CACE3a6120711206", + "constructorArguments": "", + "isProxy": true, + "name": "DomaingRoutingIsm" + }, + { + "address": "0xEbA276cdC61D4BC954E80985aC8FD71453fDab8e", + "constructorArguments": "", + "isProxy": true, + "name": "StaticMerkleRootMultisigIsm" + }, + { + "address": "0xfD122f59ee8073528Cc5d36D5cc1451Bf1aF6923", + "constructorArguments": "", + "isProxy": true, + "name": "StaticMessageIdMultisigIsm" + }, + { + "address": "0xBbc6e404F8d841560261b036cA3468B55CB9f566", + "constructorArguments": "", + "isProxy": true, + "name": "StaticAggregationIsm" + }, + { + "address": "0x97c5dC51adAa04B3BefE63F4e62e4778219D9426", + "constructorArguments": "", + "isProxy": true, + "name": "StaticAggregationHook" + }, + { + "address": "0xF5C9D13D0a3308a06375fD09CACE3a6120711206", + "constructorArguments": "", + "isProxy": true, + "name": "DomaingRoutingIsm" + }, + { + "address": "0xEbA276cdC61D4BC954E80985aC8FD71453fDab8e", + "constructorArguments": "", + "isProxy": true, + "name": "StaticMerkleRootMultisigIsm" + }, + { + "address": "0xfD122f59ee8073528Cc5d36D5cc1451Bf1aF6923", + "constructorArguments": "", + "isProxy": true, + "name": "StaticMessageIdMultisigIsm" + }, + { + "address": "0xBbc6e404F8d841560261b036cA3468B55CB9f566", + "constructorArguments": "", + "isProxy": true, + "name": "StaticAggregationIsm" + }, + { + "address": "0x97c5dC51adAa04B3BefE63F4e62e4778219D9426", + "constructorArguments": "", + "isProxy": true, + "name": "StaticAggregationHook" + }, + { + "address": "0xF5C9D13D0a3308a06375fD09CACE3a6120711206", + "constructorArguments": "", + "isProxy": true, + "name": "DomaingRoutingIsm" + }, + { + "address": "0xEbA276cdC61D4BC954E80985aC8FD71453fDab8e", + "constructorArguments": "", + "isProxy": true, + "name": "StaticMerkleRootMultisigIsm" + }, + { + "address": "0xfD122f59ee8073528Cc5d36D5cc1451Bf1aF6923", + "constructorArguments": "", + "isProxy": true, + "name": "StaticMessageIdMultisigIsm" + }, + { + "address": "0xBbc6e404F8d841560261b036cA3468B55CB9f566", + "constructorArguments": "", + "isProxy": true, + "name": "StaticAggregationIsm" + }, + { + "address": "0x97c5dC51adAa04B3BefE63F4e62e4778219D9426", + "constructorArguments": "", + "isProxy": true, + "name": "StaticAggregationHook" + }, + { + "address": "0xF5C9D13D0a3308a06375fD09CACE3a6120711206", + "constructorArguments": "", + "isProxy": true, + "name": "DomaingRoutingIsm" + } + ], + "avalanche": [ + { + "address": "0x896cF1D1B66cD211633eDd589fF158E8Cfaf9B54", + "constructorArguments": "", + "isProxy": false, + "name": "StaticMerkleRootMultisigIsmFactory" + }, + { + "address": "0x06b9dC1a6629122e7188698d20A92edbE966914f", + "constructorArguments": "", + "isProxy": true, + "name": "StaticMerkleRootMultisigIsm" + }, + { + "address": "0x8819D653DF5b1FC0DdB32189a2704E471AF8483c", + "constructorArguments": "", + "isProxy": false, + "name": "StaticMessageIdMultisigIsmFactory" + }, + { + "address": "0xeD8F4199e4409FDAe2AfD50dC7571f6771AadE50", + "constructorArguments": "", + "isProxy": true, + "name": "StaticMessageIdMultisigIsm" + }, + { + "address": "0xa5E13796eB7d2EDCc88012c8cfF90D69B51FcF9f", + "constructorArguments": "", + "isProxy": false, + "name": "StaticAggregationIsmFactory" + }, + { + "address": "0x86Bb7AC2BF6044289aEAFFC421b118E38C995c5a", + "constructorArguments": "", + "isProxy": true, + "name": "StaticAggregationIsm" + }, + { + "address": "0x3bF6Ac986C7Af9A9Ac356C0e99C0041EFd8D96e7", + "constructorArguments": "", + "isProxy": false, + "name": "StaticAggregationHookFactory" + }, + { + "address": "0x3988b98C43C7A1f7C9D3edce6CeAD3b8a3F3d969", + "constructorArguments": "", + "isProxy": true, + "name": "StaticAggregationHook" + }, + { + "address": "0xA9Ddc70f50009aF8bDB312aA757B4304b0F7BbB3", + "constructorArguments": "", + "isProxy": false, + "name": "DomainRoutingIsmFactory" + }, + { + "address": "0x61ca653A1F61A69E6498c45874237C4f1D8fC645", + "constructorArguments": "", + "isProxy": true, + "name": "DomaingRoutingIsm" + }, + { + "address": "0x06b9dC1a6629122e7188698d20A92edbE966914f", + "constructorArguments": "", + "isProxy": true, + "name": "StaticMerkleRootMultisigIsm" + }, + { + "address": "0xeD8F4199e4409FDAe2AfD50dC7571f6771AadE50", + "constructorArguments": "", + "isProxy": true, + "name": "StaticMessageIdMultisigIsm" + }, + { + "address": "0x86Bb7AC2BF6044289aEAFFC421b118E38C995c5a", + "constructorArguments": "", + "isProxy": true, + "name": "StaticAggregationIsm" + }, + { + "address": "0x3988b98C43C7A1f7C9D3edce6CeAD3b8a3F3d969", + "constructorArguments": "", + "isProxy": true, + "name": "StaticAggregationHook" + }, + { + "address": "0x61ca653A1F61A69E6498c45874237C4f1D8fC645", + "constructorArguments": "", + "isProxy": true, + "name": "DomaingRoutingIsm" + }, + { + "address": "0x06b9dC1a6629122e7188698d20A92edbE966914f", + "constructorArguments": "", + "isProxy": true, + "name": "StaticMerkleRootMultisigIsm" + }, + { + "address": "0xeD8F4199e4409FDAe2AfD50dC7571f6771AadE50", + "constructorArguments": "", + "isProxy": true, + "name": "StaticMessageIdMultisigIsm" + }, + { + "address": "0x86Bb7AC2BF6044289aEAFFC421b118E38C995c5a", + "constructorArguments": "", + "isProxy": true, + "name": "StaticAggregationIsm" + }, + { + "address": "0x3988b98C43C7A1f7C9D3edce6CeAD3b8a3F3d969", + "constructorArguments": "", + "isProxy": true, + "name": "StaticAggregationHook" + }, + { + "address": "0x61ca653A1F61A69E6498c45874237C4f1D8fC645", + "constructorArguments": "", + "isProxy": true, + "name": "DomaingRoutingIsm" + }, + { + "address": "0x06b9dC1a6629122e7188698d20A92edbE966914f", + "constructorArguments": "", + "isProxy": true, + "name": "StaticMerkleRootMultisigIsm" + }, + { + "address": "0xeD8F4199e4409FDAe2AfD50dC7571f6771AadE50", + "constructorArguments": "", + "isProxy": true, + "name": "StaticMessageIdMultisigIsm" + }, + { + "address": "0x86Bb7AC2BF6044289aEAFFC421b118E38C995c5a", "constructorArguments": "", - "isProxy": false, - "name": "StaticMerkleRootMultisigIsmFactory" + "isProxy": true, + "name": "StaticAggregationIsm" }, { - "address": "0xEbA276cdC61D4BC954E80985aC8FD71453fDab8e", + "address": "0x3988b98C43C7A1f7C9D3edce6CeAD3b8a3F3d969", "constructorArguments": "", "isProxy": true, - "name": "StaticMerkleRootMultisigIsm" + "name": "StaticAggregationHook" }, { - "address": "0x12Df53079d399a47e9E730df095b712B0FDFA791", + "address": "0x28F7907911C7E321c596686AE6D1F20516450037", "constructorArguments": "", "isProxy": false, - "name": "StaticMessageIdMultisigIsmFactory" + "name": "DomainRoutingIsmFactory" }, { - "address": "0xfD122f59ee8073528Cc5d36D5cc1451Bf1aF6923", + "address": "0x0a3E78c160daF8be96051D318d668F97182D60Bf", "constructorArguments": "", "isProxy": true, - "name": "StaticMessageIdMultisigIsm" + "name": "DomaingRoutingIsm" }, { - "address": "0xD4883084389fC1Eeb4dAfB2ADcFc36B711c310EB", + "address": "0x06b9dC1a6629122e7188698d20A92edbE966914f", "constructorArguments": "", - "isProxy": false, - "name": "StaticAggregationIsmFactory" + "isProxy": true, + "name": "StaticMerkleRootMultisigIsm" }, { - "address": "0xBbc6e404F8d841560261b036cA3468B55CB9f566", + "address": "0xeD8F4199e4409FDAe2AfD50dC7571f6771AadE50", "constructorArguments": "", "isProxy": true, - "name": "StaticAggregationIsm" + "name": "StaticMessageIdMultisigIsm" }, { - "address": "0x9B5f440bBb64Fee337F37e03362b628711Ea09C7", + "address": "0x86Bb7AC2BF6044289aEAFFC421b118E38C995c5a", "constructorArguments": "", - "isProxy": false, - "name": "StaticAggregationHookFactory" + "isProxy": true, + "name": "StaticAggregationIsm" }, { - "address": "0x97c5dC51adAa04B3BefE63F4e62e4778219D9426", + "address": "0x3988b98C43C7A1f7C9D3edce6CeAD3b8a3F3d969", "constructorArguments": "", "isProxy": true, "name": "StaticAggregationHook" }, { - "address": "0xC020F8A7b00178dFA0fcC75C159e14b79F8e5c63", - "constructorArguments": "", - "isProxy": false, - "name": "DomainRoutingIsmFactory" - }, - { - "address": "0xc0Ce143F44ADc65d35fB0d24436Eaa953380dF97", + "address": "0x0a3E78c160daF8be96051D318d668F97182D60Bf", "constructorArguments": "", "isProxy": true, "name": "DomaingRoutingIsm" }, { - "address": "0xEbA276cdC61D4BC954E80985aC8FD71453fDab8e", + "address": "0x06b9dC1a6629122e7188698d20A92edbE966914f", "constructorArguments": "", "isProxy": true, "name": "StaticMerkleRootMultisigIsm" }, { - "address": "0xfD122f59ee8073528Cc5d36D5cc1451Bf1aF6923", + "address": "0xeD8F4199e4409FDAe2AfD50dC7571f6771AadE50", "constructorArguments": "", "isProxy": true, "name": "StaticMessageIdMultisigIsm" }, { - "address": "0xBbc6e404F8d841560261b036cA3468B55CB9f566", + "address": "0x86Bb7AC2BF6044289aEAFFC421b118E38C995c5a", "constructorArguments": "", "isProxy": true, "name": "StaticAggregationIsm" }, { - "address": "0x97c5dC51adAa04B3BefE63F4e62e4778219D9426", + "address": "0x3988b98C43C7A1f7C9D3edce6CeAD3b8a3F3d969", "constructorArguments": "", "isProxy": true, "name": "StaticAggregationHook" }, { - "address": "0xc0Ce143F44ADc65d35fB0d24436Eaa953380dF97", + "address": "0x0a3E78c160daF8be96051D318d668F97182D60Bf", "constructorArguments": "", "isProxy": true, "name": "DomaingRoutingIsm" }, { - "address": "0xEbA276cdC61D4BC954E80985aC8FD71453fDab8e", + "address": "0x06b9dC1a6629122e7188698d20A92edbE966914f", "constructorArguments": "", "isProxy": true, "name": "StaticMerkleRootMultisigIsm" }, { - "address": "0xfD122f59ee8073528Cc5d36D5cc1451Bf1aF6923", + "address": "0xeD8F4199e4409FDAe2AfD50dC7571f6771AadE50", "constructorArguments": "", "isProxy": true, "name": "StaticMessageIdMultisigIsm" }, { - "address": "0xBbc6e404F8d841560261b036cA3468B55CB9f566", + "address": "0x86Bb7AC2BF6044289aEAFFC421b118E38C995c5a", "constructorArguments": "", "isProxy": true, "name": "StaticAggregationIsm" }, { - "address": "0x97c5dC51adAa04B3BefE63F4e62e4778219D9426", + "address": "0x3988b98C43C7A1f7C9D3edce6CeAD3b8a3F3d969", "constructorArguments": "", "isProxy": true, "name": "StaticAggregationHook" }, { - "address": "0xa2931C37957f3079d3B21b877d56E1db930e02a5", + "address": "0x0a3E78c160daF8be96051D318d668F97182D60Bf", "constructorArguments": "", - "isProxy": false, - "name": "DomainRoutingIsmFactory" + "isProxy": true, + "name": "DomaingRoutingIsm" }, { - "address": "0xF5C9D13D0a3308a06375fD09CACE3a6120711206", + "address": "0x06b9dC1a6629122e7188698d20A92edbE966914f", + "constructorArguments": "", + "isProxy": true, + "name": "StaticMerkleRootMultisigIsm" + }, + { + "address": "0xeD8F4199e4409FDAe2AfD50dC7571f6771AadE50", + "constructorArguments": "", + "isProxy": true, + "name": "StaticMessageIdMultisigIsm" + }, + { + "address": "0x86Bb7AC2BF6044289aEAFFC421b118E38C995c5a", + "constructorArguments": "", + "isProxy": true, + "name": "StaticAggregationIsm" + }, + { + "address": "0x3988b98C43C7A1f7C9D3edce6CeAD3b8a3F3d969", + "constructorArguments": "", + "isProxy": true, + "name": "StaticAggregationHook" + }, + { + "address": "0x0a3E78c160daF8be96051D318d668F97182D60Bf", "constructorArguments": "", "isProxy": true, "name": "DomaingRoutingIsm" }, { - "address": "0xEbA276cdC61D4BC954E80985aC8FD71453fDab8e", + "address": "0x06b9dC1a6629122e7188698d20A92edbE966914f", "constructorArguments": "", "isProxy": true, "name": "StaticMerkleRootMultisigIsm" }, { - "address": "0xfD122f59ee8073528Cc5d36D5cc1451Bf1aF6923", + "address": "0xeD8F4199e4409FDAe2AfD50dC7571f6771AadE50", "constructorArguments": "", "isProxy": true, "name": "StaticMessageIdMultisigIsm" }, { - "address": "0xBbc6e404F8d841560261b036cA3468B55CB9f566", + "address": "0x86Bb7AC2BF6044289aEAFFC421b118E38C995c5a", "constructorArguments": "", "isProxy": true, "name": "StaticAggregationIsm" }, { - "address": "0x97c5dC51adAa04B3BefE63F4e62e4778219D9426", + "address": "0x3988b98C43C7A1f7C9D3edce6CeAD3b8a3F3d969", "constructorArguments": "", "isProxy": true, "name": "StaticAggregationHook" }, { - "address": "0xF5C9D13D0a3308a06375fD09CACE3a6120711206", + "address": "0x0a3E78c160daF8be96051D318d668F97182D60Bf", "constructorArguments": "", "isProxy": true, "name": "DomaingRoutingIsm" } ], - "avalanche": [ + "base": [ { - "address": "0x896cF1D1B66cD211633eDd589fF158E8Cfaf9B54", + "address": "0x8b83fefd896fAa52057798f6426E9f0B080FCCcE", "constructorArguments": "", "isProxy": false, "name": "StaticMerkleRootMultisigIsmFactory" }, { - "address": "0x06b9dC1a6629122e7188698d20A92edbE966914f", + "address": "0xAF03386044373E2fe26C5b1dCedF5a7e854a7a3F", "constructorArguments": "", "isProxy": true, "name": "StaticMerkleRootMultisigIsm" }, { - "address": "0x8819D653DF5b1FC0DdB32189a2704E471AF8483c", + "address": "0x8F7454AC98228f3504Bb91eA3D8Adafe6406110A", "constructorArguments": "", "isProxy": false, "name": "StaticMessageIdMultisigIsmFactory" }, { - "address": "0xeD8F4199e4409FDAe2AfD50dC7571f6771AadE50", + "address": "0x882CD0C5D50b6dD74b36Da4BDb059507fddEDdf2", "constructorArguments": "", "isProxy": true, "name": "StaticMessageIdMultisigIsm" }, { - "address": "0xa5E13796eB7d2EDCc88012c8cfF90D69B51FcF9f", + "address": "0xEb9FcFDC9EfDC17c1EC5E1dc085B98485da213D6", "constructorArguments": "", "isProxy": false, "name": "StaticAggregationIsmFactory" }, { - "address": "0x86Bb7AC2BF6044289aEAFFC421b118E38C995c5a", + "address": "0x19930232E9aFC4f4F09d09fe2375680fAc2100D0", "constructorArguments": "", "isProxy": true, "name": "StaticAggregationIsm" }, { - "address": "0x3bF6Ac986C7Af9A9Ac356C0e99C0041EFd8D96e7", + "address": "0x1052eF3419f26Bec74Ed7CEf4a4FA6812Bc09908", "constructorArguments": "", "isProxy": false, "name": "StaticAggregationHookFactory" }, { - "address": "0x3988b98C43C7A1f7C9D3edce6CeAD3b8a3F3d969", + "address": "0x12Ed1BbA182CbC63692F813651BD493B7445C874", "constructorArguments": "", "isProxy": true, "name": "StaticAggregationHook" }, { - "address": "0xA9Ddc70f50009aF8bDB312aA757B4304b0F7BbB3", + "address": "0x0761b0827849abbf7b0cC09CE14e1C93D87f5004", "constructorArguments": "", "isProxy": false, "name": "DomainRoutingIsmFactory" }, { - "address": "0x61ca653A1F61A69E6498c45874237C4f1D8fC645", + "address": "0x3b9f24fD2ecfed0d3A88fa7f0E4e5747671981D7", "constructorArguments": "", "isProxy": true, "name": "DomaingRoutingIsm" }, { - "address": "0x06b9dC1a6629122e7188698d20A92edbE966914f", + "address": "0xAF03386044373E2fe26C5b1dCedF5a7e854a7a3F", "constructorArguments": "", "isProxy": true, "name": "StaticMerkleRootMultisigIsm" }, { - "address": "0xeD8F4199e4409FDAe2AfD50dC7571f6771AadE50", + "address": "0x882CD0C5D50b6dD74b36Da4BDb059507fddEDdf2", "constructorArguments": "", "isProxy": true, "name": "StaticMessageIdMultisigIsm" }, { - "address": "0x86Bb7AC2BF6044289aEAFFC421b118E38C995c5a", + "address": "0x19930232E9aFC4f4F09d09fe2375680fAc2100D0", "constructorArguments": "", "isProxy": true, "name": "StaticAggregationIsm" }, { - "address": "0x3988b98C43C7A1f7C9D3edce6CeAD3b8a3F3d969", + "address": "0x12Ed1BbA182CbC63692F813651BD493B7445C874", "constructorArguments": "", "isProxy": true, "name": "StaticAggregationHook" }, { - "address": "0x61ca653A1F61A69E6498c45874237C4f1D8fC645", + "address": "0x3b9f24fD2ecfed0d3A88fa7f0E4e5747671981D7", "constructorArguments": "", "isProxy": true, "name": "DomaingRoutingIsm" }, { - "address": "0x06b9dC1a6629122e7188698d20A92edbE966914f", + "address": "0xAF03386044373E2fe26C5b1dCedF5a7e854a7a3F", "constructorArguments": "", "isProxy": true, "name": "StaticMerkleRootMultisigIsm" }, { - "address": "0xeD8F4199e4409FDAe2AfD50dC7571f6771AadE50", + "address": "0x882CD0C5D50b6dD74b36Da4BDb059507fddEDdf2", "constructorArguments": "", "isProxy": true, "name": "StaticMessageIdMultisigIsm" }, { - "address": "0x86Bb7AC2BF6044289aEAFFC421b118E38C995c5a", + "address": "0x19930232E9aFC4f4F09d09fe2375680fAc2100D0", "constructorArguments": "", "isProxy": true, "name": "StaticAggregationIsm" }, { - "address": "0x3988b98C43C7A1f7C9D3edce6CeAD3b8a3F3d969", + "address": "0x12Ed1BbA182CbC63692F813651BD493B7445C874", "constructorArguments": "", "isProxy": true, "name": "StaticAggregationHook" }, { - "address": "0x61ca653A1F61A69E6498c45874237C4f1D8fC645", + "address": "0x3b9f24fD2ecfed0d3A88fa7f0E4e5747671981D7", "constructorArguments": "", "isProxy": true, "name": "DomaingRoutingIsm" }, { - "address": "0x06b9dC1a6629122e7188698d20A92edbE966914f", + "address": "0xAF03386044373E2fe26C5b1dCedF5a7e854a7a3F", "constructorArguments": "", "isProxy": true, "name": "StaticMerkleRootMultisigIsm" }, { - "address": "0xeD8F4199e4409FDAe2AfD50dC7571f6771AadE50", + "address": "0x882CD0C5D50b6dD74b36Da4BDb059507fddEDdf2", "constructorArguments": "", "isProxy": true, "name": "StaticMessageIdMultisigIsm" }, { - "address": "0x86Bb7AC2BF6044289aEAFFC421b118E38C995c5a", + "address": "0x19930232E9aFC4f4F09d09fe2375680fAc2100D0", "constructorArguments": "", "isProxy": true, "name": "StaticAggregationIsm" }, { - "address": "0x3988b98C43C7A1f7C9D3edce6CeAD3b8a3F3d969", + "address": "0x12Ed1BbA182CbC63692F813651BD493B7445C874", "constructorArguments": "", "isProxy": true, "name": "StaticAggregationHook" }, { - "address": "0x28F7907911C7E321c596686AE6D1F20516450037", + "address": "0x7E27456a839BFF31CA642c060a2b68414Cb6e503", "constructorArguments": "", "isProxy": false, "name": "DomainRoutingIsmFactory" }, { - "address": "0x0a3E78c160daF8be96051D318d668F97182D60Bf", + "address": "0x0d2FdC0264059C1334Aa28187E8628E1c9c6EC70", "constructorArguments": "", "isProxy": true, "name": "DomaingRoutingIsm" }, { - "address": "0x06b9dC1a6629122e7188698d20A92edbE966914f", + "address": "0xAF03386044373E2fe26C5b1dCedF5a7e854a7a3F", "constructorArguments": "", "isProxy": true, "name": "StaticMerkleRootMultisigIsm" }, { - "address": "0xeD8F4199e4409FDAe2AfD50dC7571f6771AadE50", + "address": "0x882CD0C5D50b6dD74b36Da4BDb059507fddEDdf2", "constructorArguments": "", "isProxy": true, "name": "StaticMessageIdMultisigIsm" }, { - "address": "0x86Bb7AC2BF6044289aEAFFC421b118E38C995c5a", + "address": "0x19930232E9aFC4f4F09d09fe2375680fAc2100D0", "constructorArguments": "", "isProxy": true, "name": "StaticAggregationIsm" }, { - "address": "0x3988b98C43C7A1f7C9D3edce6CeAD3b8a3F3d969", + "address": "0x12Ed1BbA182CbC63692F813651BD493B7445C874", "constructorArguments": "", "isProxy": true, "name": "StaticAggregationHook" }, { - "address": "0x0a3E78c160daF8be96051D318d668F97182D60Bf", + "address": "0x0d2FdC0264059C1334Aa28187E8628E1c9c6EC70", "constructorArguments": "", "isProxy": true, "name": "DomaingRoutingIsm" - } - ], - "base": [ - { - "address": "0x8b83fefd896fAa52057798f6426E9f0B080FCCcE", - "constructorArguments": "", - "isProxy": false, - "name": "StaticMerkleRootMultisigIsmFactory" }, { "address": "0xAF03386044373E2fe26C5b1dCedF5a7e854a7a3F", @@ -420,36 +960,18 @@ "isProxy": true, "name": "StaticMerkleRootMultisigIsm" }, - { - "address": "0x8F7454AC98228f3504Bb91eA3D8Adafe6406110A", - "constructorArguments": "", - "isProxy": false, - "name": "StaticMessageIdMultisigIsmFactory" - }, { "address": "0x882CD0C5D50b6dD74b36Da4BDb059507fddEDdf2", "constructorArguments": "", "isProxy": true, "name": "StaticMessageIdMultisigIsm" }, - { - "address": "0xEb9FcFDC9EfDC17c1EC5E1dc085B98485da213D6", - "constructorArguments": "", - "isProxy": false, - "name": "StaticAggregationIsmFactory" - }, { "address": "0x19930232E9aFC4f4F09d09fe2375680fAc2100D0", "constructorArguments": "", "isProxy": true, "name": "StaticAggregationIsm" }, - { - "address": "0x1052eF3419f26Bec74Ed7CEf4a4FA6812Bc09908", - "constructorArguments": "", - "isProxy": false, - "name": "StaticAggregationHookFactory" - }, { "address": "0x12Ed1BbA182CbC63692F813651BD493B7445C874", "constructorArguments": "", @@ -457,13 +979,7 @@ "name": "StaticAggregationHook" }, { - "address": "0x0761b0827849abbf7b0cC09CE14e1C93D87f5004", - "constructorArguments": "", - "isProxy": false, - "name": "DomainRoutingIsmFactory" - }, - { - "address": "0x3b9f24fD2ecfed0d3A88fa7f0E4e5747671981D7", + "address": "0x0d2FdC0264059C1334Aa28187E8628E1c9c6EC70", "constructorArguments": "", "isProxy": true, "name": "DomaingRoutingIsm" @@ -493,7 +1009,7 @@ "name": "StaticAggregationHook" }, { - "address": "0x3b9f24fD2ecfed0d3A88fa7f0E4e5747671981D7", + "address": "0x0d2FdC0264059C1334Aa28187E8628E1c9c6EC70", "constructorArguments": "", "isProxy": true, "name": "DomaingRoutingIsm" @@ -523,7 +1039,7 @@ "name": "StaticAggregationHook" }, { - "address": "0x3b9f24fD2ecfed0d3A88fa7f0E4e5747671981D7", + "address": "0x0d2FdC0264059C1334Aa28187E8628E1c9c6EC70", "constructorArguments": "", "isProxy": true, "name": "DomaingRoutingIsm" @@ -553,43 +1069,87 @@ "name": "StaticAggregationHook" }, { - "address": "0x7E27456a839BFF31CA642c060a2b68414Cb6e503", + "address": "0x0d2FdC0264059C1334Aa28187E8628E1c9c6EC70", + "constructorArguments": "", + "isProxy": true, + "name": "DomaingRoutingIsm" + } + ], + "blast": [ + { + "address": "0x8b83fefd896fAa52057798f6426E9f0B080FCCcE", "constructorArguments": "", "isProxy": false, - "name": "DomainRoutingIsmFactory" + "name": "StaticMerkleRootMultisigIsmFactory" }, { - "address": "0x0d2FdC0264059C1334Aa28187E8628E1c9c6EC70", + "address": "0x8F7454AC98228f3504Bb91eA3D8Adafe6406110A", + "constructorArguments": "", + "isProxy": false, + "name": "StaticMerkleRootMultisigIsmFactory" + }, + { + "address": "0x8F7454AC98228f3504Bb91eA3D8Adafe6406110A", + "constructorArguments": "", + "isProxy": false, + "name": "StaticMerkleRootMultisigIsmFactory" + }, + { + "address": "0xEb9FcFDC9EfDC17c1EC5E1dc085B98485da213D6", + "constructorArguments": "", + "isProxy": false, + "name": "StaticMerkleRootMultisigIsmFactory" + }, + { + "address": "0x19930232E9aFC4f4F09d09fe2375680fAc2100D0", "constructorArguments": "", "isProxy": true, - "name": "DomaingRoutingIsm" + "name": "StaticMerkleRootMultisigIsm" + }, + { + "address": "0x1052eF3419f26Bec74Ed7CEf4a4FA6812Bc09908", + "constructorArguments": "", + "isProxy": false, + "name": "StaticMessageIdMultisigIsmFactory" + }, + { + "address": "0x12Ed1BbA182CbC63692F813651BD493B7445C874", + "constructorArguments": "", + "isProxy": true, + "name": "StaticMessageIdMultisigIsm" + }, + { + "address": "0x0761b0827849abbf7b0cC09CE14e1C93D87f5004", + "constructorArguments": "", + "isProxy": false, + "name": "StaticAggregationIsmFactory" }, { - "address": "0xAF03386044373E2fe26C5b1dCedF5a7e854a7a3F", + "address": "0x3b9f24fD2ecfed0d3A88fa7f0E4e5747671981D7", "constructorArguments": "", "isProxy": true, - "name": "StaticMerkleRootMultisigIsm" + "name": "StaticAggregationIsm" }, { - "address": "0x882CD0C5D50b6dD74b36Da4BDb059507fddEDdf2", + "address": "0x4Ed7d626f1E96cD1C0401607Bf70D95243E3dEd1", "constructorArguments": "", - "isProxy": true, - "name": "StaticMessageIdMultisigIsm" + "isProxy": false, + "name": "StaticAggregationHookFactory" }, { - "address": "0x19930232E9aFC4f4F09d09fe2375680fAc2100D0", + "address": "0x71DCcD21B912F7d4f636af0C9eA5DC0C10617354", "constructorArguments": "", "isProxy": true, - "name": "StaticAggregationIsm" + "name": "StaticAggregationHook" }, { - "address": "0x12Ed1BbA182CbC63692F813651BD493B7445C874", + "address": "0x2f2aFaE1139Ce54feFC03593FeE8AB2aDF4a85A7", "constructorArguments": "", - "isProxy": true, - "name": "StaticAggregationHook" + "isProxy": false, + "name": "DomainRoutingIsmFactory" }, { - "address": "0x0d2FdC0264059C1334Aa28187E8628E1c9c6EC70", + "address": "0x7f51A658837A315134A97ff8B586d71B726B7e61", "constructorArguments": "", "isProxy": true, "name": "DomaingRoutingIsm" @@ -734,6 +1294,36 @@ "isProxy": true, "name": "StaticAggregationHook" }, + { + "address": "0x1467aB848fCCdA65c2cCed0ebeBD0d95ad89E0D8", + "constructorArguments": "", + "isProxy": true, + "name": "DomaingRoutingIsm" + }, + { + "address": "0xDc3D51c58BDb84F4F209d2684151dfCa271e504f", + "constructorArguments": "", + "isProxy": true, + "name": "StaticMerkleRootMultisigIsm" + }, + { + "address": "0x707609419b70DCb4C41Ef185d3C184814c61Af9c", + "constructorArguments": "", + "isProxy": true, + "name": "StaticMessageIdMultisigIsm" + }, + { + "address": "0x769FeC9f1a1e3DD1891015A387C92Ee9631CB0bA", + "constructorArguments": "", + "isProxy": true, + "name": "StaticAggregationIsm" + }, + { + "address": "0xf771dA1B909B67ca41dda9133E1C9934B5A2D8bb", + "constructorArguments": "", + "isProxy": true, + "name": "StaticAggregationHook" + }, { "address": "0x1467aB848fCCdA65c2cCed0ebeBD0d95ad89E0D8", "constructorArguments": "", @@ -922,6 +1512,36 @@ "isProxy": true, "name": "StaticAggregationHook" }, + { + "address": "0x866599CEaE5060D774EBAaE7e9f8A0431a8c1ED5", + "constructorArguments": "", + "isProxy": true, + "name": "DomaingRoutingIsm" + }, + { + "address": "0x7F6cD932412508E9a8297CA626C56Ed3D279937F", + "constructorArguments": "", + "isProxy": true, + "name": "StaticMerkleRootMultisigIsm" + }, + { + "address": "0xf422a4Af27e5fbDDAf799A1d92532Edd5dE58fF3", + "constructorArguments": "", + "isProxy": true, + "name": "StaticMessageIdMultisigIsm" + }, + { + "address": "0x43379b54E27EA8387B34B5c15534E230d490f0A8", + "constructorArguments": "", + "isProxy": true, + "name": "StaticAggregationIsm" + }, + { + "address": "0x8d9dB8bbF91d7852F36a954229BDf6ec69A3ae00", + "constructorArguments": "", + "isProxy": true, + "name": "StaticAggregationHook" + }, { "address": "0x866599CEaE5060D774EBAaE7e9f8A0431a8c1ED5", "constructorArguments": "", @@ -1110,6 +1730,36 @@ "isProxy": true, "name": "StaticAggregationHook" }, + { + "address": "0xBbaDB49B1fD1A0574C8D2B0589Cd9b8A79452e67", + "constructorArguments": "", + "isProxy": true, + "name": "DomaingRoutingIsm" + }, + { + "address": "0xD4dAcca08737d2a910b4Ad401f805F83D0C170f3", + "constructorArguments": "", + "isProxy": true, + "name": "StaticMerkleRootMultisigIsm" + }, + { + "address": "0x5371942D3Ed75b10d77F0f4184dDc85cC35A1420", + "constructorArguments": "", + "isProxy": true, + "name": "StaticMessageIdMultisigIsm" + }, + { + "address": "0xc2cCfc65D2D5719E78a77EA5f6C10AA4cdEC6719", + "constructorArguments": "", + "isProxy": true, + "name": "StaticAggregationIsm" + }, + { + "address": "0x03862793C0EE59af3e475f7Ca67406b547FfD95c", + "constructorArguments": "", + "isProxy": true, + "name": "StaticAggregationHook" + }, { "address": "0xBbaDB49B1fD1A0574C8D2B0589Cd9b8A79452e67", "constructorArguments": "", @@ -1275,133 +1925,287 @@ "name": "StaticMerkleRootMultisigIsmFactory" }, { - "address": "0x71AB2390e4eF4A8AF685aE11AAd974AC3E8eF85D", + "address": "0x71AB2390e4eF4A8AF685aE11AAd974AC3E8eF85D", + "constructorArguments": "", + "isProxy": true, + "name": "StaticMerkleRootMultisigIsm" + }, + { + "address": "0x8528bAa7d1d386E7967603e480fa2B558a23644c", + "constructorArguments": "", + "isProxy": false, + "name": "StaticMessageIdMultisigIsmFactory" + }, + { + "address": "0x28846fCb579747E8ddad9E93b55BE51b0A1Bf1f3", + "constructorArguments": "", + "isProxy": false, + "name": "StaticMerkleRootMultisigIsmFactory" + }, + { + "address": "0x71AB2390e4eF4A8AF685aE11AAd974AC3E8eF85D", + "constructorArguments": "", + "isProxy": true, + "name": "StaticMerkleRootMultisigIsm" + }, + { + "address": "0x8528bAa7d1d386E7967603e480fa2B558a23644c", + "constructorArguments": "", + "isProxy": false, + "name": "StaticMessageIdMultisigIsmFactory" + }, + { + "address": "0xe46CDa25130A89759F1Da00591D7a920CAe7667E", + "constructorArguments": "", + "isProxy": true, + "name": "StaticMerkleRootMultisigIsm" + }, + { + "address": "0xEeBd8F72573C5a08F18BeC0DbadCCD3365c06AEF", + "constructorArguments": "", + "isProxy": true, + "name": "StaticMessageIdMultisigIsm" + }, + { + "address": "0x5aaF70a9944d2D7cf17153ea07632618b1e45C6F", + "constructorArguments": "", + "isProxy": true, + "name": "StaticAggregationIsm" + }, + { + "address": "0x72AffdEd251dF55c7c89566c64B9961dbc3e7A23", + "constructorArguments": "", + "isProxy": true, + "name": "StaticAggregationHook" + }, + { + "address": "0xc4c11C88AbF6087150273b2c39B27878d137a920", + "constructorArguments": "", + "isProxy": true, + "name": "DomaingRoutingIsm" + }, + { + "address": "0xe46CDa25130A89759F1Da00591D7a920CAe7667E", + "constructorArguments": "", + "isProxy": true, + "name": "StaticMerkleRootMultisigIsm" + }, + { + "address": "0xEeBd8F72573C5a08F18BeC0DbadCCD3365c06AEF", + "constructorArguments": "", + "isProxy": true, + "name": "StaticMessageIdMultisigIsm" + }, + { + "address": "0x5aaF70a9944d2D7cf17153ea07632618b1e45C6F", + "constructorArguments": "", + "isProxy": true, + "name": "StaticAggregationIsm" + }, + { + "address": "0x72AffdEd251dF55c7c89566c64B9961dbc3e7A23", + "constructorArguments": "", + "isProxy": true, + "name": "StaticAggregationHook" + }, + { + "address": "0xbB5Df000113e767dE11343A16f83De733e5bCC0F", + "constructorArguments": "", + "isProxy": false, + "name": "DomainRoutingIsmFactory" + }, + { + "address": "0x901bFAC323Dc06b1302D82201F62729Dff39b20a", + "constructorArguments": "", + "isProxy": true, + "name": "DomaingRoutingIsm" + }, + { + "address": "0xe46CDa25130A89759F1Da00591D7a920CAe7667E", + "constructorArguments": "", + "isProxy": true, + "name": "StaticMerkleRootMultisigIsm" + }, + { + "address": "0xEeBd8F72573C5a08F18BeC0DbadCCD3365c06AEF", + "constructorArguments": "", + "isProxy": true, + "name": "StaticMessageIdMultisigIsm" + }, + { + "address": "0x5aaF70a9944d2D7cf17153ea07632618b1e45C6F", + "constructorArguments": "", + "isProxy": true, + "name": "StaticAggregationIsm" + }, + { + "address": "0x72AffdEd251dF55c7c89566c64B9961dbc3e7A23", + "constructorArguments": "", + "isProxy": true, + "name": "StaticAggregationHook" + }, + { + "address": "0x901bFAC323Dc06b1302D82201F62729Dff39b20a", + "constructorArguments": "", + "isProxy": true, + "name": "DomaingRoutingIsm" + }, + { + "address": "0xe46CDa25130A89759F1Da00591D7a920CAe7667E", + "constructorArguments": "", + "isProxy": true, + "name": "StaticMerkleRootMultisigIsm" + }, + { + "address": "0xEeBd8F72573C5a08F18BeC0DbadCCD3365c06AEF", + "constructorArguments": "", + "isProxy": true, + "name": "StaticMessageIdMultisigIsm" + }, + { + "address": "0x5aaF70a9944d2D7cf17153ea07632618b1e45C6F", + "constructorArguments": "", + "isProxy": true, + "name": "StaticAggregationIsm" + }, + { + "address": "0x72AffdEd251dF55c7c89566c64B9961dbc3e7A23", "constructorArguments": "", "isProxy": true, - "name": "StaticMerkleRootMultisigIsm" + "name": "StaticAggregationHook" }, { - "address": "0x8528bAa7d1d386E7967603e480fa2B558a23644c", + "address": "0x901bFAC323Dc06b1302D82201F62729Dff39b20a", "constructorArguments": "", - "isProxy": false, - "name": "StaticMessageIdMultisigIsmFactory" - }, + "isProxy": true, + "name": "DomaingRoutingIsm" + } + ], + "inevm": [ { - "address": "0x28846fCb579747E8ddad9E93b55BE51b0A1Bf1f3", + "address": "0x2C1FAbEcd7bFBdEBF27CcdB67baADB38b6Df90fC", "constructorArguments": "", "isProxy": false, "name": "StaticMerkleRootMultisigIsmFactory" }, { - "address": "0x71AB2390e4eF4A8AF685aE11AAd974AC3E8eF85D", + "address": "0x4725F7b8037513915aAf6D6CBDE2920E28540dDc", "constructorArguments": "", "isProxy": true, "name": "StaticMerkleRootMultisigIsm" }, { - "address": "0x8528bAa7d1d386E7967603e480fa2B558a23644c", + "address": "0x8b83fefd896fAa52057798f6426E9f0B080FCCcE", "constructorArguments": "", "isProxy": false, "name": "StaticMessageIdMultisigIsmFactory" }, { - "address": "0xe46CDa25130A89759F1Da00591D7a920CAe7667E", + "address": "0xAF03386044373E2fe26C5b1dCedF5a7e854a7a3F", "constructorArguments": "", "isProxy": true, - "name": "StaticMerkleRootMultisigIsm" + "name": "StaticMessageIdMultisigIsm" }, { - "address": "0xEeBd8F72573C5a08F18BeC0DbadCCD3365c06AEF", + "address": "0x8F7454AC98228f3504Bb91eA3D8Adafe6406110A", "constructorArguments": "", - "isProxy": true, - "name": "StaticMessageIdMultisigIsm" + "isProxy": false, + "name": "StaticAggregationIsmFactory" }, { - "address": "0x5aaF70a9944d2D7cf17153ea07632618b1e45C6F", + "address": "0x882CD0C5D50b6dD74b36Da4BDb059507fddEDdf2", "constructorArguments": "", "isProxy": true, "name": "StaticAggregationIsm" }, { - "address": "0x72AffdEd251dF55c7c89566c64B9961dbc3e7A23", + "address": "0xEb9FcFDC9EfDC17c1EC5E1dc085B98485da213D6", + "constructorArguments": "", + "isProxy": false, + "name": "StaticAggregationHookFactory" + }, + { + "address": "0x19930232E9aFC4f4F09d09fe2375680fAc2100D0", "constructorArguments": "", "isProxy": true, "name": "StaticAggregationHook" }, { - "address": "0xc4c11C88AbF6087150273b2c39B27878d137a920", + "address": "0x1052eF3419f26Bec74Ed7CEf4a4FA6812Bc09908", + "constructorArguments": "", + "isProxy": false, + "name": "DomainRoutingIsmFactory" + }, + { + "address": "0x12Ed1BbA182CbC63692F813651BD493B7445C874", "constructorArguments": "", "isProxy": true, "name": "DomaingRoutingIsm" }, { - "address": "0xe46CDa25130A89759F1Da00591D7a920CAe7667E", + "address": "0x4725F7b8037513915aAf6D6CBDE2920E28540dDc", "constructorArguments": "", "isProxy": true, "name": "StaticMerkleRootMultisigIsm" }, { - "address": "0xEeBd8F72573C5a08F18BeC0DbadCCD3365c06AEF", + "address": "0xAF03386044373E2fe26C5b1dCedF5a7e854a7a3F", "constructorArguments": "", "isProxy": true, "name": "StaticMessageIdMultisigIsm" }, { - "address": "0x5aaF70a9944d2D7cf17153ea07632618b1e45C6F", + "address": "0x882CD0C5D50b6dD74b36Da4BDb059507fddEDdf2", "constructorArguments": "", "isProxy": true, "name": "StaticAggregationIsm" }, { - "address": "0x72AffdEd251dF55c7c89566c64B9961dbc3e7A23", + "address": "0x19930232E9aFC4f4F09d09fe2375680fAc2100D0", "constructorArguments": "", "isProxy": true, "name": "StaticAggregationHook" }, { - "address": "0xbB5Df000113e767dE11343A16f83De733e5bCC0F", - "constructorArguments": "", - "isProxy": false, - "name": "DomainRoutingIsmFactory" - }, - { - "address": "0x901bFAC323Dc06b1302D82201F62729Dff39b20a", + "address": "0x12Ed1BbA182CbC63692F813651BD493B7445C874", "constructorArguments": "", "isProxy": true, "name": "DomaingRoutingIsm" - }, + } + ], + "mantapacific": [ { - "address": "0xe46CDa25130A89759F1Da00591D7a920CAe7667E", + "address": "0x882CD0C5D50b6dD74b36Da4BDb059507fddEDdf2", "constructorArguments": "", "isProxy": true, "name": "StaticMerkleRootMultisigIsm" }, { - "address": "0xEeBd8F72573C5a08F18BeC0DbadCCD3365c06AEF", + "address": "0x19930232E9aFC4f4F09d09fe2375680fAc2100D0", "constructorArguments": "", "isProxy": true, "name": "StaticMessageIdMultisigIsm" }, { - "address": "0x5aaF70a9944d2D7cf17153ea07632618b1e45C6F", + "address": "0x12Ed1BbA182CbC63692F813651BD493B7445C874", "constructorArguments": "", "isProxy": true, "name": "StaticAggregationIsm" }, { - "address": "0x72AffdEd251dF55c7c89566c64B9961dbc3e7A23", + "address": "0x3b9f24fD2ecfed0d3A88fa7f0E4e5747671981D7", "constructorArguments": "", "isProxy": true, "name": "StaticAggregationHook" }, { - "address": "0x901bFAC323Dc06b1302D82201F62729Dff39b20a", + "address": "0x6C360932873629929ff3D9ffB70bD4cbC1606541", "constructorArguments": "", "isProxy": true, "name": "DomaingRoutingIsm" } ], - "inevm": [ + "mode": [ { "address": "0x2C1FAbEcd7bFBdEBF27CcdB67baADB38b6Df90fC", "constructorArguments": "", @@ -1583,6 +2387,36 @@ "constructorArguments": "", "isProxy": true, "name": "DomaingRoutingIsm" + }, + { + "address": "0x28336d2b8783f2373bCFc173058EA932bf3b901C", + "constructorArguments": "", + "isProxy": true, + "name": "StaticMerkleRootMultisigIsm" + }, + { + "address": "0x76FD8c164F380107631160d8Fd1f4Edc2719004D", + "constructorArguments": "", + "isProxy": true, + "name": "StaticMessageIdMultisigIsm" + }, + { + "address": "0xd5FF00DD9E737c9d1a197246738876fAF43e4aC0", + "constructorArguments": "", + "isProxy": true, + "name": "StaticAggregationIsm" + }, + { + "address": "0x568De5f1639Fe7c9eba67f1191DE19eeCc77985B", + "constructorArguments": "", + "isProxy": true, + "name": "StaticAggregationHook" + }, + { + "address": "0x2214b2AC96215d2FF1fffC84E4Af295d7497B013", + "constructorArguments": "", + "isProxy": true, + "name": "DomaingRoutingIsm" } ], "optimism": [ @@ -1736,6 +2570,36 @@ "isProxy": true, "name": "StaticAggregationHook" }, + { + "address": "0x71c5167429f522FA009D110954Cb08E0317d4d69", + "constructorArguments": "", + "isProxy": true, + "name": "DomaingRoutingIsm" + }, + { + "address": "0xC91A3282FE1eBc29AE494f10680006f152DcE316", + "constructorArguments": "", + "isProxy": true, + "name": "StaticMerkleRootMultisigIsm" + }, + { + "address": "0xb61544De4d3A103698AC57Fd62402627B8AC3cC2", + "constructorArguments": "", + "isProxy": true, + "name": "StaticMessageIdMultisigIsm" + }, + { + "address": "0xD416cF29F961c090e9b9b8aF0970c86D93c2Ff61", + "constructorArguments": "", + "isProxy": true, + "name": "StaticAggregationIsm" + }, + { + "address": "0x315d8B4229134Fcb12B8955f0B5FC1310E56E764", + "constructorArguments": "", + "isProxy": true, + "name": "StaticAggregationHook" + }, { "address": "0x71c5167429f522FA009D110954Cb08E0317d4d69", "constructorArguments": "", @@ -1924,6 +2788,36 @@ "isProxy": true, "name": "StaticAggregationHook" }, + { + "address": "0x6921808186c66558e91dF1233910862A94a57475", + "constructorArguments": "", + "isProxy": true, + "name": "DomaingRoutingIsm" + }, + { + "address": "0x14CEa5Df89Fa709409e83ebEA9518C5B6fb4B19B", + "constructorArguments": "", + "isProxy": true, + "name": "StaticMerkleRootMultisigIsm" + }, + { + "address": "0x370815EdA08438c8F385a6f7AB5A2Dfa75008abC", + "constructorArguments": "", + "isProxy": true, + "name": "StaticMessageIdMultisigIsm" + }, + { + "address": "0xCC38436BFB9B9888be96b59d825E0fE5DC19e05c", + "constructorArguments": "", + "isProxy": true, + "name": "StaticAggregationIsm" + }, + { + "address": "0x5B8418082D87c96B7De689D0368756cddAbB35F5", + "constructorArguments": "", + "isProxy": true, + "name": "StaticAggregationHook" + }, { "address": "0x6921808186c66558e91dF1233910862A94a57475", "constructorArguments": "", @@ -2112,6 +3006,36 @@ "isProxy": true, "name": "StaticAggregationHook" }, + { + "address": "0x0741b6Fd92DA99E77E5eE78CFf74cB1689B3588e", + "constructorArguments": "", + "isProxy": true, + "name": "DomaingRoutingIsm" + }, + { + "address": "0x882CD0C5D50b6dD74b36Da4BDb059507fddEDdf2", + "constructorArguments": "", + "isProxy": true, + "name": "StaticMerkleRootMultisigIsm" + }, + { + "address": "0x19930232E9aFC4f4F09d09fe2375680fAc2100D0", + "constructorArguments": "", + "isProxy": true, + "name": "StaticMessageIdMultisigIsm" + }, + { + "address": "0x12Ed1BbA182CbC63692F813651BD493B7445C874", + "constructorArguments": "", + "isProxy": true, + "name": "StaticAggregationIsm" + }, + { + "address": "0x3b9f24fD2ecfed0d3A88fa7f0E4e5747671981D7", + "constructorArguments": "", + "isProxy": true, + "name": "StaticAggregationHook" + }, { "address": "0x0741b6Fd92DA99E77E5eE78CFf74cB1689B3588e", "constructorArguments": "", @@ -2300,6 +3224,36 @@ "isProxy": true, "name": "StaticAggregationHook" }, + { + "address": "0x9d9238fD3715281De2c8FC321135bF82EB66E932", + "constructorArguments": "", + "isProxy": true, + "name": "DomaingRoutingIsm" + }, + { + "address": "0x4725F7b8037513915aAf6D6CBDE2920E28540dDc", + "constructorArguments": "", + "isProxy": true, + "name": "StaticMerkleRootMultisigIsm" + }, + { + "address": "0xAF03386044373E2fe26C5b1dCedF5a7e854a7a3F", + "constructorArguments": "", + "isProxy": true, + "name": "StaticMessageIdMultisigIsm" + }, + { + "address": "0x882CD0C5D50b6dD74b36Da4BDb059507fddEDdf2", + "constructorArguments": "", + "isProxy": true, + "name": "StaticAggregationIsm" + }, + { + "address": "0x19930232E9aFC4f4F09d09fe2375680fAc2100D0", + "constructorArguments": "", + "isProxy": true, + "name": "StaticAggregationHook" + }, { "address": "0x9d9238fD3715281De2c8FC321135bF82EB66E932", "constructorArguments": "", @@ -2362,6 +3316,36 @@ "isProxy": false, "name": "DomainRoutingIsmFactory" }, + { + "address": "0x12Ed1BbA182CbC63692F813651BD493B7445C874", + "constructorArguments": "", + "isProxy": true, + "name": "DomaingRoutingIsm" + }, + { + "address": "0x4725F7b8037513915aAf6D6CBDE2920E28540dDc", + "constructorArguments": "", + "isProxy": true, + "name": "StaticMerkleRootMultisigIsm" + }, + { + "address": "0xAF03386044373E2fe26C5b1dCedF5a7e854a7a3F", + "constructorArguments": "", + "isProxy": true, + "name": "StaticMessageIdMultisigIsm" + }, + { + "address": "0x882CD0C5D50b6dD74b36Da4BDb059507fddEDdf2", + "constructorArguments": "", + "isProxy": true, + "name": "StaticAggregationIsm" + }, + { + "address": "0x19930232E9aFC4f4F09d09fe2375680fAc2100D0", + "constructorArguments": "", + "isProxy": true, + "name": "StaticAggregationHook" + }, { "address": "0x12Ed1BbA182CbC63692F813651BD493B7445C874", "constructorArguments": "", diff --git a/typescript/infra/config/environments/mainnet3/tokenPrices.json b/typescript/infra/config/environments/mainnet3/tokenPrices.json index 9c8c3f9117..b39ffb1085 100644 --- a/typescript/infra/config/environments/mainnet3/tokenPrices.json +++ b/typescript/infra/config/environments/mainnet3/tokenPrices.json @@ -3,9 +3,11 @@ "arbitrum": "2914.61", "avalanche": "35.71", "bsc": "373.19", + "blast": "2914.61", "celo": "0.772619", "ethereum": "2914.61", "mantapacific": "2914.61", + "mode": "2914.61", "moonbeam": "0.419658", "optimism": "2914.61", "polygon": "0.982687", diff --git a/typescript/infra/config/environments/mainnet3/validators.ts b/typescript/infra/config/environments/mainnet3/validators.ts index ad32c9339f..ad68b2a0a6 100644 --- a/typescript/infra/config/environments/mainnet3/validators.ts +++ b/typescript/infra/config/environments/mainnet3/validators.ts @@ -339,7 +339,7 @@ export const validatorChainConfig = ( }, viction: { interval: 5, - reorgPeriod: 0, + reorgPeriod: getReorgPeriod(chainMetadata.viction), validators: validatorsConfig( { [Contexts.Hyperlane]: ['0x1f87c368f8e05a85ef9126d984a980a20930cb9c'], @@ -353,5 +353,33 @@ export const validatorChainConfig = ( 'viction', ), }, + blast: { + interval: 5, + reorgPeriod: getReorgPeriod(chainMetadata.blast), + validators: validatorsConfig( + { + [Contexts.Hyperlane]: ['0xf20c0b09f597597c8d2430d3d72dfddaf09177d1'], + [Contexts.ReleaseCandidate]: [ + '0x5b32f226e472da6ca19abfe1a29d5d28102a2d1a', + ], + [Contexts.Neutron]: [], + }, + 'blast', + ), + }, + mode: { + interval: 5, + reorgPeriod: getReorgPeriod(chainMetadata.mode), + validators: validatorsConfig( + { + [Contexts.Hyperlane]: ['0x7eb2e1920a4166c19d6884c1cec3d2cf356fc9b7'], + [Contexts.ReleaseCandidate]: [ + '0x2f04ed30b1c27ef8e9e6acd360728d9bd5c3a9e2', + ], + [Contexts.Neutron]: [], + }, + 'mode', + ), + }, }; }; diff --git a/typescript/infra/scripts/announce-validators.ts b/typescript/infra/scripts/announce-validators.ts index 82d1685119..8bdb09ab05 100644 --- a/typescript/infra/scripts/announce-validators.ts +++ b/typescript/infra/scripts/announce-validators.ts @@ -26,15 +26,11 @@ function getArgs() { 'location, e.g. s3://hyperlane-testnet4-sepolia-validator-0/us-east-1', ) .string('location') - .check(({ context, chain, location }) => { - const isSet = [!!context, !!chain, !!location]; - if (isSet[1] == isSet[2]) { - return true; - } else { - throw new Error( - 'Must set either both or neither of chain and location', - ); + .check(({ chain, location }) => { + if (!!location && !chain) { + throw new Error('Must set chain when setting location'); } + return true; }).argv; } @@ -82,15 +78,21 @@ async function main() { } await Promise.all( Object.entries(agentConfig.validators.chains) - .filter(([chain, _]) => isEthereumProtocolChain(chain)) - .map(async ([chain, validatorChainConfig]) => { + .filter(([validatorChain, _]) => { + // If a chain arg was specified, filter to only that chain + if (!!chain && chain !== validatorChain) { + return false; + } + return isEthereumProtocolChain(validatorChain); + }) + .map(async ([validatorChain, validatorChainConfig]) => { for (const validatorBaseConfig of validatorChainConfig.validators) { if ( validatorBaseConfig.checkpointSyncer.type == CheckpointSyncerType.S3 ) { - const contracts = core.getContracts(chain); - const localDomain = multiProvider.getDomainId(chain); + const contracts = core.getContracts(validatorChain); + const localDomain = multiProvider.getDomainId(validatorChain); const validator = new S3Validator( validatorBaseConfig.address, localDomain, @@ -103,7 +105,7 @@ async function main() { storageLocation: validator.storageLocation(), announcement: await validator.getAnnouncement(), }); - chains.push(chain); + chains.push(validatorChain); } } }), diff --git a/typescript/infra/src/agents/gcp.ts b/typescript/infra/src/agents/gcp.ts index f7041e6462..782c34631d 100644 --- a/typescript/infra/src/agents/gcp.ts +++ b/typescript/infra/src/agents/gcp.ts @@ -123,7 +123,7 @@ export class AgentGCPKey extends CloudAgentKey { ); // TODO support other prefixes? // https://cosmosdrops.io/en/tools/bech32-converter is useful for converting to other prefixes. - return pubkeyToAddress(encodedPubkey, 'inj'); + return pubkeyToAddress(encodedPubkey, 'neutron'); } default: this.logger.debug(`Unsupported protocol: ${protocol}`); diff --git a/typescript/infra/src/deployment/deploy.ts b/typescript/infra/src/deployment/deploy.ts index e7737bf4d9..8ea0b55c4d 100644 --- a/typescript/infra/src/deployment/deploy.ts +++ b/typescript/infra/src/deployment/deploy.ts @@ -136,8 +136,13 @@ export async function writeAgentConfig( } const mailbox = core.getContracts(chain).mailbox; - const deployedBlock = await mailbox.deployedBlock(); - return deployedBlock.toNumber(); + try { + const deployedBlock = await mailbox.deployedBlock(); + return deployedBlock.toNumber(); + } catch (err) { + console.error('Failed to get deployed block for', chain, err); + return 0; + } }), ); diff --git a/typescript/sdk/src/consts/chainMetadata.ts b/typescript/sdk/src/consts/chainMetadata.ts index 0f4bda7abb..254c54a0ed 100644 --- a/typescript/sdk/src/consts/chainMetadata.ts +++ b/typescript/sdk/src/consts/chainMetadata.ts @@ -94,7 +94,6 @@ export const arbitrum: ChainMetadata = { displayName: 'Arbitrum', domainId: 42161, gasCurrencyCoinGeckoId: 'ethereum', - // ETH is used for gas gnosisSafeTransactionServiceUrl: 'https://safe-transaction-arbitrum.safe.global/', index: { @@ -155,7 +154,6 @@ export const base: ChainMetadata = { url: 'https://basescan.org', }, ], - // ETH is used for gas blocks: { confirmations: 1, estimateBlockTime: 2, @@ -176,6 +174,38 @@ export const base: ChainMetadata = { ], }; +export const blast: ChainMetadata = { + blockExplorers: [ + { + apiUrl: 'https://api.blastscan.io/api', + family: ExplorerFamily.Etherscan, + name: 'Blast Explorer', + url: 'https://blastscan.io', + }, + { + apiUrl: + 'https://api.routescan.io/v2/network/mainnet/evm/81457/etherscan/api', + family: ExplorerFamily.Routescan, + name: 'Blast Explorer', + url: 'https://blastexplorer.io', + }, + ], + blocks: { + confirmations: 1, + estimateBlockTime: 2, + reorgPeriod: 1, + }, + chainId: 81457, + displayName: 'Blast', + domainId: 81457, + gasCurrencyCoinGeckoId: 'ethereum', + name: Chains.blast, + nativeToken: etherToken, + protocol: ProtocolType.Ethereum, + rpcUrls: [{ http: 'https://rpc.blast.io' }], + technicalStack: ChainTechnicalStack.Other, +}; + export const bsc: ChainMetadata = { blockExplorers: [ { @@ -473,6 +503,31 @@ export const mantapacific: ChainMetadata = { rpcUrls: [{ http: 'https://pacific-rpc.manta.network/http' }], }; +export const mode: ChainMetadata = { + blockExplorers: [ + { + apiUrl: 'https://explorer.mode.network/api', + family: ExplorerFamily.Blockscout, + name: 'Mode Explorer', + url: 'https://explorer.mode.network', + }, + ], + blocks: { + confirmations: 1, + estimateBlockTime: 2, + reorgPeriod: 1, + }, + chainId: 34443, + displayName: 'Mode', + domainId: 34443, + gasCurrencyCoinGeckoId: 'ethereum', + name: Chains.mode, + nativeToken: etherToken, + protocol: ProtocolType.Ethereum, + rpcUrls: [{ http: 'https://mainnet.mode.network' }], + technicalStack: ChainTechnicalStack.Other, +}; + export const moonbeam: ChainMetadata = { blockExplorers: [ { @@ -581,7 +636,6 @@ export const optimism: ChainMetadata = { displayName: 'Optimism', domainId: 10, gasCurrencyCoinGeckoId: 'ethereum', - // ETH is used for gas gnosisSafeTransactionServiceUrl: 'https://safe-transaction-optimism.safe.global/', name: Chains.optimism, @@ -667,7 +721,6 @@ export const polygonzkevm: ChainMetadata = { url: 'https://zkevm.polygonscan.com', }, ], - // ETH is used for gas blocks: { confirmations: 1, estimateBlockTime: 10, @@ -720,7 +773,6 @@ export const scroll: ChainMetadata = { url: 'https://scrollscan.com/', }, ], - // ETH is used for gas blocks: { confirmations: 1, estimateBlockTime: 3, @@ -979,6 +1031,7 @@ export const chainMetadata: ChainMap = { arbitrum, avalanche, base, + blast, bsc, bsctestnet, celo, @@ -990,6 +1043,7 @@ export const chainMetadata: ChainMap = { inevm, injective, mantapacific, + mode, moonbeam, nautilus, neutron, diff --git a/typescript/sdk/src/consts/chains.ts b/typescript/sdk/src/consts/chains.ts index daf991c344..979aa2bb22 100644 --- a/typescript/sdk/src/consts/chains.ts +++ b/typescript/sdk/src/consts/chains.ts @@ -8,6 +8,7 @@ export enum Chains { arbitrum = 'arbitrum', avalanche = 'avalanche', base = 'base', + blast = 'blast', bsc = 'bsc', bsctestnet = 'bsctestnet', celo = 'celo', @@ -18,6 +19,7 @@ export enum Chains { inevm = 'inevm', injective = 'injective', mantapacific = 'mantapacific', + mode = 'mode', moonbeam = 'moonbeam', nautilus = 'nautilus', neutron = 'neutron', @@ -56,16 +58,18 @@ export const Mainnets: Array = [ Chains.arbitrum, Chains.ancient8, Chains.avalanche, + Chains.base, + Chains.blast, Chains.bsc, Chains.celo, Chains.ethereum, Chains.neutron, Chains.mantapacific, + Chains.mode, Chains.moonbeam, Chains.optimism, Chains.polygon, Chains.gnosis, - Chains.base, Chains.scroll, Chains.polygonzkevm, Chains.injective, diff --git a/typescript/sdk/src/consts/environments/mainnet.json b/typescript/sdk/src/consts/environments/mainnet.json index 600db8d3d7..ed4818abe2 100644 --- a/typescript/sdk/src/consts/environments/mainnet.json +++ b/typescript/sdk/src/consts/environments/mainnet.json @@ -1,37 +1,37 @@ { "ancient8": { - "staticAggregationHookFactory": "0xEb9FcFDC9EfDC17c1EC5E1dc085B98485da213D6", - "staticAggregationIsmFactory": "0x8F7454AC98228f3504Bb91eA3D8Adafe6406110A", + "domainRoutingIsmFactory": "0x1052eF3419f26Bec74Ed7CEf4a4FA6812Bc09908", "fallbackRoutingHook": "0x5E01d8F34b629E3f92d69546bbc4142A7Adee7e9", "interchainGasPaymaster": "0x8F1E22d309baa69D398a03cc88E9b46037e988AA", "interchainSecurityModule": "0x6E3387e12C6e181BF8e712eCa9c60ccEEaBD1c67", "mailbox": "0x2f2aFaE1139Ce54feFC03593FeE8AB2aDF4a85A7", - "staticMerkleRootMultisigIsmFactory": "0x2C1FAbEcd7bFBdEBF27CcdB67baADB38b6Df90fC", "merkleTreeHook": "0x811808Dd29ba8B0FC6C0ec0b5537035E59745162", - "staticMessageIdMultisigIsmFactory": "0x8b83fefd896fAa52057798f6426E9f0B080FCCcE", "pausableHook": "0x66DC49405Ae2956f7E87FEAa9fE8f506C8987462", "protocolFee": "0xE0C452DDA7506f0F4dE5C8C1d383F7aD866eA4F0", "proxyAdmin": "0x0761b0827849abbf7b0cC09CE14e1C93D87f5004", - "domainRoutingIsmFactory": "0x1052eF3419f26Bec74Ed7CEf4a4FA6812Bc09908", + "staticAggregationHookFactory": "0xEb9FcFDC9EfDC17c1EC5E1dc085B98485da213D6", + "staticAggregationIsmFactory": "0x8F7454AC98228f3504Bb91eA3D8Adafe6406110A", + "staticMerkleRootMultisigIsmFactory": "0x2C1FAbEcd7bFBdEBF27CcdB67baADB38b6Df90fC", + "staticMessageIdMultisigIsmFactory": "0x8b83fefd896fAa52057798f6426E9f0B080FCCcE", "storageGasOracle": "0x59Bf7c7b458375b1A7c453aE70EaCb376E65CDAF", "testRecipient": "0x2Fa570E83009eaEef3a1cbd496a9a30F05266634", "validatorAnnounce": "0x931dFCc8c1141D6F532FD023bd87DAe0080c835d" }, "arbitrum": { "aggregationHook": "0xe0cb37cFc47296f1c4eD77EFf92Aed478644d10c", - "staticAggregationHookFactory": "0x9B5f440bBb64Fee337F37e03362b628711Ea09C7", - "staticAggregationIsmFactory": "0xD4883084389fC1Eeb4dAfB2ADcFc36B711c310EB", + "domainRoutingIsmFactory": "0xa2931C37957f3079d3B21b877d56E1db930e02a5", "fallbackRoutingHook": "0x9e8fFb1c26099e75Dd5D794030e2E9AA51471c25", "interchainGasPaymaster": "0x3b6044acd6767f017e99318AA6Ef93b7B06A5a22", "interchainSecurityModule": "0xD0DBBF922076352cC50B285A0023536561F00EEa", "mailbox": "0x979Ca5202784112f4738403dBec5D0F3B9daabB9", - "staticMerkleRootMultisigIsmFactory": "0x3C330D4A2e2b8443AFaB8E326E64ab4251B7Eae0", "merkleTreeHook": "0x748040afB89B8FdBb992799808215419d36A0930", - "staticMessageIdMultisigIsmFactory": "0x12Df53079d399a47e9E730df095b712B0FDFA791", "pausableHook": "0xEf30f29Dcd3FCB1DCcDA9C7Cbf2A5957E8Ee9Cc3", "protocolFee": "0xD0199067DACb8526e7dc524a9a7DCBb57Cd25421", "proxyAdmin": "0x80Cebd56A65e46c474a1A101e89E76C4c51D179c", - "domainRoutingIsmFactory": "0xa2931C37957f3079d3B21b877d56E1db930e02a5", + "staticAggregationHookFactory": "0x9B5f440bBb64Fee337F37e03362b628711Ea09C7", + "staticAggregationIsmFactory": "0xD4883084389fC1Eeb4dAfB2ADcFc36B711c310EB", + "staticMerkleRootMultisigIsmFactory": "0x3C330D4A2e2b8443AFaB8E326E64ab4251B7Eae0", + "staticMessageIdMultisigIsmFactory": "0x12Df53079d399a47e9E730df095b712B0FDFA791", "storageGasOracle": "0xD3805207b65d99C075ceA938Fa7c0587026a5DF5", "testRecipient": "0x36FdA966CfffF8a9Cdc814f546db0e6378bFef35", "testTokenRecipient": "0x85ac1164878e017b67660a74ff1f41f3D05C02Bb", @@ -39,19 +39,19 @@ }, "avalanche": { "aggregationHook": "0x0165a22BA489F7DA37DAf6397781777D9FCB5708", - "staticAggregationHookFactory": "0x3bF6Ac986C7Af9A9Ac356C0e99C0041EFd8D96e7", - "staticAggregationIsmFactory": "0xa5E13796eB7d2EDCc88012c8cfF90D69B51FcF9f", + "domainRoutingIsmFactory": "0x28F7907911C7E321c596686AE6D1F20516450037", "fallbackRoutingHook": "0x61D15D571D5f7A9eF0D1938f072f430bBF024747", "interchainGasPaymaster": "0x95519ba800BBd0d34eeAE026fEc620AD978176C0", "interchainSecurityModule": "0xA36B02a83564f52d9244310Ea439ee6F6AfeFb60", "mailbox": "0xFf06aFcaABaDDd1fb08371f9ccA15D73D51FeBD6", - "staticMerkleRootMultisigIsmFactory": "0x896cF1D1B66cD211633eDd589fF158E8Cfaf9B54", "merkleTreeHook": "0x84eea61D679F42D92145fA052C89900CBAccE95A", - "staticMessageIdMultisigIsmFactory": "0x8819D653DF5b1FC0DdB32189a2704E471AF8483c", "pausableHook": "0x239eB860770F1C48ABAC9bE9825d20e3E7c018df", "protocolFee": "0xEc4AdA26E51f2685279F37C8aE62BeAd8212D597", "proxyAdmin": "0xd7CF8c05fd81b8cA7CfF8E6C49B08a9D63265c9B", - "domainRoutingIsmFactory": "0x28F7907911C7E321c596686AE6D1F20516450037", + "staticAggregationHookFactory": "0x3bF6Ac986C7Af9A9Ac356C0e99C0041EFd8D96e7", + "staticAggregationIsmFactory": "0xa5E13796eB7d2EDCc88012c8cfF90D69B51FcF9f", + "staticMerkleRootMultisigIsmFactory": "0x896cF1D1B66cD211633eDd589fF158E8Cfaf9B54", + "staticMessageIdMultisigIsmFactory": "0x8819D653DF5b1FC0DdB32189a2704E471AF8483c", "storageGasOracle": "0x175821F30AdCAA4bbB72Ce98eF76C2E0De2C3f21", "testRecipient": "0x36FdA966CfffF8a9Cdc814f546db0e6378bFef35", "testTokenRecipient": "0x85ac1164878e017b67660a74ff1f41f3D05C02Bb", @@ -59,37 +59,55 @@ }, "base": { "aggregationHook": "0x13f3d4B0Ee0a713430fded9E18f7fb6c91A6E41F", - "staticAggregationHookFactory": "0x1052eF3419f26Bec74Ed7CEf4a4FA6812Bc09908", - "staticAggregationIsmFactory": "0xEb9FcFDC9EfDC17c1EC5E1dc085B98485da213D6", + "domainRoutingIsmFactory": "0x7E27456a839BFF31CA642c060a2b68414Cb6e503", "fallbackRoutingHook": "0x4Eb82Ee35b0a1c1d776E3a3B547f9A9bA6FCC9f2", "interchainGasPaymaster": "0xc3F23848Ed2e04C0c6d41bd7804fa8f89F940B94", "interchainSecurityModule": "0x5D1e7D7c5B9e6dDC8439F67F10c578f2A1084f6F", "mailbox": "0xeA87ae93Fa0019a82A727bfd3eBd1cFCa8f64f1D", - "staticMerkleRootMultisigIsmFactory": "0x8b83fefd896fAa52057798f6426E9f0B080FCCcE", "merkleTreeHook": "0x19dc38aeae620380430C200a6E990D5Af5480117", - "staticMessageIdMultisigIsmFactory": "0x8F7454AC98228f3504Bb91eA3D8Adafe6406110A", "pausableHook": "0x46fa3A5780e5B90Eaf34BDED554d5353B5ABE9E7", "protocolFee": "0x99ca8c74cE7Cfa9d72A51fbb05F9821f5f826b3a", "proxyAdmin": "0x4Ed7d626f1E96cD1C0401607Bf70D95243E3dEd1", - "domainRoutingIsmFactory": "0x7E27456a839BFF31CA642c060a2b68414Cb6e503", + "staticAggregationHookFactory": "0x1052eF3419f26Bec74Ed7CEf4a4FA6812Bc09908", + "staticAggregationIsmFactory": "0xEb9FcFDC9EfDC17c1EC5E1dc085B98485da213D6", + "staticMerkleRootMultisigIsmFactory": "0x8b83fefd896fAa52057798f6426E9f0B080FCCcE", + "staticMessageIdMultisigIsmFactory": "0x8F7454AC98228f3504Bb91eA3D8Adafe6406110A", "storageGasOracle": "0xBF12ef4B9f307463D3FB59c3604F294dDCe287E2", "validatorAnnounce": "0x182E8d7c5F1B06201b102123FC7dF0EaeB445a7B" }, + "blast": { + "domainRoutingIsmFactory": "0x2f2aFaE1139Ce54feFC03593FeE8AB2aDF4a85A7", + "fallbackRoutingHook": "0x6Fae4D9935E2fcb11fC79a64e917fb2BF14DaFaa", + "interchainGasPaymaster": "0xB3fCcD379ad66CED0c91028520C64226611A48c9", + "interchainSecurityModule": "0xfeBe2fB33d203B43D763f119874574c33326d545", + "mailbox": "0x3a867fCfFeC2B790970eeBDC9023E75B0a172aa7", + "merkleTreeHook": "0xC9B8ea6230d6687a4b13fD3C0b8f0Ec607B26465", + "pausableHook": "0xE0C452DDA7506f0F4dE5C8C1d383F7aD866eA4F0", + "protocolFee": "0x12582c7B0f43c6A667CBaA7fA8b112F7fb1E69F0", + "proxyAdmin": "0xeA87ae93Fa0019a82A727bfd3eBd1cFCa8f64f1D", + "staticAggregationHookFactory": "0x4Ed7d626f1E96cD1C0401607Bf70D95243E3dEd1", + "staticAggregationIsmFactory": "0x0761b0827849abbf7b0cC09CE14e1C93D87f5004", + "staticMerkleRootMultisigIsmFactory": "0xEb9FcFDC9EfDC17c1EC5E1dc085B98485da213D6", + "staticMessageIdMultisigIsmFactory": "0x1052eF3419f26Bec74Ed7CEf4a4FA6812Bc09908", + "storageGasOracle": "0xBDa330Ea8F3005C421C8088e638fBB64fA71b9e0", + "testRecipient": "0x17E216fBb22dF4ef8A6640ae9Cb147C92710ac84", + "validatorAnnounce": "0xFC62DeF1f08793aBf0E67f69257c6be258194F72" + }, "bsc": { "aggregationHook": "0x402Fc106576462a892355d69ACF03D46A888ae88", - "staticAggregationHookFactory": "0xe70E86a7D1e001D419D71F960Cb6CaD59b6A3dB6", - "staticAggregationIsmFactory": "0x38B3878c4fb44d201DA924c4a04bae3EE728c065", + "domainRoutingIsmFactory": "0xe6Af5720d34213C805C08e2470aea979e3F72F75", "fallbackRoutingHook": "0x237E81f87F57Badad9e09f13CC676D986cA852e7", "interchainGasPaymaster": "0x78E25e7f84416e69b9339B0A6336EB6EFfF6b451", "interchainSecurityModule": "0xab3df354baBee6c2B88E2CeD3b2e030e31aA5e61", "mailbox": "0x2971b9Aec44bE4eb673DF1B88cDB57b96eefe8a4", - "staticMerkleRootMultisigIsmFactory": "0xfADBc81Ca8A957F1Bf7c78bCc575b28DBDE042b6", "merkleTreeHook": "0xFDb9Cd5f9daAA2E4474019405A328a88E7484f26", - "staticMessageIdMultisigIsmFactory": "0x4B1d8352E35e3BDE36dF5ED2e73C24E35c4a96b7", "pausableHook": "0x7DBdAd1b4A922B65d37d7258a4227b6658344b7f", "protocolFee": "0xA8Aa5f14a5463a78E45CC068F11c867949F3E367", "proxyAdmin": "0x65993Af9D0D3a64ec77590db7ba362D6eB78eF70", - "domainRoutingIsmFactory": "0xe6Af5720d34213C805C08e2470aea979e3F72F75", + "staticAggregationHookFactory": "0xe70E86a7D1e001D419D71F960Cb6CaD59b6A3dB6", + "staticAggregationIsmFactory": "0x38B3878c4fb44d201DA924c4a04bae3EE728c065", + "staticMerkleRootMultisigIsmFactory": "0xfADBc81Ca8A957F1Bf7c78bCc575b28DBDE042b6", + "staticMessageIdMultisigIsmFactory": "0x4B1d8352E35e3BDE36dF5ED2e73C24E35c4a96b7", "storageGasOracle": "0x91d23D603d60445411C06e6443d81395593B7940", "testRecipient": "0x36FdA966CfffF8a9Cdc814f546db0e6378bFef35", "testTokenRecipient": "0x85ac1164878e017b67660a74ff1f41f3D05C02Bb", @@ -97,22 +115,22 @@ }, "celo": { "aggregationHook": "0xc65890329066FB20c339Bc5C22f1756e9D3a4fF5", - "staticAggregationHookFactory": "0xc3745652EFB8555A8b064A0EA78d295133d326D2", - "staticAggregationIsmFactory": "0x1722dd970a1F56040712129f5Eeb76B003fd7500", "domainRoutingIsm": "0xf18E32428dad0802C5D6F723cB80A6Da889777c4", + "domainRoutingIsmFactory": "0x2A2c22B0a8615ad24839fA6Af302E896Af32d1a3", "fallbackRoutingHook": "0xDC98a856fb9112894c2fE32267DA8bF35645FAF3", "interchainGasPaymaster": "0x571f1435613381208477ac5d6974310d88AC7cB7", "interchainSecurityModule": "0x99e8E56Dce3402D6E09A82718937fc1cA2A9491E", "mailbox": "0x50da3B3907A08a24fe4999F4Dcf337E8dC7954bb", - "staticMerkleRootMultisigIsmFactory": "0x4C96a1abc44dc846775CE702C9E9BE821D3b487c", "merkleTreeHook": "0x04dB778f05854f26E67e0a66b740BBbE9070D366", - "staticMessageIdMultisigIsmFactory": "0xaB402f227e892Ef37C105bf06619c0fa106a1fB2", "pausableHook": "0x80672c5D9Fd26B235654C24adc1CFcDeb8d15115", "pausableIsm": "0x6Bc4437ce69696C9461Cbc89582c259AC8847A58", "protocolFee": "0x89886d431f9c3eEE64DCD6dAbA3f7D689D98D899", "proxyAdmin": "0x90f9a2E9eCe93516d65FdaB726a3c62F5960a1b9", - "domainRoutingIsmFactory": "0x2A2c22B0a8615ad24839fA6Af302E896Af32d1a3", + "staticAggregationHookFactory": "0xc3745652EFB8555A8b064A0EA78d295133d326D2", "staticAggregationIsm": "0x99e8E56Dce3402D6E09A82718937fc1cA2A9491E", + "staticAggregationIsmFactory": "0x1722dd970a1F56040712129f5Eeb76B003fd7500", + "staticMerkleRootMultisigIsmFactory": "0x4C96a1abc44dc846775CE702C9E9BE821D3b487c", + "staticMessageIdMultisigIsmFactory": "0xaB402f227e892Ef37C105bf06619c0fa106a1fB2", "storageGasOracle": "0xD9A9966E7dA9a7f0032bF449FB12696a638E673C", "testRecipient": "0x36FdA966CfffF8a9Cdc814f546db0e6378bFef35", "testTokenRecipient": "0x85ac1164878e017b67660a74ff1f41f3D05C02Bb", @@ -120,19 +138,19 @@ }, "ethereum": { "aggregationHook": "0xb87AC8EA4533AE017604E44470F7c1E550AC6F10", - "staticAggregationHookFactory": "0x6D2555A8ba483CcF4409C39013F5e9a3285D3C9E", - "staticAggregationIsmFactory": "0x46FA191Ad972D9674Ed752B69f9659A0d7b22846", + "domainRoutingIsmFactory": "0x28fA9552F19039b450498B0d8e5DEAe0d0aAc559", "fallbackRoutingHook": "0x571f1435613381208477ac5d6974310d88AC7cB7", "interchainGasPaymaster": "0x9e6B1022bE9BBF5aFd152483DAD9b88911bC8611", "interchainSecurityModule": "0x43Ce4Eb4aE3585dDe9Ac6967Db5b06f7f6764C8a", "mailbox": "0xc005dc82818d67AF737725bD4bf75435d065D239", - "staticMerkleRootMultisigIsmFactory": "0x47e8aF9e30C32Ab91060ED587894288786761B45", "merkleTreeHook": "0x48e6c30B97748d1e2e03bf3e9FbE3890ca5f8CCA", - "staticMessageIdMultisigIsmFactory": "0xfA21D9628ADce86531854C2B7ef00F07394B0B69", "pausableHook": "0x3A66Dc852e56d3748838b3C27CF381105b83705b", "protocolFee": "0x8B05BF30F6247a90006c5837eA63C7905D79e6d8", "proxyAdmin": "0x75EE15Ee1B4A75Fa3e2fDF5DF3253c25599cc659", - "domainRoutingIsmFactory": "0x28fA9552F19039b450498B0d8e5DEAe0d0aAc559", + "staticAggregationHookFactory": "0x6D2555A8ba483CcF4409C39013F5e9a3285D3C9E", + "staticAggregationIsmFactory": "0x46FA191Ad972D9674Ed752B69f9659A0d7b22846", + "staticMerkleRootMultisigIsmFactory": "0x47e8aF9e30C32Ab91060ED587894288786761B45", + "staticMessageIdMultisigIsmFactory": "0xfA21D9628ADce86531854C2B7ef00F07394B0B69", "storageGasOracle": "0xc9a103990A8dB11b4f627bc5CD1D0c2685484Ec5", "testRecipient": "0x36FdA966CfffF8a9Cdc814f546db0e6378bFef35", "testTokenRecipient": "0x85ac1164878e017b67660a74ff1f41f3D05C02Bb", @@ -140,19 +158,19 @@ }, "gnosis": { "aggregationHook": "0xdD1FA1C12496474c1dDC67a658Ba81437F818861", - "staticAggregationHookFactory": "0xbC8AA096dabDf4A0200BB9f8D4Cbb644C3D86d7B", - "staticAggregationIsmFactory": "0x11EF91d17c5ad3330DbCa709a8841743d3Af6819", + "domainRoutingIsmFactory": "0xbB5Df000113e767dE11343A16f83De733e5bCC0F", "fallbackRoutingHook": "0x24f5E353dD03E103Ba2372F7D6FC0cf3A66f849c", "interchainGasPaymaster": "0xDd260B99d302f0A3fF885728c086f729c06f227f", "interchainSecurityModule": "0x8e1aa0687B6d939D5a44304D13B7c922ebB012f1", "mailbox": "0xaD09d78f4c6b9dA2Ae82b1D34107802d380Bb74f", - "staticMerkleRootMultisigIsmFactory": "0x8E273260EAd8B72A085B19346A676d355740e875", "merkleTreeHook": "0x2684C6F89E901987E1FdB7649dC5Be0c57C61645", - "staticMessageIdMultisigIsmFactory": "0x603f46cc520d2fc22957b81e206408590808F02F", "pausableHook": "0xf728C884De5275a608dEC222dACd0f2BF2E23AB6", "protocolFee": "0x9c2214467Daf9e2e1F45b36d08ce0b9C65BFeA88", "proxyAdmin": "0x81a92A1a272cb09d7b4970b07548463dC7aE0cB7", - "domainRoutingIsmFactory": "0xbB5Df000113e767dE11343A16f83De733e5bCC0F", + "staticAggregationHookFactory": "0xbC8AA096dabDf4A0200BB9f8D4Cbb644C3D86d7B", + "staticAggregationIsmFactory": "0x11EF91d17c5ad3330DbCa709a8841743d3Af6819", + "staticMerkleRootMultisigIsmFactory": "0x8E273260EAd8B72A085B19346A676d355740e875", + "staticMessageIdMultisigIsmFactory": "0x603f46cc520d2fc22957b81e206408590808F02F", "storageGasOracle": "0x5E01d8F34b629E3f92d69546bbc4142A7Adee7e9", "testRecipient": "0x36FdA966CfffF8a9Cdc814f546db0e6378bFef35", "testTokenRecipient": "0x85ac1164878e017b67660a74ff1f41f3D05C02Bb", @@ -160,60 +178,78 @@ }, "inevm": { "aggregationHook": "0xe0dDb5dE7D52918237cC1Ae131F29dcAbcb0F62B", - "staticAggregationHookFactory": "0xEb9FcFDC9EfDC17c1EC5E1dc085B98485da213D6", - "staticAggregationIsmFactory": "0x8F7454AC98228f3504Bb91eA3D8Adafe6406110A", "domainRoutingIsm": "0xBD70Ea9D599a0FC8158B026797177773C3445730", + "domainRoutingIsmFactory": "0x1052eF3419f26Bec74Ed7CEf4a4FA6812Bc09908", "interchainGasPaymaster": "0x19dc38aeae620380430C200a6E990D5Af5480117", "interchainSecurityModule": "0x3052aD50De54aAAc5D364d80bBE681d29e924597", "mailbox": "0x2f2aFaE1139Ce54feFC03593FeE8AB2aDF4a85A7", - "staticMerkleRootMultisigIsmFactory": "0x2C1FAbEcd7bFBdEBF27CcdB67baADB38b6Df90fC", "merkleTreeHook": "0x0972954923a1e2b2aAb04Fa0c4a0797e5989Cd65", - "staticMessageIdMultisigIsmFactory": "0x8b83fefd896fAa52057798f6426E9f0B080FCCcE", "pausableHook": "0xBDa330Ea8F3005C421C8088e638fBB64fA71b9e0", "pausableIsm": "0x6Fae4D9935E2fcb11fC79a64e917fb2BF14DaFaa", "protocolFee": "0x0D63128D887159d63De29497dfa45AFc7C699AE4", "proxyAdmin": "0x0761b0827849abbf7b0cC09CE14e1C93D87f5004", - "domainRoutingIsmFactory": "0x1052eF3419f26Bec74Ed7CEf4a4FA6812Bc09908", + "staticAggregationHookFactory": "0xEb9FcFDC9EfDC17c1EC5E1dc085B98485da213D6", "staticAggregationIsm": "0x3052aD50De54aAAc5D364d80bBE681d29e924597", + "staticAggregationIsmFactory": "0x8F7454AC98228f3504Bb91eA3D8Adafe6406110A", + "staticMerkleRootMultisigIsmFactory": "0x2C1FAbEcd7bFBdEBF27CcdB67baADB38b6Df90fC", + "staticMessageIdMultisigIsmFactory": "0x8b83fefd896fAa52057798f6426E9f0B080FCCcE", "storageGasOracle": "0x6119E37Bd66406A1Db74920aC79C15fB8411Ba76", "validatorAnnounce": "0x15ab173bDB6832f9b64276bA128659b0eD77730B" }, "mantapacific": { "aggregationHook": "0x8464aF853363B8d6844070F68b0AB34Cb6523d0F", - "staticAggregationHookFactory": "0x0761b0827849abbf7b0cC09CE14e1C93D87f5004", - "staticAggregationIsmFactory": "0x1052eF3419f26Bec74Ed7CEf4a4FA6812Bc09908", "domainRoutingIsm": "0xDEed16fe4b1c9b2a93483EDFf34C77A9b57D31Ff", + "domainRoutingIsmFactory": "0x8358D8291e3bEDb04804975eEa0fe9fe0fAfB147", "fallbackRoutingHook": "0xD1E267d2d7876e97E217BfE61c34AB50FEF52807", "interchainGasPaymaster": "0x0D63128D887159d63De29497dfa45AFc7C699AE4", "interchainSecurityModule": "0xDEed16fe4b1c9b2a93483EDFf34C77A9b57D31Ff", "mailbox": "0x3a464f746D23Ab22155710f44dB16dcA53e0775E", - "staticMerkleRootMultisigIsmFactory": "0x8F7454AC98228f3504Bb91eA3D8Adafe6406110A", "merkleTreeHook": "0x149db7afD694722747035d5AEC7007ccb6F8f112", - "staticMessageIdMultisigIsmFactory": "0xEb9FcFDC9EfDC17c1EC5E1dc085B98485da213D6", "pausableHook": "0x7556a0E61d577D921Cba8Fca0d7D6299d36E607E", "protocolFee": "0xd83A4F747fE80Ed98839e05079B1B7Fe037b1638", "proxyAdmin": "0x2f2aFaE1139Ce54feFC03593FeE8AB2aDF4a85A7", - "domainRoutingIsmFactory": "0x8358D8291e3bEDb04804975eEa0fe9fe0fAfB147", + "staticAggregationHookFactory": "0x0761b0827849abbf7b0cC09CE14e1C93D87f5004", + "staticAggregationIsmFactory": "0x1052eF3419f26Bec74Ed7CEf4a4FA6812Bc09908", + "staticMerkleRootMultisigIsmFactory": "0x8F7454AC98228f3504Bb91eA3D8Adafe6406110A", + "staticMessageIdMultisigIsmFactory": "0xEb9FcFDC9EfDC17c1EC5E1dc085B98485da213D6", "storageGasOracle": "0x19dc38aeae620380430C200a6E990D5Af5480117", "testRecipient": "0x4E1c88DD261BEe2941e6c1814597e30F53330428", "testTokenRecipient": "0x5060eCD5dFAD300A90592C04e504600A7cdcF70b", "validatorAnnounce": "0x2fa5F5C96419C222cDbCeC797D696e6cE428A7A9" }, + "mode": { + "domainRoutingIsmFactory": "0x1052eF3419f26Bec74Ed7CEf4a4FA6812Bc09908", + "fallbackRoutingHook": "0x8F1E22d309baa69D398a03cc88E9b46037e988AA", + "interchainGasPaymaster": "0x931dFCc8c1141D6F532FD023bd87DAe0080c835d", + "interchainSecurityModule": "0x8dfE6790DbB2Ecc1bEdb0eECfc1Ff467Ae5d8C89", + "mailbox": "0x2f2aFaE1139Ce54feFC03593FeE8AB2aDF4a85A7", + "merkleTreeHook": "0xE2ee936bEa8e42671c400aC96dE198E06F2bA2A6", + "pausableHook": "0xA1ac41d8A663fd317cc3BD94C7de92dC4BA4a882", + "protocolFee": "0xea820f9BCFD5E16a0dd42071EB61A29874Ad81A4", + "proxyAdmin": "0x0761b0827849abbf7b0cC09CE14e1C93D87f5004", + "staticAggregationHookFactory": "0xEb9FcFDC9EfDC17c1EC5E1dc085B98485da213D6", + "staticAggregationIsmFactory": "0x8F7454AC98228f3504Bb91eA3D8Adafe6406110A", + "staticMerkleRootMultisigIsmFactory": "0x2C1FAbEcd7bFBdEBF27CcdB67baADB38b6Df90fC", + "staticMessageIdMultisigIsmFactory": "0x8b83fefd896fAa52057798f6426E9f0B080FCCcE", + "storageGasOracle": "0xC9B8ea6230d6687a4b13fD3C0b8f0Ec607B26465", + "testRecipient": "0x12582c7B0f43c6A667CBaA7fA8b112F7fb1E69F0", + "validatorAnnounce": "0x48083C69f5a42c6B69ABbAd48AE195BD36770ee2" + }, "moonbeam": { "aggregationHook": "0x23cca255aE83F57F39EAf9D14fB9FdaDF22D5863", - "staticAggregationHookFactory": "0x59cC3E7A49DdC4893eB8754c7908f96072A7DbE8", - "staticAggregationIsmFactory": "0x40c6Abcb6A2CdC8882d4bEcaC47927005c7Bb8c2", + "domainRoutingIsmFactory": "0x8061Af3A459093540d17823D651BC5E2A92669a7", "fallbackRoutingHook": "0x6C2D6eA0969F7Aa0A850CCA88c7BFACa563B2361", "interchainGasPaymaster": "0x14760E32C0746094cF14D97124865BC7F0F7368F", "interchainSecurityModule": "0x373836DFa82f2D27ec79Ca32A197Aa1665F0E1e9", "mailbox": "0x094d03E751f49908080EFf000Dd6FD177fd44CC3", - "staticMerkleRootMultisigIsmFactory": "0xE2f485bc031Feb5a4C41C1967bf028653d75f0C3", "merkleTreeHook": "0x87403b85f6f316e7ba91ba1fa6C3Fb7dD4095547", - "staticMessageIdMultisigIsmFactory": "0x84Df48F8f241f11d0fA302d09d73030429Bd9C73", "pausableHook": "0xe28f2AEEB42ee83CAd068D9A9a449c8b868C137f", "protocolFee": "0xCd3e29A9D293DcC7341295996a118913F7c582c0", "proxyAdmin": "0x6A9cdA3dd1F593983BFd142Eb35e6ce4137bd5ce", - "domainRoutingIsmFactory": "0x8061Af3A459093540d17823D651BC5E2A92669a7", + "staticAggregationHookFactory": "0x59cC3E7A49DdC4893eB8754c7908f96072A7DbE8", + "staticAggregationIsmFactory": "0x40c6Abcb6A2CdC8882d4bEcaC47927005c7Bb8c2", + "staticMerkleRootMultisigIsmFactory": "0xE2f485bc031Feb5a4C41C1967bf028653d75f0C3", + "staticMessageIdMultisigIsmFactory": "0x84Df48F8f241f11d0fA302d09d73030429Bd9C73", "storageGasOracle": "0x448b7ADB0dA36d41AA2AfDc9d63b97541A7b3819", "testRecipient": "0x36FdA966CfffF8a9Cdc814f546db0e6378bFef35", "testTokenRecipient": "0x85ac1164878e017b67660a74ff1f41f3D05C02Bb", @@ -221,19 +257,19 @@ }, "optimism": { "aggregationHook": "0x4ccC6d8eB79f2a1EC9bcb0f211fef7907631F91f", - "staticAggregationHookFactory": "0x15DEeAB8dECDe553bb0B1F9C00984cbcae1af3D7", - "staticAggregationIsmFactory": "0x7491843F3A5Ba24E0f17a22645bDa04A1Ae2c584", + "domainRoutingIsmFactory": "0xD2e905108c5e44dADA680274740f896Ea96Cf2Fb", "fallbackRoutingHook": "0xD4b132C6d4AA93A4247F1A91e1ED929c0572a43d", "interchainGasPaymaster": "0xD8A76C4D91fCbB7Cc8eA795DFDF870E48368995C", "interchainSecurityModule": "0x04938856bE60c8e734ffDe5f720E2238302BE8D2", "mailbox": "0xd4C1905BB1D26BC93DAC913e13CaCC278CdCC80D", - "staticMerkleRootMultisigIsmFactory": "0xCA6Cb9Bc3cfF9E11003A06617cF934B684Bc78BC", "merkleTreeHook": "0x68eE9bec9B4dbB61f69D9D293Ae26a5AACb2e28f", - "staticMessageIdMultisigIsmFactory": "0xAa4Be20E9957fE21602c74d7C3cF5CB1112EA9Ef", "pausableHook": "0xf753CA2269c8A7693ce1808b5709Fbf36a65D47A", "protocolFee": "0xD71Ff941120e8f935b8b1E2C1eD72F5d140FF458", "proxyAdmin": "0xE047cb95FB3b7117989e911c6afb34771183fC35", - "domainRoutingIsmFactory": "0xD2e905108c5e44dADA680274740f896Ea96Cf2Fb", + "staticAggregationHookFactory": "0x15DEeAB8dECDe553bb0B1F9C00984cbcae1af3D7", + "staticAggregationIsmFactory": "0x7491843F3A5Ba24E0f17a22645bDa04A1Ae2c584", + "staticMerkleRootMultisigIsmFactory": "0xCA6Cb9Bc3cfF9E11003A06617cF934B684Bc78BC", + "staticMessageIdMultisigIsmFactory": "0xAa4Be20E9957fE21602c74d7C3cF5CB1112EA9Ef", "storageGasOracle": "0x27e88AeB8EA4B159d81df06355Ea3d20bEB1de38", "testRecipient": "0x36FdA966CfffF8a9Cdc814f546db0e6378bFef35", "testTokenRecipient": "0x85ac1164878e017b67660a74ff1f41f3D05C02Bb", @@ -241,19 +277,19 @@ }, "polygon": { "aggregationHook": "0x34dAb05650Cf590088bA18aF9d597f3e081bCc47", - "staticAggregationHookFactory": "0xFeeB86e70e4a640cDd29636CCE19BD6fe8628135", - "staticAggregationIsmFactory": "0x81AdDD9Ca89105063DaDEBd5B4408551Ce850E22", + "domainRoutingIsmFactory": "0x0d0E816eE4557689d34fAd5885C53b9393C1D9fA", "fallbackRoutingHook": "0xca4cCe24E7e06241846F5EA0cda9947F0507C40C", "interchainGasPaymaster": "0x0071740Bf129b05C4684abfbBeD248D80971cce2", "interchainSecurityModule": "0x9a795fB62f86146ec06e2377e3C95Af65c7C20eB", "mailbox": "0x5d934f4e2f797775e53561bB72aca21ba36B96BB", - "staticMerkleRootMultisigIsmFactory": "0xa9E0E18E78b098c2DE36c42E4DDEA13ce214c592", "merkleTreeHook": "0x73FbD25c3e817DC4B4Cd9d00eff6D83dcde2DfF6", - "staticMessageIdMultisigIsmFactory": "0xEa5Be2AD66BB1BA321B7aCf0A079fBE304B09Ca0", "pausableHook": "0x748040afB89B8FdBb992799808215419d36A0930", "protocolFee": "0xF8F3629e308b4758F8396606405989F8D8C9c578", "proxyAdmin": "0xC4F7590C5d30BE959225dC75640657954A86b980", - "domainRoutingIsmFactory": "0x0d0E816eE4557689d34fAd5885C53b9393C1D9fA", + "staticAggregationHookFactory": "0xFeeB86e70e4a640cDd29636CCE19BD6fe8628135", + "staticAggregationIsmFactory": "0x81AdDD9Ca89105063DaDEBd5B4408551Ce850E22", + "staticMerkleRootMultisigIsmFactory": "0xa9E0E18E78b098c2DE36c42E4DDEA13ce214c592", + "staticMessageIdMultisigIsmFactory": "0xEa5Be2AD66BB1BA321B7aCf0A079fBE304B09Ca0", "storageGasOracle": "0xA3a24EC5670F1F416AB9fD554FcE2f226AE9D7eB", "testRecipient": "0x36FdA966CfffF8a9Cdc814f546db0e6378bFef35", "testTokenRecipient": "0x85ac1164878e017b67660a74ff1f41f3D05C02Bb", @@ -261,52 +297,52 @@ }, "polygonzkevm": { "aggregationHook": "0x8464aF853363B8d6844070F68b0AB34Cb6523d0F", - "staticAggregationHookFactory": "0x0761b0827849abbf7b0cC09CE14e1C93D87f5004", - "staticAggregationIsmFactory": "0x1052eF3419f26Bec74Ed7CEf4a4FA6812Bc09908", + "domainRoutingIsmFactory": "0xe4057c5B0c43Dc18E36b08C39B419F190D29Ac2d", "fallbackRoutingHook": "0x01aE937A7B05d187bBCBE80F44F41879D3D335a4", "interchainGasPaymaster": "0x0D63128D887159d63De29497dfa45AFc7C699AE4", "interchainSecurityModule": "0xf2BEE9D2c15Ba9D7e06799B5912dE1F05533c141", "mailbox": "0x3a464f746D23Ab22155710f44dB16dcA53e0775E", - "staticMerkleRootMultisigIsmFactory": "0x8F7454AC98228f3504Bb91eA3D8Adafe6406110A", "merkleTreeHook": "0x149db7afD694722747035d5AEC7007ccb6F8f112", - "staticMessageIdMultisigIsmFactory": "0xEb9FcFDC9EfDC17c1EC5E1dc085B98485da213D6", "pausableHook": "0xc2FbB9411186AB3b1a6AFCCA702D1a80B48b197c", "protocolFee": "0xd83A4F747fE80Ed98839e05079B1B7Fe037b1638", "proxyAdmin": "0x2f2aFaE1139Ce54feFC03593FeE8AB2aDF4a85A7", - "domainRoutingIsmFactory": "0xe4057c5B0c43Dc18E36b08C39B419F190D29Ac2d", + "staticAggregationHookFactory": "0x0761b0827849abbf7b0cC09CE14e1C93D87f5004", + "staticAggregationIsmFactory": "0x1052eF3419f26Bec74Ed7CEf4a4FA6812Bc09908", + "staticMerkleRootMultisigIsmFactory": "0x8F7454AC98228f3504Bb91eA3D8Adafe6406110A", + "staticMessageIdMultisigIsmFactory": "0xEb9FcFDC9EfDC17c1EC5E1dc085B98485da213D6", "storageGasOracle": "0x19dc38aeae620380430C200a6E990D5Af5480117", "validatorAnnounce": "0x2fa5F5C96419C222cDbCeC797D696e6cE428A7A9" }, "scroll": { "aggregationHook": "0x9Bc0FAf446E128a618A88a2F28960Fb2Ca169faE", - "staticAggregationHookFactory": "0xEb9FcFDC9EfDC17c1EC5E1dc085B98485da213D6", - "staticAggregationIsmFactory": "0x8F7454AC98228f3504Bb91eA3D8Adafe6406110A", + "domainRoutingIsmFactory": "0xe03dad16074BC5EEA9A9311257BF02Eb0B6AAA2b", "fallbackRoutingHook": "0xDa7cECb05C4aeB02c1aFDE277d4306a2da7Bd762", "interchainGasPaymaster": "0xBF12ef4B9f307463D3FB59c3604F294dDCe287E2", "interchainSecurityModule": "0xaDc0cB48E8DB81855A930C0C1165ea3dCe4Ba5C7", "mailbox": "0x2f2aFaE1139Ce54feFC03593FeE8AB2aDF4a85A7", - "staticMerkleRootMultisigIsmFactory": "0x2C1FAbEcd7bFBdEBF27CcdB67baADB38b6Df90fC", "merkleTreeHook": "0x6119E37Bd66406A1Db74920aC79C15fB8411Ba76", - "staticMessageIdMultisigIsmFactory": "0x8b83fefd896fAa52057798f6426E9f0B080FCCcE", "pausableHook": "0x4Eb82Ee35b0a1c1d776E3a3B547f9A9bA6FCC9f2", "protocolFee": "0xc3F23848Ed2e04C0c6d41bd7804fa8f89F940B94", "proxyAdmin": "0x0761b0827849abbf7b0cC09CE14e1C93D87f5004", - "domainRoutingIsmFactory": "0xe03dad16074BC5EEA9A9311257BF02Eb0B6AAA2b", + "staticAggregationHookFactory": "0xEb9FcFDC9EfDC17c1EC5E1dc085B98485da213D6", + "staticAggregationIsmFactory": "0x8F7454AC98228f3504Bb91eA3D8Adafe6406110A", + "staticMerkleRootMultisigIsmFactory": "0x2C1FAbEcd7bFBdEBF27CcdB67baADB38b6Df90fC", + "staticMessageIdMultisigIsmFactory": "0x8b83fefd896fAa52057798f6426E9f0B080FCCcE", "storageGasOracle": "0x481171eb1aad17eDE6a56005B7F1aB00C581ef13", "validatorAnnounce": "0xd83A4F747fE80Ed98839e05079B1B7Fe037b1638" }, "viction": { - "staticAggregationHookFactory": "0xEb9FcFDC9EfDC17c1EC5E1dc085B98485da213D6", - "staticAggregationIsmFactory": "0x8F7454AC98228f3504Bb91eA3D8Adafe6406110A", + "domainRoutingIsmFactory": "0x1052eF3419f26Bec74Ed7CEf4a4FA6812Bc09908", "interchainGasPaymaster": "0x0D63128D887159d63De29497dfa45AFc7C699AE4", "interchainSecurityModule": "0xBD70Ea9D599a0FC8158B026797177773C3445730", "mailbox": "0x2f2aFaE1139Ce54feFC03593FeE8AB2aDF4a85A7", - "staticMerkleRootMultisigIsmFactory": "0x2C1FAbEcd7bFBdEBF27CcdB67baADB38b6Df90fC", "merkleTreeHook": "0x149db7afD694722747035d5AEC7007ccb6F8f112", - "staticMessageIdMultisigIsmFactory": "0x8b83fefd896fAa52057798f6426E9f0B080FCCcE", "protocolFee": "0xd83A4F747fE80Ed98839e05079B1B7Fe037b1638", "proxyAdmin": "0x0761b0827849abbf7b0cC09CE14e1C93D87f5004", - "domainRoutingIsmFactory": "0x1052eF3419f26Bec74Ed7CEf4a4FA6812Bc09908", + "staticAggregationHookFactory": "0xEb9FcFDC9EfDC17c1EC5E1dc085B98485da213D6", + "staticAggregationIsmFactory": "0x8F7454AC98228f3504Bb91eA3D8Adafe6406110A", + "staticMerkleRootMultisigIsmFactory": "0x2C1FAbEcd7bFBdEBF27CcdB67baADB38b6Df90fC", + "staticMessageIdMultisigIsmFactory": "0x8b83fefd896fAa52057798f6426E9f0B080FCCcE", "storageGasOracle": "0x19dc38aeae620380430C200a6E990D5Af5480117", "testRecipient": "0x17E216fBb22dF4ef8A6640ae9Cb147C92710ac84", "testTokenRecipient": "0xe042D1fbDf59828dd16b9649Ede7abFc856F7a6c", diff --git a/typescript/sdk/src/consts/multisigIsm.ts b/typescript/sdk/src/consts/multisigIsm.ts index 914e24ad9d..318debb480 100644 --- a/typescript/sdk/src/consts/multisigIsm.ts +++ b/typescript/sdk/src/consts/multisigIsm.ts @@ -51,6 +51,11 @@ export const defaultMultisigConfigs: ChainMap = { ], }, + blast: { + threshold: 1, + validators: ['0xf20c0b09f597597c8d2430d3d72dfddaf09177d1'], + }, + bsc: { threshold: 2, validators: [ @@ -156,6 +161,11 @@ export const defaultMultisigConfigs: ChainMap = { ], }, + mode: { + threshold: 1, + validators: ['0x7eb2e1920a4166c19d6884c1cec3d2cf356fc9b7'], + }, + moonbeam: { threshold: 2, validators: [ From af26342079a37fe38e3fdb749eaeeaca94236091 Mon Sep 17 00:00:00 2001 From: Paul Balaji Date: Thu, 25 Apr 2024 15:57:13 +0100 Subject: [PATCH 16/16] feat: add `hyperlane hook read` + `hyperlane ism read` to cli (#3648) --- .changeset/hip-toys-warn.md | 5 ++ .changeset/odd-books-think.md | 5 ++ .changeset/thirty-games-shake.md | 6 +++ typescript/cli/cli.ts | 4 ++ typescript/cli/src/commands/hook.ts | 53 +++++++++++++++++++ typescript/cli/src/commands/ism.ts | 58 ++++++++++++++++++++ typescript/cli/src/commands/options.ts | 16 +++++- typescript/cli/src/hook/read.ts | 51 ++++++++++++++++++ typescript/cli/src/ism/read.ts | 51 ++++++++++++++++++ typescript/cli/src/utils/files.ts | 45 ++++++++++++---- typescript/infra/scripts/read-config.ts | 70 ------------------------- typescript/sdk/src/hook/read.ts | 5 -- typescript/sdk/src/ism/read.ts | 5 -- typescript/utils/package.json | 3 +- typescript/utils/src/index.ts | 1 + typescript/utils/src/objects.ts | 18 +++++++ yarn.lock | 1 + 17 files changed, 304 insertions(+), 93 deletions(-) create mode 100644 .changeset/hip-toys-warn.md create mode 100644 .changeset/odd-books-think.md create mode 100644 .changeset/thirty-games-shake.md create mode 100644 typescript/cli/src/commands/hook.ts create mode 100644 typescript/cli/src/commands/ism.ts create mode 100644 typescript/cli/src/hook/read.ts create mode 100644 typescript/cli/src/ism/read.ts delete mode 100644 typescript/infra/scripts/read-config.ts diff --git a/.changeset/hip-toys-warn.md b/.changeset/hip-toys-warn.md new file mode 100644 index 0000000000..c7860068be --- /dev/null +++ b/.changeset/hip-toys-warn.md @@ -0,0 +1,5 @@ +--- +'@hyperlane-xyz/infra': minor +--- + +Moved Hook/ISM reading into CLI. diff --git a/.changeset/odd-books-think.md b/.changeset/odd-books-think.md new file mode 100644 index 0000000000..3929f5cbde --- /dev/null +++ b/.changeset/odd-books-think.md @@ -0,0 +1,5 @@ +--- +'@hyperlane-xyz/cli': minor +--- + +Introduces `hyperlane hook read` and `hyperlane ism read` commands for deriving onchain Hook/ISM configs from an address on a given chain. diff --git a/.changeset/thirty-games-shake.md b/.changeset/thirty-games-shake.md new file mode 100644 index 0000000000..7419098a01 --- /dev/null +++ b/.changeset/thirty-games-shake.md @@ -0,0 +1,6 @@ +--- +'@hyperlane-xyz/utils': minor +'@hyperlane-xyz/sdk': minor +--- + +Moved Hook/ISM config stringify into a general object stringify utility. diff --git a/typescript/cli/cli.ts b/typescript/cli/cli.ts index dfdfbae1f9..e974f81f71 100644 --- a/typescript/cli/cli.ts +++ b/typescript/cli/cli.ts @@ -8,6 +8,8 @@ import './env.js'; import { chainsCommand } from './src/commands/chains.js'; import { configCommand } from './src/commands/config.js'; import { deployCommand } from './src/commands/deploy.js'; +import { hookCommand } from './src/commands/hook.js'; +import { ismCommand } from './src/commands/ism.js'; import { logFormatCommandOption, logLevelCommandOption, @@ -37,6 +39,8 @@ try { .command(chainsCommand) .command(configCommand) .command(deployCommand) + .command(hookCommand) + .command(ismCommand) .command(sendCommand) .command(statusCommand) .version(VERSION) diff --git a/typescript/cli/src/commands/hook.ts b/typescript/cli/src/commands/hook.ts new file mode 100644 index 0000000000..dd284198c6 --- /dev/null +++ b/typescript/cli/src/commands/hook.ts @@ -0,0 +1,53 @@ +import { CommandModule } from 'yargs'; + +import { readHookConfig } from '../hook/read.js'; +import { log } from '../logger.js'; + +import { + addressCommandOption, + chainCommandOption, + chainsCommandOption, + fileFormatOption, + outputFileOption, +} from './options.js'; + +/** + * Parent command + */ +export const hookCommand: CommandModule = { + command: 'hook', + describe: 'Operations relating to Hooks', + builder: (yargs) => yargs.command(read).version(false).demandCommand(), + handler: () => log('Command required'), +}; + +// Examples for testing: +// Fallback routing hook on polygon (may take 5s): +// hyperlane hook read --chain polygon --address 0xca4cCe24E7e06241846F5EA0cda9947F0507C40C +// IGP hook on inevm (may take 5s): +// hyperlane hook read --chain inevm --address 0x19dc38aeae620380430C200a6E990D5Af5480117 +export const read: CommandModule = { + command: 'read', + describe: 'Reads onchain Hook configuration for a given address', + builder: (yargs) => + yargs.options({ + chains: chainsCommandOption, + chain: { + ...chainCommandOption, + demandOption: true, + }, + address: addressCommandOption('Address of the Hook to read.', true), + format: fileFormatOption, + output: outputFileOption(), + }), + handler: async (argv: any) => { + await readHookConfig({ + chain: argv.chain, + address: argv.address, + chainConfigPath: argv.chains, + format: argv.format, + output: argv.output, + }); + process.exit(0); + }, +}; diff --git a/typescript/cli/src/commands/ism.ts b/typescript/cli/src/commands/ism.ts new file mode 100644 index 0000000000..10c4044734 --- /dev/null +++ b/typescript/cli/src/commands/ism.ts @@ -0,0 +1,58 @@ +import { CommandModule } from 'yargs'; + +import { readIsmConfig } from '../ism/read.js'; +import { log } from '../logger.js'; + +import { + addressCommandOption, + chainCommandOption, + chainsCommandOption, + fileFormatOption, + outputFileOption, +} from './options.js'; + +/** + * Parent command + */ +export const ismCommand: CommandModule = { + command: 'ism', + describe: 'Operations relating to ISMs', + builder: (yargs) => yargs.command(read).version(false).demandCommand(), + handler: () => log('Command required'), +}; + +// Examples for testing: +// Top-level aggregation ISM on celo (may take 10s) +// hyperlane ism read --chain celo --address 0x99e8E56Dce3402D6E09A82718937fc1cA2A9491E +// Aggregation ISM for bsc domain on inevm (may take 5s) +// hyperlane ism read --chain inevm --address 0x79A7c7Fe443971CBc6baD623Fdf8019C379a7178 +// Test ISM on alfajores testnet +// hyperlane ism read --chain alfajores --address 0xdB52E4853b6A40D2972E6797E0BDBDb3eB761966 +export const read: CommandModule = { + command: 'read', + describe: 'Reads onchain ISM configuration for a given address', + builder: (yargs) => + yargs.options({ + chains: chainsCommandOption, + chain: { + ...chainCommandOption, + demandOption: true, + }, + address: addressCommandOption( + 'Address of the Interchain Security Module to read.', + true, + ), + format: fileFormatOption, + output: outputFileOption(), + }), + handler: async (argv: any) => { + await readIsmConfig({ + chain: argv.chain, + address: argv.address, + chainConfigPath: argv.chains, + format: argv.format, + output: argv.output, + }); + process.exit(0); + }, +}; diff --git a/typescript/cli/src/commands/options.ts b/typescript/cli/src/commands/options.ts index 90aa53e1ff..d278701e23 100644 --- a/typescript/cli/src/commands/options.ts +++ b/typescript/cli/src/commands/options.ts @@ -126,7 +126,7 @@ export const fileFormatOption: Options = { alias: 'f', }; -export const outputFileOption = (defaultPath: string): Options => ({ +export const outputFileOption = (defaultPath?: string): Options => ({ type: 'string', description: 'Output file path', default: defaultPath, @@ -146,3 +146,17 @@ export const dryRunOption: Options = { 'Chain name to fork and simulate deployment. Please ensure an anvil node instance is running during execution via `anvil`.', alias: ['d', 'dr'], }; + +export const chainCommandOption: Options = { + type: 'string', + description: 'The specific chain to perform operations with.', +}; + +export const addressCommandOption = ( + description: string, + demandOption = false, +): Options => ({ + type: 'string', + description, + demandOption, +}); diff --git a/typescript/cli/src/hook/read.ts b/typescript/cli/src/hook/read.ts new file mode 100644 index 0000000000..b79cf4ae4c --- /dev/null +++ b/typescript/cli/src/hook/read.ts @@ -0,0 +1,51 @@ +import { ChainName, EvmHookReader } from '@hyperlane-xyz/sdk'; +import { Address, ProtocolType, stringifyObject } from '@hyperlane-xyz/utils'; + +import { readChainConfigsIfExists } from '../config/chain.js'; +import { getMultiProvider } from '../context.js'; +import { log, logBlue, logRed } from '../logger.js'; +import { + FileFormat, + resolveFileFormat, + writeFileAtPath, +} from '../utils/files.js'; + +/** + * Read Hook config for a specified chain and address, logging or writing result to file. + */ +export async function readHookConfig({ + chain, + address, + chainConfigPath, + format, + output, +}: { + chain: ChainName; + address: Address; + chainConfigPath: string; + format: FileFormat; + output?: string; +}): Promise { + const customChains = readChainConfigsIfExists(chainConfigPath); + const multiProvider = getMultiProvider(customChains); + + if (multiProvider.getProtocol(chain) === ProtocolType.Ethereum) { + const hookReader = new EvmHookReader(multiProvider, chain); + const config = await hookReader.deriveHookConfig(address); + const stringConfig = stringifyObject( + config, + resolveFileFormat(output, format), + 2, + ); + if (!output) { + logBlue(`Hook Config at ${address} on ${chain}:`); + log(stringConfig); + } else { + writeFileAtPath(output, stringConfig + '\n'); + logBlue(`Hook Config written to ${output}.`); + } + return; + } + + logRed('Unsupported chain. Currently this command supports EVM chains only.'); +} diff --git a/typescript/cli/src/ism/read.ts b/typescript/cli/src/ism/read.ts new file mode 100644 index 0000000000..4c378f7b91 --- /dev/null +++ b/typescript/cli/src/ism/read.ts @@ -0,0 +1,51 @@ +import { ChainName, EvmIsmReader } from '@hyperlane-xyz/sdk'; +import { Address, ProtocolType, stringifyObject } from '@hyperlane-xyz/utils'; + +import { readChainConfigsIfExists } from '../config/chain.js'; +import { getMultiProvider } from '../context.js'; +import { log, logBlue, logRed } from '../logger.js'; +import { + FileFormat, + resolveFileFormat, + writeFileAtPath, +} from '../utils/files.js'; + +/** + * Read ISM config for a specified chain and address, logging or writing result to file. + */ +export async function readIsmConfig({ + chain, + address, + chainConfigPath, + format, + output, +}: { + chain: ChainName; + address: Address; + chainConfigPath: string; + format: FileFormat; + output?: string; +}): Promise { + const customChains = readChainConfigsIfExists(chainConfigPath); + const multiProvider = getMultiProvider(customChains); + + if (multiProvider.getProtocol(chain) === ProtocolType.Ethereum) { + const ismReader = new EvmIsmReader(multiProvider, chain); + const config = await ismReader.deriveIsmConfig(address); + const stringConfig = stringifyObject( + config, + resolveFileFormat(output, format), + 2, + ); + if (!output) { + logBlue(`ISM Config at ${address} on ${chain}:`); + log(stringConfig); + } else { + writeFileAtPath(output, stringConfig + '\n'); + logBlue(`ISM Config written to ${output}.`); + } + return; + } + + logRed('Unsupported chain. Currently this command supports EVM chains only.'); +} diff --git a/typescript/cli/src/utils/files.ts b/typescript/cli/src/utils/files.ts index 2c79ac73ed..276eb84b2a 100644 --- a/typescript/cli/src/utils/files.ts +++ b/typescript/cli/src/utils/files.ts @@ -99,7 +99,7 @@ export function mergeYaml>( } export function readYamlOrJson(filepath: string, format?: FileFormat): T { - return resolveYamlOrJson(filepath, readJson, readYaml, format); + return resolveYamlOrJsonFn(filepath, readJson, readYaml, format); } export function writeYamlOrJson( @@ -107,7 +107,7 @@ export function writeYamlOrJson( obj: Record, format?: FileFormat, ) { - return resolveYamlOrJson( + return resolveYamlOrJsonFn( filepath, (f: string) => writeJson(f, obj), (f: string) => writeYaml(f, obj), @@ -120,7 +120,7 @@ export function mergeYamlOrJson( obj: Record, format?: FileFormat, ) { - return resolveYamlOrJson( + return resolveYamlOrJsonFn( filepath, (f: string) => mergeJson(f, obj), (f: string) => mergeYaml(f, obj), @@ -128,23 +128,46 @@ export function mergeYamlOrJson( ); } -function resolveYamlOrJson( +function resolveYamlOrJsonFn( filepath: string, jsonFn: any, yamlFn: any, format?: FileFormat, ) { - if (format === 'json' || filepath.endsWith('.json')) { + const fileFormat = resolveFileFormat(filepath, format); + if (!fileFormat) { + throw new Error(`Invalid file format for ${filepath}`); + } + + if (fileFormat === 'json') { return jsonFn(filepath); - } else if ( + } + + return yamlFn(filepath); +} + +export function resolveFileFormat( + filepath?: string, + format?: FileFormat, +): FileFormat | undefined { + // early out if filepath is undefined + if (!filepath) { + return format; + } + + if (format === 'json' || filepath?.endsWith('.json')) { + return 'json'; + } + + if ( format === 'yaml' || - filepath.endsWith('.yaml') || - filepath.endsWith('.yml') + filepath?.endsWith('.yaml') || + filepath?.endsWith('.yml') ) { - return yamlFn(filepath); - } else { - throw new Error(`Invalid file format for ${filepath}`); + return 'yaml'; } + + return undefined; } export function prepNewArtifactsFiles( diff --git a/typescript/infra/scripts/read-config.ts b/typescript/infra/scripts/read-config.ts deleted file mode 100644 index dd74bdfcd1..0000000000 --- a/typescript/infra/scripts/read-config.ts +++ /dev/null @@ -1,70 +0,0 @@ -import { EvmHookReader, EvmIsmReader, chainMetadata } from '@hyperlane-xyz/sdk'; - -import { mainnetConfigs } from '../config/environments/mainnet3/chains.js'; -import { testnetConfigs } from '../config/environments/testnet4/chains.js'; -import { Role } from '../src/roles.js'; - -import { - getArgs, - getMultiProviderForRole, - withContext, - withNetwork, -} from './agent-utils.js'; - -// Examples from /typescript/infra: -// Fallback routing hook on polygon (may take 5s): -// yarn tsx scripts/read-config.ts -e mainnet3 --type hook --network polygon --address 0xca4cCe24E7e06241846F5EA0cda9947F0507C40C -// IGP hook on inevm (may take 5s): -// yarn tsx scripts/read-config.ts -e mainnet3 --type hook --network inevm --address 0x19dc38aeae620380430C200a6E990D5Af5480117 -// Top-level aggregation ISM on celo (may take 10s) -// yarn tsx scripts/read-config.ts -e mainnet3 --type ism --network celo --address 0x99e8E56Dce3402D6E09A82718937fc1cA2A9491E -// Aggregation ISM for bsc domain on inevm (may take 5s) -// yarn tsx scripts/read-config.ts -e mainnet3 --type ism --network inevm --address 0x79A7c7Fe443971CBc6baD623Fdf8019C379a7178 -// Test ISM on alfajores testnet -// yarn tsx scripts/read-config.ts -e testnet4 --type ism --network alfajores --address 0xdB52E4853b6A40D2972E6797E0BDBDb3eB761966 - -async function readConfig() { - const { environment, network, context, type, address, concurrency } = - await withContext(withNetwork(getArgs())) - .option('type', { - describe: 'Specify the type of config to read', - choices: ['ism', 'hook'], - demandOption: true, - }) - .number('concurrency') - .describe( - 'concurrency', - 'option to override the default concurrency level', - ) - .string('address') - .describe('address', 'config address') - .demandOption('address') - .demandOption('network').argv; - - const multiProvider = await getMultiProviderForRole( - chainMetadata[network].isTestnet ? testnetConfigs : mainnetConfigs, - environment, - context, - Role.Deployer, - ); - - if (type === 'ism') { - const ismReader = new EvmIsmReader(multiProvider, network, concurrency); - const config = await ismReader.deriveIsmConfig(address); - console.log(EvmIsmReader.stringifyConfig(config, 2)); - } else if (type === 'hook') { - const hookReader = new EvmHookReader(multiProvider, network, concurrency); - const config = await hookReader.deriveHookConfig(address); - console.log(EvmHookReader.stringifyConfig(config, 2)); - } else { - console.error('Invalid type specified. Please use "ism" or "hook".'); - process.exit(1); - } - - process.exit(0); -} - -readConfig().catch((e) => { - console.error(e); - process.exit(1); -}); diff --git a/typescript/sdk/src/hook/read.ts b/typescript/sdk/src/hook/read.ts index a53e14a9e5..d8b9dafe42 100644 --- a/typescript/sdk/src/hook/read.ts +++ b/typescript/sdk/src/hook/read.ts @@ -20,7 +20,6 @@ import { WithAddress, concurrentMap, eqAddress, - ethersBigNumberSerializer, rootLogger, } from '@hyperlane-xyz/utils'; @@ -81,10 +80,6 @@ export class EvmHookReader implements HookReader { this.provider = this.multiProvider.getProvider(chain); } - public static stringifyConfig(config: HookConfig, space?: number): string { - return JSON.stringify(config, ethersBigNumberSerializer, space); - } - async deriveHookConfig(address: Address): Promise> { const hook = IPostDispatchHook__factory.connect(address, this.provider); const onchainHookType: OnchainHookType = await hook.hookType(); diff --git a/typescript/sdk/src/ism/read.ts b/typescript/sdk/src/ism/read.ts index 8ab38b18aa..a8898fa8d7 100644 --- a/typescript/sdk/src/ism/read.ts +++ b/typescript/sdk/src/ism/read.ts @@ -15,7 +15,6 @@ import { WithAddress, assert, concurrentMap, - ethersBigNumberSerializer, rootLogger, } from '@hyperlane-xyz/utils'; @@ -70,10 +69,6 @@ export class EvmIsmReader implements IsmReader { this.provider = this.multiProvider.getProvider(chain); } - public static stringifyConfig(config: IsmConfig, space?: number): string { - return JSON.stringify(config, ethersBigNumberSerializer, space); - } - async deriveIsmConfig( address: Address, ): Promise { diff --git a/typescript/utils/package.json b/typescript/utils/package.json index 46b6bf9487..726158b7f5 100644 --- a/typescript/utils/package.json +++ b/typescript/utils/package.json @@ -7,7 +7,8 @@ "@solana/web3.js": "^1.78.0", "bignumber.js": "^9.1.1", "ethers": "^5.7.2", - "pino": "^8.19.0" + "pino": "^8.19.0", + "yaml": "^2.3.1" }, "devDependencies": { "@types/mocha": "^10.0.1", diff --git a/typescript/utils/src/index.ts b/typescript/utils/src/index.ts index 8c965bad82..e7d2dd76b2 100644 --- a/typescript/utils/src/index.ts +++ b/typescript/utils/src/index.ts @@ -110,6 +110,7 @@ export { objMerge, pick, promiseObjAll, + stringifyObject, } from './objects.js'; export { difference, setEquality, symmetricDifference } from './sets.js'; export { diff --git a/typescript/utils/src/objects.ts b/typescript/utils/src/objects.ts index 9f3dd466cf..21e122d867 100644 --- a/typescript/utils/src/objects.ts +++ b/typescript/utils/src/objects.ts @@ -1,3 +1,7 @@ +import { stringify as yamlStringify } from 'yaml'; + +import { ethersBigNumberSerializer } from './logging.js'; + export function isObject(item: any) { return item && typeof item === 'object' && !Array.isArray(item); } @@ -118,3 +122,17 @@ export function arrayToObject(keys: Array, val = true) { return result; }, {}); } + +export function stringifyObject( + object: object, + format: 'json' | 'yaml' = 'yaml', + space?: number, +): string { + // run through JSON first because ethersBigNumberSerializer does not play nice with yamlStringify + // so we fix up in JSON, then parse and if required return yaml on processed JSON after + const json = JSON.stringify(object, ethersBigNumberSerializer, space); + if (format === 'json') { + return json; + } + return yamlStringify(JSON.parse(json), null, space); +} diff --git a/yarn.lock b/yarn.lock index 27c1bad3a6..64a0cf4153 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5224,6 +5224,7 @@ __metadata: pino: "npm:^8.19.0" prettier: "npm:^2.8.8" typescript: "npm:5.3.3" + yaml: "npm:^2.3.1" languageName: unknown linkType: soft