{"_id":"@camoseed/evm-elf","_rev":"3-0cac658a7a6e72a3a2a648fb4e732ae3","name":"@camoseed/evm-elf","dist-tags":{"latest":"1.1.0"},"versions":{"1.0.0":{"name":"@camoseed/evm-elf","version":"1.0.0","keywords":["evm","ethereum","cli","wallet","multichain","proxy","ethers"],"license":"MIT","_id":"@camoseed/evm-elf@1.0.0","maintainers":[{"name":"camoseed","email":"alekseev.gleb@gmail.com"}],"homepage":"https://github.com/galekseev/evm-elf#readme","bugs":{"url":"https://github.com/galekseev/evm-elf/issues"},"bin":{"evm":"dist/index.js"},"dist":{"shasum":"0512e70a4bb71fc75815e31731ad369ae7f3c1d9","tarball":"https://registry.npmjs.org/@camoseed/evm-elf/-/evm-elf-1.0.0.tgz","fileCount":88,"integrity":"sha512-7n6Pwyhgi6f9iTgv+gRntMAYWRdS8IC4ojkPOhJRfv/oTOpD6JP20GFxWac5RMCA8b4yid66UF/PicmubrEmtQ==","signatures":[{"sig":"MEUCIQCs3zuFC1NA7Q3H95GV4YZEZ8VqS/4LyQG3CuDM7ReB5AIgdUKZ42qURez8Lu6Wyq/npGNXWWKubfw2WWvmIxV6fOA=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":215873},"type":"module","engines":{"node":">=22.0.0"},"gitHead":"bfad06f705b38862b4016bc23ad92a32172db20e","scripts":{"evm":"tsx index.ts","lint":"eslint .","build":"tsc","clean":"rm -rf dist","prepare":"tsc","typecheck":"tsc --noEmit","prepublishOnly":"npm run clean && npm run lint && npm run typecheck"},"_npmUser":{"name":"camoseed","email":"alekseev.gleb@gmail.com"},"repository":{"url":"git+https://github.com/galekseev/evm-elf.git","type":"git"},"_npmVersion":"11.8.0","description":"Multi-chain EVM CLI for wallets and contracts","directories":{},"_nodeVersion":"24.13.1","dependencies":{"yaml":"^2.8.3","chalk":"^5.3.0","dotenv":"^16.4.5","ethers":"^6.13.0","commander":"^12.1.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"tsx":"^4.19.2","eslint":"^9.18.0","@eslint/js":"^9.18.0","typescript":"^5.7.3","@types/node":"^22.10.7","@typescript-eslint/parser":"^8.21.0","@typescript-eslint/eslint-plugin":"^8.21.0"},"_npmOperationalInternal":{"tmp":"tmp/evm-elf_1.0.0_1785539379976_0.5174708412257452","host":"s3://npm-registry-packages-npm-production"}},"1.0.1":{"name":"@camoseed/evm-elf","version":"1.0.1","keywords":["evm","ethereum","cli","wallet","multichain","proxy","ethers"],"license":"MIT","_id":"@camoseed/evm-elf@1.0.1","maintainers":[{"name":"camoseed","email":"alekseev.gleb@gmail.com"}],"homepage":"https://github.com/galekseev/evm-elf#readme","bugs":{"url":"https://github.com/galekseev/evm-elf/issues"},"bin":{"evm":"dist/index.js"},"dist":{"shasum":"3833187cdef85e0cc4062edce5860faaaa95faab","tarball":"https://registry.npmjs.org/@camoseed/evm-elf/-/evm-elf-1.0.1.tgz","fileCount":88,"integrity":"sha512-XHktP6B9YgAqQCMiaYzWtWFSkYGDuqPAn8WC/zTM7vweFxAS4ax+yiPS+UO51tclwLZHnE/akrIlc9w+OjFVTw==","signatures":[{"sig":"MEUCIDt8q/WF51PgCpYhFhpXxbQ8L7De3Yakk90xkxuZNkqWAiEAmwWEfxYurBMK+dVR4NYCTGsRdwM16gt8HEbgNaZSikk=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@camoseed%2fevm-elf@1.0.1","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":220910},"type":"module","engines":{"node":">=22.0.0"},"gitHead":"4375dd6a4277445c2f19eaf8f0d99967abd11bac","scripts":{"evm":"tsx index.ts","lint":"eslint .","build":"tsc","clean":"rm -rf dist","prepare":"tsc","release":"npm version patch && git push --follow-tags","typecheck":"tsc --noEmit","prepublishOnly":"npm run clean && npm run lint && npm run typecheck"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:d7bf4f18-a742-4736-b509-5517b52f43c6"}},"repository":{"url":"git+https://github.com/galekseev/evm-elf.git","type":"git"},"_npmVersion":"11.16.0","description":"Multi-chain EVM CLI for wallets and contracts","directories":{},"_nodeVersion":"24.18.0","dependencies":{"yaml":"^2.8.3","chalk":"^5.3.0","dotenv":"^16.4.5","ethers":"^6.13.0","commander":"^12.1.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"tsx":"^4.19.2","eslint":"^9.18.0","@eslint/js":"^9.18.0","typescript":"^5.7.3","@types/node":"^22.10.7","@typescript-eslint/parser":"^8.21.0","@typescript-eslint/eslint-plugin":"^8.21.0"},"_npmOperationalInternal":{"tmp":"tmp/evm-elf_1.0.1_1785927833282_0.24852847166089886","host":"s3://npm-registry-packages-npm-production"}},"1.1.0":{"name":"@camoseed/evm-elf","version":"1.1.0","description":"Multi-chain EVM CLI for wallets and contracts","keywords":["evm","ethereum","cli","wallet","multichain","proxy","ethers"],"license":"MIT","repository":{"type":"git","url":"git+https://github.com/galekseev/evm-elf.git"},"homepage":"https://github.com/galekseev/evm-elf#readme","bugs":{"url":"https://github.com/galekseev/evm-elf/issues"},"type":"module","bin":{"evm":"dist/index.js"},"engines":{"node":">=22.0.0"},"publishConfig":{"access":"public"},"scripts":{"build":"tsc","prepare":"tsc","prepublishOnly":"npm run clean && npm run lint && npm run typecheck","release":"npm version patch && git push --follow-tags","evm":"tsx index.ts","typecheck":"tsc --noEmit","lint":"eslint .","clean":"rm -rf dist"},"dependencies":{"chalk":"^5.3.0","commander":"^12.1.0","dotenv":"^16.4.5","ethers":"^6.13.0","yaml":"^2.8.3"},"devDependencies":{"@eslint/js":"^9.18.0","@types/node":"^22.10.7","@typescript-eslint/eslint-plugin":"^8.21.0","@typescript-eslint/parser":"^8.21.0","eslint":"^9.18.0","tsx":"^4.19.2","typescript":"^5.7.3"},"gitHead":"d8ec12a37ae99f569697d21681665b73d5c1c07a","_id":"@camoseed/evm-elf@1.1.0","_nodeVersion":"24.19.0","_npmVersion":"11.17.0","dist":{"integrity":"sha512-c7YhJaYI/f3gly3njVaeZbjxqWe3Qx9pMmCFZMckYBHd2ejRvnZYIza0ABNGkcwyCjPqFtJtFRI6jHf5HuWTCg==","shasum":"6a1b22b90cac5470ca5210873a4dc4a9d461572f","tarball":"https://registry.npmjs.org/@camoseed/evm-elf/-/evm-elf-1.1.0.tgz","fileCount":92,"unpackedSize":262696,"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@camoseed%2fevm-elf@1.1.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIHv8m182CBCwFSMeXSCzRheaAWdYCkqiN7ZmL4OX2N/cAiEAxYkw5rsO5cmgq7qWhH/ht0Bxc5Et3q4xcToEj3Z0W44="}]},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:d7bf4f18-a742-4736-b509-5517b52f43c6"}},"directories":{},"maintainers":[{"name":"camoseed","email":"alekseev.gleb@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/evm-elf_1.1.0_1786745602960_0.9525645132344012"},"_hasShrinkwrap":false}},"time":{"created":"2026-07-31T23:09:39.764Z","modified":"2026-08-14T22:13:23.397Z","1.0.0":"2026-07-31T23:09:40.110Z","1.0.1":"2026-08-05T11:03:53.473Z","1.1.0":"2026-08-14T22:13:23.108Z"},"bugs":{"url":"https://github.com/galekseev/evm-elf/issues"},"license":"MIT","homepage":"https://github.com/galekseev/evm-elf#readme","keywords":["evm","ethereum","cli","wallet","multichain","proxy","ethers"],"repository":{"type":"git","url":"git+https://github.com/galekseev/evm-elf.git"},"description":"Multi-chain EVM CLI for wallets and contracts","maintainers":[{"name":"camoseed","email":"alekseev.gleb@gmail.com"}],"readme":"<h1 align=\"center\">evm-elf</h1>\n\n<p align=\"center\">Wallet and contract operations on many EVM chains in one command. Built on ethers v6, installs as <code>evm</code>.</p>\n\n<p align=\"center\">\n  <a href=\"LICENSE\"><img src=\"https://img.shields.io/badge/license-MIT-blue.svg\" alt=\"MIT License\"></a>\n  <a href=\"package.json\"><img src=\"https://img.shields.io/badge/node-%3E%3D22-brightgreen.svg\" alt=\"Node.js 22 or newer\"></a>\n</p>\n\nWorking on a multichain deployment means running the same operation on every chain: checking a deployer's balance, confirming who owns a contract, finding out where a proxy points, topping up gas. evm-elf turns each of those into one command that covers all your chains at once, instead of a loop over RPC URLs.\n\n## Features\n\n- **Reads fan out.** Every query hits all the chains in your profile at once unless you narrow it with `-c`/`-xc`, so `evm contract proxy-info 0x...` answers \"where is this deployed and what is it\" in one pass.\n- **Writes are dry-run.** A command that sends a transaction prints its plan and stops there; `--exec` is what sends. The contract commands also compare the signer against the owner and static-call the transaction, so a revert costs nothing.\n- **A profile is the chain list.** One file holds the endpoints, headers and token metadata for a set of chains, so `-p myproject` switches the chains and their RPC URLs together.\n- **Everything speaks JSON.** `--json` works on every command and carries the same per-chain data as the table.\n\n## Install\n\n```bash\nnpm install -g @camoseed/evm-elf\n```\n\nRequires Node.js 22+. To build from the current state of the repository instead, install from git: `npm install -g github:galekseev/evm-elf`.\n\n## Quick start\n\n```bash\nevm wallet balance 0xef3c29bc05a77B266A76f2cEa11d8b8886342e8a           # balances on every chain\nevm contract proxy-info 0x4200000000000000000000000000000000000010 -s   # where is it, and what is it\nevm chain set base https://base.example/rpc                             # your endpoint instead of the public one\n```\n\nThe first run creates `~/.config/evm-elf/profiles/default.yaml` from the profile bundled with the package: 14 chains pointed at their own public endpoints, which is enough to try things out and rate-limited under load. Every command supports `--help`.\n\n## Documentation\n\nThis README is the overview. The [docs](docs/) directory covers setup and use in depth:\n\n- [Installation](docs/installation.md) — requirements, the global install, upgrades, and running from a checkout\n- [Getting started](docs/getting-started.md) — a ten-minute walkthrough from the first fan-out read to the first dry run\n- [Configuration](docs/configuration.md) — profiles, every chain field, environment variables, and prices\n- [Private keys](docs/private-keys.md) — passing a signing key without leaving it in your shell history\n- [Wallet commands](docs/wallet-commands.md) and [Contract commands](docs/contract-commands.md) — every argument, option, output, and exit code\n- [Profile commands](docs/profile-commands.md) — creating, copying, and switching between profiles\n- [Chain commands](docs/chain-commands.md) — adding a chain to a profile and pointing it at your own endpoint\n- [Explorer commands](docs/explorer-commands.md) — the block explorer API keys that `proxy-info --full` and `deploy-info` depend on\n- [Troubleshooting](docs/troubleshooting.md) — the error messages, with a cause and a fix for each\n\n## Contents\n\n- [Documentation](#documentation) — the full guides, in `docs/`\n- [Options](#options) — the flags every command shares\n- [Wallet commands](#wallet-commands): [`balance`](#balance-wallet), [`send`](#send-to), [`set-nonce`](#set-nonce-target), [`generate`](#generate), [`address`](#address-private-key)\n- [Contract commands](#contract-commands): [`owner`](#owner-address), [`proxy-info`](#proxy-info-address), [`deploy-info`](#deploy-info-address), [`transfer-ownership`](#transfer-ownership-address-newowner), [`proxy-upgrade`](#proxy-upgrade-proxy-newimplementation), [`code`](#code-address)\n- [Configuration](#configuration): [the profile file](#the-profile-file), [`evm profile`](#profile-commands), [`evm chain`](#chain-commands), [`evm explorer`](#explorer-commands), [chain selection](#chain-selection), [private keys](#private-keys), [environment variables](#environment-variables), [prices](#prices)\n- [Requirements](#requirements), [Development](#development), [License](#license)\n\n## Options\n\nShared by the commands that reach a chain:\n\n```\n-c, --chain <chains>           Chains to use, comma-separated (default: every chain in the profile)\n-xc, --exclude-chain <chains>  Chains to leave out (cannot be combined with -c)\n-p, --profile <nameOrPath>     Profile to use (default: $EVM_ELF_PROFILE, else the default profile)\n    --private-key <key>        Hex key, or the name of an env var holding one (commands that sign)\n    --exec                     Send the transaction; without it the command prints its plan\n    --json                     Print JSON instead of a table\n```\n\n`evm --help` lists the five command groups. `evm <group> <command> --help` documents a single command, with examples of its own.\n\n## Wallet commands\n\nBalances, native-token transfers and nonce management. The reads fan out across the profile; `send` and `set-nonce` sign, so they require `--private-key`.\n\n### `balance <wallet>`\n\nNative balance, USD value and pending nonce across chains, with a total. Accepts an address, a private key, or the name of an env var holding either.\n\n```bash\nevm wallet balance 0xef3c29bc05a77B266A76f2cEa11d8b8886342e8a\n```\n\n```\nWallet Balance: 0xef3c29bc05a77B266A76f2cEa11d8b8886342e8a\n\nChain           Chain ID   Balance (Native)          Token    Value (USD)      Nonce      Status\n────────────────────────────────────────────────────────────────────────────────────────────────\narbitrum        42161      0.0076740380881518        ETH      $14.43           34         OK\navax            43114      1.987267192700984185      AVAX     $12.80           34         OK\nbase            8453       0.008921096499920447      ETH      $16.78           34         OK\nbsc             56         0.026384506008903151      BNB      $15.60           34         OK\nxdai            100        30.397500968793352058     xDAI     $30.04           34         OK\nlinea           59144      0.003118555158229058      ETH      $5.86            34         OK\nmainnet         1          0.080837487973711977      ETH      $152.03          34         OK\noptimistic      10         0.009932713394950238      ETH      $18.68           34         OK\nmatic           137        91.998910300164719596     POL      $6.62            34         OK\nsepolia         11155111   0.029869928923982585      ETH      -                34         OK\nsonic           146        219.575066457902650843    S        $4.63            34         OK\nunichain        130        0.019892840367799299      ETH      $37.41           34         OK\nzksync          324        0.12696957183574137       ETH      $238.79          34         OK\nrobinhood       4663       0.007545200223644         ETH      $14.19           34         OK\n────────────────────────────────────────────────────────────────────────────────────────────────\nTotal                                                         $567.85\nNo price for: sepolia (excluded from total)\n```\n\nChains whose native token has no meaningful price (testnets) show `-` and are left out of the total, as the last line notes. See [Prices](#prices).\n\n```bash\nevm wallet balance 0x72B4...Be7a -c base,arbitrum --json\nevm wallet balance 0x72B4...Be7a --no-usd     # skip the price lookup\n```\n\n### `send <to>`\n\nSend the native token. `--value` sends the same amount on each selected chain, `--all` sweeps the whole balance minus a gas reserve. Both print a plan and need `--exec` to send.\n\n```bash\nevm wallet send 0x5d0F...95eB --value 0.01 --private-key DEPLOYER_PK -c base\nevm wallet send 0x5d0F...95eB --value 0.01 --private-key DEPLOYER_PK -c base --exec\nevm wallet send 0x5d0F...95eB --all --private-key DEPLOYER_PK -c bsc,base,arbitrum\nevm wallet send 0x5d0F...95eB --all --exec --fee-buffer 1.5 --private-key DEPLOYER_PK -xc mainnet\n```\n\n`--value` accepts ether amounts (`0.01`, `0.01ether`) or wei (`10000000000000000wei`). The `--all` plan reads balances and gas prices, so it prints the exact amount each chain would send; `--fee-buffer` is the multiplier on that gas reserve (default `1.1`, `--all` only) and whatever the reserve does not spend stays behind as dust. `--no-wait` returns once the transactions are broadcast instead of waiting for receipts, so it needs `--exec`. Amounts are named in each chain's own token, from its `symbol` in the profile, falling back to a lowercase `ether` on a chain that names none.\n\n### `set-nonce <target>`\n\nBump a wallet's nonce to a target by sending zero-value self-transactions. Without `--exec` it prints how many transactions each chain needs.\n\n```bash\nevm wallet set-nonce 23 --private-key DEPLOYER_PK\nevm wallet set-nonce 23 --private-key DEPLOYER_PK -c base --exec\n```\n\nChains already at or above the target are skipped, since a nonce can never be lowered.\n\n### `generate`\n\nGenerate a new random wallet. The mnemonic and private key are printed to stdout — store them securely.\n\n```bash\nevm wallet generate\nevm wallet generate --words 24 --json\n```\n\n### `address <private-key>`\n\nDerive the address for a private key or for an env var holding one.\n\n```bash\nevm wallet address DEPLOYER_PK\n```\n\n## Contract commands\n\nOwnership, proxy and deployment inspection for a contract that lives at the same address on several chains. The reads fan out; `transfer-ownership` and `proxy-upgrade` act on one chain, so `-c` is required there.\n\n### `owner <address>`\n\nRead `owner()` across chains.\n\n```bash\nevm contract owner 0x1111111254EEB25477B68fb85Ed929f73A960582\nevm contract owner 0x1111...0582 -c base,arbitrum --json\n```\n\n### `proxy-info <address>`\n\nAuto-detects the proxy type and prints what is relevant for each:\n\n| Detected type | Shown |\n|---|---|\n| Transparent (EIP-1967) | implementation, ProxyAdmin, admin owner, proxy-level `owner()` |\n| UUPS / ERC-1967 | implementation, proxy-level `owner()` (usually authorizes upgrades) |\n| Beacon proxy | beacon, beacon owner, `beacon.implementation()`, proxy-level `owner()` |\n| Minimal proxy (EIP-1167/7511 clone) | implementation embedded in bytecode (not upgradeable) |\n| Beacon contract | the address itself is a beacon: its implementation and owner |\n| ProxyAdmin contract | owner, plus the managed proxy and its implementation, traced through the admin's creation transaction (OZ v5 admins, explorer only) |\n| Not a proxy | `owner()` if present |\n\n```bash\nevm contract proxy-info 0x4200000000000000000000000000000000000010 -s\n```\n\n```\nProxy Info: 0x4200000000000000000000000000000000000010\n\nChain           Chain ID   Proxy type\n──────────────────────────────────────────────────\narbitrum        42161      no code at address\navax            43114      no code at address\nbase            8453       transparent proxy\nbsc             56         no code at address\nxdai            100        no code at address\nlinea           59144      no code at address\nmainnet         1          no code at address\noptimistic      10         transparent proxy\nmatic           137        no code at address\nsepolia         11155111   no code at address\nsonic           146        no code at address\nunichain        130        transparent proxy\nzksync          324        no code at address\nrobinhood       4663       no code at address\n```\n\n`-s, --short` skips owner lookups and the managed-proxy trace, so it is fast enough to scan every chain in the profile at once: the OP Stack bridge above turns up on the three OP chains of the default profile and nowhere else. Drop `-s` once you know which chains matter.\n\n```bash\nevm contract proxy-info 0x4200000000000000000000000000000000000010 -c base,optimistic\nevm contract proxy-info 0x4200...0010 -c base --full   # extra diagnostics\n```\n\n`--full` adds:\n\n- bytecode size; ProxyAdmin `UPGRADE_INTERFACE_VERSION()` (OZ v5 vs v4); ERC-1822 `proxiableUUID()` check for UUPS\n- initialization state (OZ v5 ERC-7201 slot, OZ v4 slot-0 heuristic) with a warning for uninitialized proxies\n- owner classification: EOA / Gnosis Safe (with `threshold/owners`) / other contract\n- `pendingOwner()` (Ownable2Step) and `paused()` (Pausable) when present\n- native balance held by the proxy (when non-zero)\n- implementation codehash plus a cross-chain comparison that warns when bytecode differs between chains\n- verified implementation name, upgrade history (`Upgraded` events) and creation info (deployer, date, transaction)\n\nThe last group and the ProxyAdmin trace read from a block explorer rather than the RPC. Sources are tried in order — the chain's own `explorer_api`, then Etherscan, then Blockscout — and the API keys come from the `explorers` section of the profile:\n\n```bash\nevm explorer set etherscan '${ETHERSCAN_API_KEY}'   # checks the key before storing it\nevm explorer list                                   # what is configured, keys masked\n```\n\nWith nothing configured, those fields are left out and the run says so once on stderr. See [Explorer commands](docs/explorer-commands.md).\n\n### `deploy-info <address>`\n\nWorks out whether a contract was deployed with `CREATE`, `CREATE2` or `CREATE3`, and recovers the salt from the creation transaction — so you can tell a deterministic deployment from a coincidence, and reproduce the address yourself.\n\n```bash\nevm contract deploy-info 0x000000000022D473030F116dDEE9F6B43aC78BA3\n```\n\n```\nDeploy Info: 0x000000000022D473030F116dDEE9F6B43aC78BA3\n\nChain           Chain ID   Method    Deployer / factory\n───────────────────────────────────────────────────────────────────────────────\nmainnet         1          CREATE2   0x4e59b44847b379578588920cA78FbF26c0B4956C\nbase            8453       CREATE2   0x4e59b44847b379578588920cA78FbF26c0B4956C\nxdai            100        CREATE2   0x4e59b44847b379578588920cA78FbF26c0B4956C\nsepolia         11155111   CREATE2   0x4e59b44847b379578588920cA78FbF26c0B4956C\n\nMethod, factory and salt are identical on all 4 chains\n  CREATE2 via Arachnid deterministic deployment proxy\n  salt 0x0000000000000000000000000000000000000000d3af2663da51c10215000000\n```\n\nNothing is reported on the strength of a factory's name: a salt appears only when it reproduces the address under the opcode's own derivation, and `--full` lists the checks that passed. That is what lets it recover a salt from a factory nobody has catalogued, since any 32-byte value in the call that derives the right address is the salt.\n\n```bash\nevm contract deploy-info 0xa7bC...F99A -c mainnet --full   # salt, proxy, factory owner, dates\n```\n\n`--full` also reports what a CREATE3 deployment needs to be understood: the intermediate proxy and whether it self-destructed, the guarded salt when the factory hashed the one it was handed (CreateX's four rules, named), and the factory's owner when `deploy` is `onlyOwner`. Finding the creation transaction needs an explorer, so see [Explorer commands](docs/explorer-commands.md).\n\n### `transfer-ownership <address> <newOwner>`\n\nCall `transferOwnership(newOwner)` on a single chain. Dry-run by default: shows the current owner and signer, warns if the signer is not the owner, and static-calls the transfer to catch reverts. Add `--exec` to send.\n\n```bash\nevm contract transfer-ownership 0xContract... 0xNewOwner... --private-key DEPLOYER_PK -c base\nevm contract transfer-ownership 0xContract... 0xNewOwner... --private-key DEPLOYER_PK -c base --exec\n```\n\n### `proxy-upgrade <proxy> <newImplementation>`\n\nUpgrade a transparent proxy via `ProxyAdmin.upgradeAndCall` (OZ v4/v5). Takes the **proxy** address — the ProxyAdmin comes from the EIP-1967 admin slot. Dry-run by default: verifies the signer owns the ProxyAdmin, the new implementation has code, and static-calls the upgrade. With `--exec` the implementation slot is re-read afterwards to confirm.\n\n```bash\nevm contract proxy-upgrade 0xProxy... 0xNewImpl... --private-key DEPLOYER_PK -c zksync\nevm contract proxy-upgrade 0xProxy... 0xNewImpl... --private-key DEPLOYER_PK -c zksync --data 0x8129fc1c --exec\n```\n\n`--data` passes calldata to `upgradeAndCall` (e.g. an initializer call); defaults to `0x`.\n\n### `code <address>`\n\nCheck deployed bytecode at an address.\n\n```bash\nevm contract code 0xD935a2bb926019E0ed6fb31fbD5b1Bbb7c05bf65 -c base,arbitrum\nevm contract code 0xD935...bf65 -c base --full   # full bytecode hex\n```\n\n## Configuration\n\nEverything the CLI knows about a chain lives in one file, a profile:\n\n| What | Where |\n|---|---|\n| Chains: RPC URL, HTTP headers, token and explorer metadata, plus explorer API keys | `~/.config/evm-elf/profiles/<name>.yaml` |\n| Which profile is used | `-p <name>`, else `$EVM_ELF_PROFILE`, else `evm profile set-default`, else `default` |\n| Values referenced as `${VAR}` | `./.env`, then `~/.config/evm-elf/.env` |\n\nA profile is also the chain list: the chains it names are the chains every read fans out across. The `default` profile is created on first use from the one bundled with the package ([config/default-profile.yaml](config/default-profile.yaml)).\n\n### The profile file\n\n```yaml\n# ~/.config/evm-elf/profiles/default.yaml\nexplorers:\n  etherscan: ${ETHERSCAN_API_KEY}\n\nchains:\n  base:\n    chain_id: 8453\n    rpc_url: https://mainnet.base.org\n    symbol: ETH\n    coingecko_id: ethereum\n  arbitrum:\n    chain_id: 42161\n    rpc_url: ${ARBITRUM_RPC_URL}\n    symbol: ETH\n    coingecko_id: ethereum\n    headers:\n      auth-key: ${ARBITRUM_AUTH_KEY}\n  zksync:\n    chain_id: 324\n    rpc_url: https://mainnet.era.zksync.io\n    symbol: ETH\n    coingecko_id: ethereum\n    explorer_api: https://block-explorer-api.mainnet.zksync.io/api\n```\n\n`chain_id` and `rpc_url` are required per chain. The rest is what an RPC cannot tell you: `symbol` and `coingecko_id` fill the token and USD columns of `wallet balance` (no `coingecko_id`, no price), and `explorer_api` names an explorer for a chain the shared sources do not cover. `${VAR}` is resolved from the environment, which keeps keys out of the file, and `rpc_url` also accepts the `<URL>|<AUTH_KEY>` form as shorthand for the `auth-key` header.\n\nThe `explorers` section holds one API key per source, since a single key covers every chain that source supports. Edit it with `evm explorer set`, which checks the key before storing it.\n\nUse several profiles for several projects — a profile doubles as \"the chains this project uses\":\n\n```bash\nevm wallet balance 0x72B4...Be7a -p myproject\n```\n\n### Profile commands\n\n```bash\nevm profile list                          # what exists, and which one is the default\nevm profile create myproject              # a copy of the bundled profile\nevm profile create myproject --empty      # no chains, fill it with evm chain set\nevm profile clone default backup          # copy an existing one, comments included\nevm profile clone ./team-chains.yaml team # a file from a repo becomes a profile\nevm profile set-default myproject         # used whenever -p is not given\nevm profile remove myproject\n```\n\n`set-default` writes the name to `~/.config/evm-elf/profiles/.default`, so it survives across shells; `$EVM_ELF_PROFILE` still wins over it and `-p` wins over both, and `set-default` says so when the variable is set. `evm profile set-default default` goes back to the bundled profile. `remove` refuses to delete the profile currently in use unless you pass `--force`, and clearing it that way also resets the default.\n\n### Chain commands\n\n`evm chain` edits a profile in place, keeping its comments and key order:\n\n```bash\nevm chain list                                                   # what is configured\nevm chain set base https://base.example/rpc                      # add or update a chain\nevm chain set base '${BASE_RPC_URL}' -H 'auth-key:${BASE_KEY}'   # keep the secrets in .env\nevm chain set base -H 'auth-key:literal-key'                     # only change the header\nevm chain set local http://127.0.0.1:8545 --chain-id 31337 --no-verify\nevm chain remove sepolia\n```\n\n`set` reads the chain id from the endpoint (`eth_chainId`) instead of guessing, so any chain works and a `--chain-id` that disagrees is an error. `--no-verify` skips the request and then needs `--chain-id`, which is how a chain that is not running yet gets added.\n\nMetadata the entry does not have yet — `symbol`, `coingecko_id`, `explorer_api` — is copied from the bundled profile when the chain id matches, which also covers forks. `--symbol`, `--coingecko-id` and `--explorer-api` override it, and an empty value (`--symbol ''`) clears it. `-H` is repeatable, and `--remove-header <name>` drops one.\n\n`chain list` masks header values, since one may be a literal key; `--reveal` prints them. All three take `-p` to work on another profile, and an edited file is written with owner-only permissions.\n\n### Explorer commands\n\n`evm explorer` manages the block explorer API keys that `contract proxy-info --full` and `contract deploy-info` use. One key covers every chain a source supports, so there is no per-chain setting:\n\n```bash\nevm explorer list                                     # what is configured, keys masked\nevm explorer set etherscan '${ETHERSCAN_API_KEY}'     # keep the key in .env\nevm explorer set blockscout YourBlockscoutKey         # or store it in the profile\nevm explorer remove blockscout\n```\n\n`set` asks the explorer whether it accepts the key before writing it, the way `chain set` reads the chain id from the endpoint; `--no-verify` skips that, which is what you want when writing a profile for another machine. Sources are tried in order: a chain's own `explorer_api`, then `etherscan`, then `blockscout`. With none configured, the explorer-backed fields are left out and the command says so once on stderr.\n\n### Chain selection\n\n1. `-c, --chain` — explicit comma-separated list\n2. every chain in the profile\n\n`-xc, --exclude-chain` (mutually exclusive with `-c`) takes the profile's chains and removes the named ones:\n\n```bash\nevm contract owner 0xD935...bf65 -xc mainnet,zksync\n```\n\n### Private keys\n\n`--private-key` accepts a raw hex key (with or without `0x`) or the **name** of an environment variable, e.g. `--private-key DEPLOYER_PK`. Keys are never logged. The name form keeps the key out of your shell history and pairs with a secret manager:\n\n```bash\nexport DEPLOYER_PK=\"$(op read 'op://Deploy Keys/deployer/private key')\"\nevm wallet send 0x5d0F...95eB --value 0.01 --private-key DEPLOYER_PK -c base --exec\n```\n\n### Environment variables\n\n| Variable | What it does |\n|---|---|\n| `EVM_ELF_PROFILE` | Profile to use when `-p` is not given; wins over `evm profile set-default` |\n| `EVM_ELF_CONFIG_DIR` | Where profiles and the user `.env` live (default: `$XDG_CONFIG_HOME/evm-elf`, else `~/.config/evm-elf`). Export it: it picks the directory a `.env` is read from, so it cannot come from one |\n| `ETHERSCAN_API_KEY` | Referenced by the bundled profile as `explorers.etherscan`, not read by the CLI directly. Exporting it without that reference does nothing |\n| `EVM_PRICE_SOURCE` | `coingecko` (the default when unset) or `none`; any other value is treated as `none`, see [Prices](#prices) |\n| `COINGECKO_API_KEY` | CoinGecko demo key; the public endpoint works without one |\n\nThe same environment supplies the `${VAR}` references in a profile, such as RPC URLs and header values. Variables are read from the real environment first, then `./.env`, then `~/.config/evm-elf/.env` — an already-set variable is never overwritten.\n\n### Prices\n\n`wallet balance` values native balances in USD through a pluggable source, selected with `EVM_PRICE_SOURCE`:\n\n| Value | Behaviour |\n|---|---|\n| `coingecko` (the default when unset) | One batched request to the public CoinGecko `simple/price` endpoint. No API key needed; set `COINGECKO_API_KEY` to use a demo key. |\n| `none` | No price lookups at all, the same as passing `--no-usd` everywhere. |\n| Anything else | Treated as `none`, with a warning on stderr. Setting the variable means you wanted to control the lookup, so an unrecognised value stops it rather than reaching for the network. |\n\nThe lookup is best-effort: a failing, rate-limited or slow source (5s timeout) leaves the USD column empty rather than failing the command. Which coin a chain's native token is comes from the profile (`symbol`, `coingecko_id`), so a chain without those falls back to a lowercase `ether` for the token and reports no price.\n\n## Requirements\n\n- Node.js 22+ (the `engines` field of [package.json](package.json))\n- An RPC endpoint per chain. The bundled profile ships the chains' own public endpoints; point the ones you use at your own provider with `evm chain set`.\n- An explorer API key for the explorer-backed fields of `proxy-info` and for `deploy-info`, stored with `evm explorer set`. Nothing else needs an API key.\n\n## Development\n\n```bash\nnpm install\nnpm run evm -- wallet balance 0x72B4...Be7a   # run from source via tsx\nnpm run build                                 # tsc -> dist/\nnpm run typecheck\nnpm run lint\n```\n\n`npm install` also builds, since `prepare` runs `tsc`. Pass CLI arguments after `--`, or npm reads them as its own.\n\n## License\n\n[MIT](LICENSE). Extracted from the `onchain-cli` workspace of `deploy-pad`, a private 1inch repository that is MIT too, so [LICENSE](LICENSE) carries both copyright notices.\n","readmeFilename":"README.md"}