@etherscan-npm/cli 1.0.1 → 1.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE CHANGED
@@ -1,21 +1,21 @@
1
- MIT License
2
-
3
- Copyright (c) 2026 Etherscan
4
-
5
- Permission is hereby granted, free of charge, to any person obtaining a copy
6
- of this software and associated documentation files (the "Software"), to deal
7
- in the Software without restriction, including without limitation the rights
8
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
- copies of the Software, and to permit persons to whom the Software is
10
- furnished to do so, subject to the following conditions:
11
-
12
- The above copyright notice and this permission notice shall be included in all
13
- copies or substantial portions of the Software.
14
-
15
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
- SOFTWARE.
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Etherscan
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -54,6 +54,8 @@ npx @etherscan-npm/cli version
54
54
 
55
55
  The npm package downloads the matching native release archive and verifies its SHA-256 checksum during installation. Lifecycle scripts must be enabled.
56
56
 
57
+ > The package is currently published as `@etherscan-npm/cli` while the `@etherscan` npm scope is being transferred. The `etherscan` command is unchanged.
58
+
57
59
  ### Installation script — macOS and Linux
58
60
 
59
61
  ```sh
@@ -92,6 +94,30 @@ Ensure your Go binary directory (`GOBIN`, or `GOPATH/bin` by default) is on `PAT
92
94
 
