From 3c1bbb44f49c1dd3b21347b8314d2b58eef490af Mon Sep 17 00:00:00 2001 From: Yunjong Jeong Date: Sun, 3 Dec 2023 17:58:10 +0900 Subject: [PATCH 01/33] ethers: Webpack bundle and web-html example --- ethers-ext/example/README.md | 1 + ethers-ext/example/browser-html/README.md | 13 + .../example/browser-html/ethers-ext.bundle.js | 1 + ethers-ext/example/browser-html/index.html | 14 + ethers-ext/example/browser-html/main.js | 1 + ethers-ext/package-lock.json | 1064 ++++++++++++++++- ethers-ext/package.json | 10 +- ethers-ext/webpack.config.js | 28 + 8 files changed, 1109 insertions(+), 23 deletions(-) create mode 100644 ethers-ext/example/browser-html/README.md create mode 120000 ethers-ext/example/browser-html/ethers-ext.bundle.js create mode 100644 ethers-ext/example/browser-html/index.html create mode 100644 ethers-ext/example/browser-html/main.js create mode 100644 ethers-ext/webpack.config.js diff --git a/ethers-ext/example/README.md b/ethers-ext/example/README.md index 87f5c4c83..9f58ffbcf 100644 --- a/ethers-ext/example/README.md +++ b/ethers-ext/example/README.md @@ -2,6 +2,7 @@ - [accountKey](./accountKey) Klaytn AccountKey types - [accountStore](./accountStore) AccountStore usage +- [browser-html](./browser-html) Browser extension wallets (e.g. Kaikas) interaction in plain HTML - [rpc](./rpc) Klaytn node RPC wrappers - [smartContract](./smartContract) Smart contract usage - [transactions](./transactions) Klaytn transaction types diff --git a/ethers-ext/example/browser-html/README.md b/ethers-ext/example/browser-html/README.md new file mode 100644 index 000000000..2ff6df158 --- /dev/null +++ b/ethers-ext/example/browser-html/README.md @@ -0,0 +1,13 @@ +# Running the browser extension example + +Run a HTTP server to serve the HTML and JS files. Use python3 http.server for example: + +``` +python3 -m http.server 3000 +``` + +Then open `http://localhost:3000` with the browser. + +Note that the browser extension wallets (e.g. MetaMask and Kaikas) does not work in the `file:///` page. +Therefore you cannot run this example by double-clicking the `index.html`. + diff --git a/ethers-ext/example/browser-html/ethers-ext.bundle.js b/ethers-ext/example/browser-html/ethers-ext.bundle.js new file mode 120000 index 000000000..31460ddd2 --- /dev/null +++ b/ethers-ext/example/browser-html/ethers-ext.bundle.js @@ -0,0 +1 @@ +../../dist/ethers-ext.bundle.js \ No newline at end of file diff --git a/ethers-ext/example/browser-html/index.html b/ethers-ext/example/browser-html/index.html new file mode 100644 index 000000000..debf5bb04 --- /dev/null +++ b/ethers-ext/example/browser-html/index.html @@ -0,0 +1,14 @@ + + + + + + + + + Hello + + + + + diff --git a/ethers-ext/example/browser-html/main.js b/ethers-ext/example/browser-html/main.js new file mode 100644 index 000000000..5ae5659f8 --- /dev/null +++ b/ethers-ext/example/browser-html/main.js @@ -0,0 +1 @@ +console.log("hello ethers_ext", ethers_ext.TxType.ValueTransfer); diff --git a/ethers-ext/package-lock.json b/ethers-ext/package-lock.json index 78e8a19d8..945dbc1fc 100644 --- a/ethers-ext/package-lock.json +++ b/ethers-ext/package-lock.json @@ -25,8 +25,12 @@ "eslint": "^8.45.0", "eslint-plugin-import": "^2.27.5", "mocha": "^10.2.0", + "ts-loader": "^9.5.1", "ts-node": "^10.9.1", - "typescript": "^5.0.4" + "typescript": "^5.0.4", + "webpack": "^5.89.0", + "webpack-cli": "^5.1.4", + "webpack-visualizer-plugin2": "^1.1.0" }, "peerDependencies": { "ethers": "^5.7.2" @@ -520,6 +524,15 @@ "kuler": "^2.0.0" } }, + "node_modules/@discoveryjs/json-ext": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz", + "integrity": "sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw==", + "dev": true, + "engines": { + "node": ">=10.0.0" + } + }, "node_modules/@eslint-community/eslint-utils": { "version": "4.4.0", "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", @@ -1362,7 +1375,6 @@ "version": "0.3.3", "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz", "integrity": "sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==", - "peer": true, "dependencies": { "@jridgewell/set-array": "^1.0.1", "@jridgewell/sourcemap-codec": "^1.4.10", @@ -1384,11 +1396,20 @@ "version": "1.1.2", "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", - "peer": true, "engines": { "node": ">=6.0.0" } }, + "node_modules/@jridgewell/source-map": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.5.tgz", + "integrity": "sha512-UTYAUj/wviwdsMfzoSJspJxbkH5o1snzwX0//0ENX1u/55kkZZkcTZP6u9bwKGkv+dkk9at4m1Cpt0uY80kcpQ==", + "dev": true, + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.0", + "@jridgewell/trace-mapping": "^0.3.9" + } + }, "node_modules/@jridgewell/sourcemap-codec": { "version": "1.4.15", "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", @@ -1538,6 +1559,32 @@ "@types/chai": "*" } }, + "node_modules/@types/eslint": { + "version": "8.44.8", + "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.44.8.tgz", + "integrity": "sha512-4K8GavROwhrYl2QXDXm0Rv9epkA8GBFu0EI+XrrnnuCl7u8CWBRusX7fXJfanhZTDWSAL24gDI/UqXyUM0Injw==", + "dev": true, + "dependencies": { + "@types/estree": "*", + "@types/json-schema": "*" + } + }, + "node_modules/@types/eslint-scope": { + "version": "3.7.7", + "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.7.tgz", + "integrity": "sha512-MzMFlSLBqNF2gcHWO0G1vP/YQyfvrxZ0bF+u7mzUdZ1/xK4A4sru+nraZz5i3iEIk1l1uyicaDVTB4QbbEkAYg==", + "dev": true, + "dependencies": { + "@types/eslint": "*", + "@types/estree": "*" + } + }, + "node_modules/@types/estree": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz", + "integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==", + "dev": true + }, "node_modules/@types/json-schema": { "version": "7.0.12", "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.12.tgz", @@ -1566,8 +1613,7 @@ "version": "18.15.11", "resolved": "https://registry.npmjs.org/@types/node/-/node-18.15.11.tgz", "integrity": "sha512-E5Kwq2n4SbMzQOn6wnmBjuK9ouqlURrcZDVfbo9ftDDTFt3nk7ZKK4GMOzoYgnpQJKcxwQw+lGaBvvlMo0qN/Q==", - "dev": true, - "peer": true + "dev": true }, "node_modules/@types/semver": { "version": "7.5.0", @@ -1870,6 +1916,208 @@ "url": "https://opencollective.com/typescript-eslint" } }, + "node_modules/@webassemblyjs/ast": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.11.6.tgz", + "integrity": "sha512-IN1xI7PwOvLPgjcf180gC1bqn3q/QaOCwYUahIOhbYUu8KA/3tw2RT/T0Gidi1l7Hhj5D/INhJxiICObqpMu4Q==", + "dev": true, + "dependencies": { + "@webassemblyjs/helper-numbers": "1.11.6", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6" + } + }, + "node_modules/@webassemblyjs/floating-point-hex-parser": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.6.tgz", + "integrity": "sha512-ejAj9hfRJ2XMsNHk/v6Fu2dGS+i4UaXBXGemOfQ/JfQ6mdQg/WXtwleQRLLS4OvfDhv8rYnVwH27YJLMyYsxhw==", + "dev": true + }, + "node_modules/@webassemblyjs/helper-api-error": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.6.tgz", + "integrity": "sha512-o0YkoP4pVu4rN8aTJgAyj9hC2Sv5UlkzCHhxqWj8butaLvnpdc2jOwh4ewE6CX0txSfLn/UYaV/pheS2Txg//Q==", + "dev": true + }, + "node_modules/@webassemblyjs/helper-buffer": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.11.6.tgz", + "integrity": "sha512-z3nFzdcp1mb8nEOFFk8DrYLpHvhKC3grJD2ardfKOzmbmJvEf/tPIqCY+sNcwZIY8ZD7IkB2l7/pqhUhqm7hLA==", + "dev": true + }, + "node_modules/@webassemblyjs/helper-numbers": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.6.tgz", + "integrity": "sha512-vUIhZ8LZoIWHBohiEObxVm6hwP034jwmc9kuq5GdHZH0wiLVLIPcMCdpJzG4C11cHoQ25TFIQj9kaVADVX7N3g==", + "dev": true, + "dependencies": { + "@webassemblyjs/floating-point-hex-parser": "1.11.6", + "@webassemblyjs/helper-api-error": "1.11.6", + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@webassemblyjs/helper-wasm-bytecode": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.6.tgz", + "integrity": "sha512-sFFHKwcmBprO9e7Icf0+gddyWYDViL8bpPjJJl0WHxCdETktXdmtWLGVzoHbqUcY4Be1LkNfwTmXOJUFZYSJdA==", + "dev": true + }, + "node_modules/@webassemblyjs/helper-wasm-section": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.11.6.tgz", + "integrity": "sha512-LPpZbSOwTpEC2cgn4hTydySy1Ke+XEu+ETXuoyvuyezHO3Kjdu90KK95Sh9xTbmjrCsUwvWwCOQQNta37VrS9g==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.11.6", + "@webassemblyjs/helper-buffer": "1.11.6", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/wasm-gen": "1.11.6" + } + }, + "node_modules/@webassemblyjs/ieee754": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.11.6.tgz", + "integrity": "sha512-LM4p2csPNvbij6U1f19v6WR56QZ8JcHg3QIJTlSwzFcmx6WSORicYj6I63f9yU1kEUtrpG+kjkiIAkevHpDXrg==", + "dev": true, + "dependencies": { + "@xtuc/ieee754": "^1.2.0" + } + }, + "node_modules/@webassemblyjs/leb128": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.11.6.tgz", + "integrity": "sha512-m7a0FhE67DQXgouf1tbN5XQcdWoNgaAuoULHIfGFIEVKA6tu/edls6XnIlkmS6FrXAquJRPni3ZZKjw6FSPjPQ==", + "dev": true, + "dependencies": { + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@webassemblyjs/utf8": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.11.6.tgz", + "integrity": "sha512-vtXf2wTQ3+up9Zsg8sa2yWiQpzSsMyXj0qViVP6xKGCUT8p8YJ6HqI7l5eCnWx1T/FYdsv07HQs2wTFbbof/RA==", + "dev": true + }, + "node_modules/@webassemblyjs/wasm-edit": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.11.6.tgz", + "integrity": "sha512-Ybn2I6fnfIGuCR+Faaz7YcvtBKxvoLV3Lebn1tM4o/IAJzmi9AWYIPWpyBfU8cC+JxAO57bk4+zdsTjJR+VTOw==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.11.6", + "@webassemblyjs/helper-buffer": "1.11.6", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/helper-wasm-section": "1.11.6", + "@webassemblyjs/wasm-gen": "1.11.6", + "@webassemblyjs/wasm-opt": "1.11.6", + "@webassemblyjs/wasm-parser": "1.11.6", + "@webassemblyjs/wast-printer": "1.11.6" + } + }, + "node_modules/@webassemblyjs/wasm-gen": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.11.6.tgz", + "integrity": "sha512-3XOqkZP/y6B4F0PBAXvI1/bky7GryoogUtfwExeP/v7Nzwo1QLcq5oQmpKlftZLbT+ERUOAZVQjuNVak6UXjPA==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.11.6", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/ieee754": "1.11.6", + "@webassemblyjs/leb128": "1.11.6", + "@webassemblyjs/utf8": "1.11.6" + } + }, + "node_modules/@webassemblyjs/wasm-opt": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.11.6.tgz", + "integrity": "sha512-cOrKuLRE7PCe6AsOVl7WasYf3wbSo4CeOk6PkrjS7g57MFfVUF9u6ysQBBODX0LdgSvQqRiGz3CXvIDKcPNy4g==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.11.6", + "@webassemblyjs/helper-buffer": "1.11.6", + "@webassemblyjs/wasm-gen": "1.11.6", + "@webassemblyjs/wasm-parser": "1.11.6" + } + }, + "node_modules/@webassemblyjs/wasm-parser": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.11.6.tgz", + "integrity": "sha512-6ZwPeGzMJM3Dqp3hCsLgESxBGtT/OeCvCZ4TA1JUPYgmhAx38tTPR9JaKy0S5H3evQpO/h2uWs2j6Yc/fjkpTQ==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.11.6", + "@webassemblyjs/helper-api-error": "1.11.6", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/ieee754": "1.11.6", + "@webassemblyjs/leb128": "1.11.6", + "@webassemblyjs/utf8": "1.11.6" + } + }, + "node_modules/@webassemblyjs/wast-printer": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.11.6.tgz", + "integrity": "sha512-JM7AhRcE+yW2GWYaKeHL5vt4xqee5N2WcezptmgyhNS+ScggqcT1OtXykhAb13Sn5Yas0j2uv9tHgrjwvzAP4A==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.11.6", + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@webpack-cli/configtest": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@webpack-cli/configtest/-/configtest-2.1.1.tgz", + "integrity": "sha512-wy0mglZpDSiSS0XHrVR+BAdId2+yxPSoJW8fsna3ZpYSlufjvxnP4YbKTCBZnNIcGN4r6ZPXV55X4mYExOfLmw==", + "dev": true, + "engines": { + "node": ">=14.15.0" + }, + "peerDependencies": { + "webpack": "5.x.x", + "webpack-cli": "5.x.x" + } + }, + "node_modules/@webpack-cli/info": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@webpack-cli/info/-/info-2.0.2.tgz", + "integrity": "sha512-zLHQdI/Qs1UyT5UBdWNqsARasIA+AaF8t+4u2aS2nEpBQh2mWIVb8qAklq0eUENnC5mOItrIB4LiS9xMtph18A==", + "dev": true, + "engines": { + "node": ">=14.15.0" + }, + "peerDependencies": { + "webpack": "5.x.x", + "webpack-cli": "5.x.x" + } + }, + "node_modules/@webpack-cli/serve": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@webpack-cli/serve/-/serve-2.0.5.tgz", + "integrity": "sha512-lqaoKnRYBdo1UgDX8uF24AfGMifWK19TxPmM5FHc2vAGxrJ/qtyUyFBWoY1tISZdelsQ5fBcOusifo5o5wSJxQ==", + "dev": true, + "engines": { + "node": ">=14.15.0" + }, + "peerDependencies": { + "webpack": "5.x.x", + "webpack-cli": "5.x.x" + }, + "peerDependenciesMeta": { + "webpack-dev-server": { + "optional": true + } + } + }, + "node_modules/@xtuc/ieee754": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", + "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==", + "dev": true + }, + "node_modules/@xtuc/long": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz", + "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==", + "dev": true + }, "node_modules/accepts": { "version": "1.3.8", "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", @@ -1895,6 +2143,15 @@ "node": ">=0.4.0" } }, + "node_modules/acorn-import-assertions": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/acorn-import-assertions/-/acorn-import-assertions-1.9.0.tgz", + "integrity": "sha512-cmMwop9x+8KFhxvKrKfPYmN6/pKTYYHBqLa0DfvVZcKMJWNyWLnaqND7dx/qn66R7ewM1UX5XMaDVP5wlVTaVA==", + "dev": true, + "peerDependencies": { + "acorn": "^8" + } + }, "node_modules/acorn-jsx": { "version": "5.3.2", "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", @@ -1935,6 +2192,15 @@ "url": "https://github.com/sponsors/epoberezkin" } }, + "node_modules/ajv-keywords": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", + "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", + "dev": true, + "peerDependencies": { + "ajv": "^6.9.1" + } + }, "node_modules/ansi-colors": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", @@ -2304,7 +2570,6 @@ "url": "https://github.com/sponsors/ai" } ], - "peer": true, "dependencies": { "caniuse-lite": "^1.0.30001503", "electron-to-chromium": "^1.4.431", @@ -2318,6 +2583,12 @@ "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" } }, + "node_modules/buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "dev": true + }, "node_modules/buffer-to-arraybuffer": { "version": "0.0.5", "resolved": "https://registry.npmjs.org/buffer-to-arraybuffer/-/buffer-to-arraybuffer-0.0.5.tgz", @@ -2403,8 +2674,7 @@ "type": "github", "url": "https://github.com/sponsors/ai" } - ], - "peer": true + ] }, "node_modules/caseless": { "version": "0.12.0", @@ -2506,6 +2776,15 @@ "fsevents": "~2.3.2" } }, + "node_modules/chrome-trace-event": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz", + "integrity": "sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg==", + "dev": true, + "engines": { + "node": ">=6.0" + } + }, "node_modules/cliui": { "version": "7.0.4", "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", @@ -2517,6 +2796,20 @@ "wrap-ansi": "^7.0.0" } }, + "node_modules/clone-deep": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz", + "integrity": "sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==", + "dev": true, + "dependencies": { + "is-plain-object": "^2.0.4", + "kind-of": "^6.0.2", + "shallow-clone": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, "node_modules/color": { "version": "3.2.1", "resolved": "https://registry.npmjs.org/color/-/color-3.2.1.tgz", @@ -2565,6 +2858,12 @@ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" }, + "node_modules/colorette": { + "version": "2.0.20", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz", + "integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==", + "dev": true + }, "node_modules/colorspace": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/colorspace/-/colorspace-1.1.4.tgz", @@ -2696,6 +2995,12 @@ "cssmin": "bin/cssmin" } }, + "node_modules/d3": { + "version": "3.5.17", + "resolved": "https://registry.npmjs.org/d3/-/d3-3.5.17.tgz", + "integrity": "sha512-yFk/2idb8OHPKkbAL8QaOaqENNoMhIaSHZerk3oQsECwkObkCpJyjYwCe+OHiq6UEdhe1m8ZGARRRO3ljFjlKg==", + "dev": true + }, "node_modules/dashdash": { "version": "1.14.1", "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", @@ -2881,8 +3186,7 @@ "node_modules/electron-to-chromium": { "version": "1.4.468", "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.468.tgz", - "integrity": "sha512-6M1qyhaJOt7rQtNti1lBA0GwclPH+oKCmsra/hkcWs5INLxfXXD/dtdnaKUYQu/pjOBP/8Osoe4mAcNvvzoFag==", - "peer": true + "integrity": "sha512-6M1qyhaJOt7rQtNti1lBA0GwclPH+oKCmsra/hkcWs5INLxfXXD/dtdnaKUYQu/pjOBP/8Osoe4mAcNvvzoFag==" }, "node_modules/elliptic": { "version": "6.5.4", @@ -2923,6 +3227,31 @@ "node": ">= 0.8" } }, + "node_modules/enhanced-resolve": { + "version": "5.15.0", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.15.0.tgz", + "integrity": "sha512-LXYT42KJ7lpIKECr2mAXIaMldcNCh/7E0KBKOu4KSfkHmP+mZmSs+8V5gBAqisWBy0OO4W5Oyys0GO1Y8KtdKg==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.2.4", + "tapable": "^2.2.0" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/envinfo": { + "version": "7.11.0", + "resolved": "https://registry.npmjs.org/envinfo/-/envinfo-7.11.0.tgz", + "integrity": "sha512-G9/6xF1FPbIw0TtalAMaVPpiq2aDEuKLXM314jPVAO9r2fo2a4BLqMNkmRS7O/xPPZ+COAhGIz3ETvHEV3eUcg==", + "dev": true, + "bin": { + "envinfo": "dist/cli.js" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/es-abstract": { "version": "1.22.1", "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.22.1.tgz", @@ -2976,6 +3305,12 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/es-module-lexer": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.4.1.tgz", + "integrity": "sha512-cXLGjP0c4T3flZJKQSuziYoq7MlT+rnvfZjfp7h+I7K9BNX54kP9nyWvdbwjQ4u1iWbOL4u96fgeZLToQlZC7w==", + "dev": true + }, "node_modules/es-set-tostringtag": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.0.1.tgz", @@ -3444,6 +3779,15 @@ "@ethersproject/wordlists": "5.7.0" } }, + "node_modules/events": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", + "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", + "dev": true, + "engines": { + "node": ">=0.8.x" + } + }, "node_modules/express": { "version": "4.18.2", "resolved": "https://registry.npmjs.org/express/-/express-4.18.2.tgz", @@ -3609,6 +3953,15 @@ "resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.1.1.tgz", "integrity": "sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==" }, + "node_modules/fastest-levenshtein": { + "version": "1.0.16", + "resolved": "https://registry.npmjs.org/fastest-levenshtein/-/fastest-levenshtein-1.0.16.tgz", + "integrity": "sha512-eRnCtTTtGZFpQCwhJiUOuxPQWRXVKYDn0b2PeHfXL6/Zi53SLAzAHfVhVWK2AryC/WH05kGfxhFIPvTF0SXQzg==", + "dev": true, + "engines": { + "node": ">= 4.9.1" + } + }, "node_modules/fastq": { "version": "1.15.0", "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz", @@ -3940,6 +4293,12 @@ "node": ">= 6" } }, + "node_modules/glob-to-regexp": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", + "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==", + "dev": true + }, "node_modules/glob/node_modules/brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", @@ -4035,6 +4394,12 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "dev": true + }, "node_modules/graphemer": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", @@ -4238,6 +4603,25 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/import-local": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.1.0.tgz", + "integrity": "sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg==", + "dev": true, + "dependencies": { + "pkg-dir": "^4.2.0", + "resolve-cwd": "^3.0.0" + }, + "bin": { + "import-local-fixture": "fixtures/cli.js" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/imurmurhash": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", @@ -4275,6 +4659,15 @@ "node": ">= 0.4" } }, + "node_modules/interpret": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/interpret/-/interpret-3.1.1.tgz", + "integrity": "sha512-6xwYfHbajpoF0xLW+iwLkhwgvLoZDfjYfoFNu8ftMoXINzwuymNLd9u/KmwtdT2GbR+/Cz66otEGEVVUHX9QLQ==", + "dev": true, + "engines": { + "node": ">=10.13.0" + } + }, "node_modules/ipaddr.js": { "version": "1.9.1", "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", @@ -4472,6 +4865,18 @@ "node": ">=8" } }, + "node_modules/is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "dev": true, + "dependencies": { + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/is-regex": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", @@ -4598,12 +5003,35 @@ "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", "dev": true }, + "node_modules/isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/isstream": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", "integrity": "sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g==", "dev": true }, + "node_modules/jest-worker": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz", + "integrity": "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==", + "dev": true, + "dependencies": { + "@types/node": "*", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, + "engines": { + "node": ">= 10.13.0" + } + }, "node_modules/js-sha3": { "version": "0.8.0", "resolved": "https://registry.npmjs.org/js-sha3/-/js-sha3-0.8.0.tgz", @@ -4612,8 +5040,7 @@ "node_modules/js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "peer": true + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" }, "node_modules/js-yaml": { "version": "4.1.0", @@ -4656,6 +5083,12 @@ "node": ">=0.1.93" } }, + "node_modules/json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", + "dev": true + }, "node_modules/json-schema": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz", @@ -4729,6 +5162,15 @@ "node": "> 0.4.11" } }, + "node_modules/kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/kuler": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/kuler/-/kuler-2.0.0.tgz", @@ -4747,6 +5189,15 @@ "node": ">= 0.8.0" } }, + "node_modules/loader-runner": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.0.tgz", + "integrity": "sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg==", + "dev": true, + "engines": { + "node": ">=6.11.5" + } + }, "node_modules/locate-path": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", @@ -4805,6 +5256,18 @@ "node": ">= 12.0.0" } }, + "node_modules/loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "dev": true, + "dependencies": { + "js-tokens": "^3.0.0 || ^4.0.0" + }, + "bin": { + "loose-envify": "cli.js" + } + }, "node_modules/loupe": { "version": "2.3.6", "resolved": "https://registry.npmjs.org/loupe/-/loupe-2.3.6.tgz", @@ -4872,6 +5335,12 @@ "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==", "dev": true }, + "node_modules/merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "dev": true + }, "node_modules/merge2": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", @@ -4981,6 +5450,18 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/mkdirp": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", + "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", + "dev": true, + "dependencies": { + "minimist": "^1.2.6" + }, + "bin": { + "mkdirp": "bin/cmd.js" + } + }, "node_modules/mocha": { "version": "10.2.0", "resolved": "https://registry.npmjs.org/mocha/-/mocha-10.2.0.tgz", @@ -5082,11 +5563,16 @@ "node": ">= 0.6" } }, + "node_modules/neo-async": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", + "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", + "dev": true + }, "node_modules/node-releases": { "version": "2.0.13", "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.13.tgz", - "integrity": "sha512-uYr7J37ae/ORWdZeQ1xxMJe3NtdmqMC/JZK+geofDrkLUApKRHPd18/TxtBOJ4A0/+uUIliorNrfYV6s1b02eQ==", - "peer": true + "integrity": "sha512-uYr7J37ae/ORWdZeQ1xxMJe3NtdmqMC/JZK+geofDrkLUApKRHPd18/TxtBOJ4A0/+uUIliorNrfYV6s1b02eQ==" }, "node_modules/normalize-path": { "version": "3.0.0", @@ -5242,6 +5728,15 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, "node_modules/parent-module": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", @@ -5334,8 +5829,7 @@ "node_modules/picocolors": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", - "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", - "peer": true + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==" }, "node_modules/picomatch": { "version": "2.3.1", @@ -5357,10 +5851,74 @@ "node": ">=6" } }, - "node_modules/prelude-ls": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", - "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "node_modules/pkg-dir": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", + "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "dev": true, + "dependencies": { + "find-up": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pkg-dir/node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pkg-dir/node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pkg-dir/node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/pkg-dir/node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", "dev": true, "engines": { "node": ">= 0.8.0" @@ -5380,6 +5938,17 @@ "resolved": "https://registry.npmjs.org/promised-io/-/promised-io-0.3.6.tgz", "integrity": "sha512-bNwZusuNIW4m0SPR8jooSyndD35ggirHlxVl/UhIaZD/F0OBv9ebfc6tNmbpZts3QXHggkjIBH8lvtnzhtcz0A==" }, + "node_modules/prop-types": { + "version": "15.8.1", + "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", + "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", + "dev": true, + "dependencies": { + "loose-envify": "^1.4.0", + "object-assign": "^4.1.1", + "react-is": "^16.13.1" + } + }, "node_modules/proxy-addr": { "version": "2.0.7", "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", @@ -5489,6 +6058,39 @@ "node": ">= 0.8" } }, + "node_modules/react": { + "version": "17.0.2", + "resolved": "https://registry.npmjs.org/react/-/react-17.0.2.tgz", + "integrity": "sha512-gnhPt75i/dq/z3/6q/0asP78D0u592D5L1pd7M8P+dck6Fu/jJeL6iVVK23fptSUZj8Vjf++7wXA8UNclGQcbA==", + "dev": true, + "dependencies": { + "loose-envify": "^1.1.0", + "object-assign": "^4.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-dom": { + "version": "17.0.2", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-17.0.2.tgz", + "integrity": "sha512-s4h96KtLDUQlsENhMn1ar8t2bEa+q/YAtj8pPPdIjPDGBDIVNsrD9aXNWqspUe6AzKCIG0C1HZZLqLV7qpOBGA==", + "dev": true, + "dependencies": { + "loose-envify": "^1.1.0", + "object-assign": "^4.1.1", + "scheduler": "^0.20.2" + }, + "peerDependencies": { + "react": "17.0.2" + } + }, + "node_modules/react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", + "dev": true + }, "node_modules/readable-stream": { "version": "3.6.2", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", @@ -5514,6 +6116,18 @@ "node": ">=8.10.0" } }, + "node_modules/rechoir": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.8.0.tgz", + "integrity": "sha512-/vxpCXddiX8NGfGO/mTafwjq4aFa/71pvamip0++IQk3zG8cbCj0fifNPrjjF1XMXUne91jL9OoxmdykoEtifQ==", + "dev": true, + "dependencies": { + "resolve": "^1.20.0" + }, + "engines": { + "node": ">= 10.13.0" + } + }, "node_modules/regexp.prototype.flags": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.0.tgz", @@ -5622,6 +6236,27 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/resolve-cwd": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", + "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", + "dev": true, + "dependencies": { + "resolve-from": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/resolve-cwd/node_modules/resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, "node_modules/resolve-from": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", @@ -5744,6 +6379,34 @@ "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", "dev": true }, + "node_modules/scheduler": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.20.2.tgz", + "integrity": "sha512-2eWfGgAqqWFGqtdMmcL5zCMK1U8KlXv8SQFGglL3CEtd0aDVDWgeF/YoCmvln55m5zSk3J/20hTaSBeSObsQDQ==", + "dev": true, + "dependencies": { + "loose-envify": "^1.1.0", + "object-assign": "^4.1.1" + } + }, + "node_modules/schema-utils": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz", + "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.8", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, "node_modules/scrypt-js": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/scrypt-js/-/scrypt-js-3.0.1.tgz", @@ -5855,6 +6518,18 @@ "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", "dev": true }, + "node_modules/shallow-clone": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz", + "integrity": "sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==", + "dev": true, + "dependencies": { + "kind-of": "^6.0.2" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/shebang-command": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", @@ -5936,6 +6611,34 @@ "node": ">=6" } }, + "node_modules/source-map": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.4.tgz", + "integrity": "sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/source-map-support": { + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "dev": true, + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "node_modules/source-map-support/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/sshpk": { "version": "1.18.0", "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.18.0.tgz", @@ -6166,6 +6869,92 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/tapable": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", + "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/terser": { + "version": "5.24.0", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.24.0.tgz", + "integrity": "sha512-ZpGR4Hy3+wBEzVEnHvstMvqpD/nABNelQn/z2r0fjVWGQsN3bpOLzQlqDxmb4CDZnXq5lpjnQ+mHQLAOpfM5iw==", + "dev": true, + "dependencies": { + "@jridgewell/source-map": "^0.3.3", + "acorn": "^8.8.2", + "commander": "^2.20.0", + "source-map-support": "~0.5.20" + }, + "bin": { + "terser": "bin/terser" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/terser-webpack-plugin": { + "version": "5.3.9", + "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.9.tgz", + "integrity": "sha512-ZuXsqE07EcggTWQjXUj+Aot/OMcD0bMKGgF63f7UxYcu5/AJF53aIpK1YoP5xR9l6s/Hy2b+t1AM0bLNPRuhwA==", + "dev": true, + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.17", + "jest-worker": "^27.4.5", + "schema-utils": "^3.1.1", + "serialize-javascript": "^6.0.1", + "terser": "^5.16.8" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.1.0" + }, + "peerDependenciesMeta": { + "@swc/core": { + "optional": true + }, + "esbuild": { + "optional": true + }, + "uglify-js": { + "optional": true + } + } + }, + "node_modules/terser-webpack-plugin/node_modules/@jridgewell/trace-mapping": { + "version": "0.3.20", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.20.tgz", + "integrity": "sha512-R8LcPeWZol2zR8mmH3JeKQ6QRCFb7XgUhV9ZlGhHLGyg4wpPiPZNQOOWhFZhxKw8u//yTbNGI42Bx/3paXEQ+Q==", + "dev": true, + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/terser-webpack-plugin/node_modules/serialize-javascript": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.1.tgz", + "integrity": "sha512-owoXEFjWRllis8/M1Q+Cw5k8ZH40e3zhp/ovX+Xr/vi1qj6QesbyXXViFbpNvWvPNAD62SutwEXavefrLJWj7w==", + "dev": true, + "dependencies": { + "randombytes": "^2.1.0" + } + }, + "node_modules/terser/node_modules/commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "dev": true + }, "node_modules/text-hex": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/text-hex/-/text-hex-1.0.0.tgz", @@ -6262,6 +7051,59 @@ "typescript": ">=4.2.0" } }, + "node_modules/ts-loader": { + "version": "9.5.1", + "resolved": "https://registry.npmjs.org/ts-loader/-/ts-loader-9.5.1.tgz", + "integrity": "sha512-rNH3sK9kGZcH9dYzC7CewQm4NtxJTjSEVRJ2DyBZR7f8/wcta+iV44UPCXc5+nzDzivKtlzV6c9P4e+oFhDLYg==", + "dev": true, + "dependencies": { + "chalk": "^4.1.0", + "enhanced-resolve": "^5.0.0", + "micromatch": "^4.0.0", + "semver": "^7.3.4", + "source-map": "^0.7.4" + }, + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "typescript": "*", + "webpack": "^5.0.0" + } + }, + "node_modules/ts-loader/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/ts-loader/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/ts-loader/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/ts-node": { "version": "10.9.1", "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.1.tgz", @@ -6527,7 +7369,6 @@ "url": "https://github.com/sponsors/ai" } ], - "peer": true, "dependencies": { "escalade": "^3.1.1", "picocolors": "^1.0.0" @@ -6618,6 +7459,181 @@ "makeerror": "1.0.12" } }, + "node_modules/watchpack": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.0.tgz", + "integrity": "sha512-Lcvm7MGST/4fup+ifyKi2hjyIAwcdI4HRgtvTpIUxBRhB+RFtUh8XtDOxUfctVCnhVi+QQj49i91OyvzkJl6cg==", + "dev": true, + "dependencies": { + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.1.2" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/webpack": { + "version": "5.89.0", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.89.0.tgz", + "integrity": "sha512-qyfIC10pOr70V+jkmud8tMfajraGCZMBWJtrmuBymQKCrLTRejBI8STDp1MCyZu/QTdZSeacCQYpYNQVOzX5kw==", + "dev": true, + "dependencies": { + "@types/eslint-scope": "^3.7.3", + "@types/estree": "^1.0.0", + "@webassemblyjs/ast": "^1.11.5", + "@webassemblyjs/wasm-edit": "^1.11.5", + "@webassemblyjs/wasm-parser": "^1.11.5", + "acorn": "^8.7.1", + "acorn-import-assertions": "^1.9.0", + "browserslist": "^4.14.5", + "chrome-trace-event": "^1.0.2", + "enhanced-resolve": "^5.15.0", + "es-module-lexer": "^1.2.1", + "eslint-scope": "5.1.1", + "events": "^3.2.0", + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.2.9", + "json-parse-even-better-errors": "^2.3.1", + "loader-runner": "^4.2.0", + "mime-types": "^2.1.27", + "neo-async": "^2.6.2", + "schema-utils": "^3.2.0", + "tapable": "^2.1.1", + "terser-webpack-plugin": "^5.3.7", + "watchpack": "^2.4.0", + "webpack-sources": "^3.2.3" + }, + "bin": { + "webpack": "bin/webpack.js" + }, + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependenciesMeta": { + "webpack-cli": { + "optional": true + } + } + }, + "node_modules/webpack-cli": { + "version": "5.1.4", + "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-5.1.4.tgz", + "integrity": "sha512-pIDJHIEI9LR0yxHXQ+Qh95k2EvXpWzZ5l+d+jIo+RdSm9MiHfzazIxwwni/p7+x4eJZuvG1AJwgC4TNQ7NRgsg==", + "dev": true, + "dependencies": { + "@discoveryjs/json-ext": "^0.5.0", + "@webpack-cli/configtest": "^2.1.1", + "@webpack-cli/info": "^2.0.2", + "@webpack-cli/serve": "^2.0.5", + "colorette": "^2.0.14", + "commander": "^10.0.1", + "cross-spawn": "^7.0.3", + "envinfo": "^7.7.3", + "fastest-levenshtein": "^1.0.12", + "import-local": "^3.0.2", + "interpret": "^3.1.1", + "rechoir": "^0.8.0", + "webpack-merge": "^5.7.3" + }, + "bin": { + "webpack-cli": "bin/cli.js" + }, + "engines": { + "node": ">=14.15.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "5.x.x" + }, + "peerDependenciesMeta": { + "@webpack-cli/generators": { + "optional": true + }, + "webpack-bundle-analyzer": { + "optional": true + }, + "webpack-dev-server": { + "optional": true + } + } + }, + "node_modules/webpack-cli/node_modules/commander": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-10.0.1.tgz", + "integrity": "sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==", + "dev": true, + "engines": { + "node": ">=14" + } + }, + "node_modules/webpack-merge": { + "version": "5.10.0", + "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-5.10.0.tgz", + "integrity": "sha512-+4zXKdx7UnO+1jaN4l2lHVD+mFvnlZQP/6ljaJVb4SZiwIKeUnrT5l0gkT8z+n4hKpC+jpOv6O9R+gLtag7pSA==", + "dev": true, + "dependencies": { + "clone-deep": "^4.0.1", + "flat": "^5.0.2", + "wildcard": "^2.0.0" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/webpack-sources": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.2.3.tgz", + "integrity": "sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==", + "dev": true, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/webpack-visualizer-plugin2": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/webpack-visualizer-plugin2/-/webpack-visualizer-plugin2-1.1.0.tgz", + "integrity": "sha512-pB2Z9a12m+LwjrfptyR4ReEPc0llOjsb2lXVLEJ4yOnRCBtLeWW+TZrZihUZhJDSW9tc60UXnj9/orgyagLOkg==", + "dev": true, + "dependencies": { + "d3": "^3.5.6", + "mkdirp": "^0.5.1", + "prop-types": "^15.7.2", + "react": "^17.0.1", + "react-dom": "^17.0.1" + }, + "engines": { + "npm": ">=5.0.0" + } + }, + "node_modules/webpack/node_modules/eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "dev": true, + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/webpack/node_modules/estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, "node_modules/which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", @@ -6668,6 +7684,12 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/wildcard": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/wildcard/-/wildcard-2.0.1.tgz", + "integrity": "sha512-CC1bOL87PIWSBhDcTrdeLo6eGT7mCFtrg0uIJtqJUFyK+eJnzl8A1niH56uu7KMa5XFrtiV+AQuHO3n7DsHnLQ==", + "dev": true + }, "node_modules/winston": { "version": "3.11.0", "resolved": "https://registry.npmjs.org/winston/-/winston-3.11.0.tgz", diff --git a/ethers-ext/package.json b/ethers-ext/package.json index 96478cd0f..4fd55312c 100644 --- a/ethers-ext/package.json +++ b/ethers-ext/package.json @@ -8,7 +8,9 @@ "./src" ], "scripts": { - "build": "tsc", + "build": "npm run build:esm && npm run build:bundle", + "build:esm": "tsc", + "build:bundle": "webpack --mode production", "watch": "tsc -w", "lint": "npm run lint:check", "lint:check": "eslint example src test --cache --quiet", @@ -32,8 +34,12 @@ "eslint": "^8.45.0", "eslint-plugin-import": "^2.27.5", "mocha": "^10.2.0", + "ts-loader": "^9.5.1", "ts-node": "^10.9.1", - "typescript": "^5.0.4" + "typescript": "^5.0.4", + "webpack": "^5.89.0", + "webpack-cli": "^5.1.4", + "webpack-visualizer-plugin2": "^1.1.0" }, "dependencies": { "@klaytn/js-ext-core": "^0.9.7-beta", diff --git a/ethers-ext/webpack.config.js b/ethers-ext/webpack.config.js new file mode 100644 index 000000000..5ad51949b --- /dev/null +++ b/ethers-ext/webpack.config.js @@ -0,0 +1,28 @@ +const path = require("path"); + +module.exports = { + entry: "./src/index.ts", + module: { + rules: [ + { + test: /\.ts$/, + use: 'ts-loader', + exclude: /node_modules/, + }, + ], + }, + resolve: { + extensions: ['.tsx', '.ts', '.js'], + fallback: { + "querystring": false, // referenced in web3rpc/ApiClient, which is unused. + }, + }, + output: { + // Output dist/ethers-ext.bundle.js + filename: 'ethers-ext.bundle.js', + path: path.resolve(__dirname, 'dist'), + // Define window.ethers_ext + library: "ethers_ext", + libraryTarget: "window", + }, +}; From 4bfe0008daa23d8f83d105a2b1d15f839483a26a Mon Sep 17 00:00:00 2001 From: "ollie.j" Date: Mon, 4 Dec 2023 11:12:21 +0900 Subject: [PATCH 02/33] ethers: Browser example imports ethers cdn --- ethers-ext/example/browser-html/index.html | 1 + 1 file changed, 1 insertion(+) diff --git a/ethers-ext/example/browser-html/index.html b/ethers-ext/example/browser-html/index.html index debf5bb04..42d6c9509 100644 --- a/ethers-ext/example/browser-html/index.html +++ b/ethers-ext/example/browser-html/index.html @@ -8,6 +8,7 @@ Hello + From 8a9efcee6c4340047cd21ca6d1a4200be2013635 Mon Sep 17 00:00:00 2001 From: Nohyun Nehemiah Kwak Date: Tue, 5 Dec 2023 19:43:57 +0900 Subject: [PATCH 03/33] Initial test version --- ethers-ext/example/browser-html/index.html | 7 +- ethers-ext/example/browser-html/main.js | 85 ++++++++++++++++++++++ 2 files changed, 91 insertions(+), 1 deletion(-) diff --git a/ethers-ext/example/browser-html/index.html b/ethers-ext/example/browser-html/index.html index 42d6c9509..bf7e63102 100644 --- a/ethers-ext/example/browser-html/index.html +++ b/ethers-ext/example/browser-html/index.html @@ -6,7 +6,12 @@ - Hello + + + + + + diff --git a/ethers-ext/example/browser-html/main.js b/ethers-ext/example/browser-html/main.js index 5ae5659f8..f389d0582 100644 --- a/ethers-ext/example/browser-html/main.js +++ b/ethers-ext/example/browser-html/main.js @@ -1 +1,86 @@ console.log("hello ethers_ext", ethers_ext.TxType.ValueTransfer); + +async function connect() { + if (typeof window.klaytn !== "undefined") { + try { + await klaytn.request({method: "klay_requestAccounts"}); + } catch (error) { + console.log(error); + } + document.getElementById("connectButton").innerHTML = "Connected"; + const accounts = await klaytn.request({ method: "klay_accounts" }); + document.getElementById("accounts").innerHTML = accounts; + console.log(accounts); + } else { + document.getElementById("connectButton").innerHTML = + "Please install Kaikas"; + } +} + +async function execute() { + if (typeof window.klaytn !== "undefined") { + const senderAddr = "0xe15cd70a41dfb05e7214004d7d054801b2a2f06b"; + const senderPriv = "0x0e4ca6d38096ad99324de0dde108587e5d7c600165ae4cd6c2462c597458c2b8"; + const senderNewPriv = "0x0e4ca6d38096ad99324de0dde108587e5d7c600165ae4cd6c2462c597458c2b8"; + + const provider = new ethers.providers.Web3Provider(window.klaytn); + const signer = provider.getSigner(); + + // 서명은 되지만 트랜잭션으로 전송되고 callback이 없어서 확인이 안됨 + // const message = 'Hello dapp'; + // const signature = await signer.signMessage(message); + // console.log( signature ); + + try { + let tx = { + type: TxType.AccountUpdate, + from: senderAddr, + key: { + type: AccountKeyType.Public, + key: ethers.utils.computePublicKey(senderNewPriv, true), + } + }; + + // 1. + // const populatedTx = await signer.populateTransaction(tx); + // const signedTx = await signer.signTransaction(populatedTx); + + // const sentTx = await this._sendRawTransaction(signedTx); + // console.log("sentTx", sentTx); + + // 2. + // const sentTx = await signer.sendTransaction(tx); + // console.log("sentTx", sentTx); + + // 3. + let params = [ + { + from: "0x672e7a695066b131cE36842D978Ad9e251A2Df7E", + to: "0x672e7a695066b131cE36842D978Ad9e251A2Df7E", + gas: "0x76c0", // 30400 + value: "0x0", // 2441406250 + } + ]; + + window.klaytn + .request({ + method: "klay_sendTransaction", + params: params, + }) + .then((result) => { + // The result varies by RPC method. + // For example, this method returns a transaction hash hexadecimal string upon success. + console.log(result); + }) + .catch((error) => { + // If the request fails, the Promise rejects with an error. + console.log(error); + }); + } catch (error) { + console.log(error); + } + } else { + document.getElementById("executeButton").innerHTML = + "Please install Kaikas"; + } +} \ No newline at end of file From f5f203c84c39a6e609eb80a4a2f6f7decd85b445 Mon Sep 17 00:00:00 2001 From: Nohyun Nehemiah Kwak Date: Tue, 5 Dec 2023 20:13:23 +0900 Subject: [PATCH 04/33] Declare path --- ethers-ext/example/browser-html/main.js | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/ethers-ext/example/browser-html/main.js b/ethers-ext/example/browser-html/main.js index f389d0582..d6a6f6d30 100644 --- a/ethers-ext/example/browser-html/main.js +++ b/ethers-ext/example/browser-html/main.js @@ -1,5 +1,3 @@ -console.log("hello ethers_ext", ethers_ext.TxType.ValueTransfer); - async function connect() { if (typeof window.klaytn !== "undefined") { try { @@ -33,10 +31,10 @@ async function execute() { try { let tx = { - type: TxType.AccountUpdate, + type: ethers_ext.TxType.AccountUpdate, from: senderAddr, key: { - type: AccountKeyType.Public, + type: ethers_ext.AccountKeyType.Public, key: ethers.utils.computePublicKey(senderNewPriv, true), } }; From d67ce8079553cd14c86bf2e2fb43d30dd7f6fd9f Mon Sep 17 00:00:00 2001 From: Nohyun Nehemiah Kwak Date: Tue, 5 Dec 2023 22:02:58 +0900 Subject: [PATCH 05/33] Initial porting --- ethers-ext/src/provider.ts | 11 +++ ethers-ext/src/signer.ts | 133 ++++++++++++++++++++++++++++++++++++- 2 files changed, 142 insertions(+), 2 deletions(-) diff --git a/ethers-ext/src/provider.ts b/ethers-ext/src/provider.ts index cc756496d..3ac7cccfe 100644 --- a/ethers-ext/src/provider.ts +++ b/ethers-ext/src/provider.ts @@ -5,6 +5,8 @@ import { asyncOpenApi, AsyncNamespaceApi } from "@klaytn/js-ext-core"; // @ts-ignore: package @klaytn/web3rpc has no .d.ts file. import { AdminApi, DebugApi, GovernanceApi, KlayApi, NetApi, PersonalApi, TxpoolApi } from "@klaytn/web3rpc"; +import {JsonRpcSigner} from "./signer"; + /* eslint-disable no-multi-spaces */ export class JsonRpcProvider extends EthersJsonRpcProvider { // API methods other than eth_ namespaces @@ -16,6 +18,9 @@ export class JsonRpcProvider extends EthersJsonRpcProvider { personal: AsyncNamespaceApi; txpool: AsyncNamespaceApi; + // TODO : chekc the meaning for _constructorGuard + private _constructorGuard: any; + constructor(url?: ConnectionInfo | string, network?: Networkish) { super(url, network); @@ -30,5 +35,11 @@ export class JsonRpcProvider extends EthersJsonRpcProvider { this.net = asyncOpenApi(send, NetApi); this.personal = asyncOpenApi(send, PersonalApi); this.txpool = asyncOpenApi(send, TxpoolApi); + + // TODO : chekc the meaning for _constructorGuard + this._constructorGuard = {}; + this.getSigner = function (addressOrIndex) { + return new JsonRpcSigner(this._constructorGuard, this, addressOrIndex); + }; } } \ No newline at end of file diff --git a/ethers-ext/src/signer.ts b/ethers-ext/src/signer.ts index 9b7cc320f..bb3c3542e 100644 --- a/ethers-ext/src/signer.ts +++ b/ethers-ext/src/signer.ts @@ -1,11 +1,11 @@ import { Provider, TransactionRequest, TransactionResponse } from "@ethersproject/abstract-provider"; import { ExternallyOwnedAccount } from "@ethersproject/abstract-signer"; -import { JsonRpcProvider as EthersJsonRpcProvider } from "@ethersproject/providers"; +import { JsonRpcProvider as EthersJsonRpcProvider, JsonRpcSigner as EthersJsonRpcSigner } from "@ethersproject/providers"; import { Wallet as EthersWallet } from "@ethersproject/wallet"; import { poll } from "@ethersproject/web"; import { KlaytnTxFactory, HexStr, isFeePayerSigTxType, parseTransaction } from "@klaytn/js-ext-core"; import { BigNumber } from "ethers"; -import { Bytes, BytesLike, Deferrable, Logger, ProgressCallback, SigningKey, computeAddress, keccak256, resolveProperties } from "ethers/lib/utils"; +import { Bytes, BytesLike, Deferrable, Logger, ProgressCallback, SigningKey, computeAddress, hexlify, keccak256, resolveProperties } from "ethers/lib/utils"; import _ from "lodash"; import { decryptKeystoreList, decryptKeystoreListSync } from "./keystore"; @@ -320,3 +320,132 @@ export class Wallet extends EthersWallet { } } } + +const Primitive = "bigint,boolean,function,number,string,symbol".split(/,/g); +function deepCopy(value: T): T { + if (value == null || Primitive.indexOf(typeof(value)) >= 0) { + return value; + } + + // Keep any Addressable + if (typeof((value).getAddress) === "function") { + return value; + } + + if (Array.isArray(value)) { return (value.map(deepCopy)); } + + if (typeof(value) === "object") { + return Object.keys(value).reduce((accum, key) => { + accum[key] = (value)[key]; + return accum; + }, { }); + } + + throw new Error(`should not happen: ${ value } (${ typeof(value) })`); +} + +export class JsonRpcSigner extends EthersJsonRpcSigner { + // TODO : inclue JsonRpcApiProvider + // constructor(provider: JsonRpcApiProvider, address: string) { + // super(provider, address); + // } + + async populateTransaction(tx: TransactionRequest): Promise> { + // @ts-ignore + return await this.populateCall(tx); + } + + async sendUncheckedTransaction(_tx: TransactionRequest): Promise { + const tx = deepCopy(_tx); + + const promises: Array> = []; + + // Make sure the from matches the sender + if (tx.from) { + const _from = tx.from; + promises.push((async () => { + const from = await resolveAddress(_from, this.provider); + assertArgument(from != null && from.toLowerCase() === this.address.toLowerCase(), + "from address mismatch", "transaction", _tx); + tx.from = from; + })()); + } else { + tx.from = this.address; + } + + // The JSON-RPC for eth_sendTransaction uses 90000 gas; if the user + // wishes to use this, it is easy to specify explicitly, otherwise + // we look it up for them. + if (tx.gasLimit == null) { + promises.push((async () => { + tx.gasLimit = await this.provider.estimateGas({ ...tx, from: this.address}); + })()); + } + + // The address may be an ENS name or Addressable + if (tx.to != null) { + const _to = tx.to; + promises.push((async () => { + tx.to = await resolveAddress(_to, this.provider); + })()); + } + + // Wait until all of our properties are filled in + if (promises.length) { await Promise.all(promises); } + + const hexTx = this.provider.getRpcTransaction(tx); + + return this.provider.send("klay_sendTransaction", [hexTx]); + } + + async sendTransaction(tx: TransactionRequest): Promise { + // This cannot be mined any earlier than any recent block + const blockNumber = await this.provider.getBlockNumber(); + + // Send the transaction + const hash = await this.sendUncheckedTransaction(tx); + + // Unfortunately, JSON-RPC only provides and opaque transaction hash + // for a response, and we need the actual transaction, so we poll + // for it; it should show up very quickly + return await (new Promise((resolve, reject) => { + const timeouts = [1000, 100]; + const checkTx = async () => { + // Try getting the transaction + const tx = await this.provider.getTransaction(hash); + if (tx != null) { + resolve(tx.replaceableTransaction(blockNumber)); + return; + } + + // Wait another 4 seconds + this.provider._setTimeout(() => { checkTx(); }, timeouts.pop() || 4000); + }; + checkTx(); + })); + } + + async signTransaction(_tx: TransactionRequest): Promise { + const tx = deepCopy(_tx); + + // Make sure the from matches the sender + if (tx.from) { + const from = await resolveAddress(tx.from, this.provider); + assertArgument(from != null && from.toLowerCase() === this.address.toLowerCase(), + "from address mismatch", "transaction", _tx); + tx.from = from; + } else { + tx.from = this.address; + } + + const hexTx = this.provider.getRpcTransaction(tx); + return await this.provider.send("klay_signTransaction", [hexTx]); + } + + + async signMessage(_message: string | Uint8Array): Promise { + const message = ((typeof(_message) === "string") ? toUtf8Bytes(_message) : _message); + return await this.provider.send("personal_sign", [ + hexlify(message), this.address.toLowerCase()]); + } +} \ No newline at end of file From 035da049f511c9aacbf7605894c61574390489dd Mon Sep 17 00:00:00 2001 From: Nohyun Nehemiah Kwak Date: Wed, 6 Dec 2023 17:57:26 +0900 Subject: [PATCH 06/33] Create child classes --- ethers-ext/example/browser-html/main.js | 18 ++-- ethers-ext/src/provider.ts | 19 ++-- ethers-ext/src/signer.ts | 131 +++--------------------- 3 files changed, 34 insertions(+), 134 deletions(-) diff --git a/ethers-ext/example/browser-html/main.js b/ethers-ext/example/browser-html/main.js index d6a6f6d30..700667152 100644 --- a/ethers-ext/example/browser-html/main.js +++ b/ethers-ext/example/browser-html/main.js @@ -1,12 +1,18 @@ +// const browser = window.klaytn; +// const nameSpace = "klay"; + +const browser = window.ethereum; +const nameSpace = "eth"; + async function connect() { - if (typeof window.klaytn !== "undefined") { + if (typeof browser !== "undefined") { try { - await klaytn.request({method: "klay_requestAccounts"}); + await browser.request({method: nameSpace+"_requestAccounts"}); } catch (error) { console.log(error); } document.getElementById("connectButton").innerHTML = "Connected"; - const accounts = await klaytn.request({ method: "klay_accounts" }); + const accounts = await browser.request({ method: nameSpace+"_accounts" }); document.getElementById("accounts").innerHTML = accounts; console.log(accounts); } else { @@ -16,12 +22,12 @@ async function connect() { } async function execute() { - if (typeof window.klaytn !== "undefined") { + if (typeof browser !== "undefined") { const senderAddr = "0xe15cd70a41dfb05e7214004d7d054801b2a2f06b"; const senderPriv = "0x0e4ca6d38096ad99324de0dde108587e5d7c600165ae4cd6c2462c597458c2b8"; const senderNewPriv = "0x0e4ca6d38096ad99324de0dde108587e5d7c600165ae4cd6c2462c597458c2b8"; - const provider = new ethers.providers.Web3Provider(window.klaytn); + const provider = new ethers.providers.Web3Provider(browser); const signer = provider.getSigner(); // 서명은 되지만 트랜잭션으로 전송되고 callback이 없어서 확인이 안됨 @@ -62,7 +68,7 @@ async function execute() { window.klaytn .request({ - method: "klay_sendTransaction", + method: nameSpace+"_sendTransaction", params: params, }) .then((result) => { diff --git a/ethers-ext/src/provider.ts b/ethers-ext/src/provider.ts index 3ac7cccfe..76e6f831c 100644 --- a/ethers-ext/src/provider.ts +++ b/ethers-ext/src/provider.ts @@ -1,12 +1,11 @@ import { Networkish } from "@ethersproject/networks"; -import { JsonRpcProvider as EthersJsonRpcProvider } from "@ethersproject/providers"; +import { JsonRpcProvider as EthersJsonRpcProvider, Web3Provider as EthersWeb3Provider, JsonRpcSigner } from "@ethersproject/providers"; import { ConnectionInfo } from "@ethersproject/web"; import { asyncOpenApi, AsyncNamespaceApi } from "@klaytn/js-ext-core"; + // @ts-ignore: package @klaytn/web3rpc has no .d.ts file. import { AdminApi, DebugApi, GovernanceApi, KlayApi, NetApi, PersonalApi, TxpoolApi } from "@klaytn/web3rpc"; -import {JsonRpcSigner} from "./signer"; - /* eslint-disable no-multi-spaces */ export class JsonRpcProvider extends EthersJsonRpcProvider { // API methods other than eth_ namespaces @@ -18,9 +17,6 @@ export class JsonRpcProvider extends EthersJsonRpcProvider { personal: AsyncNamespaceApi; txpool: AsyncNamespaceApi; - // TODO : chekc the meaning for _constructorGuard - private _constructorGuard: any; - constructor(url?: ConnectionInfo | string, network?: Networkish) { super(url, network); @@ -35,11 +31,12 @@ export class JsonRpcProvider extends EthersJsonRpcProvider { this.net = asyncOpenApi(send, NetApi); this.personal = asyncOpenApi(send, PersonalApi); this.txpool = asyncOpenApi(send, TxpoolApi); + } +} - // TODO : chekc the meaning for _constructorGuard - this._constructorGuard = {}; - this.getSigner = function (addressOrIndex) { - return new JsonRpcSigner(this._constructorGuard, this, addressOrIndex); - }; +const _constructorGuard = {}; +export class Web3Provider extends EthersWeb3Provider { + override getSigner(addressOrIndex?: string | number | undefined): JsonRpcSigner { + return new JsonRpcSigner(_constructorGuard, this, addressOrIndex); } } \ No newline at end of file diff --git a/ethers-ext/src/signer.ts b/ethers-ext/src/signer.ts index bb3c3542e..779e78927 100644 --- a/ethers-ext/src/signer.ts +++ b/ethers-ext/src/signer.ts @@ -321,131 +321,28 @@ export class Wallet extends EthersWallet { } } -const Primitive = "bigint,boolean,function,number,string,symbol".split(/,/g); -function deepCopy(value: T): T { - if (value == null || Primitive.indexOf(typeof(value)) >= 0) { - return value; - } - - // Keep any Addressable - if (typeof((value).getAddress) === "function") { - return value; - } - - if (Array.isArray(value)) { return (value.map(deepCopy)); } - - if (typeof(value) === "object") { - return Object.keys(value).reduce((accum, key) => { - accum[key] = (value)[key]; - return accum; - }, { }); - } +export class JsonRpcSigner extends EthersJsonRpcSigner { - throw new Error(`should not happen: ${ value } (${ typeof(value) })`); -} + // TODO : implements all method -export class JsonRpcSigner extends EthersJsonRpcSigner { - // TODO : inclue JsonRpcApiProvider // constructor(provider: JsonRpcApiProvider, address: string) { // super(provider, address); // } - async populateTransaction(tx: TransactionRequest): Promise> { - // @ts-ignore - return await this.populateCall(tx); - } - - async sendUncheckedTransaction(_tx: TransactionRequest): Promise { - const tx = deepCopy(_tx); - - const promises: Array> = []; - - // Make sure the from matches the sender - if (tx.from) { - const _from = tx.from; - promises.push((async () => { - const from = await resolveAddress(_from, this.provider); - assertArgument(from != null && from.toLowerCase() === this.address.toLowerCase(), - "from address mismatch", "transaction", _tx); - tx.from = from; - })()); - } else { - tx.from = this.address; - } - - // The JSON-RPC for eth_sendTransaction uses 90000 gas; if the user - // wishes to use this, it is easy to specify explicitly, otherwise - // we look it up for them. - if (tx.gasLimit == null) { - promises.push((async () => { - tx.gasLimit = await this.provider.estimateGas({ ...tx, from: this.address}); - })()); - } - - // The address may be an ENS name or Addressable - if (tx.to != null) { - const _to = tx.to; - promises.push((async () => { - tx.to = await resolveAddress(_to, this.provider); - })()); - } - - // Wait until all of our properties are filled in - if (promises.length) { await Promise.all(promises); } - - const hexTx = this.provider.getRpcTransaction(tx); - - return this.provider.send("klay_sendTransaction", [hexTx]); - } - - async sendTransaction(tx: TransactionRequest): Promise { - // This cannot be mined any earlier than any recent block - const blockNumber = await this.provider.getBlockNumber(); - - // Send the transaction - const hash = await this.sendUncheckedTransaction(tx); - - // Unfortunately, JSON-RPC only provides and opaque transaction hash - // for a response, and we need the actual transaction, so we poll - // for it; it should show up very quickly - return await (new Promise((resolve, reject) => { - const timeouts = [1000, 100]; - const checkTx = async () => { - // Try getting the transaction - const tx = await this.provider.getTransaction(hash); - if (tx != null) { - resolve(tx.replaceableTransaction(blockNumber)); - return; - } - - // Wait another 4 seconds - this.provider._setTimeout(() => { checkTx(); }, timeouts.pop() || 4000); - }; - checkTx(); - })); - } - - async signTransaction(_tx: TransactionRequest): Promise { - const tx = deepCopy(_tx); + // override async populateTransaction(tx: TransactionRequest): Promise> { + // // @ts-ignore + // return await this.populateCall(tx); + // } - // Make sure the from matches the sender - if (tx.from) { - const from = await resolveAddress(tx.from, this.provider); - assertArgument(from != null && from.toLowerCase() === this.address.toLowerCase(), - "from address mismatch", "transaction", _tx); - tx.from = from; - } else { - tx.from = this.address; - } + // override async sendUncheckedTransaction(_tx: TransactionRequest): Promise { + // } - const hexTx = this.provider.getRpcTransaction(tx); - return await this.provider.send("klay_signTransaction", [hexTx]); - } + // override async sendTransaction(tx: TransactionRequest): Promise { + // } + // override async signTransaction(_tx: TransactionRequest): Promise { + // } - async signMessage(_message: string | Uint8Array): Promise { - const message = ((typeof(_message) === "string") ? toUtf8Bytes(_message) : _message); - return await this.provider.send("personal_sign", [ - hexlify(message), this.address.toLowerCase()]); - } + // override async signMessage(_message: string | Uint8Array): Promise { + // } } \ No newline at end of file From 18992248013a6e00396a7aa70045ccae08606429 Mon Sep 17 00:00:00 2001 From: Nohyun Nehemiah Kwak Date: Wed, 6 Dec 2023 18:27:19 +0900 Subject: [PATCH 07/33] Web3Provider's getSigner call succeeds --- ethers-ext/example/browser-html/main.js | 80 ++++++++++++------------- ethers-ext/src/provider.ts | 1 + 2 files changed, 41 insertions(+), 40 deletions(-) diff --git a/ethers-ext/example/browser-html/main.js b/ethers-ext/example/browser-html/main.js index 700667152..c67bcfc4e 100644 --- a/ethers-ext/example/browser-html/main.js +++ b/ethers-ext/example/browser-html/main.js @@ -1,7 +1,7 @@ -// const browser = window.klaytn; +const browser = window.klaytn; // const nameSpace = "klay"; -const browser = window.ethereum; +// const browser = window.ethereum; const nameSpace = "eth"; async function connect() { @@ -23,27 +23,27 @@ async function connect() { async function execute() { if (typeof browser !== "undefined") { - const senderAddr = "0xe15cd70a41dfb05e7214004d7d054801b2a2f06b"; - const senderPriv = "0x0e4ca6d38096ad99324de0dde108587e5d7c600165ae4cd6c2462c597458c2b8"; - const senderNewPriv = "0x0e4ca6d38096ad99324de0dde108587e5d7c600165ae4cd6c2462c597458c2b8"; - - const provider = new ethers.providers.Web3Provider(browser); + const provider = new ethers_ext.Web3Provider(browser); const signer = provider.getSigner(); // 서명은 되지만 트랜잭션으로 전송되고 callback이 없어서 확인이 안됨 - // const message = 'Hello dapp'; - // const signature = await signer.signMessage(message); - // console.log( signature ); + const message = 'Hello dapp'; + const signature = await signer.signMessage(message); + console.log( signature ); + + const senderAddr = "0xe15cd70a41dfb05e7214004d7d054801b2a2f06b"; + const senderPriv = "0x0e4ca6d38096ad99324de0dde108587e5d7c600165ae4cd6c2462c597458c2b8"; + const senderNewPriv = "0x0e4ca6d38096ad99324de0dde108587e5d7c600165ae4cd6c2462c597458c2b8"; try { - let tx = { - type: ethers_ext.TxType.AccountUpdate, - from: senderAddr, - key: { - type: ethers_ext.AccountKeyType.Public, - key: ethers.utils.computePublicKey(senderNewPriv, true), - } - }; + // let tx = { + // type: ethers_ext.TxType.AccountUpdate, + // from: senderAddr, + // key: { + // type: ethers_ext.AccountKeyType.Public, + // key: ethers.utils.computePublicKey(senderNewPriv, true), + // } + // }; // 1. // const populatedTx = await signer.populateTransaction(tx); @@ -57,29 +57,29 @@ async function execute() { // console.log("sentTx", sentTx); // 3. - let params = [ - { - from: "0x672e7a695066b131cE36842D978Ad9e251A2Df7E", - to: "0x672e7a695066b131cE36842D978Ad9e251A2Df7E", - gas: "0x76c0", // 30400 - value: "0x0", // 2441406250 - } - ]; + // let params = [ + // { + // from: "0x672e7a695066b131cE36842D978Ad9e251A2Df7E", + // to: "0x672e7a695066b131cE36842D978Ad9e251A2Df7E", + // gas: "0x76c0", // 30400 + // value: "0x0", // 2441406250 + // } + // ]; - window.klaytn - .request({ - method: nameSpace+"_sendTransaction", - params: params, - }) - .then((result) => { - // The result varies by RPC method. - // For example, this method returns a transaction hash hexadecimal string upon success. - console.log(result); - }) - .catch((error) => { - // If the request fails, the Promise rejects with an error. - console.log(error); - }); + + // browser.request({ + // method: nameSpace+"_sendTransaction", + // params: params, + // }) + // .then((result) => { + // // The result varies by RPC method. + // // For example, this method returns a transaction hash hexadecimal string upon success. + // console.log(result); + // }) + // .catch((error) => { + // // If the request fails, the Promise rejects with an error. + // console.log(error); + // }); } catch (error) { console.log(error); } diff --git a/ethers-ext/src/provider.ts b/ethers-ext/src/provider.ts index 76e6f831c..4cc57b561 100644 --- a/ethers-ext/src/provider.ts +++ b/ethers-ext/src/provider.ts @@ -37,6 +37,7 @@ export class JsonRpcProvider extends EthersJsonRpcProvider { const _constructorGuard = {}; export class Web3Provider extends EthersWeb3Provider { override getSigner(addressOrIndex?: string | number | undefined): JsonRpcSigner { + console.log("it's me") return new JsonRpcSigner(_constructorGuard, this, addressOrIndex); } } \ No newline at end of file From 8a5d9d3dd6972773144d8eb3a99dc3dcf7712f91 Mon Sep 17 00:00:00 2001 From: Yunjong Jeong Date: Thu, 7 Dec 2023 00:11:43 +0900 Subject: [PATCH 08/33] Update browser-html --- ethers-ext/.eslintrc.js | 7 + ethers-ext/example/browser-html/index.html | 20 ++- ethers-ext/example/browser-html/main.js | 145 +++++++++------------ 3 files changed, 82 insertions(+), 90 deletions(-) diff --git a/ethers-ext/.eslintrc.js b/ethers-ext/.eslintrc.js index 593d82b79..5295cbe28 100644 --- a/ethers-ext/.eslintrc.js +++ b/ethers-ext/.eslintrc.js @@ -94,5 +94,12 @@ module.exports = { "prefer-const": "off", } }, + { // browser examples use browser globals + "filters": ["example/browser-html/*"], + "rules": { + "no-undef": "off", + "no-unused-vars": "off", + } + } ] }; diff --git a/ethers-ext/example/browser-html/index.html b/ethers-ext/example/browser-html/index.html index bf7e63102..64ccf102c 100644 --- a/ethers-ext/example/browser-html/index.html +++ b/ethers-ext/example/browser-html/index.html @@ -7,13 +7,25 @@ - - - +

+

+
+

+

+
+

+

+

+

+
+

accounts:

+

signature:

+

txhash:

- + + diff --git a/ethers-ext/example/browser-html/main.js b/ethers-ext/example/browser-html/main.js index c67bcfc4e..2034df536 100644 --- a/ethers-ext/example/browser-html/main.js +++ b/ethers-ext/example/browser-html/main.js @@ -1,90 +1,63 @@ -const browser = window.klaytn; -// const nameSpace = "klay"; +var provider = null; -// const browser = window.ethereum; -const nameSpace = "eth"; - -async function connect() { - if (typeof browser !== "undefined") { - try { - await browser.request({method: nameSpace+"_requestAccounts"}); - } catch (error) { - console.log(error); - } - document.getElementById("connectButton").innerHTML = "Connected"; - const accounts = await browser.request({ method: nameSpace+"_accounts" }); - document.getElementById("accounts").innerHTML = accounts; - console.log(accounts); - } else { - document.getElementById("connectButton").innerHTML = - "Please install Kaikas"; +// https://docs.ethers.org/v5/getting-started/#getting-started--connecting +async function connect(injectedProvider) { + if (!injectedProvider) { + alert("Please install wallet"); + return; } + provider = new ethers.providers.Web3Provider(injectedProvider); + + await provider.send("eth_requestAccounts", []); + const accounts = await provider.listAccounts(); // internally eth_accounts + console.log("accounts", accounts); + $("#textAccounts").html(accounts); } - -async function execute() { - if (typeof browser !== "undefined") { - const provider = new ethers_ext.Web3Provider(browser); - const signer = provider.getSigner(); - - // 서명은 되지만 트랜잭션으로 전송되고 callback이 없어서 확인이 안됨 - const message = 'Hello dapp'; - const signature = await signer.signMessage(message); - console.log( signature ); - - const senderAddr = "0xe15cd70a41dfb05e7214004d7d054801b2a2f06b"; - const senderPriv = "0x0e4ca6d38096ad99324de0dde108587e5d7c600165ae4cd6c2462c597458c2b8"; - const senderNewPriv = "0x0e4ca6d38096ad99324de0dde108587e5d7c600165ae4cd6c2462c597458c2b8"; - - try { - // let tx = { - // type: ethers_ext.TxType.AccountUpdate, - // from: senderAddr, - // key: { - // type: ethers_ext.AccountKeyType.Public, - // key: ethers.utils.computePublicKey(senderNewPriv, true), - // } - // }; - - // 1. - // const populatedTx = await signer.populateTransaction(tx); - // const signedTx = await signer.signTransaction(populatedTx); - - // const sentTx = await this._sendRawTransaction(signedTx); - // console.log("sentTx", sentTx); - - // 2. - // const sentTx = await signer.sendTransaction(tx); - // console.log("sentTx", sentTx); - - // 3. - // let params = [ - // { - // from: "0x672e7a695066b131cE36842D978Ad9e251A2Df7E", - // to: "0x672e7a695066b131cE36842D978Ad9e251A2Df7E", - // gas: "0x76c0", // 30400 - // value: "0x0", // 2441406250 - // } - // ]; - - - // browser.request({ - // method: nameSpace+"_sendTransaction", - // params: params, - // }) - // .then((result) => { - // // The result varies by RPC method. - // // For example, this method returns a transaction hash hexadecimal string upon success. - // console.log(result); - // }) - // .catch((error) => { - // // If the request fails, the Promise rejects with an error. - // console.log(error); - // }); - } catch (error) { - console.log(error); - } - } else { - document.getElementById("executeButton").innerHTML = - "Please install Kaikas"; +async function connectMM() { await connect(window.ethereum); } +async function connectKK() { await connect(window.klaytn); } + +// https://docs.metamask.io/wallet/how-to/add-network/ +// EIP-3085 wallet_addEthereumChain +// EIP-3326 wallet_switchEthereumChain +async function switchNetwork(networkSpec) { + console.log("switching to", networkSpec); + try { + await provider.send("wallet_switchEthereumChain", [{ chainId: networkSpec.chainId }]); + } catch (e) { + await provider.send("wallet_addEthereumChain", [networkSpec]); } -} \ No newline at end of file +} +async function switchBaobab() { + await switchNetwork({ + chainId: "0x3e9", + chainName: "Klaytn Baobab", + nativeCurrency: { + name: "KLAY", + symbol: "KLAY", + decimals: 18, + }, + rpcUrls: ["https://public-en-baobab.klaytn.net"], + blockExplorerUrls: ["https://baobab.klaytnscope.com/"], + }); +} +async function switchLocal() { + await switchNetwork({ + chainId: "0x7a69", + chainName: "localhost 8545", + nativeCurrency: { + name: "KLAY", + symbol: "KLAY", + decimals: 18, + }, + rpcUrls: ["http://localhost:8545"], + blockExplorerUrls: ["http://localhost:4000"], + }); +} + +async function signMsg() { + const signer = provider.getSigner(); + const message = "Hello dapp"; + const signature = await signer.signMessage(message); + console.log("signature", signature); + $("#textSignature").html(signature); +} From f76bb27fb20bc52f36aa40b6899cbc9d3632e3ca Mon Sep 17 00:00:00 2001 From: Yunjong Jeong Date: Thu, 7 Dec 2023 00:47:11 +0900 Subject: [PATCH 09/33] ethers: Web3Provider and JsonRpcSigner skeleton --- ethers-ext/example/browser-html/main.js | 6 +- ethers-ext/src/provider.ts | 12 ++- ethers-ext/src/signer.ts | 98 +++++++++++++++++++------ 3 files changed, 90 insertions(+), 26 deletions(-) diff --git a/ethers-ext/example/browser-html/main.js b/ethers-ext/example/browser-html/main.js index 2034df536..687fc0096 100644 --- a/ethers-ext/example/browser-html/main.js +++ b/ethers-ext/example/browser-html/main.js @@ -6,7 +6,11 @@ async function connect(injectedProvider) { alert("Please install wallet"); return; } - provider = new ethers.providers.Web3Provider(injectedProvider); + if (0) { + provider = new ethers.providers.Web3Provider(injectedProvider); + } else { + provider = new ethers_ext.Web3Provider(injectedProvider); + } await provider.send("eth_requestAccounts", []); const accounts = await provider.listAccounts(); // internally eth_accounts diff --git a/ethers-ext/src/provider.ts b/ethers-ext/src/provider.ts index 4cc57b561..c7acbcbc4 100644 --- a/ethers-ext/src/provider.ts +++ b/ethers-ext/src/provider.ts @@ -1,11 +1,16 @@ import { Networkish } from "@ethersproject/networks"; -import { JsonRpcProvider as EthersJsonRpcProvider, Web3Provider as EthersWeb3Provider, JsonRpcSigner } from "@ethersproject/providers"; +import { + JsonRpcProvider as EthersJsonRpcProvider, + Web3Provider as EthersWeb3Provider, + JsonRpcSigner as EthersJsonRpcSigner } from "@ethersproject/providers"; import { ConnectionInfo } from "@ethersproject/web"; import { asyncOpenApi, AsyncNamespaceApi } from "@klaytn/js-ext-core"; // @ts-ignore: package @klaytn/web3rpc has no .d.ts file. import { AdminApi, DebugApi, GovernanceApi, KlayApi, NetApi, PersonalApi, TxpoolApi } from "@klaytn/web3rpc"; +import { JsonRpcSigner as KlaytnJsonRpcSigner } from "./signer"; + /* eslint-disable no-multi-spaces */ export class JsonRpcProvider extends EthersJsonRpcProvider { // API methods other than eth_ namespaces @@ -36,8 +41,7 @@ export class JsonRpcProvider extends EthersJsonRpcProvider { const _constructorGuard = {}; export class Web3Provider extends EthersWeb3Provider { - override getSigner(addressOrIndex?: string | number | undefined): JsonRpcSigner { - console.log("it's me") - return new JsonRpcSigner(_constructorGuard, this, addressOrIndex); + override getSigner(addressOrIndex?: string | number | undefined): EthersJsonRpcSigner { + return new KlaytnJsonRpcSigner(this, addressOrIndex); } } \ No newline at end of file diff --git a/ethers-ext/src/signer.ts b/ethers-ext/src/signer.ts index 779e78927..290eceecd 100644 --- a/ethers-ext/src/signer.ts +++ b/ethers-ext/src/signer.ts @@ -1,11 +1,15 @@ import { Provider, TransactionRequest, TransactionResponse } from "@ethersproject/abstract-provider"; -import { ExternallyOwnedAccount } from "@ethersproject/abstract-signer"; -import { JsonRpcProvider as EthersJsonRpcProvider, JsonRpcSigner as EthersJsonRpcSigner } from "@ethersproject/providers"; +import { Signer as EthersSigner, ExternallyOwnedAccount, TypedDataDomain, TypedDataField } from "@ethersproject/abstract-signer"; +import { + JsonRpcProvider as EthersJsonRpcProvider, + JsonRpcSigner as EthersJsonRpcSigner, +} from "@ethersproject/providers"; import { Wallet as EthersWallet } from "@ethersproject/wallet"; +import { defineReadOnly } from "@ethersproject/properties"; import { poll } from "@ethersproject/web"; import { KlaytnTxFactory, HexStr, isFeePayerSigTxType, parseTransaction } from "@klaytn/js-ext-core"; import { BigNumber } from "ethers"; -import { Bytes, BytesLike, Deferrable, Logger, ProgressCallback, SigningKey, computeAddress, hexlify, keccak256, resolveProperties } from "ethers/lib/utils"; +import { Bytes, BytesLike, Deferrable, ProgressCallback, SigningKey, computeAddress, keccak256, resolveProperties, getAddress } from "ethers/lib/utils"; import _ from "lodash"; import { decryptKeystoreList, decryptKeystoreListSync } from "./keystore"; @@ -321,28 +325,80 @@ export class Wallet extends EthersWallet { } } -export class JsonRpcSigner extends EthersJsonRpcSigner { +// EthersJsonRpcSigner cannot be subclassed because of the constructorGuard. +// Instead, we re-create the class by copying the implementation. +export class JsonRpcSigner extends EthersSigner implements EthersJsonRpcSigner { + readonly provider: EthersJsonRpcProvider; + _index: number; + _address: string; - // TODO : implements all method + // Equivalent to EthersJsonRpcSigner.constructor, but without constructorGuard. + constructor(provider: EthersJsonRpcProvider, addressOrIndex?: string | number) { + super(); - // constructor(provider: JsonRpcApiProvider, address: string) { - // super(provider, address); - // } + this.provider = provider; - // override async populateTransaction(tx: TransactionRequest): Promise> { - // // @ts-ignore - // return await this.populateCall(tx); - // } + if (addressOrIndex == null) { + addressOrIndex = 0; + } + + if (typeof(addressOrIndex) === "string") { + this._address = getAddress(addressOrIndex); + this._index = null as unknown as number; + } else if (typeof(addressOrIndex) === "number") { + this._address = null as unknown as string; + this._index = addressOrIndex; + } else { + throw new Error(`invalid address or index '${addressOrIndex}'`); + } + } + + override async getAddress(): Promise { + return Promise.resolve(""); + } + + override connect(provider: Provider): EthersJsonRpcSigner { + throw new Error("cannot alter JSON-RPC Signer connection"); + } + + connectUnchecked(): EthersJsonRpcSigner { + return this; + } + + override async signMessage(message: string | Bytes): Promise { + return Promise.resolve(""); + } - // override async sendUncheckedTransaction(_tx: TransactionRequest): Promise { - // } + override checkTransaction(transaction: Deferrable): Deferrable { + return super.checkTransaction(transaction); + } + + override async populateTransaction(transaction: Deferrable): Promise { + return super.populateTransaction(transaction); + } - // override async sendTransaction(tx: TransactionRequest): Promise { - // } + override async signTransaction(transaction: Deferrable): Promise { + return Promise.resolve(""); + } - // override async signTransaction(_tx: TransactionRequest): Promise { - // } + override async sendTransaction(transaction: Deferrable): Promise { + return Promise.resolve({} as TransactionResponse); + } + + sendUncheckedTransaction(transaction: Deferrable): Promise { + return Promise.resolve(""); + } - // override async signMessage(_message: string | Uint8Array): Promise { - // } -} \ No newline at end of file + async _legacySignMessage(message: Bytes | string): Promise { + throw new Error("Legacy eth_sign not supported"); + } + + async _signTypedData(domain: TypedDataDomain, types: Record>, value: Record): Promise { + throw new Error("eth_signTypedData_v4 not supported"); + } + + async unlock(password: string): Promise { + const address = await this.getAddress(); + return this.provider.send("personal_unlockAccount", [ address.toLowerCase(), password, null ]); + } +} From 09e1abf7c66ae2ba5380a3fa3f56e9a0f4ea7a41 Mon Sep 17 00:00:00 2001 From: Nohyun Nehemiah Kwak Date: Fri, 8 Dec 2023 12:08:13 +0900 Subject: [PATCH 10/33] Test signMessage and sendLegacyTx --- ethers-ext/example/browser-html/main.js | 99 +++++++++++++++++++++++-- 1 file changed, 91 insertions(+), 8 deletions(-) diff --git a/ethers-ext/example/browser-html/main.js b/ethers-ext/example/browser-html/main.js index 687fc0096..2e68097b9 100644 --- a/ethers-ext/example/browser-html/main.js +++ b/ethers-ext/example/browser-html/main.js @@ -1,4 +1,6 @@ +var activeWallet = null; var provider = null; +var accounts = null; // https://docs.ethers.org/v5/getting-started/#getting-started--connecting async function connect(injectedProvider) { @@ -13,12 +15,22 @@ async function connect(injectedProvider) { } await provider.send("eth_requestAccounts", []); - const accounts = await provider.listAccounts(); // internally eth_accounts + accounts = await provider.listAccounts(); // internally eth_accounts console.log("accounts", accounts); $("#textAccounts").html(accounts); } -async function connectMM() { await connect(window.ethereum); } -async function connectKK() { await connect(window.klaytn); } +async function connectMM() { + activeWallet = "metamask"; + $("#textSignature").html(""); + $("#textTxhash").html(""); + await connect(window.ethereum); +} +async function connectKK() { + activeWallet = "kaikas"; + $("#textSignature").html(""); + $("#textTxhash").html(""); + await connect(window.klaytn); +} // https://docs.metamask.io/wallet/how-to/add-network/ // EIP-3085 wallet_addEthereumChain @@ -59,9 +71,80 @@ async function switchLocal() { } async function signMsg() { - const signer = provider.getSigner(); - const message = "Hello dapp"; - const signature = await signer.signMessage(message); - console.log("signature", signature); - $("#textSignature").html(signature); + // const signer = provider.getSigner(); + // const message = "Hello dapp"; + // const signature = await signer.signMessage(message); + // console.log("signature", signature); + // $("#textSignature").html(signature); + + if (activeWallet == "metamask") { + try { + const from = accounts[0]; + const msg = "0x61626364"; + const sign = await ethereum.request({ + method: 'personal_sign', + params: [msg, from], + }); + $("#textSignature").html(sign); + } catch (err) { + console.error(err); + $("#textSignature").html(`Error: ${err.message}`); + } + } + else if (activeWallet == "kaikas") { + try { + const from = accounts[0]; + const msg = "0x61626364"; + const sign = await klaytn.request({ + method: 'eth_sign', + params: [from, msg], + }); + $("#textSignature").html(sign); + } catch (err) { + console.error(err); + $("#textSignature").html(`Error: ${err.message}`); + } + } } + +async function sendLegacy() { + + if (activeWallet == "metamask") { + ethereum + .request({ + method: 'eth_sendTransaction', + // The following sends an EIP-1559 transaction. Legacy transactions are also supported. + params: [ + { + from: accounts[0], // The user's active address. + to: accounts[0], // same with sender for testing + value: 0, + }, + ], + }) + .then( function (txHash) { + console.log(txHash); + $("#textTxhash").html(txHash); + }) + .catch((error) => console.error(error)); + } + else if (activeWallet == "kaikas") { + klaytn + .request({ + method: 'eth_sendTransaction', + // The following sends an EIP-1559 transaction. Legacy transactions are also supported. + params: [ + { + from: accounts[0], // The user's active address. + to: accounts[0], // same with sender for testing + value: 0, + }, + ], + }) + .then( function (txHash) { + console.log(txHash); + $("#textTxhash").html(txHash); + }) + .catch((error) => console.error(error)); + } +} \ No newline at end of file From d05ede3a58ac2ad598f7b0dbecd3a27b39d92726 Mon Sep 17 00:00:00 2001 From: "ollie.j" Date: Fri, 8 Dec 2023 13:37:22 +0900 Subject: [PATCH 11/33] ethers: Fix browser-html signMsg --- ethers-ext/example/browser-html/index.html | 1 + ethers-ext/example/browser-html/main.js | 103 ++++++++++++++++----- 2 files changed, 83 insertions(+), 21 deletions(-) diff --git a/ethers-ext/example/browser-html/index.html b/ethers-ext/example/browser-html/index.html index 64ccf102c..3f594434d 100644 --- a/ethers-ext/example/browser-html/index.html +++ b/ethers-ext/example/browser-html/index.html @@ -20,6 +20,7 @@

accounts:

signature:

+

signer adddress recovered from signature:

txhash:

diff --git a/ethers-ext/example/browser-html/main.js b/ethers-ext/example/browser-html/main.js index 2e68097b9..bbf000e1a 100644 --- a/ethers-ext/example/browser-html/main.js +++ b/ethers-ext/example/browser-html/main.js @@ -1,4 +1,3 @@ -var activeWallet = null; var provider = null; var accounts = null; @@ -8,28 +7,28 @@ async function connect(injectedProvider) { alert("Please install wallet"); return; } - if (0) { + if (1) { + console.log("use ethers"); provider = new ethers.providers.Web3Provider(injectedProvider); } else { + console.log("use ethers-ext"); provider = new ethers_ext.Web3Provider(injectedProvider); } - + await provider.send("eth_requestAccounts", []); accounts = await provider.listAccounts(); // internally eth_accounts console.log("accounts", accounts); $("#textAccounts").html(accounts); } -async function connectMM() { - activeWallet = "metamask"; +async function connectMM() { $("#textSignature").html(""); $("#textTxhash").html(""); - await connect(window.ethereum); + await connect(window.ethereum); } -async function connectKK() { - activeWallet = "kaikas"; +async function connectKK() { $("#textSignature").html(""); $("#textTxhash").html(""); - await connect(window.klaytn); + await connect(window.klaytn); } // https://docs.metamask.io/wallet/how-to/add-network/ @@ -71,13 +70,52 @@ async function switchLocal() { } async function signMsg() { - // const signer = provider.getSigner(); - // const message = "Hello dapp"; - // const signature = await signer.signMessage(message); - // console.log("signature", signature); - // $("#textSignature").html(signature); + const isKaikas = provider.provider.isKaikas || false; - if (activeWallet == "metamask") { + const { hexlify, toUtf8Bytes, keccak256, concat } = ethers.utils; + + + try { + if (isKaikas) { + const signer = provider.getSigner(); + const message = "Hello dapp"; + const hexMessage = hexlify(toUtf8Bytes(message)); + + const signature = await provider.send("eth_sign", [await signer.getAddress(), hexMessage]); + console.log("signature", signature); + $("#textSignature").html(signature); + + // Similar to ethers.utils.hashMessage but uses Klaytn prefix + var digest = keccak256( + concat([ + toUtf8Bytes("\x19Klaytn Signed Message:\n"), + toUtf8Bytes(String(message.length)), + toUtf8Bytes(message), + ]) + ); + const recoveredAddress = ethers.utils.recoverAddress(digest, signature); + console.log("recoveredAddress", recoveredAddress); + $("#textRecoveredAddress").html(recoveredAddress); + } else { + const signer = provider.getSigner(); + const message = "Hello dapp"; + + const signature = await signer.signMessage(message); + console.log("signature", signature); + $("#textSignature").html(signature); + + const recoveredAddress = ethers.utils.verifyMessage(message, signature); + console.log("recoveredAddress", recoveredAddress); + $("#textRecoveredAddress").html(recoveredAddress); + } + } catch (err) { + console.error(err); + $("#textSignature").html(`Error: ${err.message}`); + } + +/* + + if (!currentInjectedProvider.isKaikas) { try { const from = accounts[0]; const msg = "0x61626364"; @@ -86,12 +124,18 @@ async function signMsg() { params: [msg, from], }); $("#textSignature").html(sign); + + const digest = ethers.utils.hashMessage("abcd"); + console.log(digest); + const rec = ethers.utils.recoverAddress(digest, sign); + console.log(rec); + } catch (err) { console.error(err); $("#textSignature").html(`Error: ${err.message}`); } } - else if (activeWallet == "kaikas") { + else if (currentInjectedProvider.isKaikas) { try { const from = accounts[0]; const msg = "0x61626364"; @@ -100,11 +144,28 @@ async function signMsg() { params: [from, msg], }); $("#textSignature").html(sign); + + var digest = ethers.utils.hashMessage("abcd"); // Ethereum prefix + var digest = ethers.utils.keccak256("0x61626364"); // no prefix + + var message = "abcd"; + var digest = ethers.utils.keccak256( // Klaytn prefix + ethers.utils.concat([ + ethers.utils.toUtf8Bytes("\x19Klaytn Signed Message:\n"), + ethers.utils.toUtf8Bytes(String(message.length)), + ethers.utils.toUtf8Bytes(message), + ]) + ) + console.log(digest); + const rec = ethers.utils.recoverAddress(digest, sign); + console.log(rec); + } catch (err) { console.error(err); $("#textSignature").html(`Error: ${err.message}`); } } + */ } async function sendLegacy() { @@ -122,8 +183,8 @@ async function sendLegacy() { }, ], }) - .then( function (txHash) { - console.log(txHash); + .then(function (txHash) { + console.log(txHash); $("#textTxhash").html(txHash); }) .catch((error) => console.error(error)); @@ -141,10 +202,10 @@ async function sendLegacy() { }, ], }) - .then( function (txHash) { - console.log(txHash); + .then(function (txHash) { + console.log(txHash); $("#textTxhash").html(txHash); }) .catch((error) => console.error(error)); } -} \ No newline at end of file +} From f466fb4978d40a7704daf55957abebb2540f5a48 Mon Sep 17 00:00:00 2001 From: "ollie.j" Date: Fri, 8 Dec 2023 13:40:31 +0900 Subject: [PATCH 12/33] ethers: Fix browser-html to use klay_recoverFromMessage --- ethers-ext/example/browser-html/main.js | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/ethers-ext/example/browser-html/main.js b/ethers-ext/example/browser-html/main.js index bbf000e1a..427536007 100644 --- a/ethers-ext/example/browser-html/main.js +++ b/ethers-ext/example/browser-html/main.js @@ -71,9 +71,7 @@ async function switchLocal() { async function signMsg() { const isKaikas = provider.provider.isKaikas || false; - - const { hexlify, toUtf8Bytes, keccak256, concat } = ethers.utils; - + const { hexlify, toUtf8Bytes } = ethers.utils; try { if (isKaikas) { @@ -85,15 +83,7 @@ async function signMsg() { console.log("signature", signature); $("#textSignature").html(signature); - // Similar to ethers.utils.hashMessage but uses Klaytn prefix - var digest = keccak256( - concat([ - toUtf8Bytes("\x19Klaytn Signed Message:\n"), - toUtf8Bytes(String(message.length)), - toUtf8Bytes(message), - ]) - ); - const recoveredAddress = ethers.utils.recoverAddress(digest, signature); + const recoveredAddress = await provider.send("klay_recoverFromMessage", [await signer.getAddress(), hexMessage, signature, "latest"]); console.log("recoveredAddress", recoveredAddress); $("#textRecoveredAddress").html(recoveredAddress); } else { From 7a1ade83f0606dc454008d3fbdfb95978788aaf1 Mon Sep 17 00:00:00 2001 From: "ollie.j" Date: Fri, 8 Dec 2023 13:48:51 +0900 Subject: [PATCH 13/33] ethers: Fix browser-html sendLegacy --- ethers-ext/example/browser-html/main.js | 110 ++++-------------------- 1 file changed, 18 insertions(+), 92 deletions(-) diff --git a/ethers-ext/example/browser-html/main.js b/ethers-ext/example/browser-html/main.js index 427536007..6a856b0d8 100644 --- a/ethers-ext/example/browser-html/main.js +++ b/ethers-ext/example/browser-html/main.js @@ -54,6 +54,10 @@ async function switchBaobab() { rpcUrls: ["https://public-en-baobab.klaytn.net"], blockExplorerUrls: ["https://baobab.klaytnscope.com/"], }); + + if (provider) { // re-connect after changing network. + await connect(provider.provider); + } } async function switchLocal() { await switchNetwork({ @@ -102,100 +106,22 @@ async function signMsg() { console.error(err); $("#textSignature").html(`Error: ${err.message}`); } - -/* - - if (!currentInjectedProvider.isKaikas) { - try { - const from = accounts[0]; - const msg = "0x61626364"; - const sign = await ethereum.request({ - method: 'personal_sign', - params: [msg, from], - }); - $("#textSignature").html(sign); - - const digest = ethers.utils.hashMessage("abcd"); - console.log(digest); - const rec = ethers.utils.recoverAddress(digest, sign); - console.log(rec); - - } catch (err) { - console.error(err); - $("#textSignature").html(`Error: ${err.message}`); - } - } - else if (currentInjectedProvider.isKaikas) { - try { - const from = accounts[0]; - const msg = "0x61626364"; - const sign = await klaytn.request({ - method: 'eth_sign', - params: [from, msg], - }); - $("#textSignature").html(sign); - - var digest = ethers.utils.hashMessage("abcd"); // Ethereum prefix - var digest = ethers.utils.keccak256("0x61626364"); // no prefix - - var message = "abcd"; - var digest = ethers.utils.keccak256( // Klaytn prefix - ethers.utils.concat([ - ethers.utils.toUtf8Bytes("\x19Klaytn Signed Message:\n"), - ethers.utils.toUtf8Bytes(String(message.length)), - ethers.utils.toUtf8Bytes(message), - ]) - ) - console.log(digest); - const rec = ethers.utils.recoverAddress(digest, sign); - console.log(rec); - - } catch (err) { - console.error(err); - $("#textSignature").html(`Error: ${err.message}`); - } - } - */ } async function sendLegacy() { - - if (activeWallet == "metamask") { - ethereum - .request({ - method: 'eth_sendTransaction', - // The following sends an EIP-1559 transaction. Legacy transactions are also supported. - params: [ - { - from: accounts[0], // The user's active address. - to: accounts[0], // same with sender for testing - value: 0, - }, - ], - }) - .then(function (txHash) { - console.log(txHash); - $("#textTxhash").html(txHash); - }) - .catch((error) => console.error(error)); - } - else if (activeWallet == "kaikas") { - klaytn - .request({ - method: 'eth_sendTransaction', - // The following sends an EIP-1559 transaction. Legacy transactions are also supported. - params: [ - { - from: accounts[0], // The user's active address. - to: accounts[0], // same with sender for testing - value: 0, - }, - ], - }) - .then(function (txHash) { - console.log(txHash); - $("#textTxhash").html(txHash); - }) - .catch((error) => console.error(error)); + try { + const signer = provider.getSigner(); + const address = await signer.getAddress(); + + const sentTx = await signer.sendTransaction({ + from: address, + to: address, + value: 0, + }); + console.log("sentTx", sentTx); + $("#textTxhash").html(sentTx.hash); + } catch (err) { + console.error(err); + $("#textTxhash").html(`Error: ${err.message}`); } } From dae22b8debf2056e035ceab8684c735f6375490a Mon Sep 17 00:00:00 2001 From: "ollie.j" Date: Fri, 8 Dec 2023 14:16:14 +0900 Subject: [PATCH 14/33] ethers: Implement JsonRpcSigner.signMessage --- ethers-ext/example/browser-html/main.js | 2 +- ethers-ext/src/signer.ts | 67 +++++++++++++++++++++---- 2 files changed, 57 insertions(+), 12 deletions(-) diff --git a/ethers-ext/example/browser-html/main.js b/ethers-ext/example/browser-html/main.js index 6a856b0d8..b5156d51d 100644 --- a/ethers-ext/example/browser-html/main.js +++ b/ethers-ext/example/browser-html/main.js @@ -7,7 +7,7 @@ async function connect(injectedProvider) { alert("Please install wallet"); return; } - if (1) { + if (0) { console.log("use ethers"); provider = new ethers.providers.Web3Provider(injectedProvider); } else { diff --git a/ethers-ext/src/signer.ts b/ethers-ext/src/signer.ts index 290eceecd..c8273dc3e 100644 --- a/ethers-ext/src/signer.ts +++ b/ethers-ext/src/signer.ts @@ -1,19 +1,39 @@ import { Provider, TransactionRequest, TransactionResponse } from "@ethersproject/abstract-provider"; -import { Signer as EthersSigner, ExternallyOwnedAccount, TypedDataDomain, TypedDataField } from "@ethersproject/abstract-signer"; +import { + Signer as EthersSigner, + ExternallyOwnedAccount, + TypedDataDomain, + TypedDataField, +} from "@ethersproject/abstract-signer"; import { JsonRpcProvider as EthersJsonRpcProvider, JsonRpcSigner as EthersJsonRpcSigner, } from "@ethersproject/providers"; import { Wallet as EthersWallet } from "@ethersproject/wallet"; -import { defineReadOnly } from "@ethersproject/properties"; import { poll } from "@ethersproject/web"; import { KlaytnTxFactory, HexStr, isFeePayerSigTxType, parseTransaction } from "@klaytn/js-ext-core"; import { BigNumber } from "ethers"; -import { Bytes, BytesLike, Deferrable, ProgressCallback, SigningKey, computeAddress, keccak256, resolveProperties, getAddress } from "ethers/lib/utils"; +import { + Bytes, + BytesLike, + Deferrable, + ProgressCallback, + SigningKey, + computeAddress, + hexlify, + keccak256, + resolveProperties, + getAddress, + toUtf8Bytes, +} from "ethers/lib/utils"; +import { Logger } from "@ethersproject/logger"; import _ from "lodash"; import { decryptKeystoreList, decryptKeystoreListSync } from "./keystore"; +// To use the same error format as ethers.js +const logger = new Logger("@klaytn/ethers-ext"); + // @ethersproject/abstract-signer/src.ts/index.ts:allowedTransactionKeys const ethersAllowedTransactionKeys: Array = [ "accessList", "ccipReadEnabled", "chainId", "customData", "data", "from", "gasLimit", "gasPrice", "maxFeePerGas", "maxPriorityFeePerGas", "nonce", "to", "type", "value", @@ -194,7 +214,7 @@ export class Wallet extends EthersWallet { } // @deprecated in favor of parseTransaction - decodeTxFromRLP(rlp :string): any { + decodeTxFromRLP(rlp: string): any { return parseTransaction(rlp); } @@ -290,7 +310,7 @@ export class Wallet extends EthersWallet { async _chainIdFromTx(tx: any): Promise { function extractFromSig(field: any[]): number | undefined { if (_.isArray(field) && field.length > 0 && - _.isArray(field[0]) && field[0].length == 3) { + _.isArray(field[0]) && field[0].length == 3) { const v = BigNumber.from(field[0][0]).toNumber(); return (v - 35) / 2; } @@ -342,10 +362,10 @@ export class JsonRpcSigner extends EthersSigner implements EthersJsonRpcSigner { addressOrIndex = 0; } - if (typeof(addressOrIndex) === "string") { + if (typeof (addressOrIndex) === "string") { this._address = getAddress(addressOrIndex); this._index = null as unknown as number; - } else if (typeof(addressOrIndex) === "number") { + } else if (typeof (addressOrIndex) === "number") { this._address = null as unknown as string; this._index = addressOrIndex; } else { @@ -354,7 +374,18 @@ export class JsonRpcSigner extends EthersSigner implements EthersJsonRpcSigner { } override async getAddress(): Promise { - return Promise.resolve(""); + if (this._address) { + return Promise.resolve(this._address); + } + + return this.provider.send("eth_accounts", []).then((accounts) => { + if (accounts.length <= this._index) { + logger.throwError("unknown account #" + this._index, Logger.errors.UNSUPPORTED_OPERATION, { + operation: "getAddress" + }); + } + return this.provider.formatter.address(accounts[this._index]) + }); } override connect(provider: Provider): EthersJsonRpcSigner { @@ -366,7 +397,21 @@ export class JsonRpcSigner extends EthersSigner implements EthersJsonRpcSigner { } override async signMessage(message: string | Bytes): Promise { - return Promise.resolve(""); + const data = ((typeof (message) === "string") ? toUtf8Bytes(message) : message); + const address = await this.getAddress(); + try { + return await this.provider.send("personal_sign", [hexlify(data), address.toLowerCase()]); + } catch (error) { + // @ts-ignore + if (typeof (error.message) === "string" && error.message.match(/user denied/i)) { + logger.throwError("user rejected signing", Logger.errors.ACTION_REJECTED, { + action: "signMessage", + from: address, + messageData: message + }); + } + throw error; + } } override checkTransaction(transaction: Deferrable): Deferrable { @@ -386,7 +431,7 @@ export class JsonRpcSigner extends EthersSigner implements EthersJsonRpcSigner { } sendUncheckedTransaction(transaction: Deferrable): Promise { - return Promise.resolve(""); + return Promise.resolve(""); } async _legacySignMessage(message: Bytes | string): Promise { @@ -399,6 +444,6 @@ export class JsonRpcSigner extends EthersSigner implements EthersJsonRpcSigner { async unlock(password: string): Promise { const address = await this.getAddress(); - return this.provider.send("personal_unlockAccount", [ address.toLowerCase(), password, null ]); + return this.provider.send("personal_unlockAccount", [address.toLowerCase(), password, null]); } } From f118520f91466394e701c6c3a24d310d6f085045 Mon Sep 17 00:00:00 2001 From: "ollie.j" Date: Fri, 8 Dec 2023 14:35:24 +0900 Subject: [PATCH 15/33] ethers: Add JsonRpcSigner.isKaikas --- ethers-ext/.eslintrc.js | 10 +++++++--- ethers-ext/src/provider.ts | 7 +++++-- ethers-ext/src/signer.ts | 15 +++++++++++++-- ethers-ext/test/provider.spec.ts | 1 + ethers-ext/test/signer.spec.ts | 1 - 5 files changed, 26 insertions(+), 8 deletions(-) diff --git a/ethers-ext/.eslintrc.js b/ethers-ext/.eslintrc.js index 5295cbe28..125fd64ed 100644 --- a/ethers-ext/.eslintrc.js +++ b/ethers-ext/.eslintrc.js @@ -95,11 +95,15 @@ module.exports = { } }, { // browser examples use browser globals - "filters": ["example/browser-html/*"], + "files": ["example/browser-html/*"], "rules": { "no-undef": "off", "no-unused-vars": "off", + "no-constant-condition": "off", } - } - ] + }, + ], + "ignorePatterns": [ + "example/browser-html/ethers-ext.bundle.js", + ], }; diff --git a/ethers-ext/src/provider.ts b/ethers-ext/src/provider.ts index c7acbcbc4..b90f93065 100644 --- a/ethers-ext/src/provider.ts +++ b/ethers-ext/src/provider.ts @@ -2,10 +2,10 @@ import { Networkish } from "@ethersproject/networks"; import { JsonRpcProvider as EthersJsonRpcProvider, Web3Provider as EthersWeb3Provider, + ExternalProvider as EthersExternalProvider, JsonRpcSigner as EthersJsonRpcSigner } from "@ethersproject/providers"; import { ConnectionInfo } from "@ethersproject/web"; import { asyncOpenApi, AsyncNamespaceApi } from "@klaytn/js-ext-core"; - // @ts-ignore: package @klaytn/web3rpc has no .d.ts file. import { AdminApi, DebugApi, GovernanceApi, KlayApi, NetApi, PersonalApi, TxpoolApi } from "@klaytn/web3rpc"; @@ -39,9 +39,12 @@ export class JsonRpcProvider extends EthersJsonRpcProvider { } } -const _constructorGuard = {}; export class Web3Provider extends EthersWeb3Provider { override getSigner(addressOrIndex?: string | number | undefined): EthersJsonRpcSigner { return new KlaytnJsonRpcSigner(this, addressOrIndex); } +} + +export interface ExternalProvider extends EthersExternalProvider { + isKaikas?: boolean; // Exists in window.klaytn that is injected by Kaikas } \ No newline at end of file diff --git a/ethers-ext/src/signer.ts b/ethers-ext/src/signer.ts index c8273dc3e..0f7beb5c4 100644 --- a/ethers-ext/src/signer.ts +++ b/ethers-ext/src/signer.ts @@ -5,7 +5,9 @@ import { TypedDataDomain, TypedDataField, } from "@ethersproject/abstract-signer"; +import { Logger } from "@ethersproject/logger"; import { + Web3Provider as EthersWeb3Provider, JsonRpcProvider as EthersJsonRpcProvider, JsonRpcSigner as EthersJsonRpcSigner, } from "@ethersproject/providers"; @@ -26,10 +28,10 @@ import { getAddress, toUtf8Bytes, } from "ethers/lib/utils"; -import { Logger } from "@ethersproject/logger"; import _ from "lodash"; import { decryptKeystoreList, decryptKeystoreListSync } from "./keystore"; +import { ExternalProvider as KlaytnExternalProvider } from "./provider"; // To use the same error format as ethers.js const logger = new Logger("@klaytn/ethers-ext"); @@ -373,6 +375,15 @@ export class JsonRpcSigner extends EthersSigner implements EthersJsonRpcSigner { } } + isKaikas(): boolean { + if (this.provider instanceof EthersWeb3Provider) { + // The EIP-1193 provider, usually injected as window.ethereum or window.klaytn. + const injectedProvider = this.provider.provider as KlaytnExternalProvider; + return injectedProvider.isKaikas === true; + } + return false; + } + override async getAddress(): Promise { if (this._address) { return Promise.resolve(this._address); @@ -384,7 +395,7 @@ export class JsonRpcSigner extends EthersSigner implements EthersJsonRpcSigner { operation: "getAddress" }); } - return this.provider.formatter.address(accounts[this._index]) + return this.provider.formatter.address(accounts[this._index]); }); } diff --git a/ethers-ext/test/provider.spec.ts b/ethers-ext/test/provider.spec.ts index f90482e41..d8c9747c1 100644 --- a/ethers-ext/test/provider.spec.ts +++ b/ethers-ext/test/provider.spec.ts @@ -1,4 +1,5 @@ import { assert } from "chai"; +import { describe } from "mocha"; import { MockKlaytnProvider } from "./mock_provider"; diff --git a/ethers-ext/test/signer.spec.ts b/ethers-ext/test/signer.spec.ts index 764acd6cb..8e3dac7a6 100644 --- a/ethers-ext/test/signer.spec.ts +++ b/ethers-ext/test/signer.spec.ts @@ -1,5 +1,4 @@ import { keccak256 } from "@ethersproject/keccak256"; -import { parseTransaction } from "@klaytn/js-ext-core"; import chai, { assert, expect } from "chai"; import chaiAsPromised from "chai-as-promised"; import { Wallet as EthersWallet } from "ethers"; From 2befa3ea323ae98492afe2b33714dc9ece96d514 Mon Sep 17 00:00:00 2001 From: "ollie.j" Date: Fri, 8 Dec 2023 18:07:59 +0900 Subject: [PATCH 16/33] ethers: Bump deps --- ethers-ext/package-lock.json | 1684 ++++++---------------------------- ethers-ext/package.json | 8 +- 2 files changed, 272 insertions(+), 1420 deletions(-) diff --git a/ethers-ext/package-lock.json b/ethers-ext/package-lock.json index 945dbc1fc..6713c0dba 100644 --- a/ethers-ext/package-lock.json +++ b/ethers-ext/package-lock.json @@ -9,13 +9,13 @@ "version": "0.9.7-beta", "license": "MIT", "dependencies": { - "@klaytn/js-ext-core": "^0.9.7-beta", - "@klaytn/web3rpc": "^0.9.7", + "@klaytn/js-ext-core": "^0.9.8-beta", + "@klaytn/web3rpc": "^0.9.8", "lodash": "^4.17.21" }, "devDependencies": { - "@klaytn/ethers-ext": "^0.9.7-beta", - "@types/chai": "^4.3.4", + "@klaytn/ethers-ext": "^0.9.8-beta", + "@types/chai": "^4.3.7", "@types/chai-as-promised": "^7.1.5", "@types/lodash": "^4.14.192", "@types/mocha": "^10.0.4", @@ -59,13 +59,13 @@ } }, "node_modules/@babel/cli": { - "version": "7.22.9", - "resolved": "https://registry.npmjs.org/@babel/cli/-/cli-7.22.9.tgz", - "integrity": "sha512-nb2O7AThqRo7/E53EGiuAkMaRbb7J5Qp3RvN+dmua1U+kydm0oznkhqbTEG15yk26G/C3yL6OdZjzgl+DMXVVA==", + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/cli/-/cli-7.23.4.tgz", + "integrity": "sha512-j3luA9xGKCXVyCa5R7lJvOMM+Kc2JEnAEIgz2ggtjQ/j5YUVgfsg/WsG95bbsgq7YLHuiCOzMnoSasuY16qiCw==", "dependencies": { "@jridgewell/trace-mapping": "^0.3.17", "commander": "^4.0.1", - "convert-source-map": "^1.1.0", + "convert-source-map": "^2.0.0", "fs-readdir-recursive": "^1.1.0", "glob": "^7.2.0", "make-dir": "^2.1.0", @@ -86,69 +86,128 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/cli/node_modules/@jridgewell/resolve-uri": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", - "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==", + "node_modules/@babel/cli/node_modules/@jridgewell/trace-mapping": { + "version": "0.3.20", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.20.tgz", + "integrity": "sha512-R8LcPeWZol2zR8mmH3JeKQ6QRCFb7XgUhV9ZlGhHLGyg4wpPiPZNQOOWhFZhxKw8u//yTbNGI42Bx/3paXEQ+Q==", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.23.5", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.23.5.tgz", + "integrity": "sha512-CgH3s1a96LipHCmSUmYFPwY7MNx8C3avkq7i4Wl3cfa662ldtUe4VM1TPXX70pfmrlWTb6jLqTYrZyT2ZTJBgA==", + "peer": true, + "dependencies": { + "@babel/highlight": "^7.23.4", + "chalk": "^2.4.2" + }, "engines": { - "node": ">=6.0.0" + "node": ">=6.9.0" } }, - "node_modules/@babel/cli/node_modules/@jridgewell/sourcemap-codec": { - "version": "1.4.14", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", - "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==" + "node_modules/@babel/code-frame/node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "peer": true, + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } }, - "node_modules/@babel/cli/node_modules/@jridgewell/trace-mapping": { - "version": "0.3.18", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.18.tgz", - "integrity": "sha512-w+niJYzMHdd7USdiH2U6869nqhD2nbfZXND5Yp93qIbEmnDNk7PD48o+YchRVpzMU7M6jVCbenTR7PA1FLQ9pA==", + "node_modules/@babel/code-frame/node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "peer": true, "dependencies": { - "@jridgewell/resolve-uri": "3.1.0", - "@jridgewell/sourcemap-codec": "1.4.14" + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" } }, - "node_modules/@babel/code-frame": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.5.tgz", - "integrity": "sha512-Xmwn266vad+6DAqEB2A6V/CcZVp62BbwVmcOJc2RPuwih1kw02TjQvWVWlcKGbBPd+8/0V5DEkOcizRGYsspYQ==", + "node_modules/@babel/code-frame/node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "peer": true, + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/@babel/code-frame/node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "peer": true + }, + "node_modules/@babel/code-frame/node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "peer": true, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/@babel/code-frame/node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "peer": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/code-frame/node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", "peer": true, "dependencies": { - "@babel/highlight": "^7.22.5" + "has-flag": "^3.0.0" }, "engines": { - "node": ">=6.9.0" + "node": ">=4" } }, "node_modules/@babel/compat-data": { - "version": "7.22.9", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.22.9.tgz", - "integrity": "sha512-5UamI7xkUcJ3i9qVDS+KFDEK8/7oJ55/sJMB1Ge7IEapr7KfdfV/HErR+koZwOfd+SgtFKOKRhRakdg++DcJpQ==", + "version": "7.23.5", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.23.5.tgz", + "integrity": "sha512-uU27kfDRlhfKl+w1U6vp16IuvSLtjAxdArVXPa9BvLkrr7CYIsxH5adpHObeAGY/41+syctUWOZ140a2Rvkgjw==", "peer": true, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/core": { - "version": "7.22.9", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.22.9.tgz", - "integrity": "sha512-G2EgeufBcYw27U4hhoIwFcgc1XU7TlXJ3mv04oOv1WCuo900U/anZSPzEqNjwdjgffkk2Gs0AN0dW1CKVLcG7w==", + "version": "7.23.5", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.23.5.tgz", + "integrity": "sha512-Cwc2XjUrG4ilcfOw4wBAK+enbdgwAcAJCfGUItPBKR7Mjw4aEfAFYrLxeRp4jWgtNIKn3n2AlBOfwwafl+42/g==", "peer": true, "dependencies": { "@ampproject/remapping": "^2.2.0", - "@babel/code-frame": "^7.22.5", - "@babel/generator": "^7.22.9", - "@babel/helper-compilation-targets": "^7.22.9", - "@babel/helper-module-transforms": "^7.22.9", - "@babel/helpers": "^7.22.6", - "@babel/parser": "^7.22.7", - "@babel/template": "^7.22.5", - "@babel/traverse": "^7.22.8", - "@babel/types": "^7.22.5", - "convert-source-map": "^1.7.0", + "@babel/code-frame": "^7.23.5", + "@babel/generator": "^7.23.5", + "@babel/helper-compilation-targets": "^7.22.15", + "@babel/helper-module-transforms": "^7.23.3", + "@babel/helpers": "^7.23.5", + "@babel/parser": "^7.23.5", + "@babel/template": "^7.22.15", + "@babel/traverse": "^7.23.5", + "@babel/types": "^7.23.5", + "convert-source-map": "^2.0.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", - "json5": "^2.2.2", + "json5": "^2.2.3", "semver": "^6.3.1" }, "engines": { @@ -160,12 +219,12 @@ } }, "node_modules/@babel/generator": { - "version": "7.22.9", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.22.9.tgz", - "integrity": "sha512-KtLMbmicyuK2Ak/FTCJVbDnkN1SlT8/kceFTiuDiiRUUSMnHMidxSCdG4ndkTOHHpoomWe/4xkvHkEOncwjYIw==", + "version": "7.23.5", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.23.5.tgz", + "integrity": "sha512-BPssCHrBD+0YrxviOa3QzpqwhNIXKEtOa2jQrm4FlmkC2apYgRnQcmPWiGZDlGxiNtltnUFolMe8497Esry+jA==", "peer": true, "dependencies": { - "@babel/types": "^7.22.5", + "@babel/types": "^7.23.5", "@jridgewell/gen-mapping": "^0.3.2", "@jridgewell/trace-mapping": "^0.3.17", "jsesc": "^2.5.1" @@ -174,67 +233,49 @@ "node": ">=6.9.0" } }, - "node_modules/@babel/generator/node_modules/@jridgewell/resolve-uri": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", - "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==", - "peer": true, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@babel/generator/node_modules/@jridgewell/sourcemap-codec": { - "version": "1.4.14", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", - "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==", - "peer": true - }, "node_modules/@babel/generator/node_modules/@jridgewell/trace-mapping": { - "version": "0.3.18", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.18.tgz", - "integrity": "sha512-w+niJYzMHdd7USdiH2U6869nqhD2nbfZXND5Yp93qIbEmnDNk7PD48o+YchRVpzMU7M6jVCbenTR7PA1FLQ9pA==", + "version": "0.3.20", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.20.tgz", + "integrity": "sha512-R8LcPeWZol2zR8mmH3JeKQ6QRCFb7XgUhV9ZlGhHLGyg4wpPiPZNQOOWhFZhxKw8u//yTbNGI42Bx/3paXEQ+Q==", "peer": true, "dependencies": { - "@jridgewell/resolve-uri": "3.1.0", - "@jridgewell/sourcemap-codec": "1.4.14" + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" } }, "node_modules/@babel/helper-compilation-targets": { - "version": "7.22.9", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.22.9.tgz", - "integrity": "sha512-7qYrNM6HjpnPHJbopxmb8hSPoZ0gsX8IvUS32JGVoy+pU9e5N0nLr1VjJoR6kA4d9dmGLxNYOjeB8sUDal2WMw==", + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.22.15.tgz", + "integrity": "sha512-y6EEzULok0Qvz8yyLkCvVX+02ic+By2UdOhylwUOvOn9dvYc9mKICJuuU1n1XBI02YWsNsnrY1kc6DVbjcXbtw==", "peer": true, "dependencies": { "@babel/compat-data": "^7.22.9", - "@babel/helper-validator-option": "^7.22.5", + "@babel/helper-validator-option": "^7.22.15", "browserslist": "^4.21.9", "lru-cache": "^5.1.1", "semver": "^6.3.1" }, "engines": { "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" } }, "node_modules/@babel/helper-environment-visitor": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.5.tgz", - "integrity": "sha512-XGmhECfVA/5sAt+H+xpSg0mfrHq6FzNr9Oxh7PSEBBRUb/mL7Kz3NICXb194rCqAEdxkhPT1a88teizAFyvk8Q==", + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz", + "integrity": "sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==", "peer": true, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-function-name": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.22.5.tgz", - "integrity": "sha512-wtHSq6jMRE3uF2otvfuD3DIvVhOsSNshQl0Qrd7qC9oQJzHvOL4qQXlQn2916+CXGywIjpGuIkoyZRRxHPiNQQ==", + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz", + "integrity": "sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==", "peer": true, "dependencies": { - "@babel/template": "^7.22.5", - "@babel/types": "^7.22.5" + "@babel/template": "^7.22.15", + "@babel/types": "^7.23.0" }, "engines": { "node": ">=6.9.0" @@ -253,28 +294,28 @@ } }, "node_modules/@babel/helper-module-imports": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.22.5.tgz", - "integrity": "sha512-8Dl6+HD/cKifutF5qGd/8ZJi84QeAKh+CEe1sBzz8UayBBGg1dAIJrdHOcOM5b2MpzWL2yuotJTtGjETq0qjXg==", + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.22.15.tgz", + "integrity": "sha512-0pYVBnDKZO2fnSPCrgM/6WMc7eS20Fbok+0r88fp+YtWVLZrp4CkafFGIp+W0VKw4a22sgebPT99y+FDNMdP4w==", "peer": true, "dependencies": { - "@babel/types": "^7.22.5" + "@babel/types": "^7.22.15" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-module-transforms": { - "version": "7.22.9", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.22.9.tgz", - "integrity": "sha512-t+WA2Xn5K+rTeGtC8jCsdAH52bjggG5TKRuRrAGNM/mjIbO4GxvlLMFOEz9wXY5I2XQ60PMFsAG2WIcG82dQMQ==", + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.23.3.tgz", + "integrity": "sha512-7bBs4ED9OmswdfDzpz4MpWgSrV7FXlc3zIagvLFjS5H+Mk7Snr21vQ6QwrsoCGMfNC4e4LQPdoULEt4ykz0SRQ==", "peer": true, "dependencies": { - "@babel/helper-environment-visitor": "^7.22.5", - "@babel/helper-module-imports": "^7.22.5", + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-module-imports": "^7.22.15", "@babel/helper-simple-access": "^7.22.5", "@babel/helper-split-export-declaration": "^7.22.6", - "@babel/helper-validator-identifier": "^7.22.5" + "@babel/helper-validator-identifier": "^7.22.20" }, "engines": { "node": ">=6.9.0" @@ -308,54 +349,54 @@ } }, "node_modules/@babel/helper-string-parser": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.22.5.tgz", - "integrity": "sha512-mM4COjgZox8U+JcXQwPijIZLElkgEpO5rsERVDJTc2qfCDfERyob6k5WegS14SX18IIjv+XD+GrqNumY5JRCDw==", + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.23.4.tgz", + "integrity": "sha512-803gmbQdqwdf4olxrX4AJyFBV/RTr3rSmOj0rKwesmzlfhYNDEs+/iOcznzpNWlJlIlTJC2QfPFcHB6DlzdVLQ==", "peer": true, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-validator-identifier": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.5.tgz", - "integrity": "sha512-aJXu+6lErq8ltp+JhkJUfk1MTGyuA4v7f3pA+BJ5HLfNC6nAQ0Cpi9uOquUj8Hehg0aUiHzWQbOVJGao6ztBAQ==", + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz", + "integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==", "peer": true, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-validator-option": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.22.5.tgz", - "integrity": "sha512-R3oB6xlIVKUnxNUxbmgq7pKjxpru24zlimpE8WK47fACIlM0II/Hm1RS8IaOI7NgCr6LNS+jl5l75m20npAziw==", + "version": "7.23.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.23.5.tgz", + "integrity": "sha512-85ttAOMLsr53VgXkTbkx8oA6YTfT4q7/HzXSLEYmjcSTJPMPQtvq1BD79Byep5xMUYbGRzEpDsjUf3dyp54IKw==", "peer": true, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helpers": { - "version": "7.22.6", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.22.6.tgz", - "integrity": "sha512-YjDs6y/fVOYFV8hAf1rxd1QvR9wJe1pDBZ2AREKq/SDayfPzgk0PBnVuTCE5X1acEpMMNOVUqoe+OwiZGJ+OaA==", + "version": "7.23.5", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.23.5.tgz", + "integrity": "sha512-oO7us8FzTEsG3U6ag9MfdF1iA/7Z6dz+MtFhifZk8C8o453rGJFFWUP1t+ULM9TUIAzC9uxXEiXjOiVMyd7QPg==", "peer": true, "dependencies": { - "@babel/template": "^7.22.5", - "@babel/traverse": "^7.22.6", - "@babel/types": "^7.22.5" + "@babel/template": "^7.22.15", + "@babel/traverse": "^7.23.5", + "@babel/types": "^7.23.5" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/highlight": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.5.tgz", - "integrity": "sha512-BSKlD1hgnedS5XRnGOljZawtag7H1yPfQp0tdNJCHoH6AZ+Pcm9VvkrK59/Yy593Ypg0zMxH2BxD1VPYUQ7UIw==", + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.23.4.tgz", + "integrity": "sha512-acGdbYSfp2WheJoJm/EBBBLh/ID8KDc64ISZ9DYtBmC8/Q204PZJLHyzeB5qMzJ5trcOkybd78M4x2KWsUq++A==", "peer": true, "dependencies": { - "@babel/helper-validator-identifier": "^7.22.5", - "chalk": "^2.0.0", + "@babel/helper-validator-identifier": "^7.22.20", + "chalk": "^2.4.2", "js-tokens": "^4.0.0" }, "engines": { @@ -434,9 +475,9 @@ } }, "node_modules/@babel/parser": { - "version": "7.22.7", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.22.7.tgz", - "integrity": "sha512-7NF8pOkHP5o2vpmGgNGcfAeCvOYhGLyA3Z4eBQkT1RJlWu47n63bCs93QfJ2hIAFCil7L5P2IWhs1oToVgrL0Q==", + "version": "7.23.5", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.5.tgz", + "integrity": "sha512-hOOqoiNXrmGdFbhgCzu6GiURxUgM27Xwd/aPuu8RfHEZPBzL1Z54okAHAQjXfcQNwvrlkAmAp4SlRTZ45vlthQ==", "peer": true, "bin": { "parser": "bin/babel-parser.js" @@ -446,33 +487,33 @@ } }, "node_modules/@babel/template": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.5.tgz", - "integrity": "sha512-X7yV7eiwAxdj9k94NEylvbVHLiVG1nvzCV2EAowhxLTwODV1jl9UzZ48leOC0sH7OnuHrIkllaBgneUykIcZaw==", + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.15.tgz", + "integrity": "sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==", "peer": true, "dependencies": { - "@babel/code-frame": "^7.22.5", - "@babel/parser": "^7.22.5", - "@babel/types": "^7.22.5" + "@babel/code-frame": "^7.22.13", + "@babel/parser": "^7.22.15", + "@babel/types": "^7.22.15" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/traverse": { - "version": "7.22.8", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.22.8.tgz", - "integrity": "sha512-y6LPR+wpM2I3qJrsheCTwhIinzkETbplIgPBbwvqPKc+uljeA5gP+3nP8irdYt1mjQaDnlIcG+dw8OjAco4GXw==", + "version": "7.23.5", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.5.tgz", + "integrity": "sha512-czx7Xy5a6sapWWRx61m1Ke1Ra4vczu1mCTtJam5zRTBOonfdJ+S/B6HYmGYu3fJtr8GGET3si6IhgWVBhJ/m8w==", "peer": true, "dependencies": { - "@babel/code-frame": "^7.22.5", - "@babel/generator": "^7.22.7", - "@babel/helper-environment-visitor": "^7.22.5", - "@babel/helper-function-name": "^7.22.5", + "@babel/code-frame": "^7.23.5", + "@babel/generator": "^7.23.5", + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-function-name": "^7.23.0", "@babel/helper-hoist-variables": "^7.22.5", "@babel/helper-split-export-declaration": "^7.22.6", - "@babel/parser": "^7.22.7", - "@babel/types": "^7.22.5", + "@babel/parser": "^7.23.5", + "@babel/types": "^7.23.5", "debug": "^4.1.0", "globals": "^11.1.0" }, @@ -481,13 +522,13 @@ } }, "node_modules/@babel/types": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.22.5.tgz", - "integrity": "sha512-zo3MIHGOkPOfoRXitsgHLjEXmlDaD/5KU1Uzuc9GNiZPhSqVxVRtxuPaSBZDsYZ9qV88AjtMtWW7ww98loJ9KA==", + "version": "7.23.5", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.5.tgz", + "integrity": "sha512-ON5kSOJwVO6xXVRTvOI0eOnWe7VdUcIpsovGo9U/Br4Ie4UVFQTboO2cYnDhAGU6Fp+UxSiT+pMft0SMHfuq6w==", "peer": true, "dependencies": { - "@babel/helper-string-parser": "^7.22.5", - "@babel/helper-validator-identifier": "^7.22.5", + "@babel/helper-string-parser": "^7.23.4", + "@babel/helper-validator-identifier": "^7.22.20", "to-fast-properties": "^2.0.0" }, "engines": { @@ -498,6 +539,7 @@ "version": "1.6.0", "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.6.0.tgz", "integrity": "sha512-Ir+AOibqzrIsL6ajt3Rz3LskB7OiMVHqltZmspbW/TJuTVuyOMirVqAkjfY6JISiLHgyNqicAC8AyHHGzNd/dA==", + "dev": true, "engines": { "node": ">=0.1.90" } @@ -518,6 +560,7 @@ "version": "2.0.3", "resolved": "https://registry.npmjs.org/@dabh/diagnostics/-/diagnostics-2.0.3.tgz", "integrity": "sha512-hrlQOIi7hAfzsMqlGSFyVucrx38O+j6wiGOf//H2ecvIEqYN4ADBSS2iLMh5UFyDunCNniUIPk/q3riFv45xRA==", + "dev": true, "dependencies": { "colorspace": "1.1.x", "enabled": "2.0.x", @@ -1425,39 +1468,40 @@ } }, "node_modules/@klaytn/ethers-ext": { - "version": "0.9.7-beta", - "resolved": "https://registry.npmjs.org/@klaytn/ethers-ext/-/ethers-ext-0.9.7-beta.tgz", - "integrity": "sha512-qZ2cjmw0VX1eNfPeaZbEJz1fLeICeKhKIAUINz3xJqAiMd4jSYrHv4VEoNZ1iz08DJI15vVsHMXWmByTsotzXg==", + "version": "0.9.8-beta", + "resolved": "https://registry.npmjs.org/@klaytn/ethers-ext/-/ethers-ext-0.9.8-beta.tgz", + "integrity": "sha512-963ED7xc+5Pb2VpvNpxJAeSFzVXc7T5K3zZUA4kA6Dt8NB3EsEH6ap5hscqNVoIxkbIElZgbmUEkgrRAzeVJbw==", "dev": true, "dependencies": { - "@klaytn/ethers-ext": "^0.9.3-beta", - "@klaytn/web3rpc": "^0.9.0", - "bn.js": "^5.2.1", - "eth-lib": "^0.1.29", - "lodash": "^4.17.21", - "uuid": "^9.0.1" + "@klaytn/js-ext-core": "^0.9.7-beta", + "@klaytn/web3rpc": "^0.9.7", + "lodash": "^4.17.21" }, "peerDependencies": { "ethers": "^5.7.2" } }, - "node_modules/@klaytn/ethers-ext/node_modules/@klaytn/ethers-ext": { - "version": "0.9.3-beta", - "resolved": "https://registry.npmjs.org/@klaytn/ethers-ext/-/ethers-ext-0.9.3-beta.tgz", - "integrity": "sha512-As3iP/KhxG6+EVbnEln4QtF5A/M5HI7uGFzbFXFSQCd4LpQlLovQcI31fjaD9tgCw4DA4agAqHNcnBPBnX6j6A==", + "node_modules/@klaytn/ethers-ext/node_modules/@klaytn/js-ext-core": { + "version": "0.9.7-beta", + "resolved": "https://registry.npmjs.org/@klaytn/js-ext-core/-/js-ext-core-0.9.7-beta.tgz", + "integrity": "sha512-dgoO8zPuPA3LQRdUic9VW2c1UIjRpnP8BbKxEWjmrjmZ6GF0rYCqIu1onV7qvq0O8dDCKg7/bGDC4rpBnhFlxQ==", "dev": true, "dependencies": { - "@klaytn/web3rpc": "^0.9.0", + "@ethersproject/address": "^5.7.0", + "@ethersproject/bignumber": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/rlp": "^5.7.0", + "@ethersproject/transactions": "^5.7.0", + "@ethersproject/units": "^5.7.0", + "build": "^0.1.4", + "elliptic": "^6.5.4", "lodash": "^4.17.21" - }, - "peerDependencies": { - "ethers": "^5.7.2" } }, "node_modules/@klaytn/js-ext-core": { - "version": "0.9.7-beta", - "resolved": "https://registry.npmjs.org/@klaytn/js-ext-core/-/js-ext-core-0.9.7-beta.tgz", - "integrity": "sha512-dgoO8zPuPA3LQRdUic9VW2c1UIjRpnP8BbKxEWjmrjmZ6GF0rYCqIu1onV7qvq0O8dDCKg7/bGDC4rpBnhFlxQ==", + "version": "0.9.8-beta", + "resolved": "https://registry.npmjs.org/@klaytn/js-ext-core/-/js-ext-core-0.9.8-beta.tgz", + "integrity": "sha512-DtkNocCL7faKvbUquiQCV2Bnyp5sa6ye3BP0zHvmDHJfVbNjgbVZiN2xqK6HDt+WBskf9KFKAgJo9LSiSfLVQw==", "dependencies": { "@ethersproject/address": "^5.7.0", "@ethersproject/bignumber": "^5.7.0", @@ -1465,15 +1509,14 @@ "@ethersproject/rlp": "^5.7.0", "@ethersproject/transactions": "^5.7.0", "@ethersproject/units": "^5.7.0", - "build": "^0.1.4", "elliptic": "^6.5.4", "lodash": "^4.17.21" } }, "node_modules/@klaytn/web3rpc": { - "version": "0.9.7", - "resolved": "https://registry.npmjs.org/@klaytn/web3rpc/-/web3rpc-0.9.7.tgz", - "integrity": "sha512-D/ZTjaQY6oF65DNJu8evaOLPoCioCDiy9uqkIPOi1gwLmYNEMqFhy9NbtPPjkXFyKfj1fAHzgByyrWmNd7GyBA==", + "version": "0.9.8", + "resolved": "https://registry.npmjs.org/@klaytn/web3rpc/-/web3rpc-0.9.8.tgz", + "integrity": "sha512-KJXukas+FOmDCHj03AgnoMK0YTtwbHhilZnv8pmmM4f17OoSVwqx4vfAuiRMnaFa+D5i0SGmhUkMhXVDba0Zcg==", "dependencies": { "@babel/cli": "^7.0.0", "superagent": "^5.3.0" @@ -1545,9 +1588,9 @@ "dev": true }, "node_modules/@types/chai": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.3.4.tgz", - "integrity": "sha512-KnRanxnpfpjUTqTCXslZSEdLfXExwgNxYPdiO2WGUj8+HDjFi8R3k5RVKPeSCzLjCcshCAtVO2QBbVuAV4kTnw==", + "version": "4.3.11", + "resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.3.11.tgz", + "integrity": "sha512-qQR1dr2rGIHYlJulmr8Ioq3De0Le9E4MJ5AiaeAETJJpndT1uUNHsGFK3L/UIu+rbkQSdj8J/w2bCsBZc/Y5fQ==", "dev": true }, "node_modules/@types/chai-as-promised": { @@ -1624,7 +1667,8 @@ "node_modules/@types/triple-beam": { "version": "1.3.5", "resolved": "https://registry.npmjs.org/@types/triple-beam/-/triple-beam-1.3.5.tgz", - "integrity": "sha512-6WaYesThRMCl19iryMYP7/x2OVgCtbIVflDGFpWnb9irXI3UjYE4AzmYuiUKY1AJstGijoY+MgUszMgRxIYTYw==" + "integrity": "sha512-6WaYesThRMCl19iryMYP7/x2OVgCtbIVflDGFpWnb9irXI3UjYE4AzmYuiUKY1AJstGijoY+MgUszMgRxIYTYw==", + "dev": true }, "node_modules/@typescript-eslint/eslint-plugin": { "version": "6.1.0", @@ -2118,19 +2162,6 @@ "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==", "dev": true }, - "node_modules/accepts": { - "version": "1.3.8", - "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", - "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", - "dev": true, - "dependencies": { - "mime-types": "~2.1.34", - "negotiator": "0.6.3" - }, - "engines": { - "node": ">= 0.6" - } - }, "node_modules/acorn": { "version": "8.10.0", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.10.0.tgz", @@ -2272,12 +2303,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/array-flatten": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", - "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==", - "dev": true - }, "node_modules/array-includes": { "version": "3.1.6", "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.6.tgz", @@ -2362,24 +2387,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/asn1": { - "version": "0.2.6", - "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.6.tgz", - "integrity": "sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ==", - "dev": true, - "dependencies": { - "safer-buffer": "~2.1.0" - } - }, - "node_modules/assert-plus": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", - "integrity": "sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw==", - "dev": true, - "engines": { - "node": ">=0.8" - } - }, "node_modules/assertion-error": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", @@ -2392,12 +2399,7 @@ "node_modules/async": { "version": "3.2.5", "resolved": "https://registry.npmjs.org/async/-/async-3.2.5.tgz", - "integrity": "sha512-baNZyqaaLhyLVKm/DlvdW051MSgO6b8eVfIezl9E5PqWxFgzLm/wQntEW4zOytVburDEr0JlALEpdOFwvErLsg==" - }, - "node_modules/async-limiter": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.1.tgz", - "integrity": "sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ==", + "integrity": "sha512-baNZyqaaLhyLVKm/DlvdW051MSgO6b8eVfIezl9E5PqWxFgzLm/wQntEW4zOytVburDEr0JlALEpdOFwvErLsg==", "dev": true }, "node_modules/asynckit": { @@ -2417,35 +2419,11 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/aws-sign2": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", - "integrity": "sha512-08kcGqnYf/YmjoRhfxyu+CLxBjUtHLXLXX/vUfx9l2LYzG3c1m61nrpyFUZI6zeS+Li/wWMMidD9KgrqtGq3mA==", - "dev": true, - "engines": { - "node": "*" - } - }, - "node_modules/aws4": { - "version": "1.12.0", - "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.12.0.tgz", - "integrity": "sha512-NmWvPnx0F1SfrQbYwOi7OeaNGokp9XhzNioJ/CSBs8Qa4vxug81mhJEAVZwxXuBmYB5KDRfMq/F3RR0BIU7sWg==", - "dev": true - }, "node_modules/balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" }, - "node_modules/bcrypt-pbkdf": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", - "integrity": "sha512-qeFIXtP4MSoi6NLqO12WfqARWWuCKi2Rn/9hJLEmtB5yTNr9DqFWkJRCf2qShWzPeAMRnOgCrq0sg/KLv5ES9w==", - "dev": true, - "dependencies": { - "tweetnacl": "^0.14.3" - } - }, "node_modules/bech32": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/bech32/-/bech32-1.1.4.tgz", @@ -2466,60 +2444,6 @@ "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.1.tgz", "integrity": "sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ==" }, - "node_modules/body-parser": { - "version": "1.20.2", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.2.tgz", - "integrity": "sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA==", - "dev": true, - "dependencies": { - "bytes": "3.1.2", - "content-type": "~1.0.5", - "debug": "2.6.9", - "depd": "2.0.0", - "destroy": "1.2.0", - "http-errors": "2.0.0", - "iconv-lite": "0.4.24", - "on-finished": "2.4.1", - "qs": "6.11.0", - "raw-body": "2.5.2", - "type-is": "~1.6.18", - "unpipe": "1.0.0" - }, - "engines": { - "node": ">= 0.8", - "npm": "1.2.8000 || >= 1.4.16" - } - }, - "node_modules/body-parser/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/body-parser/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "dev": true - }, - "node_modules/body-parser/node_modules/qs": { - "version": "6.11.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", - "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", - "dev": true, - "dependencies": { - "side-channel": "^1.0.4" - }, - "engines": { - "node": ">=0.6" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/brace-expansion": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", @@ -2589,16 +2513,11 @@ "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", "dev": true }, - "node_modules/buffer-to-arraybuffer": { - "version": "0.0.5", - "resolved": "https://registry.npmjs.org/buffer-to-arraybuffer/-/buffer-to-arraybuffer-0.0.5.tgz", - "integrity": "sha512-3dthu5CYiVB1DEJp61FtApNnNndTckcqe4pFcLdvHtrpG+kcyekCJKg4MRiDcFW7A6AODnXB9U4dwQiCW5kzJQ==", - "dev": true - }, "node_modules/build": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/build/-/build-0.1.4.tgz", "integrity": "sha512-KwbDJ/zrsU8KZRRMfoURG14cKIAStUlS8D5jBDvtrZbwO5FEkYqc3oB8HIhRiyD64A48w1lc+sOmQ+mmBw5U/Q==", + "dev": true, "dependencies": { "cssmin": "0.3.x", "jsmin": "1.x", @@ -2615,15 +2534,6 @@ "node": ">v0.4.12" } }, - "node_modules/bytes": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", - "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", - "dev": true, - "engines": { - "node": ">= 0.8" - } - }, "node_modules/call-bind": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", @@ -2676,12 +2586,6 @@ } ] }, - "node_modules/caseless": { - "version": "0.12.0", - "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", - "integrity": "sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw==", - "dev": true - }, "node_modules/chai": { "version": "4.3.7", "resolved": "https://registry.npmjs.org/chai/-/chai-4.3.7.tgz", @@ -2814,6 +2718,7 @@ "version": "3.2.1", "resolved": "https://registry.npmjs.org/color/-/color-3.2.1.tgz", "integrity": "sha512-aBl7dZI9ENN6fUGC7mWpMTPNHmWUSNan9tuWN6ahh5ZLNk9baLJOnSMlrQkHcrfFgz2/RigjUVAjdx36VcemKA==", + "dev": true, "dependencies": { "color-convert": "^1.9.3", "color-string": "^1.6.0" @@ -2834,12 +2739,14 @@ "node_modules/color-name": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true }, "node_modules/color-string": { "version": "1.9.1", "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.9.1.tgz", "integrity": "sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==", + "dev": true, "dependencies": { "color-name": "^1.0.0", "simple-swizzle": "^0.2.2" @@ -2849,6 +2756,7 @@ "version": "1.9.3", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, "dependencies": { "color-name": "1.1.3" } @@ -2856,7 +2764,8 @@ "node_modules/color/node_modules/color-name": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "dev": true }, "node_modules/colorette": { "version": "2.0.20", @@ -2868,6 +2777,7 @@ "version": "1.1.4", "resolved": "https://registry.npmjs.org/colorspace/-/colorspace-1.1.4.tgz", "integrity": "sha512-BgvKJiuVu1igBUF2kEjRCZXol6wiiGbY5ipL/oVPwm0BL9sIpMIzM8IK7vwuxIIzOXMV3Ey5w+vxhm0rR/TN8w==", + "dev": true, "dependencies": { "color": "^3.1.3", "text-hex": "1.0.x" @@ -2893,80 +2803,28 @@ } }, "node_modules/component-emitter": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz", - "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==" + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.1.tgz", + "integrity": "sha512-T0+barUSQRTUQASh8bx02dl+DhF54GtIDY13Y3m9oWTklKbb3Wv974meRpeZ3lp1JpLVECWWNHC4vaG2XHXouQ==", + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } }, "node_modules/concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==" }, - "node_modules/content-disposition": { - "version": "0.5.4", - "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", - "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", - "dev": true, - "dependencies": { - "safe-buffer": "5.2.1" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/content-type": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", - "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", - "dev": true, - "engines": { - "node": ">= 0.6" - } - }, "node_modules/convert-source-map": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", - "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==" - }, - "node_modules/cookie": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz", - "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==", - "dev": true, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/cookie-signature": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", - "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==", - "dev": true + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==" }, "node_modules/cookiejar": { "version": "2.1.4", "resolved": "https://registry.npmjs.org/cookiejar/-/cookiejar-2.1.4.tgz", "integrity": "sha512-LDx6oHrK+PhzLKJU9j5S7/Y3jM/mUHvD/DeI1WQmJn652iPC5Y4TBzC9l+5OMOXlyTTA+SmVUPm0HQUwpD5Jqw==" }, - "node_modules/core-util-is": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", - "integrity": "sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ==", - "dev": true - }, - "node_modules/cors": { - "version": "2.8.5", - "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz", - "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==", - "dev": true, - "dependencies": { - "object-assign": "^4", - "vary": "^1" - }, - "engines": { - "node": ">= 0.10" - } - }, "node_modules/create-require": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", @@ -2991,6 +2849,7 @@ "version": "0.3.2", "resolved": "https://registry.npmjs.org/cssmin/-/cssmin-0.3.2.tgz", "integrity": "sha512-bynxGIAJ8ybrnFobjsQotIjA8HFDDgPwbeUWNXXXfR+B4f9kkxdcUyagJoQCSUOfMV+ZZ6bMn8bvbozlCzUGwQ==", + "dev": true, "bin": { "cssmin": "bin/cssmin" } @@ -3001,18 +2860,6 @@ "integrity": "sha512-yFk/2idb8OHPKkbAL8QaOaqENNoMhIaSHZerk3oQsECwkObkCpJyjYwCe+OHiq6UEdhe1m8ZGARRRO3ljFjlKg==", "dev": true }, - "node_modules/dashdash": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", - "integrity": "sha512-jRFi8UDGo6j+odZiEpjazZaWqEal3w/basFjQHQEwVtZJGDpxbH1MeYluwCS8Xq5wmLJooDlMgvVarmWfGM44g==", - "dev": true, - "dependencies": { - "assert-plus": "^1.0.0" - }, - "engines": { - "node": ">=0.10" - } - }, "node_modules/debug": { "version": "4.3.4", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", @@ -3046,27 +2893,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/decode-uri-component": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.2.tgz", - "integrity": "sha512-FqUYQ+8o158GyGTrMFJms9qh3CqTKvAqgqsTnkLI8sKu0028orqBhxNMFkFen0zGyg6epACD32pjVk58ngIErQ==", - "dev": true, - "engines": { - "node": ">=0.10" - } - }, - "node_modules/decompress-response": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-3.3.0.tgz", - "integrity": "sha512-BzRPQuY1ip+qDonAOz42gRm/pg9F768C+npV/4JOsxRC2sq+Rlk+Q4ZCAsOhnIaMrgarILY+RMUIvMmmX1qAEA==", - "dev": true, - "dependencies": { - "mimic-response": "^1.0.0" - }, - "engines": { - "node": ">=4" - } - }, "node_modules/deep-eql": { "version": "4.1.3", "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-4.1.3.tgz", @@ -3109,25 +2935,6 @@ "node": ">=0.4.0" } }, - "node_modules/depd": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", - "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", - "dev": true, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/destroy": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", - "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", - "dev": true, - "engines": { - "node": ">= 0.8", - "npm": "1.2.8000 || >= 1.4.16" - } - }, "node_modules/diff": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", @@ -3161,28 +2968,6 @@ "node": ">=6.0.0" } }, - "node_modules/dom-walk": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/dom-walk/-/dom-walk-0.1.2.tgz", - "integrity": "sha512-6QvTW9mrGeIegrFXdtQi9pk7O/nSK6lSdXW2eqUspN5LWD7UTji2Fqw5V2YLjBpHEoU9Xl/eUWNpDeZvoyOv2w==", - "dev": true - }, - "node_modules/ecc-jsbn": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", - "integrity": "sha512-eh9O+hwRHNbG4BLTjEl3nw044CkGm5X6LoaCf7LPp7UU8Qrt47JYNi6nPX8xjW97TKGKm1ouctg0QSpZe9qrnw==", - "dev": true, - "dependencies": { - "jsbn": "~0.1.0", - "safer-buffer": "^2.1.0" - } - }, - "node_modules/ee-first": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", - "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", - "dev": true - }, "node_modules/electron-to-chromium": { "version": "1.4.468", "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.468.tgz", @@ -3216,16 +3001,8 @@ "node_modules/enabled": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/enabled/-/enabled-2.0.0.tgz", - "integrity": "sha512-AKrN98kuwOzMIdAizXGI86UFBoo26CL21UM763y1h/GMSJ4/OHU9k2YlsmBpyScFo/wbLzWQJBMCW4+IO3/+OQ==" - }, - "node_modules/encodeurl": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", - "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", - "dev": true, - "engines": { - "node": ">= 0.8" - } + "integrity": "sha512-AKrN98kuwOzMIdAizXGI86UFBoo26CL21UM763y1h/GMSJ4/OHU9k2YlsmBpyScFo/wbLzWQJBMCW4+IO3/+OQ==", + "dev": true }, "node_modules/enhanced-resolve": { "version": "5.15.0", @@ -3359,12 +3136,6 @@ "node": ">=6" } }, - "node_modules/escape-html": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", - "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", - "dev": true - }, "node_modules/escape-string-regexp": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", @@ -3685,52 +3456,6 @@ "node": ">=0.10.0" } }, - "node_modules/etag": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", - "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", - "dev": true, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/eth-lib": { - "version": "0.1.29", - "resolved": "https://registry.npmjs.org/eth-lib/-/eth-lib-0.1.29.tgz", - "integrity": "sha512-bfttrr3/7gG4E02HoWTDUcDDslN003OlOoBxk9virpAZQ1ja/jDgwkWB8QfJF7ojuEowrqy+lzp9VcJG7/k5bQ==", - "dev": true, - "dependencies": { - "bn.js": "^4.11.6", - "elliptic": "^6.4.0", - "nano-json-stream-parser": "^0.1.2", - "servify": "^0.1.12", - "ws": "^3.0.0", - "xhr-request-promise": "^0.1.2" - } - }, - "node_modules/eth-lib/node_modules/bn.js": { - "version": "4.12.0", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", - "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==", - "dev": true - }, - "node_modules/eth-lib/node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true - }, - "node_modules/eth-lib/node_modules/ws": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/ws/-/ws-3.3.3.tgz", - "integrity": "sha512-nnWLa/NwZSt4KQJu51MYlCcSQ5g7INpOrOMt4XV8j4dqTXdmlUmSHQ8/oLC069ckre0fRsgfvsKwbTdtKLCDkA==", - "dev": true, - "dependencies": { - "async-limiter": "~1.0.0", - "safe-buffer": "~5.1.0", - "ultron": "~1.1.0" - } - }, "node_modules/ethers": { "version": "5.7.2", "resolved": "https://registry.npmjs.org/ethers/-/ethers-5.7.2.tgz", @@ -3788,132 +3513,6 @@ "node": ">=0.8.x" } }, - "node_modules/express": { - "version": "4.18.2", - "resolved": "https://registry.npmjs.org/express/-/express-4.18.2.tgz", - "integrity": "sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ==", - "dev": true, - "dependencies": { - "accepts": "~1.3.8", - "array-flatten": "1.1.1", - "body-parser": "1.20.1", - "content-disposition": "0.5.4", - "content-type": "~1.0.4", - "cookie": "0.5.0", - "cookie-signature": "1.0.6", - "debug": "2.6.9", - "depd": "2.0.0", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "etag": "~1.8.1", - "finalhandler": "1.2.0", - "fresh": "0.5.2", - "http-errors": "2.0.0", - "merge-descriptors": "1.0.1", - "methods": "~1.1.2", - "on-finished": "2.4.1", - "parseurl": "~1.3.3", - "path-to-regexp": "0.1.7", - "proxy-addr": "~2.0.7", - "qs": "6.11.0", - "range-parser": "~1.2.1", - "safe-buffer": "5.2.1", - "send": "0.18.0", - "serve-static": "1.15.0", - "setprototypeof": "1.2.0", - "statuses": "2.0.1", - "type-is": "~1.6.18", - "utils-merge": "1.0.1", - "vary": "~1.1.2" - }, - "engines": { - "node": ">= 0.10.0" - } - }, - "node_modules/express/node_modules/body-parser": { - "version": "1.20.1", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.1.tgz", - "integrity": "sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw==", - "dev": true, - "dependencies": { - "bytes": "3.1.2", - "content-type": "~1.0.4", - "debug": "2.6.9", - "depd": "2.0.0", - "destroy": "1.2.0", - "http-errors": "2.0.0", - "iconv-lite": "0.4.24", - "on-finished": "2.4.1", - "qs": "6.11.0", - "raw-body": "2.5.1", - "type-is": "~1.6.18", - "unpipe": "1.0.0" - }, - "engines": { - "node": ">= 0.8", - "npm": "1.2.8000 || >= 1.4.16" - } - }, - "node_modules/express/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/express/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "dev": true - }, - "node_modules/express/node_modules/qs": { - "version": "6.11.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", - "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", - "dev": true, - "dependencies": { - "side-channel": "^1.0.4" - }, - "engines": { - "node": ">=0.6" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/express/node_modules/raw-body": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz", - "integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==", - "dev": true, - "dependencies": { - "bytes": "3.1.2", - "http-errors": "2.0.0", - "iconv-lite": "0.4.24", - "unpipe": "1.0.0" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/extend": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", - "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", - "dev": true - }, - "node_modules/extsprintf": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", - "integrity": "sha512-11Ndz7Nv+mvAC1j0ktTa7fAb0vLyGGX+rMHNBYQviQDGU0Hw7lhctJANqbPhu9nV9/izT/IntTgZ7Im/9LJs9g==", - "dev": true, - "engines": [ - "node >=0.6.0" - ] - }, "node_modules/fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", @@ -3974,7 +3573,8 @@ "node_modules/fecha": { "version": "4.2.3", "resolved": "https://registry.npmjs.org/fecha/-/fecha-4.2.3.tgz", - "integrity": "sha512-OP2IUU6HeYKJi3i0z4A19kHMQoLVs4Hc+DPqqxI2h/DPZHTm/vjsfC6P0b4jCMy14XizLBqvndQ+UilD7707Jw==" + "integrity": "sha512-OP2IUU6HeYKJi3i0z4A19kHMQoLVs4Hc+DPqqxI2h/DPZHTm/vjsfC6P0b4jCMy14XizLBqvndQ+UilD7707Jw==", + "dev": true }, "node_modules/file-entry-cache": { "version": "6.0.1", @@ -4000,39 +3600,6 @@ "node": ">=8" } }, - "node_modules/finalhandler": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", - "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==", - "dev": true, - "dependencies": { - "debug": "2.6.9", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "on-finished": "2.4.1", - "parseurl": "~1.3.3", - "statuses": "2.0.1", - "unpipe": "~1.0.0" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/finalhandler/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/finalhandler/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "dev": true - }, "node_modules/find-up": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", @@ -4080,7 +3647,8 @@ "node_modules/fn.name": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/fn.name/-/fn.name-1.1.0.tgz", - "integrity": "sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw==" + "integrity": "sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw==", + "dev": true }, "node_modules/for-each": { "version": "0.3.3", @@ -4091,15 +3659,6 @@ "is-callable": "^1.1.3" } }, - "node_modules/forever-agent": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", - "integrity": "sha512-j0KLYPhm6zeac4lz3oJ3o65qvgQCcPubiyotZrXqEaG4hNagNYO8qdlUrX5vwqv9ohqeT/Z3j6+yW067yWWdUw==", - "dev": true, - "engines": { - "node": "*" - } - }, "node_modules/form-data": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/form-data/-/form-data-3.0.1.tgz", @@ -4122,24 +3681,6 @@ "url": "https://ko-fi.com/tunnckoCore/commissions" } }, - "node_modules/forwarded": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", - "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", - "dev": true, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/fresh": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", - "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", - "dev": true, - "engines": { - "node": ">= 0.6" - } - }, "node_modules/fs-readdir-recursive": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/fs-readdir-recursive/-/fs-readdir-recursive-1.1.0.tgz", @@ -4215,9 +3756,9 @@ } }, "node_modules/get-func-name": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.0.tgz", - "integrity": "sha512-Hm0ixYtaSZ/V7C8FJrtZIuBBI+iSgL+1Aq82zSu8VQNB4S3Gk8e7Qs3VwBDJAhmRZcFqkl3tQu36g/Foh5I5ig==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.2.tgz", + "integrity": "sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ==", "dev": true, "engines": { "node": "*" @@ -4253,15 +3794,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/getpass": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", - "integrity": "sha512-0fzj9JxOLfJ+XGLhR8ze3unN0KZCgZwiSSDz168VERjK8Wl8kVSdcu2kspd4s4wtAa1y/qrVRiAA0WclVsu0ng==", - "dev": true, - "dependencies": { - "assert-plus": "^1.0.0" - } - }, "node_modules/glob": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", @@ -4319,16 +3851,6 @@ "node": "*" } }, - "node_modules/global": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/global/-/global-4.4.0.tgz", - "integrity": "sha512-wv/LAoHdRE3BeTGz53FAamhGlPLhlssK45usmGFThIi4XqnBmjKQ16u+RNbP7WvigRZDxUsM0J3gcQ5yicaL0w==", - "dev": true, - "dependencies": { - "min-document": "^2.19.0", - "process": "^0.11.10" - } - }, "node_modules/globals": { "version": "11.12.0", "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", @@ -4406,29 +3928,6 @@ "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", "dev": true }, - "node_modules/har-schema": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", - "integrity": "sha512-Oqluz6zhGX8cyRaTQlFMPw80bSJVG2x/cFb8ZPhUILGgHka9SsokCCOQgpveePerqidZOrT14ipqfJb7ILcW5Q==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/har-validator": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.5.tgz", - "integrity": "sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w==", - "deprecated": "this library is no longer supported", - "dev": true, - "dependencies": { - "ajv": "^6.12.3", - "har-schema": "^2.0.0" - }, - "engines": { - "node": ">=6" - } - }, "node_modules/has": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", @@ -4535,49 +4034,6 @@ "minimalistic-crypto-utils": "^1.0.1" } }, - "node_modules/http-errors": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", - "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", - "dev": true, - "dependencies": { - "depd": "2.0.0", - "inherits": "2.0.4", - "setprototypeof": "1.2.0", - "statuses": "2.0.1", - "toidentifier": "1.0.1" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/http-signature": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", - "integrity": "sha512-CAbnr6Rz4CYQkLYUtSNXxQPUH2gK8f3iWexVlsnMeD+GjlsQ0Xsy1cOX+mN3dtxYomRy21CiOzU8Uhw6OwncEQ==", - "dev": true, - "dependencies": { - "assert-plus": "^1.0.0", - "jsprim": "^1.2.2", - "sshpk": "^1.7.0" - }, - "engines": { - "node": ">=0.8", - "npm": ">=1.3.7" - } - }, - "node_modules/iconv-lite": { - "version": "0.4.24", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", - "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", - "dev": true, - "dependencies": { - "safer-buffer": ">= 2.1.2 < 3" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/ignore": { "version": "5.2.4", "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz", @@ -4668,15 +4124,6 @@ "node": ">=10.13.0" } }, - "node_modules/ipaddr.js": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", - "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", - "dev": true, - "engines": { - "node": ">= 0.10" - } - }, "node_modules/is-array-buffer": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.2.tgz", @@ -4694,7 +4141,8 @@ "node_modules/is-arrayish": { "version": "0.3.2", "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz", - "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==" + "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==", + "dev": true }, "node_modules/is-bigint": { "version": "1.0.4", @@ -4793,12 +4241,6 @@ "node": ">=8" } }, - "node_modules/is-function": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-function/-/is-function-1.0.2.tgz", - "integrity": "sha512-lw7DUp0aWXYg+CBCN+JKkcE0Q2RayZnSvnZBlwgxHBQhqt5pZNVy4Ri7H9GmmXkdu7LUthszM+Tor1u/2iBcpQ==", - "dev": true - }, "node_modules/is-glob": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", @@ -4909,6 +4351,7 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "dev": true, "engines": { "node": ">=8" }, @@ -4961,12 +4404,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-typedarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", - "integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==", - "dev": true - }, "node_modules/is-unicode-supported": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", @@ -5012,12 +4449,6 @@ "node": ">=0.10.0" } }, - "node_modules/isstream": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", - "integrity": "sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g==", - "dev": true - }, "node_modules/jest-worker": { "version": "27.5.1", "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz", @@ -5054,12 +4485,6 @@ "js-yaml": "bin/js-yaml.js" } }, - "node_modules/jsbn": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", - "integrity": "sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg==", - "dev": true - }, "node_modules/jsesc": { "version": "2.5.2", "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", @@ -5076,6 +4501,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/jsmin/-/jsmin-1.0.1.tgz", "integrity": "sha512-OPuL5X/bFKgVdMvEIX3hnpx3jbVpFCrEM8pKPXjFkZUqg521r41ijdyTz7vACOhW6o1neVlcLyd+wkbK5fNHRg==", + "dev": true, "bin": { "jsmin": "bin/jsmin" }, @@ -5089,12 +4515,6 @@ "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", "dev": true }, - "node_modules/json-schema": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz", - "integrity": "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==", - "dev": true - }, "node_modules/json-schema-traverse": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", @@ -5107,12 +4527,6 @@ "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", "dev": true }, - "node_modules/json-stringify-safe": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", - "integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==", - "dev": true - }, "node_modules/json5": { "version": "2.2.3", "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", @@ -5125,25 +4539,11 @@ "node": ">=6" } }, - "node_modules/jsprim": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.2.tgz", - "integrity": "sha512-P2bSOMAc/ciLz6DzgjVlGJP9+BrJWu5UDGK70C2iweC5QBIeFf0ZXRvGjEj2uYgrY2MkAAhsSWHDWlFtEroZWw==", - "dev": true, - "dependencies": { - "assert-plus": "1.0.0", - "extsprintf": "1.3.0", - "json-schema": "0.4.0", - "verror": "1.10.0" - }, - "engines": { - "node": ">=0.6.0" - } - }, "node_modules/jxLoader": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/jxLoader/-/jxLoader-0.1.1.tgz", "integrity": "sha512-ClEvAj3K68y8uKhub3RgTmcRPo5DfIWvtxqrKQdDPyZ1UVHIIKvVvjrAsJFSVL5wjv0rt5iH9SMCZ0XRKNzeUA==", + "dev": true, "dependencies": { "js-yaml": "0.3.x", "moo-server": "1.3.x", @@ -5158,6 +4558,7 @@ "version": "0.3.7", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-0.3.7.tgz", "integrity": "sha512-/7PsVDNP2tVe2Z1cF9kTEkjamIwz4aooDpRKmN1+g/9eePCgcxsv4QDvEbxO0EH+gdDD7MLyDoR6BASo3hH51g==", + "dev": true, "engines": { "node": "> 0.4.11" } @@ -5174,7 +4575,8 @@ "node_modules/kuler": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/kuler/-/kuler-2.0.0.tgz", - "integrity": "sha512-Xq9nH7KlWZmXAtodXDDRE7vs6DU1gTU8zYDHDiWLSip45Egwq3plLHzPn27NgvzL2r1LMPC1vdqh98sQxtqj4A==" + "integrity": "sha512-Xq9nH7KlWZmXAtodXDDRE7vs6DU1gTU8zYDHDiWLSip45Egwq3plLHzPn27NgvzL2r1LMPC1vdqh98sQxtqj4A==", + "dev": true }, "node_modules/levn": { "version": "0.4.1", @@ -5244,6 +4646,7 @@ "version": "2.6.0", "resolved": "https://registry.npmjs.org/logform/-/logform-2.6.0.tgz", "integrity": "sha512-1ulHeNPp6k/LD8H91o7VYFBng5i1BDE7HoKxVbZiGFidS1Rj65qcywLxX+pVfAPoQJEjRdvKcusKwOupHCVOVQ==", + "dev": true, "dependencies": { "@colors/colors": "1.6.0", "@types/triple-beam": "^1.3.2", @@ -5316,25 +4719,11 @@ "version": "1.0.12", "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.12.tgz", "integrity": "sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==", + "dev": true, "dependencies": { "tmpl": "1.0.5" } }, - "node_modules/media-typer": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", - "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", - "dev": true, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/merge-descriptors": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", - "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==", - "dev": true - }, "node_modules/merge-stream": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", @@ -5401,24 +4790,6 @@ "node": ">= 0.6" } }, - "node_modules/mimic-response": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz", - "integrity": "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/min-document": { - "version": "2.19.0", - "resolved": "https://registry.npmjs.org/min-document/-/min-document-2.19.0.tgz", - "integrity": "sha512-9Wy1B3m3f66bPPmU5hdA4DR4PB2OfDU/+GS3yAB7IQozE3tqXaVv2zOjgla7MEGSRv95+ILmOuvhLkOK6wJtCQ==", - "dev": true, - "dependencies": { - "dom-walk": "^0.1.0" - } - }, "node_modules/minimalistic-assert": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", @@ -5515,6 +4886,7 @@ "version": "1.3.0", "resolved": "https://registry.npmjs.org/moo-server/-/moo-server-1.3.0.tgz", "integrity": "sha512-9A8/eor2DXwpv1+a4pZAAydqLFVrWoKoO1fzdzqLUhYVXAO1Kgd1FR2gFZi7YdHzF0s4W8cDNwCfKJQrvLqxDw==", + "dev": true, "engines": { "node": ">v0.4.10" } @@ -5522,12 +4894,7 @@ "node_modules/ms": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" - }, - "node_modules/nano-json-stream-parser": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/nano-json-stream-parser/-/nano-json-stream-parser-0.1.2.tgz", - "integrity": "sha512-9MqxMH/BSJC7dnLsEMPyfN5Dvoo49IsPFYMcHw3Bcfc2kN0lpHRBSzlMSVx4HGyJ7s9B31CyBTVehWJoQ8Ctew==", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", "dev": true }, "node_modules/nanoid": { @@ -5554,15 +4921,6 @@ "integrity": "sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g==", "dev": true }, - "node_modules/negotiator": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", - "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", - "dev": true, - "engines": { - "node": ">= 0.6" - } - }, "node_modules/neo-async": { "version": "2.6.2", "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", @@ -5583,15 +4941,6 @@ "node": ">=0.10.0" } }, - "node_modules/oauth-sign": { - "version": "0.9.0", - "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", - "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==", - "dev": true, - "engines": { - "node": "*" - } - }, "node_modules/object-assign": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", @@ -5653,18 +5002,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/on-finished": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", - "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", - "dev": true, - "dependencies": { - "ee-first": "1.1.1" - }, - "engines": { - "node": ">= 0.8" - } - }, "node_modules/once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", @@ -5677,6 +5014,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/one-time/-/one-time-1.0.0.tgz", "integrity": "sha512-5DXOiRKwuSEcQ/l0kGCF6Q3jcADFv5tSmRaJck/OqkVFcOzutB134KRSfF0xDrL39MNnqxbHBbUUcjZIhTgb2g==", + "dev": true, "dependencies": { "fn.name": "1.x.x" } @@ -5749,21 +5087,6 @@ "node": ">=6" } }, - "node_modules/parse-headers": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/parse-headers/-/parse-headers-2.0.5.tgz", - "integrity": "sha512-ft3iAoLOB/MlwbNXgzy43SWGP6sQki2jQvAyBg/zDFAgr9bfNWZIUj42Kw2eJIl8kEi4PbgE6U1Zau/HwI75HA==", - "dev": true - }, - "node_modules/parseurl": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", - "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", - "dev": true, - "engines": { - "node": ">= 0.8" - } - }, "node_modules/path-exists": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", @@ -5796,12 +5119,6 @@ "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", "dev": true }, - "node_modules/path-to-regexp": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", - "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==", - "dev": true - }, "node_modules/path-type": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", @@ -5820,12 +5137,6 @@ "node": "*" } }, - "node_modules/performance-now": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", - "integrity": "sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==", - "dev": true - }, "node_modules/picocolors": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", @@ -5924,19 +5235,11 @@ "node": ">= 0.8.0" } }, - "node_modules/process": { - "version": "0.11.10", - "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", - "integrity": "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==", - "dev": true, - "engines": { - "node": ">= 0.6.0" - } - }, "node_modules/promised-io": { "version": "0.3.6", "resolved": "https://registry.npmjs.org/promised-io/-/promised-io-0.3.6.tgz", - "integrity": "sha512-bNwZusuNIW4m0SPR8jooSyndD35ggirHlxVl/UhIaZD/F0OBv9ebfc6tNmbpZts3QXHggkjIBH8lvtnzhtcz0A==" + "integrity": "sha512-bNwZusuNIW4m0SPR8jooSyndD35ggirHlxVl/UhIaZD/F0OBv9ebfc6tNmbpZts3QXHggkjIBH8lvtnzhtcz0A==", + "dev": true }, "node_modules/prop-types": { "version": "15.8.1", @@ -5949,25 +5252,6 @@ "react-is": "^16.13.1" } }, - "node_modules/proxy-addr": { - "version": "2.0.7", - "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", - "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", - "dev": true, - "dependencies": { - "forwarded": "0.2.0", - "ipaddr.js": "1.9.1" - }, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/psl": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz", - "integrity": "sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==", - "dev": true - }, "node_modules/punycode": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz", @@ -5991,20 +5275,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/query-string": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/query-string/-/query-string-5.1.1.tgz", - "integrity": "sha512-gjWOsm2SoGlgLEdAGt7a6slVOk9mGiXmPFMqrEhLQ68rhQuBnpfs3+EmlvqKyxnCo9/PPlF+9MtY02S1aFg+Jw==", - "dev": true, - "dependencies": { - "decode-uri-component": "^0.2.0", - "object-assign": "^4.1.0", - "strict-uri-encode": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/queue-microtask": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", @@ -6034,30 +5304,6 @@ "safe-buffer": "^5.1.0" } }, - "node_modules/range-parser": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", - "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", - "dev": true, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/raw-body": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz", - "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==", - "dev": true, - "dependencies": { - "bytes": "3.1.2", - "http-errors": "2.0.0", - "iconv-lite": "0.4.24", - "unpipe": "1.0.0" - }, - "engines": { - "node": ">= 0.8" - } - }, "node_modules/react": { "version": "17.0.2", "resolved": "https://registry.npmjs.org/react/-/react-17.0.2.tgz", @@ -6145,71 +5391,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/request": { - "version": "2.88.2", - "resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz", - "integrity": "sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==", - "deprecated": "request has been deprecated, see https://github.com/request/request/issues/3142", - "dev": true, - "dependencies": { - "aws-sign2": "~0.7.0", - "aws4": "^1.8.0", - "caseless": "~0.12.0", - "combined-stream": "~1.0.6", - "extend": "~3.0.2", - "forever-agent": "~0.6.1", - "form-data": "~2.3.2", - "har-validator": "~5.1.3", - "http-signature": "~1.2.0", - "is-typedarray": "~1.0.0", - "isstream": "~0.1.2", - "json-stringify-safe": "~5.0.1", - "mime-types": "~2.1.19", - "oauth-sign": "~0.9.0", - "performance-now": "^2.1.0", - "qs": "~6.5.2", - "safe-buffer": "^5.1.2", - "tough-cookie": "~2.5.0", - "tunnel-agent": "^0.6.0", - "uuid": "^3.3.2" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/request/node_modules/form-data": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", - "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", - "dev": true, - "dependencies": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.6", - "mime-types": "^2.1.12" - }, - "engines": { - "node": ">= 0.12" - } - }, - "node_modules/request/node_modules/qs": { - "version": "6.5.3", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.3.tgz", - "integrity": "sha512-qxXIEh4pCGfHICj1mAJQ2/2XVZkjCDTcEgfoSQxc/fYivUZxTkk7L3bDBJSoNrEzXI17oUO5Dp07ktqE5KzczA==", - "dev": true, - "engines": { - "node": ">=0.6" - } - }, - "node_modules/request/node_modules/uuid": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", - "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", - "deprecated": "Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details.", - "dev": true, - "bin": { - "uuid": "bin/uuid" - } - }, "node_modules/require-directory": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", @@ -6369,16 +5550,11 @@ "version": "2.4.3", "resolved": "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-2.4.3.tgz", "integrity": "sha512-e2bDA2WJT0wxseVd4lsDP4+3ONX6HpMXQa1ZhFQ7SU+GjvORCmShbCMltrtIDfkYhVHrOcPtj+KhmDBdPdZD1g==", + "dev": true, "engines": { "node": ">=10" } }, - "node_modules/safer-buffer": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", - "dev": true - }, "node_modules/scheduler": { "version": "0.20.2", "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.20.2.tgz", @@ -6421,57 +5597,6 @@ "semver": "bin/semver.js" } }, - "node_modules/send": { - "version": "0.18.0", - "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", - "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", - "dev": true, - "dependencies": { - "debug": "2.6.9", - "depd": "2.0.0", - "destroy": "1.2.0", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "etag": "~1.8.1", - "fresh": "0.5.2", - "http-errors": "2.0.0", - "mime": "1.6.0", - "ms": "2.1.3", - "on-finished": "2.4.1", - "range-parser": "~1.2.1", - "statuses": "2.0.1" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/send/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/send/node_modules/debug/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "dev": true - }, - "node_modules/send/node_modules/mime": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", - "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", - "dev": true, - "bin": { - "mime": "cli.js" - }, - "engines": { - "node": ">=4" - } - }, "node_modules/serialize-javascript": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz", @@ -6481,43 +5606,6 @@ "randombytes": "^2.1.0" } }, - "node_modules/serve-static": { - "version": "1.15.0", - "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz", - "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==", - "dev": true, - "dependencies": { - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "parseurl": "~1.3.3", - "send": "0.18.0" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/servify": { - "version": "0.1.12", - "resolved": "https://registry.npmjs.org/servify/-/servify-0.1.12.tgz", - "integrity": "sha512-/xE6GvsKKqyo1BAY+KxOWXcLpPsUUyji7Qg3bVD7hh1eRze5bR1uYiuDA/k3Gof1s9BTzQZEJK8sNcNGFIzeWw==", - "dev": true, - "dependencies": { - "body-parser": "^1.16.0", - "cors": "^2.8.1", - "express": "^4.14.0", - "request": "^2.79.0", - "xhr": "^2.3.3" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/setprototypeof": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", - "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", - "dev": true - }, "node_modules/shallow-clone": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz", @@ -6564,41 +5652,11 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/simple-concat": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz", - "integrity": "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/simple-get": { - "version": "2.8.2", - "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-2.8.2.tgz", - "integrity": "sha512-Ijd/rV5o+mSBBs4F/x9oDPtTx9Zb6X9brmnXvMW4J7IR15ngi9q5xxqWBKU744jTZiaXtxaPL7uHG6vtN8kUkw==", - "dev": true, - "dependencies": { - "decompress-response": "^3.3.0", - "once": "^1.3.1", - "simple-concat": "^1.0.0" - } - }, "node_modules/simple-swizzle": { "version": "0.2.2", "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz", "integrity": "sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==", + "dev": true, "dependencies": { "is-arrayish": "^0.3.1" } @@ -6639,55 +5697,13 @@ "node": ">=0.10.0" } }, - "node_modules/sshpk": { - "version": "1.18.0", - "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.18.0.tgz", - "integrity": "sha512-2p2KJZTSqQ/I3+HX42EpYOa2l3f8Erv8MWKsy2I9uf4wA7yFIkXRffYdsx86y6z4vHtV8u7g+pPlr8/4ouAxsQ==", - "dev": true, - "dependencies": { - "asn1": "~0.2.3", - "assert-plus": "^1.0.0", - "bcrypt-pbkdf": "^1.0.0", - "dashdash": "^1.12.0", - "ecc-jsbn": "~0.1.1", - "getpass": "^0.1.1", - "jsbn": "~0.1.0", - "safer-buffer": "^2.0.2", - "tweetnacl": "~0.14.0" - }, - "bin": { - "sshpk-conv": "bin/sshpk-conv", - "sshpk-sign": "bin/sshpk-sign", - "sshpk-verify": "bin/sshpk-verify" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/stack-trace": { "version": "0.0.10", "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz", "integrity": "sha512-KGzahc7puUKkzyMt+IqAep+TVNbKP+k2Lmwhub39m1AsTSkaDutx56aDCo+HLDzf/D26BIHTJWNiTG1KAJiQCg==", - "engines": { - "node": "*" - } - }, - "node_modules/statuses": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", - "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", - "dev": true, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/strict-uri-encode": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz", - "integrity": "sha512-R3f198pcvnB+5IpnBlRkphuE9n46WyVl8I39W/ZUTZLz4nqSP/oLYUrcnJrw462Ds8he4YKMov2efsTIw1BDGQ==", "dev": true, "engines": { - "node": ">=0.10.0" + "node": "*" } }, "node_modules/string_decoder": { @@ -6958,7 +5974,8 @@ "node_modules/text-hex": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/text-hex/-/text-hex-1.0.0.tgz", - "integrity": "sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg==" + "integrity": "sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg==", + "dev": true }, "node_modules/text-table": { "version": "0.2.0", @@ -6966,19 +5983,11 @@ "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", "dev": true }, - "node_modules/timed-out": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/timed-out/-/timed-out-4.0.1.tgz", - "integrity": "sha512-G7r3AhovYtr5YKOWQkta8RKAPb+J9IsO4uVmzjl8AZwfhs8UcUwTiD6gcJYSgOtzyjvQKrKYn41syHbUWMkafA==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/timespan": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/timespan/-/timespan-2.3.0.tgz", "integrity": "sha512-0Jq9+58T2wbOyLth0EU+AUb6JMGCLaTWIykJFa7hyAybjVH9gpVMTfUAwo5fWAvtFt2Tjh/Elg8JtgNpnMnM8g==", + "dev": true, "engines": { "node": ">= 0.2.0" } @@ -6986,7 +5995,8 @@ "node_modules/tmpl": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", - "integrity": "sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==" + "integrity": "sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==", + "dev": true }, "node_modules/to-fast-properties": { "version": "2.0.0", @@ -7009,32 +6019,11 @@ "node": ">=8.0" } }, - "node_modules/toidentifier": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", - "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", - "dev": true, - "engines": { - "node": ">=0.6" - } - }, - "node_modules/tough-cookie": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz", - "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==", - "dev": true, - "dependencies": { - "psl": "^1.1.28", - "punycode": "^2.1.1" - }, - "engines": { - "node": ">=0.8" - } - }, "node_modules/triple-beam": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/triple-beam/-/triple-beam-1.4.1.tgz", "integrity": "sha512-aZbgViZrg1QNcG+LULa7nhZpJTZSLm/mXnHXnbAbjmN5aSa0y7V+wvv6+4WaBtpISJzThKy+PIPxc1Nq1EJ9mg==", + "dev": true, "engines": { "node": ">= 14.0.0" } @@ -7171,24 +6160,6 @@ "json5": "lib/cli.js" } }, - "node_modules/tunnel-agent": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", - "integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==", - "dev": true, - "dependencies": { - "safe-buffer": "^5.0.1" - }, - "engines": { - "node": "*" - } - }, - "node_modules/tweetnacl": { - "version": "0.14.5", - "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", - "integrity": "sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA==", - "dev": true - }, "node_modules/type-check": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", @@ -7222,19 +6193,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/type-is": { - "version": "1.6.18", - "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", - "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", - "dev": true, - "dependencies": { - "media-typer": "0.3.0", - "mime-types": "~2.1.24" - }, - "engines": { - "node": ">= 0.6" - } - }, "node_modules/typed-array-buffer": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.0.tgz", @@ -7317,16 +6275,11 @@ "version": "1.3.5", "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-1.3.5.tgz", "integrity": "sha512-YPX1DjKtom8l9XslmPFQnqWzTBkvI4N0pbkzLuPZZ4QTyig0uQqvZz9NgUdfEV+qccJzi7fVcGWdESvRIjWptQ==", + "dev": true, "bin": { "uglifyjs": "bin/uglifyjs" } }, - "node_modules/ultron": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/ultron/-/ultron-1.1.1.tgz", - "integrity": "sha512-UIEXBNeYmKptWH6z8ZnqTeS8fV74zG0/eRU9VGkpzz+LIJNs8W/zM/L+7ctCkRrgbNnnR0xxw4bKOr0cW0N0Og==", - "dev": true - }, "node_modules/unbox-primitive": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz", @@ -7342,15 +6295,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/unpipe": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", - "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", - "dev": true, - "engines": { - "node": ">= 0.8" - } - }, "node_modules/update-browserslist-db": { "version": "1.0.11", "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.11.tgz", @@ -7389,72 +6333,22 @@ "punycode": "^2.1.0" } }, - "node_modules/url-set-query": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/url-set-query/-/url-set-query-1.0.0.tgz", - "integrity": "sha512-3AChu4NiXquPfeckE5R5cGdiHCMWJx1dwCWOmWIL4KHAziJNOFIYJlpGFeKDvwLPHovZRCxK3cYlwzqI9Vp+Gg==", - "dev": true - }, "node_modules/util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" }, - "node_modules/utils-merge": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", - "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", - "dev": true, - "engines": { - "node": ">= 0.4.0" - } - }, - "node_modules/uuid": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz", - "integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==", - "dev": true, - "funding": [ - "https://github.com/sponsors/broofa", - "https://github.com/sponsors/ctavan" - ], - "bin": { - "uuid": "dist/bin/uuid" - } - }, "node_modules/v8-compile-cache-lib": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", "dev": true }, - "node_modules/vary": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", - "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", - "dev": true, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/verror": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", - "integrity": "sha512-ZZKSmDAEFOijERBLkmYfJ+vmk3w+7hOLYDNkRCuRuMJGEmqYNCNLyBBFwWKVMhfwaEF3WOd0Zlw86U/WC/+nYw==", - "dev": true, - "engines": [ - "node >=0.6.0" - ], - "dependencies": { - "assert-plus": "^1.0.0", - "core-util-is": "1.0.2", - "extsprintf": "^1.2.0" - } - }, "node_modules/walker": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz", "integrity": "sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==", + "dev": true, "dependencies": { "makeerror": "1.0.12" } @@ -7694,6 +6588,7 @@ "version": "3.11.0", "resolved": "https://registry.npmjs.org/winston/-/winston-3.11.0.tgz", "integrity": "sha512-L3yR6/MzZAOl0DsysUXHVjOwv8mKZ71TrA/41EIduGpOOV5LQVodqN+QdQ6BS6PJ/RdIshZhq84P/fStEZkk7g==", + "dev": true, "dependencies": { "@colors/colors": "^1.6.0", "@dabh/diagnostics": "^2.0.2", @@ -7715,6 +6610,7 @@ "version": "4.6.0", "resolved": "https://registry.npmjs.org/winston-transport/-/winston-transport-4.6.0.tgz", "integrity": "sha512-wbBA9PbPAHxKiygo7ub7BYRiKxms0tpfU2ljtWzb3SjRjv5yl6Ozuy/TkXf00HTAt+Uylo3gSkNwzc4ME0wiIg==", + "dev": true, "dependencies": { "logform": "^2.3.2", "readable-stream": "^3.6.0", @@ -7757,6 +6653,7 @@ "resolved": "https://registry.npmjs.org/wrench/-/wrench-1.3.9.tgz", "integrity": "sha512-srTJQmLTP5YtW+F5zDuqjMEZqLLr/eJOZfDI5ibfPfRMeDh3oBUefAscuH0q5wBKE339ptH/S/0D18ZkfOfmKQ==", "deprecated": "wrench.js is deprecated! You should check out fs-extra (https://github.com/jprichardson/node-fs-extra) for any operations you were using wrench for. Thanks for all the usage over the years.", + "dev": true, "engines": { "node": ">=0.1.97" } @@ -7782,51 +6679,6 @@ } } }, - "node_modules/xhr": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/xhr/-/xhr-2.6.0.tgz", - "integrity": "sha512-/eCGLb5rxjx5e3mF1A7s+pLlR6CGyqWN91fv1JgER5mVWg1MZmlhBvy9kjcsOdRk8RrIujotWyJamfyrp+WIcA==", - "dev": true, - "dependencies": { - "global": "~4.4.0", - "is-function": "^1.0.1", - "parse-headers": "^2.0.0", - "xtend": "^4.0.0" - } - }, - "node_modules/xhr-request": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/xhr-request/-/xhr-request-1.1.0.tgz", - "integrity": "sha512-Y7qzEaR3FDtL3fP30k9wO/e+FBnBByZeybKOhASsGP30NIkRAAkKD/sCnLvgEfAIEC1rcmK7YG8f4oEnIrrWzA==", - "dev": true, - "dependencies": { - "buffer-to-arraybuffer": "^0.0.5", - "object-assign": "^4.1.1", - "query-string": "^5.0.1", - "simple-get": "^2.7.0", - "timed-out": "^4.0.1", - "url-set-query": "^1.0.0", - "xhr": "^2.0.4" - } - }, - "node_modules/xhr-request-promise": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/xhr-request-promise/-/xhr-request-promise-0.1.3.tgz", - "integrity": "sha512-YUBytBsuwgitWtdRzXDDkWAXzhdGB8bYm0sSzMPZT7Z2MBjMSTHFsyCT1yCRATY+XC69DUrQraRAEgcoCRaIPg==", - "dev": true, - "dependencies": { - "xhr-request": "^1.1.0" - } - }, - "node_modules/xtend": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", - "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", - "dev": true, - "engines": { - "node": ">=0.4" - } - }, "node_modules/y18n": { "version": "5.0.8", "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", diff --git a/ethers-ext/package.json b/ethers-ext/package.json index 4fd55312c..f40210bf7 100644 --- a/ethers-ext/package.json +++ b/ethers-ext/package.json @@ -23,8 +23,8 @@ "ethers": "^5.7.2" }, "devDependencies": { - "@klaytn/ethers-ext": "^0.9.7-beta", - "@types/chai": "^4.3.4", + "@klaytn/ethers-ext": "^0.9.8-beta", + "@types/chai": "^4.3.7", "@types/chai-as-promised": "^7.1.5", "@types/lodash": "^4.14.192", "@types/mocha": "^10.0.4", @@ -42,8 +42,8 @@ "webpack-visualizer-plugin2": "^1.1.0" }, "dependencies": { - "@klaytn/js-ext-core": "^0.9.7-beta", - "@klaytn/web3rpc": "^0.9.7", + "@klaytn/js-ext-core": "^0.9.8-beta", + "@klaytn/web3rpc": "^0.9.8", "lodash": "^4.17.21" } } From 57909b4feb2c168f1de73ef9282580deeea82abf Mon Sep 17 00:00:00 2001 From: Nohyun Nehemiah Kwak Date: Tue, 12 Dec 2023 14:27:10 +0900 Subject: [PATCH 17/33] ethers: Add JsonRpcSigner.sendTransaction --- ethers-ext/example/browser-html/main.js | 32 +++++++--- ethers-ext/src/signer.ts | 79 ++++++++++++++++++++++++- 2 files changed, 100 insertions(+), 11 deletions(-) diff --git a/ethers-ext/example/browser-html/main.js b/ethers-ext/example/browser-html/main.js index b5156d51d..835a08af5 100644 --- a/ethers-ext/example/browser-html/main.js +++ b/ethers-ext/example/browser-html/main.js @@ -109,17 +109,31 @@ async function signMsg() { } async function sendLegacy() { + const isKaikas = provider.provider.isKaikas || false; + try { - const signer = provider.getSigner(); - const address = await signer.getAddress(); + if (isKaikas) { + const signer = provider.getSigner(); + const address = await signer.getAddress(); - const sentTx = await signer.sendTransaction({ - from: address, - to: address, - value: 0, - }); - console.log("sentTx", sentTx); - $("#textTxhash").html(sentTx.hash); + const sentTx = await signer.sendTransaction({ + from: address, + to: address, + value: 0, + }); + console.log("sentTx", sentTx); + $("#textTxhash").html(sentTx.hash); + } else { + const signer = provider.getSigner(); + const address = await signer.getAddress(); + + const sentTx = await signer.sendTransaction({ + to: address, + value: 0, + }); + console.log("sentTx", sentTx); + $("#textTxhash").html(sentTx.hash); + } } catch (err) { console.error(err); $("#textTxhash").html(`Error: ${err.message}`); diff --git a/ethers-ext/src/signer.ts b/ethers-ext/src/signer.ts index 0f7beb5c4..188e323a4 100644 --- a/ethers-ext/src/signer.ts +++ b/ethers-ext/src/signer.ts @@ -28,6 +28,7 @@ import { getAddress, toUtf8Bytes, } from "ethers/lib/utils"; +import { shallowCopy } from "@ethersproject/properties"; import _ from "lodash"; import { decryptKeystoreList, decryptKeystoreListSync } from "./keystore"; @@ -438,11 +439,83 @@ export class JsonRpcSigner extends EthersSigner implements EthersJsonRpcSigner { } override async sendTransaction(transaction: Deferrable): Promise { - return Promise.resolve({} as TransactionResponse); + // This cannot be mined any earlier than any recent block + const blockNumber = await this.provider._getInternalBlockNumber(100 + 2 * this.provider.pollingInterval); + + // Send the transaction + const hash = await this.sendUncheckedTransaction(transaction); + + try { + // Unfortunately, JSON-RPC only provides and opaque transaction hash + // for a response, and we need the actual transaction, so we poll + // for it; it should show up very quickly + return await poll(async () => { + const tx = await this.provider.getTransaction(hash); + if (tx === null) { return undefined; } + return this.provider._wrapTransaction(tx, hash, blockNumber); + }, { oncePoll: this.provider }) as any; + } catch (error) { + (error).transactionHash = hash; + throw error; + } } sendUncheckedTransaction(transaction: Deferrable): Promise { - return Promise.resolve(""); + transaction = shallowCopy(transaction); + + const fromAddress = this.getAddress().then((address) => { + if (address) { address = address.toLowerCase(); } + return address; + }); + + // The JSON-RPC for eth_sendTransaction uses 90000 gas; if the user + // wishes to use this, it is easy to specify explicitly, otherwise + // we look it up for them. + if (transaction.gasLimit == null) { + const estimate = shallowCopy(transaction); + estimate.from = fromAddress; + transaction.gasLimit = this.provider.estimateGas(estimate); + } + + if (transaction.to != null) { + (transaction as any).to = Promise.resolve(transaction.to).then(async (to) => { + if (to == null) { return null; } + const address = await this.provider.resolveName(to); + if (address == null) { + logger.throwArgumentError("provided ENS name resolves to null", "tx.to", to); + } + return address; + }); + } + + return resolveProperties({ + tx: resolveProperties(transaction), + sender: fromAddress + }).then(({ tx, sender }) => { + + if (tx.from != null) { + if (tx.from.toLowerCase() !== sender) { + logger.throwArgumentError("from address mismatch", "transaction", transaction); + } + } else { + tx.from = sender; + } + + const hexTx = (this.provider.constructor).hexlifyTransaction(tx, { from: true }); + + return this.provider.send("eth_sendTransaction", [ hexTx ]).then((hash) => { + return hash; + }, (error) => { + if (typeof(error.message) === "string" && error.message.match(/user denied/i)) { + logger.throwError("user rejected transaction", Logger.errors.ACTION_REJECTED, { + action: "sendTransaction", + transaction: tx + }); + } + + //return checkError("sendTransaction", error, hexTx); + }); + }); } async _legacySignMessage(message: Bytes | string): Promise { @@ -458,3 +531,5 @@ export class JsonRpcSigner extends EthersSigner implements EthersJsonRpcSigner { return this.provider.send("personal_unlockAccount", [address.toLowerCase(), password, null]); } } + + From 48e688bdc60f2f7661438bacee7b70e0a855af06 Mon Sep 17 00:00:00 2001 From: Nohyun Nehemiah Kwak Date: Tue, 12 Dec 2023 14:53:41 +0900 Subject: [PATCH 18/33] ethers: Refactor JsonRpcSigner.sendTransaction --- ethers-ext/example/browser-html/main.js | 10 ++- ethers-ext/src/signer.ts | 114 ++++++++++-------------- 2 files changed, 53 insertions(+), 71 deletions(-) diff --git a/ethers-ext/example/browser-html/main.js b/ethers-ext/example/browser-html/main.js index 835a08af5..26cd52ebe 100644 --- a/ethers-ext/example/browser-html/main.js +++ b/ethers-ext/example/browser-html/main.js @@ -110,7 +110,7 @@ async function signMsg() { async function sendLegacy() { const isKaikas = provider.provider.isKaikas || false; - + try { if (isKaikas) { const signer = provider.getSigner(); @@ -122,7 +122,9 @@ async function sendLegacy() { value: 0, }); console.log("sentTx", sentTx); - $("#textTxhash").html(sentTx.hash); + const txhash = sentTx.hash; + const explorerUrl = "https://baobab.klaytnscope.com/tx/"; + $("#textTxhash").html(`${txhash}`); } else { const signer = provider.getSigner(); const address = await signer.getAddress(); @@ -132,7 +134,9 @@ async function sendLegacy() { value: 0, }); console.log("sentTx", sentTx); - $("#textTxhash").html(sentTx.hash); + const txhash = sentTx.hash; + const explorerUrl = "https://baobab.klaytnscope.com/tx/"; + $("#textTxhash").html(`${txhash}`); } } catch (err) { console.error(err); diff --git a/ethers-ext/src/signer.ts b/ethers-ext/src/signer.ts index 188e323a4..d33f70840 100644 --- a/ethers-ext/src/signer.ts +++ b/ethers-ext/src/signer.ts @@ -13,7 +13,7 @@ import { } from "@ethersproject/providers"; import { Wallet as EthersWallet } from "@ethersproject/wallet"; import { poll } from "@ethersproject/web"; -import { KlaytnTxFactory, HexStr, isFeePayerSigTxType, parseTransaction } from "@klaytn/js-ext-core"; +import { KlaytnTxFactory, HexStr, isFeePayerSigTxType, parseTransaction, getRpcTxObject } from "@klaytn/js-ext-core"; import { BigNumber } from "ethers"; import { Bytes, @@ -439,82 +439,60 @@ export class JsonRpcSigner extends EthersSigner implements EthersJsonRpcSigner { } override async sendTransaction(transaction: Deferrable): Promise { - // This cannot be mined any earlier than any recent block - const blockNumber = await this.provider._getInternalBlockNumber(100 + 2 * this.provider.pollingInterval); - // Send the transaction - const hash = await this.sendUncheckedTransaction(transaction); - - try { - // Unfortunately, JSON-RPC only provides and opaque transaction hash - // for a response, and we need the actual transaction, so we poll - // for it; it should show up very quickly - return await poll(async () => { - const tx = await this.provider.getTransaction(hash); - if (tx === null) { return undefined; } - return this.provider._wrapTransaction(tx, hash, blockNumber); - }, { oncePoll: this.provider }) as any; - } catch (error) { - (error).transactionHash = hash; - throw error; - } + const txhash = await this.sendUncheckedTransaction(transaction); + + // Retry until the transaction shows up in the txpool + // Using poll() like in the ethers.JsonRpcProvider.sendTransaction + // https://github.com/ethers-io/ethers.js/blob/v5.7/packages/providers/src.ts/json-rpc-provider.ts#L283 + const pollFunc = async () => { + const tx = await this.provider.getTransaction(txhash); + if (tx == null) { + return undefined; // retry + } else { + return tx; // success + } + }; + return poll(pollFunc) as Promise; } - sendUncheckedTransaction(transaction: Deferrable): Promise { - transaction = shallowCopy(transaction); - - const fromAddress = this.getAddress().then((address) => { - if (address) { address = address.toLowerCase(); } - return address; - }); + async sendUncheckedTransaction(transaction: Deferrable): Promise { + const tx = await getTransactionRequest(transaction); - // The JSON-RPC for eth_sendTransaction uses 90000 gas; if the user - // wishes to use this, it is easy to specify explicitly, otherwise - // we look it up for them. - if (transaction.gasLimit == null) { - const estimate = shallowCopy(transaction); - estimate.from = fromAddress; - transaction.gasLimit = this.provider.estimateGas(estimate); + if (!tx.from) { + tx.from = await this.getAddress(); } - if (transaction.to != null) { - (transaction as any).to = Promise.resolve(transaction.to).then(async (to) => { - if (to == null) { return null; } - const address = await this.provider.resolveName(to); - if (address == null) { - logger.throwArgumentError("provided ENS name resolves to null", "tx.to", to); - } - return address; - }); + if (!tx.gasLimit) { + tx.gasLimit = await this.provider.estimateGas(tx); + } + + if (tx.to) { + const toAddress = await this.provider.resolveName(tx.to); + if (toAddress == null) { + logger.throwArgumentError("provided ENS name resolves to null", "tx.to", tx.to); + } else { + tx.to = toAddress; + } + } + + const fromAddress = await this.getAddress(); + if (tx.from && tx.from.toLowerCase() != fromAddress.toLowerCase()) { + logger.throwArgumentError("from address mismatch", "transaction", transaction); } - return resolveProperties({ - tx: resolveProperties(transaction), - sender: fromAddress - }).then(({ tx, sender }) => { - - if (tx.from != null) { - if (tx.from.toLowerCase() !== sender) { - logger.throwArgumentError("from address mismatch", "transaction", transaction); - } - } else { - tx.from = sender; - } - - const hexTx = (this.provider.constructor).hexlifyTransaction(tx, { from: true }); - - return this.provider.send("eth_sendTransaction", [ hexTx ]).then((hash) => { - return hash; - }, (error) => { - if (typeof(error.message) === "string" && error.message.match(/user denied/i)) { - logger.throwError("user rejected transaction", Logger.errors.ACTION_REJECTED, { - action: "sendTransaction", - transaction: tx - }); - } - - //return checkError("sendTransaction", error, hexTx); + const rpcTx = getRpcTxObject(tx); + return this.provider.send("eth_sendTransaction", [rpcTx]).then((hash) => { + return hash; + }, (error) => { + if (typeof (error.message) === "string" && error.message.match(/user denied/i)) { + logger.throwError("user rejected transaction", Logger.errors.ACTION_REJECTED, { + action: "sendTransaction", + transaction: tx }); + } + + //return checkError("sendTransaction", error, hexTx); }); } From 51955c320089240a8b3dbed938a0be0848d0049f Mon Sep 17 00:00:00 2001 From: Nohyun Nehemiah Kwak Date: Tue, 12 Dec 2023 18:28:38 +0900 Subject: [PATCH 19/33] ethers: request VT to Kaikas --- ethers-ext/example/browser-html/main.js | 60 +++++++++++++++++++++++++ ethers-ext/src/signer.ts | 7 ++- 2 files changed, 65 insertions(+), 2 deletions(-) diff --git a/ethers-ext/example/browser-html/main.js b/ethers-ext/example/browser-html/main.js index 26cd52ebe..26879454f 100644 --- a/ethers-ext/example/browser-html/main.js +++ b/ethers-ext/example/browser-html/main.js @@ -143,3 +143,63 @@ async function sendLegacy() { $("#textTxhash").html(`Error: ${err.message}`); } } + +async function sendVT() { + const isKaikas = provider.provider.isKaikas || false; + if (!isKaikas) { + alert("not kaikas"); + return; + } + + try { + const signer = provider.getSigner(); + const address = await signer.getAddress(); + + signer.sendTransaction({ + type: 8, + from: address, + to: address, + value: 0, + }) + return; + let params = [ + { + type: "VALUE_TRANSFER", + from: address, + to: address, + gas: '0x76c0', // 30400 + value: '0x0', // 2441406250 + } + ]; + + window.klaytn + .request({ + method: 'klay_sendTransaction', + params:params, + }) + .then((result) => { + // The result varies by RPC method. + // For example, this method returns a transaction hash hexadecimal string upon success. + console.log(result); + }) + .catch((error) => { + // If the request fails, the Promise rejects with an error. + console.log(error); + }); + // const signer = provider.getSigner(); + // const address = await signer.getAddress(); + // const sentTx = await signer.sendTransaction({ + // from: address, + // to: address, + // value: 0, + // type: 8, + // }); + // console.log("sentTx", sentTx); + // const txhash = sentTx.hash; + // const explorerUrl = "https://baobab.klaytnscope.com/tx/"; + // $("#textTxhash").html(`${txhash}`); + } catch (err) { + console.error(err); + $("#textTxhash").html(`Error: ${err.message}`); + } +} \ No newline at end of file diff --git a/ethers-ext/src/signer.ts b/ethers-ext/src/signer.ts index d33f70840..1aef1f1a7 100644 --- a/ethers-ext/src/signer.ts +++ b/ethers-ext/src/signer.ts @@ -28,7 +28,7 @@ import { getAddress, toUtf8Bytes, } from "ethers/lib/utils"; -import { shallowCopy } from "@ethersproject/properties"; +import { TxType } from "@klaytn/js-ext-core"; import _ from "lodash"; import { decryptKeystoreList, decryptKeystoreListSync } from "./keystore"; @@ -482,7 +482,10 @@ export class JsonRpcSigner extends EthersSigner implements EthersJsonRpcSigner { } const rpcTx = getRpcTxObject(tx); - return this.provider.send("eth_sendTransaction", [rpcTx]).then((hash) => { + rpcTx.type = _.snakeCase(TxType[tx.type || 0]).toUpperCase() + console.log('sending', rpcTx); + + return this.provider.send("klay_sendTransaction", [rpcTx]).then((hash) => { return hash; }, (error) => { if (typeof (error.message) === "string" && error.message.match(/user denied/i)) { From efc67b9372e64371462abd39b6e95ff8a77e36c8 Mon Sep 17 00:00:00 2001 From: Nohyun Nehemiah Kwak Date: Wed, 13 Dec 2023 18:17:48 +0900 Subject: [PATCH 20/33] ethers: Separate logics in sendUncheckedTransaction --- ethers-ext/example/browser-html/main.js | 49 ++++++----------------- ethers-ext/src/signer.ts | 52 ++++++++++++++++++++++++- 2 files changed, 62 insertions(+), 39 deletions(-) diff --git a/ethers-ext/example/browser-html/main.js b/ethers-ext/example/browser-html/main.js index 26879454f..e4f38fdef 100644 --- a/ethers-ext/example/browser-html/main.js +++ b/ethers-ext/example/browser-html/main.js @@ -155,51 +155,24 @@ async function sendVT() { const signer = provider.getSigner(); const address = await signer.getAddress(); - signer.sendTransaction({ + const sentTx = await signer.sendTransaction({ type: 8, from: address, to: address, value: 0, }) - return; - let params = [ - { - type: "VALUE_TRANSFER", - from: address, - to: address, - gas: '0x76c0', // 30400 - value: '0x0', // 2441406250 - } - ]; - - window.klaytn - .request({ - method: 'klay_sendTransaction', - params:params, - }) - .then((result) => { - // The result varies by RPC method. - // For example, this method returns a transaction hash hexadecimal string upon success. - console.log(result); - }) - .catch((error) => { - // If the request fails, the Promise rejects with an error. - console.log(error); - }); - // const signer = provider.getSigner(); - // const address = await signer.getAddress(); - // const sentTx = await signer.sendTransaction({ - // from: address, - // to: address, - // value: 0, - // type: 8, - // }); - // console.log("sentTx", sentTx); - // const txhash = sentTx.hash; - // const explorerUrl = "https://baobab.klaytnscope.com/tx/"; - // $("#textTxhash").html(`${txhash}`); + + console.log("sentTx", sentTx); + const txhash = sentTx.hash; + const explorerUrl = "https://baobab.klaytnscope.com/tx/"; + $("#textTxhash").html(`${txhash}`); } catch (err) { console.error(err); $("#textTxhash").html(`Error: ${err.message}`); } +} + + +async function sendFVT() { + } \ No newline at end of file diff --git a/ethers-ext/src/signer.ts b/ethers-ext/src/signer.ts index 1aef1f1a7..eef355350 100644 --- a/ethers-ext/src/signer.ts +++ b/ethers-ext/src/signer.ts @@ -457,6 +457,15 @@ export class JsonRpcSigner extends EthersSigner implements EthersJsonRpcSigner { } async sendUncheckedTransaction(transaction: Deferrable): Promise { + const type = transaction.type; + if ( this.isKaikas() ) { + return this.sendUncheckedTransactionKlaytn(transaction) as Promise; + } else { + return this.sendUncheckedTransactionEth(transaction)as Promise; ; + } + } + + async sendUncheckedTransactionEth(transaction: Deferrable): Promise { const tx = await getTransactionRequest(transaction); if (!tx.from) { @@ -481,6 +490,47 @@ export class JsonRpcSigner extends EthersSigner implements EthersJsonRpcSigner { logger.throwArgumentError("from address mismatch", "transaction", transaction); } + return this.provider.send("eth_sendTransaction", [tx]).then((hash) => { + return hash; + }, (error) => { + if (typeof (error.message) === "string" && error.message.match(/user denied/i)) { + logger.throwError("user rejected transaction", Logger.errors.ACTION_REJECTED, { + action: "sendTransaction", + transaction: tx + }); + } + + //return checkError("sendTransaction", error, hexTx); + }); + } + + + async sendUncheckedTransactionKlaytn(transaction: Deferrable): Promise { + const tx = await getTransactionRequest(transaction); + + if (!tx.from) { + tx.from = await this.getAddress(); + } + + if (!tx.gasLimit) { + tx.gasLimit = await this.provider.estimateGas(tx); + } + + if (tx.to) { + const toAddress = await this.provider.resolveName(tx.to); + if (toAddress == null) { + logger.throwArgumentError("provided ENS name resolves to null", "tx.to", tx.to); + } else { + tx.to = toAddress; + } + } + + const fromAddress = await this.getAddress(); + if (tx.from && tx.from.toLowerCase() != fromAddress.toLowerCase()) { + logger.throwArgumentError("from address mismatch", "transaction", transaction); + } + + // It must be changed to the following format like (TxType.ValueTransfer -> VALUE_TRANSFER) const rpcTx = getRpcTxObject(tx); rpcTx.type = _.snakeCase(TxType[tx.type || 0]).toUpperCase() console.log('sending', rpcTx); @@ -495,7 +545,7 @@ export class JsonRpcSigner extends EthersSigner implements EthersJsonRpcSigner { }); } - //return checkError("sendTransaction", error, hexTx); + // return checkError("sendTransaction", error, hexTx); }); } From 0fe25ab3b7d8d7fbf20772461506b98e708da82d Mon Sep 17 00:00:00 2001 From: Nohyun Nehemiah Kwak Date: Wed, 13 Dec 2023 19:30:57 +0900 Subject: [PATCH 21/33] ethers: Kaikas sign for FeeDelegatedVT --- ethers-ext/example/browser-html/index.html | 6 +++++- ethers-ext/example/browser-html/main.js | 23 ++++++++++++++++++++++ ethers-ext/src/signer.ts | 2 +- 3 files changed, 29 insertions(+), 2 deletions(-) diff --git a/ethers-ext/example/browser-html/index.html b/ethers-ext/example/browser-html/index.html index 3f594434d..ec537ed1c 100644 --- a/ethers-ext/example/browser-html/index.html +++ b/ethers-ext/example/browser-html/index.html @@ -16,12 +16,16 @@

+


accounts:

+ +

signed tx:

+

txhash:

+

signature:

signer adddress recovered from signature:

-

txhash:

diff --git a/ethers-ext/example/browser-html/main.js b/ethers-ext/example/browser-html/main.js index e4f38fdef..0b189c83a 100644 --- a/ethers-ext/example/browser-html/main.js +++ b/ethers-ext/example/browser-html/main.js @@ -174,5 +174,28 @@ async function sendVT() { async function sendFVT() { + const isKaikas = provider.provider.isKaikas || false; + + if (!isKaikas) { + alert("not kaikas"); + return; + } + + try { + const signer = provider.getSigner(); + const address = await signer.getAddress(); + + const signedTx = await signer.signTransaction({ + type: 'FEE_DELEGATED_VALUE_TRANSFER', // TODO: accept number + from: address, + to: address, + value: '0x0', // TODO : accept number + }) + console.log("signedTx", signedTx); + $("#textSignedTx").html(`${signedTx.rawTransaction}`); + } catch (err) { + console.error(err); + $("#textTxhash").html(`Error: ${err.message}`); + } } \ No newline at end of file diff --git a/ethers-ext/src/signer.ts b/ethers-ext/src/signer.ts index eef355350..72aacb9c2 100644 --- a/ethers-ext/src/signer.ts +++ b/ethers-ext/src/signer.ts @@ -435,7 +435,7 @@ export class JsonRpcSigner extends EthersSigner implements EthersJsonRpcSigner { } override async signTransaction(transaction: Deferrable): Promise { - return Promise.resolve(""); + return await this.provider.send("klay_signTransaction", [transaction]); } override async sendTransaction(transaction: Deferrable): Promise { From 79674c014828c242efd31df647da8c6d8e0da42b Mon Sep 17 00:00:00 2001 From: "ollie.j" Date: Fri, 15 Dec 2023 12:09:37 +0900 Subject: [PATCH 22/33] ethers: Export providers like ethers v5 --- ethers-ext/src/index.ts | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/ethers-ext/src/index.ts b/ethers-ext/src/index.ts index e0912204c..213c4b5e1 100644 --- a/ethers-ext/src/index.ts +++ b/ethers-ext/src/index.ts @@ -9,5 +9,14 @@ export { export * from "./accountStore"; export * from "./keystore"; -export * from "./provider"; export * from "./signer"; + +// Follow ethers v6 convention for `ethers.JsonRpcProvider` +export * from "./provider"; + +// Follow ethers v5 convention for `ethers.providers.JsonRpcProvider` +import { JsonRpcProvider, Web3Provider } from "./provider"; +export const providers = { + JsonRpcProvider, + Web3Provider, +}; From 82c11ec54a08ac7920a567c9dfbe7c7000f58dab Mon Sep 17 00:00:00 2001 From: "ollie.j" Date: Fri, 15 Dec 2023 14:02:23 +0900 Subject: [PATCH 23/33] ethers: Web3Provider and FeePayer --- ethers-ext/example/browser-html/main.js | 27 +++++--- ethers-ext/src/index.ts | 20 +++++- ethers-ext/src/signer.ts | 86 +++++++++++++++++++------ 3 files changed, 101 insertions(+), 32 deletions(-) diff --git a/ethers-ext/example/browser-html/main.js b/ethers-ext/example/browser-html/main.js index 0b189c83a..e386c7e18 100644 --- a/ethers-ext/example/browser-html/main.js +++ b/ethers-ext/example/browser-html/main.js @@ -12,7 +12,7 @@ async function connect(injectedProvider) { provider = new ethers.providers.Web3Provider(injectedProvider); } else { console.log("use ethers-ext"); - provider = new ethers_ext.Web3Provider(injectedProvider); + provider = new ethers_ext.providers.Web3Provider(injectedProvider); } await provider.send("eth_requestAccounts", []); @@ -156,11 +156,11 @@ async function sendVT() { const address = await signer.getAddress(); const sentTx = await signer.sendTransaction({ - type: 8, + type: ethers_ext.TxType.ValueTransfer, from: address, to: address, value: 0, - }) + }); console.log("sentTx", sentTx); const txhash = sentTx.hash; @@ -172,10 +172,8 @@ async function sendVT() { } } - async function sendFVT() { const isKaikas = provider.provider.isKaikas || false; - if (!isKaikas) { alert("not kaikas"); return; @@ -186,14 +184,25 @@ async function sendFVT() { const address = await signer.getAddress(); const signedTx = await signer.signTransaction({ - type: 'FEE_DELEGATED_VALUE_TRANSFER', // TODO: accept number + type: "FEE_DELEGATED_VALUE_TRANSFER", // TODO: accept number from: address, to: address, - value: '0x0', // TODO : accept number - }) + value: "0x0", // TODO : accept number + }); console.log("signedTx", signedTx); - $("#textSignedTx").html(`${signedTx.rawTransaction}`); + $("#textSignedTx").html(`${signedTx}`); + + // Simulate fee payer behavior, which is usually in the backend. + const httpProvider = new ethers_ext.JsonRpcProvider("https://public-en-baobab.klaytn.net"); + const feePayerPriv = "0xb3cf575dea0081563fe5482de2fe4425e025502b1f4ae7e02b2540ac0a5beda1"; + const feePayerWallet = new ethers_ext.Wallet(feePayerPriv, httpProvider); + + const sentTx = await feePayerWallet.sendTransactionAsFeePayer(signedTx); + console.log("sentTx", sentTx); + const txhash = sentTx.hash; + const explorerUrl = "https://baobab.klaytnscope.com/tx/"; + $("#textTxhash").html(`${txhash}`); } catch (err) { console.error(err); $("#textTxhash").html(`Error: ${err.message}`); diff --git a/ethers-ext/src/index.ts b/ethers-ext/src/index.ts index 213c4b5e1..f9a952914 100644 --- a/ethers-ext/src/index.ts +++ b/ethers-ext/src/index.ts @@ -11,12 +11,26 @@ export * from "./accountStore"; export * from "./keystore"; export * from "./signer"; -// Follow ethers v6 convention for `ethers.JsonRpcProvider` -export * from "./provider"; - // Follow ethers v5 convention for `ethers.providers.JsonRpcProvider` +export * from "./provider"; +// Follow ethers v6 convention for `ethers.JsonRpcProvider` import { JsonRpcProvider, Web3Provider } from "./provider"; export const providers = { JsonRpcProvider, Web3Provider, }; + +/* +import { Wallet } from "./signer"; + +async function ttt() { + const signedTx = "0x09f89a820171850ba43b7400827918943208ca99480f82bfe240ca6bc06110cd12bb636680943208ca99480f82bfe240ca6bc06110cd12bb6366f847f8458207f6a082945cf792dbebf375a39ca3efb0972afff4504ca713743ad1d52ae0f5918dafa05848b3e7049e600475145891bbf58401c85a755ca4b1ce29588e67e4b8d58579940000000000000000000000000000000000000000c4c3018080"; + const directProvider = new JsonRpcProvider("https://public-en-baobab.klaytn.net"); + const feePayerPriv = "0xb3cf575dea0081563fe5482de2fe4425e025502b1f4ae7e02b2540ac0a5beda1"; + const feePayerWallet = new Wallet(feePayerPriv, directProvider); + + const feePayerSignedTx = await feePayerWallet.signTransactionAsFeePayer(signedTx as any); + console.log(feePayerSignedTx); +} +ttt(); +*/ \ No newline at end of file diff --git a/ethers-ext/src/signer.ts b/ethers-ext/src/signer.ts index 72aacb9c2..1e55c18ba 100644 --- a/ethers-ext/src/signer.ts +++ b/ethers-ext/src/signer.ts @@ -5,6 +5,7 @@ import { TypedDataDomain, TypedDataField, } from "@ethersproject/abstract-signer"; +import { AddressZero } from "@ethersproject/constants"; import { Logger } from "@ethersproject/logger"; import { Web3Provider as EthersWeb3Provider, @@ -13,7 +14,7 @@ import { } from "@ethersproject/providers"; import { Wallet as EthersWallet } from "@ethersproject/wallet"; import { poll } from "@ethersproject/web"; -import { KlaytnTxFactory, HexStr, isFeePayerSigTxType, parseTransaction, getRpcTxObject } from "@klaytn/js-ext-core"; +import { KlaytnTxFactory, HexStr, isFeePayerSigTxType, parseTransaction, getRpcTxObject, TxType, getSignatureTuple } from "@klaytn/js-ext-core"; import { BigNumber } from "ethers"; import { Bytes, @@ -28,7 +29,6 @@ import { getAddress, toUtf8Bytes, } from "ethers/lib/utils"; -import { TxType } from "@klaytn/js-ext-core"; import _ from "lodash"; import { decryptKeystoreList, decryptKeystoreListSync } from "./keystore"; @@ -254,17 +254,48 @@ export class Wallet extends EthersWallet { async signTransactionAsFeePayer(transaction: Deferrable): Promise { const tx = await getTransactionRequest(transaction); + console.log("signfee BEFORE", tx); + // Not a Klaytn TxType; not supported if (!KlaytnTxFactory.has(tx.type)) { throw new Error(`feePayer signature not supported for tx type ${tx.type}`); } + // feePayer + // TODO: define feePayer type in KlaytnTransactionRequest + // originally undefined => this.getAddress() + // originally 0x0000000 => this.getAddress() // returned from caver + // originally 0x1231331 => check if it matches this.getAddress() + const inputFeePayer = (tx as any).feePayer; + if (!inputFeePayer || inputFeePayer == AddressZero) { + (tx as any).feePayer = await this.getAddress(); + } else { + if (inputFeePayer != await this.getAddress()) { + throw new Error(`feePayer address mismatch: ${inputFeePayer} != ${await this.getAddress()}`); + } + } + + // feePayerSignatures + // TODO: define feePayerSignatures type in KlaytnTransactionRequest + // originally [ '0x01', '0x', '0x' ] => remove it + const inputFeePayerSignatures = (tx as any).feePayerSignatures; + if (_.isArray(inputFeePayerSignatures)) { + (tx as any).feePayerSignatures = _.filter(inputFeePayerSignatures, (sig) => { + try { + if (sig[0] == "0x01" && sig[1] == "0x" && sig[2] == "0x") { + return false; + } + } catch { + // Ignore other types of signatures. Let KlaytnTxFactory handle it. + } + return true; + }); + } + // Because RLP-encoded tx may not contain chainId, fill up here. tx.chainId ??= await this._chainIdFromTx(tx); - // Automatically populate 'feePayer' field, just like how 'from' field is populated. - // @ts-ignore: feePayer field does not exist in ethers.TransactionRequest type - tx.feePayer ??= await this.getAddress(); + console.log("signfee AFTER", tx); const klaytnTx = KlaytnTxFactory.fromObject(tx); if (!isFeePayerSigTxType(klaytnTx.type)) { @@ -315,7 +346,7 @@ export class Wallet extends EthersWallet { if (_.isArray(field) && field.length > 0 && _.isArray(field[0]) && field[0].length == 3) { const v = BigNumber.from(field[0][0]).toNumber(); - return (v - 35) / 2; + return (v + (v % 2) - 36) / 2; } return undefined; } @@ -435,7 +466,23 @@ export class JsonRpcSigner extends EthersSigner implements EthersJsonRpcSigner { } override async signTransaction(transaction: Deferrable): Promise { - return await this.provider.send("klay_signTransaction", [transaction]); + if (!this.isKaikas()) { + throw new Error("signTransaction is only supported in Kaikas"); + } + + let signedTx; + try { + signedTx = await this.provider.send("klay_signTransaction", [transaction]); + } catch (error: any) { + if (typeof (error.message) === "string" && error.message.match(/user denied/i)) { + logger.throwError("user rejected transaction", Logger.errors.ACTION_REJECTED, { + action: "signTransaction", + transaction: transaction + }); + } + } + + return signedTx.rawTransaction; } override async sendTransaction(transaction: Deferrable): Promise { @@ -457,11 +504,10 @@ export class JsonRpcSigner extends EthersSigner implements EthersJsonRpcSigner { } async sendUncheckedTransaction(transaction: Deferrable): Promise { - const type = transaction.type; - if ( this.isKaikas() ) { - return this.sendUncheckedTransactionKlaytn(transaction) as Promise; + if (this.isKaikas()) { + return this.sendUncheckedTransactionKlaytn(transaction) as Promise; } else { - return this.sendUncheckedTransactionEth(transaction)as Promise; ; + return this.sendUncheckedTransactionEth(transaction)as Promise; } } @@ -475,7 +521,7 @@ export class JsonRpcSigner extends EthersSigner implements EthersJsonRpcSigner { if (!tx.gasLimit) { tx.gasLimit = await this.provider.estimateGas(tx); } - + if (tx.to) { const toAddress = await this.provider.resolveName(tx.to); if (toAddress == null) { @@ -484,10 +530,10 @@ export class JsonRpcSigner extends EthersSigner implements EthersJsonRpcSigner { tx.to = toAddress; } } - + const fromAddress = await this.getAddress(); if (tx.from && tx.from.toLowerCase() != fromAddress.toLowerCase()) { - logger.throwArgumentError("from address mismatch", "transaction", transaction); + logger.throwArgumentError("from address mismatch", "transaction", transaction); } return this.provider.send("eth_sendTransaction", [tx]).then((hash) => { @@ -500,7 +546,7 @@ export class JsonRpcSigner extends EthersSigner implements EthersJsonRpcSigner { }); } - //return checkError("sendTransaction", error, hexTx); + // return checkError("sendTransaction", error, hexTx); }); } @@ -515,7 +561,7 @@ export class JsonRpcSigner extends EthersSigner implements EthersJsonRpcSigner { if (!tx.gasLimit) { tx.gasLimit = await this.provider.estimateGas(tx); } - + if (tx.to) { const toAddress = await this.provider.resolveName(tx.to); if (toAddress == null) { @@ -524,16 +570,16 @@ export class JsonRpcSigner extends EthersSigner implements EthersJsonRpcSigner { tx.to = toAddress; } } - + const fromAddress = await this.getAddress(); if (tx.from && tx.from.toLowerCase() != fromAddress.toLowerCase()) { - logger.throwArgumentError("from address mismatch", "transaction", transaction); + logger.throwArgumentError("from address mismatch", "transaction", transaction); } // It must be changed to the following format like (TxType.ValueTransfer -> VALUE_TRANSFER) const rpcTx = getRpcTxObject(tx); - rpcTx.type = _.snakeCase(TxType[tx.type || 0]).toUpperCase() - console.log('sending', rpcTx); + rpcTx.type = _.snakeCase(TxType[tx.type || 0]).toUpperCase(); + console.log("sending", rpcTx); return this.provider.send("klay_sendTransaction", [rpcTx]).then((hash) => { return hash; From 1331ae5d1e132dbd60cec369d74c8feab5c36826 Mon Sep 17 00:00:00 2001 From: "ollie.j" Date: Fri, 15 Dec 2023 14:52:37 +0900 Subject: [PATCH 24/33] ethers: Add deps TypeDoc --- ethers-ext/.gitignore | 3 ++ ethers-ext/package-lock.json | 91 ++++++++++++++++++++++++++++++++++++ ethers-ext/package.json | 1 + 3 files changed, 95 insertions(+) diff --git a/ethers-ext/.gitignore b/ethers-ext/.gitignore index b770fb2b1..9535ae191 100644 --- a/ethers-ext/.gitignore +++ b/ethers-ext/.gitignore @@ -44,3 +44,6 @@ yarn.lock # eslint .eslintcache + +# TypeDoc +docs diff --git a/ethers-ext/package-lock.json b/ethers-ext/package-lock.json index 6713c0dba..428c90e38 100644 --- a/ethers-ext/package-lock.json +++ b/ethers-ext/package-lock.json @@ -27,6 +27,7 @@ "mocha": "^10.2.0", "ts-loader": "^9.5.1", "ts-node": "^10.9.1", + "typedoc": "^0.25.4", "typescript": "^5.0.4", "webpack": "^5.89.0", "webpack-cli": "^5.1.4", @@ -2250,6 +2251,12 @@ "node": ">=8" } }, + "node_modules/ansi-sequence-parser": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ansi-sequence-parser/-/ansi-sequence-parser-1.1.1.tgz", + "integrity": "sha512-vJXt3yiaUL4UU546s3rPXlsry/RnM730G1+HkpKE012AN0sx1eOrxSu95oKDIonskeLTijMgqWZ3uDEe3NFvyg==", + "dev": true + }, "node_modules/ansi-styles": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", @@ -4539,6 +4546,12 @@ "node": ">=6" } }, + "node_modules/jsonc-parser": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.0.tgz", + "integrity": "sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w==", + "dev": true + }, "node_modules/jxLoader": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/jxLoader/-/jxLoader-0.1.1.tgz", @@ -4689,6 +4702,12 @@ "yallist": "^3.0.2" } }, + "node_modules/lunr": { + "version": "2.3.9", + "resolved": "https://registry.npmjs.org/lunr/-/lunr-2.3.9.tgz", + "integrity": "sha512-zTU3DaZaF3Rt9rhN3uBMGQD3dD2/vFQqnvZCDv4dl5iOzq2IZQqTxu90r4E5J+nP70J3ilqVCrbho2eWaeW8Ow==", + "dev": true + }, "node_modules/make-dir": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz", @@ -4724,6 +4743,18 @@ "tmpl": "1.0.5" } }, + "node_modules/marked": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/marked/-/marked-4.3.0.tgz", + "integrity": "sha512-PRsaiG84bK+AMvxziE/lCFss8juXjNaWzVbN5tXAm4XjeaS9NAHhop+PjQxz2A9h8Q4M/xGmzP8vqNwy6JeK0A==", + "dev": true, + "bin": { + "marked": "bin/marked.js" + }, + "engines": { + "node": ">= 12" + } + }, "node_modules/merge-stream": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", @@ -5639,6 +5670,18 @@ "node": ">=8" } }, + "node_modules/shiki": { + "version": "0.14.6", + "resolved": "https://registry.npmjs.org/shiki/-/shiki-0.14.6.tgz", + "integrity": "sha512-R4koBBlQP33cC8cpzX0hAoOURBHJILp4Aaduh2eYi+Vj8ZBqtK/5SWNEHBS3qwUMu8dqOtI/ftno3ESfNeVW9g==", + "dev": true, + "dependencies": { + "ansi-sequence-parser": "^1.1.0", + "jsonc-parser": "^3.2.0", + "vscode-oniguruma": "^1.7.0", + "vscode-textmate": "^8.0.0" + } + }, "node_modules/side-channel": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", @@ -6258,6 +6301,42 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/typedoc": { + "version": "0.25.4", + "resolved": "https://registry.npmjs.org/typedoc/-/typedoc-0.25.4.tgz", + "integrity": "sha512-Du9ImmpBCw54bX275yJrxPVnjdIyJO/84co0/L9mwe0R3G4FSR6rQ09AlXVRvZEGMUg09+z/usc8mgygQ1aidA==", + "dev": true, + "dependencies": { + "lunr": "^2.3.9", + "marked": "^4.3.0", + "minimatch": "^9.0.3", + "shiki": "^0.14.1" + }, + "bin": { + "typedoc": "bin/typedoc" + }, + "engines": { + "node": ">= 16" + }, + "peerDependencies": { + "typescript": "4.6.x || 4.7.x || 4.8.x || 4.9.x || 5.0.x || 5.1.x || 5.2.x || 5.3.x" + } + }, + "node_modules/typedoc/node_modules/minimatch": { + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", + "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/typescript": { "version": "5.0.4", "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.0.4.tgz", @@ -6344,6 +6423,18 @@ "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", "dev": true }, + "node_modules/vscode-oniguruma": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/vscode-oniguruma/-/vscode-oniguruma-1.7.0.tgz", + "integrity": "sha512-L9WMGRfrjOhgHSdOYgCt/yRMsXzLDJSL7BPrOZt73gU0iWO4mpqzqQzOz5srxqTvMBaR0XZTSrVWo4j55Rc6cA==", + "dev": true + }, + "node_modules/vscode-textmate": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/vscode-textmate/-/vscode-textmate-8.0.0.tgz", + "integrity": "sha512-AFbieoL7a5LMqcnOF04ji+rpXadgOXnZsxQr//r83kLPr7biP7am3g9zbaZIaBGwBRWeSvoMD4mgPdX3e4NWBg==", + "dev": true + }, "node_modules/walker": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz", diff --git a/ethers-ext/package.json b/ethers-ext/package.json index f40210bf7..57b8a82ec 100644 --- a/ethers-ext/package.json +++ b/ethers-ext/package.json @@ -36,6 +36,7 @@ "mocha": "^10.2.0", "ts-loader": "^9.5.1", "ts-node": "^10.9.1", + "typedoc": "^0.25.4", "typescript": "^5.0.4", "webpack": "^5.89.0", "webpack-cli": "^5.1.4", From 848b32f01bb826d972820dd3820b27c50ba9eca3 Mon Sep 17 00:00:00 2001 From: "ollie.j" Date: Fri, 15 Dec 2023 15:29:07 +0900 Subject: [PATCH 25/33] ethers: Update README --- ethers-ext/README.md | 240 ++++++++++++++++----------------- ethers-ext/src/signer.ts | 10 +- ethers-ext/test/signer.spec.ts | 6 +- 3 files changed, 121 insertions(+), 135 deletions(-) diff --git a/ethers-ext/README.md b/ethers-ext/README.md index 9f90c34e2..ed504dd5b 100644 --- a/ethers-ext/README.md +++ b/ethers-ext/README.md @@ -39,135 +39,121 @@ See [example](./example) and [test](./test). node example/rpc/rpc.js ``` -## Core classes +## Class extension design ```mermaid classDiagram - FieldType ..|> FieldTypeBytes - FieldType ..|> FieldTypeSignatureTuples - FieldType ..|> FieldTypeAccountKey - FieldType ..|> etc - class FieldType { - <> - canonicalize(any): any - emptyValue(): any - } - class FieldTypeBytes { - canonicalize(any): string - emptyValue(): string - } - class FieldTypeSignatureTuples { - canonicalize( SignatureLike[]): SignatureTuple[] - emptyValue(): SignatureTuple[] - } - class FieldTypeAccountKey { - canonicalize(TypedAccountKey | string | any): string - emptyValue(): string - } -``` - -```mermaid -classDiagram - FieldSet <|-- KlaytnTx - KlaytnTx <|-- TxTypeValueTransfer - KlaytnTx <|-- TxTypeFeeDelegatedValueTransfer - KlaytnTx <|-- other TxTypes - FieldSet <|-- AccountKey - AccountKey <|-- AccountKeyLegacy - AccountKey <|-- AccountKeyPublic - AccountKey <|-- other AccountKey - class FieldSet { - type: number - typeName: string - fieldTypes: string -> FieldType - setFields(any) - setFieldsFromArray( string[], any[] ) - getField( string ): any - getFields( string[] ): any[] - toObject(): any - } - class KlaytnTx { - sigRLP(): string - sigFeePayerRLP(): string - senderTxHashRLP(): string - txHashRLP(): string - addSenderSig(sig) - addFeePayerSig(sig) - setFieldsFromRLP(string): void - } - class AccountKey { - toRLP(): string - } -``` - -```mermaid -classDiagram - FieldSetFactory <|.. KlaytnTxFactory - FieldSetFactory <|.. AccountKeyFactory - class FieldSetFactory { - private registry: [number] -> FieldSet - private requiredFields: string[] - add(typeof T) - has(type?): boolean - lookup(type?): typeof T - fromObject(any): T - } - class KlaytnTxFactory { - fromRLP(string): KlaytnTx - } - class AccountKeyFactory { - } -``` + namespace ethers { + class ethers_Signer["ethers.Signer"] { + provider + checkTransaction() + populateTransaction() + sendTransaction() + } + class ethers_Wallet["ethers.Wallet"] { + connect() + getAddress() + signMessage() + signTransaction() + static fromEncryptedJson() + static fromEncryptedJsonSync() + } + class ethers_JsonRpcSigner["ethers.JsonRpcSigner"] { + connect() + connectUnchecked() + getAddress() + signMessage() + signTransaction() + sendUncheckedTransaction() + _legacySignMessage() + _signTypedData() + override sendTransaction() + } + + class ethers_Provider["ethers.Provider"] { + } + class ethers_BaseProvider["ethers.BaseProvider"] { + } + class ethers_JsonRpcProvider["ethers.JsonRpcProvider"] { + getSigner() + send() + } + class ethers_Web3Provider["ethers.Web3Provider"] { + override send() + } + class ethers_ExternalProvider["ethers.ExternalProvider"] { + isMetaMask + request() + } + } + namespace ethers_ext { + class Wallet { + override getAddress() + override checkTransaction() + override populateTransaction() + override signTransaction() + override sendTransaction() + override static fromEncryptedJson() + override static fromEncryptedJsonSync() + signTransactionAsFeePayer() + sendTransactionAsFeePayer() + static fromEncryptedJsonList() + static fromEncryptedJsonListSync() + } + class JsonRpcSigner { + override connectUnchecked() + override getAddress() + override signMessage() + override checkTransaction() + override populateTransaction() + override signTransaction() + override _legacySignMessage() + override _signTypedData() + override sendTransaction() + override sendUncheckedTransaction() + } + + class JsonRpcProvider { + admin + debug + governance + klay + net + personal + txpool + + override getSigner() + override send() + } + class Web3Provider { + admin + debug + governance + klay + net + personal + txpool + + override getSigner() + } + class ExternalProvider { + isKaikas + } + } + + ethers_Signer <|-- ethers_Wallet + ethers_Signer <|-- ethers_JsonRpcSigner + + ethers_Wallet <|-- Wallet + ethers_JsonRpcSigner <|-- JsonRpcSigner + + + ethers_Provider <|-- ethers_BaseProvider + ethers_BaseProvider <|-- ethers_JsonRpcProvider + ethers_JsonRpcProvider <|-- ethers_Web3Provider + + ethers_JsonRpcProvider <|-- JsonRpcProvider + ethers_Web3Provider <|-- Web3Provider + ethers_ExternalProvider <|-- ExternalProvider -## ethers extension classes - -```mermaid -classDiagram - ethers_Wallet <|-- KlaytnWallet - ethers_Signer <|-- ethers_Wallet - class ethers_Signer { - provider - abstract getAddress() - abstract signMessage() - abstract signTransaction() - sendTransaction() - } - class ethers_Wallet { - address - privateKey - getAddress() - signMessage() - signTransaction() - checkTransaction() - populateTransaction() - sendTransaction() - } - class KlaytnWallet { - signTransaction() - checkTransaction() - populateTransaction() - sendTransaction() - } - - ethers_Provider <|-- ethers_BaseProvider - ethers_BaseProvider <|-- ethers_JsonRpcProvider - ethers_JsonRpcProvider <|-- KlaytnJsonRpcProvider - class ethers_Provider { - abstract sendTransaction() - abstract call() - abstract estimateGas() - } - class ethers_BaseProvider { - sendTransaction() - waitForTransaction() - } - class ethers_JsonRpcProvider { - perform() - send() - prepareRequest() // "eth_sendRawTransaction" - } - class KlaytnJsonRpcProvider { - sendTransaction() - prepareRequest() // "klay_sendRawTransaction" - } ``` diff --git a/ethers-ext/src/signer.ts b/ethers-ext/src/signer.ts index 1e55c18ba..6888d4d87 100644 --- a/ethers-ext/src/signer.ts +++ b/ethers-ext/src/signer.ts @@ -133,7 +133,7 @@ export class Wallet extends EthersWallet { } } - getAddress(legacy?: boolean): Promise { + override getAddress(legacy?: boolean): Promise { if (legacy || !this.klaytnAddr) { return Promise.resolve(computeAddress(this.publicKey)); } else { @@ -155,7 +155,7 @@ export class Wallet extends EthersWallet { } // Fill legacy address for Ethereum TxTypes, and (possibly) decoupled address for Klaytn TxTypes. - checkTransaction(transaction: Deferrable): Deferrable { + override checkTransaction(transaction: Deferrable): Deferrable { const tx = _.clone(transaction); const legacy = !KlaytnTxFactory.has(tx.type); @@ -176,7 +176,7 @@ export class Wallet extends EthersWallet { return tx; } - async populateTransaction(transaction: Deferrable): Promise { + override async populateTransaction(transaction: Deferrable): Promise { const tx = await getTransactionRequest(transaction); // Not a Klaytn TxType; fallback to ethers.Wallet @@ -224,7 +224,7 @@ export class Wallet extends EthersWallet { // Sign as a sender // tx.sigs += Sign(tx.sigRLP(), wallet.privateKey) // return tx.txHashRLP() or tx.senderTxHashRLP(); - async signTransaction(transaction: Deferrable): Promise { + override async signTransaction(transaction: Deferrable): Promise { const tx = await getTransactionRequest(transaction); // Not a Klaytn TxType; fallback to ethers.Wallet @@ -309,7 +309,7 @@ export class Wallet extends EthersWallet { return klaytnTx.txHashRLP(); } - async sendTransaction(transaction: Deferrable): Promise { + override async sendTransaction(transaction: Deferrable): Promise { this._checkProvider("sendTransaction"); const populatedTx = await this.populateTransaction(transaction); diff --git a/ethers-ext/test/signer.spec.ts b/ethers-ext/test/signer.spec.ts index 8e3dac7a6..ce2ebef8a 100644 --- a/ethers-ext/test/signer.spec.ts +++ b/ethers-ext/test/signer.spec.ts @@ -166,7 +166,7 @@ describe("Wallet", () => { }); it("as fee payer", async () => { for (let W of [KW, KWD]) { - await testOK_AsFeePayer(W, { type: 9, from: (await W.getAddress()), to, feePayer, value, nonce, gasPrice, gasLimit, chainId, txSignatures }); + await testOK_AsFeePayer(W, { type: 9, from, to, feePayer: (await W.getAddress()), value, nonce, gasPrice, gasLimit, chainId, txSignatures }); } for (let W of [KW, KWD]) { await testOK_AsFeePayer(W, senderTxHashRLP); @@ -197,12 +197,12 @@ describe("Wallet", () => { await testOK(W, { type: 0, to, value }); } for (let W of [KW, KWD]) { - // await testOK(W, { type: 9, to, feePayer, value }); + await testOK(W, { type: 9, to, feePayer, value }); } }); it("as fee payer", async () => { for (let W of [KW, KWD]) { - await testOK_AsFeePayer(W, { type: 9, to, feePayer, value, nonce, gasPrice, gasLimit, chainId, txSignatures }); + await testOK_AsFeePayer(W, { type: 9, to, feePayer: (await W.getAddress()), value, nonce, gasPrice, gasLimit, chainId, txSignatures }); } for (let W of [KW, KWD]) { await testOK_AsFeePayer(W, senderTxHashRLP); From 95b2de03e2d77d0f29e9817b628e35ad427f3c00 Mon Sep 17 00:00:00 2001 From: "ollie.j" Date: Fri, 15 Dec 2023 15:35:23 +0900 Subject: [PATCH 26/33] Update README --- ethers-ext/README.md | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/ethers-ext/README.md b/ethers-ext/README.md index ed504dd5b..43db6f03e 100644 --- a/ethers-ext/README.md +++ b/ethers-ext/README.md @@ -4,9 +4,10 @@ Ethers.js Extension for Klaytn offers: - Drop-in replacement to `ethers.Wallet` that handles both Ethereum and Klaytn transactions involving AccountKey and TxTypes. -- Drop-in replacement to `ethers.JsonRpcProvider` that provides Ethereum RPC as well as +- Drop-in replacement to `ethers.JsonRpcProvider` that provides accesses to both Ethereum RPCs and Klaytn-specific RPCs. -- AccountStore to manage Klaytn account keys. +- Drop-in replacement to `ethers.Web3Provider` to work with both MetaMask (`window.ethereum`) and Kaikas (`window.klaytn`) +- (WIP) AccountStore to manage Klaytn account keys. ## Install @@ -39,8 +40,11 @@ See [example](./example) and [test](./test). node example/rpc/rpc.js ``` + ## Class extension design +If diagram does not render, view it [here](https://mermaid.live/edit#pako:eNrVV02P0zAQ_SuVTyB1q35vW3FZtMsBqLSiICQIqmbtaTdqYgfbXTWU_nfcJLRx4jRZISHIpfXz84w9M36294QKhmRGaABK3fqwlhB6vGU-DiGqCCi2UD-iVK19ih-_hJ3hy4W_5ii_eiRtd9K2R77lRxy_SIonn5kuC6WPSDcfJXAFVPuCv3hZGCWibQAaL1AUclbRfaiY9GcIAtTnSadtx6Sp4BypLrpco75hTKJSpcmY5c8NDmt0dV1ahgbt09ZKivCOUxlHGtlb1Zy3iDltsvYj90NEi3mz4OaRyOBPPEkksr8SKZPwk8MLvGWAa6DxotrRMvEUR8huQUOxVzyhlKZkayqsIs73Wb2fQ_wbKUS3KlGvQWHZSB5taChLbdlWocORdZO-tCJcOWi00_BhUHacRx1ercA38XK30yg5BGVPxR6HN1_NUcMc1MbGJX7fotIO_we3Ri5xp8s6mWpL5RKrN8iJUqeRJ2IDsTyH9vIea1L7Nq-hfNUOKOqYQxBu1BvEe4jdZdmMWOH9va_0c7i1qmvpamUV1Mnoc8rlgrD-GyVVr8tn6h8LdIlXd3I4FL2gk8UsAgt9bkMMH7brgpQeZ8GBU7TxTQCxjXBzFbEvQUZchBExG9W7SIjA49WV4pbu5uqal-n_eNGldRUPhfKJ8A78DSiX8Kd_rMtv69XPqyv7alnHsm9bttHswEjoDmu2oCSskjVrwGmV-QlY14g8O9_hmrJzUHGDWAHJn_W8ftglP1ZBpgGyrOeopRwn9NJ1gJM2CVGG4DPzDkrqwCPGQogemZm_DFewDczTwOMHQ4WtFkfJJ7MVBArbZBsxo47Z0-mERsC_CGG1yWxPdmTWm_Y6_elg0r3u9Qe98bQ7apOYzMajznDS7Y-G3eFkOBiOpoc2-ZFY6HauB6Nhfzzp9Ue98XV_MmkTZL4Wcp693Y4_h18MVzCG) + ```mermaid classDiagram namespace ethers { From 66f6540d5a412ffcb44203ae974a58b0271fb588 Mon Sep 17 00:00:00 2001 From: "ollie.j" Date: Fri, 15 Dec 2023 16:29:10 +0900 Subject: [PATCH 27/33] ethers: Refactor --- ethers-ext/.eslintrc.js | 3 +- ethers-ext/example/browser-html/main.js | 4 +- ethers-ext/src/accountStore.ts | 3 +- ethers-ext/src/index.ts | 23 +- ethers-ext/src/keystore.ts | 3 +- ethers-ext/src/provider.ts | 35 +- ethers-ext/src/signer.ts | 653 +++++++++++------------- ethers-ext/src/txutil.ts | 216 ++++++++ ethers-ext/src/types.ts | 20 + ethers-ext/test/signer.spec.ts | 32 +- 10 files changed, 586 insertions(+), 406 deletions(-) create mode 100644 ethers-ext/src/txutil.ts create mode 100644 ethers-ext/src/types.ts diff --git a/ethers-ext/.eslintrc.js b/ethers-ext/.eslintrc.js index 125fd64ed..cb32e39c9 100644 --- a/ethers-ext/.eslintrc.js +++ b/ethers-ext/.eslintrc.js @@ -38,9 +38,10 @@ module.exports = { "import/order": ["warn", { "alphabetize": { "order": "asc", "caseInsensitive": true }, "pathGroups": [ - { "pattern": "@klaytn/**", "group": "external", "position": "after" }, + { "pattern": "@klaytn/**", "group": "parent", "position": "after" }, ], "newlines-between": "always", + "pathGroupsExcludedImportTypes": ["@klaytn/**"], }], "import/no-unresolved": [ "error", // eslint-plugin-import cannot resolve subpaths https://github.com/firebase/firebase-admin-node/discussions/1359 diff --git a/ethers-ext/example/browser-html/main.js b/ethers-ext/example/browser-html/main.js index e386c7e18..4b1d0fa3b 100644 --- a/ethers-ext/example/browser-html/main.js +++ b/ethers-ext/example/browser-html/main.js @@ -184,10 +184,10 @@ async function sendFVT() { const address = await signer.getAddress(); const signedTx = await signer.signTransaction({ - type: "FEE_DELEGATED_VALUE_TRANSFER", // TODO: accept number + type: ethers_ext.TxType.FeeDelegatedValueTransfer, from: address, to: address, - value: "0x0", // TODO : accept number + value: 0, }); console.log("signedTx", signedTx); diff --git a/ethers-ext/src/accountStore.ts b/ethers-ext/src/accountStore.ts index 86798903f..588117d63 100644 --- a/ethers-ext/src/accountStore.ts +++ b/ethers-ext/src/accountStore.ts @@ -2,9 +2,10 @@ import { BigNumber } from "@ethersproject/bignumber"; import { JsonRpcProvider } from "@ethersproject/providers"; import { SigningKey } from "@ethersproject/signing-key"; import { computeAddress } from "@ethersproject/transactions"; -import { HexStr } from "@klaytn/js-ext-core"; import { computePublicKey, getAddress } from "ethers/lib/utils"; +import { HexStr } from "@klaytn/js-ext-core"; + import { Wallet } from "./signer"; function isSameAddress(a: string, b: string) { diff --git a/ethers-ext/src/index.ts b/ethers-ext/src/index.ts index f9a952914..3c96b3458 100644 --- a/ethers-ext/src/index.ts +++ b/ethers-ext/src/index.ts @@ -1,3 +1,4 @@ +// Pass-through js-ext-core exports export * from "@klaytn/js-ext-core/util"; export { AccountKey, @@ -7,30 +8,16 @@ export { parseTransaction, } from "@klaytn/js-ext-core"; +// ethers-ext classes and functions export * from "./accountStore"; export * from "./keystore"; export * from "./signer"; -// Follow ethers v5 convention for `ethers.providers.JsonRpcProvider` +// Follow ethers v6 convention like `ethers.JsonRpcProvider` export * from "./provider"; -// Follow ethers v6 convention for `ethers.JsonRpcProvider` +// Follow ethers v5 convention like `ethers.providers.JsonRpcProvider` import { JsonRpcProvider, Web3Provider } from "./provider"; export const providers = { JsonRpcProvider, Web3Provider, -}; - -/* -import { Wallet } from "./signer"; - -async function ttt() { - const signedTx = "0x09f89a820171850ba43b7400827918943208ca99480f82bfe240ca6bc06110cd12bb636680943208ca99480f82bfe240ca6bc06110cd12bb6366f847f8458207f6a082945cf792dbebf375a39ca3efb0972afff4504ca713743ad1d52ae0f5918dafa05848b3e7049e600475145891bbf58401c85a755ca4b1ce29588e67e4b8d58579940000000000000000000000000000000000000000c4c3018080"; - const directProvider = new JsonRpcProvider("https://public-en-baobab.klaytn.net"); - const feePayerPriv = "0xb3cf575dea0081563fe5482de2fe4425e025502b1f4ae7e02b2540ac0a5beda1"; - const feePayerWallet = new Wallet(feePayerPriv, directProvider); - - const feePayerSignedTx = await feePayerWallet.signTransactionAsFeePayer(signedTx as any); - console.log(feePayerSignedTx); -} -ttt(); -*/ \ No newline at end of file +}; \ No newline at end of file diff --git a/ethers-ext/src/keystore.ts b/ethers-ext/src/keystore.ts index b8bd6e141..2ea22e098 100644 --- a/ethers-ext/src/keystore.ts +++ b/ethers-ext/src/keystore.ts @@ -1,9 +1,10 @@ import { getAddress } from "@ethersproject/address"; import { Bytes } from "@ethersproject/bytes"; import { ProgressCallback, decryptKeystore, decryptKeystoreSync } from "@ethersproject/json-wallets"; -import { isKIP3Json, splitKeystoreKIP3 } from "@klaytn/js-ext-core"; import _ from "lodash"; +import { isKIP3Json, splitKeystoreKIP3 } from "@klaytn/js-ext-core"; + // Decrypted keystore private keys. export interface KeystoreAccountList { address: string; diff --git a/ethers-ext/src/provider.ts b/ethers-ext/src/provider.ts index b90f93065..c4e633af5 100644 --- a/ethers-ext/src/provider.ts +++ b/ethers-ext/src/provider.ts @@ -2,14 +2,14 @@ import { Networkish } from "@ethersproject/networks"; import { JsonRpcProvider as EthersJsonRpcProvider, Web3Provider as EthersWeb3Provider, - ExternalProvider as EthersExternalProvider, JsonRpcSigner as EthersJsonRpcSigner } from "@ethersproject/providers"; import { ConnectionInfo } from "@ethersproject/web"; + import { asyncOpenApi, AsyncNamespaceApi } from "@klaytn/js-ext-core"; // @ts-ignore: package @klaytn/web3rpc has no .d.ts file. import { AdminApi, DebugApi, GovernanceApi, KlayApi, NetApi, PersonalApi, TxpoolApi } from "@klaytn/web3rpc"; -import { JsonRpcSigner as KlaytnJsonRpcSigner } from "./signer"; +import { JsonRpcSigner } from "./signer"; /* eslint-disable no-multi-spaces */ export class JsonRpcProvider extends EthersJsonRpcProvider { @@ -40,11 +40,32 @@ export class JsonRpcProvider extends EthersJsonRpcProvider { } export class Web3Provider extends EthersWeb3Provider { - override getSigner(addressOrIndex?: string | number | undefined): EthersJsonRpcSigner { - return new KlaytnJsonRpcSigner(this, addressOrIndex); + // API methods other than eth_ namespaces + admin: AsyncNamespaceApi; + debug: AsyncNamespaceApi; + governance: AsyncNamespaceApi; + klay: AsyncNamespaceApi; + net: AsyncNamespaceApi; + personal: AsyncNamespaceApi; + txpool: AsyncNamespaceApi; + + constructor(provider: any, network?: any) { + super(provider, network); + + const send = (method: string, params: any) => { + return this.send(method, params); + }; + + this.admin = asyncOpenApi(send, AdminApi); + this.debug = asyncOpenApi(send, DebugApi); + this.governance = asyncOpenApi(send, GovernanceApi); + this.klay = asyncOpenApi(send, KlayApi); + this.net = asyncOpenApi(send, NetApi); + this.personal = asyncOpenApi(send, PersonalApi); + this.txpool = asyncOpenApi(send, TxpoolApi); } -} -export interface ExternalProvider extends EthersExternalProvider { - isKaikas?: boolean; // Exists in window.klaytn that is injected by Kaikas + override getSigner(addressOrIndex?: string | number | undefined): EthersJsonRpcSigner { + return new JsonRpcSigner(this, addressOrIndex); + } } \ No newline at end of file diff --git a/ethers-ext/src/signer.ts b/ethers-ext/src/signer.ts index 6888d4d87..6001519ed 100644 --- a/ethers-ext/src/signer.ts +++ b/ethers-ext/src/signer.ts @@ -1,95 +1,59 @@ -import { Provider, TransactionRequest, TransactionResponse } from "@ethersproject/abstract-provider"; import { Signer as EthersSigner, - ExternallyOwnedAccount, TypedDataDomain, TypedDataField, } from "@ethersproject/abstract-signer"; -import { AddressZero } from "@ethersproject/constants"; +import { getAddress } from "@ethersproject/address"; +import { Bytes, hexlify } from "@ethersproject/bytes"; +import { _TypedDataEncoder } from "@ethersproject/hash"; +import { ProgressCallback } from "@ethersproject/json-wallets"; +import { keccak256 } from "@ethersproject/keccak256"; import { Logger } from "@ethersproject/logger"; +import { Deferrable } from "@ethersproject/properties"; import { Web3Provider as EthersWeb3Provider, JsonRpcProvider as EthersJsonRpcProvider, JsonRpcSigner as EthersJsonRpcSigner, + Provider, + TransactionRequest, + TransactionResponse, } from "@ethersproject/providers"; +import { toUtf8Bytes } from "@ethersproject/strings"; import { Wallet as EthersWallet } from "@ethersproject/wallet"; -import { poll } from "@ethersproject/web"; -import { KlaytnTxFactory, HexStr, isFeePayerSigTxType, parseTransaction, getRpcTxObject, TxType, getSignatureTuple } from "@klaytn/js-ext-core"; -import { BigNumber } from "ethers"; -import { - Bytes, - BytesLike, - Deferrable, - ProgressCallback, - SigningKey, - computeAddress, - hexlify, - keccak256, - resolveProperties, - getAddress, - toUtf8Bytes, -} from "ethers/lib/utils"; import _ from "lodash"; -import { decryptKeystoreList, decryptKeystoreListSync } from "./keystore"; -import { ExternalProvider as KlaytnExternalProvider } from "./provider"; - -// To use the same error format as ethers.js -const logger = new Logger("@klaytn/ethers-ext"); - -// @ethersproject/abstract-signer/src.ts/index.ts:allowedTransactionKeys -const ethersAllowedTransactionKeys: Array = [ - "accessList", "ccipReadEnabled", "chainId", "customData", "data", "from", "gasLimit", "gasPrice", "maxFeePerGas", "maxPriorityFeePerGas", "nonce", "to", "type", "value", -]; - -// ethers.js may strip or reject some Klaytn-specific transaction fields. -// To prserve transaction fields around super method calls, use -// saveCustomFields and restoreCustomFields. -function saveCustomFields(tx: Deferrable): any { - // Save fields that are not allowed in ethers.js - const savedFields: any = {}; - for (const key in tx) { - // 'from' may not be corresponded to the public key of the private key in a decoupled account. - if (ethersAllowedTransactionKeys.indexOf(key) === -1 || key == "from") { - savedFields[key] = _.get(tx, key); - _.unset(tx, key); - } - } - - // Save txtype that is not supported in ethers.js. - // and disguise as legacy (type 0) transaction. - // - // Why disguise as legacy type? - // Signer.populateTransaction() will not fill gasPrice - // unless tx type is explicitly Legacy (type=0) or EIP-2930 (type=1). - // Klaytn tx types, however, always uses gasPrice. - if (_.isNumber(tx.type) && KlaytnTxFactory.has(tx.type)) { - savedFields["type"] = tx.type; - tx.type = 0; - } - - return savedFields; -} +import { + HexStr, + KlaytnTxFactory, + parseTransaction, + getRpcTxObject, + isKlaytnTxType, + isFeePayerSigTxType, +} from "@klaytn/js-ext-core"; -function restoreCustomFields(tx: Deferrable, savedFields: any) { - for (const key in savedFields) { - _.set(tx, key, savedFields[key]); - } -} +import { decryptKeystoreList, decryptKeystoreListSync } from "./keystore"; +import { + eip155sign, + getTransactionRequest, + resolveType, + populateFrom, + populateFromSync, + populateTo, + populateNonce, + populateGasLimit, + populateGasPrice, + populateChainId, + populateFeePayerAndSignatures, + resolveTypeForKaikas, + pollTransactionInPool, +} from "./txutil"; +import { PrivateKeyLike, ExternalProvider } from "./types"; -async function getTransactionRequest(transactionOrRLP: Deferrable | string): Promise { - if (_.isString(transactionOrRLP)) { - return parseTransaction(transactionOrRLP) as TransactionRequest; - } else { - const tx = transactionOrRLP; - return resolveProperties(tx); - } -} -type PrivateKeyLike = BytesLike | ExternallyOwnedAccount | SigningKey; +const logger = new Logger("@klaytn/ethers-ext"); export class Wallet extends EthersWallet { - // Override Wallet factories accepting keystores to support KIP-3 (v4) format + // Override Wallet factories accepting keystores to support both v3 and v4 (KIP-3) formats static override async fromEncryptedJson(json: string, password: string | Bytes, progress?: ProgressCallback): Promise { const { address, privateKey } = await decryptKeystoreList(json, password, progress); return new Wallet(address, privateKey); @@ -100,7 +64,7 @@ export class Wallet extends EthersWallet { return new Wallet(address, privateKey); } - // New Wallet[] factories accepting keystores supporting KIP-3 (v4) format + // New Wallet[] factories accepting keystores supporting v4 (KIP-3) format static async fromEncryptedJsonList(json: string, password: string | Bytes, progress?: ProgressCallback): Promise { const { address, privateKeyList } = await decryptKeystoreList(json, password, progress); return _.map(privateKeyList, (privateKey) => new Wallet(address, privateKey)); @@ -120,22 +84,28 @@ export class Wallet extends EthersWallet { addressOrPrivateKey: string | PrivateKeyLike, privateKeyOrProvider?: PrivateKeyLike | Provider, provider?: Provider) { - // First argument is an address. if (HexStr.isHex(addressOrPrivateKey, 20)) { - const address = HexStr.from(addressOrPrivateKey); - const privateKey = privateKeyOrProvider as PrivateKeyLike; - super(privateKey, provider); - this.klaytnAddr = address; - } else { // First argument is a private key. - const privateKey = addressOrPrivateKey as PrivateKeyLike; + // First argument is an address. new KlaytnWallet(address, privateKey, provider?) + const _address = HexStr.from(addressOrPrivateKey); + const _privateKey = privateKeyOrProvider as PrivateKeyLike; + const _provider = provider; + + super(_privateKey, _provider); + this.klaytnAddr = _address; + } else { + // First argument is a private key. new KlaytnWallet(privateKey, provider?) + const _privateKey = addressOrPrivateKey as PrivateKeyLike; const _provider = privateKeyOrProvider as Provider; - super(privateKey, _provider); + + super(_privateKey, _provider); } } + // If the Wallet is created as a decoupled account, and `legacy` is false, returns the decoupled address. + // Otherwise, returns the address derived from the private key. override getAddress(legacy?: boolean): Promise { if (legacy || !this.klaytnAddr) { - return Promise.resolve(computeAddress(this.publicKey)); + return super.getAddress(); } else { return Promise.resolve(this.klaytnAddr); } @@ -146,6 +116,11 @@ export class Wallet extends EthersWallet { return super.getAddress(); } + // @deprecated in favor of parseTransaction + decodeTxFromRLP(rlp: string): any { + return parseTransaction(rlp); + } + async isDecoupled(): Promise { if (!this.klaytnAddr) { return false; @@ -154,71 +129,42 @@ export class Wallet extends EthersWallet { } } - // Fill legacy address for Ethereum TxTypes, and (possibly) decoupled address for Klaytn TxTypes. + // Fill 'from' if not set. Check 'from' against the private key or decoupled address. override checkTransaction(transaction: Deferrable): Deferrable { const tx = _.clone(transaction); - const legacy = !KlaytnTxFactory.has(tx.type); - const expectedFrom = this.getAddress(legacy); - if (!tx.from) { - tx.from = expectedFrom; - } else { - tx.from = Promise.all([ - Promise.resolve(tx.from), - expectedFrom, - ]).then(([from, expectedFrom]) => { - if (from?.toLowerCase() != expectedFrom?.toLowerCase()) { - throw new Error(`from address mismatch tx=${JSON.stringify(transaction)} addr=${expectedFrom}`); - } - return from; - }); - } + const useLegacyFrom = !isKlaytnTxType(resolveType(tx.type as number)); + const expectedFrom = this.getAddress(useLegacyFrom); + populateFromSync(tx, expectedFrom); + return tx; } - override async populateTransaction(transaction: Deferrable): Promise { + async populateTransaction(transaction: Deferrable): Promise { + return this._populateTransaction(transaction, false); + } + + // If asFeePayer is true, skip the 'from' address check. + private async _populateTransaction(transaction: Deferrable, asFeePayer: boolean): Promise { const tx = await getTransactionRequest(transaction); - // Not a Klaytn TxType; fallback to ethers.Wallet - if (!KlaytnTxFactory.has(tx.type)) { + // Not a Klaytn TxType; fallback to ethers.Signer.populateTransaction() + if (!isKlaytnTxType(resolveType(tx.type))) { return super.populateTransaction(tx); } - // Fill 'from' field. - if (!tx.from) { - tx.from = await this.getAddress(); + // If the current Wallet acts as feePayer, then tx.from is unrelated to this.getAddress(). + // Skip the check, and does not fill up here. If tx.from was empty, then an error is generated + // at signTransaction(), not here. + if (!asFeePayer) { + await populateFrom(tx, await this.getAddress()); } - - // If the account address is decoupled from private key, - // the ethers.Wallet.populateTransaction() may fill the nonce of the wrong address. - if (!tx.nonce) { - tx.nonce = await this.provider.getTransactionCount(tx.from); - } - - // Sometimes estimateGas underestimates the required gas limit. - // Therefore adding some buffer to the RPC result. - // Other cases: - // - ethers.js uses estimateGas result as-is. - // - Metamask multiplies by 1 or 1.5 depending on chainId - // (https://github.com/MetaMask/metamask-extension/blob/v11.3.0/ui/ducks/send/helpers.js#L126) - // TODO: To minimize buffer, add constant intrinsic gas overhead instead of multiplier. - if (!tx.gasLimit) { - const bufferMultiplier = 2.5; - const gasLimit = await this.provider.estimateGas(tx); - tx.gasLimit = Math.ceil(gasLimit.toNumber() * bufferMultiplier); - } - - // Leave rest of the fields to ethers - const savedFields = saveCustomFields(tx); - const populatedTx = await super.populateTransaction(tx); - restoreCustomFields(populatedTx, savedFields); - - return populatedTx; - } - - // @deprecated in favor of parseTransaction - decodeTxFromRLP(rlp: string): any { - return parseTransaction(rlp); + await populateTo(tx, this.provider); + await populateNonce(tx, this.provider, await this.getAddress()); + await populateGasLimit(tx, this.provider); + await populateGasPrice(tx, this.provider); + await populateChainId(tx, this.provider); + return tx; } // Sign as a sender @@ -227,18 +173,18 @@ export class Wallet extends EthersWallet { override async signTransaction(transaction: Deferrable): Promise { const tx = await getTransactionRequest(transaction); - // Not a Klaytn TxType; fallback to ethers.Wallet - if (!KlaytnTxFactory.has(tx.type)) { + // Not a Klaytn TxType; fallback to ethers.Wallet.signTransaction() + if (!isKlaytnTxType(resolveType(tx.type))) { return super.signTransaction(tx); } // Because RLP-encoded tx may not contain chainId, fill up here. - tx.chainId ??= await this._chainIdFromTx(tx); + await populateChainId(tx, this.provider); + const chainId = tx.chainId!; // chainId should have been determined in populateChainId. const klaytnTx = KlaytnTxFactory.fromObject(tx); - const sigHash = keccak256(klaytnTx.sigRLP()); - const sig = this._eip155sign(sigHash, tx.chainId); + const sig = eip155sign(this._signingKey(), sigHash, chainId); klaytnTx.addSenderSig(sig); if (isFeePayerSigTxType(klaytnTx.type)) { @@ -251,134 +197,64 @@ export class Wallet extends EthersWallet { // Sign as a fee payer // tx.feepayerSigs += Sign(tx.sigFeePayerRLP(), wallet.privateKey) // return tx.txHashRLP(); - async signTransactionAsFeePayer(transaction: Deferrable): Promise { - const tx = await getTransactionRequest(transaction); - - console.log("signfee BEFORE", tx); - - // Not a Klaytn TxType; not supported - if (!KlaytnTxFactory.has(tx.type)) { - throw new Error(`feePayer signature not supported for tx type ${tx.type}`); - } + async signTransactionAsFeePayer(transactionOrRLP: Deferrable | string): Promise { + const tx = await getTransactionRequest(transactionOrRLP); - // feePayer - // TODO: define feePayer type in KlaytnTransactionRequest - // originally undefined => this.getAddress() - // originally 0x0000000 => this.getAddress() // returned from caver - // originally 0x1231331 => check if it matches this.getAddress() - const inputFeePayer = (tx as any).feePayer; - if (!inputFeePayer || inputFeePayer == AddressZero) { - (tx as any).feePayer = await this.getAddress(); - } else { - if (inputFeePayer != await this.getAddress()) { - throw new Error(`feePayer address mismatch: ${inputFeePayer} != ${await this.getAddress()}`); - } - } - - // feePayerSignatures - // TODO: define feePayerSignatures type in KlaytnTransactionRequest - // originally [ '0x01', '0x', '0x' ] => remove it - const inputFeePayerSignatures = (tx as any).feePayerSignatures; - if (_.isArray(inputFeePayerSignatures)) { - (tx as any).feePayerSignatures = _.filter(inputFeePayerSignatures, (sig) => { - try { - if (sig[0] == "0x01" && sig[1] == "0x" && sig[2] == "0x") { - return false; - } - } catch { - // Ignore other types of signatures. Let KlaytnTxFactory handle it. - } - return true; - }); + // Not a Klaytn FeePayerSig TxType; not supported + if (!isFeePayerSigTxType(resolveType(tx.type))) { + throw new Error(`signTransactionAsFeePayer not supported for tx type ${tx.type}`); } + // Because RLP-encoded tx may contain dummy fee payer fields, fix here. + await populateFeePayerAndSignatures(tx, await this.getAddress()); // Because RLP-encoded tx may not contain chainId, fill up here. - tx.chainId ??= await this._chainIdFromTx(tx); - - console.log("signfee AFTER", tx); + await populateChainId(tx, this.provider); + const chainId = tx.chainId!; // chainId should have been determined in populateChainId. const klaytnTx = KlaytnTxFactory.fromObject(tx); - if (!isFeePayerSigTxType(klaytnTx.type)) { - klaytnTx.throwTypeError("feePayer signature not supported"); - } const sigFeePayerHash = keccak256(klaytnTx.sigFeePayerRLP()); - const sig = this._eip155sign(sigFeePayerHash, tx.chainId); + const sig = eip155sign(this._signingKey(), sigFeePayerHash, chainId); klaytnTx.addFeePayerSig(sig); return klaytnTx.txHashRLP(); } override async sendTransaction(transaction: Deferrable): Promise { - this._checkProvider("sendTransaction"); + const tx = await getTransactionRequest(transaction); + if (!isKlaytnTxType(resolveType(tx.type))) { + return super.sendTransaction(tx); + } - const populatedTx = await this.populateTransaction(transaction); + const populatedTx = await this._populateTransaction(tx, false); const signedTx = await this.signTransaction(populatedTx); - - if (!KlaytnTxFactory.has(populatedTx.type)) { - return await this.provider.sendTransaction(signedTx); - } else { - return await this._sendRawTransaction(signedTx); - } + return await this._sendKlaytnRawTransaction(signedTx); } - async sendTransactionAsFeePayer(transaction: Deferrable): Promise { - this._checkProvider("sendTransactionAsFeePayer"); + async sendTransactionAsFeePayer(transactionOrRLP: Deferrable | string): Promise { + const tx = await getTransactionRequest(transactionOrRLP); - const populatedTx = await this.populateTransaction(transaction); - const signedTx = await this.signTransactionAsFeePayer(populatedTx); - - return await this._sendRawTransaction(signedTx); - } - - _eip155sign(digest: string, chainId?: number) { - const sig = this._signingKey().signDigest(digest); - if (chainId) { - sig.v = sig.recoveryParam + chainId * 2 + 35; + // Not a Klaytn FeePayerSig TxType; not supported + if (!isFeePayerSigTxType(resolveType(tx.type))) { + throw new Error(`sendTransactionAsFeePayer not supported for tx type ${tx.type}`); } - return sig; - } - // Extract chainId from tx signatures. - // If no signatures, query provider. - async _chainIdFromTx(tx: any): Promise { - function extractFromSig(field: any[]): number | undefined { - if (_.isArray(field) && field.length > 0 && - _.isArray(field[0]) && field[0].length == 3) { - const v = BigNumber.from(field[0][0]).toNumber(); - return (v + (v % 2) - 36) / 2; - } - return undefined; - } - - return ( - extractFromSig(tx.txSignatures) ?? - extractFromSig(tx.feePayerSignatures) ?? - this.getChainId()); + const populatedTx = await this._populateTransaction(tx, true); + const signedTx = await this.signTransactionAsFeePayer(populatedTx); + return await this._sendKlaytnRawTransaction(signedTx); } - async _sendRawTransaction(signedTx: string): Promise { + async _sendKlaytnRawTransaction(signedTx: string): Promise { if (!(this.provider instanceof EthersJsonRpcProvider)) { - throw new Error("Klaytn typed transaction can only be broadcasted to a Klaytn JSON-RPC server"); + throw new Error("Provider is not JsonRpcProvider: cannot send klay_sendRawTransaction"); } else { const txhash = await this.provider.send("klay_sendRawTransaction", [signedTx]); - - // Retry until the transaction shows up in the txpool - // Using poll() like in the ethers.JsonRpcProvider.sendTransaction - // https://github.com/ethers-io/ethers.js/blob/v5.7/packages/providers/src.ts/json-rpc-provider.ts#L283 - const pollFunc = async () => { - const tx = await this.provider.getTransaction(txhash); - if (tx == null) { - return undefined; // retry - } else { - return tx; // success - } - }; - return poll(pollFunc) as Promise; + return await pollTransactionInPool(txhash, this.provider); } } } + // EthersJsonRpcSigner cannot be subclassed because of the constructorGuard. // Instead, we re-create the class by copying the implementation. export class JsonRpcSigner extends EthersSigner implements EthersJsonRpcSigner { @@ -387,6 +263,7 @@ export class JsonRpcSigner extends EthersSigner implements EthersJsonRpcSigner { _address: string; // Equivalent to EthersJsonRpcSigner.constructor, but without constructorGuard. + // @ethersproject/providers/src.ts/json-rpc-provider.ts:JsonRpcSigner.constructor constructor(provider: EthersJsonRpcProvider, addressOrIndex?: string | number) { super(); @@ -410,12 +287,13 @@ export class JsonRpcSigner extends EthersSigner implements EthersJsonRpcSigner { isKaikas(): boolean { if (this.provider instanceof EthersWeb3Provider) { // The EIP-1193 provider, usually injected as window.ethereum or window.klaytn. - const injectedProvider = this.provider.provider as KlaytnExternalProvider; + const injectedProvider = this.provider.provider as ExternalProvider; return injectedProvider.isKaikas === true; } return false; } + // @ethersproject/providers/src.ts/json-rpc-provider.ts:JsonRpcSigner.getAddress override async getAddress(): Promise { if (this._address) { return Promise.resolve(this._address); @@ -431,176 +309,184 @@ export class JsonRpcSigner extends EthersSigner implements EthersJsonRpcSigner { }); } - override connect(provider: Provider): EthersJsonRpcSigner { - throw new Error("cannot alter JSON-RPC Signer connection"); + // @ethersproject/providers/src.ts/json-rpc-provider.ts:JsonRpcSigner.connect + override connect(_provider: Provider): EthersJsonRpcSigner { + return logger.throwError("cannot alter JSON-RPC Signer connection", Logger.errors.UNSUPPORTED_OPERATION, { + operation: "connect" + }); } + // @ethersproject/providers/src.ts/json-rpc-provider.ts:JsonRpcSigner.connectUnchecked connectUnchecked(): EthersJsonRpcSigner { - return this; + return new UncheckedJsonRpcSigner(this.provider, this._address || this._index); } + // If underlying EIP-1193 provider is Kaikas, return the KIP-97 signed message in which + // the message is prefixed with "\x19Klaytn Signed Message:\n" + len(message) before signing. + // https://kips.klaytn.foundation/KIPs/kip-97 + // + // Otherwise, return the ERC-191 signed message in which the message is prefixed with + // "\x19Ethereum Signed Message:\n" + len(message) before signing. + // https://eips.ethereum.org/EIPS/eip-191 + // + // @ethersproject/providers/src.ts/json-rpc-provider.ts:JsonRpcSigner.signMessage override async signMessage(message: string | Bytes): Promise { const data = ((typeof (message) === "string") ? toUtf8Bytes(message) : message); const address = await this.getAddress(); + try { - return await this.provider.send("personal_sign", [hexlify(data), address.toLowerCase()]); - } catch (error) { - // @ts-ignore - if (typeof (error.message) === "string" && error.message.match(/user denied/i)) { - logger.throwError("user rejected signing", Logger.errors.ACTION_REJECTED, { - action: "signMessage", - from: address, - messageData: message - }); + if (this.isKaikas()) { + // KIP-97 states that the prefixed message signature should be accessible + // through the personal_sign method, but Kaikas provides it as eth_sign. + return await this.provider.send("eth_sign", [address.toLowerCase(), hexlify(data)]); + } else { + // Otherwise, use the standard personal_sign for ERC-191. + return await this.provider.send("personal_sign", [hexlify(data), address.toLowerCase()]); } + } catch (error: any) { + catchUserRejectedSigning(error, "signMessage", address, message); throw error; } } - override checkTransaction(transaction: Deferrable): Deferrable { - return super.checkTransaction(transaction); - } - - override async populateTransaction(transaction: Deferrable): Promise { - return super.populateTransaction(transaction); - } - - override async signTransaction(transaction: Deferrable): Promise { - if (!this.isKaikas()) { - throw new Error("signTransaction is only supported in Kaikas"); + // Return the signature of the message without prefix via the eth_sign method. + // This operation is deprecated in favor of signMessage (ERC-191 or KIP-97). + // + // Some providers may support this operation for backward compatibility, or reject it. + // In Kaikas, eth_sign is reserved for KIP-97 purpose, so the legacy sign message is decisively not supported. + // - If the provider is Kaikas, always throw an error. + // - If the provider is not Kaikas, try the eth_sign method. + // - If the provider rejects the operation, throw an error. + // - If the provider accepts the operation, return the signature. + // https://docs.metamask.io/wallet/concepts/signing-methods/#eth_sign + // https://support.metamask.io/hc/en-us/articles/14764161421467-What-is-eth-sign-and-why-is-it-a-risk- + async _legacySignMessage(message: Bytes | string): Promise { + if (this.isKaikas()) { + logger.throwError("Kaikas does not support the prefix-less legacy sign message", Logger.errors.UNSUPPORTED_OPERATION, { + operation: "_legacySignMessage" + }); } - let signedTx; + // @ethersproject/providers/src.ts/json-rpc-provider.ts:JsonRpcSigner._legacySignMessage + const data = ((typeof (message) === "string") ? toUtf8Bytes(message) : message); + const address = await this.getAddress(); + try { - signedTx = await this.provider.send("klay_signTransaction", [transaction]); + return await this.provider.send("eth_sign", [address.toLowerCase(), hexlify(data)]); } catch (error: any) { - if (typeof (error.message) === "string" && error.message.match(/user denied/i)) { - logger.throwError("user rejected transaction", Logger.errors.ACTION_REJECTED, { - action: "signTransaction", - transaction: transaction - }); - } + catchUserRejectedSigning(error, "_legacySignMessage", address, message); + throw error; } - - return signedTx.rawTransaction; } - override async sendTransaction(transaction: Deferrable): Promise { - // Send the transaction - const txhash = await this.sendUncheckedTransaction(transaction); + // Return the signature of the structured data according to EIP-712 via the eth_signTypedData_v4 method. + // https://eips.ethereum.org/EIPS/eip-712 + // https://docs.metamask.io/wallet/how-to/sign-data/#use-eth_signtypeddata_v4 + async _signTypedData(domain: TypedDataDomain, types: Record>, value: Record): Promise { + if (this.isKaikas()) { + logger.throwError("Kaikas does not support the EIP-712 typed structured data signing", Logger.errors.UNSUPPORTED_OPERATION, { + operation: "_signTypedData" + }); + } - // Retry until the transaction shows up in the txpool - // Using poll() like in the ethers.JsonRpcProvider.sendTransaction - // https://github.com/ethers-io/ethers.js/blob/v5.7/packages/providers/src.ts/json-rpc-provider.ts#L283 - const pollFunc = async () => { - const tx = await this.provider.getTransaction(txhash); - if (tx == null) { - return undefined; // retry - } else { - return tx; // success - } - }; - return poll(pollFunc) as Promise; - } + // @ethersproject/providers/src.ts/json-rpc-provider.ts:JsonRpcSigner._signTypedData + // Populate any ENS names (in-place) + const populated = await _TypedDataEncoder.resolveNames(domain, types, value, (name: string) => { + return this.provider.resolveName(name) as Promise; + }); - async sendUncheckedTransaction(transaction: Deferrable): Promise { - if (this.isKaikas()) { - return this.sendUncheckedTransactionKlaytn(transaction) as Promise; - } else { - return this.sendUncheckedTransactionEth(transaction)as Promise; + const address = await this.getAddress(); + + try { + return await this.provider.send("eth_signTypedData_v4", [ + address.toLowerCase(), + JSON.stringify(_TypedDataEncoder.getPayload(populated.domain, types, populated.value)) + ]); + } catch (error: any) { + catchUserRejectedSigning(error, "_signTypedData", address, { domain: populated.domain, types, value: populated.value }); + throw error; } } - async sendUncheckedTransactionEth(transaction: Deferrable): Promise { + override checkTransaction(transaction: Deferrable): Deferrable { + const tx = _.clone(transaction); + const expectedFrom = this.getAddress(); + populateFromSync(tx, expectedFrom); + return tx; + } + + override async populateTransaction(transaction: Deferrable): Promise { const tx = await getTransactionRequest(transaction); - if (!tx.from) { - tx.from = await this.getAddress(); + // Not a Klaytn TxType; fallback to ethers.Signer.populateTransaction() + if (!isKlaytnTxType(resolveType(tx.type))) { + return super.populateTransaction(tx); } - if (!tx.gasLimit) { - tx.gasLimit = await this.provider.estimateGas(tx); - } + await populateFrom(tx, await this.getAddress()); + await populateTo(tx, this.provider); + await populateNonce(tx, this.provider, await this.getAddress()); + await populateGasLimit(tx, this.provider); + await populateGasPrice(tx, this.provider); + await populateChainId(tx, this.provider); + return tx; + } - if (tx.to) { - const toAddress = await this.provider.resolveName(tx.to); - if (toAddress == null) { - logger.throwArgumentError("provided ENS name resolves to null", "tx.to", tx.to); - } else { - tx.to = toAddress; - } + // Return the signed transaction as a string but do not send it. + override async signTransaction(transaction: Deferrable): Promise { + if (!this.isKaikas()) { + return logger.throwError("signing transactions is only supported in Kaikas", Logger.errors.UNSUPPORTED_OPERATION, { + operation: "signTransaction" + }); } - const fromAddress = await this.getAddress(); - if (tx.from && tx.from.toLowerCase() != fromAddress.toLowerCase()) { - logger.throwArgumentError("from address mismatch", "transaction", transaction); - } + const tx = await getTransactionRequest(transaction); + await populateFrom(tx, await this.getAddress()); + await populateGasLimit(tx, this.provider); + await populateTo(tx, this.provider); - return this.provider.send("eth_sendTransaction", [tx]).then((hash) => { - return hash; - }, (error) => { - if (typeof (error.message) === "string" && error.message.match(/user denied/i)) { - logger.throwError("user rejected transaction", Logger.errors.ACTION_REJECTED, { - action: "sendTransaction", - transaction: tx - }); - } + const rpcTx = getRpcTxObject(tx); + if (this.isKaikas()) { + rpcTx.type = resolveTypeForKaikas(rpcTx.type); + } - // return checkError("sendTransaction", error, hexTx); - }); + try { + // Kaikas returns the web3-style signed transaction object. + const signedTx = await this.provider.send("klay_signTransaction", [rpcTx]); + return Promise.resolve(signedTx.rawTransaction); + } catch (error: any) { + catchUserRejectedTransaction(error, "signTransaction", transaction); + throw error; + } } + override async sendTransaction(transaction: Deferrable): Promise { + const txhash = await this.sendUncheckedTransaction(transaction); + return pollTransactionInPool(txhash, this.provider); + } - async sendUncheckedTransactionKlaytn(transaction: Deferrable): Promise { + async sendUncheckedTransaction(transaction: Deferrable): Promise { const tx = await getTransactionRequest(transaction); + await populateFrom(tx, await this.getAddress()); + await populateGasLimit(tx, this.provider); + await populateTo(tx, this.provider); - if (!tx.from) { - tx.from = await this.getAddress(); - } - - if (!tx.gasLimit) { - tx.gasLimit = await this.provider.estimateGas(tx); + const rpcTx = getRpcTxObject(tx); + if (this.isKaikas()) { + rpcTx.type = resolveTypeForKaikas(rpcTx.type); } + console.log(rpcTx); - if (tx.to) { - const toAddress = await this.provider.resolveName(tx.to); - if (toAddress == null) { - logger.throwArgumentError("provided ENS name resolves to null", "tx.to", tx.to); + try { + if (this.isKaikas()) { + return await this.provider.send("klay_sendTransaction", [rpcTx]); } else { - tx.to = toAddress; + return await this.provider.send("eth_sendTransaction", [rpcTx]); } + } catch (error: any) { + catchUserRejectedTransaction(error, "sendTransaction", tx); + throw error; } - - const fromAddress = await this.getAddress(); - if (tx.from && tx.from.toLowerCase() != fromAddress.toLowerCase()) { - logger.throwArgumentError("from address mismatch", "transaction", transaction); - } - - // It must be changed to the following format like (TxType.ValueTransfer -> VALUE_TRANSFER) - const rpcTx = getRpcTxObject(tx); - rpcTx.type = _.snakeCase(TxType[tx.type || 0]).toUpperCase(); - console.log("sending", rpcTx); - - return this.provider.send("klay_sendTransaction", [rpcTx]).then((hash) => { - return hash; - }, (error) => { - if (typeof (error.message) === "string" && error.message.match(/user denied/i)) { - logger.throwError("user rejected transaction", Logger.errors.ACTION_REJECTED, { - action: "sendTransaction", - transaction: tx - }); - } - - // return checkError("sendTransaction", error, hexTx); - }); - } - - async _legacySignMessage(message: Bytes | string): Promise { - throw new Error("Legacy eth_sign not supported"); - } - - async _signTypedData(domain: TypedDataDomain, types: Record>, value: Record): Promise { - throw new Error("eth_signTypedData_v4 not supported"); } async unlock(password: string): Promise { @@ -609,4 +495,41 @@ export class JsonRpcSigner extends EthersSigner implements EthersJsonRpcSigner { } } +// Variant of JsonRpcSigner where it does not wait for the transaction to be in the txpool. +// @ethersproject/providers/src.ts/json-rpc-provider.ts:UncheckedJsonRpcSigner +class UncheckedJsonRpcSigner extends JsonRpcSigner { + override async sendTransaction(transaction: Deferrable): Promise { + const txhash = await this.sendUncheckedTransaction(transaction); + return Promise.resolve({ + hash: txhash, + nonce: null, + gasLimit: null, + gasPrice: null, + data: null, + value: null, + chainId: null, + confirmations: 0, + from: null, + wait: (confirmations?: number) => { return this.provider.waitForTransaction(txhash, confirmations); } + } as unknown as TransactionResponse); // forcefully cast to TransactionResponse + } +} +function catchUserRejectedSigning(error: any, action: string, from: string, messageData: any) { + if (typeof(error.message) === "string" && error.message.match(/user denied/i)) { + logger.throwError("user rejected signing", Logger.errors.ACTION_REJECTED, { + action, + from, + messageData, + }); + } +} + +function catchUserRejectedTransaction(error: any, action: string, transaction: any) { + if (typeof (error.message) === "string" && error.message.match(/user denied/i)) { + logger.throwError("user rejected transaction", Logger.errors.ACTION_REJECTED, { + action, + transaction, + }); + } +} \ No newline at end of file diff --git a/ethers-ext/src/txutil.ts b/ethers-ext/src/txutil.ts new file mode 100644 index 000000000..798d14ce3 --- /dev/null +++ b/ethers-ext/src/txutil.ts @@ -0,0 +1,216 @@ +import { Provider, TransactionResponse } from "@ethersproject/abstract-provider"; +import { BigNumber } from "@ethersproject/bignumber"; +import { Signature } from "@ethersproject/bytes"; +import { AddressZero } from "@ethersproject/constants"; +import { Logger } from "@ethersproject/logger"; +import { Deferrable, resolveProperties } from "@ethersproject/properties"; +import { SigningKey } from "@ethersproject/signing-key"; +import { poll } from "@ethersproject/web"; +import _ from "lodash"; + +import { HexStr, TxType, isKlaytnTxType, parseTransaction } from "@klaytn/js-ext-core"; + +import { TransactionRequest } from "./types"; + +const logger = new Logger("@klaytn/ethers-ext"); + + +// Normalize transaction request in Object or RLP format +export async function getTransactionRequest(transactionOrRLP: Deferrable | string): Promise { + if (_.isString(transactionOrRLP)) { + return parseTransaction(transactionOrRLP) as TransactionRequest; + } else { + return resolveProperties(transactionOrRLP); + } +} + +export function resolveType(type?: number | string): number { + if (!type) { + return 0; + } + if (_.isNumber(type)) { + return type; + } + if (_.isString(type)) { + // Try the hex string, e.g. "0x08" + if (HexStr.isHex(type)) { + return HexStr.toNumber(type); + } + } + throw new Error(`Unrecognized tx type '${type}'. Must be a number.'`); +} + +// Convert tx.type field to what Kaikas wants. +// - If unspecified, keep it as-is. undefined => undefined +// - Ethereum types are kept as-is. 0,1,2 => 0,1,2 +// - Klaytn types are converted to string. 8 => "VALUE_TRANSFER" +export function resolveTypeForKaikas(type?: string | number): string | number | undefined { + // Skip type == 0 or undefined + if (!type) { + return undefined; + } + + if (_.isString(type)) { + if (HexStr.isHex(type)) { + // Try the hex string, e.g. "0x08" + return resolveTypeForKaikas(HexStr.toNumber(type)); + } else { + // Pass-through if type is already string. Let Kaikas handle it. + return type; + } + } + + if (_.isNumber(type)) { + if (!isKlaytnTxType(type)) { + // Pass-through Ethereum TxTypes as number + return type; + } + + const camelName: string | undefined = TxType[type]; + if (camelName) { + // "ValueTransfer" => "VALUE_TRANSFER" + return _.snakeCase(camelName).toUpperCase(); + } + } + + throw new Error(`Unrecognized tx type '${type}'.`); +} + +// Below populateX() methods are partial replacements to: +// - ethers.Signer.checkTransaction() +// - ethers.Signer.populateTransaction() +// - ethers.JsonRpcSigner.sendUncheckedTransaction() + +// populateFromSync is a synchronous method so it can be used in checkTransaction(). +export function populateFromSync(tx: Deferrable, expectedFrom: string | Promise) { + // See @ethersproject/abstract-signer/src/index.ts:Signer.checkTransaction() + if (!tx.from) { + tx.from = expectedFrom; + } else { + tx.from = Promise.all([ + Promise.resolve(tx.from), + expectedFrom, + ]).then(([from, expectedFrom]) => { + if (from?.toLowerCase() != expectedFrom?.toLowerCase()) { + logger.throwArgumentError(`from address mismatch (wallet address=${expectedFrom}) (tx.from=${from})`, "transaction", tx); + } + return from; + }); + } +} + +export async function populateFrom(tx: TransactionRequest, expectedFrom: string) { + populateFromSync(tx, expectedFrom); + tx.from = await tx.from; +} + +export async function populateTo(tx: TransactionRequest, provider: Provider) { + if (!tx.to) { + tx.to = AddressZero; + } else { + const address = await provider.resolveName(tx.to); + if (address == null) { + logger.throwArgumentError("provided ENS name resolves to null", "tx.to", tx.to); + } + } +} + +export async function populateNonce(tx: TransactionRequest, provider: Provider, fromAddress: string) { + if (!tx.nonce) { + tx.nonce = await provider.getTransactionCount(fromAddress); + } +} + +export async function populateGasLimit(tx: TransactionRequest, provider: Provider) { + if (!tx.gasLimit) { + // Sometimes Klaytn node's eth_estimateGas may return insufficient amount. + // To avoid this, add buffer to the estimated gas. + // References: + // - ethers.js uses estimateGas result as-is. + // - Metamask multiplies by 1 or 1.5 depending on chainId + // (https://github.com/MetaMask/metamask-extension/blob/v11.3.0/ui/ducks/send/helpers.js#L126) + // TODO: To minimize buffer, add constant intrinsic gas overhead instead of multiplier. + try { + const bufferMultiplier = 2.5; + const gasLimit = await provider.estimateGas(tx); + tx.gasLimit = Math.ceil(gasLimit.toNumber() * bufferMultiplier); + } catch (error) { + logger.throwError("cannot estimate gas; transaction may fail or may require manual gas limit", Logger.errors.UNPREDICTABLE_GAS_LIMIT, { + error: error, + tx: tx + }); + } + } +} + +export async function populateGasPrice(tx: TransactionRequest, provider: Provider) { + if (!tx.gasPrice) { + tx.gasPrice = await provider.getGasPrice(); + } +} + +export function eip155sign(key: SigningKey, digest: string, chainId: number): Signature { + const sig = key.signDigest(digest); + sig.v = sig.recoveryParam + chainId * 2 + 35; + return sig; +} + +// Extract chainId from tx.txSignatures[] or tx.feePayerSignatures[]. +// It works because Klaytn TxType always follows EIP-155. +function chainIdFromSig(signatures?: any[]): number | undefined { + if (_.isArray(signatures) && signatures.length > 0) { + const signature = signatures[0]; + if (_.isArray(signature) && signature.length == 3) { + const v = BigNumber.from(signature[0]).toNumber(); + if (v >= 35) { + return (v + (v % 2) - 36) / 2; + } + } + } + return undefined; +} + +export async function populateChainId(tx: TransactionRequest, provider: Provider) { + if (!tx.chainId) { + tx.chainId = ( + chainIdFromSig(tx.txSignatures) ?? + chainIdFromSig(tx.feePayerSignatures) ?? + (await provider.getNetwork()).chainId); + } +} + +export async function populateFeePayerAndSignatures(tx: TransactionRequest, expectedFeePayer: string) { + // A SenderTxHashRLP returned from caver may have dummy feePayer even if SenderTxHashRLP shouldn't have feePayer. + // So ignore AddressZero in the feePayer field. + if (!tx.feePayer || tx.feePayer == AddressZero) { + tx.feePayer = expectedFeePayer; + } else { + if (tx.feePayer.toLowerCase() != expectedFeePayer.toLowerCase()) { + logger.throwArgumentError("feePayer address mismatch", "transaction", tx); + } + } + + // A SenderTxHashRLP returned from caver may have dummy feePayerSignatures if SenderTxHashRLP shouldn't have feePayerSignatures. + // So ignore [ '0x01', '0x', '0x' ] in the feePayerSignatures field. + if (_.isArray(tx.feePayerSignatures)) { + tx.feePayerSignatures = tx.feePayerSignatures.filter((sig) => { + return !(_.isArray(sig) && sig.length == 3 && sig[0] == "0x01" && sig[1] == "0x" && sig[2] == "0x"); + }); + } +} + +// Poll for `eth_getTransaction` until the transaction is found in the transaction pool. +export async function pollTransactionInPool(txhash: string, provider: Provider): Promise { + // Retry until the transaction shows up in the txpool + // Using poll() like in the ethers.JsonRpcSigner.sendTransaction + // https://github.com/ethers-io/ethers.js/blob/v5.7/packages/providers/src.ts/json-rpc-provider.ts#L283 + const pollFunc = async () => { + const tx = await provider.getTransaction(txhash); + if (tx == null) { + return undefined; // retry + } else { + return tx; // success + } + }; + return poll(pollFunc) as Promise; +} \ No newline at end of file diff --git a/ethers-ext/src/types.ts b/ethers-ext/src/types.ts new file mode 100644 index 000000000..6e253fcdb --- /dev/null +++ b/ethers-ext/src/types.ts @@ -0,0 +1,20 @@ +import { TransactionRequest as EthersTransactionRequest } from "@ethersproject/abstract-provider"; +import { ExternallyOwnedAccount } from "@ethersproject/abstract-signer"; +import { ExternalProvider as EthersExternalProvider } from "@ethersproject/providers"; +import { SigningKey } from "@ethersproject/signing-key"; +import { BytesLike } from "ethers"; + + +export interface TransactionRequest extends EthersTransactionRequest { + txSignatures?: any[]; + feePayer?: string; + feePayerSignatures?: any[]; +} + +// Used in Wallet constructor. +export type PrivateKeyLike = BytesLike | ExternallyOwnedAccount | SigningKey; + +// Represents window.ethereum (MetaMask) and window.klaytn (Kaikas) +export interface ExternalProvider extends EthersExternalProvider { + isKaikas?: boolean; // Exists in window.klaytn that is injected by Kaikas +} \ No newline at end of file diff --git a/ethers-ext/test/signer.spec.ts b/ethers-ext/test/signer.spec.ts index ce2ebef8a..3069adf8b 100644 --- a/ethers-ext/test/signer.spec.ts +++ b/ethers-ext/test/signer.spec.ts @@ -1,3 +1,4 @@ +import { AddressZero } from "@ethersproject/constants"; import { keccak256 } from "@ethersproject/keccak256"; import chai, { assert, expect } from "chai"; import chaiAsPromised from "chai-as-promised"; @@ -5,7 +6,7 @@ import { Wallet as EthersWallet } from "ethers"; import _ from "lodash"; import { describe, it } from "mocha"; -import { Wallet as KlaytnWallet } from "../src"; +import { KlaytnTxFactory, Wallet as KlaytnWallet, parseTransaction } from "../src"; import { MockEthersProvider, MockKlaytnProvider } from "./mock_provider"; @@ -24,12 +25,16 @@ const nonce = 2; const gasPrice = 25e9; const gasLimit = 50000; const chainId = 1001; -const txHashRLP = "0x08f87a8204d219830f4240947b65b75d204abed71587c9e519a89277766ee1d00a94a94f5374fce5edbc8e2a8697c15331677e6ebf0bf845f84325a0f3d0cd43661cabf53425535817c5058c27781f478cb5459874feaa462ed3a29aa06748abe186269ff10b8100a4b7d7fea274b53ea2905acbf498dc8b5ab1bf4fbc"; -const senderTxHashRLP = "0x09f87a8204d219830f4240947b65b75d204abed71587c9e519a89277766ee1d00a94a94f5374fce5edbc8e2a8697c15331677e6ebf0bf845f84325a09f8e49e2ad84b0732984398749956e807e4b526c786af3c5f7416b293e638956a06bf88342092f6ff9fabe31739b2ebfa1409707ce54a54693e91a6b9bb77df0e7"; -const txSignatures = [["0x25", "0x9f8e49e2ad84b0732984398749956e807e4b526c786af3c5f7416b293e638956", "0x6bf88342092f6ff9fabe31739b2ebfa1409707ce54a54693e91a6b9bb77df0e7"]]; + +const txHashRLP = "0x08f87e028505d21dba0082c3509470997970c51812dc3a010c7d01b50e0d17dc79c8809490f79bf6eb2c4f870365e785982e1f101e93b906f847f8458207f5a0e16b4d0efd52c217dc3d868834cd1dc7a36f793acf8f4558a3de0eb9a62869fba02fe50e20b55ea59a41678eab633696db728c65755e5fe1d72cb4c006fafad67b"; +const senderTxHashRLP_fit = "0x09f880821922850ba43b740082cd149470997970c51812dc3a010c7d01b50e0d17dc79c88094f39fd6e51aad88f6f4ce6ab8827279cfffb92266f847f8458207f5a003b5e4371caae44de62e9b2c799b9744d46e84c3309b704cfa276cc6659671f8a0453a40c726a6f5e6fb32e54fc3279508c48cb54e589982c3f01580209a8b0c02"; +const senderTxHashRLP_pad = "0x09f89a821922850ba43b740082cd149470997970c51812dc3a010c7d01b50e0d17dc79c88094f39fd6e51aad88f6f4ce6ab8827279cfffb92266f847f8458207f5a003b5e4371caae44de62e9b2c799b9744d46e84c3309b704cfa276cc6659671f8a0453a40c726a6f5e6fb32e54fc3279508c48cb54e589982c3f01580209a8b0c02940000000000000000000000000000000000000000c4c3018080"; +const txSignatures = [["0x7f5", "0x9f8e49e2ad84b0732984398749956e807e4b526c786af3c5f7416b293e638956", "0x6bf88342092f6ff9fabe31739b2ebfa1409707ce54a54693e91a6b9bb77df0e7"]]; + const block = JSON.parse('{"difficulty":"0x1","extraData":"0x","gasLimit":"0xe8d4a50fff","gasUsed":"0x0","hash":"0xe6a28d57db4dec9eacad5e6ce3d90fef900ab65760c579c46567b4bbb3803bc2","logsBloom":"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000","miner":"0x571e53df607be97431a5bbefca1dffe5aef56f4d","mixHash":"0x0000000000000000000000000000000000000000000000000000000000000000","nonce":"0x0000000000000000","number":"0x12d687","parentHash":"0x720ed13d78e8b0f2c20f4129b9b69dcbad49eebecfc2bb22e792be5ea28ecbfc","receiptsRoot":"0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470","sha3Uncles":"0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","size":"0x33b","stateRoot":"0xd3db6e4adfc526b5028764512e338d0ff3d8bc76e02593a763ac747ed8a22112","timestamp":"0x5d261b95","totalDifficulty":"0x12d688","transactions":[],"transactionsRoot":"0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470","uncles":[]}'); const txJson = JSON.parse('{"blockHash":"0x1d59ff54b1eb26b013ce3cb5fc9dab3705b415a67127a003c3e61eb445bb8df2","blockNumber":"0x5daf3b","hash":"0x88df016429689c079f3b2f6ad39fa052532c56795b733da78a91ebe6a713944b","from":"0xa7d9ddbe1f17865597fbd27ec712455208b6b76d","gas":"0xc350","gasPrice":"0x4a817c800","input":"0x68656c6c6f21","nonce":"0x15","r":"0x1b5e176d927f8e9ab405058b2d2457392da3e20f328b16ddabcebc33eaac5fea","s":"0x4ba69724e8f69de52f0125ad8b3c5c2cef33019bac3249e2c0a2192766d1721c","to":"0xf02c1c8e6114b1dbe8937a39260b5b0a374432bb","transactionIndex":"0x41","type":"0x0","v":"0x25","value":"0xf3dbb76162000"}'); + describe("Wallet", () => { let EP: MockEthersProvider; let KP: MockKlaytnProvider; @@ -118,9 +123,6 @@ describe("Wallet", () => { }); // populateTransaction must fill all missing fields - // - from, nonce, gasPrice, gasLimit correctly added as resolved (not Promise) types - // - Only check field existence because values depend on network state. - // - Original tx object remain untouched describe("populateTransaction", () => { async function testOK(W: EthersWallet, tx: any) { let res = await W.populateTransaction(tx); @@ -169,7 +171,8 @@ describe("Wallet", () => { await testOK_AsFeePayer(W, { type: 9, from, to, feePayer: (await W.getAddress()), value, nonce, gasPrice, gasLimit, chainId, txSignatures }); } for (let W of [KW, KWD]) { - await testOK_AsFeePayer(W, senderTxHashRLP); + await testOK_AsFeePayer(W, senderTxHashRLP_fit); + await testOK_AsFeePayer(W, senderTxHashRLP_pad); } }); }); @@ -185,11 +188,14 @@ describe("Wallet", () => { assert.isDefined(res.hash); assert.isDefined(res.wait); } - async function testOK_AsFeePayer(W: KlaytnWallet, tx: any) { + async function testOK_AsFeePayer(W: KlaytnWallet, tx: any, expectedFrom?: string) { let res = await W.sendTransactionAsFeePayer(tx); assert.isDefined(res); assert.isDefined(res.hash); assert.isDefined(res.wait); + + expectedFrom ??= await W.getAddress(); + assert.equal(parseTransaction(sentRawTx).from, expectedFrom); } it("as sender", async () => { @@ -200,12 +206,16 @@ describe("Wallet", () => { await testOK(W, { type: 9, to, feePayer, value }); } }); + // 'from' address differs from W.getAddress() + // because W is the fee payer, not the sender. + // The sentRawTx must have the original 'from' address, not fee payer's. it("as fee payer", async () => { for (let W of [KW, KWD]) { - await testOK_AsFeePayer(W, { type: 9, to, feePayer: (await W.getAddress()), value, nonce, gasPrice, gasLimit, chainId, txSignatures }); + await testOK_AsFeePayer(W, { type: 9, from, to, feePayer: (await W.getAddress()), value, nonce, gasPrice, gasLimit, chainId, txSignatures }, from); } for (let W of [KW, KWD]) { - await testOK_AsFeePayer(W, senderTxHashRLP); + await testOK_AsFeePayer(W, senderTxHashRLP_fit, from); + await testOK_AsFeePayer(W, senderTxHashRLP_pad, from); } }); }); From 3125bdefd11e050dd358bf4b2e826d8a48072aee Mon Sep 17 00:00:00 2001 From: "ollie.j" Date: Mon, 18 Dec 2023 16:10:42 +0900 Subject: [PATCH 28/33] ethers: Directly depend on @ethersproject packages --- ethers-ext/package-lock.json | 572 ++------------------------------- ethers-ext/package.json | 22 +- ethers-ext/src/accountStore.ts | 4 +- ethers-ext/src/types.ts | 2 +- 4 files changed, 47 insertions(+), 553 deletions(-) diff --git a/ethers-ext/package-lock.json b/ethers-ext/package-lock.json index 428c90e38..d40eedbe5 100644 --- a/ethers-ext/package-lock.json +++ b/ethers-ext/package-lock.json @@ -1,20 +1,37 @@ { "name": "@klaytn/ethers-ext", - "version": "0.9.7-beta", + "version": "0.9.8-beta", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@klaytn/ethers-ext", - "version": "0.9.7-beta", + "version": "0.9.8-beta", "license": "MIT", "dependencies": { + "@ethersproject/abstract-provider": "^5.7.0", + "@ethersproject/abstract-signer": "^5.7.0", + "@ethersproject/address": "^5.7.0", + "@ethersproject/bignumber": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/constants": "^5.7.0", + "@ethersproject/hash": "^5.7.0", + "@ethersproject/json-wallets": "^5.7.0", + "@ethersproject/keccak256": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/networks": "^5.7.1", + "@ethersproject/properties": "^5.7.0", + "@ethersproject/providers": "^5.7.2", + "@ethersproject/signing-key": "^5.7.0", + "@ethersproject/strings": "^5.7.0", + "@ethersproject/transactions": "^5.7.0", + "@ethersproject/wallet": "^5.7.0", + "@ethersproject/web": "^5.7.1", "@klaytn/js-ext-core": "^0.9.8-beta", "@klaytn/web3rpc": "^0.9.8", "lodash": "^4.17.21" }, "devDependencies": { - "@klaytn/ethers-ext": "^0.9.8-beta", "@types/chai": "^4.3.7", "@types/chai-as-promised": "^7.1.5", "@types/lodash": "^4.14.192", @@ -32,9 +49,6 @@ "webpack": "^5.89.0", "webpack-cli": "^5.1.4", "webpack-visualizer-plugin2": "^1.1.0" - }, - "peerDependencies": { - "ethers": "^5.7.2" } }, "node_modules/@aashutoshrathi/word-wrap": { @@ -536,15 +550,6 @@ "node": ">=6.9.0" } }, - "node_modules/@colors/colors": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.6.0.tgz", - "integrity": "sha512-Ir+AOibqzrIsL6ajt3Rz3LskB7OiMVHqltZmspbW/TJuTVuyOMirVqAkjfY6JISiLHgyNqicAC8AyHHGzNd/dA==", - "dev": true, - "engines": { - "node": ">=0.1.90" - } - }, "node_modules/@cspotcode/source-map-support": { "version": "0.8.1", "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", @@ -557,17 +562,6 @@ "node": ">=12" } }, - "node_modules/@dabh/diagnostics": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/@dabh/diagnostics/-/diagnostics-2.0.3.tgz", - "integrity": "sha512-hrlQOIi7hAfzsMqlGSFyVucrx38O+j6wiGOf//H2ecvIEqYN4ADBSS2iLMh5UFyDunCNniUIPk/q3riFv45xRA==", - "dev": true, - "dependencies": { - "colorspace": "1.1.x", - "enabled": "2.0.x", - "kuler": "^2.0.0" - } - }, "node_modules/@discoveryjs/json-ext": { "version": "0.5.7", "resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz", @@ -670,33 +664,6 @@ "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } }, - "node_modules/@ethersproject/abi": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/@ethersproject/abi/-/abi-5.7.0.tgz", - "integrity": "sha512-351ktp42TiRcYB3H1OP8yajPeAQstMW/yCFokj/AthP9bLHzQFPlOrxOcwYEDkUAICmOHljvN4K39OMTMUa9RA==", - "funding": [ - { - "type": "individual", - "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], - "peer": true, - "dependencies": { - "@ethersproject/address": "^5.7.0", - "@ethersproject/bignumber": "^5.7.0", - "@ethersproject/bytes": "^5.7.0", - "@ethersproject/constants": "^5.7.0", - "@ethersproject/hash": "^5.7.0", - "@ethersproject/keccak256": "^5.7.0", - "@ethersproject/logger": "^5.7.0", - "@ethersproject/properties": "^5.7.0", - "@ethersproject/strings": "^5.7.0" - } - }, "node_modules/@ethersproject/abstract-provider": { "version": "5.7.0", "resolved": "https://registry.npmjs.org/@ethersproject/abstract-provider/-/abstract-provider-5.7.0.tgz", @@ -711,7 +678,6 @@ "url": "https://www.buymeacoffee.com/ricmoo" } ], - "peer": true, "dependencies": { "@ethersproject/bignumber": "^5.7.0", "@ethersproject/bytes": "^5.7.0", @@ -736,7 +702,6 @@ "url": "https://www.buymeacoffee.com/ricmoo" } ], - "peer": true, "dependencies": { "@ethersproject/abstract-provider": "^5.7.0", "@ethersproject/bignumber": "^5.7.0", @@ -781,7 +746,6 @@ "url": "https://www.buymeacoffee.com/ricmoo" } ], - "peer": true, "dependencies": { "@ethersproject/bytes": "^5.7.0" } @@ -800,7 +764,6 @@ "url": "https://www.buymeacoffee.com/ricmoo" } ], - "peer": true, "dependencies": { "@ethersproject/bytes": "^5.7.0", "@ethersproject/properties": "^5.7.0" @@ -862,34 +825,6 @@ "@ethersproject/bignumber": "^5.7.0" } }, - "node_modules/@ethersproject/contracts": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/@ethersproject/contracts/-/contracts-5.7.0.tgz", - "integrity": "sha512-5GJbzEU3X+d33CdfPhcyS+z8MzsTrBGk/sc+G+59+tPa9yFkl6HQ9D6L0QMgNTA9q8dT0XKxxkyp883XsQvbbg==", - "funding": [ - { - "type": "individual", - "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], - "peer": true, - "dependencies": { - "@ethersproject/abi": "^5.7.0", - "@ethersproject/abstract-provider": "^5.7.0", - "@ethersproject/abstract-signer": "^5.7.0", - "@ethersproject/address": "^5.7.0", - "@ethersproject/bignumber": "^5.7.0", - "@ethersproject/bytes": "^5.7.0", - "@ethersproject/constants": "^5.7.0", - "@ethersproject/logger": "^5.7.0", - "@ethersproject/properties": "^5.7.0", - "@ethersproject/transactions": "^5.7.0" - } - }, "node_modules/@ethersproject/hash": { "version": "5.7.0", "resolved": "https://registry.npmjs.org/@ethersproject/hash/-/hash-5.7.0.tgz", @@ -904,7 +839,6 @@ "url": "https://www.buymeacoffee.com/ricmoo" } ], - "peer": true, "dependencies": { "@ethersproject/abstract-signer": "^5.7.0", "@ethersproject/address": "^5.7.0", @@ -931,7 +865,6 @@ "url": "https://www.buymeacoffee.com/ricmoo" } ], - "peer": true, "dependencies": { "@ethersproject/abstract-signer": "^5.7.0", "@ethersproject/basex": "^5.7.0", @@ -961,7 +894,6 @@ "url": "https://www.buymeacoffee.com/ricmoo" } ], - "peer": true, "dependencies": { "@ethersproject/abstract-signer": "^5.7.0", "@ethersproject/address": "^5.7.0", @@ -1026,7 +958,6 @@ "url": "https://www.buymeacoffee.com/ricmoo" } ], - "peer": true, "dependencies": { "@ethersproject/logger": "^5.7.0" } @@ -1045,7 +976,6 @@ "url": "https://www.buymeacoffee.com/ricmoo" } ], - "peer": true, "dependencies": { "@ethersproject/bytes": "^5.7.0", "@ethersproject/sha2": "^5.7.0" @@ -1083,7 +1013,6 @@ "url": "https://www.buymeacoffee.com/ricmoo" } ], - "peer": true, "dependencies": { "@ethersproject/abstract-provider": "^5.7.0", "@ethersproject/abstract-signer": "^5.7.0", @@ -1121,7 +1050,6 @@ "url": "https://www.buymeacoffee.com/ricmoo" } ], - "peer": true, "dependencies": { "@ethersproject/bytes": "^5.7.0", "@ethersproject/logger": "^5.7.0" @@ -1160,7 +1088,6 @@ "url": "https://www.buymeacoffee.com/ricmoo" } ], - "peer": true, "dependencies": { "@ethersproject/bytes": "^5.7.0", "@ethersproject/logger": "^5.7.0", @@ -1190,30 +1117,6 @@ "hash.js": "1.1.7" } }, - "node_modules/@ethersproject/solidity": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/@ethersproject/solidity/-/solidity-5.7.0.tgz", - "integrity": "sha512-HmabMd2Dt/raavyaGukF4XxizWKhKQ24DoLtdNbBmNKUOPqwjsKQSdV9GQtj9CBEea9DlzETlVER1gYeXXBGaA==", - "funding": [ - { - "type": "individual", - "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], - "peer": true, - "dependencies": { - "@ethersproject/bignumber": "^5.7.0", - "@ethersproject/bytes": "^5.7.0", - "@ethersproject/keccak256": "^5.7.0", - "@ethersproject/logger": "^5.7.0", - "@ethersproject/sha2": "^5.7.0", - "@ethersproject/strings": "^5.7.0" - } - }, "node_modules/@ethersproject/strings": { "version": "5.7.0", "resolved": "https://registry.npmjs.org/@ethersproject/strings/-/strings-5.7.0.tgz", @@ -1228,7 +1131,6 @@ "url": "https://www.buymeacoffee.com/ricmoo" } ], - "peer": true, "dependencies": { "@ethersproject/bytes": "^5.7.0", "@ethersproject/constants": "^5.7.0", @@ -1295,7 +1197,6 @@ "url": "https://www.buymeacoffee.com/ricmoo" } ], - "peer": true, "dependencies": { "@ethersproject/abstract-provider": "^5.7.0", "@ethersproject/abstract-signer": "^5.7.0", @@ -1328,7 +1229,6 @@ "url": "https://www.buymeacoffee.com/ricmoo" } ], - "peer": true, "dependencies": { "@ethersproject/base64": "^5.7.0", "@ethersproject/bytes": "^5.7.0", @@ -1351,7 +1251,6 @@ "url": "https://www.buymeacoffee.com/ricmoo" } ], - "peer": true, "dependencies": { "@ethersproject/bytes": "^5.7.0", "@ethersproject/hash": "^5.7.0", @@ -1468,37 +1367,6 @@ "@jridgewell/sourcemap-codec": "^1.4.10" } }, - "node_modules/@klaytn/ethers-ext": { - "version": "0.9.8-beta", - "resolved": "https://registry.npmjs.org/@klaytn/ethers-ext/-/ethers-ext-0.9.8-beta.tgz", - "integrity": "sha512-963ED7xc+5Pb2VpvNpxJAeSFzVXc7T5K3zZUA4kA6Dt8NB3EsEH6ap5hscqNVoIxkbIElZgbmUEkgrRAzeVJbw==", - "dev": true, - "dependencies": { - "@klaytn/js-ext-core": "^0.9.7-beta", - "@klaytn/web3rpc": "^0.9.7", - "lodash": "^4.17.21" - }, - "peerDependencies": { - "ethers": "^5.7.2" - } - }, - "node_modules/@klaytn/ethers-ext/node_modules/@klaytn/js-ext-core": { - "version": "0.9.7-beta", - "resolved": "https://registry.npmjs.org/@klaytn/js-ext-core/-/js-ext-core-0.9.7-beta.tgz", - "integrity": "sha512-dgoO8zPuPA3LQRdUic9VW2c1UIjRpnP8BbKxEWjmrjmZ6GF0rYCqIu1onV7qvq0O8dDCKg7/bGDC4rpBnhFlxQ==", - "dev": true, - "dependencies": { - "@ethersproject/address": "^5.7.0", - "@ethersproject/bignumber": "^5.7.0", - "@ethersproject/bytes": "^5.7.0", - "@ethersproject/rlp": "^5.7.0", - "@ethersproject/transactions": "^5.7.0", - "@ethersproject/units": "^5.7.0", - "build": "^0.1.4", - "elliptic": "^6.5.4", - "lodash": "^4.17.21" - } - }, "node_modules/@klaytn/js-ext-core": { "version": "0.9.8-beta", "resolved": "https://registry.npmjs.org/@klaytn/js-ext-core/-/js-ext-core-0.9.8-beta.tgz", @@ -1654,9 +1522,9 @@ "dev": true }, "node_modules/@types/node": { - "version": "18.15.11", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.15.11.tgz", - "integrity": "sha512-E5Kwq2n4SbMzQOn6wnmBjuK9ouqlURrcZDVfbo9ftDDTFt3nk7ZKK4GMOzoYgnpQJKcxwQw+lGaBvvlMo0qN/Q==", + "version": "18.15.13", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.15.13.tgz", + "integrity": "sha512-N+0kuo9KgrUQ1Sn/ifDXsvg0TTleP7rIy4zOBGECxAljqvqfqpTfzx0Q1NUedOixRMBfe2Whhb056a42cWs26Q==", "dev": true }, "node_modules/@types/semver": { @@ -1665,12 +1533,6 @@ "integrity": "sha512-G8hZ6XJiHnuhQKR7ZmysCeJWE08o8T0AXtk5darsCaTVsYZhhgUrq53jizaR2FvsoeCwJhlmwTjkXBY5Pn/ZHw==", "dev": true }, - "node_modules/@types/triple-beam": { - "version": "1.3.5", - "resolved": "https://registry.npmjs.org/@types/triple-beam/-/triple-beam-1.3.5.tgz", - "integrity": "sha512-6WaYesThRMCl19iryMYP7/x2OVgCtbIVflDGFpWnb9irXI3UjYE4AzmYuiUKY1AJstGijoY+MgUszMgRxIYTYw==", - "dev": true - }, "node_modules/@typescript-eslint/eslint-plugin": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.1.0.tgz", @@ -2205,8 +2067,7 @@ "node_modules/aes-js": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/aes-js/-/aes-js-3.0.0.tgz", - "integrity": "sha512-H7wUZRn8WpTq9jocdxQ2c8x2sKo9ZVmzfRE13GiNJXfp7NcKYEdvl3vspKjXox6RIG2VtaRe4JFvxG4rqp2Zuw==", - "peer": true + "integrity": "sha512-H7wUZRn8WpTq9jocdxQ2c8x2sKo9ZVmzfRE13GiNJXfp7NcKYEdvl3vspKjXox6RIG2VtaRe4JFvxG4rqp2Zuw==" }, "node_modules/ajv": { "version": "6.12.6", @@ -2403,12 +2264,6 @@ "node": "*" } }, - "node_modules/async": { - "version": "3.2.5", - "resolved": "https://registry.npmjs.org/async/-/async-3.2.5.tgz", - "integrity": "sha512-baNZyqaaLhyLVKm/DlvdW051MSgO6b8eVfIezl9E5PqWxFgzLm/wQntEW4zOytVburDEr0JlALEpdOFwvErLsg==", - "dev": true - }, "node_modules/asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", @@ -2434,8 +2289,7 @@ "node_modules/bech32": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/bech32/-/bech32-1.1.4.tgz", - "integrity": "sha512-s0IrSOzLlbvX7yp4WBfPITzpAU8sqQcpsmwXDiKwrG4r491vwCO/XpejasRNl0piBMe/DvP4Tz0mIS/X1DPJBQ==", - "peer": true + "integrity": "sha512-s0IrSOzLlbvX7yp4WBfPITzpAU8sqQcpsmwXDiKwrG4r491vwCO/XpejasRNl0piBMe/DvP4Tz0mIS/X1DPJBQ==" }, "node_modules/binary-extensions": { "version": "2.2.0", @@ -2520,27 +2374,6 @@ "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", "dev": true }, - "node_modules/build": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/build/-/build-0.1.4.tgz", - "integrity": "sha512-KwbDJ/zrsU8KZRRMfoURG14cKIAStUlS8D5jBDvtrZbwO5FEkYqc3oB8HIhRiyD64A48w1lc+sOmQ+mmBw5U/Q==", - "dev": true, - "dependencies": { - "cssmin": "0.3.x", - "jsmin": "1.x", - "jxLoader": "*", - "moo-server": "*", - "promised-io": "*", - "timespan": "2.x", - "uglify-js": "1.x", - "walker": "1.x", - "winston": "*", - "wrench": "1.3.x" - }, - "engines": { - "node": ">v0.4.12" - } - }, "node_modules/call-bind": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", @@ -2721,16 +2554,6 @@ "node": ">=6" } }, - "node_modules/color": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/color/-/color-3.2.1.tgz", - "integrity": "sha512-aBl7dZI9ENN6fUGC7mWpMTPNHmWUSNan9tuWN6ahh5ZLNk9baLJOnSMlrQkHcrfFgz2/RigjUVAjdx36VcemKA==", - "dev": true, - "dependencies": { - "color-convert": "^1.9.3", - "color-string": "^1.6.0" - } - }, "node_modules/color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", @@ -2749,47 +2572,12 @@ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true }, - "node_modules/color-string": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.9.1.tgz", - "integrity": "sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==", - "dev": true, - "dependencies": { - "color-name": "^1.0.0", - "simple-swizzle": "^0.2.2" - } - }, - "node_modules/color/node_modules/color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, - "dependencies": { - "color-name": "1.1.3" - } - }, - "node_modules/color/node_modules/color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", - "dev": true - }, "node_modules/colorette": { "version": "2.0.20", "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz", "integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==", "dev": true }, - "node_modules/colorspace": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/colorspace/-/colorspace-1.1.4.tgz", - "integrity": "sha512-BgvKJiuVu1igBUF2kEjRCZXol6wiiGbY5ipL/oVPwm0BL9sIpMIzM8IK7vwuxIIzOXMV3Ey5w+vxhm0rR/TN8w==", - "dev": true, - "dependencies": { - "color": "^3.1.3", - "text-hex": "1.0.x" - } - }, "node_modules/combined-stream": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", @@ -2852,15 +2640,6 @@ "node": ">= 8" } }, - "node_modules/cssmin": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/cssmin/-/cssmin-0.3.2.tgz", - "integrity": "sha512-bynxGIAJ8ybrnFobjsQotIjA8HFDDgPwbeUWNXXXfR+B4f9kkxdcUyagJoQCSUOfMV+ZZ6bMn8bvbozlCzUGwQ==", - "dev": true, - "bin": { - "cssmin": "bin/cssmin" - } - }, "node_modules/d3": { "version": "3.5.17", "resolved": "https://registry.npmjs.org/d3/-/d3-3.5.17.tgz", @@ -3005,12 +2784,6 @@ "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", "dev": true }, - "node_modules/enabled": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/enabled/-/enabled-2.0.0.tgz", - "integrity": "sha512-AKrN98kuwOzMIdAizXGI86UFBoo26CL21UM763y1h/GMSJ4/OHU9k2YlsmBpyScFo/wbLzWQJBMCW4+IO3/+OQ==", - "dev": true - }, "node_modules/enhanced-resolve": { "version": "5.15.0", "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.15.0.tgz", @@ -3463,54 +3236,6 @@ "node": ">=0.10.0" } }, - "node_modules/ethers": { - "version": "5.7.2", - "resolved": "https://registry.npmjs.org/ethers/-/ethers-5.7.2.tgz", - "integrity": "sha512-wswUsmWo1aOK8rR7DIKiWSw9DbLWe6x98Jrn8wcTflTVvaXhAMaB5zGAXy0GYQEQp9iO1iSHWVyARQm11zUtyg==", - "funding": [ - { - "type": "individual", - "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], - "peer": true, - "dependencies": { - "@ethersproject/abi": "5.7.0", - "@ethersproject/abstract-provider": "5.7.0", - "@ethersproject/abstract-signer": "5.7.0", - "@ethersproject/address": "5.7.0", - "@ethersproject/base64": "5.7.0", - "@ethersproject/basex": "5.7.0", - "@ethersproject/bignumber": "5.7.0", - "@ethersproject/bytes": "5.7.0", - "@ethersproject/constants": "5.7.0", - "@ethersproject/contracts": "5.7.0", - "@ethersproject/hash": "5.7.0", - "@ethersproject/hdnode": "5.7.0", - "@ethersproject/json-wallets": "5.7.0", - "@ethersproject/keccak256": "5.7.0", - "@ethersproject/logger": "5.7.0", - "@ethersproject/networks": "5.7.1", - "@ethersproject/pbkdf2": "5.7.0", - "@ethersproject/properties": "5.7.0", - "@ethersproject/providers": "5.7.2", - "@ethersproject/random": "5.7.0", - "@ethersproject/rlp": "5.7.0", - "@ethersproject/sha2": "5.7.0", - "@ethersproject/signing-key": "5.7.0", - "@ethersproject/solidity": "5.7.0", - "@ethersproject/strings": "5.7.0", - "@ethersproject/transactions": "5.7.0", - "@ethersproject/units": "5.7.0", - "@ethersproject/wallet": "5.7.0", - "@ethersproject/web": "5.7.1", - "@ethersproject/wordlists": "5.7.0" - } - }, "node_modules/events": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", @@ -3577,12 +3302,6 @@ "reusify": "^1.0.4" } }, - "node_modules/fecha": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/fecha/-/fecha-4.2.3.tgz", - "integrity": "sha512-OP2IUU6HeYKJi3i0z4A19kHMQoLVs4Hc+DPqqxI2h/DPZHTm/vjsfC6P0b4jCMy14XizLBqvndQ+UilD7707Jw==", - "dev": true - }, "node_modules/file-entry-cache": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", @@ -3651,12 +3370,6 @@ "integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==", "dev": true }, - "node_modules/fn.name": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/fn.name/-/fn.name-1.1.0.tgz", - "integrity": "sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw==", - "dev": true - }, "node_modules/for-each": { "version": "0.3.3", "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", @@ -4145,12 +3858,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-arrayish": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz", - "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==", - "dev": true - }, "node_modules/is-bigint": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", @@ -4354,18 +4061,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-stream": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", - "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", - "dev": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/is-string": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", @@ -4504,18 +4199,6 @@ "node": ">=4" } }, - "node_modules/jsmin": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/jsmin/-/jsmin-1.0.1.tgz", - "integrity": "sha512-OPuL5X/bFKgVdMvEIX3hnpx3jbVpFCrEM8pKPXjFkZUqg521r41ijdyTz7vACOhW6o1neVlcLyd+wkbK5fNHRg==", - "dev": true, - "bin": { - "jsmin": "bin/jsmin" - }, - "engines": { - "node": ">=0.1.93" - } - }, "node_modules/json-parse-even-better-errors": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", @@ -4552,30 +4235,6 @@ "integrity": "sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w==", "dev": true }, - "node_modules/jxLoader": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/jxLoader/-/jxLoader-0.1.1.tgz", - "integrity": "sha512-ClEvAj3K68y8uKhub3RgTmcRPo5DfIWvtxqrKQdDPyZ1UVHIIKvVvjrAsJFSVL5wjv0rt5iH9SMCZ0XRKNzeUA==", - "dev": true, - "dependencies": { - "js-yaml": "0.3.x", - "moo-server": "1.3.x", - "promised-io": "*", - "walker": "1.x" - }, - "engines": { - "node": ">v0.4.10" - } - }, - "node_modules/jxLoader/node_modules/js-yaml": { - "version": "0.3.7", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-0.3.7.tgz", - "integrity": "sha512-/7PsVDNP2tVe2Z1cF9kTEkjamIwz4aooDpRKmN1+g/9eePCgcxsv4QDvEbxO0EH+gdDD7MLyDoR6BASo3hH51g==", - "dev": true, - "engines": { - "node": "> 0.4.11" - } - }, "node_modules/kind-of": { "version": "6.0.3", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", @@ -4585,12 +4244,6 @@ "node": ">=0.10.0" } }, - "node_modules/kuler": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/kuler/-/kuler-2.0.0.tgz", - "integrity": "sha512-Xq9nH7KlWZmXAtodXDDRE7vs6DU1gTU8zYDHDiWLSip45Egwq3plLHzPn27NgvzL2r1LMPC1vdqh98sQxtqj4A==", - "dev": true - }, "node_modules/levn": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", @@ -4655,23 +4308,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/logform": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/logform/-/logform-2.6.0.tgz", - "integrity": "sha512-1ulHeNPp6k/LD8H91o7VYFBng5i1BDE7HoKxVbZiGFidS1Rj65qcywLxX+pVfAPoQJEjRdvKcusKwOupHCVOVQ==", - "dev": true, - "dependencies": { - "@colors/colors": "1.6.0", - "@types/triple-beam": "^1.3.2", - "fecha": "^4.2.0", - "ms": "^2.1.1", - "safe-stable-stringify": "^2.3.1", - "triple-beam": "^1.3.0" - }, - "engines": { - "node": ">= 12.0.0" - } - }, "node_modules/loose-envify": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", @@ -4734,15 +4370,6 @@ "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", "dev": true }, - "node_modules/makeerror": { - "version": "1.0.12", - "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.12.tgz", - "integrity": "sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==", - "dev": true, - "dependencies": { - "tmpl": "1.0.5" - } - }, "node_modules/marked": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/marked/-/marked-4.3.0.tgz", @@ -4913,15 +4540,6 @@ "node": ">=0.3.1" } }, - "node_modules/moo-server": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/moo-server/-/moo-server-1.3.0.tgz", - "integrity": "sha512-9A8/eor2DXwpv1+a4pZAAydqLFVrWoKoO1fzdzqLUhYVXAO1Kgd1FR2gFZi7YdHzF0s4W8cDNwCfKJQrvLqxDw==", - "dev": true, - "engines": { - "node": ">v0.4.10" - } - }, "node_modules/ms": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", @@ -5041,15 +4659,6 @@ "wrappy": "1" } }, - "node_modules/one-time": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/one-time/-/one-time-1.0.0.tgz", - "integrity": "sha512-5DXOiRKwuSEcQ/l0kGCF6Q3jcADFv5tSmRaJck/OqkVFcOzutB134KRSfF0xDrL39MNnqxbHBbUUcjZIhTgb2g==", - "dev": true, - "dependencies": { - "fn.name": "1.x.x" - } - }, "node_modules/optionator": { "version": "0.9.3", "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz", @@ -5266,12 +4875,6 @@ "node": ">= 0.8.0" } }, - "node_modules/promised-io": { - "version": "0.3.6", - "resolved": "https://registry.npmjs.org/promised-io/-/promised-io-0.3.6.tgz", - "integrity": "sha512-bNwZusuNIW4m0SPR8jooSyndD35ggirHlxVl/UhIaZD/F0OBv9ebfc6tNmbpZts3QXHggkjIBH8lvtnzhtcz0A==", - "dev": true - }, "node_modules/prop-types": { "version": "15.8.1", "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", @@ -5577,15 +5180,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/safe-stable-stringify": { - "version": "2.4.3", - "resolved": "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-2.4.3.tgz", - "integrity": "sha512-e2bDA2WJT0wxseVd4lsDP4+3ONX6HpMXQa1ZhFQ7SU+GjvORCmShbCMltrtIDfkYhVHrOcPtj+KhmDBdPdZD1g==", - "dev": true, - "engines": { - "node": ">=10" - } - }, "node_modules/scheduler": { "version": "0.20.2", "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.20.2.tgz", @@ -5617,8 +5211,7 @@ "node_modules/scrypt-js": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/scrypt-js/-/scrypt-js-3.0.1.tgz", - "integrity": "sha512-cdwTTnqPu0Hyvf5in5asVdZocVDTNRmR7XEcJuIzMjJeSHybHl7vpB66AzwTaIg6CLSbtjcxc8fqcySfnTkccA==", - "peer": true + "integrity": "sha512-cdwTTnqPu0Hyvf5in5asVdZocVDTNRmR7XEcJuIzMjJeSHybHl7vpB66AzwTaIg6CLSbtjcxc8fqcySfnTkccA==" }, "node_modules/semver": { "version": "6.3.1", @@ -5695,15 +5288,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/simple-swizzle": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz", - "integrity": "sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==", - "dev": true, - "dependencies": { - "is-arrayish": "^0.3.1" - } - }, "node_modules/slash": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/slash/-/slash-2.0.0.tgz", @@ -5740,15 +5324,6 @@ "node": ">=0.10.0" } }, - "node_modules/stack-trace": { - "version": "0.0.10", - "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz", - "integrity": "sha512-KGzahc7puUKkzyMt+IqAep+TVNbKP+k2Lmwhub39m1AsTSkaDutx56aDCo+HLDzf/D26BIHTJWNiTG1KAJiQCg==", - "dev": true, - "engines": { - "node": "*" - } - }, "node_modules/string_decoder": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", @@ -6014,33 +5589,12 @@ "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", "dev": true }, - "node_modules/text-hex": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/text-hex/-/text-hex-1.0.0.tgz", - "integrity": "sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg==", - "dev": true - }, "node_modules/text-table": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", "dev": true }, - "node_modules/timespan": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/timespan/-/timespan-2.3.0.tgz", - "integrity": "sha512-0Jq9+58T2wbOyLth0EU+AUb6JMGCLaTWIykJFa7hyAybjVH9gpVMTfUAwo5fWAvtFt2Tjh/Elg8JtgNpnMnM8g==", - "dev": true, - "engines": { - "node": ">= 0.2.0" - } - }, - "node_modules/tmpl": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", - "integrity": "sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==", - "dev": true - }, "node_modules/to-fast-properties": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", @@ -6062,15 +5616,6 @@ "node": ">=8.0" } }, - "node_modules/triple-beam": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/triple-beam/-/triple-beam-1.4.1.tgz", - "integrity": "sha512-aZbgViZrg1QNcG+LULa7nhZpJTZSLm/mXnHXnbAbjmN5aSa0y7V+wvv6+4WaBtpISJzThKy+PIPxc1Nq1EJ9mg==", - "dev": true, - "engines": { - "node": ">= 14.0.0" - } - }, "node_modules/ts-api-utils": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.0.1.tgz", @@ -6350,15 +5895,6 @@ "node": ">=12.20" } }, - "node_modules/uglify-js": { - "version": "1.3.5", - "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-1.3.5.tgz", - "integrity": "sha512-YPX1DjKtom8l9XslmPFQnqWzTBkvI4N0pbkzLuPZZ4QTyig0uQqvZz9NgUdfEV+qccJzi7fVcGWdESvRIjWptQ==", - "dev": true, - "bin": { - "uglifyjs": "bin/uglifyjs" - } - }, "node_modules/unbox-primitive": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz", @@ -6435,15 +5971,6 @@ "integrity": "sha512-AFbieoL7a5LMqcnOF04ji+rpXadgOXnZsxQr//r83kLPr7biP7am3g9zbaZIaBGwBRWeSvoMD4mgPdX3e4NWBg==", "dev": true }, - "node_modules/walker": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz", - "integrity": "sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==", - "dev": true, - "dependencies": { - "makeerror": "1.0.12" - } - }, "node_modules/watchpack": { "version": "2.4.0", "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.0.tgz", @@ -6675,42 +6202,6 @@ "integrity": "sha512-CC1bOL87PIWSBhDcTrdeLo6eGT7mCFtrg0uIJtqJUFyK+eJnzl8A1niH56uu7KMa5XFrtiV+AQuHO3n7DsHnLQ==", "dev": true }, - "node_modules/winston": { - "version": "3.11.0", - "resolved": "https://registry.npmjs.org/winston/-/winston-3.11.0.tgz", - "integrity": "sha512-L3yR6/MzZAOl0DsysUXHVjOwv8mKZ71TrA/41EIduGpOOV5LQVodqN+QdQ6BS6PJ/RdIshZhq84P/fStEZkk7g==", - "dev": true, - "dependencies": { - "@colors/colors": "^1.6.0", - "@dabh/diagnostics": "^2.0.2", - "async": "^3.2.3", - "is-stream": "^2.0.0", - "logform": "^2.4.0", - "one-time": "^1.0.0", - "readable-stream": "^3.4.0", - "safe-stable-stringify": "^2.3.1", - "stack-trace": "0.0.x", - "triple-beam": "^1.3.0", - "winston-transport": "^4.5.0" - }, - "engines": { - "node": ">= 12.0.0" - } - }, - "node_modules/winston-transport": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/winston-transport/-/winston-transport-4.6.0.tgz", - "integrity": "sha512-wbBA9PbPAHxKiygo7ub7BYRiKxms0tpfU2ljtWzb3SjRjv5yl6Ozuy/TkXf00HTAt+Uylo3gSkNwzc4ME0wiIg==", - "dev": true, - "dependencies": { - "logform": "^2.3.2", - "readable-stream": "^3.6.0", - "triple-beam": "^1.3.0" - }, - "engines": { - "node": ">= 12.0.0" - } - }, "node_modules/workerpool": { "version": "6.2.1", "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.2.1.tgz", @@ -6739,21 +6230,10 @@ "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" }, - "node_modules/wrench": { - "version": "1.3.9", - "resolved": "https://registry.npmjs.org/wrench/-/wrench-1.3.9.tgz", - "integrity": "sha512-srTJQmLTP5YtW+F5zDuqjMEZqLLr/eJOZfDI5ibfPfRMeDh3oBUefAscuH0q5wBKE339ptH/S/0D18ZkfOfmKQ==", - "deprecated": "wrench.js is deprecated! You should check out fs-extra (https://github.com/jprichardson/node-fs-extra) for any operations you were using wrench for. Thanks for all the usage over the years.", - "dev": true, - "engines": { - "node": ">=0.1.97" - } - }, "node_modules/ws": { "version": "7.4.6", "resolved": "https://registry.npmjs.org/ws/-/ws-7.4.6.tgz", "integrity": "sha512-YmhHDO4MzaDLB+M9ym/mDA5z0naX8j7SIlT8f8z+I0VtzsRbekxEutHSme7NPS2qE8StCYQNUnfWdXta/Yu85A==", - "peer": true, "engines": { "node": ">=8.3.0" }, diff --git a/ethers-ext/package.json b/ethers-ext/package.json index b23d8cd1d..d9df2fa58 100644 --- a/ethers-ext/package.json +++ b/ethers-ext/package.json @@ -19,11 +19,7 @@ "prepublishOnly": "npm run build" }, "license": "MIT", - "peerDependencies": { - "ethers": "^5.7.2" - }, "devDependencies": { - "@klaytn/ethers-ext": "^0.9.8-beta", "@types/chai": "^4.3.7", "@types/chai-as-promised": "^7.1.5", "@types/lodash": "^4.14.192", @@ -43,6 +39,24 @@ "webpack-visualizer-plugin2": "^1.1.0" }, "dependencies": { + "@ethersproject/abstract-provider": "^5.7.0", + "@ethersproject/abstract-signer": "^5.7.0", + "@ethersproject/address": "^5.7.0", + "@ethersproject/bignumber": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/constants": "^5.7.0", + "@ethersproject/hash": "^5.7.0", + "@ethersproject/json-wallets": "^5.7.0", + "@ethersproject/keccak256": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/networks": "^5.7.1", + "@ethersproject/properties": "^5.7.0", + "@ethersproject/providers": "^5.7.2", + "@ethersproject/signing-key": "^5.7.0", + "@ethersproject/strings": "^5.7.0", + "@ethersproject/transactions": "^5.7.0", + "@ethersproject/wallet": "^5.7.0", + "@ethersproject/web": "^5.7.1", "@klaytn/js-ext-core": "^0.9.8-beta", "@klaytn/web3rpc": "^0.9.8", "lodash": "^4.17.21" diff --git a/ethers-ext/src/accountStore.ts b/ethers-ext/src/accountStore.ts index 588117d63..3e076e384 100644 --- a/ethers-ext/src/accountStore.ts +++ b/ethers-ext/src/accountStore.ts @@ -1,8 +1,8 @@ +import { getAddress } from "@ethersproject/address"; import { BigNumber } from "@ethersproject/bignumber"; import { JsonRpcProvider } from "@ethersproject/providers"; -import { SigningKey } from "@ethersproject/signing-key"; +import { SigningKey, computePublicKey } from "@ethersproject/signing-key"; import { computeAddress } from "@ethersproject/transactions"; -import { computePublicKey, getAddress } from "ethers/lib/utils"; import { HexStr } from "@klaytn/js-ext-core"; diff --git a/ethers-ext/src/types.ts b/ethers-ext/src/types.ts index 6e253fcdb..a8b1832d4 100644 --- a/ethers-ext/src/types.ts +++ b/ethers-ext/src/types.ts @@ -1,8 +1,8 @@ import { TransactionRequest as EthersTransactionRequest } from "@ethersproject/abstract-provider"; import { ExternallyOwnedAccount } from "@ethersproject/abstract-signer"; +import { BytesLike } from "@ethersproject/bytes"; import { ExternalProvider as EthersExternalProvider } from "@ethersproject/providers"; import { SigningKey } from "@ethersproject/signing-key"; -import { BytesLike } from "ethers"; export interface TransactionRequest extends EthersTransactionRequest { From 1473a09096c5ffd4f526b764a2ba80985c564d95 Mon Sep 17 00:00:00 2001 From: "ollie.j" Date: Mon, 18 Dec 2023 16:28:42 +0900 Subject: [PATCH 29/33] ethers: Update package.json informational metadata --- ethers-ext/package.json | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/ethers-ext/package.json b/ethers-ext/package.json index d9df2fa58..ea2c69ad7 100644 --- a/ethers-ext/package.json +++ b/ethers-ext/package.json @@ -1,6 +1,21 @@ { "name": "@klaytn/ethers-ext", "version": "0.9.8-beta", + "license": "MIT", + "description": "ethers.js extension for Klaytn blockchain", + "keywords": [ + "ethereum", + "ethers", + "ethersjs", + "klaytn", + "klaytn sdk", + "klaytn api" + ], + "homepage": "https://github.com/klaytn/web3klaytn/tree/dev/ethers-ext", + "repository": { + "type": "git", + "url": "https://github.com/klaytn/web3klaytn" + }, "main": "dist/index.js", "types": "dist/index.d.ts", "files": [ @@ -18,7 +33,6 @@ "test": "mocha --timeout 10000 -r ts-node/register \"test/**/*.ts\"", "prepublishOnly": "npm run build" }, - "license": "MIT", "devDependencies": { "@types/chai": "^4.3.7", "@types/chai-as-promised": "^7.1.5", From a2a488128818d77a1a5dda631e5c761ce4b0f9e9 Mon Sep 17 00:00:00 2001 From: "ollie.j" Date: Mon, 18 Dec 2023 17:02:25 +0900 Subject: [PATCH 30/33] ethers: Update README --- ethers-ext/README.md | 49 ++++++++++++---------- ethers-ext/example/browser-html/index.html | 2 +- 2 files changed, 27 insertions(+), 24 deletions(-) diff --git a/ethers-ext/README.md b/ethers-ext/README.md index 43db6f03e..4cc323786 100644 --- a/ethers-ext/README.md +++ b/ethers-ext/README.md @@ -2,44 +2,47 @@ Ethers.js Extension for Klaytn offers: -- Drop-in replacement to `ethers.Wallet` that handles both Ethereum and Klaytn transactions +- Drop-in replacement to `ethers.Wallet` that handles both Ethereum and Klaytn transaction types involving AccountKey and TxTypes. - Drop-in replacement to `ethers.JsonRpcProvider` that provides accesses to both Ethereum RPCs and Klaytn-specific RPCs. - Drop-in replacement to `ethers.Web3Provider` to work with both MetaMask (`window.ethereum`) and Kaikas (`window.klaytn`) -- (WIP) AccountStore to manage Klaytn account keys. ## Install -``` -npm install --save @klaytn/ethers-ext -``` - -## Usage - -See [example](./example) and [test](./test). - - -## Build - -- Install dependencies +### Node.js +- Install + ```sh + npm install --save @klaytn/ethers-ext ``` - npm install +- ESM or TypeScript + ```ts + import { Wallet, JsonRpcProvider } from "@klaytn/ethers-ext"; + const provider = new JsonRpcProvider("https://public-en-baobab.klaytn.net"); + const wallet = new Wallet("", provider); + ``` +- CommonJS + ```js + const { Wallet, JsonRpcProvider } = require("@klaytn/ethers-ext"); + const provider = new JsonRpcProvider("https://public-en-baobab.klaytn.net"); + const wallet = new Wallet("", provider); ``` -- Build the library +### Browser - ``` - npm run build - ``` +It is not recommended to use CDNs in production, But you can use below for quick prototyping. -- Run examples +```html + + +``` - ``` - node example/rpc/rpc.js - ``` +## Usage +See [example](./example) and [test](./test). ## Class extension design diff --git a/ethers-ext/example/browser-html/index.html b/ethers-ext/example/browser-html/index.html index ec537ed1c..4ffc29598 100644 --- a/ethers-ext/example/browser-html/index.html +++ b/ethers-ext/example/browser-html/index.html @@ -30,7 +30,7 @@ - + From 64af1a8bc5d3c4ecffe0bef2c1fca44d17898986 Mon Sep 17 00:00:00 2001 From: "ollie.j" Date: Mon, 18 Dec 2023 18:11:49 +0900 Subject: [PATCH 31/33] ethers: Update browser-html example --- ethers-ext/example/browser-html/index.html | 45 +++-- ethers-ext/example/browser-html/main.js | 216 +++++++++++---------- ethers-ext/src/signer.ts | 1 - 3 files changed, 141 insertions(+), 121 deletions(-) diff --git a/ethers-ext/example/browser-html/index.html b/ethers-ext/example/browser-html/index.html index 4ffc29598..4a790e693 100644 --- a/ethers-ext/example/browser-html/index.html +++ b/ethers-ext/example/browser-html/index.html @@ -3,29 +3,46 @@ - + @klaytn/ethers-ext in browser demo


-

-

+

+ +


-

-

-

- +

For MetaMask and Kaikas

+

+ + +


-

accounts:

- -

signed tx:

-

txhash:

- -

signature:

-

signer adddress recovered from signature:

+

For Kaikas

+

+ + +

+

+ + +

+
+

+

accounts:
+
chainId:
+

+

+

message signature:
+
recovered signer address:
+

+

+

signed tx:
+
txhash:
+

diff --git a/ethers-ext/example/browser-html/main.js b/ethers-ext/example/browser-html/main.js index 4b1d0fa3b..3a1c89301 100644 --- a/ethers-ext/example/browser-html/main.js +++ b/ethers-ext/example/browser-html/main.js @@ -1,33 +1,57 @@ var provider = null; var accounts = null; +// https://baobab.klaytnscope.com/account/0xa9eF4a5BfB21e92C06da23Ed79294DaB11F5A6df?tabId=contractCode +var contractAddress = "0xa9eF4a5BfB21e92C06da23Ed79294DaB11F5A6df"; +var contractCalldata = "0xd09de08a"; // function increment() + +function isKaikas() { + return provider && provider.provider.isKaikas; +} + // https://docs.ethers.org/v5/getting-started/#getting-started--connecting async function connect(injectedProvider) { if (!injectedProvider) { alert("Please install wallet"); return; } - if (0) { - console.log("use ethers"); - provider = new ethers.providers.Web3Provider(injectedProvider); - } else { - console.log("use ethers-ext"); + + // Wrap the window.{ethereum,klaytn} object with Web3Provider. + provider = new ethers_ext.providers.Web3Provider(injectedProvider); + // Uncomment to use the original ethers.js Web3Provider: + // provider = new ethers.providers.Web3Provider(injectedProvider); + + // Detect user network + // https://docs.metamask.io/wallet/how-to/connect/detect-network/ + const chainId = await provider.send("eth_chainId"); + console.log("chainId", chainId); + $("#textChainId").html(chainId); + + injectedProvider.on("networkChanged", (chainId) => { + console.log("chainId changed", chainId); + $("#textChainId").html(chainId); provider = new ethers_ext.providers.Web3Provider(injectedProvider); - } + }); - await provider.send("eth_requestAccounts", []); - accounts = await provider.listAccounts(); // internally eth_accounts + // Detect user account + // https://docs.metamask.io/wallet/how-to/connect/access-accounts/ + await provider.send("eth_requestAccounts"); + + const accounts = await provider.listAccounts(); // internally eth_accounts console.log("accounts", accounts); $("#textAccounts").html(accounts); + + injectedProvider.on("accountsChanged", async (accounts) => { + console.log("accounts changed", accounts); + $("#textAccounts").html(accounts); + }); } async function connectMM() { - $("#textSignature").html(""); - $("#textTxhash").html(""); + $("text").html(""); // Clear all text await connect(window.ethereum); } async function connectKK() { - $("#textSignature").html(""); - $("#textTxhash").html(""); + $("text").html(""); // Clear all text await connect(window.klaytn); } @@ -54,31 +78,12 @@ async function switchBaobab() { rpcUrls: ["https://public-en-baobab.klaytn.net"], blockExplorerUrls: ["https://baobab.klaytnscope.com/"], }); - - if (provider) { // re-connect after changing network. - await connect(provider.provider); - } -} -async function switchLocal() { - await switchNetwork({ - chainId: "0x7a69", - chainName: "localhost 8545", - nativeCurrency: { - name: "KLAY", - symbol: "KLAY", - decimals: 18, - }, - rpcUrls: ["http://localhost:8545"], - blockExplorerUrls: ["http://localhost:4000"], - }); } async function signMsg() { - const isKaikas = provider.provider.isKaikas || false; - const { hexlify, toUtf8Bytes } = ethers.utils; - try { - if (isKaikas) { + if (isKaikas()) { + const { hexlify, toUtf8Bytes } = ethers.utils; const signer = provider.getSigner(); const message = "Hello dapp"; const hexMessage = hexlify(toUtf8Bytes(message)); @@ -108,60 +113,13 @@ async function signMsg() { } } -async function sendLegacy() { - const isKaikas = provider.provider.isKaikas || false; - - try { - if (isKaikas) { - const signer = provider.getSigner(); - const address = await signer.getAddress(); - - const sentTx = await signer.sendTransaction({ - from: address, - to: address, - value: 0, - }); - console.log("sentTx", sentTx); - const txhash = sentTx.hash; - const explorerUrl = "https://baobab.klaytnscope.com/tx/"; - $("#textTxhash").html(`${txhash}`); - } else { - const signer = provider.getSigner(); - const address = await signer.getAddress(); - - const sentTx = await signer.sendTransaction({ - to: address, - value: 0, - }); - console.log("sentTx", sentTx); - const txhash = sentTx.hash; - const explorerUrl = "https://baobab.klaytnscope.com/tx/"; - $("#textTxhash").html(`${txhash}`); - } - } catch (err) { - console.error(err); - $("#textTxhash").html(`Error: ${err.message}`); - } -} - -async function sendVT() { - const isKaikas = provider.provider.isKaikas || false; - if (!isKaikas) { - alert("not kaikas"); - return; - } - +async function doSendTx(makeTxRequest) { try { const signer = provider.getSigner(); const address = await signer.getAddress(); + const txRequest = await makeTxRequest(address); - const sentTx = await signer.sendTransaction({ - type: ethers_ext.TxType.ValueTransfer, - from: address, - to: address, - value: 0, - }); - + const sentTx = await signer.sendTransaction(txRequest); console.log("sentTx", sentTx); const txhash = sentTx.hash; const explorerUrl = "https://baobab.klaytnscope.com/tx/"; @@ -171,40 +129,86 @@ async function sendVT() { $("#textTxhash").html(`Error: ${err.message}`); } } +async function sendLegacyVT() { + doSendTx(async (address) => { + return { + to: address, // send to myself + value: 0, + }; + }); +} +async function sendLegacySC() { + doSendTx(async () => { + return { + to: contractAddress, + data: contractCalldata, + }; + }); +} +async function sendKlaytnVT() { + doSendTx(async (address) => { + return { + type: ethers_ext.TxType.ValueTransfer, // 0x08 + to: address, // send to myself + value: 0, + }; + }); +} +async function sendKlaytnSC() { + doSendTx(async () => { + return { + type: ethers_ext.TxType.SmartContractExecution, // 0x30 + to: contractAddress, + data: contractCalldata, + }; + }); +} -async function sendFVT() { - const isKaikas = provider.provider.isKaikas || false; - if (!isKaikas) { - alert("not kaikas"); - return; - } +// This operation is usually done in the backend by the dApp operator. +// We do it here with hardcoded private key for demonstration purpose. +async function doSendTxAsFeePayer(signedTx) { + const httpProvider = new ethers_ext.JsonRpcProvider("https://public-en-baobab.klaytn.net"); + const feePayerPriv = "0xb3cf575dea0081563fe5482de2fe4425e025502b1f4ae7e02b2540ac0a5beda1"; + const feePayerWallet = new ethers_ext.Wallet(feePayerPriv, httpProvider); + + const sentTx = await feePayerWallet.sendTransactionAsFeePayer(signedTx); + console.log("sentTx", sentTx); + const txhash = sentTx.hash; + const explorerUrl = "https://baobab.klaytnscope.com/tx/"; + $("#textTxhash").html(`${txhash}`); +} +async function doSignTx(makeTxRequest) { try { const signer = provider.getSigner(); const address = await signer.getAddress(); + const txRequest = await makeTxRequest(address); - const signedTx = await signer.signTransaction({ - type: ethers_ext.TxType.FeeDelegatedValueTransfer, - from: address, - to: address, - value: 0, - }); - + const signedTx = await signer.signTransaction(txRequest); console.log("signedTx", signedTx); $("#textSignedTx").html(`${signedTx}`); - // Simulate fee payer behavior, which is usually in the backend. - const httpProvider = new ethers_ext.JsonRpcProvider("https://public-en-baobab.klaytn.net"); - const feePayerPriv = "0xb3cf575dea0081563fe5482de2fe4425e025502b1f4ae7e02b2540ac0a5beda1"; - const feePayerWallet = new ethers_ext.Wallet(feePayerPriv, httpProvider); - - const sentTx = await feePayerWallet.sendTransactionAsFeePayer(signedTx); - console.log("sentTx", sentTx); - const txhash = sentTx.hash; - const explorerUrl = "https://baobab.klaytnscope.com/tx/"; - $("#textTxhash").html(`${txhash}`); + await doSendTxAsFeePayer(signedTx); } catch (err) { console.error(err); $("#textTxhash").html(`Error: ${err.message}`); } +} +async function sendFeeDelegatedVT() { + doSignTx(async (address) => { + return { + type: ethers_ext.TxType.FeeDelegatedValueTransfer, // 0x09 + to: address, // send to myself + value: 0, + }; + }); +} +async function sendFeeDelegatedSC() { + doSignTx(async () => { + return { + type: ethers_ext.TxType.FeeDelegatedSmartContractExecution, // 0x09 + to: contractAddress, + data: contractCalldata, + }; + }); } \ No newline at end of file diff --git a/ethers-ext/src/signer.ts b/ethers-ext/src/signer.ts index 6001519ed..d42096163 100644 --- a/ethers-ext/src/signer.ts +++ b/ethers-ext/src/signer.ts @@ -475,7 +475,6 @@ export class JsonRpcSigner extends EthersSigner implements EthersJsonRpcSigner { if (this.isKaikas()) { rpcTx.type = resolveTypeForKaikas(rpcTx.type); } - console.log(rpcTx); try { if (this.isKaikas()) { From 2773baf2c93cc66dc8c8750393efe2137202eaa2 Mon Sep 17 00:00:00 2001 From: "ollie.j" Date: Mon, 18 Dec 2023 18:44:18 +0900 Subject: [PATCH 32/33] jscore: Add parseTxType and getKaikasTxType --- ethers-ext/src/txutil.ts | 2 + js-ext-core/package.json | 1 + js-ext-core/src/tx/factory.ts | 2 +- js-ext-core/src/util/const.ts | 84 ++++++++++++++++++++++++++++------- js-ext-core/test/util.spec.ts | 34 +++++++++++--- 5 files changed, 100 insertions(+), 23 deletions(-) diff --git a/ethers-ext/src/txutil.ts b/ethers-ext/src/txutil.ts index 798d14ce3..4f48b2741 100644 --- a/ethers-ext/src/txutil.ts +++ b/ethers-ext/src/txutil.ts @@ -24,6 +24,7 @@ export async function getTransactionRequest(transactionOrRLP: Deferrable undefined // - Ethereum types are kept as-is. 0,1,2 => 0,1,2 diff --git a/js-ext-core/package.json b/js-ext-core/package.json index 671ff9cd9..05f4cf2cf 100644 --- a/js-ext-core/package.json +++ b/js-ext-core/package.json @@ -33,6 +33,7 @@ "@types/elliptic": "^6.4.16", "@types/jest": "^29.5.7", "@types/lodash": "^4.14.199", + "@types/mocha": "^10.0.6", "@types/node": "^20.8.10", "@typescript-eslint/eslint-plugin": "^6.1.0", "chai": "^4.3.7", diff --git a/js-ext-core/src/tx/factory.ts b/js-ext-core/src/tx/factory.ts index c22b4755c..13fd867e8 100644 --- a/js-ext-core/src/tx/factory.ts +++ b/js-ext-core/src/tx/factory.ts @@ -143,7 +143,7 @@ class _KlaytnTxFactory extends FieldSetFactory { fields.data = fields.input; } // In TxTypeSmartContractDeploy, force 'to' = 0x for compatibility - if (HexStr.fromNumber(fields.type) == HexStr.fromNumber(TxType.SmartContractDeploy) || + if (HexStr.fromNumber(fields.type) == HexStr.fromNumber(TxType.SmartContractDeploy) || HexStr.fromNumber(fields.type) == HexStr.fromNumber(TxType.FeeDelegatedSmartContractDeploy) || HexStr.fromNumber(fields.type) == HexStr.fromNumber(TxType.FeeDelegatedSmartContractDeployWithRatio)) { fields.to = "0x"; diff --git a/js-ext-core/src/util/const.ts b/js-ext-core/src/util/const.ts index b4050625f..c4005249a 100644 --- a/js-ext-core/src/util/const.ts +++ b/js-ext-core/src/util/const.ts @@ -1,3 +1,7 @@ +import _ from "lodash"; + +import { HexStr } from "./data"; + // Klaytn Type Enumeration export enum TxType { // Basic @@ -25,19 +29,68 @@ export enum TxType { FeeDelegatedCancelWithRatio = 0x3a, } -export function isKlaytnTxType(type: number): boolean { - return (type in TxType); +// Parse Klaytn TxType in various formats including number (8), +// hex string (0x08), camel case string ("ValueTransfer"), and snake case string ("VALUE_TRANSFER"). +export function parseTxType(type?: number | string): number { + if (type == undefined) { + return 0; + } + + if (_.isNumber(type)) { + return type; + } + + if (_.isString(type) && type.length > 0) { + // Try the hex string, e.g. "0x08" + if (HexStr.isHex(type)) { + return HexStr.toNumber(type); + } + // Try camel case string, e.g. "ValueTransfer", "TxTypeValueTransfer" + // or snake case string, e.g. "VALUE_TRANSFER" + let name = type; + if (name.startsWith("TxType")) { + name = name.substring(6); + } + name = _.upperFirst(_.camelCase(name)); + if (_.has(TxType, name)) { + return _.get(TxType, name); + } + } + + throw new Error(`Unrecognized tx type '${type}'. Expected a number.'`); +} + +// Convert Klaytn TxType to what Kaikas wallet (https://docs.kaikas.io/) understands. +// Pass-through undefined and non-Klaytn TxTypes. +// Convert Klaytn TxTypes to upper and snake case string (e.g. "VALUE_TRANSFER"). +export function getKaikasTxType(type?: number | string): number | string | undefined { + const num = parseTxType(type); + if (!isKlaytnTxType(num)) { + return num; + } else { + const name = TxType[num]; + return _.snakeCase(name).toUpperCase(); + } +} + +// Returns true for Klaytn TxType. +export function isKlaytnTxType(type?: number): boolean { + return !!type && (type in TxType); } -export function isBasicTxType(type: number): boolean { - return (type in TxType) && ((type & 0x3) == 0x0); +// Returns true for Klaytn Basic (i.e. not fee delegated) TxType. +export function isBasicTxType(type?: number): boolean { + return !!type && (type in TxType) && ((type & 0x3) == 0x0); } -export function isFeeDelegationTxType(type: number): boolean { - return (type in TxType) && ((type & 0x3) == 0x1); +// Returns true for Klaytn Fee Delegated TxType. +export function isFeeDelegationTxType(type?: number): boolean { + return !!type && (type in TxType) && ((type & 0x3) == 0x1); } -export function isPartialFeeDelegationTxType(type: number): boolean { - return (type in TxType) && ((type & 0x3) == 0x2); +// Returns true for Klaytn Partial Fee Delegated (i.e. with ratio) TxType. +export function isPartialFeeDelegationTxType(type?: number): boolean { + return !!type && (type in TxType) && ((type & 0x3) == 0x2); } -export function isFeePayerSigTxType(type: number): boolean { +// Returns true for Klaytn TxType with feePayer feature (i.e. fee delegation or partial fee delegation). +export function isFeePayerSigTxType(type?: number): boolean { return isFeeDelegationTxType(type) || isPartialFeeDelegationTxType(type); } @@ -51,13 +104,14 @@ export enum AccountKeyType { RoleBased = 0x05 } -export function isKlaytnAccountKeyType(type: number): boolean { - return (type in AccountKeyType); +// Returns true for Klaytn AccountKeyType. +export function isKlaytnAccountKeyType(type?: number): boolean { + return !!type && (type in AccountKeyType); } -// Returns true if it can be embedded in an AccountKeyRoleBased -export function isEmbeddableAccountKeyType(type: number): boolean { - // any of AccountKeyNil, AccountKeyLegacy, AccountKeyPublic, AccountKeyFail, and AccountKeyWeightedMultiSig. - return (type in AccountKeyType) && (type != AccountKeyType.RoleBased); +// Returns true for AccountKeyTypes that can be embedded in an AccountKeyRoleBased +// (i.e. AccountKeyNil, AccountKeyLegacy, AccountKeyPublic, AccountKeyFail, and AccountKeyWeightedMultiSig) +export function isEmbeddableAccountKeyType(type?: number): boolean { + return !!type && (type in AccountKeyType) && (type != AccountKeyType.RoleBased); } export const CodeFormatEVM = 0x00; diff --git a/js-ext-core/test/util.spec.ts b/js-ext-core/test/util.spec.ts index ca85ac6c5..7f572d9ea 100644 --- a/js-ext-core/test/util.spec.ts +++ b/js-ext-core/test/util.spec.ts @@ -1,6 +1,7 @@ import { BigNumber } from "@ethersproject/bignumber"; import { formatUnits as formatEthUnits, parseUnits as parseEthUnits, formatEther, parseEther } from "@ethersproject/units"; import { assert } from "chai"; +import { describe, it } from "mocha"; /* eslint-disable */ // @ts-ignore: package @klaytn/web3rpc has no .d.ts file. //import { ApiClient, KlayApi } from "@klaytn/web3rpc"; @@ -8,6 +9,8 @@ import { assert } from "chai"; import { TxType, + parseTxType, + getKaikasTxType, isBasicTxType, isFeeDelegationTxType, isKlaytnTxType, @@ -27,7 +30,7 @@ import { describe("util", () => { - it("TxType", () => { + it.only("const", () => { // Eth types are not Klaytn TxType assert.isFalse(isKlaytnTxType(0)); assert.isFalse(isBasicTxType(0)); @@ -48,6 +51,22 @@ describe("util", () => { assert.isFalse(isBasicTxType(ty)); assert.isFalse(isFeeDelegationTxType(ty)); assert.isTrue(isPartialFeeDelegationTxType(ty)); + + assert.equal(parseTxType(), 0); + assert.equal(parseTxType(0), 0); + assert.equal(parseTxType(2), 2); + assert.equal(parseTxType(8), 8); + assert.equal(parseTxType("0x09"), 9); + assert.equal(parseTxType("FeeDelegatedValueTransferWithRatio"), 0x0a); + assert.equal(parseTxType("TxTypeValueTransferMemo"), 0x10); + assert.equal(parseTxType("SMART_CONTRACT_EXECUTION"), 0x30); + + assert.equal(getKaikasTxType(), 0); + assert.equal(getKaikasTxType(0), 0); + assert.equal(getKaikasTxType(2), 2); + assert.equal(getKaikasTxType(8), "VALUE_TRANSFER"); + assert.equal(getKaikasTxType("0x09"), "FEE_DELEGATED_VALUE_TRANSFER"); + assert.equal(getKaikasTxType("SMART_CONTRACT_EXECUTION"), "SMART_CONTRACT_EXECUTION"); }); it.only("getCompressedPublicKey", () => { @@ -221,7 +240,7 @@ describe("util", () => { //* // (3) Test mock const send = (_method: string, _params: any[]) => Promise.resolve("0x1234"); - //*/ + //* / // Uncomment to test with real OpenApi generated codes. /* // (1) @klaytn/web3rpc @@ -234,14 +253,15 @@ describe("util", () => { constructor(apiClient: any) { this.apiClient = apiClient; } + blockNumber(_opts: any, callback: any) { - const bodyParams = { method: 'klay_blockNumber', params: [] }; - this.apiClient.callApi('/', 'POST', null, null, null, null, bodyParams, - [], ['application/json'], ['application/json'], {}, null, callback); + const bodyParams = { method: "klay_blockNumber", params: [] }; + this.apiClient.callApi("/", "POST", null, null, null, null, bodyParams, + [], ["application/json"], ["application/json"], {}, null, callback); } - }; + } const KlayApi = MockKlayApi as any; - //*/ + //* / const klay = asyncOpenApi(send, KlayApi); const ret = await klay.blockNumber(); From 463fe2847b2098ce7d473cccc1a1fb3981eb5156 Mon Sep 17 00:00:00 2001 From: "ollie.j" Date: Mon, 18 Dec 2023 19:15:43 +0900 Subject: [PATCH 33/33] jscore: Add getChainIdFromSignatureTuples --- ethers-ext/src/txutil.ts | 1 + js-ext-core/src/util/ec.ts | 63 ++++++++++++++++++++++++----------- js-ext-core/test/util.spec.ts | 26 +++++++++++++-- 3 files changed, 68 insertions(+), 22 deletions(-) diff --git a/ethers-ext/src/txutil.ts b/ethers-ext/src/txutil.ts index 4f48b2741..349ff7792 100644 --- a/ethers-ext/src/txutil.ts +++ b/ethers-ext/src/txutil.ts @@ -157,6 +157,7 @@ export function eip155sign(key: SigningKey, digest: string, chainId: number): Si return sig; } +// TODO: replace with js-ext-core getChainIdFromSignatureTuples // Extract chainId from tx.txSignatures[] or tx.feePayerSignatures[]. // It works because Klaytn TxType always follows EIP-155. function chainIdFromSig(signatures?: any[]): number | undefined { diff --git a/js-ext-core/src/util/ec.ts b/js-ext-core/src/util/ec.ts index 4c3dcd88a..ba2c8d8f0 100644 --- a/js-ext-core/src/util/ec.ts +++ b/js-ext-core/src/util/ec.ts @@ -1,4 +1,4 @@ -import { splitSignature } from "@ethersproject/bytes"; +import { SignatureLike as EthersSignatureLike, Signature, splitSignature } from "@ethersproject/bytes"; import { ec } from "elliptic"; import _ from "lodash"; @@ -33,19 +33,11 @@ export function getCompressedPublicKey(pub: any): string { // All elements must be string for RLP encoding. export type SignatureTuple = [string, string, string]; -// Commonly used signature object. -export interface SignatureObject { - r: string; - s: string; - v?: number; - recoveryParam?: number; -} - // All kinds of ECDSA signatures returned from various libraries. export type SignatureLike = - SignatureTuple | - SignatureObject | - string; + EthersSignatureLike | // { r, s, v } or { r, s, recoveryParam } + string | // compact signature + string[]; // [v, r, s] // If the sig is an array, the first element 'v' must be one of: // - pre-EIP-155 v: {27, 28} @@ -65,18 +57,51 @@ export type SignatureLike = // "0x75c2c3e5f7b0a182c767137c488649cd5104a5e747371fd922d618e328e5c508", // ] export function getSignatureTuple(sig: SignatureLike): SignatureTuple { - // For array, pass through splitSignature() for sanity check - if (_.isArray(sig) && sig.length == 3) { + // Pass through splitSignature() for sanity check + let obj: Signature; + if (_.isArray(sig)) { + if (sig.length != 3) { + throw new Error("Signature tuple must have 3 elements [v,r,s]"); + } const numV = HexStr.toNumber(sig[0]); - sig = { v: numV, r: sig[1], s: sig[2] }; + obj = splitSignature({ v: numV, r: sig[1], s: sig[2] }); + } else { + obj = splitSignature(sig); } - const split = splitSignature(sig); // R and S must not have leading zeros // c.f. https://github.com/ethers-io/ethers.js/blob/v5/packages/transactions/src.ts/index.ts#L298 return [ - HexStr.fromNumber(split.v), - HexStr.stripZeros(split.r), - HexStr.stripZeros(split.s), + HexStr.fromNumber(obj.v), + HexStr.stripZeros(obj.r), + HexStr.stripZeros(obj.s), ]; } + +// Extract chainId from tx.txSignatures[] or tx.feePayerSignatures[]. +// It works because Klaytn TxType signatures are always EIP-155. +// Returns undefined if chainId cannot be extracted. Use other methods like RPC to get chainId. +export function getChainIdFromSignatureTuples(signatures?: any[]): number | undefined { + if (!_.isArray(signatures) || signatures.length == 0) { + return undefined; + } + + const signature = signatures[0]; + if (!_.isArray(signature) || signature.length != 3) { + return undefined; + } + + const strV = signature[0]; + if (!HexStr.isHex(strV)) { + return undefined; + } + + // v = 2 * chainId + {35, 36} + // v + (v % 2) = 2 * chainId + 36 + const v = HexStr.toNumber(strV); + if (v >= 35) { + return (v + (v % 2) - 36) / 2; + } else { + return undefined; + } +} diff --git a/js-ext-core/test/util.spec.ts b/js-ext-core/test/util.spec.ts index 7f572d9ea..b028e18a8 100644 --- a/js-ext-core/test/util.spec.ts +++ b/js-ext-core/test/util.spec.ts @@ -26,11 +26,12 @@ import { HexStr, isKIP3Json, splitKeystoreKIP3, + getChainIdFromSignatureTuples, } from "../src"; describe("util", () => { - it.only("const", () => { + it("const", () => { // Eth types are not Klaytn TxType assert.isFalse(isKlaytnTxType(0)); assert.isFalse(isBasicTxType(0)); @@ -69,7 +70,7 @@ describe("util", () => { assert.equal(getKaikasTxType("SMART_CONTRACT_EXECUTION"), "SMART_CONTRACT_EXECUTION"); }); - it.only("getCompressedPublicKey", () => { + it("getCompressedPublicKey", () => { const testcases = [ { x: "dc9dccbd788c00fa98f7f4082f2f714e799bc0c29d63f04d48b54fe6250453cd", y: "af06ca34ae8714cf3dae06bacdb78c7c2d4054bd38961d40853cd5f15955da79" }, { x: "0xdc9dccbd788c00fa98f7f4082f2f714e799bc0c29d63f04d48b54fe6250453cd", y: "0xaf06ca34ae8714cf3dae06bacdb78c7c2d4054bd38961d40853cd5f15955da79" }, @@ -107,11 +108,30 @@ describe("util", () => { ]; for (const tc of testcases) { - let tuple = getSignatureTuple(tc as any); + let tuple = getSignatureTuple(tc); assert.deepEqual(tuple, canonical); } }); + it("getChainIdFromSignatureTuples", () => { + const oddV = [ + [ + "0x7f5", + "0xe77a78c4a972f883e05df3a143a3b42cb08b8c082c3f7582f89e27c7062b6d2a", + "0x506da8080866d5a9ae40197917d0a5268a7bb5d33a3093b780c8134b55777ccf", + ], + ]; + const evenV = [ + [ + "0x7f6", + "0x3c72041cdb99c5d9902dd5784361e5fe91b205fa109db8b58097d8ed983e15f5", + "0x11716a098568b68eac778acf256bbbfececdff02478a620de696339ec86473a0", + ] + ]; + assert.equal(getChainIdFromSignatureTuples(oddV), 1001); + assert.equal(getChainIdFromSignatureTuples(evenV), 1001); + }); + it("getRpcTxObject", () => { let tx = { chainId: 42,