diff --git a/package-lock.json b/package-lock.json index 2670b0b4..80063341 100644 --- a/package-lock.json +++ b/package-lock.json @@ -14,7 +14,7 @@ }, "devDependencies": { "@axelar-network/axelar-chains-config": "~0.1.2", - "@axelarjs/utils": "^0.1.12", + "@axelarjs/evm": "^0.1.18", "@nomicfoundation/hardhat-toolbox": "^2.0.2", "@tsconfig/strictest": "^2.0.2", "chai": "^4.3.7", @@ -28,10 +28,7 @@ "prettier": "^2.8.8", "prettier-plugin-solidity": "^1.1.3", "solhint": "^3.4.1", - "solidity-docgen": "^0.6.0-beta.36", - "tsx": "^3.14.0", - "viem": "^1.18.3", - "zx": "^7.2.3" + "solidity-docgen": "^0.6.0-beta.36" }, "engines": { "node": ">=16" @@ -81,6 +78,23 @@ "node": ">=16" } }, + "node_modules/@axelarjs/evm": { + "version": "0.1.18", + "resolved": "https://registry.npmjs.org/@axelarjs/evm/-/evm-0.1.18.tgz", + "integrity": "sha512-0DdBb8v3N7vlpntdjMJ9NCaF9wX77Q3owAvRQM+IJ83JwuydEpZQQVeBx9jSwNGYbk+JVN3Lmnd+AOh2TNNOoQ==", + "dev": true, + "hasInstallScript": true, + "dependencies": { + "@axelarjs/utils": "0.1.12", + "package-json": "^8.1.1", + "tsx": "^3.14.0", + "viem": "^1.18.7", + "zx": "^7.2.3" + }, + "bin": { + "evm": "bin/cli.mjs" + } + }, "node_modules/@axelarjs/utils": { "version": "0.1.12", "resolved": "https://registry.npmjs.org/@axelarjs/utils/-/utils-0.1.12.tgz", @@ -2041,6 +2055,47 @@ "node": ">= 4.0.0" } }, + "node_modules/@pnpm/config.env-replace": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@pnpm/config.env-replace/-/config.env-replace-1.1.0.tgz", + "integrity": "sha512-htyl8TWnKL7K/ESFa1oW2UB5lVDxuF5DpM7tBi6Hu2LNL3mWkIzNLG6N4zoCUP1lCKNxWy/3iu8mS8MvToGd6w==", + "dev": true, + "engines": { + "node": ">=12.22.0" + } + }, + "node_modules/@pnpm/network.ca-file": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@pnpm/network.ca-file/-/network.ca-file-1.0.2.tgz", + "integrity": "sha512-YcPQ8a0jwYU9bTdJDpXjMi7Brhkr1mXsXrUJvjqM2mQDgkRiz8jFaQGOdaLxgjtUfQgZhKy/O3cG/YwmgKaxLA==", + "dev": true, + "dependencies": { + "graceful-fs": "4.2.10" + }, + "engines": { + "node": ">=12.22.0" + } + }, + "node_modules/@pnpm/network.ca-file/node_modules/graceful-fs": { + "version": "4.2.10", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", + "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==", + "dev": true + }, + "node_modules/@pnpm/npm-conf": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/@pnpm/npm-conf/-/npm-conf-2.2.2.tgz", + "integrity": "sha512-UA91GwWPhFExt3IizW6bOeY/pQ0BkuNwKjk9iQW9KqxluGCrg4VenZ0/L+2Y0+ZOtme72EVvg6v0zo3AMQRCeA==", + "dev": true, + "dependencies": { + "@pnpm/config.env-replace": "^1.1.0", + "@pnpm/network.ca-file": "^1.0.1", + "config-chain": "^1.1.11" + }, + "engines": { + "node": ">=12" + } + }, "node_modules/@scure/base": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/@scure/base/-/base-1.1.3.tgz", @@ -2180,6 +2235,18 @@ "node": ">=6" } }, + "node_modules/@sindresorhus/is": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-5.6.0.tgz", + "integrity": "sha512-TV7t8GKYaJWsn00tFDqBw8+Uqmr8A0fRU1tvTQhyZzGv0sJCGRQL3JGMI3ucuKo3XIZdUP+Lx7/gh2t3lewy7g==", + "dev": true, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sindresorhus/is?sponsor=1" + } + }, "node_modules/@solidity-parser/parser": { "version": "0.14.5", "resolved": "https://registry.npmjs.org/@solidity-parser/parser/-/parser-0.14.5.tgz", @@ -2190,6 +2257,18 @@ "antlr4ts": "^0.5.0-alpha.4" } }, + "node_modules/@szmarczak/http-timer": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-5.0.1.tgz", + "integrity": "sha512-+PmQX0PiAYPMeVYe237LJAYvOMYW1j2rH5YROyS3b4CTVJum34HfRvKvAzozHAQG0TnHNdUfY9nCeUyRAs//cw==", + "dev": true, + "dependencies": { + "defer-to-connect": "^2.0.1" + }, + "engines": { + "node": ">=14.16" + } + }, "node_modules/@tsconfig/node10": { "version": "1.0.9", "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.9.tgz", @@ -2323,9 +2402,9 @@ } }, "node_modules/@types/fs-extra": { - "version": "11.0.3", - "resolved": "https://registry.npmjs.org/@types/fs-extra/-/fs-extra-11.0.3.tgz", - "integrity": "sha512-sF59BlXtUdzEAL1u0MSvuzWd7PdZvZEtnaVkzX5mjpdWTJ8brG0jUqve3jPCzSzvAKKMHTG8F8o/WMQLtleZdQ==", + "version": "11.0.4", + "resolved": "https://registry.npmjs.org/@types/fs-extra/-/fs-extra-11.0.4.tgz", + "integrity": "sha512-yTbItCNreRooED33qjunPthRcSjERP1r4MqCZc7wv0u2sUkzTFp45tgUfS5+r7FrZPdmCCNflLhVSP/o+SemsQ==", "dev": true, "dependencies": { "@types/jsonfile": "*", @@ -2343,6 +2422,12 @@ "@types/node": "*" } }, + "node_modules/@types/http-cache-semantics": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/@types/http-cache-semantics/-/http-cache-semantics-4.0.4.tgz", + "integrity": "sha512-1m0bIFVc7eJWyve9S0RnuRgcQqF/Xd5QsUZAZeQFr1Q3/p9JWoQQEqmVy+DPTNpGXwhgIetAoYF8JSc33q29QA==", + "dev": true + }, "node_modules/@types/json5": { "version": "0.0.29", "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", @@ -2350,9 +2435,9 @@ "dev": true }, "node_modules/@types/jsonfile": { - "version": "6.1.3", - "resolved": "https://registry.npmjs.org/@types/jsonfile/-/jsonfile-6.1.3.tgz", - "integrity": "sha512-/yqTk2SZ1wIezK0hiRZD7RuSf4B3whFxFamB1kGStv+8zlWScTMcHanzfc0XKWs5vA1TkHeckBlOyM8jxU8nHA==", + "version": "6.1.4", + "resolved": "https://registry.npmjs.org/@types/jsonfile/-/jsonfile-6.1.4.tgz", + "integrity": "sha512-D5qGUYwjvnNNextdU59/+fI+spnwtTFmyQP0h+PfIOSkNfpU6AOICUOkm4i0OnSk+NyjdPJrxCDro0sJsWlRpQ==", "dev": true, "dependencies": { "@types/node": "*" @@ -2372,9 +2457,9 @@ "peer": true }, "node_modules/@types/minimist": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@types/minimist/-/minimist-1.2.4.tgz", - "integrity": "sha512-Kfe/D3hxHTusnPNRbycJE1N77WHDsdS4AjUYIzlDzhDrS47NrwuL3YW4VITxwR7KCVpzwgy4Rbj829KSSQmwXQ==", + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/@types/minimist/-/minimist-1.2.5.tgz", + "integrity": "sha512-hov8bUuiLiyFPGyFPE1lwWhmzYbirOXQNNo40+y3zow8aFVTeyn3VWL0VFFfdNddA8S4Vf0Tc062rzyNr7Paag==", "dev": true }, "node_modules/@types/mocha": { @@ -2410,9 +2495,9 @@ "peer": true }, "node_modules/@types/ps-tree": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/@types/ps-tree/-/ps-tree-1.1.4.tgz", - "integrity": "sha512-CJyu2BqU/aZN/s8Ili3jiMctqXfTjCaWXirEcjRD8y1lUQZJ8eNohnal8+LXeWFs1VbdAOrCIdgATFsv+lnQ5Q==", + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/@types/ps-tree/-/ps-tree-1.1.5.tgz", + "integrity": "sha512-3LU5a3EZYI1/HvvOkQmmVGrdXopwKXpr3K5cxlZ0zRiP0QzW7IH0o1z4UDI7KdnyQnpPfYHXOOqflEXIl23LFw==", "dev": true }, "node_modules/@types/qs": { @@ -2448,9 +2533,9 @@ } }, "node_modules/@types/which": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@types/which/-/which-3.0.1.tgz", - "integrity": "sha512-OJWjr4k8gS1HXuOnCmQbBrQez+xqt/zqfp5PhgbKtsmEFEuojAg23arr+TiTZZ1TORdUF9RKXb/WKEpT1dwgSg==", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/which/-/which-3.0.2.tgz", + "integrity": "sha512-UqCG7NjNyume6e+BHcFkOQOS8of/E18V2z/jTRkiD98YiiryYOFBVvPxqA/8PQCwkn7icKqz/hFflMIRN2HGhQ==", "dev": true }, "node_modules/@ungap/structured-clone": { @@ -3146,6 +3231,33 @@ "node": ">= 0.8" } }, + "node_modules/cacheable-lookup": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/cacheable-lookup/-/cacheable-lookup-7.0.0.tgz", + "integrity": "sha512-+qJyx4xiKra8mZrcwhjMRMUhD5NR1R8esPkzIYxX96JiecFoxAXFuz/GpR3+ev4PE1WamHip78wV0vcmPQtp8w==", + "dev": true, + "engines": { + "node": ">=14.16" + } + }, + "node_modules/cacheable-request": { + "version": "10.2.14", + "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-10.2.14.tgz", + "integrity": "sha512-zkDT5WAF4hSSoUgyfg5tFIxz8XQK+25W/TLVojJTMKBaxevLBBtLxgqguAuVQB8PVW79FVjHcU+GJ9tVbDZ9mQ==", + "dev": true, + "dependencies": { + "@types/http-cache-semantics": "^4.0.2", + "get-stream": "^6.0.1", + "http-cache-semantics": "^4.1.1", + "keyv": "^4.5.3", + "mimic-response": "^4.0.0", + "normalize-url": "^8.0.0", + "responselike": "^3.0.0" + }, + "engines": { + "node": ">=14.16" + } + }, "node_modules/call-bind": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.5.tgz", @@ -3557,6 +3669,16 @@ "safe-buffer": "~5.1.0" } }, + "node_modules/config-chain": { + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/config-chain/-/config-chain-1.1.13.tgz", + "integrity": "sha512-qj+f8APARXHrM0hraqXYb2/bOVSV4PvJQlNZ/DVj0QrmNM2q2euizkeuVckQ57J+W0mRH6Hvi+k50M4Jul2VRQ==", + "dev": true, + "dependencies": { + "ini": "^1.3.4", + "proto-list": "~1.2.1" + } + }, "node_modules/cookie": { "version": "0.4.2", "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.2.tgz", @@ -3732,6 +3854,33 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/decompress-response": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", + "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==", + "dev": true, + "dependencies": { + "mimic-response": "^3.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/decompress-response/node_modules/mimic-response": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz", + "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/deep-eql": { "version": "4.1.3", "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-4.1.3.tgz", @@ -3749,7 +3898,6 @@ "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", "dev": true, - "peer": true, "engines": { "node": ">=4.0.0" } @@ -3760,6 +3908,15 @@ "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", "dev": true }, + "node_modules/defer-to-connect": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-2.0.1.tgz", + "integrity": "sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg==", + "dev": true, + "engines": { + "node": ">=10" + } + }, "node_modules/define-data-property": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.1.tgz", @@ -5237,6 +5394,15 @@ "node": ">= 6" } }, + "node_modules/form-data-encoder": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/form-data-encoder/-/form-data-encoder-2.1.4.tgz", + "integrity": "sha512-yDYSgNMraqvnxiEXO4hi88+YZxaHC6QKzb5N84iRCTDeRO7ZALpir/lVmf/uXUhnwUr2O4HU8s/n6x+yNjQkHw==", + "dev": true, + "engines": { + "node": ">= 14.17" + } + }, "node_modules/formdata-polyfill": { "version": "4.0.10", "resolved": "https://registry.npmjs.org/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz", @@ -5405,6 +5571,18 @@ "node": ">=4" } }, + "node_modules/get-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/get-symbol-description": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.0.tgz", @@ -5582,6 +5760,31 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/got": { + "version": "12.6.1", + "resolved": "https://registry.npmjs.org/got/-/got-12.6.1.tgz", + "integrity": "sha512-mThBblvlAF1d4O5oqyvN+ZxLAYwIJK7bpMxgYqPD9okW0C3qm5FFn7k811QrcuEBwaogR3ngOFoCfs6mRv7teQ==", + "dev": true, + "dependencies": { + "@sindresorhus/is": "^5.2.0", + "@szmarczak/http-timer": "^5.0.1", + "cacheable-lookup": "^7.0.0", + "cacheable-request": "^10.2.8", + "decompress-response": "^6.0.0", + "form-data-encoder": "^2.1.2", + "get-stream": "^6.0.1", + "http2-wrapper": "^2.1.10", + "lowercase-keys": "^3.0.0", + "p-cancelable": "^3.0.0", + "responselike": "^3.0.0" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sindresorhus/got?sponsor=1" + } + }, "node_modules/graceful-fs": { "version": "4.2.11", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", @@ -6101,6 +6304,12 @@ "node": ">=6.0.0" } }, + "node_modules/http-cache-semantics": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz", + "integrity": "sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==", + "dev": true + }, "node_modules/http-errors": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", @@ -6134,6 +6343,19 @@ "dev": true, "peer": true }, + "node_modules/http2-wrapper": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/http2-wrapper/-/http2-wrapper-2.2.0.tgz", + "integrity": "sha512-kZB0wxMo0sh1PehyjJUWRFEd99KC5TLjZ2cULC4f9iqJBAmKQQXEICjxl5iPJRwP40dpeHFqqhm7tYCvODpqpQ==", + "dev": true, + "dependencies": { + "quick-lru": "^5.1.1", + "resolve-alpn": "^1.2.0" + }, + "engines": { + "node": ">=10.19.0" + } + }, "node_modules/https-proxy-agent": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", @@ -6258,8 +6480,7 @@ "version": "1.3.8", "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", - "dev": true, - "peer": true + "dev": true }, "node_modules/internal-slot": { "version": "1.0.6", @@ -6984,6 +7205,18 @@ "get-func-name": "^2.0.1" } }, + "node_modules/lowercase-keys": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-3.0.0.tgz", + "integrity": "sha512-ozCC6gdQ+glXOQsveKD0YsDy8DSQFjDTz4zyzEHNV5+JP5D62LmfDZ6o1cycFx9ouG940M5dE8C8CTewdj2YWQ==", + "dev": true, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/lru_map": { "version": "0.3.3", "resolved": "https://registry.npmjs.org/lru_map/-/lru_map-0.3.3.tgz", @@ -7114,6 +7347,18 @@ "node": ">= 0.6" } }, + "node_modules/mimic-response": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-4.0.0.tgz", + "integrity": "sha512-e5ISH9xMYU0DzrT+jl8q2ze9D6eWBto+I8CNpe+VI+K2J/F/k3PdkdTdz4wvGVH4NTpo+NRYTVIuMQEMMcsLqg==", + "dev": true, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/minimalistic-assert": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", @@ -7422,6 +7667,18 @@ "node": ">=0.10.0" } }, + "node_modules/normalize-url": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-8.0.0.tgz", + "integrity": "sha512-uVFpKhj5MheNBJRTiMZ9pE/7hD1QTeEvugSJW/OmLzAp78PB5O6adfMNTvmfKhXBkvCzC+rqifWcVYpGFwTjnw==", + "dev": true, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/number-to-bn": { "version": "1.7.0", "resolved": "https://registry.npmjs.org/number-to-bn/-/number-to-bn-1.7.0.tgz", @@ -7584,6 +7841,15 @@ "node": ">=0.10.0" } }, + "node_modules/p-cancelable": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-3.0.0.tgz", + "integrity": "sha512-mlVgR3PGuzlo0MmTdk4cXqXWlwQDLnONTAg6sm62XkMJEiRxN3GL3SffkYvqwonbkJBcrI7Uvv5Zh9yjvn2iUw==", + "dev": true, + "engines": { + "node": ">=12.20" + } + }, "node_modules/p-limit": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", @@ -7638,6 +7904,57 @@ "node": ">=4" } }, + "node_modules/package-json": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/package-json/-/package-json-8.1.1.tgz", + "integrity": "sha512-cbH9IAIJHNj9uXi196JVsRlt7cHKak6u/e6AkL/bkRelZ7rlL3X1YKxsZwa36xipOEKAsdtmaG6aAJoM1fx2zA==", + "dev": true, + "dependencies": { + "got": "^12.1.0", + "registry-auth-token": "^5.0.1", + "registry-url": "^6.0.0", + "semver": "^7.3.7" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/package-json/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/package-json/node_modules/semver": { + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/package-json/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, "node_modules/parent-module": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", @@ -7882,6 +8199,12 @@ "asap": "~2.0.6" } }, + "node_modules/proto-list": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/proto-list/-/proto-list-1.2.4.tgz", + "integrity": "sha512-vtK/94akxsTMhe0/cbfpR+syPuszcuwhqVjJq26CuNDgFGj682oRBXOP5MJpv2r7JtE8MsiepGIqvvOTBwn2vA==", + "dev": true + }, "node_modules/proxy-from-env": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", @@ -7949,6 +8272,18 @@ } ] }, + "node_modules/quick-lru": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-5.1.1.tgz", + "integrity": "sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/ramda": { "version": "0.27.2", "resolved": "https://registry.npmjs.org/ramda/-/ramda-0.27.2.tgz", @@ -7979,6 +8314,30 @@ "node": ">= 0.8" } }, + "node_modules/rc": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", + "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", + "dev": true, + "dependencies": { + "deep-extend": "^0.6.0", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" + }, + "bin": { + "rc": "cli.js" + } + }, + "node_modules/rc/node_modules/strip-json-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/readable-stream": { "version": "3.6.2", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", @@ -8070,6 +8429,33 @@ "url": "https://github.com/sponsors/mysticatea" } }, + "node_modules/registry-auth-token": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-5.0.2.tgz", + "integrity": "sha512-o/3ikDxtXaA59BmZuZrJZDJv8NMDGSj+6j6XaeBmHw8eY1i1qd9+6H+LjVvQXx3HN6aRCGa1cUdJ9RaJZUugnQ==", + "dev": true, + "dependencies": { + "@pnpm/npm-conf": "^2.1.0" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/registry-url": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/registry-url/-/registry-url-6.0.1.tgz", + "integrity": "sha512-+crtS5QjFRqFCoQmvGduwYWEBng99ZvmFvF+cUJkGYF1L1BfU8C6Zp9T7f5vPAwyLkUExpvK+ANVZmGU49qi4Q==", + "dev": true, + "dependencies": { + "rc": "1.2.8" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/req-cwd": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/req-cwd/-/req-cwd-2.0.0.tgz", @@ -8141,6 +8527,12 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/resolve-alpn": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/resolve-alpn/-/resolve-alpn-1.2.1.tgz", + "integrity": "sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g==", + "dev": true + }, "node_modules/resolve-from": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", @@ -8159,6 +8551,21 @@ "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1" } }, + "node_modules/responselike": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/responselike/-/responselike-3.0.0.tgz", + "integrity": "sha512-40yHxbNcl2+rzXvZuVkrYohathsSJlMTXKryG5y8uciHv1+xDLHQpgjG64JUO9nrEq2jGLH6IZ8BcZyw3wrweg==", + "dev": true, + "dependencies": { + "lowercase-keys": "^3.0.0" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/reusify": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", @@ -10034,9 +10441,9 @@ "peer": true }, "node_modules/viem": { - "version": "1.18.3", - "resolved": "https://registry.npmjs.org/viem/-/viem-1.18.3.tgz", - "integrity": "sha512-r27eb39MHEXul/k2jZnRVNJY8QhoS816Kqh0guaLVLRJkGGIutryh7z5sKIuhKHU1yz2+CoPaiRn08gGKrfskw==", + "version": "1.18.9", + "resolved": "https://registry.npmjs.org/viem/-/viem-1.18.9.tgz", + "integrity": "sha512-eAXtoTwAFA3YEgjTYMb5ZTQrDC0UPx5qyZ4sv90TirVKepcM9mBPksTkC1SSWya0UdxhBmhEBL/CiYMjmGCTWg==", "dev": true, "funding": [ { @@ -10362,9 +10769,9 @@ "dev": true }, "node_modules/yaml": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.3.3.tgz", - "integrity": "sha512-zw0VAJxgeZ6+++/su5AFoqBbZbrEakwu+X0M5HmcwUiBL7AzcuPKjj5we4xfQLp78LkEMpD0cOnUhmgOVy3KdQ==", + "version": "2.3.4", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.3.4.tgz", + "integrity": "sha512-8aAvwVUSHpfEqTQ4w/KMlf3HcRdt50E5ODIQJBw1fQ5RL34xabzxtUlzTXVqc4rkZsPbvrXKWnABCD7kWSmocA==", "dev": true, "engines": { "node": ">= 14" @@ -10464,9 +10871,9 @@ } }, "node_modules/zx/node_modules/@types/node": { - "version": "18.18.8", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.18.8.tgz", - "integrity": "sha512-OLGBaaK5V3VRBS1bAkMVP2/W9B+H8meUfl866OrMNQqt7wDgdpWPp5o6gmIc9pB+lIQHSq4ZL8ypeH1vPxcPaQ==", + "version": "18.18.9", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.18.9.tgz", + "integrity": "sha512-0f5klcuImLnG4Qreu9hPj/rEfFq6YRc5n2mAjSsH+ec/mJL+3voBH0+8T7o8RpFjH7ovc+TRsL/c7OYIQsPTfQ==", "dev": true, "dependencies": { "undici-types": "~5.26.4" diff --git a/package.json b/package.json index bda0ac75..fa2e24cf 100644 --- a/package.json +++ b/package.json @@ -8,7 +8,8 @@ "main": "index.js", "scripts": { "build": "npx hardhat clean && npx hardhat compile && npm run copy:interfaces", - "codegen:ts": "rm -rf typescript/contracts && tsx scripts/codegen.ts", + "codegen:ts": "npm run clean:ts && npx @axelarjs/evm codegen --src artifacts/contracts --out typescript/contracts --exclude test", + "clean:ts": "rm -rf typescript", "build:ts": "npm run codegen:ts && tsc", "test": "npx hardhat test", "copy:interfaces": "rm -rf interfaces && mkdir interfaces && cp artifacts/contracts/interfaces/*/*.json interfaces/ && rm interfaces/*.dbg.json", @@ -33,7 +34,7 @@ }, "devDependencies": { "@axelar-network/axelar-chains-config": "~0.1.2", - "@axelarjs/utils": "^0.1.12", + "@axelarjs/evm": "^0.1.18", "@nomicfoundation/hardhat-toolbox": "^2.0.2", "@tsconfig/strictest": "^2.0.2", "chai": "^4.3.7", @@ -47,10 +48,7 @@ "prettier": "^2.8.8", "prettier-plugin-solidity": "^1.1.3", "solhint": "^3.4.1", - "solidity-docgen": "^0.6.0-beta.36", - "tsx": "^3.14.0", - "viem": "^1.18.3", - "zx": "^7.2.3" + "solidity-docgen": "^0.6.0-beta.36" }, "description": "Interchain token service for EVM chains to faciliate cross-chain token transfers and contract calls", "files": [ diff --git a/scripts/codegen.ts b/scripts/codegen.ts deleted file mode 100644 index 64d5ef2f..00000000 --- a/scripts/codegen.ts +++ /dev/null @@ -1,199 +0,0 @@ -#!/usr/bin/env zx -import { convertCase } from '@axelarjs/utils/case-conversion'; -import { capitalize } from '@axelarjs/utils/string'; - -import fs from 'fs/promises'; -import path from 'path'; -import prettier from 'prettier'; -import { $, glob } from 'zx'; - -$.verbose = false; - -const pascalToKebabCase = convertCase('PascalCase', 'kebab-case'); - -type ABIInputItem = { - name: string; - type: string; -}; - -type ABIItem = { - name: string; - type: string; - inputs: { - name: string; - type: string; - }[]; -}; - -const getInputType = (input: ABIInputItem) => { - switch (input.type) { - // string types - case 'address': - case 'bytes32': - case 'bytes': - return '`0x${string}`'; - case 'string': - return 'string'; - // number types - case 'uint256': - return 'bigint'; - case 'uint8': - return 'number'; - // boolean - case 'bool': - return 'boolean'; - // default - default: - return 'any'; - } -}; - -/** - * Represents the contract folders to be codegen'd under artifacts/contracts - */ -const CONTRACT_FOLDERS = ['InterchainTokenService.sol', 'InterchainTokenFactory.sol', 'interchain-token', 'token-manager']; - -/** - * Extracts the contract formatted name and path from the folder name - * - * @param folderPath - */ -function extractContractNameAndPath(folderPath: string) { - const pascalName = path.basename(folderPath).replace(/.sol$/, ''); - - return { - pascalName, - kebabName: pascalToKebabCase(pascalName), - abiPath: path.join(folderPath, `${pascalName}.json`), - }; -} - -async function main( - contractFolder: string, - options: { - excludePatterns?: string[]; - outputFolder?: string; - } -) { - const contractFolders = await glob(`${contractFolder}/**/**.sol`, { - onlyDirectories: true, - ignore: options.excludePatterns?.flatMap((pattern) => [`${pattern}/**`, `${contractFolder}/${pattern}/**`, `**/${pattern}/**`]), - }); - - for (const contractFolder of contractFolders) { - const { pascalName, abiPath } = extractContractNameAndPath(contractFolder); - - const { stdout: abiFileJson } = await $`cat ./${abiPath}`; - - if (!abiFileJson) { - console.log(`ABI file not found: ${abiPath}`); - continue; - } - - const GENERATED_DISCLAIMER = ` - /* eslint-disable @typescript-eslint/no-explicit-any */ - /** - * This file was generated by scripts/codegen.ts - * - * Original abi file: - * - ${abiPath} - * - * DO NOT EDIT MANUALLY - */ - `; - - const { abi, contractName } = JSON.parse(abiFileJson) as { - abi: ABIItem[]; - contractName: string; - }; - - const abiJsonFile = `${JSON.stringify({ contractName, abi }, null, 2)}`; - - const outputPath = path.join(path.resolve(options.outputFolder ?? ''), pascalName); - - // only generate args file if there are functions with inputs - const abiFns = abi.filter((x) => x.type === 'function' && x.inputs.length && x.inputs.every((input) => input.name)); - - const argsFile = ` - import { encodeFunctionData } from "viem"; - - import ABI_FILE from "./${pascalName}.abi"; - - ${abiFns - .map(({ name, inputs }) => { - const argNames = inputs.map(({ name = '' }) => name).join(', '); - - const argsType = inputs.map((input) => `${input.name}: ${getInputType(input)}`).join('; '); - - const fnName = capitalize(name); - const typeName = `${pascalName}${fnName}Args`; - - return ` - export type ${typeName} = {${argsType}} - - /** - * Factory function for ${pascalName}.${name} function args - */ - export const encode${pascalName}${fnName}Args = ({${argNames}}: ${typeName}) => [${argNames}] as const; - - /** - * Encoder function for ${pascalName}.${name} function data - */ - export const encode${pascalName}${fnName}Data = ({${argNames}}: ${typeName}) => encodeFunctionData({ - functionName: "${name}", - abi: ABI_FILE.abi, - args:[${argNames}] - }); - `; - }) - .join('\n\n')} - `; - - const abiFile = ` - export default ${abiJsonFile} as const; - `; - - // create base path folder - await $`mkdir -p ${outputPath}`; - - const files = [ - { - name: `${pascalName}.abi.ts`, - content: abiFile, - parser: 'babel-ts', - }, - { - name: `${pascalName}.args.ts`, - content: argsFile, - parser: 'babel-ts', - excluded: !abiFns.length, - }, - ].filter(({ excluded }) => !excluded); - - // write files - await Promise.all( - files.map(async ({ name, content, parser }) => - fs.writeFile( - path.join(outputPath, name), - prettier.format(parser === 'json' ? content : `${GENERATED_DISCLAIMER}\n\n${content}`, { parser }) - ) - ) - ); - - console.info(`Synced "${pascalName}" contract ABI.`, { - functions: abiFns.length, - }); - console.info(`Synced ${CONTRACT_FOLDERS.length} contract ABIs.\n`, `Generated code can be found in the typescript directory`); - } -} - -const CONTRACT_FOLDER = 'artifacts/contracts'; -const EXCLUDED_SUBFOLDERS = ['test']; - -main(CONTRACT_FOLDER, { - excludePatterns: EXCLUDED_SUBFOLDERS, - outputFolder: 'typescript/contracts', -}).catch((err) => { - console.error(err); - process.exit(1); -}); diff --git a/scripts/deploy.js b/scripts/deploy.js index a92865fb..db36c833 100644 --- a/scripts/deploy.js +++ b/scripts/deploy.js @@ -37,6 +37,7 @@ async function deployInterchainTokenService( chainName, evmChains = [], deploymentKey, + ownerAddress = wallet.address, operatorAddress = wallet.address, ) { const interchainTokenServiceAddress = await getCreate3Address(create3DeployerAddress, wallet, deploymentKey); @@ -52,7 +53,7 @@ async function deployInterchainTokenService( ]); const proxy = await create3DeployContract(create3DeployerAddress, wallet, InterchainTokenServiceProxy, deploymentKey, [ implementation.address, - wallet.address, + ownerAddress, defaultAbiCoder.encode( ['address', 'string', 'string[]', 'string[]'], [operatorAddress, chainName, evmChains, evmChains.map(() => interchainTokenServiceAddress)], diff --git a/test/TokenServiceUpgradeFlow.js b/test/TokenServiceUpgradeFlow.js new file mode 100644 index 00000000..4a6fc3b5 --- /dev/null +++ b/test/TokenServiceUpgradeFlow.js @@ -0,0 +1,234 @@ +'use strict'; + +const chai = require('chai'); +const { expect } = chai; +require('dotenv').config(); +const { ethers } = require('hardhat'); +const { + utils: { keccak256, Interface, defaultAbiCoder }, + getContractAt, +} = ethers; +const { getCreate3Address } = require('@axelar-network/axelar-gmp-sdk-solidity'); +const { approveContractCall } = require('../scripts/utils'); +const { isHardhat, waitFor, getRandomBytes32, getPayloadAndProposalHash } = require('./utils'); +const { + deployContract, + deployMockGateway, + deployGasService, + deployInterchainTokenService, + deployTokenManagerImplementations, +} = require('../scripts/deploy'); +const { getBytecodeHash } = require('@axelar-network/axelar-chains-config'); +const AxelarServiceGovernance = require('@axelar-network/axelar-gmp-sdk-solidity/artifacts/contracts/governance/AxelarServiceGovernance.sol/AxelarServiceGovernance.json'); +const Create3Deployer = require('@axelar-network/axelar-gmp-sdk-solidity/artifacts/contracts/deploy/Create3Deployer.sol/Create3Deployer.json'); + +describe('Interchain Token Service Upgrade Flow', () => { + let wallet, otherWallet, signer1, signer2, signer3; + let service, gateway, gasService; + let tokenManagerDeployer, interchainTokenDeployer, tokenManagerImplementations; + let interchainTokenFactoryAddress; + + let axelarServiceGovernanceFactory; + let axelarServiceGovernance; + + let governanceAddress; + let buffer; + + const governanceChain = 'Governance Chain'; + const threshold = 2; + const deploymentKey = 'InterchainTokenService'; + const chainName = 'Test'; + + const tokenName = 'Token Name'; + const tokenSymbol = 'TN'; + const tokenDecimals = 13; + + async function testDeployTokenManager() { + const salt = getRandomBytes32(); + const tokenId = await service.interchainTokenId(wallet.address, salt); + const tokenManager = await getContractAt('TokenManager', await service.tokenManagerAddress(tokenId), wallet); + + const token = await deployContract(wallet, 'InterchainTokenTest', [tokenName, tokenSymbol, tokenDecimals, tokenManager.address]); + const params = defaultAbiCoder.encode(['bytes', 'address'], [wallet.address, token.address]); + + await expect(service.deployTokenManager(salt, '', 0, params, 0)) + .to.emit(service, 'TokenManagerDeployed') + .withArgs(tokenId, tokenManager.address, 0, params); + } + + before(async () => { + [wallet, otherWallet, signer1, signer2, signer3] = await ethers.getSigners(); + const signers = [signer1, signer2, signer3]; + governanceAddress = otherWallet.address; + + buffer = isHardhat ? 10 * 60 * 60 : 10; + + const create3DeployerFactory = await ethers.getContractFactory(Create3Deployer.abi, Create3Deployer.bytecode, wallet); + const create3Deployer = await create3DeployerFactory.deploy().then((d) => d.deployed()); + const interchainTokenServiceAddress = await getCreate3Address(create3Deployer.address, wallet, deploymentKey); + const interchainToken = await deployContract(wallet, 'InterchainToken'); + + gateway = await deployMockGateway(wallet); + gasService = await deployGasService(wallet); + tokenManagerDeployer = await deployContract(wallet, 'TokenManagerDeployer', []); + interchainTokenDeployer = await deployContract(wallet, 'InterchainTokenDeployer', [interchainToken.address]); + tokenManagerImplementations = await deployTokenManagerImplementations(wallet, interchainTokenServiceAddress); + interchainTokenFactoryAddress = await getCreate3Address(create3Deployer.address, wallet, deploymentKey + 'Factory'); + + axelarServiceGovernanceFactory = await ethers.getContractFactory( + AxelarServiceGovernance.abi, + AxelarServiceGovernance.bytecode, + wallet, + ); + + axelarServiceGovernance = await axelarServiceGovernanceFactory + .deploy( + gateway.address, + governanceChain, + governanceAddress, + buffer, + signers.map((signer) => signer.address), + threshold, + ) + .then((d) => d.deployed()); + + service = await deployInterchainTokenService( + wallet, + create3Deployer.address, + tokenManagerDeployer.address, + interchainTokenDeployer.address, + gateway.address, + gasService.address, + interchainTokenFactoryAddress, + tokenManagerImplementations.map((impl) => impl.address), + chainName, + [], + deploymentKey, + axelarServiceGovernance.address, + ); + }); + + it('should upgrade Interchain Token Service through AxelarServiceGovernance timeLock proposal', async () => { + const commandID = 0; + const target = service.address; + const nativeValue = 0; + const timeDelay = isHardhat ? 12 * 60 * 60 : 12; + + const targetInterface = new Interface(service.interface.fragments); + const newServiceImplementation = await deployContract(wallet, 'InterchainTokenService', [ + tokenManagerDeployer.address, + interchainTokenDeployer.address, + gateway.address, + gasService.address, + interchainTokenFactoryAddress, + chainName, + tokenManagerImplementations.map((impl) => impl.address), + ]); + const newServiceImplementationCodeHash = await getBytecodeHash(newServiceImplementation); + const setupParams = '0x'; + const calldata = targetInterface.encodeFunctionData('upgrade', [ + newServiceImplementation.address, + newServiceImplementationCodeHash, + setupParams, + ]); + + const [payload, proposalHash, eta] = await getPayloadAndProposalHash(commandID, target, nativeValue, calldata, timeDelay); + + const commandIdGateway = getRandomBytes32(); + const sourceTxHash = keccak256('0x123abc123abc'); + const sourceEventIndex = 17; + + await approveContractCall( + gateway, + governanceChain, + governanceAddress, + axelarServiceGovernance.address, + payload, + sourceTxHash, + sourceEventIndex, + commandIdGateway, + ); + + const txExecute = await axelarServiceGovernance.execute(commandIdGateway, governanceChain, governanceAddress, payload); + + const receiptExecute = await txExecute.wait(); + const minimumEta = (await ethers.provider.getBlock(receiptExecute.blockNumber)).timestamp + buffer; + const finalEta = minimumEta > eta ? minimumEta : eta; + + await expect(txExecute) + .to.emit(axelarServiceGovernance, 'ProposalScheduled') + .withArgs(proposalHash, target, calldata, nativeValue, finalEta); + + await waitFor(timeDelay); + + const tx = await axelarServiceGovernance.executeProposal(target, calldata, nativeValue); + const receipt = await tx.wait(); + const executionTimestamp = (await ethers.provider.getBlock(receipt.blockNumber)).timestamp; + + await expect(tx) + .to.emit(axelarServiceGovernance, 'ProposalExecuted') + .withArgs(proposalHash, target, calldata, nativeValue, executionTimestamp) + .and.to.emit(service, 'Upgraded') + .withArgs(newServiceImplementation.address); + + await testDeployTokenManager(); + }); + + it('should upgrade Interchain Token Service through AxelarServiceGovernance multisig proposal', async () => { + const commandID = 2; + const target = service.address; + const nativeValue = 0; + + const targetInterface = new Interface(service.interface.fragments); + const newServiceImplementation = await deployContract(wallet, 'InterchainTokenService', [ + tokenManagerDeployer.address, + interchainTokenDeployer.address, + gateway.address, + gasService.address, + interchainTokenFactoryAddress, + chainName, + tokenManagerImplementations.map((impl) => impl.address), + ]); + const newServiceImplementationCodeHash = await getBytecodeHash(newServiceImplementation); + const setupParams = '0x'; + const calldata = targetInterface.encodeFunctionData('upgrade', [ + newServiceImplementation.address, + newServiceImplementationCodeHash, + setupParams, + ]); + + const [payload, proposalHash] = await getPayloadAndProposalHash(commandID, target, nativeValue, calldata); + + const commandIdGateway = getRandomBytes32(); + const sourceTxHash = keccak256('0x123abc123abc'); + const sourceEventIndex = 17; + + await approveContractCall( + gateway, + governanceChain, + governanceAddress, + axelarServiceGovernance.address, + payload, + sourceTxHash, + sourceEventIndex, + commandIdGateway, + ); + + await expect(axelarServiceGovernance.execute(commandIdGateway, governanceChain, governanceAddress, payload)) + .to.emit(axelarServiceGovernance, 'MultisigApproved') + .withArgs(proposalHash, target, calldata, nativeValue); + + await axelarServiceGovernance + .connect(signer1) + .executeMultisigProposal(target, calldata, nativeValue) + .then((tx) => tx.wait()); + + await expect(axelarServiceGovernance.connect(signer2).executeMultisigProposal(target, calldata, nativeValue)) + .to.emit(axelarServiceGovernance, 'MultisigExecuted') + .withArgs(proposalHash, target, calldata, nativeValue) + .and.to.emit(service, 'Upgraded') + .withArgs(newServiceImplementation.address); + + await testDeployTokenManager(); + }); +}); diff --git a/test/utils.js b/test/utils.js index b82f34d4..806956ec 100644 --- a/test/utils.js +++ b/test/utils.js @@ -8,12 +8,12 @@ function getRandomBytes32() { return keccak256(defaultAbiCoder.encode(['uint256'], [Math.floor(new Date().getTime() * Math.random())])); } +const isHardhat = network.name === 'hardhat'; + const getGasOptions = () => { return network.config.blockGasLimit ? { gasLimit: network.config.blockGasLimit.toString() } : { gasLimit: 5e6 }; // defaults to 5M gas for revert tests to work correctly }; -const isHardhat = network.name === 'hardhat'; - const expectRevert = async (txFunc, contract, error, args) => { if (network.config.skipRevertTests) { await expect(txFunc(getGasOptions())).to.be.reverted; @@ -28,6 +28,30 @@ const expectRevert = async (txFunc, contract, error, args) => { } }; +const getChainId = () => { + return network.config.chainId; +}; + +const getPayloadAndProposalHash = async (commandID, target, nativeValue, calldata, timeDelay) => { + let eta; + + if (timeDelay) { + const block = await ethers.provider.getBlock('latest'); + eta = block.timestamp + timeDelay - 12; // 12 second buffer for live network tests + } else { + eta = 0; + } + + const proposalHash = keccak256(defaultAbiCoder.encode(['address', 'bytes', 'uint256'], [target, calldata, nativeValue])); + + const payload = defaultAbiCoder.encode( + ['uint256', 'address', 'bytes', 'uint256', 'uint256'], + [commandID, target, calldata, nativeValue, eta], + ); + + return [payload, proposalHash, eta]; +}; + const waitFor = async (timeDelay) => { if (isHardhat) { await network.provider.send('evm_increaseTime', [timeDelay]); @@ -37,15 +61,12 @@ const waitFor = async (timeDelay) => { } }; -const getChainId = () => { - return network.config.chainId; -}; - module.exports = { getRandomBytes32, + isHardhat, getChainId, getGasOptions, - isHardhat, expectRevert, + getPayloadAndProposalHash, waitFor, };