93
95
  Download the archive for your operating system and architecture plus `checksums.txt` from [GitHub Releases](https://github.com/etherscan/etherscan-cli/releases/latest). Verify the archive's SHA-256 checksum, extract it, and place `etherscan` (or `etherscan.exe`) on your `PATH`.
94
96
 
97
+ ## Uninstall
98
+
99
+ Run:
100
+
101
+ ```sh
102
+ etherscan uninstall
103
+ ```
104
+
105
+ The command shows the exact package-manager action or executable and configuration paths before asking for confirmation. Use `--yes` to skip the prompt. Homebrew and npm installations are removed through their owning package manager. Installer, Go, manual, and source builds remove only the exact running executable; custom directories and `PATH` entries are left alone unless the installer recorded that it added them and the directory contains no other files.
106
+
107
+ The command never requests administrator privileges. If a manually copied binary is in a protected location, it leaves the saved configuration intact and prints the exact command needed to remove the binary. Manually created aliases or separate symlinks may also need to be removed by hand.
108
+
109
+ The installer scripts can remove a script installation without downloading a release archive:
110
+
111
+ ```sh
112
+ curl -fsSL https://raw.githubusercontent.com/etherscan/etherscan-cli/master/scripts/install.sh | sh -s -- --uninstall
113
+ ```
114
+
115
+ ```powershell
116
+ & ([scriptblock]::Create((irm https://raw.githubusercontent.com/etherscan/etherscan-cli/master/scripts/install.ps1))) -Uninstall
117
+ ```
118
+
119
+ Uninstall removes the saved configuration directory. If `ETHERSCAN_API_KEY` is set, unset it separately in the shell or environment where it is defined.
120
+
95
121
  ## Get started
96
122
 
97
123
  ### 1. Create an API key
@@ -141,7 +167,7 @@ Run `etherscan tui` to open the full-screen endpoint explorer:
141
167
  etherscan tui
142
168
  ```
143
169
 
144
- The explorer can be opened before authentication and asks you to validate and save a key when you submit an API-backed endpoint. Running `etherscan` with no command prints the Quick Start guide.
170
+ The explorer can be opened before authentication and asks you to validate and save a key when you submit an API-backed endpoint. It is read-only; source and proxy verification submissions remain available through the traditional commands. Running `etherscan` with no command prints the Quick Start guide.
145
171
 
146
172
  ## Practical workflows
147
173
 
@@ -166,6 +192,33 @@ etherscan contract getabi 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2
166
192
  etherscan contract getsourcecode 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2
167
193
  ```
168
194
 
195
+ ### Verify a contract
196
+
197
+ Verification lives in its own command group, `etherscan contractverification`, so that `etherscan contract` stays purely for reading on-chain contract data. Both groups call the same `contract` API module.
198
+
199
+ Use `--file` for Solidity, Abstract zkSync-stack, or Vyper source payloads. Stylus verification takes a public Git repository URL instead.
200
+
201
+ ```sh
202
+ # Solidity standard JSON
203
+ etherscan contractverification verify 0xYourContract --file input.json --codeformat solidity-standard-json-input --contractname contracts/Verified.sol:Verified --compilerversion v0.8.24+commit.e11b9ed9
204
+
205
+ # Abstract uses the zkSync compiler stack (Abstract Mainnet and Sepolia only)
206
+ etherscan --chain abstract contractverification verify-zksync 0xYourContract --file input.json --codeformat solidity-standard-json-input --contractname contracts/Verified.sol:Verified --compilerversion v0.8.24+commit.e11b9ed9 --zksolc-version v1.5.7
207
+
208
+ # Vyper JSON verification, and Stylus repository verification (Arbitrum One and Sepolia only)
209
+ etherscan contractverification verify-vyper 0xYourContract --file input.json --contractname contracts/Verified.vy:Verified --compilerversion vyper:0.4.0 --optimization-used 0
210
+ etherscan --chain arbitrum contractverification verify-stylus 0xYourContract --source-code https://github.com/example/project --contractname project --compilerversion stylus:0.5.3 --license-type 3
211
+ ```
212
+
213
+ Each submission returns a GUID. Poll it with `check-status` for source verification, or `check-proxy` for a proxy submission:
214
+
215
+ ```sh
216
+ etherscan contractverification check-status <guid>
217
+ etherscan contractverification check-proxy <guid>
218
+ ```
219
+
220
+ Constructor arguments may be supplied as bare ABI-encoded hex or with a `0x` prefix; the CLI sends the documented bare form. Verification source files are limited to 3,000,000 bytes. Run any verification command with `--help` for its exact options.
221
+
169
222
  ### Switch chains
170
223
 
171
224
  ```sh
@@ -207,7 +260,7 @@ Every command includes built-in parameter and usage help:
207
260
  ```sh
208
261
  etherscan --help
209
262
  etherscan account txlist --help
210
- etherscan contract verify --help
263
+ etherscan contractverification verify --help
211
264
  ```
212
265
 
213
266
  <details>
@@ -221,7 +274,7 @@ etherscan contract verify --help
221
274
  | `etherscan tui` | Launch the interactive explorer |
222
275
  | `etherscan login` | Validate and store an API key |
223
276
  | `etherscan logout` | Remove the stored API key |
224
- | `etherscan uninstall` | Remove all CLI configuration |
277
+ | `etherscan uninstall` | Remove the CLI and saved configuration |
225
278
  | `etherscan update` | Update a Homebrew or installer-script installation |
226
279
  | `etherscan whoami` | Show the active chain and masked API key |
227
280
  | `etherscan config` | Get, list, or set CLI configuration |
@@ -262,10 +315,20 @@ etherscan contract verify --help
262
315
  | `etherscan contract getabi` | Get a verified contract's ABI | [getabi](https://docs.etherscan.io/api-reference/endpoint/getabi.md) |
263
316
  | `etherscan contract getsourcecode` | Get verified source code and contract metadata | [getsourcecode](https://docs.etherscan.io/api-reference/endpoint/getsourcecode.md) |
264
317
  | `etherscan contract getcontractcreation` | Get creator and creation transaction data for contracts | [getcontractcreation](https://docs.etherscan.io/api-reference/endpoint/getcontractcreation.md) |
265
- | `etherscan contract verify` | Submit contract source code for verification | [verifysourcecode](https://docs.etherscan.io/api-reference/endpoint/verifysourcecode.md) |
266
- | `etherscan contract verify-status` | Check a source verification submission | [checkverifystatus](https://docs.etherscan.io/api-reference/endpoint/checkverifystatus.md) |
267
- | `etherscan contract verify-proxy` | Submit a proxy contract for verification | [verifyproxycontract](https://docs.etherscan.io/api-reference/endpoint/verifyproxycontract.md) |
268
- | `etherscan contract check-proxy` | Check a proxy verification submission | [checkproxyverification](https://docs.etherscan.io/api-reference/endpoint/checkproxyverification.md) |
318
+
319
+ ### Contract verification
320
+
321
+ Grouped separately from the contract data commands above. All of these call the `contract` API module.
322
+
323
+ | Command | Description | API docs |
324
+ | --- | --- | --- |
325
+ | `etherscan contractverification verify` | Submit Solidity source code for verification | [verifysourcecode](https://docs.etherscan.io/api-reference/endpoint/verifysourcecode.md) |
326
+ | `etherscan contractverification verify-zksync` | Submit zkSync-stack source code on Abstract | [verifyzksyncsourcecode](https://docs.etherscan.io/api-reference/endpoint/verifyzksyncsourcecode.md) |
327
+ | `etherscan contractverification verify-vyper` | Submit Vyper source code for verification | [verifyvyper](https://docs.etherscan.io/api-reference/endpoint/verifyvyper.md) |
328
+ | `etherscan contractverification verify-stylus` | Submit Stylus source code for verification | [verifystylus](https://docs.etherscan.io/api-reference/endpoint/verifystylus.md) |
329
+ | `etherscan contractverification verify-proxy` | Submit a proxy contract for verification | [verifyproxycontract](https://docs.etherscan.io/api-reference/endpoint/verifyproxycontract.md) |
330
+ | `etherscan contractverification check-status` | Check a source verification submission | [checkverifystatus](https://docs.etherscan.io/api-reference/endpoint/checkverifystatus.md) |
331
+ | `etherscan contractverification check-proxy` | Check a proxy verification submission | [checkproxyverification](https://docs.etherscan.io/api-reference/endpoint/checkproxyverification.md) |
269
332
 
270
333
  ### Transaction
271
334
 
@@ -5,6 +5,7 @@
5
5
  const fs = require("node:fs");
6
6
  const path = require("node:path");
7
7
  const { spawnSync } = require("node:child_process");
8
+ const packageInfo = require("../../package.json");
8
9
 
9
10
  const packageRoot = path.resolve(__dirname, "..", "..");
10
11
  const executable = path.join(
@@ -26,6 +27,8 @@ const result = spawnSync(executable, process.argv.slice(2), {
26
27
  env: {
27
28
  ...process.env,
28
29
  ETHERSCAN_INSTALL_METHOD: "npm",
30
+ ETHERSCAN_NPM_PACKAGE: packageInfo.name,
31
+ ETHERSCAN_NPM_WRAPPER_PID: String(process.pid),
29
32
  },
30
33
  });
31
34
 
@@ -1,58 +1,58 @@
1
- "use strict";
2
-
3
- const fs = require("node:fs");
4
- const path = require("node:path");
5
- const { spawnSync } = require("node:child_process");
6
- const packageInfo = require("../package.json");
7
-
8
- const packageRoot = path.resolve(__dirname, "..");
9
- const installDir = path.join(packageRoot, "vendor");
10
- const version = `v${packageInfo.version}`;
11
-
12
- let command;
13
- let args;
14
- if (process.platform === "win32") {
15
- command = "powershell.exe";
16
- args = [
17
- "-NoLogo",
18
- "-NoProfile",
19
- "-NonInteractive",
20
- "-ExecutionPolicy",
21
- "Bypass",
22
- "-File",
23
- path.join(packageRoot, "scripts", "install.ps1"),
24
- "-Version",
25
- version,
26
- "-InstallDir",
27
- installDir,
28
- "-NoPathUpdate",
29
- ];
30
- } else {
31
- command = "sh";
32
- args = [
33
- path.join(packageRoot, "scripts", "install.sh"),
34
- "--version",
35
- version,
36
- "--install-dir",
37
- installDir,
38
- "--no-path-update",
39
- ];
40
- }
41
-
42
- const result = spawnSync(command, args, { stdio: "inherit", env: process.env });
43
- if (result.error) {
44
- console.error(`Unable to run the Etherscan CLI installer: ${result.error.message}`);
45
- process.exit(1);
46
- }
47
- if (result.status !== 0) {
48
- process.exit(result.status === null ? 1 : result.status);
49
- }
50
-
51
- const executable = path.join(
52
- installDir,
53
- process.platform === "win32" ? "etherscan.exe" : "etherscan",
54
- );
55
- if (!fs.existsSync(executable)) {
56
- console.error(`The installer did not create ${executable}.`);
57
- process.exit(1);
58
- }
1
+ "use strict";
2
+
3
+ const fs = require("node:fs");
4
+ const path = require("node:path");
5
+ const { spawnSync } = require("node:child_process");
6
+ const packageInfo = require("../package.json");
7
+
8
+ const packageRoot = path.resolve(__dirname, "..");
9
+ const installDir = path.join(packageRoot, "vendor");
10
+ const version = `v${packageInfo.version}`;
11
+
12
+ let command;
13
+ let args;
14
+ if (process.platform === "win32") {
15
+ command = "powershell.exe";
16
+ args = [
17
+ "-NoLogo",
18
+ "-NoProfile",
19
+ "-NonInteractive",
20
+ "-ExecutionPolicy",
21
+ "Bypass",
22
+ "-File",
23
+ path.join(packageRoot, "scripts", "install.ps1"),
24
+ "-Version",
25
+ version,
26
+ "-InstallDir",
27
+ installDir,
28
+ "-NoPathUpdate",
29
+ ];
30
+ } else {
31
+ command = "sh";
32
+ args = [
33
+ path.join(packageRoot, "scripts", "install.sh"),
34
+ "--version",
35
+ version,
36
+ "--install-dir",
37
+ installDir,
38
+ "--no-path-update",
39
+ ];
40
+ }
41
+
42
+ const result = spawnSync(command, args, { stdio: "inherit", env: process.env });
43
+ if (result.error) {
44
+ console.error(`Unable to run the Etherscan CLI installer: ${result.error.message}`);
45
+ process.exit(1);
46
+ }
47
+ if (result.status !== 0) {
48
+ process.exit(result.status === null ? 1 : result.status);
49
+ }
50
+
51
+ const executable = path.join(
52
+ installDir,
53
+ process.platform === "win32" ? "etherscan.exe" : "etherscan",
54
+ );
55
+ if (!fs.existsSync(executable)) {
56
+ console.error(`The installer did not create ${executable}.`);
57
+ process.exit(1);
58
+ }
@@ -1,15 +1,81 @@
1
- "use strict";
2
-
3
- const packageInfo = require("../package.json");
4
-
5
- try {
6
- if (packageInfo.version === "0.0.0-development") {
7
- throw new Error("the development placeholder version cannot be published");
8
- }
9
- if (!/^(?:0|[1-9]\d*)\.(?:0|[1-9]\d*)\.(?:0|[1-9]\d*)(?:-[0-9A-Za-z.-]+)?(?:\+[0-9A-Za-z.-]+)?$/.test(packageInfo.version)) {
10
- throw new Error(`invalid release version: ${packageInfo.version}`);
11
- }
12
- } catch (error) {
13
- console.error(`Refusing to publish @etherscan/cli: ${error.message}`);
14
- process.exit(1);
15
- }
1
+ "use strict";
2
+
3
+ const fs = require("node:fs");
4
+ const path = require("node:path");
5
+ const packageInfo = require("../package.json");
6
+
7
+ const versionPattern =
8
+ /^(?:0|[1-9]\d*)\.(?:0|[1-9]\d*)\.(?:0|[1-9]\d*)(?:-[0-9A-Za-z.-]+)?(?:\+[0-9A-Za-z.-]+)?$/;
9
+
10
+ // npm treats these as glob metacharacters in package.json "files".
11
+ const globPattern = /[*?[\]{}]/;
12
+
13
+ function checkVersion(version) {
14
+ if (version === "0.0.0-development") {
15
+ throw new Error("the development placeholder version cannot be published");
16
+ }
17
+ if (!versionPattern.test(version)) {
18
+ throw new Error(`invalid release version: ${version}`);
19
+ }
20
+ }
21
+
22
+ // `npm pack` copies the working tree, not the committed blobs. On Windows a
23
+ // checkout with core.autocrlf=true turns the LF blobs into CRLF, and a CRLF
24
+ // scripts/install.sh cannot be run by /bin/sh on Linux or macOS, which is how
25
+ // @etherscan-npm/cli@1.0.1 shipped an installer that failed on both.
26
+ function checkFileLineEndings(filePath, label) {
27
+ const contents = fs.readFileSync(filePath);
28
+ // Skip binaries using the same NUL-byte heuristic git applies for text=auto.
29
+ if (contents.includes(0x00)) {
30
+ return;
31
+ }
32
+ if (contents.includes(0x0d)) {
33
+ throw new Error(`${label} contains CRLF line endings`);
34
+ }
35
+ }
36
+
37
+ // Checks the literal entries of package.json "files". This fails closed: npm
38
+ // also accepts globs and directories there, and silently skipping what it cannot
39
+ // resolve would let a future "files" edit disable the gate while leaving the
40
+ // publish green — the same silent-pass shape that let 1.0.1 ship.
41
+ function checkLineEndings(baseDir, files = packageInfo.files) {
42
+ for (const entry of files) {
43
+ if (globPattern.test(entry)) {
44
+ throw new Error(
45
+ `${entry} is a glob pattern; this check only understands literal file paths, so update it before publishing`,
46
+ );
47
+ }
48
+ const filePath = path.join(baseDir, entry);
49
+ let stats;
50
+ try {
51
+ stats = fs.statSync(filePath);
52
+ } catch (error) {
53
+ if (error.code === "ENOENT") {
54
+ throw new Error(`${entry} is listed in package.json "files" but does not exist`);
55
+ }
56
+ throw error;
57
+ }
58
+ if (stats.isDirectory()) {
59
+ throw new Error(
60
+ `${entry} is a directory; this check only understands literal file paths, so update it before publishing`,
61
+ );
62
+ }
63
+ checkFileLineEndings(filePath, entry);
64
+ }
65
+ }
66
+
67
+ function main() {
68
+ checkVersion(packageInfo.version);
69
+ checkLineEndings(path.resolve(__dirname, ".."));
70
+ }
71
+
72
+ module.exports = { checkVersion, checkFileLineEndings, checkLineEndings };
73
+
74
+ if (require.main === module) {
75
+ try {
76
+ main();
77
+ } catch (error) {
78
+ console.error(`Refusing to publish @etherscan/cli: ${error.message}`);
79
+ process.exit(1);
80
+ }
81
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@etherscan-npm/cli",
3
- "version": "1.0.1",
3
+ "version": "1.0.3",
4
4
  "description": "Command-line client and interactive explorer for the Etherscan V2 API",
5
5
  "license": "MIT",
6
6
  "homepage": "https://github.com/etherscan/etherscan-cli",
@@ -19,7 +19,8 @@
19
19
  "postinstall": "node npm/postinstall.js",
20
20
  "prepublishOnly": "node npm/prepublish-check.js",
21
21
  "test:package": "npm pack --dry-run",
22
- "test:release": "node npm/publish.test.js"
22
+ "test:release": "node npm/publish.test.js",
23
+ "test:eol": "node npm/check-tarball-eol.js"
23
24
  },
24
25
  "files": [
25
26
  "npm/bin/etherscan.js",