# MetaMask Agent Wallet documentation

> Complete documentation for MetaMask Agent Wallet

Version: CLI 7.2.0

If you are an AI agent operating the `mm` CLI, read "Rules for AI agents" first.
If you can load skills, install `npx skills add MetaMask/agent-skills` and prefer the skill.

- Never choose the sign-in method, wallet mode, or trading mode for the user. Ask, then pass `--wallet` and `--mode` explicitly.
- Each sign-in method (Google, email, MetaMask Mobile QR) loads a different wallet address.
- `AWAITING_MFA` or `pending_approval` means the request is waiting for the user's 2FA approval. It has not failed. Tell the user where to approve: the MetaMask Mobile notifications menu for QR sign-in, or the approval email for browser sign-in.
- Confirm recipient, amount, token, and chain with the user before moving funds.

## Rules for AI agents


This page is for AI agents that run the `mm` CLI on a user's behalf.
Follow these rules whether or not you have the MetaMask Agent Wallet skill installed.

If you can load skills, install the skill and prefer it:

```bash
npx skills add MetaMask/agent-skills
```

The canonical rules live in the
[MetaMask Agent Wallet skill](https://github.com/MetaMask/agent-skills/blob/main/skills/metamask-agent-wallet/SKILL.md)
(`metamask-agent-wallet`).
This page mirrors them for agents that read the documentation instead.

## Before the first command

Run these checks once per session, in order.

1. **Check the CLI version.**

   ```bash
   mm --version
   npm view @metamask/agent-wallet version
   ```

   If the installed version is behind the latest release, tell the user once and continue.
   They can update with `npm install -g @metamask/agent-wallet@latest`.
   The CLI requires Node.js 22.18 or later.
   On older versions every command fails with `UNSUPPORTED_NODE`.

2. **Check readiness.**

   ```bash
   mm doctor
   ```

   Don't run any other command until `mm doctor` reports both `authenticated: true` and
   `initialized: true`.

   - `authenticated: false`: help the user sign in. See [Quickstart](quickstart.md).
   - `initialized: false`: help the user run `mm init`. See the next section.

   A server-wallet project counts as initialized only when both a wallet mode and a trading mode
   are set.

## Choices you must leave to the user

Never make these choices for the user.
Explain the options, ask, and pass the answer explicitly.

| Choice                                               | Why it matters                                                                              | How to pass it                           |
| ---------------------------------------------------- | ------------------------------------------------------------------------------------------- | ---------------------------------------- |
| Sign-in method (Google, email, QR)                   | Each method loads a different wallet address. It also decides where 2FA approvals are sent. | `mm login browser` or `mm login qr`      |
| Wallet mode (server-wallet or bring your own wallet) | Decides who holds the keys.                                                                 | `mm init --wallet <server-wallet\|byok>` |
| Trading mode (Guard Mode or Beast Mode)              | Decides which guardrails apply and which transactions need 2FA approval.                    | `mm init --mode <guard\|beast>`          |

In a non-interactive session, `mm init` sets Guard Mode when you omit `--mode`.
Don't rely on that.
Ask the user and pass `--mode`.

Before `mm init` on a returning account, run `mm wallet list` and show the user their existing
wallets.
See [Switch modes and wallets](switch-modes-and-wallets.md).

## Confirm before you act

Show the user these details and get an explicit yes before running the command.

| Operation                           | Confirm                                                                                                                                                    |
| ----------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Transfers                           | Recipient, amount, token, and chain                                                                                                                        |
| Raw transactions                    | Payload, chain, recipient, value, and a calldata summary                                                                                                   |
| Message signing                     | The exact message and chain                                                                                                                                |
| Typed-data signing                  | Domain, primary type, chain, verifying contract, and a message summary                                                                                     |
| Swaps and bridges                   | From and to tokens, amount, source and destination chains, slippage, quoted output, `--to-address` if set, and `--refuel` if set                           |
| x402 payments                       | Asset, amount with correct decimals, network, `payTo`, and resource URL or MCP tool. Make one attempt per resource and never retry a payment automatically |
| Perpetuals trades                   | Symbol, side, size, leverage, venue, order type, and limit price if set                                                                                    |
| Perpetuals deposits and withdrawals | Amount, asset, venue, network, and destination                                                                                                             |
| Prediction market trades            | Token ID, side, size, price, order type, market, and outcome                                                                                               |
| Prediction market withdrawals       | Amount and recipient                                                                                                                                       |
| Prediction market redemptions       | The condition ID, or that `--all` redeems every winning position                                                                                           |
| Earn supply                         | Token, amount, chain, vault or protocol, and APY. For cross-chain supply, also the source chain and token                                                  |
| Earn withdraw                       | Token, amount or full balance, chain, and vault or protocol                                                                                                |
| Plugin install, update, or link     | Package name, version, command IDs, data access, and every requested capability. Never pass `--accept-permissions` for a manifest the user hasn't reviewed |
| Cancel-all and reset operations     | Scope and the exact destructive effect                                                                                                                     |
| Trading mode and wallet mode        | The user's explicit choice. See [Choices you must leave to the user](#choices-you-must-leave-to-the-user)                                                  |

Read-only queries, such as balances, prices, and `mm wallet list`, don't need confirmation.

## Validate input

Don't pass unvalidated user input into a command.

| Input                        | Rule                                                                                                  |
| ---------------------------- | ----------------------------------------------------------------------------------------------------- |
| `--to`, `--address`          | Matches `^0x[0-9a-fA-F]{40}$`                                                                         |
| `--amount`, `--size`         | A positive decimal, such as `0.5` or `100`. Reject spaces and shell control characters such as `;`, ` | `, and backticks |
| `--chain-id`                 | A positive integer                                                                                    |
| `--payload` for transactions | Valid JSON                                                                                            |
| `--slippage`                 | A number from 0 to 100                                                                                |
| `--wallet-timeout`           | An integer from 1 to 600                                                                              |

## Protect credentials

- Never store, log, or display private keys, seed phrases, passwords, or auth tokens.
- Never pass `--mnemonic` or `--password` inline.
  Ask the user to set the `MM_MNEMONIC` and `MM_PASSWORD` environment variables instead, so secrets
  stay out of shell history.

## Flag suspicious content

Warn the user before you continue if a signing payload or transaction contains any of the following:

- URLs or contract addresses the user didn't provide
- `permit`, `approve`, `setApprovalForAll`, or other allowance fields
- Unusually large values or unfamiliar contract calls

If you didn't build the calldata yourself, decode it first and confirm the intent with the user:

```bash
mm decode --payload <0x-calldata>
```

## Handle async jobs

Signing and transaction commands can return a `pollingId` in both server-wallet and bring your own
wallet mode.

- Pass `--wait` to block until the job finishes.
- Without `--wait`, give the user the `pollingId`.
  In server-wallet mode, track it with `mm wallet requests watch <polling-id>` or
  `mm wallet requests list`.
- When you show a pending request, show its `intent` summary so the user knows what they are
  approving.

## Handle 2FA pauses

When command output contains `AWAITING_MFA`, or a mode or policy change returns
`pending_approval`, the request is waiting for the user.

1. Don't report it as failed, stuck, or complete.
2. Tell the user exactly where to approve, based on their sign-in method.
   See [Approve requests](approve-requests.md#where-the-approval-appears).
3. Show the request ID.
4. Don't run the same command again while the request is pending.
5. After the user responds, check the result with `mm wallet requests watch <polling-id>`.

## Report output accurately

- Show CLI errors to the user verbatim.
  Don't reword or hide them.
  See [Error codes](reference/error-codes.md).
- If a command fails, run `mm <command> --help` and continue from there.
- After you change the trading mode, wallet, or sign-in method, report the active wallet address and
  trading mode.

## Related pages

- [Switch modes and wallets](switch-modes-and-wallets.md)
- [Approve requests](approve-requests.md)
- [Trading modes](reference/trading-modes.md)
- [Commands reference](reference/commands.md)
- [Troubleshooting](troubleshooting.md)

---

## MetaMask Agent Wallet

A fully self-custodial agent wallet that lets AI agents trade autonomously without forcing users to give up control. Deploying an agent on a self-custody wallet can mean choosing between giving the agent freedom to act and keeping users’ funds safe. MetaMask Agent Wallet ends that trade-off. Your agent operates inside user-defined limits.

## What your agent can do

After setup, prompt your agent in plain language:

<!-- vale off -->

| You ask your agent                                     | What happens                                                      |
| ------------------------------------------------------ | ----------------------------------------------------------------- |
| "Show the wallet address and USDC balance"             | Your agent checks auth, then queries balances.                    |
| "Send 10 USDT to 0x123… on Ethereum"                   | Your agent confirms details, then submits a transfer.             |
| "Swap 0.1 ETH to USDC on Base"                         | Your agent fetches a quote, confirms with you, then executes.     |
| "Open a 5x long on BTC with $100 on Hyperliquid"       | Your agent deposits if needed, quotes, and opens the position.    |
| "Bet 10 USDT on YES for BTC 5-min price up"            | Your agent searches markets, confirms odds, and places the order. |
| "Supply 100 USDC to a yield vault on Base"             | Your agent finds vaults, compares APYs, and supplies your tokens. |
| "Book and Pay for my flight ticket at api.example.com" | Your agent inspects the x402 offer, confirms with you, then pays. |

<!-- vale on -->

## MetaMask safety-checks every transaction before it lands

Security by default, not configuration.
Supported EVM transactions pass through a mandatory 3-step pipeline before they land onchain.

1. **Transaction simulation**: What will this transaction actually do? Balance changes, approvals,
   and gas are surfaced before signing.

<!-- vale off -->

2. **Threat scanning**: Powered by Blockaid and production-tested across millions of MetaMask
   transactions. Malicious transactions get auto-bounced. Flagged transactions require your approval
   before they execute.

<!-- vale on -->

3. **[Smart Transactions](https://support.metamask.io/manage-crypto/transactions/smart-transactions/)**:
   Smart transaction execution with built-in MEV protection, fewer fails, and better gas where
   supported on the target chain.

Eligible transactions deemed safe are backed by
[Transaction Protection](https://support.metamask.io/manage-crypto/transactions/transaction-shield/)
coverage up to $10,000/month.\*

:::note

Learn more in [Architecture](reference/architecture.md). See
[Transaction Shield](https://support.metamask.io/manage-crypto/transactions/transaction-shield/) for
subscription details, eligibility, coverage limits, and terms.

:::

## Capabilities

The `mm` CLI exposes a full command surface for wallet operations.
Your agent routes natural-language requests to these commands through installed skills.

<!-- vale off -->

| Area                                                                | What your agent can do                                          |
| ------------------------------------------------------------------- | --------------------------------------------------------------- |
| [Authentication](quickstart.md)                                     | Sign in, verify with `mm doctor`, sign out                      |
| [Wallet](guides/check-balances-and-prices.md)                       | Create wallet, show address, check balances, tx history         |
| [Send](guides/send-tokens.md)                                       | Transfer native tokens and ERC-20s                              |
| [Sign / raw transactions](guides/sign-messages-and-transactions.md) | Sign messages, typed data, and raw EVM transactions             |
| [Decode calldata](guides/sign-messages-and-transactions.md)         | Inspect unfamiliar EVM calldata before signing                  |
| [Swap / bridge](guides/swap-and-bridge.md)                          | Quote, execute, and track swaps and cross-chain bridges         |
| [Perpetuals](guides/trade-perpetuals.md)                            | Trade on Hyperliquid (deposit, open, modify, close)             |
| [Prediction markets](guides/trade-prediction-markets.md)            | Search, quote, trade, and redeem on Polymarket                  |
| [Earn (yield vaults)](guides/earn-yield-vaults.md)                  | Supply and withdraw across chains and protocols, including Aave |
| [x402 payments](guides/pay-for-apis-x402.md)                        | Pay for HTTP 402 paywalled APIs and endpoints                   |
| [Market data](guides/check-balances-and-prices.md)                  | Spot prices, token discovery, supported chains                  |
| [Plugins](plugins/index.md)                                         | Extend Agent Wallet with custom commands from npm packages      |

<!-- vale on -->

See the [commands reference](reference/commands.md) for every flag and subcommand.

## Supported chains

MetaMask Agent Wallet supports multiple EVM chains.
Run `mm chains list` for the authoritative list for your CLI version.
See [Supported chains](reference/supported-chains.md) for typical networks.

## Set up

<CardList
  items={[
    {
      href: '/agent-wallet/quickstart',
      title: 'Quickstart',
      description:
        'Install the CLI, add skills to your agent, sign in, and send your first transfer.',
    },
    {
      href: '/agent-wallet/reference/architecture',
      title: 'Architecture',
      description:
        'Wallet modes, threat scanning, Transaction Protection, Smart Transactions, and 2FA.',
    },
    {
      href: '/agent-wallet/guides/trade-perpetuals',
      title: 'Trade perpetuals',
      description: 'Deposit, open, modify, and close Hyperliquid positions.',
    },
    {
      href: '/agent-wallet/guides/earn-yield-vaults',
      title: 'Earn with yield vaults',
      description: 'Supply and withdraw from yield vaults across chains and protocols.',
    },
    {
      href: '/agent-wallet/reference/trading-modes',
      title: 'Trading modes',
      description:
        'Compare Guard Mode and Beast Mode guardrails, 2FA approval, and outflow limits.',
    },
    {
      href: '/agent-wallet/approve-requests',
      title: 'Approve requests',
      description:
        'Find where 2FA approvals appear for your sign-in method, and track pending requests.',
    },
    {
      href: '/agent-wallet/agent-rules',
      title: 'Rules for AI agents',
      description:
        'What agents must confirm, which choices to leave to the user, and how to handle 2FA pauses.',
    },
  ]}
/>

---

## Quickstart


Follow these steps in order.
Each step tells you what you are doing, why it matters, and what to do next.

## Before you start

- **Node.js** 22.18 or later
- An AI agent that supports skills (Claude Code, Codex, Cursor, OpenClaw, Hermes Agent, or similar)

## Step 1: Install the CLI

The `mm` CLI is how your agent signs in, checks balances, and sends transactions.

```bash npm2yarn
npm install -g @metamask/agent-wallet@latest
```

## Step 2: Add skills to your agent

Skills teach your agent which `mm` commands to run and when to ask for your confirmation before
moving funds.

```bash
npx skills add MetaMask/agent-skills
```

When prompted, install `metamask-agent-wallet`.
See the [agent-skills changelog](https://github.com/MetaMask/agent-skills/blob/main/CHANGELOG.md)
for the latest skill version and the CLI version it targets.

## Step 3: Start setup with your agent

Open your agent and paste:

```text
Set up MetaMask Agent Wallet: help me pick a sign-in method, wallet mode, and trading mode, then show my address.
```

Your agent asks which sign-in method you want, then runs the setup commands.
The next steps walk through what happens on your screen.

## Step 4: Sign in

Pick one sign-in method and keep using it.
**Google**, **email passwordless**, and **MetaMask Mobile QR** are three separate methods.
Each one loads a **different wallet address**, even if you use the same email across them.

| Method                 | How you sign in                                   |
| ---------------------- | ------------------------------------------------- |
| **Google**             | **Continue with Google** in the browser dashboard |
| **Email passwordless** | **Continue with email** in the browser dashboard  |
| **MetaMask Mobile QR** | Scan a QR code with MetaMask Mobile               |

Using the same email for Google, email sign-in, and MetaMask Mobile does not give you the same
wallet. Every method has its own address.

### Google or email (browser)

Your agent opens the Agent Wallet dashboard in your browser.

1. Sign in with **Continue with Google** or **Continue with email** (pick one and keep using it).
2. Click **Authorize**.
3. Copy the CLI token from the browser and paste it into your terminal if prompted.

If you choose **email**, check your inbox for a verification code and enter it in the browser
before you click **Authorize**. That code is only for sign-in.

### MetaMask Mobile QR

Your agent shows a QR code in the terminal.

1. Open **MetaMask Mobile** on your phone.
2. Scan the QR code.
3. Approve the connection in the app.

You do not use a browser for this path.
Your terminal stays connected while you scan and approve.

## Step 5: Choose how your agent holds funds

Your agent asks you to pick a **wallet mode**:

| Mode                      | Best for                                                                                                         |
| ------------------------- | ---------------------------------------------------------------------------------------------------------------- |
| **Server wallet**         | Most users. Keys stay secured server-side so your agent gets a dedicated wallet without access to your main one. |
| **Bring your own wallet** | You already have a seed phrase and want keys to stay on your machine.                                            |

## Step 6: Choose your safety settings

Your agent asks you to pick a **trading mode**:

| Mode                         | Best for                                                                                                  |
| ---------------------------- | --------------------------------------------------------------------------------------------------------- |
| **Guard Mode (Recommended)** | Everyday use. Allowlists, outflow limits, and your approval when a transaction falls outside your policy. |
| **Beast Mode**               | Power users who want fewer limits. Malicious transactions still need your approval.                       |

See [Trading modes](reference/trading-modes.md) if you want the full comparison before you choose.

Your agent should ask you rather than choose for you.
If you signed in to this account before, setup loads your existing wallet and its trading mode
instead of asking.
You can change the mode later. See [Switch modes and wallets](switch-modes-and-wallets.md).

## Step 7: Fund your wallet

Your agent shows your wallet address when setup finishes.
Confirm it, then send funds from another wallet or exchange.

Ask your agent anytime:

```text
Show my wallet address and balance.
```

## Step 8: Approve flagged transactions

After setup, your agent can send transactions on your behalf within the limits you chose.
When a transaction needs your OK:

- **Google or email sign-in**: you get an email at the address registered to your dashboard. Open
  the link and approve or reject.
- **MetaMask Mobile QR**: open MetaMask Mobile and go to the **notifications menu**. The request is
  listed there even if no push notification arrives.

See [Approve requests](approve-requests.md) if you can't find the approval.

## Next steps

- [Send tokens](guides/send-tokens.md)
- [Switch modes and wallets](switch-modes-and-wallets.md)
- [Approve requests](approve-requests.md)
- [Troubleshooting](troubleshooting.md)
- [CLI setup](cli-setup.md) — command-by-command setup for the terminal or agents without skills

---

## CLI setup


Complete Agent Wallet setup with the `mm` CLI command by command.

Use this page if you are running setup in a terminal, automating in CI, or if your agent does not
have MetaMask skills installed and needs a full setup reference.
For the fastest path with skills, see [Quickstart](quickstart.md).

## Prerequisites

- **Node.js** 22.x or later

## 1. Install the CLI

```bash npm2yarn
npm install -g @metamask/agent-wallet@latest
```

Run `mm doctor` after install to confirm the CLI version and skill compatibility.

:::note Node.js requirement
The CLI requires **Node.js 22.18** or later.
:::

## 2. Complete setup

Step through sign-in and wallet initialization:

```bash
mm doctor
mm login
mm init
mm doctor
```

Or run `mm` with no arguments for the interactive REPL.

### Verify readiness

Run `mm doctor` before your first wallet operation.
Do not send transactions until the output shows `authenticated: true` and `initialized: true`.

If either flag is false, follow the hints in the output (sign in, run `mm init`, or reinstall
skills), then run `mm doctor` again.

## 3. Sign in

Run `mm login` and choose a method, or pass it explicitly:

```bash
mm login browser   # Google or email in the browser
mm login qr        # Scan with MetaMask Mobile
```

:::caution Three sign-in methods, three wallet addresses

**Google**, **email passwordless**, and **MetaMask Mobile QR** each load a different server-wallet
address.
Using the same email for all three does not link them to one wallet.
After every sign-in, run `mm wallet address` and confirm the expected address before you fund it.

See [Troubleshooting](troubleshooting.md) for sign-in errors and wallet recovery.

:::

### Browser (Google or email)

1. Your browser opens the Agent Wallet dashboard.
2. Sign in with **Continue with Google** or **Continue with email**.
3. Click **Authorize**.
4. Copy the CLI token from the browser and paste it into the waiting terminal.

| Step     | Google                                            | Email passwordless                                      |
| -------- | ------------------------------------------------- | ------------------------------------------------------- |
| Sign in  | **Continue with Google**                          | Enter email, then the verification code from your inbox |
| Link CLI | Copy the CLI token and paste it into the terminal | Same                                                    |

### MetaMask Mobile QR

1. The terminal displays a QR code.
2. Open **MetaMask Mobile** and scan the code.
3. Approve the connection in the app.

The CLI waits for the scan and approval. QR sign-in does not support `--no-wait`.

Confirm sign-in succeeded:

```bash
mm auth status
mm wallet list
mm wallet address
```

Your sign-in method determines where 2FA approvals are sent: an email link for browser sign-in, or
the MetaMask Mobile notifications menu for QR sign-in.
See [Approve requests](approve-requests.md).

## 4. Initialize wallet

If `mm doctor` reports `initialized: false`, run `mm init` and choose a wallet mode and, for
server-wallet, a trading mode.

If the account already has server wallets, `mm init` syncs them and loads each wallet's trading mode
from the server. `--mode` is ignored.
If the account has no wallet, `mm init` creates one.
In a non-interactive session, `mm init` sets Guard Mode when `--mode` is omitted, so always pass
`--mode` with the user's choice.
Run `mm wallet list` before `mm init` if you are returning to an existing account.
See [Switch modes and wallets](switch-modes-and-wallets.md#what-mm-init-does-after-you-sign-in).

### Wallet mode (choose one)

- **Server wallet**: keys are managed and secured server-side in a TEE, so agents can't access your
  main wallet. Signing uses an asynchronous model; long-running operations return a `pollingId` unless
  you pass `--wait`.

  ```bash
  mm init --wallet server-wallet --mode guard
  ```

- **Bring your own wallet**: you supply a BIP-39 mnemonic. Keys stay under your local control and
  signing happens locally. Signed requests are still submitted as jobs, so commands can return a
  `pollingId` unless you pass `--wait`.

  ```bash
  export MM_MNEMONIC="word1 word2 ..."
  mm init --wallet byok --mode guard
  ```

  Optionally encrypt the mnemonic at rest with `mm wallet password set`.

### Trading mode (server wallet only)

| Mode                     | CLI flag       | Summary                                                                                           |
| ------------------------ | -------------- | ------------------------------------------------------------------------------------------------- |
| Guard Mode (Recommended) | `--mode guard` | Designed for everyday traders. Transactions outside your policy limits require 2FA approval.      |
| Beast Mode               | `--mode beast` | Designed for power users. Malicious transactions are still blocked and surfaced for 2FA approval. |

Guard Mode enforces threat scanning, network and recipient allowlists, address allowlists, and a
rolling 24-hour outflow limit.
Beast Mode keeps only the threat scanning guardrail.

See [Trading modes](reference/trading-modes.md) for guardrails and approval conditions.

Switch modes after setup:

```bash
mm wallet trading-mode set guard
mm wallet trading-mode set beast
```

Switching to Beast Mode needs your 2FA approval. Switching to Guard Mode applies immediately.
See [Switch modes and wallets](switch-modes-and-wallets.md).

Confirm your choices:

```bash
mm init show
mm wallet trading-mode get
mm wallet policy get
```

## 5. Fund and verify

Get your Agent Wallet address:

```bash
mm wallet address
mm wallet add-fund
```

Transfer funds to this address on the chain you plan to use (from another wallet or exchange).

Verify the deposit:

```bash
mm wallet balance --chain-ids <chain-id>
```

Confirm your balance before you send transactions from this wallet.

## 6. Send your first transfer

```bash
mm transfer --to <ADDRESS> --amount 0.001 --token native --chain-id 8453 --wait
```

## Headless and CI environments

```bash
mm login browser --no-wait
mm login --token "<cliToken:cliRefreshToken>"
```

Bare `mm login --no-wait` fails without a TTY because no sign-in method is selected.
Use `mm login browser --no-wait` to print a dashboard sign-in URL.
After you authorize in the browser, paste the CLI token into a separate
`mm login --token` invocation.

## Machine-readable output

Pass `--format json` or `--json` for scripts and automation:

```bash
mm wallet balance --chain-ids 8453 --json
mm auth status --json
mm doctor --json
```

## Next steps

- [Commands reference](reference/commands.md)
- [Quickstart](quickstart.md) — set up through your agent with skills
- [Troubleshooting](troubleshooting.md)

---

## Switch modes and wallets


You can switch four things after setup.
Two of them change which wallet address your agent uses.

| What you switch                               | Command                                     | Changes your wallet address?           | Needs 2FA approval?                                         |
| --------------------------------------------- | ------------------------------------------- | -------------------------------------- | ----------------------------------------------------------- |
| [Trading mode](#switch-trading-mode)          | `mm wallet trading-mode set <guard\|beast>` | No                                     | Guard Mode to Beast Mode: yes. Beast Mode to Guard Mode: no |
| [Active wallet](#switch-the-active-wallet)    | `mm wallet select <address>`                | Yes, to another wallet you already own | No                                                          |
| [Sign-in method](#change-your-sign-in-method) | `mm logout`, then `mm login`                | **Yes, always**                        | No                                                          |
| [Wallet mode](#change-wallet-mode)            | `mm init --wallet <server-wallet\|byok>`    | Yes                                    | No                                                          |

## Switch trading mode

Each wallet has its own trading mode.
Switching changes the mode of the active wallet only.

Check the current mode:

```bash
mm wallet trading-mode get
```

Switch to Beast Mode or Guard Mode:

```bash
mm wallet trading-mode set beast
mm wallet trading-mode set guard
```

- **Guard Mode to Beast Mode** loosens your guardrails, so it needs your 2FA approval.
  The command waits until you approve or reject.
  See [Approve requests](approve-requests.md) for where the approval appears.
- **Beast Mode to Guard Mode** tightens your guardrails, so it applies immediately.

The 2FA approval is the only confirmation. The terminal shows no separate prompt.

The command returns `status: confirmed` when the change is applied.
With `--no-wait`, or if the wait ends before you respond, it returns `status: pending_approval` and
a `requestId`.
Run `mm wallet trading-mode get` to check whether the change was applied.

| Error code                         | Meaning                                               |
| ---------------------------------- | ----------------------------------------------------- |
| `ALREADY_SET_TRADING_MODE`         | The wallet is already in that mode                    |
| `INVALID_TRADING_MODE`             | The mode is not `guard` or `beast`                    |
| `WALLET_MODE_APPROVAL_IN_PROGRESS` | A trading mode change is already waiting for approval |
| `TRADING_MODE_APPROVAL_REJECTED`   | You rejected the change                               |
| `TRADING_MODE_APPROVAL_EXPIRED`    | The approval expired before you responded             |

:::caution

In CLI v7.2.0, the usage line in `mm wallet trading-mode set --help` and the hint after `mm init`
show `mm mode set`.
That command doesn't exist.
Use `mm wallet trading-mode set`.

:::

See [Trading modes](reference/trading-modes.md) to compare the guardrails in each mode.

## Switch the active wallet

One account can hold more than one wallet.
Commands always use the active wallet.

List your wallets, then select one by address:

```bash
mm wallet list
mm wallet select 0x742d35Cc6634C0532925a3b844Bc9e7595f2bD18
mm wallet address
```

Always pass the address.
Without an address, `mm wallet select` opens an interactive picker, which needs a terminal (TTY).
In a non-interactive session, it returns `MISSING_WALLET_REF`.

| Error code            | Meaning                                                     |
| --------------------- | ----------------------------------------------------------- |
| `MISSING_WALLET_REF`  | No address was passed in a non-interactive session          |
| `INVALID_EVM_ADDRESS` | The address is malformed                                    |
| `WALLET_NOT_FOUND`    | The address isn't one of your wallets. Run `mm wallet list` |
| `WRONG_NAMESPACE`     | The wallet belongs to a different chain namespace           |

To add another wallet to the same account, run `mm wallet create`.
Pass `--name` to label it and `--trading-mode <guard|beast>` to set its trading mode.

## Change your sign-in method

**Google**, **email passwordless**, and **MetaMask Mobile QR** are three separate sign-in methods.
Each one signs you in to a separate account with its own wallets.
Switching methods always loads a different wallet address, even when you use the same email for
more than one method.

Funds stay onchain at the original address.
They don't appear in the CLI until you sign in with the method you used to fund that wallet.

If your wallet address changed after you signed in again:

1. Sign out:

   ```bash
   mm logout
   ```

2. Sign in with the method you used when you funded the wallet.
3. Confirm the address:

   ```bash
   mm wallet list
   mm wallet address
   ```

Steps inside one sign-in method, such as entering the email verification code or pasting the CLI
token, don't change your wallet.

## What `mm init` does after you sign in

`mm init` behaves differently depending on whether the account already has a wallet.
This is why signing in with a new method can create a new wallet.

| Account state                                  | What `mm init` does                                                                                                                                                                |
| ---------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Has server wallets                             | Syncs the existing wallets and loads each wallet's trading mode from the server. `--mode` is ignored. In a non-interactive session with several wallets, it selects the first one. |
| Has no server wallet                           | Creates a new wallet and asks for a trading mode.                                                                                                                                  |
| No trading mode given, non-interactive session | Sets Guard Mode. Pass `--mode` to choose explicitly.                                                                                                                               |

Before you run `mm init` on an account you have used before, run `mm wallet list` to see which
wallets it already has.

For bring your own wallet, `mm init` registers your wallet with the server and loads its existing
trading mode.
If the wallet has no trading mode yet, it asks for one.
The CLI labels policy-based 2FA for bring your own wallet as coming soon.

## Change wallet mode

Re-run `mm init` with the other wallet mode:

```bash
mm init --wallet server-wallet --mode guard
```

```bash
export MM_MNEMONIC="word1 word2 ..."
mm init --wallet byok --mode guard
```

Server wallets and bring your own wallet have different addresses.
Your server wallets stay on your account.
When you switch back to server-wallet, `mm init` syncs them again.

## Guidance for AI agents that switch modes or wallets

- Never choose a sign-in method, wallet mode, or trading mode for the user.
  Ask, explain the difference, then pass the user's choice explicitly with `--wallet` and `--mode`.
- Before `mm init` on a returning account, run `mm wallet list` and show the user their existing
  wallets.
- Before switching sign-in method, warn the user that their wallet address will change.
- After any switch, report the active wallet address and trading mode back to the user.
- When a switch needs approval, tell the user exactly where to approve.
  See [Approve requests](approve-requests.md#where-the-approval-appears).

See [Rules for AI agents](agent-rules.md) for the rest of the rules.

---

## Approve requests


Some Agent Wallet requests pause until you approve or reject them with 2-factor authentication (2FA).
The CLI waits, and your agent can't continue until you respond.

A request needs your approval when it is one of the following:

- A transaction that is flagged as malicious or risky, or that falls outside your Guard Mode policy.
  See [Trading modes](reference/trading-modes.md) for the full list.
- A trading mode change from Guard Mode to Beast Mode.
  See [Switch modes and wallets](switch-modes-and-wallets.md).
- A wallet policy change that loosens your limits, such as raising your outflow limit.
  See [Outflow policy](reference/outflow-policy.md).

## Where the approval appears

Your sign-in method decides where the approval request is sent.
If you don't remember how you signed in, read the message the CLI prints when the request pauses.
The message is different for each sign-in method.

| Sign-in method            | Where to approve                                                                                  | What the CLI prints                                                                       |
| ------------------------- | ------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------- |
| MetaMask Mobile QR        | MetaMask Mobile. Open the **notifications menu** in the app. A push notification may also appear. | `Approval required: please approve this <request> in MetaMask Mobile.`                    |
| Google or email (browser) | The email address registered to your Agent Wallet dashboard. Open the link in the email.          | `Approval required: check the email registered to your dashboard and confirm to proceed.` |

The CLI also prints `Request ID: <polling-id>`.
Use that ID to [track the request](#track-a-pending-request).

## If you can't find the approval

### MetaMask Mobile

1. Open MetaMask Mobile and go to the **notifications menu**.
   The request is listed there even if no push notification arrived.
2. To get push notifications for future requests, turn on notifications in MetaMask Mobile under
   **Settings > Notifications**.
   Also check your phone's system settings.
   If you declined the notification permission during MetaMask onboarding, turn it on in the
   iOS or Android settings for MetaMask.

### Email

1. Check your spam and promotions folders.
2. Look for the approval email, not the sign-in verification code.
   The verification code is only used to sign in to the browser dashboard.
3. Approve before the request expires.
   If it expires, run the original command again and approve the new request.

## Recognize a pending approval

This section is for agents and scripts that read `mm` output.

When a request is waiting for approval, the CLI prints the literal token `AWAITING_MFA`.
From CLI v6.1.5, every output mode prints it:

| Output mode              | What to look for                                                                                                              |
| ------------------------ | ----------------------------------------------------------------------------------------------------------------------------- |
| `--json` or piped output | An NDJSON line containing `"_notice":{"kind":"AWAITING_MFA",...}`, with `pollingId`, `expiresAt`, `authMethod`, and `message` |
| Terminal (TTY) or REPL   | A line containing `[AWAITING_MFA]`, followed by the approval message                                                          |

`mm wallet trading-mode set` and `mm wallet policy set` also return `status: pending_approval` with a
`requestId` when you pass `--no-wait`, or when the wait ends before you respond.
They return `status: confirmed` after the change is applied.

`AWAITING_MFA` and `pending_approval` mean the request is waiting for you.
They don't mean the command failed, stopped responding, or completed.

## Track a pending request

List pending requests:

```bash
mm wallet requests list
```

Wait for one request to finish:

```bash
mm wallet requests watch <polling-id>
```

`--wallet-timeout <seconds>` sets how long to wait, up to `600`.

Don't run the original command again while its request is still pending.
That creates a second request.

To confirm a trading mode change was applied, run `mm wallet trading-mode get`.

## If the approval is rejected or expires

| Error code                           | Meaning                                               | What to do                                                           |
| ------------------------------------ | ----------------------------------------------------- | -------------------------------------------------------------------- |
| `TX_DENIED`                          | You rejected the transaction                          | Run the command again only if you want to retry                      |
| `TX_EXPIRED`                         | The transaction approval expired                      | Run the command again and approve before it expires                  |
| `TRADING_MODE_APPROVAL_REJECTED`     | You rejected the trading mode change                  | Run `mm wallet trading-mode set` again to retry                      |
| `TRADING_MODE_APPROVAL_EXPIRED`      | The trading mode approval expired                     | Run `mm wallet trading-mode set` again and approve before it expires |
| `WALLET_POLICY_APPROVAL_REJECTED`    | You rejected the policy change                        | Run `mm wallet policy set` again to retry                            |
| `WALLET_POLICY_APPROVAL_EXPIRED`     | The policy approval expired                           | Run `mm wallet policy set` again and approve before it expires       |
| `WALLET_MODE_APPROVAL_IN_PROGRESS`   | A trading mode change is already waiting for approval | Approve or reject the pending request, or wait for it to expire      |
| `WALLET_POLICY_APPROVAL_IN_PROGRESS` | A policy change is already waiting for approval       | Approve or reject the pending request, or wait for it to expire      |
| `JOB_TIMEOUT`                        | The CLI stopped waiting before you responded          | Run `mm wallet requests list`. The request may still be pending      |

See [Error codes](reference/error-codes.md) for all codes.

## Guidance for AI agents that hit a 2FA pause

- Treat `AWAITING_MFA` and `pending_approval` as waiting for the user.
  Don't report them as a failure, and don't retry the command.
- Tell the user exactly where to approve, based on their sign-in method in the
  [table above](#where-the-approval-appears).
  Don't say "MetaMask will probably ask you."
- Show the user the `message` from the notice and the request ID.
- After the user approves, confirm the result with `mm wallet requests watch <polling-id>`, or
  with `mm wallet trading-mode get` for a trading mode change.

See [Rules for AI agents](agent-rules.md) for the rest of the rules.

---

## Troubleshooting


Symptom-first fixes for common `mm` CLI issues.

## `UNSUPPORTED_NODE` at startup

The CLI checks the Node.js version before loading. If the active runtime is below Node.js 22.18, it
exits immediately:

```
Error: Node.js <current> is not supported. MetaMask Agent Wallet (mm) requires Node.js 22.18 or later.
Upgrade Node.js from https://nodejs.org/ or use a version manager (nvm, fnm, volta).
```

With `--json`, the exit payload is:

```json
{ "ok": false, "error": { "code": "UNSUPPORTED_NODE", "message": "...", "hint": "..." } }
```

Upgrade Node.js to 22.18 or later, then verify:

```bash
node --version
mm doctor
```

## Start with `mm doctor`

Run `mm doctor` first to inspect CLI version, skill compatibility, authentication, and
initialization:

```bash
mm doctor
```

The output includes `authenticated`, `initialized`, `compatible`, and actionable `hints`.
Fix each hint, then re-run `mm doctor` until both `authenticated` and `initialized` are `true`.

Authentication and initialization are independent.
A session can be authenticated but not initialized, which causes `NOT_INITIALIZED` on wallet
commands.

## Authentication and access

### `AUTH_FAILED`, `TOKEN_INVALID`, or `TOKEN_REFRESH_FAILED`

Sign in again:

```bash
mm login browser
mm auth status
```

For CI or headless agents:

```bash
mm login browser --no-wait
mm login --token "<cliToken:cliRefreshToken>"
```

### `ALREADY_AUTHENTICATED`

You already have a valid session.
Run `mm logout` before signing in again.

### `MWP_TIMEOUT` or `MWP_CANCELLED` during QR sign-in

QR sign-in (`mm login qr`) timed out or was cancelled in MetaMask Mobile.

1. Run `mm login qr` again.
2. Scan the new QR code with MetaMask Mobile and approve promptly.

### `PAIRING_EXPIRED`, `INVALID_OTP`, or terminal timed out during browser sign-in

Browser sign-in opens the dashboard, then expects a CLI token pasted into the terminal.
If you take too long, the terminal may time out or return `PAIRING_EXPIRED` or `INVALID_OTP`.

1. Run `mm login browser` again.
2. Complete Google or email sign-in in the browser and click **Authorize**.
3. Copy the CLI token from the browser immediately and paste it into the waiting terminal.

Do not paste the email verification OTP (used only during email sign-in in the browser) into the
terminal.
The terminal expects the CLI token shown after **Authorize**.

See [Commands reference](reference/commands.md#mm-login) for flags and alternate flows.

### Codes during sign-in

| Code or link                 | When it appears                                                                     | What to do                                                   |
| ---------------------------- | ----------------------------------------------------------------------------------- | ------------------------------------------------------------ |
| Email verification OTP       | During email passwordless sign-in in the browser, before **Authorize**              | Enter the OTP in the browser dashboard                       |
| CLI token                    | After **Authorize** in browser sign-in, to link the browser session to the terminal | Copy from the browser and paste into the waiting terminal    |
| MetaMask Mobile QR scan      | During `mm login qr`                                                                | Scan with MetaMask Mobile and approve in the app             |
| Transaction 2FA email link   | Later, when a flagged transaction needs your approval (browser sign-in)             | Open the link and approve or reject the transaction          |
| MetaMask Mobile notification | Later, when a flagged transaction needs your approval (QR sign-in)                  | Open MetaMask Mobile and approve from the notifications menu |

Entering an email OTP or pasting a CLI token does not switch you to a different wallet.
Only changing your sign-in method (Google, email passwordless, or MetaMask Mobile QR) can do that.
See [Switch modes and wallets](switch-modes-and-wallets.md#change-your-sign-in-method).

### Email verification OTP not received during browser sign-in

The email verification OTP is sent only during email sign-in in the browser, before you click
**Authorize**.
It is not the CLI token and not the transaction 2FA email link.

1. Check spam or promotions folders.
2. Wait a minute and request a new code from the dashboard.
3. If sign-in still fails, try a different sign-in method only if you have not funded a wallet yet.
   Google, email passwordless, and MetaMask Mobile QR each bind you to a different wallet address,
   even if you use the same email for more than one method.

### Wallet address changed after re-login

Your **sign-in method** determines which server-wallet address the CLI loads.
**Google**, **email passwordless**, and **MetaMask Mobile QR** are three separate methods, and each
one has its own wallets.
If you sign in with a method that has no wallet yet, `mm init` creates a new wallet with a new
trading mode.
Funds stay onchain at the original address but don't appear in the CLI until you sign in with the
original method.
See [Switch modes and wallets](switch-modes-and-wallets.md#change-your-sign-in-method).

1. Run `mm wallet list` and `mm wallet address` and compare with the address you funded.
2. Sign out with `mm logout`.
3. Sign in again with the same method you used when you first set up and funded the wallet:
   - Google → `mm login browser`, then **Continue with Google**
   - Email → `mm login browser`, then **Continue with email**
   - MetaMask Mobile → `mm login qr`
4. Re-run `mm wallet address` and confirm the expected address before sending transactions.

Pick one sign-in method and use it every time.
Verify the address after every sign-in.

### `NOT_INITIALIZED`

Run setup before wallet commands:

```bash
mm init
mm doctor
```

### `INVALID_POLICY_YAML` on `mm wallet policy set`

The YAML you passed is not a valid policy object (for example, it is an empty document, a plain
string, or a list). Start from a known-good baseline:

```bash
# Start from your current live policy:
mm wallet policy get

# Or start from the project template:
mm wallet policy template
```

Edit the output, then pass it back:

```bash
mm wallet policy set --policy "$(mm wallet policy get)"
```

### Reset local session

```bash
mm reset
mm login browser
mm init --wallet server-wallet --mode guard
mm doctor
```

## Perpetuals

### `HYPERLIQUID_ERROR` or `ORDER_REJECTED` on first perpetuals trade

Deposit USDC from Arbitrum before opening a position:

```bash
mm perps deposit --venue hyperliquid --amount <AMOUNT>
mm perps balance --venue hyperliquid
```

See [Trade perpetuals](guides/trade-perpetuals.md).

### Minimum deposit, withdraw, or order notional errors

The CLI provides actionable hints for Hyperliquid minimum-amount failures under `INVALID_AMOUNT`:

- **Deposits and withdrawals below the venue minimum**: the error shows the required minimum and your
  actual amount. Increase the amount and retry.
- **Orders below $10 notional**: increase your position size or leverage.
- **Funding shortfall**: if your venue balance can't cover the order, run `mm perps deposit` or
  `mm perps transfer --venue hyperliquid --amount <N> --direction spot-to-perp`.

## Prediction markets

### `JsonRpcError: execution reverted` on predict deposit

Run setup and fund the predict wallet with Polygon USDC.e:

```bash
mm predict setup --wait
mm predict deposit --amount <AMOUNT> --wait
```

See [Trade prediction markets](guides/trade-prediction-markets.md).

### `PREDICT_INSUFFICIENT_GAS` on predict deposit

You need native POL on Polygon to cover gas for the predict deposit transaction. The CLI detects
native POL shortfalls from both SDK preflight checks and RPC errors, and surfaces this code with a
POL-specific hint instead of a generic `PREDICT_ERROR`. Fund your wallet with POL, verify with
`mm wallet balance`, then retry.

### `PREDICT_ORDER_SIZE_TOO_SMALL` on predict place

The order size is below the exchange minimum. Raise `--size` to at least the minimum stated in the
error hint, and inspect liquidity with `mm predict book` before retrying.

### `PREDICT_ORDER_NOT_FILLED` on predict place

A fill-or-kill (FOK) order could not be fully filled at the requested price. Adjust `--size` or
`--price`, check liquidity with `mm predict book`, or use a GTC (good-till-cancelled) order type
instead of FOK.

### `PREDICT_UNAVAILABLE_FOR_LEGAL_REASONS` or `PREDICT_GEOBLOCKED`

Polymarket is unavailable from your location. The two codes come from different signals:

- `PREDICT_GEOBLOCKED` comes from the dedicated geoblock API.
- `PREDICT_UNAVAILABLE_FOR_LEGAL_REASONS` comes from an HTTP 451 response on a Polymarket
  request, which indicates a legal restriction.

Neither is a bug. Confirm the restriction with `mm predict geoblock`, and
retry from an allowed location.

## Swaps

### `NO_QUOTES` or unavailable quote from `mm swap quote`

When the bridge returns zero routes for actionable reasons, `mm swap quote` returns a soft
unavailable result (exit 0) with a `reason`, `message`, and `hint`. Common reasons include
`AMOUNT_TOO_LOW`, `SLIPPAGE_TOO_HIGH`, and `NO_QUOTES`. Adjust the amount, slippage, or token and
retry. Do not call `mm swap execute` without a valid `quoteId` from a successful quote step.

When bridging with `--refuel`, do not use the flag if the destination token is the destination
chain's native gas asset (for example, bridging ETH to Arbitrum ETH).
The backend returns no quotes in that case.

### `INSUFFICIENT_FUNDS` or `INSUFFICIENT_GAS` on swap execute

The CLI runs a preflight check before execution. If you don't have enough of the source token, you
receive `INSUFFICIENT_FUNDS` with guidance on the required amount. If native gas balance is too low,
the CLI returns `INSUFFICIENT_GAS`. Bridge or transfer the needed tokens before retrying.

For gas-insufficient swaps, the CLI may offer a gasless route via the EIP-7702 relay when the quote
is gas-included.

### Swap execute fails after a quote

Re-run `mm swap quote` and execute immediately. Quotes expire and are auto-pruned after 24 hours.

### `QUOTE_PERSIST_FAILED` on the first swap quote

The CLI could not create `~/.metamask/swap-quotes` to store the quote. It retries once, then returns
this code. Create the directory yourself and re-run the quote:

```bash
mkdir -p ~/.metamask/swap-quotes && chmod 700 ~/.metamask/swap-quotes
mm swap quote --from <TOKEN> --to <TOKEN> --amount <AMOUNT> --from-chain-id <CHAIN_ID>
```

## Earn

### Withdraw reverts on full withdrawal

For rebasing tokens (like Aave aTokens), interest accrues between the balance query and transaction
execution. The CLI applies a small dust buffer for `--all` withdrawals, but if the transaction still
reverts, it automatically retries up to 3 times. If retries fail, try withdrawing a slightly smaller
amount.

### Position not showing after supply

Earn positions can lag 15–30 seconds after deposit. Use `--wait` on `mm earn supply` to
poll until the position reflects (up to ~45 seconds), or check manually:

```bash
mm earn positions --chain-id <CHAIN_ID>
```

### Approval required for supply

When supplying for the first time, the CLI sends an ERC-20 approval transaction before the supply.
In server-wallet mode with Guard Mode, this may require 2FA approval.

## Transfers

### Insufficient balance on the target chain

`mm transfer` only spends balances on the chain specified by `--chain-id`. Bridge tokens with
`mm swap execute` first.

### ENS names not resolving

ENS is not supported for `--to`. Use a hex address.

### `UNSUPPORTED_CHAIN` on a chain that `mm chains list` shows

Transfers on Monad (`143`), HyperEVM (`999`), Sei (`1329`), and MegaETH (`4326`) failed on CLI
versions before 6.1.2, even though the chains appeared in `mm chains list`. Upgrade and retry:

```bash
npm install -g @metamask/agent-wallet@latest
mm doctor
```

If the code persists on an up-to-date CLI, the chain isn't supported for that operation. Confirm with
`mm chains list --json` and check the `features` field for the chain.

## Balances and prices

### `mm wallet balance` shows 0 for a funded wallet

Bring your own wallet balances returned empty on CLI versions before 6.1.3 even when funds were
onchain. Upgrade with `npm install -g @metamask/agent-wallet@latest`, then re-run
`mm wallet balance --chain-ids <CHAIN_ID>`.

### Assets listed as `unpriced` in `mm wallet balance`

The Price API rejected or had no price for those assets. Balances are still accurate; only the fiat
value is missing. The affected asset IDs appear under `unpricedAssetIds` in `--json` output. This is
not an error and the command exits 0.

### `INVALID_DATA` on `mm price history`

The Price API returned an empty or malformed response. Retry, and verify the asset and chain are
supported:

```bash
mm price spot --asset-ids <CAIP19_ASSET_ID>
mm price networks
```

## Server-wallet polling

### Command returned a `pollingId` but no hash

Use `--wait` on signing and transfer commands, or watch the job:

```bash
mm wallet requests watch <POLLING_ID>
```

The default wallet job poll timeout is 10 minutes. You can override it with `--wallet-timeout`
(max 600 seconds).

See [Architecture](reference/architecture.md).

## 2FA approval pending

If the output contains `AWAITING_MFA` or `pending_approval`, the request is waiting for you.
It hasn't failed.

- **MetaMask Mobile QR sign-in**: open MetaMask Mobile and go to the **notifications menu**. The
  request is listed there even if no push notification arrived.
- **Browser sign-in (Google or email)**: open the approval email sent to the address registered to
  your dashboard.

Don't run the command again while the request is pending.
See [Approve requests](approve-requests.md) for push notification settings, tracking, and
rejection and expiry errors.

### Trading mode was set without asking

In a non-interactive session, `mm init` sets Guard Mode when `--mode` is omitted.
Each new wallet gets its own trading mode, so this can happen once per wallet.
Check the mode with `mm wallet trading-mode get` and change it with `mm wallet trading-mode set`.
See [Switch modes and wallets](switch-modes-and-wallets.md#switch-trading-mode).

## x402 payments

Symptom-first fixes for the `x402_pay.py` helper bundled with the `metamask-agent-wallet` skill.
See [Pay for paywalled APIs (x402)](guides/pay-for-apis-x402.md).

### No eligible payment option

The script returns an error that no eligible option was found.
The server offered no `exact`-scheme payment on a network that `mm chains list` supports.
Inspect the `402` response and show the offered options to the user.

### Multiple eligible payment options

The script returns an error about multiple eligible options.
The server offered the same scheme on several networks or assets (for example, Base and Polygon).
Rerun `pay` with `--network` or `--asset` to choose one.

### Permit2-only offer

The error mentions Permit2.
The server offered only Permit2 asset transfer methods, which the helper does not sign.
It supports EIP-3009 only.
Tell the user the offer is unsupported.

### Non-standard 402 challenge

The error states the response is not a standard x402 challenge.
The endpoint returned `402` in a different payment scheme (for example, pay first, then send a
transaction hash).
The helper supports the standard x402 `exact` scheme only.

### Payment not accepted

The script returns a payment-not-accepted error after signing.
Do not rerun blindly.
Each `pay` run makes a new payment.
Inspect the settlement output and confirm the authorization window has not expired before retrying.

## Related pages

- [Error codes](reference/error-codes.md)
- [Commands reference](reference/commands.md)

---

## Trading modes


During `mm init`, you are prompted to choose a trading mode.
Each wallet has its own trading mode.
If the account already has a wallet, `mm init` loads that wallet's trading mode instead of
prompting.
For bring your own wallet, the CLI labels policy-based 2FA as coming soon.

## Guard Mode vs Beast Mode

Guard Mode enforces all of your policies and asks for approval on anything outside them.

Beast Mode is for power users who want fewer interruptions.
It still blocks and surfaces dangerous transactions.

:::info

We recommend **Guard Mode** for most users.

:::

## Comparison

### Guardrails

Policies enforced automatically before a transaction can proceed.

| Guardrail                       | Guard Mode | Beast Mode |
| ------------------------------- | ---------- | ---------- |
| Threat scanning                 | ✓          | ✓          |
| Network allowlist               | ✓          | No         |
| Address allowlist               | ✓          | No         |
| Token recipient allowlist       | ✓          | No         |
| Rolling 24-hour outflow limit\* | ✓          | No         |

In Guard Mode, untrusted contracts, networks, and recipients are caught by your allowlists.
In Beast Mode there are no allowlists.

### Requires 2FA approval

Transactions that pause the job until you approve or reject them.

| Condition                        | Guard Mode | Beast Mode |
| -------------------------------- | ---------- | ---------- |
| Malicious transactions           | ✓          | ✓          |
| Risky contracts                  | ✓          | ✓          |
| Anything outside your allowlists | ✓          | No         |
| Raising your outflow limit       | ✓          | No         |

In Beast Mode, only malicious and risky transactions trigger approval.

:::note

See [Outflow policy](outflow-policy.md) for how outflows are tracked.

:::

## Set your trading mode

Set the mode with the `--mode` flag during `mm init`, or pick it at the interactive prompt:

```bash
mm init --mode guard   # or --mode beast
```

In a non-interactive session, `mm init` sets Guard Mode when `--mode` is omitted.
Agents must ask the user and pass `--mode` explicitly.

## How 2FA approval works

When a transaction needs approval, the CLI pauses the job and prints `AWAITING_MFA` until you
approve or reject it.
The agent cannot proceed on a flagged or policy-violating transaction without your response.

Your sign-in method determines where the approval request is sent: an email link for browser
sign-in, or the MetaMask Mobile notifications menu for QR sign-in.
See [Approve requests](../approve-requests.md) for details and recovery steps.

## Switch modes

Change the active wallet's trading mode without re-running `mm init`:

```bash
mm wallet trading-mode set guard
mm wallet trading-mode set beast
mm wallet trading-mode set beast --no-wait
```

Switching to Beast Mode needs your 2FA approval.
Switching to Guard Mode applies immediately.
View the current mode with:

```bash
mm wallet trading-mode get
```

See [Switch modes and wallets](../switch-modes-and-wallets.md#switch-trading-mode) for return values
and errors.

## Wallet policy

Guard Mode allowlists and outflow limits are stored as policy YAML on the server wallet.
View, update, or inspect the template with:

```bash
mm wallet policy get
mm wallet policy set --policy "<yaml>"
mm wallet policy set --policy "<yaml>" --no-wait
mm wallet policy template
```

## Outflow policy

Guard Mode enforces a rolling 24-hour outflow limit on server-wallet outgoing transfers.
You're prompted to set the limit on your first transaction, or when a transaction would exceed your
current limit.
If a transaction would exceed the limit, or you request a higher limit, the CLI requires
2-factor authentication approval before the transaction proceeds.

See [Outflow policy](outflow-policy.md) for how outflows are calculated, what counts toward the
limit, and known limitations.

---

## Outflow policy


Your outflow limit caps the total value that can leave the server-wallet in a rolling 24-hour window.
MetaMask tracks outflows automatically and requests 2-factor authentication approval when a transaction
would exceed the limit.

Outflow limits apply in **Guard Mode (Recommended)** when using server-wallet.
See [Trading modes](trading-modes.md) for how Guard Mode enforces this policy alongside other
guardrails.

## Setting your outflow limit

You're prompted to set your outflow limit on your first transaction, or whenever a transaction would
exceed your current limit.
When you set your 24-hour outflow limit, it counts the transaction you're approving now plus all
transactions in the rolling window.

## How outflow is calculated

Before signing, MetaMask simulates the transaction value and adds that value to your 24-hour total once
the transaction is confirmed (submitted successfully).

For example, if you swap 10 USDC to ETH and later swap the ETH to DAI, this counts as a \$10 outflow for
USDC to ETH and another \$10 for ETH to DAI.

You'll receive a 2-factor authentication request when the transaction exceeds your 24-hour outflow
limit.

## What's included

<!-- vale off -->

Our transaction simulation engine analyzes token outflow from your account and estimates the volume
in USD.
This includes token transfers, swaps, and deposits (for example, to Uniswap, Polymarket, or
Hyperliquid).

<!-- vale on -->

## Limitations

Outflow tracking can be imprecise if transactions are not submitted through our backend.

When an outflow can't be tracked reliably, such as when a transaction can't be simulated, fall back on
your allowlists.

Signatures (for example, Permit2) are not included in the outflow calculation as of now.

## Related

- [Trading modes](trading-modes.md)
- [Architecture](architecture.md)

---

## Commands reference


All `mm` commands accept global flags unless noted.

## Global flags

| Flag        | Short | Description                                                                               |
| ----------- | ----- | ----------------------------------------------------------------------------------------- |
| `--format`  | `-f`  | Output format: `text`, `json`, or `toon` (defaults to `text` in a TTY, `json` when piped) |
| `--json`    |       | Shorthand for `--format=json`                                                             |
| `--toon`    |       | Shorthand for `--format=toon`                                                             |
| `--verbose` | `-v`  | Show debug logs on standard error                                                         |

Many signing and transfer commands also accept `--password` (environment variable: `MM_PASSWORD`) in
bring your own wallet mode to unlock an encrypted mnemonic.

Commands that take an `--amount` accept a positive, human-readable decimal such as `100` or `0.5`.
Scientific notation such as `1e3` is allowed, and grouping and decimal separators follow the host
locale, so both `1,000.50` and `1.000,50` are valid. Plain ASCII decimals like `0.5` are accepted in
every locale. An unparseable or non-positive value returns `INVALID_AMOUNT`. See
[Error codes](error-codes.md).

## `mm doctor`

Inspect CLI version, installed skills, environment, and session health.
Does not require authentication or initialization.

```bash
mm doctor
```

| Field               | Description                                                                |
| ------------------- | -------------------------------------------------------------------------- |
| `authenticated`     | Whether the CLI session is valid                                           |
| `initialized`       | Whether wallet mode and trading mode are set                               |
| `recommendedSkills` | Status of `metamask-agent-wallet`                                          |
| `compatible`        | Whether installed skills match the CLI version (`null` if no skills found) |
| `hints`             | Actionable guidance for missing skills, auth, init, or version mismatch    |

Run before the first wallet operation in a session.
Do not run wallet commands until both `authenticated` and `initialized` are `true`.

## `mm init`

Initialize wallet mode and trading mode.

```bash
mm init [--wallet server-wallet|byok] [--mode guard|beast]
mm init show
```

| Flag         | Required | Description                                                                           |
| ------------ | -------- | ------------------------------------------------------------------------------------- |
| `--wallet`   | No       | `server-wallet` or `byok`                                                             |
| `--mode`     | No       | `guard` (recommended) or `beast`. Ignored when the account already has server wallets |
| `--mnemonic` | No       | Bring your own wallet only. Prefer the `MM_MNEMONIC` environment variable             |
| `--password` | No       | Encrypts the mnemonic at rest. Prefer the `MM_PASSWORD` environment variable          |

Environment variables: `MM_MNEMONIC`, `MM_PASSWORD` (bring your own wallet encryption).

If the account already has server wallets, `mm init` syncs them and loads each wallet's trading
mode from the server.
In a non-interactive session with several wallets, it selects the first one.
If the account has no wallet, `mm init` creates one.
In a non-interactive session, omitting `--mode` sets Guard Mode.
See [Switch modes and wallets](../switch-modes-and-wallets.md#what-mm-init-does-after-you-sign-in).

Use `mm wallet policy get` to view wallet policy YAML.
Policy is not included in `mm init show` output.

## `mm login`

Sign in to MetaMask Agent Wallet.

```bash
mm login [qr | browser] [--token <token>] [--no-wait] [--otp-pair]
mm login browser [--no-wait] [--otp-pair]
mm login qr
```

On a TTY, bare `mm login` shows a method picker (**MetaMask Mobile QR** or **Dashboard (browser)**).
Choosing **Dashboard (browser)** is equivalent to `mm login browser`.

### Browser sign-in (`mm login browser`)

Use for Google or email sign-in through the MetaMask dashboard at
`https://developer.metamask.io/agentic/login`.

1. Opens the dashboard in your browser.
2. Completes Google or email authentication (email sign-in includes a browser email verification
   OTP step).
3. Prompts you to click **Authorize**.
4. Displays a CLI token (`cliToken:cliRefreshToken`) to copy and paste into the waiting terminal.

Google sign-in skips the email verification OTP step.

For non-interactive or CI flows, use `mm login browser --no-wait` to print the sign-in URL, then
complete login with `mm login --token "<cliToken:cliRefreshToken>"` after the user authorizes in the
browser.

Use `--otp-pair` for the legacy 6-digit pairing-code flow instead of the default CLI token paste.

### MetaMask Mobile QR (`mm login qr`)

Displays a QR code in the terminal. Scan it with **MetaMask Mobile** and approve the connection in
the app. The CLI waits for the scan and does not support `--no-wait`.

Available in production. Requires MetaMask Mobile v7.82.0 or later.
QR sign-in is the recommended path when you already use MetaMask Mobile and want transaction
approvals in MetaMask Mobile.
See [Approve requests](../approve-requests.md).

:::caution Three sign-in methods, three wallet addresses

**Google**, **email passwordless**, and **MetaMask Mobile QR** each load a different server-wallet
address.
Using the same email for all three does not link them to one wallet.
After sign-in, run `mm wallet address` to confirm the expected address.
See [Switch modes and wallets](../switch-modes-and-wallets.md#change-your-sign-in-method) and
[Troubleshooting](../troubleshooting.md) for sign-in errors and wallet recovery.

:::

| Flag         | Required | Description                                                                                                                                            |
| ------------ | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `--token`    | No       | Pre-minted token as `cliToken:cliRefreshToken`. Environment variable: `MM_CLI_TOKEN`                                                                   |
| `--timeout`  | No       | Seconds to wait for the QR or browser callback                                                                                                         |
| `--no-wait`  | No       | Print sign-in URL and exit. Use with `browser` in headless mode. Not supported with QR                                                                 |
| `--otp-pair` | No       | Use legacy 6-digit OTP pairing instead of the default CLI token paste flow. Browser sign-in only, and cannot be combined with `--no-wait` or `--token` |

Common sign-in errors: `PAIRING_EXPIRED`, `INVALID_OTP`, `MWP_TIMEOUT`, and `MWP_CANCELLED`.
Re-run `mm login browser` or `mm login qr` and complete the flow before the session expires.

After you sign in successfully in server-wallet mode, the CLI syncs the existing server wallets for
the developer project tied to your sign-in method.
Run `mm wallet list` and `mm wallet address` to verify the active wallet.

## `mm auth status`

Check authentication status. No additional flags beyond global flags.

## `mm logout`

Sign out and revoke the CLI session.
When no CLI auth session is stored, returns `reason: ALREADY_LOGGED_OUT` with a hint to run
`mm login` instead of the same success payload as a real sign-out. Still exits with code 0.

```bash
mm logout [--yes]
```

## `mm reset`

Clear local session and wallet state files.

```bash
mm reset [--yes]
```

## `mm chains list`

List supported EVM networks. No auth required.
The output includes a `features` field per chain (for example, `swap`, `predict`, `perps`) and a
`relaySupported` flag indicating gasless relay availability.

## `mm wallet`

Wallet lifecycle and signing commands.

### `mm wallet create`

```bash
mm wallet create [--chain-namespace <namespace>] [--name <name>] [--trading-mode <guard|beast>]
```

`--trading-mode` sets the trading mode for the new server wallet.

Returns `policyYaml: string | null` in structured output.

### `mm wallet list`

```bash
mm wallet list [--chain-namespace <namespace>]
```

### `mm wallet select`

```bash
mm wallet select [<address>] [--chain-namespace <namespace>]
```

Pass the wallet address as a positional argument, such as `mm wallet select 0x1234…`.
In an interactive terminal, run `mm wallet select` with no address to choose from your wallets.
Headless runs require the address; omitting it returns `MISSING_WALLET_REF`.
See [Switch modes and wallets](../switch-modes-and-wallets.md#switch-the-active-wallet) for errors.

### `mm wallet show`

```bash
mm wallet show [--chain-namespace <namespace>] [--id <id>] [--address <address>] [--name <name>]
```

Returns `policyYaml: string | null` in structured output.

### `mm wallet address`

```bash
mm wallet address [--chain-namespace <namespace>]
```

### `mm wallet add-fund`

Show a QR code and address to fund the active wallet.
In headless mode (`--json`), outputs the address only.

```bash
mm wallet add-fund [--chain-namespace <namespace>]
```

### `mm wallet balance`

```bash
mm wallet balance [--currency <code>] [--chain-ids <chains>] [--token <token>] [--address <address>] [--testnet] [--testnet-chain-ids <ids>] [--token-contracts <addresses>]
```

| Flag                  | Required | Description                                                                                             |
| --------------------- | -------- | ------------------------------------------------------------------------------------------------------- |
| `--currency`          | No       | Fiat currency code for price conversion, such as `usd` or `eur`                                         |
| `--chain-ids`         | No       | Comma-separated chain filters, such as `1,137` or `eip155:1`                                            |
| `--token`             | No       | Filter by token symbol, contract address, or CAIP-19 asset ID                                           |
| `--address`           | No       | Wallet address to query instead of the active wallet                                                    |
| `--testnet`           | No       | Read balances over RPC on Arbitrum Sepolia, Amoy, and Sepolia                                           |
| `--testnet-chain-ids` | No       | Comma-separated testnet chain IDs for onchain RPC balance reads, such as `421614`                       |
| `--token-contracts`   | No       | Comma-separated ERC-20 contract addresses to read on testnet RPC chains. Use with `--testnet-chain-ids` |

Balances are returned even when the Price API cannot price every asset.
Assets without a price are listed under `unpricedAssetIds` in structured output and shown as
`unpriced` in the terminal, instead of failing the whole command.

### `mm wallet trading-mode get`

Show the current trading mode and active server-wallet address.
Server-wallet mode only.

```bash
mm wallet trading-mode get [--chain-namespace <namespace>] [--address <address>]
```

### `mm wallet trading-mode set`

Set the trading mode for the active server wallet.

```bash
mm wallet trading-mode set <guard|beast> [--chain-namespace <namespace>] [--address <address>] [--no-wait] [--wallet-timeout <seconds>]
```

Switching to Guard Mode applies immediately and returns `status: confirmed`.
Switching to Beast Mode needs 2FA approval: the command prints `AWAITING_MFA` and waits until you
approve or reject.
With `--no-wait`, or if the wait ends first, it returns `status: pending_approval` with a
`requestId`.
The 2FA approval is the only confirmation. The terminal shows no separate prompt.
See [Approve requests](../approve-requests.md) for where the approval appears.

In CLI v7.2.0, the usage line in this command's `--help` output shows `mm mode set`.
That command doesn't exist. Use `mm wallet trading-mode set`.

### `mm wallet policy get`

Show the policy YAML for the active server wallet.
Server-wallet mode only.

```bash
mm wallet policy get
```

This command always reads the policy of the active server wallet and takes no target flags.
To read another wallet's policy, switch to it with `mm wallet select` first.

### `mm wallet policy set`

Set the policy for the active server wallet.
Server-wallet mode only.
Changes that tighten your policy apply immediately and return `status: confirmed`.
Changes that loosen it, such as raising your outflow limit, need 2FA approval: the command prints
`AWAITING_MFA` and waits until you approve or reject.
Use `--no-wait` to return `status: pending_approval` with a `requestId` as soon as the approval is
requested.
See [Approve requests](../approve-requests.md).

```bash
mm wallet policy set --policy <yaml> [--no-wait]
```

### `mm wallet policy template`

Show the project policy template.
Server-wallet mode only.

```bash
mm wallet policy template
```

### `mm wallet sign-message`

```bash
mm wallet sign-message --message <text> --chain-id <id> [--wait]
```

### `mm wallet sign-typed-data`

```bash
mm wallet sign-typed-data --chain-id <id> --payload '<JSON>' [--wait] [--intent <text>]
```

### `mm wallet send-transaction`

```bash
mm wallet send-transaction --chain-id <id> --payload '<JSON>' [--wait] [--intent <text>]
```

The payload requires at least a `to` address.
Optional fields are `gas`, `nonce`, `maxFeePerGas`, and `maxPriorityFeePerGas`.
The `value` field must be 0x-prefixed hex, not a decimal wei string.

`--intent` attaches a human-readable summary to the wallet request, so you see what you are
approving during 2FA and in `mm wallet requests list`.

### `mm wallet requests list`

List pending server-wallet requests. Server-wallet mode only.

```bash
mm wallet requests list [--sync]
```

Requests are synced from the server before listing. Pass `--no-sync` to skip the refresh.

### `mm wallet requests watch`

```bash
mm wallet requests watch <polling-id> [--wallet-timeout <seconds>]
```

### `mm wallet password`

```bash
mm wallet password set --new=<password>
mm wallet password change --current=<old> --new=<new>
mm wallet password remove --current=<password>
```

## `mm transfer`

Send native currency or ERC-20 tokens on one EVM chain.
For ERC-20 transfers, the CLI automatically uses gasless relay when the wallet's native balance
cannot cover gas fees.

```bash
mm transfer --to <address> --amount <value> --chain-id <id> --token <symbol-or-address> [--wait]
```

| Flag         | Required | Description                              |
| ------------ | -------- | ---------------------------------------- |
| `--to`       | Yes      | Recipient hex address. ENS not supported |
| `--amount`   | Yes      | Human-readable amount                    |
| `--chain-id` | Yes      | EVM chain ID                             |
| `--token`    | Yes      | `native`, symbol, or ERC-20 address      |
| `--wait`     | No       | Block until complete (server-wallet)     |

When the wallet's native balance cannot cover gas, the CLI uses gasless relay and chooses relay fees
automatically.
Gasless relay applies to ERC-20 transfers only, not native token sends, and only on chains that
support it. Unsupported chains return `GASLESS_UNSUPPORTED`.

## `mm swap`

### `mm swap quote`

```bash
mm swap quote --from <token> --to <token> --amount <amount> --from-chain-id <chain-id> [--to-chain-id <chain-id>] [--to-address <address>] [--slippage <percent>] [--refuel] [--all-quotes] [--strategy <strategies>] [--yes]
```

| Flag            | Required | Description                                                                                                 |
| --------------- | -------- | ----------------------------------------------------------------------------------------------------------- |
| `--to-chain-id` | No       | Destination chain ID. The default is `--from-chain-id` for same-chain swaps                                 |
| `--to-address`  | No       | Recipient for bridged output tokens. Cross-chain only. The default is signer                                |
| `--slippage`    | No       | Maximum slippage as a percentage, 0–100 (default 0.5)                                                       |
| `--refuel`      | No       | Bundle destination native-gas top-up into a cross-chain quote. Cross-chain only                             |
| `--all-quotes`  | No       | Show all ranked candidate quotes with the recommended quote marked (★)                                      |
| `--strategy`    | No       | Comma-separated ranking strategy: `cost`, `speed`, `impact`, `output` (default: `cost,speed`)               |
| `--yes`         | No       | Skip interactive confirmation and execute immediately after quoting. Cannot be combined with `--all-quotes` |

`--refuel` is opt-in and cross-chain only.
Do not use it when the destination token is the destination chain's native gas asset; the backend
returns `NO_QUOTES`.

The CLI streams quotes via SSE for faster response times.
Use `--all-quotes` to compare routes, then execute a specific one with `--quote-id`.
Old quote artifacts are automatically pruned after 24 hours.

Quote output includes `tierName` and `vipTier` when a VIP fee tier applies.
When a tier is present, `quoteBpsFee` reflects the discounted rate rather than `baseBpsFee`.

When the bridge returns zero routes for actionable reasons, `mm swap quote` returns a soft
unavailable result (exit 0) with `kind: "unavailable"`, a `reason` (such as `AMOUNT_TOO_LOW`,
`SLIPPAGE_TOO_HIGH`, or `NO_QUOTES`), a `message`, and a `hint`. Only the transient `QUOTE_RETRY`
signal produces a hard error (exit 1).

### `mm swap execute`

```bash
mm swap execute --quote-id <id> [--wallet-timeout <seconds>]
mm swap execute --from <token> --to <token> --amount <amount> --from-chain-id <chain-id> [--to-chain-id <chain-id>] [--to-address <address>] [--slippage <percent>] [--refuel] [--strategy <strategies>] [--wallet-timeout <seconds>]
```

When executing by `--quote-id`, the persisted quote retains `--to-address` and `--refuel` settings
from the quote step.

On eligible chains and accounts, the CLI uses **ERC-7821 batch execution** to atomically combine
approval and trade in a single `execute()` call. The result includes `route: "erc7821"` when
batching is used. If batching is not available, the CLI falls back to sequential submission.

When the wallet's native balance cannot cover gas, the CLI uses **gasless execution** via the
EIP-7702 relay for gas-included quotes.

The CLI runs an `INSUFFICIENT_FUNDS` preflight check before execution and returns actionable hints
if the source token balance is insufficient.

MFA poll timeouts on gasless relay and sequential server-wallet legs surface `RELAY_TIMEOUT` or
`JOB_TIMEOUT` errors with a recovery hint to run `mm wallet requests watch <id>` and
a warning not to re-run execute while the job may still complete. Gasless relay polling honors
`--wallet-timeout` and the CLI's 10-minute default.

### `mm swap status`

```bash
mm swap status --quote-id <id> [--tx-hash <hash>]
```

## `mm perps`

<!-- vale off -->

Hyperliquid perpetuals commands.

`--venue` is optional on every command and defaults to `hyperliquid`.
Run `mm perps list-venues` for the current list.
`--network` is optional and defaults to `mainnet`; pass `--network testnet` to trade on the
venue's testnet.
Balance, positions, and orders default to the main Hyperliquid DEX.
Use `--dex <name>` to scope a HIP-3 DEX, or `--all-dexes` (balance and positions only) to
aggregate across DEXs.

Perps commands do not use `--wait`.
`--yes` skips the confirmation prompt on `open`, `close`, `modify`, and `cancel`.
Deposit, withdraw, and transfer accept `--yes` but do not prompt, so it has no effect there.

| Command                | Usage summary                                                                                                                                                  |
| ---------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `mm perps list-venues` | List supported venues                                                                                                                                          |
| `mm perps dexs`        | `[--venue <venue>] [--network <network>]`: list HIP-3 DEX identifiers                                                                                          |
| `mm perps markets`     | `[--venue <venue>] [--symbol <symbol>] [--symbols <list>] [--dex <dex>] [--network <network>]`                                                                 |
| `mm perps balance`     | `[--venue <venue>] [--dex <dex>] [--all-dexes] [--network <network>]`                                                                                          |
| `mm perps positions`   | `[--venue <venue>] [--dex <dex>] [--all-dexes] [--network <network>]`                                                                                          |
| `mm perps orders`      | `[--venue <venue>] [--dex <dex>] [--network <network>]`                                                                                                        |
| `mm perps quote`       | `--symbol <symbol> --side long\|short --size <size> --leverage <n> [--type market\|limit] [--limit-px <price>]`                                                |
| `mm perps open`        | `--symbol <symbol> --side long\|short --size <size> --leverage <n> [--type market\|limit] [--limit-px <price>] [--max-slippage-bps <bps>] [--dry-run] [--yes]` |
| `mm perps close`       | `[--symbol <symbol>] [--size <size>] [--all] [--max-slippage-bps <bps>] [--dry-run] [--yes]`                                                                   |
| `mm perps modify`      | `--symbol <symbol> [--leverage <n>] [--tp <price>] [--sl <price>] [--dry-run] [--yes]`                                                                         |
| `mm perps cancel`      | `--order-id <id> [--symbol <symbol>] [--dry-run] [--yes]`                                                                                                      |
| `mm perps deposit`     | `--amount <amount> [--asset <asset>] [--source-chain-id <chain>] [--dry-run] [--yes]`                                                                          |
| `mm perps withdraw`    | `--amount <amount> [--asset <asset>] [--destination <address>] [--include-spot] [--dry-run] [--yes]`                                                           |
| `mm perps transfer`    | `--amount <amount> --direction spot-to-perp\|perp-to-spot [--asset <asset>] [--dry-run]`                                                                       |

Notes on individual flags:

- `--limit-px` is required when `--type` is `limit`.
- `mm perps close` requires `--symbol` unless you pass `--all`. `--size` performs a partial close
  and cannot be combined with `--all`.
- `mm perps modify` requires at least one of `--leverage`, `--tp`, or `--sl`.
- `mm perps cancel --symbol` is optional and skips an open-order lookup.
- `--source-chain-id` accepts a decimal chain ID or CAIP-2 ID. It defaults to Arbitrum
  (`eip155:42161` on mainnet, `eip155:421614` on testnet).
- `--asset` defaults to `USDC` on deposit, withdraw, and transfer.
- `--dry-run` validates and previews without signing or submitting.

<!-- vale on -->

## `mm predict`

<!-- vale off -->

Polymarket prediction market commands.

| Command                     | Description                                                                          |
| --------------------------- | ------------------------------------------------------------------------------------ |
| `mm predict setup`          | One-time predict setup                                                               |
| `mm predict deposit`        | Fund predict deposit wallet                                                          |
| `mm predict balance`        | Check predict balance                                                                |
| `mm predict mode`           | Set `mainnet` or `testnet`                                                           |
| `mm predict auth`           | Refresh predict credentials                                                          |
| `mm predict approve`        | Repair approvals                                                                     |
| `mm predict status`         | Backend status                                                                       |
| `mm predict portfolio`      | Snapshot of pUSD balance, positions, redeemable winnings                             |
| `mm predict redeem list`    | List redeemable winning positions                                                    |
| `mm predict redeem`         | Redeem one or all winning positions                                                  |
| `mm predict markets search` | Search markets                                                                       |
| `mm predict markets list`   | List markets with filters                                                            |
| `mm predict markets get`    | Inspect a market (slug, ID, or condition ID)                                         |
| `mm predict events list`    | List Polymarket events with filters                                                  |
| `mm predict events get`     | Retrieve a single event by ID or slug                                                |
| `mm predict series list`    | List event series                                                                    |
| `mm predict series get`     | Retrieve a single event series                                                       |
| `mm predict tags list`      | List Polymarket tags                                                                 |
| `mm predict tags get`       | Retrieve a tag by ID or slug                                                         |
| `mm predict quote`          | Preview order cost (supports `--tick-size`)                                          |
| `mm predict place`          | Place an order (supports `--tick-size`)                                              |
| `mm predict cancel`         | Cancel orders                                                                        |
| `mm predict orders`         | List open orders                                                                     |
| `mm predict positions`      | View positions                                                                       |
| `mm predict withdraw`       | Withdraw pUSD from deposit wallet                                                    |
| `mm predict book`           | Order book for a token                                                               |
| `mm predict watch`          | Watch a predict job                                                                  |
| `mm predict geoblock`       | Check Polymarket geoblock for your IP                                                |
| `mm predict history`        | List closed positions by default; use `--type trade` or `--type redeem` for activity |
| `mm predict history get`    | Inspect activity for a specific market condition                                     |

`mm predict quote` and `mm predict place` accept an optional `--tick-size` flag to override the
market's default tick size. Valid values: `0.1`, `0.01`, `0.005`, `0.0025`, `0.001`, `0.0001`.
Defaults to the CLOB tick size for the token. An unsupported value returns `INVALID_TICK_SIZE`.

`mm predict place` also accepts `--order-type` (`GTC` by default, or `GTD`, `FOK`, `FAK`),
`--post-only` to reject an order that would cross the book, and `--expiration <unix>`, which is
required for `GTD` orders. `--post-only` is not supported with `FOK` or `FAK`.

### `mm predict history`

List deposit-wallet history. Defaults to **closed positions** with signed `pnl`.
Use `--type trade` for fill activity or `--type redeem` for past claims.
Open holdings remain on `mm predict positions`.
`--start` and `--end` apply only when `--type` is `trade` or `redeem`.

```bash
mm predict history [--type closed|trade|redeem] [--limit <n>] [--offset <n>] [--start <unix>] [--end <unix>] [--sort-by realizedpnl|title|price|avgprice|timestamp|tokens|cash] [--sort-direction asc|desc] [--side buy|sell]
```

| Flag               | Required | Description                                                                |
| ------------------ | -------- | -------------------------------------------------------------------------- |
| `--type`           | No       | `closed` (default), `trade`, or `redeem`                                   |
| `--limit`          | No       | Page size, 1–500. `closed` caps at 50; `trade` and `redeem` default to 100 |
| `--offset`         | No       | Skip the first N results (pagination, zero-based)                          |
| `--start`          | No       | Start timestamp in unix seconds (`trade` or `redeem` only)                 |
| `--end`            | No       | End timestamp in unix seconds (`trade` or `redeem` only)                   |
| `--sort-by`        | No       | Sort field. Depends on `--type`, see the following table                   |
| `--sort-direction` | No       | Sort direction: `asc` or `desc`. The default is `desc`                     |
| `--side`           | No       | Filter by side: `buy` or `sell` (`trade` only)                             |

Valid `--sort-by` values depend on `--type`.
Passing a value from the wrong set returns `PREDICT_HISTORY_INVALID_SORT_BY`.

| `--type`           | Valid `--sort-by` values                                 |
| ------------------ | -------------------------------------------------------- |
| `closed` (default) | `realizedpnl`, `title`, `price`, `avgprice`, `timestamp` |
| `trade`, `redeem`  | `timestamp` (default), `tokens`, `cash`                  |

### `mm predict history get`

Inspect deposit-wallet activity for a specific market condition.

```bash
mm predict history get <condition-id> [--type closed|trade|redeem]
```

| Flag     | Required | Description                              |
| -------- | -------- | ---------------------------------------- |
| `--type` | No       | `closed` (default), `trade`, or `redeem` |

<!-- vale on -->

Run `mm predict <command> --help` for command-specific flags.

## `mm decode`

Decode hex-encoded EVM calldata into a function name, parameters, and a plain-language summary.
Use before signing unfamiliar raw transactions.

```bash
mm decode --payload <0x-calldata>
mm decode <0x-calldata>
```

| Flag        | Required | Description                            |
| ----------- | -------- | -------------------------------------- |
| `--payload` | Yes      | Hex-encoded calldata (also positional) |

## `mm price`

| Command               | Usage                                                                                                                         |
| --------------------- | ----------------------------------------------------------------------------------------------------------------------------- |
| `mm price spot`       | `--asset-ids <ids> [--vs <currency>] [--market-data]`                                                                         |
| `mm price history`    | `--chain-id <caip2> [--asset-type <type>] [--time-period <period>] [--interval <interval>] [--from] [--to] [--vs <currency>]` |
| `mm price currencies` | Supported quote currencies                                                                                                    |
| `mm price networks`   | Supported price networks                                                                                                      |

### `mm price spot`

```bash
mm price spot --asset-ids <ids> [--vs <currency>] [--market-data]
```

`--asset-ids` accepts comma-separated CAIP-19 asset IDs, such as `eip155:1/slip44:60`.
A bare CAIP-2 chain ID auto-completes to that chain's native asset, so `eip155:1` resolves to
`eip155:1/slip44:60`:

```bash
mm price spot --asset-ids eip155:1,eip155:137
```

A malformed ID returns `INVALID_ASSET_ID` with a hint, and passing no IDs returns
`MISSING_ASSET_IDS`. `mm token assets` does not auto-complete chain IDs and requires full CAIP-19
asset IDs.

### `mm price history`

```bash
mm price history --chain-id <caip2-chain-id> [--asset-type <asset-type>] [--time-period <period>] [--interval <interval>] [--from <unix>] [--to <unix>] [--vs <currency>]
```

`--asset-type` is optional and defaults to the chain's native asset, so `--chain-id eip155:1`
resolves to `slip44:60`. An invalid asset type fails fast with `INVALID_ASSET_ID`.

Use `--from` and `--to` for a custom range instead of `--time-period`.
`--time-period` accepts Price API values such as `1d`, `7d`, `30d`, `2M`, `1y`, and `3y`.
Supported `--interval` values include `5m`, `15m`, `30m`, `hourly`, and `daily`.
The Price API accepts `5m`, `hourly`, and `daily` directly; `15m` and `30m` are downsampled from
5m data client-side.

When the Price API returns an empty or malformed response, the command returns `INVALID_DATA` with a
hint to retry or verify the asset and chain with `mm price spot`.

## `mm token`

| Command                    | Usage                                                                                                                                                                                        |
| -------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `mm token assets`          | `--asset-ids <ids> [--include-market-data] [--include-token-security-data] [--include-labels] [--include-aggregators] [--include-coingecko-id] [--include-occurrences] [--include-rwa-data]` |
| `mm token networks`        | List token networks                                                                                                                                                                          |
| `mm token list popular`    | `[--chain-id <chain>]`                                                                                                                                                                       |
| `mm token list trending`   | `[--chain-id <chain>]`                                                                                                                                                                       |
| `mm token list search`     | `<query> [--chain-ids <chains>] [--limit <n>] [--after <cursor>]`                                                                                                                            |
| `mm token list top-gainer` | `[--chain-id <chain>]`                                                                                                                                                                       |

`mm token list search` takes the search term as a positional argument:

```bash
mm token list search USDC --chain-ids 1,137
```

The `--query` flag still works for backward compatibility.
Passing neither returns `MISSING_QUERY`.

`--chain-id` and `--chain-ids` accept a chain ID, a CAIP-2 ID, or a configured chain key.
They default to the active wallet's chain, or `eip155:1` when no wallet is selected.
On `mm token list search`, `--limit` defaults to 10 and accepts 1–500.

## `mm earn`

Yield vault operations. Supply and withdraw from vaults across supported chains and protocols.

| Command             | Usage summary                                                                                                                                                                        |
| ------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `mm earn markets`   | `[--chain-id <chain-id>] [--token <symbol\|address>] [--protocol <protocol>] [--min-tvl <usd>] [--sort apy\|tvl] [--limit <n>]`                                                      |
| `mm earn positions` | `[--chain-id <chain-id>] [--address <address>] [--token <symbol\|address>] [--protocol <name>] [--vault <address>] [--min-usd <n>] [--sort usd] [--limit <n>]`                       |
| `mm earn supply`    | `--token <token> --amount <amount> --chain-id <chain-id> [--vault <address>] [--protocol <name>] [--min-tvl <usd>] [--from-chain-id <id>] [--from-token <symbol\|address>] [--wait]` |
| `mm earn withdraw`  | `--token <token> --chain-id <chain-id> [--amount <amount>] [--vault <address>] [--protocol <name>] [--all]`                                                                          |

### `mm earn markets`

List available yield vaults with APY and TVL data.

```bash
mm earn markets [--chain-id <chain-id>] [--token <symbol|address>] [--protocol <protocol>] [--min-tvl <amount>] [--sort apy|tvl] [--limit <n>]
```

### `mm earn positions`

View your current yield vault positions.

```bash
mm earn positions [--chain-id <chain-id>] [--address <address>] [--token <symbol|address>] [--protocol <name>] [--vault <address>] [--min-usd <n>] [--sort usd] [--limit <n>]
```

### `mm earn supply`

Supply tokens to a yield vault. The CLI handles ERC-20 approval automatically when the vault's
allowance is insufficient.

```bash
mm earn supply --token <token> --amount <amount> --chain-id <chain-id> [--vault <address>] [--protocol <name>] [--min-tvl <usd>] [--from-chain-id <chain-id>] [--from-token <symbol|address>] [--wait]
```

Use `--from-chain-id` for cross-chain supply operations that bridge and supply in one step.
Use `--wait` to poll until the position reflects in the portfolio (up to ~45 seconds) and display
an inline balance confirmation. Without `--wait`, the CLI prints a hint that positions may lag
15–30 seconds.

### `mm earn withdraw`

Withdraw tokens from a yield vault.

```bash
mm earn withdraw --token <token> --chain-id <chain-id> [--amount <amount>] [--vault <address>] [--protocol <name>] [--all]
```

Use `--all` to withdraw your full position.
The CLI automatically retries failed withdrawals (up to 3 attempts with backoff).

## `mm config`

Get or set CLI configuration values persisted in `~/.metamask/config.json`.

```bash
mm config get <key>
mm config set <key> <value>
```

| Key                                   | Accepted values        | Description                                                               |
| ------------------------------------- | ---------------------- | ------------------------------------------------------------------------- |
| `env`                                 | `prod`, `dev`, `uat`   | Backend environment                                                       |
| `verbose`                             | `true`, `false`        | Default for the global `--verbose` flag                                   |
| `format`                              | `text`, `json`, `toon` | Default for the global `--format` flag                                    |
| `walletTimeoutSeconds`                | Integer (max 600)      | Default for `--wallet-timeout` on server-wallet signing and swap commands |
| `experimentalPlugins`                 | `true`, `false`        | Enable the [plugin system](#mm-plugins). Beta, off by default             |
| `experimentalAllowUnverifiedInstalls` | `true`, `false`        | Allow installing plugins from local or git sources. Development only      |

Run `mm config get` with no key to show all values.
Persisted `format` and `verbose` apply when you do not pass the corresponding global flags.
Override `env` for a single invocation with the `MM_ENV` environment variable.
Non-prod sessions are stored in environment-scoped files under `~/.metamask/`, such as
`session.dev.json`; prod uses `session.json`.
`walletTimeoutSeconds` is the stored default for `--wallet-timeout` (see [Troubleshooting](../troubleshooting.md)).

## `mm plugins`

Manage plugins, npm packages that add custom commands to Agent Wallet.
Plugins are a beta feature and are off by default.
Enable them with `mm config set experimentalPlugins true`.
See the [plugins overview](../plugins/index.md).

```bash
mm plugins                                   # list installed plugins
mm plugins install <package>                 # interactive consent per package
mm plugins install <package> --accept-permissions   # non-interactive / CI
mm plugins inspect <package>
mm plugins update                            # re-consents changed manifests
mm plugins uninstall <package>
```

Installs from npm are consent-gated.
Agent Wallet shows the plugin's commands, data access, and requested capabilities before
installing, and fails closed if the package can't be verified.
Plugin lifecycle scripts such as `postinstall` never run.
Local `file:` and git sources are refused unless you opt in with
`mm config set experimentalAllowUnverifiedInstalls true`, which is intended for development only.

## `mm tx`

### `mm tx history`

List recent transactions for the active wallet or specific addresses.
Each row includes chain name, chain ID, explorer link, and protocol when indexer metadata is
available. When a pending wallet job matches an indexed transaction hash, the local CLI intent is
preserved on that row. Pending jobs that never reached the chain are excluded;
use `mm wallet requests list` to see stranded or expired requests.

```bash
mm tx history [--addresses <addrs>] [--chain-ids <chains>] [--type <filter>] [--limit <n>] [--after <cursor>]
```

| Flag          | Required | Description                                                                |
| ------------- | -------- | -------------------------------------------------------------------------- |
| `--addresses` | No       | Comma-separated EVM addresses. Defaults to all EVM wallets on your account |
| `--chain-ids` | No       | Comma-separated chain filters, such as `1,137` or `eip155:1`               |
| `--type`      | No       | Filter by direction (`in`, `out`, or `self`) or by transaction category    |
| `--limit`     | No       | Number of transactions to return, 1–50. The default is 50                  |
| `--after`     | No       | Pagination cursor from a previous response (`endCursor` value)             |

When more results are available, JSON and toon output include `hasNextPage: true` and an `endCursor`
value. Pass that cursor as `--after <endCursor>` to fetch the next page. The REPL also displays a
ready-to-run next-page command in a footer when `hasNextPage` is true.

### `mm tx`

Look up a specific transaction by hash.

```bash
mm tx --hash <tx-hash> [--chain-id <chain-id-or-caip2>]
```

| Flag         | Required | Description                                                                                         |
| ------------ | -------- | --------------------------------------------------------------------------------------------------- |
| `--hash`     | Yes      | Transaction hash (0x-prefixed)                                                                      |
| `--chain-id` | No       | Chain ID or CAIP-2 (for example, `1` or `eip155:1`). When omitted, the CLI probes common EVM chains |

Returns `TX_NOT_FOUND` for unknown hashes and `INVALID_TX_HASH` for malformed input.

## Help

Every command supports `--help`:

```bash
mm transfer --help
mm perps open --help
```

---

## Error codes


The `mm` CLI surfaces errors with stable `code` values. Use these codes in scripts and agent
workflows to branch on failures.

Run `mm <command> --help` for command-specific validation rules.

## Authentication errors (`AuthError`)

| Code                    | Meaning                                                         |
| ----------------------- | --------------------------------------------------------------- |
| `AUTH_FAILED`           | Authentication failed (includes missing refresh token)          |
| `AUTH_ERROR`            | Generic authentication error                                    |
| `ALREADY_AUTHENTICATED` | Valid session already exists; run `mm logout` before signing in |
| `COMING_SOON`           | Feature not yet available                                       |
| `TOKEN_INVALID`         | Invalid CLI token, token pair, or project ID                    |
| `TOKEN_REFRESH_FAILED`  | Failed to refresh token                                         |
| `PAIRING_TIMEOUT`       | Sign-in pairing timed out                                       |
| `PAIRING_EXPIRED`       | Pairing session expired                                         |
| `INVALID_OTP`           | Invalid one-time password                                       |
| `MWP_TIMEOUT`           | Mobile Wallet Protocol timeout                                  |
| `MWP_CANCELLED`         | Mobile Wallet Protocol cancelled (pairing aborted)              |
| `LOGOUT_FAILED`         | Sign-out operation failed (includes token revoke failures)      |
| `ALREADY_LOGGED_OUT`    | No active session to sign out of. `mm logout` still exits 0     |

## Validation errors (`ValidationError`)

| Code                          | Meaning                                                                                                                                                  |
| ----------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `MISSING_FLAG`                | Required flag missing in headless mode                                                                                                                   |
| `MISSING_INPUT`               | Required input is missing                                                                                                                                |
| `MISSING_CHAIN`               | Chain value is missing                                                                                                                                   |
| `MISSING_CHAIN_ID`            | `--chain-id` is missing                                                                                                                                  |
| `INVALID_CHAIN`               | Chain value is invalid                                                                                                                                   |
| `INVALID_INPUT`               | Invalid user input                                                                                                                                       |
| `INVALID_TO`                  | Recipient address is invalid                                                                                                                             |
| `INVALID_TYPED_DATA`          | EIP-712 payload is invalid                                                                                                                               |
| `INVALID_TRANSACTION_PAYLOAD` | Transaction payload is invalid                                                                                                                           |
| `CHAIN_ID_MISMATCH`           | Typed-data domain chain ID differs from `--chain-id`                                                                                                     |
| `INVALID_MNEMONIC`            | Bring your own wallet mnemonic is invalid                                                                                                                |
| `NOT_INITIALIZED`             | Project not initialized; run `mm init`                                                                                                                   |
| `INVALID_LIMIT`               | Invalid `--limit` value; `mm tx history` accepts 1–50 and `mm token list search` accepts 1–500                                                           |
| `INVALID_DATA`                | The Price API returned an empty or malformed response for `mm price history`; retry, or verify the asset and chain with `mm price spot`                  |
| `MISSING_ASSET_IDS`           | No asset IDs passed to `mm price spot` or `mm token assets`; pass `--asset-ids` as comma-separated CAIP-19 IDs                                           |
| `MISSING_ASSET_TYPE`          | `--asset-type` is missing on `mm price history` and the chain has no native asset to fall back to                                                        |
| `INVALID_ASSET_ID`            | Malformed CAIP-19 asset ID or `--asset-type`. `mm price spot` also accepts a bare CAIP-2 chain ID and resolves it to that chain's native asset           |
| `MISSING_QUERY`               | No search term passed to `mm token list search`; pass it as a positional argument                                                                        |
| `INVALID_POLICY_YAML`         | Policy YAML passed to `mm wallet policy set` is not a valid policy object; use `mm wallet policy get` or `mm wallet policy template` as a starting point |
| `INVALID_CONFIG_KEY`          | Unknown CLI config key                                                                                                                                   |
| `INVALID_NETWORK`             | Unsupported or unknown network                                                                                                                           |
| `UNKNOWN_FLAG`                | Unrecognized CLI flag                                                                                                                                    |
| `MISSING_WALLET_REF`          | Missing wallet address for `mm wallet select` in a non-interactive run; pass the address as a positional argument                                        |
| `INVALID_EVM_ADDRESS`         | Malformed EVM address input                                                                                                                              |
| `INVALID_SORT_BY`             | Invalid `--sort-by` field                                                                                                                                |
| `INVALID_SORT_DIRECTION`      | Invalid `--sort-direction` value; use `asc` or `desc`                                                                                                    |
| `INVALID_HISTORY_TYPE`        | Invalid `--type`; use `closed`, `trade`, or `redeem`                                                                                                     |

## Wallet errors (`WalletError`)

| Code                    | Meaning                                                                                                                                                                                                                                       |
| ----------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `MISSING_MNEMONIC`      | Bring your own wallet mode is missing a mnemonic                                                                                                                                                                                              |
| `MNEMONIC_LOCKED`       | Mnemonic unlock failed after the maximum attempts                                                                                                                                                                                             |
| `WRONG_PASSWORD`        | Mnemonic password is incorrect                                                                                                                                                                                                                |
| `WALLET_NOT_FOUND`      | Wallet not found                                                                                                                                                                                                                              |
| `WALLET_NOT_REGISTERED` | BYOK wallet registration failed during `mm init`                                                                                                                                                                                              |
| `WALLET_ERROR`          | Wallet operation failed                                                                                                                                                                                                                       |
| `WALLET_LIMIT_EXCEEDED` | Project has reached the maximum of 100 wallets. Run `mm wallet list` to see existing wallets                                                                                                                                                  |
| `NO_AUTH_TOKEN`         | Missing authentication token                                                                                                                                                                                                                  |
| `NO_PROJECT_ID`         | Project ID not configured                                                                                                                                                                                                                     |
| `NO_HISTORY_WALLETS`    | No EVM wallets found for `mm tx history`                                                                                                                                                                                                      |
| `TX_NOT_FOUND`          | Transaction hash not found onchain                                                                                                                                                                                                            |
| `INVALID_TX_HASH`       | Malformed transaction hash                                                                                                                                                                                                                    |
| `UNSUPPORTED_CHAIN`     | Chain not supported for this operation                                                                                                                                                                                                        |
| `INVALID_AMOUNT`        | Amount is not a positive, parseable number. Use a positive decimal like `100` or `0.5`. Scientific notation such as `1e3` is allowed, and grouping and decimal separators follow the host locale, so both `1,000.50` and `1.000,50` are valid |
| `TX_REVERTED`           | Transaction reverted onchain                                                                                                                                                                                                                  |
| `TX_DENIED`             | Transaction was rejected during 2FA approval                                                                                                                                                                                                  |
| `TX_EXPIRED`            | 2FA approval for the transaction expired                                                                                                                                                                                                      |
| `TX_FAILED`             | Transaction failed after submission                                                                                                                                                                                                           |
| `WRONG_NAMESPACE`       | The wallet belongs to a different chain namespace                                                                                                                                                                                             |

## Trading mode and policy errors

These codes come from `mm wallet trading-mode set` and `mm wallet policy set`.
See [Approve requests](../approve-requests.md) for how to approve and retry.

| Code                                 | Meaning                                                   |
| ------------------------------------ | --------------------------------------------------------- |
| `INVALID_TRADING_MODE`               | The trading mode is not `guard` or `beast`                |
| `ALREADY_SET_TRADING_MODE`           | The wallet is already in the requested trading mode       |
| `WALLET_MODE_APPROVAL_IN_PROGRESS`   | A trading mode change is already waiting for 2FA approval |
| `TRADING_MODE_APPROVAL_REJECTED`     | The trading mode change was rejected during 2FA approval  |
| `TRADING_MODE_APPROVAL_EXPIRED`      | 2FA approval for the trading mode change expired          |
| `WALLET_POLICY_APPROVAL_IN_PROGRESS` | A policy change is already waiting for 2FA approval       |
| `WALLET_POLICY_APPROVAL_REJECTED`    | The policy change was rejected during 2FA approval        |
| `WALLET_POLICY_APPROVAL_EXPIRED`     | 2FA approval for the policy change expired                |

## Swap errors (`SwapCommandError`)

| Code                   | Meaning                                                 |
| ---------------------- | ------------------------------------------------------- |
| `NO_QUOTES`            | No swap quotes returned for the request                 |
| `INVALID_SWAP_PARAMS`  | Missing or invalid swap parameters                      |
| `TOKEN_NOT_FOUND`      | Token not found for the selected chain                  |
| `QUOTE_NOT_FOUND`      | Quote ID not found                                      |
| `QUOTE_PERSIST_FAILED` | Quote could not be written to `~/.metamask/swap-quotes` |
| `GASLESS_UNSUPPORTED`  | Gasless relay unavailable on this chain                 |
| `NO_TRADE_DATA`        | Selected quote has no trade transaction                 |
| `EXECUTE_FAILED`       | Swap execution failed                                   |
| `STATUS_UNAVAILABLE`   | Swap status unavailable                                 |
| `INSUFFICIENT_FUNDS`   | Source token balance insufficient                       |
| `INSUFFICIENT_GAS`     | Native balance cannot cover gas fees                    |
| `AMOUNT_TOO_LOW`       | Swap amount below minimum threshold                     |
| `SLIPPAGE_TOO_HIGH`    | Slippage exceeds acceptable range                       |
| `QUOTE_RETRY`          | Transient bridge quote-stream retry signal (retryable)  |
| `FEES_LOOKUP_FAILED`   | Wallet fee lookup failed unexpectedly                   |
| `SWAP_ERROR`           | Generic swap error                                      |

## Perpetuals errors

<!-- vale off -->

| Code                   | Meaning                                                |
| ---------------------- | ------------------------------------------------------ |
| `ORDER_REJECTED`       | Order rejected by Hyperliquid                          |
| `DEPOSIT_FAILED`       | Deposit to venue failed                                |
| `INSUFFICIENT_BALANCE` | Venue sub-account has insufficient balance             |
| `HYPERLIQUID_ERROR`    | Generic Hyperliquid error (often unfunded sub-account) |
| `RATE_LIMITED`         | Hyperliquid HTTP 429 rate limit; retry after a delay   |
| `POSITION_NOT_FOUND`   | Perpetuals position not found for the given symbol     |

The CLI provides actionable hints for common failures — for example, minimum amounts for deposits
and withdrawals, the $10 notional floor for orders, funding shortfalls (deposit or
`mm perps transfer --direction spot-to-perp`), and source-chain mismatches. Operational errors
surface a retry hint instead of raw provider text.

See [Trade perpetuals](../guides/trade-perpetuals.md).

<!-- vale on -->

## Predict errors

All expected predict failures return actionable per-code hints. Inspect the `hint` field to determine the next action.

| Code                                    | Meaning                                                                   |
| --------------------------------------- | ------------------------------------------------------------------------- |
| `PREDICT_SETUP_REQUIRED`                | Run `mm predict setup` before this operation                              |
| `PREDICT_AUTH_REQUIRED`                 | Predict credentials missing or expired                                    |
| `PREDICT_AUTH_INVALID`                  | Predict credentials invalid; run `mm predict auth --refresh`              |
| `PREDICT_INSUFFICIENT_BALANCE`          | Insufficient pUSD in the deposit wallet                                   |
| `PREDICT_INSUFFICIENT_FUNDING_BALANCE`  | Insufficient USDC.e for `mm predict deposit`                              |
| `PREDICT_INSUFFICIENT_GAS`              | Insufficient native POL for gas on predict deposit                        |
| `PREDICT_INSUFFICIENT_ALLOWANCE`        | Insufficient allowance; run `mm predict approve`                          |
| `PREDICT_ORDER_SIZE_TOO_SMALL`          | Order size below exchange minimum; raise `--size`                         |
| `PREDICT_ORDER_NOT_FILLED`              | FOK order could not be fully filled; adjust `--size`/`--price` or use GTC |
| `PREDICT_GEOBLOCKED`                    | Polymarket is unavailable in this region, per the geoblock API            |
| `PREDICT_UNAVAILABLE_FOR_LEGAL_REASONS` | Polymarket returned HTTP 451 for a legal restriction in this region       |
| `PREDICT_WITHDRAW_ZERO`                 | Withdraw amount must be greater than zero                                 |
| `PREDICT_WITHDRAW_INSUFFICIENT_BALANCE` | Insufficient balance for withdrawal                                       |
| `PREDICT_REDEEM_NONE`                   | No redeemable positions found                                             |
| `PREDICT_REDEEM_NOT_FOUND`              | Redeem target not found; check `mm predict redeem list`                   |
| `PREDICT_CANCEL_TARGET_REQUIRED`        | Cancel requires an order ID, market, or `--all`                           |
| `INVALID_TICK_SIZE`                     | Invalid `--tick-size` value for `mm predict quote`/`place`                |
| `PREDICT_HISTORY_INVALID_SORT_BY`       | Invalid `--sort-by` value for `mm predict history`                        |
| `PREDICT_ERROR`                         | Generic predict error                                                     |

## Earn errors

| Code                      | Meaning                                                         |
| ------------------------- | --------------------------------------------------------------- |
| `VAULT_NOT_FOUND`         | Yield vault not found for the specified token and chain         |
| `AMBIGUOUS_VAULT`         | Multiple vaults match `--token`; pass `--vault` or `--protocol` |
| `POSITION_NOT_FOUND`      | No earn position matches `--token` for `mm earn withdraw`       |
| `NO_POSITION`             | No yield positions found for the active wallet                  |
| `NOT_REDEEMABLE`          | The vault does not support withdrawals                          |
| `INSUFFICIENT_LP_BALANCE` | Insufficient LP balance for the requested withdraw amount       |
| `EARN_API_ERROR`          | LiFi API error or rate limit                                    |
| `EARN_ERROR`              | Generic earn error                                              |

## Server-wallet errors

| Code                | Meaning                                                                                                                    |
| ------------------- | -------------------------------------------------------------------------------------------------------------------------- |
| `JOB_TIMEOUT`       | Wallet job timed out (default 10 minutes, max 600s)                                                                        |
| `RELAY_TIMEOUT`     | Gasless relay timed out; run `mm wallet requests watch <id>`                                                               |
| `RELAY_FAILED`      | Gasless relay failed, usually because the wallet cannot cover the amount plus the relay fee. Retry with a lower `--amount` |
| `RELAY_ABORTED`     | Gasless relay aborted                                                                                                      |
| `REQUEST_NOT_FOUND` | Server-wallet request not found                                                                                            |

## Runtime errors

| Code               | Meaning                                                                                                              |
| ------------------ | -------------------------------------------------------------------------------------------------------------------- |
| `UNSUPPORTED_NODE` | Node.js version is below the minimum required (22.18). Upgrade Node.js from https://nodejs.org/ or use nvm/fnm/volta |

## Network errors

| Code                  | Meaning             |
| --------------------- | ------------------- |
| `NETWORK_UNREACHABLE` | Network unreachable |

## Plugin errors

Returned by `mm plugins` and installed plugin commands.
See the [plugins overview](../plugins/index.md).

| Code                           | Meaning                                                                                        |
| ------------------------------ | ---------------------------------------------------------------------------------------------- |
| `PLUGIN_BETA_DISABLED`         | Plugins are disabled. Run `mm config set experimentalPlugins true`                             |
| `PLUGIN_UNVERIFIED_SOURCE`     | Local or git source refused. Enable `experimentalAllowUnverifiedInstalls` for development      |
| `PLUGIN_NOT_FOUND`             | npm package could not be resolved                                                              |
| `PLUGIN_METADATA_UNAVAILABLE`  | npm metadata could not be fetched. The install fails closed                                    |
| `PLUGIN_MANIFEST_INVALID`      | The package's `package.json#mm` manifest is missing or invalid                                 |
| `PLUGIN_MANIFEST_FILE_MISSING` | The package did not ship a prebuilt `oclif.manifest.json`. It was not approved and was removed |
| `PLUGIN_CLI_VERSION`           | The plugin requires a newer Agent Wallet version than the one running                          |
| `PLUGIN_ID_COLLISION`          | A plugin command ID collides with a built-in command                                           |
| `PLUGIN_HOOKS_FORBIDDEN`       | The package declares `oclif.hooks` or `oclif.plugins`, which are not allowed                   |
| `PLUGIN_INVALID_BASE`          | A plugin command does not extend `PluginCommand`                                               |
| `PLUGIN_SEALED_OVERRIDE`       | A plugin command overrides a sealed lifecycle member                                           |
| `PERMISSION_DENIED`            | Install consent was declined, or a command used a capability it was not granted                |

## Related pages

- [Troubleshooting](../troubleshooting.md)
- [Commands reference](commands.md)

---

## Check balances and prices


Query wallet balances, spot prices, and token metadata without submitting transactions.

## Ask your agent

```text
You (to your agent): "What's my USDC balance?"
```

```text
You (to your agent): "What's the current price of ETH?"
```

```text
You (to your agent): "Show me trending tokens"
```

Read-only queries like these do not require confirmation before your agent runs them.

## Commands

1. Confirm your wallet address:

   ```bash
   mm wallet address
   ```

2. Query balances, prices, or token lists using the commands in the following sections.

## Wallet balance

```bash
mm wallet balance
mm wallet balance --chain-ids 8453
mm wallet balance --token USDC
```

If `--token` with a symbol returns no balance or an error, pass the ERC-20 contract address for that
chain. Run `mm token list search <symbol> --chain-ids <chain-id>` to look up the address.

## Spot prices

```bash
mm price spot --asset-ids <ASSET_IDS> --vs USD
mm price currencies
mm price networks
```

`--asset-ids` takes comma-separated CAIP-19 asset IDs. To price a chain's native asset, pass the
bare CAIP-2 chain ID and the CLI resolves it for you, so `eip155:1` becomes `eip155:1/slip44:60`:

```bash
mm price spot --asset-ids eip155:1,eip155:8453 --vs USD
```

Use `mm token assets` to resolve asset identifiers for tokens you care about.

## Historical prices

```bash
mm price history --chain-id eip155:1 --time-period 7d
mm price history --chain-id eip155:1 --asset-type erc20:0x<ADDRESS> --time-period 30d
```

`--asset-type` is optional and defaults to the chain's native asset.

## Token discovery

```bash
mm token list popular --chain-id ethereum
mm token list search uniswap --chain-ids ethereum
mm token list trending --chain-id base
mm token networks
```

## Supported chains

```bash
mm chains list
```

## Transaction history

List recent transactions for your wallets:

```bash
mm tx history
mm tx history --chain-ids 1,8453 --limit 20
mm tx history --type out
```

## Related commands

See [Commands reference](../reference/commands.md) for `mm wallet balance`, `mm price`, `mm token`,
and [`mm tx history`](../reference/commands.md#mm-tx-history).

---

## Earn with yield vaults


Browse yield vaults, supply tokens, and withdraw positions using the `mm earn` commands.
Agent Wallet routes supply and withdraw operations through LiFi for cross-chain support.

## Ask your agent

```text
You (to your agent): "Show me the best yield vaults for USDC on Base"
```

```text
You (to your agent): "Supply 100 USDC to a vault on Base"
```

```text
You (to your agent): "Withdraw all my USDC from the Aave vault on Base"
```

Your agent lists available vaults, compares APYs and TVL, confirms your choice, then executes.

## Prerequisites

- [Quickstart](../quickstart.md) completed
- Sufficient token balance on the source chain

## Browse vaults

List available yield vaults with APY and TVL data:

```bash
mm earn markets [--chain-id <chain-id>] [--token <symbol|address>] [--protocol <protocol>] [--min-tvl <amount>] [--sort apy|tvl] [--limit <n>]
```

Filter by chain, token, protocol, minimum TVL, or sort order to find the best opportunities.

## Check your positions

View your current yield positions:

```bash
mm earn positions [--chain-id <chain-id>] [--address <address>] [--token <symbol|address>] [--protocol <name>] [--vault <address>] [--min-usd <n>] [--sort usd] [--limit <n>]
```

`--address` defaults to the active wallet.

## Supply to a vault

Supply tokens to a yield vault:

```bash
mm earn supply --token <TOKEN> --amount <AMOUNT> --chain-id <chain-id> [--vault <address>] [--protocol <name>] [--min-tvl <usd>] [--from-chain-id <chain-id>] [--from-token <symbol|address>] [--wait]
```

| Flag              | Required | Description                                                             |
| ----------------- | -------- | ----------------------------------------------------------------------- |
| `--token`         | Yes      | Token symbol or contract address                                        |
| `--amount`        | Yes      | Human-readable amount to supply                                         |
| `--chain-id`      | Yes      | Destination chain for the vault                                         |
| `--vault`         | No       | Vault contract address (skips auto-selection)                           |
| `--protocol`      | No       | Restrict vault auto-selection to a protocol                             |
| `--min-tvl`       | No       | Minimum TVL in USD for vault auto-selection                             |
| `--from-chain-id` | No       | Source chain if supplying cross-chain                                   |
| `--from-token`    | No       | Source token. Required when `--from-chain-id` differs from `--chain-id` |
| `--wait`          | No       | Poll until the position reflects (up to ~45s) and confirm balance       |

Pass either `--token` or `--vault`.
The CLI automatically handles ERC-20 approval when the vault's allowance is insufficient.

## Withdraw from a vault

Withdraw tokens from a yield vault:

```bash
mm earn withdraw --token <TOKEN> --chain-id <chain-id> [--amount <amount>] [--vault <address>] [--protocol <name>] [--all]
```

Pass either `--amount` or `--all`.
Use `--all` to withdraw your full position.
For Aave rebasing aTokens, `--all` applies a small dust buffer to avoid revert from interest
accrual between the query and the transaction.

## Cross-chain supply

Supply from a different chain than the vault's chain by passing `--from-chain-id` and
`--from-token`:

```bash
mm earn supply --token USDC --amount 100 --chain-id 8453 --from-chain-id 1 --from-token USDC
```

This bridges and supplies in a single operation.
`--from-token` is required whenever `--from-chain-id` differs from `--chain-id`.
The CLI routes through LiFi and polls until the cross-chain transaction completes, with a
10-minute timeout.

## Common pitfalls

:::caution Approval required
When supplying for the first time, the CLI sends an ERC-20 approval transaction before the supply
transaction. In server-wallet mode, this may require 2FA approval depending on your trading mode.
:::

:::note Withdraw reverts
If a full withdrawal reverts, retry with a slightly smaller amount. Rebasing tokens (like Aave
aTokens) accrue interest between the balance query and transaction execution.
:::

## Related commands

- [`mm earn`](../reference/commands.md#mm-earn) in the commands reference
- [Check balances and prices](check-balances-and-prices.md)

---

## Pay for paywalled APIs (x402)


Pay for HTTP resources that return `402 Payment Required` using the [x402 protocol](https://www.x402.org/).
Your agent uses a Python helper script bundled with the `metamask-agent-wallet` skill.
The script delegates EIP-3009 signing to `mm wallet sign-typed-data`, so your agent never handles
private keys directly.

## Ask your agent

```text
You (to your agent): "Fetch the premium data from https://api.example.com/premium and pay if it returns 402."
```

Your agent inspects the payment requirement, shows you the asset, amount, network, and recipient,
then pays only after you approve.

## Prerequisites

- [Quickstart](../quickstart.md) completed
- Python 3 available in your environment
- Sufficient token balance on the network the server requires

## How x402 works

1. The client requests a resource. The server replies with `402 Payment Required` and one or more
   payment options (scheme, network, amount, asset, `payTo`, validity window).
2. The client signs an EIP-3009 `TransferWithAuthorization` for one option. This is a gasless,
   off-chain authorization that permits a pull of exactly the amount to `payTo`.
3. The client retries with the payment header. The server's facilitator settles on-chain and returns
   the resource plus a settlement header (transaction hash).

The helper script supports the `exact` scheme on EVM networks (`eip155:*`) using EIP-3009, for
protocol v1 and v2.

## Steps

The helper is `scripts/x402_pay.py` inside the installed skill directory.
It is not an `mm` subcommand.
Use the full path to the script because the shell working directory is not stable between commands.
It always prints JSON and does not accept `--format` or `--toon`.

Let `SKILL_DIR` be the directory that contains the skill's `SKILL.md` file (for example, the
`metamask-agent-wallet` folder under your agent's skills install path).

### 1. Inspect the payment requirement

Run the inspect subcommand to read the server's offer without spending:

```bash
python3 "$SKILL_DIR/scripts/x402_pay.py" inspect <url>
```

The output includes the asset, human-readable amount, network, `payTo` address, and resource URL.
Show this to the user before paying.

For a non-GET resource, pass `--method` and `--data` (and `--content-type` when needed).
The same request is replayed with the payment attached.

### 2. Pay after approval

Run the pay subcommand only after the user approves the payment details.
The `--confirm` flag is required:

```bash
python3 "$SKILL_DIR/scripts/x402_pay.py" pay <url> --confirm
```

When the `402` response offers more than one eligible option, disambiguate with `--asset <contract>`
or `--network <network>`.

On success, the script prints the settlement transaction and the resource body.

## Supported and unsupported offers

Supported:

- The `exact` scheme on EVM networks that `mm chains list` includes
- EIP-3009 `transferWithAuthorization` (protocol v1 and v2)

Not supported:

- Permit2 asset transfer methods (`extra.assetTransferMethod: "permit2"`)
- Other schemes such as `upto`
- Non-EVM networks (for example, Solana)
- Offers that omit the EIP-712 domain `name` and `version` in `extra`

## Wallet mode notes

**Server wallet**: Signing runs synchronously via `--wait`.
Guard Mode permits EIP-712 signing.
The x402 authorization window is short.
If 2FA approval on your side is slow, the authorization can expire.
Rerun `pay` to sign again with fresh values.

**Bring your own wallet**: Signing returns immediately.
Set `MM_PASSWORD` when your mnemonic is encrypted so signing is non-interactive.

## Idempotency

The script is stateless.
Each `pay` run makes a new payment.
The EIP-3009 nonce prevents the same signed authorization from settling twice, but rerunning `pay`
for the same resource authorizes a new debit.
Guard repeated calls at the caller.

## Next steps

- [Sign messages and transactions](sign-messages-and-transactions.md)
- [Troubleshooting](../troubleshooting.md#x402-payments)
- [Commands reference](../reference/commands.md)

---

## Send tokens


Transfer native currency or ERC-20 tokens to a recipient on one EVM chain.

## Ask your agent

```text
You (to your agent): "Send 10 USDC to 0xabc..."
```

Your agent confirms the recipient, amount, token, and chain before executing.

## Prerequisites

- [Quickstart](../quickstart.md) completed
- Sufficient balance on the source chain for the transfer amount and gas

## Steps

1. Confirm your wallet address:

   ```bash
   mm wallet address
   ```

2. Check your balance on the target chain:

   ```bash
   mm wallet balance --chain-ids <chain-id>
   ```

3. Send the transfer:

   ```bash
   mm transfer --to <ADDRESS> --amount <AMOUNT> --token <TOKEN> --chain-id <CHAIN_ID> --wait
   ```

   - `--to`: recipient hex address (`0x…`). ENS names are not supported.
   - `--amount`: human-readable amount (for example, `0.5`).
   - `--token`: `native`, a token symbol, or an ERC-20 contract address. If a symbol fails to
     resolve, run `mm token list search <symbol> --chain-ids <chain-id>` and pass the contract
     address instead.
   - `--chain-id`: EVM chain ID (for example, `8453` for Base). Run `mm chains list` for options.

4. Confirm the transaction hash in the command output.

## Gasless ERC-20 transfers

When your wallet's native balance cannot cover gas, the CLI automatically routes ERC-20 transfers
through a gasless relay and chooses relay fees automatically.

```bash
mm transfer --to <ADDRESS> --amount 10 --token USDC --chain-id 8453 --wait
```

Gasless transfers are not available for native token sends.

## Common pitfalls

:::note Per-chain balances
`mm transfer` spends from the chain you specify with `--chain-id`. To send on a chain where you do
not currently hold a balance, bridge first with `mm swap execute`, then transfer.
:::

## Related commands

See [`mm transfer`](../reference/commands.md#mm-transfer) in the commands reference.

---

## Sign messages and transactions


Sign plaintext messages, EIP-712 typed data, or submit raw EVM transactions.

## Ask your agent

```text
You (to your agent): "Sign this message on Ethereum: Hello, world"
```

```text
You (to your agent): "Sign this EIP-712 typed data: <paste JSON payload>"
```

Your agent shows the exact payload and asks you to confirm before signing.

## Prerequisites

- [Quickstart](../quickstart.md) completed
- Understanding of what you are signing. Review payloads before confirming.

## Sign a plaintext message

```bash
mm wallet sign-message --message "<TEXT>" --chain-id <CHAIN_ID> [--wait]
```

## Sign EIP-712 typed data

```bash
mm wallet sign-typed-data --chain-id <CHAIN_ID> --payload '<JSON>' [--wait]
```

The payload must be valid JSON with `domain`, `types`, `primaryType`, and `message` fields.

## Send a raw transaction

If the calldata is unfamiliar, decode it first:

```bash
mm decode --payload <0x-calldata>
```

Then submit the transaction:

```bash
mm wallet send-transaction --chain-id <CHAIN_ID> --payload '<JSON>' [--wait]
```

The payload must include at least a `to` address. See the commands reference for the full schema.
If `mm decode` returns `Call unknown function`, treat the transaction as higher risk and confirm
the payload before signing.

## Polling

Signing commands can return a `pollingId` when `--wait` is omitted, in both server-wallet and bring
your own wallet mode.
In bring your own wallet mode, the request is signed locally and then submitted as a job, so pass
`--wait` to get the result in one call.
In server-wallet mode, track pending requests:

```bash
mm wallet requests list
mm wallet requests watch <POLLING_ID>
```

If the output contains `AWAITING_MFA`, the request is waiting for your 2FA approval.
See [Approve requests](../approve-requests.md).

## Related commands

See [`mm wallet`](../reference/commands.md#mm-wallet) and [`mm decode`](../reference/commands.md#mm-decode)
in the commands reference.

---

## Swap and bridge tokens


Get a quote, review the route, and execute a same-chain swap or cross-chain bridge.

## Ask your agent

```text
You (to your agent): "Swap 0.1 ETH to USDC"
```

For a cross-chain bridge:

```text
You (to your agent): "Bridge 10 USDC from Base to Arbitrum"
```

Your agent fetches a quote, shows you the route and output, then executes after you confirm.

## Prerequisites

- [Quickstart](../quickstart.md) completed
- Sufficient balance of the source token on the source chain

## Same-chain swap

1. Request a quote:

   ```bash
   mm swap quote --from <TOKEN> --to <TOKEN> --amount <AMOUNT> --from-chain-id <CHAIN_ID> [--slippage <PERCENT>]
   ```

2. Review the quoted output, fees, and route in the command output. Note the `quoteId`.

3. Execute the swap:

   ```bash
   mm swap execute --quote-id <QUOTE_ID>
   ```

4. Optionally check status:

   ```bash
   mm swap status --quote-id <QUOTE_ID>
   ```

## Cross-chain bridge

Include `--to-chain-id` when requesting a quote:

```bash
mm swap quote --from USDC --to USDC --amount 10 --from-chain-id 8453 --to-chain-id 42161
mm swap execute --quote-id <QUOTE_ID>
```

### Send bridged tokens to another address

Add `--to-address` to send output tokens to a recipient other than your wallet.
Only valid for cross-chain bridges (`--to-chain-id` differs from `--from-chain-id`):

```bash
mm swap quote --from USDC --to USDC --amount 10 --from-chain-id 8453 --to-chain-id 42161 --to-address 0x742d35Cc6634C0532925a3b844Bc454e4438f08e
```

### Top up destination gas (refuel)

When bridging to a chain where you hold no native gas token, add `--refuel` to bundle a small
destination native-gas top-up into the quote:

```bash
mm swap quote --from USDC --to USDC --amount 50 --from-chain-id 1 --to-chain-id 42161 --refuel
```

Refuel is opt-in and cross-chain only.
Do not use `--refuel` when the destination token is the destination chain's native gas asset (for
example, bridging ETH to Arbitrum ETH).
The backend returns `NO_QUOTES` in that case.

## Compare quotes

Use `--all-quotes` to see all available routes ranked by your preferred strategy:

```bash
mm swap quote --from ETH --to USDC --amount 0.5 --from-chain-id 1 --all-quotes --strategy cost,speed
```

A ★ marks the recommended quote. Execute a specific quote by its ID:

```bash
mm swap execute --quote-id <QUOTE_ID>
```

Available strategies: `cost`, `speed`, `impact`, `output`. The default is `cost,speed`.

## Gasless swaps

When your wallet's native balance cannot cover gas, the CLI automatically uses gasless execution
via the EIP-7702 relay for eligible quotes. No additional flags are required.

## Unavailable quotes

When the bridge returns zero routes for actionable reasons, `mm swap quote` returns a soft
unavailable result (exit 0) instead of a hard error. The response includes:

- `kind: "unavailable"` — no quote was generated.
- `reason` — one of `AMOUNT_TOO_LOW`, `SLIPPAGE_TOO_HIGH`, `NO_QUOTES`, or other actionable codes.
- `message` — a human-readable explanation.
- `hint` — guidance on how to adjust and retry.

Your agent can inspect the reason and adjust amount, slippage, or token before retrying.
Only the transient `QUOTE_RETRY` bridge signal produces a hard error (exit 1).

## Common pitfalls

:::caution Verify the quote step succeeded
If `mm swap quote` returns an unavailable result or no quote ID, do not call `mm swap execute` with
a fabricated or expired quote ID. The execute step fails and no transaction is submitted, even when
partial output is printed.
:::

## Related commands

See [`mm swap`](../reference/commands.md#mm-swap) in the commands reference.

---

## Trade perpetuals


<!-- vale off -->

Open, modify, and close perpetual positions on Hyperliquid through the `mm perps` commands.

## Ask your agent

```text
You (to your agent): "Open a 5x long on BTC with $100 on Hyperliquid"
```

```text
You (to your agent): "Close my BTC perp position on Hyperliquid"
```

Your agent deposits if needed, fetches a quote, confirms details with you, then executes.

## Prerequisites

- [Quickstart](../quickstart.md) completed
- USDC on a supported source chain for the initial deposit

## First-time setup

1. List venues:

   ```bash
   mm perps list-venues
   ```

2. Deposit USDC into the venue before your first trade:

   ```bash
   mm perps deposit --venue hyperliquid --amount <AMOUNT>
   ```

3. Confirm your perpetuals balance (defaults to the main Hyperliquid DEX):

   ```bash
   mm perps balance --venue hyperliquid
   ```

   To query a HIP-3 DEX or aggregate across DEXs:

   ```bash
   mm perps balance --venue hyperliquid --dex <DEX_NAME>
   mm perps balance --venue hyperliquid --all-dexes
   mm perps positions --venue hyperliquid --all-dexes
   ```

## Open a position

1. List markets:

   ```bash
   mm perps markets --venue hyperliquid
   ```

2. Get a quote:

   ```bash
   mm perps quote --venue hyperliquid --symbol <SYMBOL> --side long --size <SIZE> --leverage <N>
   ```

3. Open the position:

   ```bash
   mm perps open --venue hyperliquid --symbol <SYMBOL> --side long --size <SIZE> --leverage <N>
   ```

   Add `--dry-run` to preview without submitting. Add `--yes` to skip interactive confirmation in
   scripted flows.

## Close or modify a position

```bash
mm perps close --venue hyperliquid --symbol <SYMBOL>
mm perps modify --venue hyperliquid --symbol <SYMBOL> --leverage <N>
```

## Common pitfalls

:::caution Deposit before you trade
The Hyperliquid sub-account is empty on first use. Running `mm perps open` before depositing can
fail with `HYPERLIQUID_ERROR` or `ORDER_REJECTED`. `mm perps deposit` sources USDC from Arbitrum by
default. Deposit with `mm perps deposit --venue hyperliquid --amount <N>` before opening your first
position. If your perp account is short on collateral, run `mm perps deposit` or
`mm perps transfer --venue hyperliquid --amount <N> --direction spot-to-perp`.
:::

## Related commands

See [`mm perps`](../reference/commands.md#mm-perps) in the commands reference.

<!-- vale on -->

---

## Trade prediction markets


<!-- vale off -->

Search markets, fund your predict deposit wallet, and place orders on Polymarket through
`mm predict`.

## Ask your agent

```text
You (to your agent): "Bet 10 USDT on YES for BTC 5-min price up"
```

```text
You (to your agent): "Show my open prediction market positions"
```

```text
You (to your agent): "Redeem my winning Polymarket positions"
```

```text
You (to your agent): "Show my Polymarket trade history"
```

Your agent runs one-time setup if needed, shows current odds, confirms your bet, then places the
order.

## Prerequisites

- [Quickstart](../quickstart.md) completed
- Polygon USDC.e in your owner EOA for `mm predict deposit` (converts to pUSD in the predict
  deposit wallet)

## First-time setup

1. Run one-time setup:

   ```bash
   mm predict setup --wait
   ```

   If the command returns a job ID instead of completing immediately, track it with
   `mm predict watch <JOB_ID> --wait`.

2. Fund the predict deposit wallet:

   ```bash
   mm predict deposit --amount <AMOUNT> --wait
   ```

3. Confirm balance:

   ```bash
   mm predict balance --sync
   ```

## Search and place an order

1. Search markets:

   ```bash
   mm predict markets search "<QUERY>" --limit 5
   ```

   Browse by event, series, or tag:

   ```bash
   mm predict events list --tag-slug politics --active
   mm predict series list --recurrence weekly
   mm predict tags list
   ```

2. Preview a quote:

   ```bash
   mm predict quote --token-id <TOKEN_ID> --side buy --size <SIZE> [--limit-price <PRICE>] [--tick-size <TICK>]
   ```

3. Inspect a market to get outcome token IDs:

   ```bash
   mm predict markets get <MARKET_SLUG_OR_ID>
   ```

4. Place the order:

   ```bash
   mm predict place --token-id <TOKEN_ID> --side buy --size <SIZE> --price <PRICE> [--order-type GTC|GTD|FOK|FAK] [--tick-size <TICK>]
   ```

   `--limit-price` applies to `mm predict quote` only. `mm predict place` requires `--price`
   (worst fill price per share, between 0 and 1).

   Use `--tick-size` to override the market's default tick size. Valid values: `0.1`, `0.01`,
   `0.005`, `0.0025`, `0.001`, `0.0001`. Defaults to the CLOB tick size for the token when omitted.

5. View open orders and positions:

   ```bash
   mm predict orders
   mm predict positions
   mm predict portfolio
   ```

## View trade history

List your closed positions by default (signed `pnl`):

```bash
mm predict history
```

Filter by type, paginate, and sort:

```bash
mm predict history --limit 20 --offset 20
mm predict history --type trade --sort-by cash --sort-direction desc
mm predict history --type redeem --sort-by cash --sort-direction desc
mm predict history --type trade --start 1700000000 --end 1700600000
```

Inspect activity for a specific market condition:

```bash
mm predict history get <CONDITION_ID>
mm predict history get <CONDITION_ID> --type trade
mm predict history get <CONDITION_ID> --type redeem
```

Use `--type trade` for fill activity or `--type redeem` for past claims.
Open holdings remain on `mm predict positions`.
`--start` and `--end` apply only when `--type` is `trade` or `redeem`.

## Redeem winnings

List redeemable winning positions:

```bash
mm predict redeem list
```

Redeem one condition or all winning positions:

```bash
mm predict redeem <CONDITION_ID> --wait
mm predict redeem --all --wait
```

## Common pitfalls

:::caution One-time setup is required
Polymarket trading routes through a dedicated predict deposit wallet. Run `mm predict setup`
followed by `mm predict deposit --amount <N>` before placing your first order. Skipping setup can
produce `JsonRpcError: execution reverted` on deposit.
:::

## Related commands

See [`mm predict`](../reference/commands.md#mm-predict) in the commands reference.

<!-- vale on -->

---

## Build a plugin


This guide helps you build your own MetaMask Agent Wallet plugin, starting from the
[plugin template](https://github.com/MetaMask/agent-wallet-plugin-template).
The template ships a working `mm hello ping` command that you can rename and extend, so you have
something running before you write any code.

By the end of this guide, you have a plugin that adds your own command to Agent Wallet, tested
locally and ready to publish.

## Prerequisites

- Install [Node.js](https://nodejs.org/en/download) v22 or later.

## 1. Clone the template

Clone the [plugin template](https://github.com/MetaMask/agent-wallet-plugin-template) into a
directory named after your plugin.

```bash
git clone https://github.com/MetaMask/agent-wallet-plugin-template my-plugin
cd my-plugin
```

## 2. Install the dependencies

Use your preferred package manager to install the dependencies.

```bash npm2yarn
npm install
```

## 3. Update the manifest

The `package.json` file declares your plugin's identity and the `mm` block declares what each
command does and needs.
Replace the template's placeholder values with your own:

- Set `name` and `description`.
- In the `mm` block, update each `commands[].id` to your command id.
- If a command reads wallet data or signs anything, list the capabilities and data access it needs.

Users consent to these capabilities at install time.
Keep the plugin-wide `capabilities` list empty because it is merged into every command.
See the [plugins reference](../reference/plugins.md) for every manifest field, capability, and
data access category.

```json
"mm": {
  "schemaVersion": 1,
  "minCliVersion": "^6.2.0",
  "capabilities": [],
  "commands": [
    {
      "id": "hello:balance",
      "capabilities": ["wallet-read"],
      "dataAccess": ["balances"]
    }
  ]
}
```

## 4. Write your command

Rename the template's command file to match the id you declared in the manifest.
The file path defines the command.
For example, `src/commands/hello/ping.ts` becomes `mm hello ping` with id `hello:ping`.

To write the command, extend `PluginCommand` from `@metamask/agent-wallet/plugin` and implement
`execute`.
The template's command shows the full pattern.

Keep the following rules in mind as you write your command:

- You implement only `execute`, plus static configuration and the optional hooks `afterExecute`,
  `successHint`, and `analyticsOutcome`.
  The rest of the lifecycle is sealed by the host.
- `pluginCommandId` must match the command's `id` in the plugin manifest.
- `requiresAuth` and `requiresInit` gate sign-in and wallet setup.
  Both default to `true`.
- Declare inputs once as a schema.
  `schemaToFlags` and `schemaToArgs` generate the command surface, and `io.resolveInputs` resolves
  flags, positionals, and interactive prompts.
- The base flags `--json`, `--format`, `--toon`, and `--verbose` are inherited automatically.

```ts

  type CommandIO,
  InputFieldType,
  type InputSchema,
  PluginCommand,
  schemaToArgs,
  schemaToFlags,
} from '@metamask/agent-wallet/plugin'

const inputs = {
  name: {
    type: InputFieldType.Text,
    flag: 'name',
    message: 'Name to greet',
    required: false,
    prompt: false,
    index: 0,
  },
} satisfies InputSchema

export default class HelloPing extends PluginCommand<{ message: string }> {
  static override description = 'Say hello from the plugin template.'
  static override requiresAuth = false
  static override requiresInit = false
  static override flags = schemaToFlags(inputs)
  static override args = schemaToArgs(inputs)

  protected readonly pluginCommandId = 'hello:ping'

  async execute(io: CommandIO) {
    const { name } = await io.resolveInputs(inputs)
    return { message: name ? `pong, ${name}!` : 'pong' }
  }
}
```

## 5. Build and test locally

Now build your plugin and install it into your local Agent Wallet to try it out. Install from the
directory rather than a packed tarball, so Agent Wallet can read your manifest and show the full
capability consent screen.

As you iterate, run `mm plugins uninstall <name>` to remove the plugin before you install it again.

```bash npm2yarn
npm run build
mm config set experimentalPlugins true
mm config set experimentalAllowUnverifiedInstalls true
mm plugins install "file:$PWD" --accept-permissions
mm hello ping Alice
```

## 6. Publish

When your plugin works the way you want, publish the package to npm.

Users then install it with `mm plugins install <your-package>` and review a consent screen listing
your commands, data access, and requested capabilities.

```bash npm2yarn
npm publish
```

## Next steps

- Browse the [plugin examples repository](https://github.com/MetaMask/agent-wallet-plugin-examples)
  for complete working plugins, including an ENS resolver built on the authenticated RPC client.
- See the [plugins reference](../reference/plugins.md) for the manifest schema, capability types,
  and the published SDK surface.

---

## Plugins overview


Plugins extend MetaMask Agent Wallet with custom commands.
A plugin is an npm package that adds native commands, discoverable in `mm help` and the REPL.
For example, a plugin can add `mm ens resolve` to resolve ENS names, or `mm x402` to pay for
paywalled APIs.

:::note Beta Notice

Plugins are a beta feature and are off by default.
Installing and running plugins are both blocked until you enable the feature.
:::

## What plugins can do

Plugins run inside Agent Wallet and use a curated context the host provides.
Each command declares the capabilities it needs, and you consent to them at install time.

| Capability       | Grants                                                                                   |
| ---------------- | ---------------------------------------------------------------------------------------- |
| `wallet-read`    | Read services such as balances, prices, and tokens, plus an authenticated EVM RPC client |
| `wallet-submit`  | Signing and transaction submission, still policy-gated by Agent Wallet                   |
| `network-manage` | Reserved for future network management                                                   |

A command with no capabilities can still run pure logic and prompt for inputs.
The session, CLI token, and Secret Recovery Phrase are host-only and never exposed to plugins.
See the [plugins reference](../reference/plugins.md) for the full list of what each capability
unlocks.

## Trust model

Plugins run in-process and unsandboxed.
Install-time consent plus MetaMask backend policy signing are the real trust boundaries.
Only install plugins from publishers you trust.

Installs from npm are consent-gated and fail closed if the package can't be verified.
Plugin lifecycle scripts such as `postinstall` never run.

## Get started

- [Install a plugin](install-a-plugin.md) to add commands published by others.
- [Build a plugin](build-a-plugin.md) to create your own, starting from the official template.

---

## Install a plugin


Install plugins to add new commands to MetaMask Agent Wallet.
Every install shows a consent screen listing the plugin's commands, data access, and requested
capabilities before anything runs.

## Enable plugins

Plugins are a beta feature and are off by default.
Installing and running plugins are both blocked until you enable the feature.

```bash
mm config set experimentalPlugins true
```

## Install from npm

Agent Wallet fetches the package metadata, shows the consent screen, and installs after you
approve. Installs fail closed when the registry is unreachable or the package can't be verified.

```bash
mm plugins install <package>

# Pass `--accept-permissions` to skip the interactive prompt in scripts and CI
mm plugins install <package> --accept-permissions
```

## Install a local plugin

Local `file:` paths and git sources can't be verified, so you need to opt in first.
This is intended for development only.
Without the opt-in, these installs are refused with `PLUGIN_UNVERIFIED_SOURCE`.

```bash
mm config set experimentalAllowUnverifiedInstalls true
mm plugins install file:/path/to/plugin --accept-permissions
```

Prefer installing from the plugin directory rather than a packed tarball.
Agent Wallet reads the manifest from the directory, so it can show the full capability consent
screen before installing. A tarball shows only the unverified-source banner, because the manifest
isn't readable until the package is unpacked. Either way, Agent Wallet persists the approved
capabilities after the install completes.

To develop against a directory without copying it, use `mm plugins link`, which shows the same
consent screen:

```bash
mm plugins link /path/to/plugin
```

## Manage installed plugins

`mm plugins update` shows the consent screen again for any plugin whose version or manifest
changed.

```bash
mm plugins                          # list installed plugins
mm plugins inspect <package>        # show plugin details
mm plugins update                   # update all and re-consent changed manifests
mm plugins uninstall <package>      # remove a plugin
```

## Disable plugins

Turn the whole plugin system off at any time. Installed plugin commands then fail with `PLUGIN_BETA_DISABLED` until you re-enable the feature.

```bash
mm config set experimentalPlugins false
```

## Next steps

- [Build a plugin](build-a-plugin.md)

---

## Architecture


MetaMask Agent Wallet exposes wallet operations through the `mm` CLI, backed by the
`@metamask/agent-sdk` package.
Security is applied by default on every signing and transaction path, backed by Transaction
Protection.

Transactions through Agent Wallet deemed safe are guaranteed against loss up to $10,000/month.\*
See [Transaction Shield](https://support.metamask.io/manage-crypto/transactions/transaction-shield/)
for eligibility, coverage limits, and terms.

## CLI and session

- Install `@metamask/agent-wallet` to get the `mm` binary.
- Run `mm doctor` to verify CLI version, skill compatibility, authentication, and initialization
  before wallet operations.
- Session data is stored at `~/.metamask/session.json` with restricted file permissions.
- Wallet metadata is stored at `~/.metamask/wallets.json`. Predict state is stored at
  `~/.metamask/predict.json`.
- Run `mm reset` to clear local session state.

## Wallet modes

Choose a wallet mode during `mm init`.
The CLI prompts interactively when you omit `--wallet`.

### Server-wallet

Keys are managed and secured server-side in a trusted execution environment (TEE), so agents can't access your main wallet. You retain self-custody.

Signing and transaction operations use an asynchronous model.
Long-running operations return a `pollingId` unless you pass `--wait`.

### Bring your own wallet

You supply a BIP-39 mnemonic.
Useful when you need local key control or an existing seed phrase.
Requests are signed locally and then submitted as jobs, so operations can also return a
`pollingId` unless you pass `--wait`.

Never pass `--mnemonic` on the command line.
Set the `MM_MNEMONIC` environment variable instead.
Optionally encrypt the mnemonic at rest with `MM_PASSWORD` or `mm wallet password set`.

## Transaction simulation

Before a transaction executes, the CLI simulates it to surface reverts, unexpected state changes,
and other failures early.

## Threat scanning

<!-- vale off -->

Threat scanning is powered by Blockaid and production-tested across millions of MetaMask
transactions.
Malicious transactions get auto-bounced.
When a transaction is flagged, it requires your approval before it executes.
You receive details in the CLI output and through the approval flow.

<!-- vale on -->

## Transaction Protection

Eligible transactions deemed safe are backed by Transaction Protection coverage up to
$10,000/month.
[Transaction Shield](https://support.metamask.io/manage-crypto/transactions/transaction-shield/) is
MetaMask's subscription that pairs Transaction Protection with priority support.
See [Transaction Shield](https://support.metamask.io/manage-crypto/transactions/transaction-shield/)
for subscription details, eligibility, coverage limits, and terms.

## Gasless execution

For ERC-20 transfers and swaps where the wallet's native balance cannot cover gas, the CLI
automatically routes through a gasless relay using EIP-7702. The relay submits the transaction on
your behalf and deducts fees from the transferred ERC-20 token automatically.

## ERC-7821 batch execution

On eligible chains and accounts, the CLI combines ERC-20 approval and trade into a single atomic
`execute()` call using ERC-7821. This reduces the number of transactions and avoids approval
front-running. The CLI falls back to sequential submission when batching is not available.

## Smart Transactions

[Smart Transactions](https://support.metamask.io/manage-crypto/transactions/smart-transactions/)
optimize how your trades land onchain with fewer fails, better gas, and built-in MEV protection
where supported on the target chain.

## Policy enforcement

During `mm init`, you choose Guard Mode or Beast Mode to define how policies are enforced.
See [Trading modes](trading-modes.md) for the guardrail and approval comparison,
[Outflow policy](outflow-policy.md) for rolling 24-hour limit details, and
[Switch modes and wallets](../switch-modes-and-wallets.md) to change modes.

## Server-wallet async model

When you submit a signing or transaction request in server-wallet mode:

1. The CLI submits the request to the wallet service.
2. The service simulates the transaction, runs threat scanning, and evaluates your policies.
3. If policy requires 2-factor authentication or threat scanning flags the transaction, the job
   enters an `AWAITING_MFA` state until you approve in the MetaMask Mobile notifications menu
   (QR sign-in) or through the approval email (browser sign-in).
   See [Approve requests](../approve-requests.md).
4. The CLI returns a `pollingId` unless you pass `--wait`.

Track pending work:

```bash
mm wallet requests list
mm wallet requests watch <POLLING_ID>
```

## REPL vs headless

- **REPL**: Run `mm` with no arguments on a TTY for an interactive shell.
- **Headless**: Pass flags explicitly or use `--format json` for machine-readable output in scripts
  and agents.

## Next steps

- [Quickstart](../quickstart.md)
- [CLI commands](commands.md)

---

## Plugins


Reference for MetaMask Agent Wallet plugin authors.
See the [plugins overview](../plugins/index.md) for concepts and the
[build a plugin](../plugins/build-a-plugin.md) guide.

## Plugin manifest

Every plugin declares an `mm` block in its `package.json`.
Agent Wallet validates the manifest at install time and shows its contents on the consent screen.

The package must also declare the `oclif-plugin` keyword, a `@metamask/agent-wallet`
peer dependency, an `oclif` block pointing at the compiled commands, and a generated
`oclif.manifest.json` shipped in the package.

Packages that declare `oclif.hooks` or `oclif.plugins` are rejected because hooks run outside the
plugin boundary.

```json
"mm": {
  "schemaVersion": 1,
  "minCliVersion": "^6.2.0",
  "capabilities": [],
  "commands": [
    {
      "id": "hello:balance",
      "capabilities": ["wallet-read"],
      "dataAccess": ["balances"],
      "targetChains": "any"
    }
  ]
}
```

| Field                     | Required | Description                                                                                                              |
| ------------------------- | -------- | ------------------------------------------------------------------------------------------------------------------------ |
| `schemaVersion`           | Yes      | Manifest schema version. Must be `1`.                                                                                    |
| `minCliVersion`           | Yes      | Semver range of Agent Wallet versions the plugin supports. The plugin system shipped in 6.2.0, so use `^6.2.0` or later. |
| `capabilities`            | No       | Plugin-wide capabilities merged into every command. Keep this empty to avoid over-granting.                              |
| `commands`                | Yes      | One entry per command. At least one command is required.                                                                 |
| `commands[].id`           | Yes      | Command id matching the command's `pluginCommandId`, such as `hello:balance`.                                            |
| `commands[].capabilities` | No       | Capabilities this command needs. Defaults to none.                                                                       |
| `commands[].dataAccess`   | No       | Data categories the command reads, shown on the consent screen. Defaults to none.                                        |
| `commands[].targetChains` | No       | `"any"` or a list of EVM chain ids the command targets. Defaults to `"any"`.                                             |

## Capability types

Capabilities gate what a command can reach on the plugin context.
Users consent to them at install time.

The capabilities `mnemonic-read` and `config-write` are reserved.
Manifests that declare them are rejected.

A command that uses a gated member without declaring the matching capability fails at runtime with
`PERMISSION_DENIED`.

| Capability       | Grants                                                                                       |
| ---------------- | -------------------------------------------------------------------------------------------- |
| `wallet-read`    | Read services and the authenticated per-chain EVM RPC client. See the table below.           |
| `wallet-submit`  | `ctx.walletExecutor` for signing and transaction submission, still policy-gated by MetaMask. |
| `network-manage` | `ctx.networkRegistry`. Reserved for future network management.                               |

## Plugin context

Commands access the host through `this.ctx`, a curated context the host restricts per command
based on its granted capabilities.

The session, CLI token, and mnemonic store are host-only.
Accessing them from a plugin always fails with `PERMISSION_DENIED`.

| Context member                    | Requires         | Description                                                         |
| --------------------------------- | ---------------- | ------------------------------------------------------------------- |
| `logger`, `args`, `flags`, `argv` | None             | Always available.                                                   |
| `accountService`                  | `wallet-read`    | Account and balance queries.                                        |
| `authService`                     | `wallet-read`    | Authentication state queries.                                       |
| `priceService`                    | `wallet-read`    | Spot and historical prices.                                         |
| `tokenService`                    | `wallet-read`    | Token metadata and discovery.                                       |
| `walletStateManager`              | `wallet-read`    | Local wallet state snapshot, including wallets and the selection.   |
| `feesService`                     | `wallet-read`    | Fee estimates.                                                      |
| `swapQuoteStore`                  | `wallet-read`    | Persisted swap quotes.                                              |
| `publicClient(chainId)`           | `wallet-read`    | Authenticated per-chain viem public client for raw EVM reads.       |
| `walletExecutor(io, source)`      | `wallet-submit`  | Executor for transactions, message signing, and typed-data signing. |
| `networkRegistry`                 | `network-manage` | Supported network registry.                                         |

### Raw EVM reads

With `wallet-read`, call `ctx.publicClient(chainId)` for an authenticated
[viem](https://viem.sh) public client backed by the same RPC gateway the host uses:

```ts
const client = this.ctx.publicClient(1)
const balance = await client.getBalance({ address })
```

### Signing and submission

With `wallet-submit`, call `ctx.walletExecutor(io, "<command-id>")` to get an executor.
The executor accepts three request kinds and routes every request through MetaMask policy:

| Request kind  | Description                          | Result                      |
| ------------- | ------------------------------------ | --------------------------- |
| `transaction` | Submit an EVM transaction on a chain | Transaction hash and status |
| `message`     | Sign a plaintext message             | Signature                   |
| `typed-data`  | Sign an EIP-712 typed-data payload   | Signature                   |

## PluginCommand class

A plugin command extends `PluginCommand` and implements `execute`. The security-critical lifecycle is sealed.
A subclass that overrides `run`, `runLifecycle`, `beforeExecute`, `init`, `prepareForRepl`,
`withPluginIsolation`, or the `requiresAuth`, `requiresInit`, and `requiresFees` getters throws
`PLUGIN_SEALED_OVERRIDE` before it can run.
Fee-cache warmup is host-only and always off for plugin commands.

| Member                                            | Role                                                                     |
| ------------------------------------------------- | ------------------------------------------------------------------------ |
| `execute(io)`                                     | Required. The command's logic. Its return value is rendered by the host. |
| `pluginCommandId`                                 | Required. Must match the command's manifest `id`.                        |
| `description`, `examples`, `flags`, `args`        | Static configuration shown in help output.                               |
| `requiresAuth`                                    | Static. Gates the sign-in check. Defaults to `true`.                     |
| `requiresInit`                                    | Static. Gates the wallet setup check. Defaults to `true`.                |
| `afterExecute`, `successHint`, `analyticsOutcome` | Optional hooks.                                                          |

## Plugin SDK surface

Import from `@metamask/agent-wallet/plugin`:

| Export                                                                                        | Description                                             |
| --------------------------------------------------------------------------------------------- | ------------------------------------------------------- |
| `PluginCommand`                                                                               | Base class for plugin commands.                         |
| `PluginCommandContext`                                                                        | Type of the curated context available as `this.ctx`.    |
| `PluginManifest`, `definePluginManifest`, `PluginManifestSchema`                              | Manifest type, authoring helper, and schema.            |
| `CommandIO`                                                                                   | Interaction surface passed to `execute`.                |
| `CommandError`, `ok`, result helpers                                                          | Error and result envelope helpers.                      |
| `schemaToFlags`, `schemaToArgs`, `resolveInputs`, `mergeArgsIntoFlags`, `enumFlag`, `trimKey` | Declarative input engine.                               |
| `InputFieldType`, `InputSchema`, `InputField`, `ResolvedInputs`, `SelectOption`, `Asker`      | Input types.                                            |
| `PublicClient`                                                                                | viem public client type returned by `ctx.publicClient`. |

## Data access categories

`commands[].dataAccess` labels the data a command reads.
The categories appear on the consent screen and are informational.

`accounts`, `balances`, `prices`, `tokens`, `network`, `fees`, `swap-quotes`, `session`,
`mnemonic`

## Storage locations

| Data                        | Location                                                                                               |
| --------------------------- | ------------------------------------------------------------------------------------------------------ |
| Plugin code                 | The oclif data directory. On macOS `~/Library/Application Support/mm/`, on Linux `~/.local/share/mm/`. |
| Approvals and configuration | `~/.metamask/config.json` under the `plugins` key.                                                     |

Each approval record stores the approved version, package integrity, manifest hash, approved
capabilities, approved command IDs, and an approval timestamp.

The data directory is outside the running CLI's module tree, so Agent Wallet symlinks itself into
the data directory's `node_modules` when user plugins are installed. That way a plugin's
`@metamask/agent-wallet/plugin` import resolves to the same running instance rather than loading a
second copy of the CLI. Declare `@metamask/agent-wallet` as a peer dependency, not a regular
dependency, so the symlink is what resolves.

## Related pages

- [Plugins overview](../plugins/index.md)
- [Install a plugin](../plugins/install-a-plugin.md)
- [Build a plugin](../plugins/build-a-plugin.md)
- [Error codes](error-codes.md#plugin-errors)

---

## Supported chains


MetaMask Agent Wallet supports preconfigured EVM networks.
The authoritative list for your CLI version is the output of `mm chains list`.

## List supported chains

```bash
mm chains list
```

For machine-readable output:

```bash
mm chains list --json
```

The JSON output includes per-network fields such as `key`, `chainNamespace`, `caip2`, `chainId`,
`name`, `selected`, `relaySupported`, and `features` (for example, `swap`, `predict`, `perps`).
`relaySupported` indicates whether gasless relay is available on that network.

## Product coverage

Pass any supported chain ID to `--chain-id` for signing, transfers, balances, and other wallet
operations.
Availability varies by CLI version.
Always confirm with `mm chains list` before scripting against a specific network.

The tables below reflect the current preconfigured network list.
The `mm chains list` output also includes a `features` field per chain (for example, `swap`,
`predict`, `perps`).
Use `mm chains list --json` to inspect feature availability programmatically.

### Mainnets

| Network         | Chain ID      | [Transaction Shield](https://support.metamask.io/manage-crypto/transactions/transaction-shield/) |
| --------------- | ------------- | ------------------------------------------------------------------------------------------------ |
| Ethereum        | `1`           | Covered                                                                                          |
| BNB Smart Chain | `56`          | Covered                                                                                          |
| Base            | `8453`        | Covered                                                                                          |
| Arbitrum        | `42161`       | Covered                                                                                          |
| Optimism        | `10`          | Covered                                                                                          |
| Polygon         | `137`         | Covered                                                                                          |
| Avalanche       | `43114`       | Covered                                                                                          |
| Linea           | `59144`       | Covered                                                                                          |
| Unichain        | `130`         | No                                                                                               |
| ZKsync Era      | `324`         | No                                                                                               |
| Scroll          | `534352`      | No                                                                                               |
| Blast           | `81457`       | No                                                                                               |
| Mantle          | `5000`        | No                                                                                               |
| opBNB           | `204`         | No                                                                                               |
| Celo            | `42220`       | No                                                                                               |
| Monad           | `143`         | Covered                                                                                          |
| Sei             | `1329`        | Covered                                                                                          |
| HyperEVM        | `999`         | Covered                                                                                          |
| MegaETH         | `4326`        | Covered                                                                                          |
| Hemi            | `43111`       | No                                                                                               |
| Robinhood Chain | `4663`        | Covered                                                                                          |
| Arc             | `5042`        | Covered                                                                                          |
| Palm            | `11297108109` | No                                                                                               |

:::caution Chains without Transaction Shield support

On chains marked **No**, threat scanning is unavailable, so Agent Wallet can't tell you whether a
recipient or contract is malicious, and Transaction Protection coverage doesn't apply.
In Guard Mode, transactions are still checked against your address allowlist, which blocks
recipients you haven't approved.
Treat that as a basic safeguard, not a replacement for threat scanning.

:::

### Testnets

| Network                 | Chain ID    |
| ----------------------- | ----------- |
| Ethereum Sepolia        | `11155111`  |
| Ethereum Hoodi          | `560048`    |
| Base Sepolia            | `84532`     |
| Arbitrum Sepolia        | `421614`    |
| Optimism Sepolia        | `11155420`  |
| Polygon Amoy            | `80002`     |
| Avalanche Fuji          | `43113`     |
| BNB Smart Chain Testnet | `97`        |
| Linea Sepolia           | `59141`     |
| ZKsync Sepolia          | `300`       |
| Scroll Sepolia          | `534351`    |
| Blast Sepolia           | `168587773` |
| Mantle Sepolia          | `5003`      |
| Unichain Sepolia        | `1301`      |
| opBNB Testnet           | `5611`      |
| Celo Sepolia            | `11142220`  |
| Monad Testnet           | `10143`     |
| Sei Testnet             | `1328`      |
| HyperEVM Testnet        | `998`       |
| MegaETH Testnet         | `6343`      |
| Hemi Testnet            | `743111`    |
| Robinhood Chain Testnet | `46630`     |
| Arc Testnet             | `5042002`   |

For chains not in the preconfigured list, `mm wallet balance` falls back to direct RPC queries via
Multicall3.

## Per-chain balances

Wallet balances and transfers are scoped to the chain you specify with `--chain-id`.
Fund each chain separately, or bridge with `mm swap execute` before transferring.

## Related commands

- [`mm chains list`](commands.md#mm-chains-list)
- [Send tokens](../guides/send-tokens.md)
