This repository contains the MegaETH Wallet CLI. Follow the orchestration plan for task ownership and keep edits scoped to the files assigned to the active task unless a small adjacent test or documentation update is required.
The user-facing command shape is mega moss <command>. Examples,
agent-facing docs, and user-facing recovery messages should teach
mega moss ...; do not teach or rely on a standalone wallet command.
Core commands:
mega moss login: connect the local wallet account profile through loopback authorization.mega moss whoami: show the active account, delegated key, expiry, and limits.mega moss list: list locally known delegated/access keys and approved limits.mega moss permissions: show a key's approved scope and on-chain spend remaining. The stored spend request is not the same thing as live remaining capacity; usespendInfos[].remainingwhen judging whether another execution can fit.mega moss call: read-onlyeth_call; does not use the relay for writes.mega moss execute: submit state-changing calls through the MegaETH/Porto relay.mega moss transfer: convenience wrapper overexecute.mega moss fund: open the wallet deposit flow for the active account.mega moss debug: inspect local profile, balance, and relay key status without private key output.mega moss update: check/install the latest CLI release and bundled skill.mega moss logout: delete the local profile and delegated private key material; it does not revoke on-chain.
Mainnet is the default network. Testnet is supported with --network testnet
and uses a separate local profile path plus testnet chain/token defaults.
Human command output may use color or lightweight terminal animation only when
the relevant stream is a TTY and the environment is not CI, NO_COLOR, or a
dumb terminal. Keep --json and --terse stdout plain and stable. Auth
progress, browser fallback URLs, and terminal animation belong on stderr; final
command results belong on stdout. Human device-code auth prints a scannable
terminal QR for verificationUriComplete on stderr by default, including in a
chat shell or other non-TTY output. Eligible terminals may use ANSI contrast;
other human-output contexts use plain Unicode. --json and --terse omit the
terminal QR. --terse is compact final output, not a headless or
QR-presentation mode. Always retain the URL, user code, direct link, and expiry
fallback. --qr-file <absolute-path.png> is an advanced, explicitly requested
host-integration option. It writes a temporary mode-0600 PNG but does not
display or attach it; a local path is not user-visible. It requires
--auth-flow device and may coexist with --json or --terse for a verified
attachment host. Any actually visible terminal-text or attached-image QR must
be introduced with: “Scan this QR code or open this link in a browser where
your wallet is available.”
The release install path is repo-owned and deterministic:
scripts/install-release.shis the canonical release installer. Future releases publish it as a versioned GitHub Release asset, andhttps://account.megaeth.com/installshould remain a small hosted bootstrapper that downloads and verifies that release-owned installer before executing it. The release installer downloads the GitHub Release archive, verifies its.sha256checksum, installs a versioned release under~/.mega/wallet-cli/releases/, updates~/.mega/wallet-cli/current, writes the auto-updatingmegawrapper into~/.local/binby default, removes repo-owned legacywalletwrappers, and installs the bundled skill unless--no-skillis passed. The wrapper may check for a newer release before launching but must keep update notices on stderr and must not read wallet profiles or key material. It must not require pnpm or a source checkout.scripts/package-release.shbuilds the self-contained GitHub Release assets:mega-wallet-cli-<tag>.tar.gzplus.sha256, andmega-wallet-cli-<tag>-install.shplus.sha256. The archive must includedist/, productionnode_modules/,package.json,pnpm-lock.yaml,README.md,assets/,SKILL.md,references/,scripts/install-skill.sh, andscripts/uninstall.shso the public installer can install CLI and skill without building from source while leaving the documented uninstall path available undercurrent/scripts/uninstall.sh.scripts/install.shis the local checkout installer. It builds the CLI, installs a versioned release under~/.mega/wallet-cli/releases/, updates~/.mega/wallet-cli/current, and writes themegawrapper into~/.local/binby default. Source installs are development installs and should not auto-check for GitHub Release updates before launching;mega moss updatemay still intentionally converge them to the latest release. It should installscripts/uninstall.shinto the versioned release and remove any repo-owned legacywalletwrapper so stale compatibility shortcuts do not remain on PATH. It must check Node.js>=22and pnpm before building. Interactive runs may prompt to install missing prerequisites; non-interactive runs must fail with instructions instead of changing system tooling silently. Production wrappers should not bake a wallet URL override. Pass--wallet-url http://localhost:4000on local auth/fund commands when testing against a local wallet UI.scripts/install-skill.shinstalls the in-repo skill bundle (SKILL.mdplus bundled resources such asreferences/) into Codex, Claude, Hermes, and OpenClaw skill directories. The main installer installs all supported skill targets by default; use--no-skillfor binary-only installs.scripts/uninstall.shremoves local install artifacts for agent-readiness testing; wallet profiles are removed only when--configis passed.- Release tags must use strict
vX.Y.Zformat and match bothpackage.jsonandsrc/version.ts. The tag-triggered release workflow verifies that match, then publishes checksum-protected assets. After publication, refresh the bundled wallet skill inmegaeth-labs/skillsmanually from the exact release tag and submit any generated changes through a normal review pull request. pnpm install:local -- --dry-run,pnpm install:release -- --dry-run --version v0.1.0,pnpm install:skill -- --dry-run,pnpm package:release -- --dry-run --version v0.1.0, andpnpm uninstall:local -- --dry-runshould remain safe, non-mutating checks.
When changing installation behavior, update README.md, package scripts, and
the installer regression tests together. Installer scripts must not read wallet
profiles, private keys, or auth material.
mega moss login defaults to a native-app loopback flow:
- The CLI opens MegaETH Wallet at
/cli-auth/loopbackwithoperation=login, a high-entropystate, and a loopbackredirectUri. - The browser wallet approves connecting the wallet account to the local CLI profile.
- The browser redirects to
http://127.0.0.1:<random-port>/callbackwith the approved public account address. - The CLI validates
stateand persists the account profile without delegated private key material.
Login is a profile bootstrap command. If a profile already exists, it must fail
before browser auth and direct the user to either mega moss logout or
mega moss create-key. Use create-key to add delegated keys to an existing
wallet profile.
mega moss create-key is the delegated-key grant flow. It generates the
secp256k1 private key locally, opens MegaETH Wallet with the delegated public
address and requested permissions, validates the callback state/account, and
persists the private key only after approval.
If create-key fails because the authorized wallet account does not match the
local profile, treat it as a browser-wallet mismatch. Run mega moss whoami
to identify the expected account, then direct the user to switch the browser
wallet/profile to that account or intentionally mega moss logout and log in
again with the desired wallet. Failed mismatched authorizations must not be
stored locally.
Loopback requires the browser and CLI process to run on the same machine.
Device-code auth is available with --auth-flow device when approval should
happen in a browser where the user's wallet is available, including on a
different device. It creates a backend device request and, in human output,
prints a scannable QR code for the backend-supplied
verificationUriComplete, including in a chat shell or other non-TTY stream.
It always prints the URL, user code, direct link, and expiry as a fallback, then
polls the wallet API with PKCE until the wallet UI approves, rejects, or the
request expires. --json and --terse omit the terminal QR. Agent-run device
auth for login, create-key, and revoke must use the text-chat handoff below.
If the backend does not expose /v1/cli-auth/device, the CLI must fail before
polling with a clear fallback message.
The wallet may attach a short actionable reason when it rejects or cancels an authorization that cannot be approved. Preserve that reason in both loopback and device flows. Agents must correct the stated condition or ask the user for direction instead of retrying the same authorization unchanged. Do not invent a reason for an ordinary cancellation.
For a text-capable chat, run device auth in human mode with none of --json,
--terse, or --qr-file. Capture the complete static prompt before presenting
any of it. Strip ANSI escape sequences and carriage returns, preserve every
remaining space and line break, exclude polling or status lines, and present
the neutral instruction plus QR once in a single fenced text block. Never
forward partial QR chunks or interleave “Waiting for approval” output. The chat
UI may still paint the completed block progressively; the agent cannot
guarantee atomic client-side rendering. After the block, repeat the CLI-supplied
direct link as a clickable link and include the user code and expiry.
An agent must not choose --qr-file autonomously. Use it only when the user or
host explicitly requests a PNG and a real attachment/display API has already
been verified. Shell access, file access, and a local path are not attachment
capability. If preformatted text cannot be preserved, use --json or --terse
for a link-only fallback, state that no QR was shown, and do not treat that as
success when the task requires a visible QR.
The agent must keep the command in one persistent live session until approval,
rejection, or expiry. The device handoff must be visible before approval or
command completion; a handoff left in tool output or presented afterward is not
success. In text chat, never invoke mega moss ... --auth-flow device directly
as a foreground shell/tool call, even if the tool claims to stream output.
Start it asynchronously with the tool's background/session facility, or as one
background supervisor whose output is captured in a private temporary log and
which atomically writes a completion/status file after mega moss exits.
Inspect output immediately and use Waiting for approval... as the
complete-prompt marker. Poll on that marker and the completion file instead of
using a blind fixed sleep. Return control while the same CLI process remains
alive, send the QR, clickable direct link, CLI-supplied user code, and expiry in
an assistant-visible message, and only then make another tool call to wait for
the completion file. Do not use kill -0 alone for completion because a zombie
process still satisfies it. Never expose the backend device code or PKCE
verifier.
Ordinary browser-opened loopback auth should run in the foreground without backgrounding or fixed sleeps. If a loopback URL must be copied into chat, use the same persistent-session ordering so the URL is visible before the agent continues waiting.
--qr-file output must be removed after a forced termination if it remains;
the CLI removes it when authorization ends normally. Never reflow the captured
Unicode QR, synthesize a replacement, or submit the verification link to an
external QR service.
The loopback callback must never carry the delegated private key, bearer tokens, API keys, passkey material, or other transferable secrets. Login callbacks may carry only public account metadata. Create-key callbacks may carry public approval metadata required to reconstruct the authorized session key.
For development auth testing, start the wallet UI from the sibling wallet
checkout with a localhost origin:
cd ../wallet
pnpm dev -- --host localhost --port 4000The wallet UI expects its local API/relay shim on port 4002. Start the shim
from this repo before login:
node scripts/loopback-e2e.mjs --shim-only --shim-port 4002 \
--artifacts-dir .e2e/artifacts-local-debug \
--config-dir .e2e/config-local-shimUse --mock-relay only for no-chain E2E harness checks. Do not use it when
verifying that grantPermissions or revoke submits on-chain: mock mode returns
successful relay statuses without broadcasting a transaction. If the wallet UI
says approved but the shim sees no /rpc traffic, check that the browser origin
is http://localhost:4000 and that the wallet UI is using the local 4002
backend rather than production.
Run local auth E2E checks from this repo:
pnpm e2e:loopback -- --screen-only --mock-relay --reset
pnpm e2e:loopback -- --management --mock-relay --reset \
--wallet-url http://localhost:4000 \
--relay-url http://127.0.0.1:4002/rpc
pnpm e2e:loopback:relay-smoke
pnpm e2e:device:relay-smokeLogin should produce a profile with no delegated keys; create-key should
produce the first active delegated key. The --management run covers login,
create-key, list, permissions, label, switch, and revoke. Use the local
--relay-url value above when --mock-relay needs to exercise command-level
relay calls with the generated profile; it keeps those calls on the shim rather
than production.
The relay-smoke run uses a persistent development-only virtual WebAuthn profile
under this checkout's .e2e/relay-smoke, creates or reuses a scoped
e2e-relay-smoke key, and submits a real 0.0001 USDM self-transfer. It must
not be run with --mock-relay; the cached wallet needs enough USDM for the
transfer and relay fee. Do not pass --reset to relay-smoke runs. This state
is intentionally separate from local wallet-cli installs and profiles, so
scripts/install.sh and scripts/uninstall.sh --config must not remove it.
Delete .e2e/relay-smoke manually only when intentionally replacing the funded
smoke wallet.
pnpm e2e:device:relay-smoke uses the same persistent funded wallet but
creates or reuses a separate e2e-relay-smoke-device delegated key through the
local shim's device-code endpoints.
The delegated key is a Porto/MegaETH session key, not a passkey/root/admin key. It must not be treated as equivalent to the user's passkey. Session authority is bounded by expiry, call permissions, spend permissions, and relay/account enforcement.
Be precise about empty fields versus omitted fields:
permissions.calls: []means no app-level call scopes were requested. A key with spend allowance butcalls: []cannot perform useful ERC20, swap, protocol, or other contract-write actions because those all require contract calls.permissions.spend: []means no explicit asset spend scopes were requested.- Omitted
permissions.callsis not broad call authority in relay execution. It has produced approvals that look funded but fail writes with delegated-key permission errors. Reject omittedpermissions.callsin CLI/auth request files.
permissions.calls scopes which target/function selectors the key may execute.
For example, a transfer-only USDC scope should include the USDC token address
and transfer(address,uint256). CLI-created call scopes must include both
to and signature; do not create broad or partial call entries. Native ETH
transfers use the recipient address as to and 0xe0e0e0e0 as the no-calldata
selector. Reject the reserved wildcard address
0x3232323232323232323232323232323232323232 and selector 0x32323232.
permissions.spend scopes how much native/token value can leave the account for
a period. Native token spend uses the zero address in CLI spend-limit args and
may appear as zero-address or omitted native token data in stored profiles and
Porto/relay internals.
Delegated-key relay fee metadata is represented by feeToken; workflow
token/native movement is represented by permissions.spend. The CLI should
send --fee-token/--fee-limit as explicit request-level feeToken metadata,
and add or merge matching fee spend capacity into spend rows. The wallet UI user
may still select the Gas Token for the approval transaction itself, and the
returned authorizedKey.feeToken is the default token later used by execute
and transfer. Be careful when changing defaults or copy around this: UI text
like "fees" is product shorthand over delegated-key fee metadata, not workflow
spend authority.
The create-key default keeps the visible approval simple: one-week expiry, a
100 USDM workflow spend cap, and roughly $1 of relay-fee capacity in the
default fee token.
It must not silently request broad call authority. Require explicit call scopes
from --allow-call, copied permissions from --from, or a full
--permissions file. Do not create CLI write keys with omitted or empty
permissions.calls, or with call entries that
omit either to or signature. Keep those caps and call-scope requirements
explicit in prompt/UI copy, avoid ambiguous empty or omitted permissions, and
update README.md, SKILL.md, tests, and this file together when changing the
default.
mega moss create-key --spend-limit <token_address>:<amount>:<period> adds a
workflow spend row to the new key request. It accepts only 20-byte token
addresses; use 0x0000000000000000000000000000000000000000 for native ETH.
Amount is a human token amount, and period must be minute, hour, day,
week, month, or year. The flow still requires --allow-call, --from,
or --permissions to define executable call scope. Use a full --permissions
file for custom expiry or no-spend requests.
mega moss create-key --fee-token <symbol> --fee-limit <amount> requests a
delegated-key fee token and limit in human fee-token units. The CLI adds or
merges matching fee spend capacity into permissions.spend. If omitted, the
limit should default to roughly $1 in the selected fee token, not a fixed
one-token amount. If either fee option is present and no --spend-limit is
supplied, the CLI requests fee spend capacity but no workflow spend capacity;
add explicit spend rows for workflow token movement. Supported shorthand
fee-token symbols are ETH, USDM, USDT0, and MEGA on mainnet, and ETH,
USDM, and TST on testnet. Revoke should pass the stored key fee token to the
wallet UI by default and support --fee-token <symbol> only as the relay
payment token for that revoke transaction.
pnpm build
pnpm test
pnpm lint
pnpm typecheck
pnpm formatWhen adding or changing wallet commands, update the command unit tests in
src/commands/*.test.ts, the shared helpers they depend on, README.md,
SKILL.md, and this file in the same commit. New user-facing commands must be
wired through registerWalletCommands and tested through the canonical
mega moss <command> shape.
For mainnet command-level regression checks, use:
pnpm e2e:functionalThis uses the current mainnet local profile and performs validation plus read-only protocol/USDM calls. Paid relay writes are opt-in:
pnpm e2e:functional:writesOnly run paid write mode when the active delegated key has the required call
scopes for the tested transfer/approval/protocol functions, and the test wallet
has enough USDM to cover relay fees. Add
-- --include-timeout only when deliberately testing timeout UX.
- Never print or log private keys, authorization blobs, API keys, bearer tokens, passkey material, or relay secrets.
- Never inspect wallet profile files directly, including with
cat,sed,rg, or editor reads. Usemega moss whoami,mega moss list,mega moss permissions, andmega moss debugfor profile, key, and permission state. - Do not put secrets in URLs. Loopback callback URLs may carry state and approved public metadata only.
- Device-auth QR codes may encode only the backend-supplied
verificationUriComplete; never encode the device code, PKCE verifier, delegated private key, or authorization material. - Agent-visible device-auth handoffs must use the text-chat procedure above.
Capture a complete terminal QR, strip ANSI escapes and carriage returns,
preserve its remaining whitespace exactly, and present it once in a fenced
textblock without polling or status output. Actual chat rendering may still stream.--qr-fileis only for an explicitly requested, verified host attachment integration; the CLI does not display or attach the PNG. Otherwise provide the direct link, code, and expiry without claiming a QR was shown. Never reconstruct a QR or disclose the complete verification URL to an external QR-generation service. The CLI must remove a PNG on normal auth completion and make a best-effort process-exit cleanup; a hard kill may leave only a mode-0600, soon-expired artifact. - Persist canonical authorization data exactly as approved by the wallet. Treat summaries shown by CLI commands as derived output.
- Keep profile files private to the local user when implementing storage.
- The local profile contains delegated private key material. Preserve
0600file permissions and redact profile contents in logs, errors, tests, and docs. - Treat
mega moss logoutas a destructive local forget operation: it deletes the local profile and delegated private key material without revoking the on-chain key authorization. - Do not construct JSON or calldata by string concatenation for wallet or relay payloads. Use structured encoders/parsers and validate untrusted callback and profile data.
- Map relay/account authorization failures to clear delegated-key permission errors; do not expose raw internals unless running an explicit debug path.
- Do not revert changes made by other workers.
- Stage only files owned by the current task.
- Use conventional commits with no AI attribution.
- Never push, force-push, delete, or move a remote tag, and never trigger a GitHub Release workflow, without explicit confirmation from the user in the current task. Before any approved release/tag repair, state the exact tag, commit, release assets, workflow state, and verification steps. If a workflow is disabled for an approved tag repair, verify no release run is queued or in progress before re-enabling it.