Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 9 additions & 2 deletions skills/metamask-agent-wallet/SKILL.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
---
name: metamask-agent-wallet
description: Use when the user asks anything about blockchain wallets, transactions, signing, token transfers, supported chains, wallet balances, perpetual futures trading, prediction markets, token swaps, cross-chain bridges, market data, token discovery, decoding EVM calldata, Aave V3 lending and borrowing, or authentication via the MetaMask Agentic CLI. Single entry point for all mm CLI operations.
description: Use when the user asks anything about blockchain wallets, transactions, signing, token transfers, supported chains, wallet balances, perpetual futures trading, prediction markets, token swaps, cross-chain bridges, market data, token discovery, decoding EVM calldata, Aave V3 lending and borrowing, or authentication via the MetaMask Agentic CLI; also when an HTTP request returns 402 Payment Required (x402) or the agent needs to pay for a paywalled API, endpoint, file, or resource over HTTP. Single entry point for all mm CLI operations.
license: MIT
metadata:
author: metamask
version: "4.0.0"
version: "4.1.0"
cliVersion: "3.0.0"
---

Expand Down Expand Up @@ -104,6 +104,7 @@ Match the user's intent to a command and reference file, then read the reference
| Execute a token swap or bridge | `mm swap execute` | [swap.md](references/swap.md) |
| Check swap or bridge status | `mm swap status` | [swap.md](references/swap.md) |
| Bridge tokens to another chain | `mm swap execute` | [swap.md](references/swap.md) |
| Pay an HTTP `402` / x402 paywalled request | `python3 scripts/x402_pay.py` | [x402.md](references/x402.md) |

## Workflows

Expand Down Expand Up @@ -133,6 +134,7 @@ CLI behavior lives in `references/`. Repeatable patterns live in `workflows/`. L
| Toggle Aave V3 collateral | [aave-collateral.md](workflows/aave-collateral.md) |
| Check Aave V3 positions and health factor | [aave-positions.md](workflows/aave-positions.md) |
| Discover Aave V3 tokens, rates, and liquidity | [aave-markets.md](workflows/aave-markets.md) |
| Pay an HTTP `402` (x402) paywalled request | [x402-pay.md](workflows/x402-pay.md) |

## Global Flags

Expand Down Expand Up @@ -218,6 +220,10 @@ Before constructing any command, validate all user-provided values:
| `--to-address` | Must match `^0x[0-9a-fA-F]{40}$`. Only valid for cross-chain swaps (`--to-chain` differs from `--from-chain`); rejected for same-chain swaps |
| `--refuel` | Boolean flag (no value). Only meaningful for cross-chain swaps (`--to-chain` differs from `--from-chain`); no effect on same-chain swaps |
| `--password` | Must be a non-empty string. Never log, display, or store the value. |
| x402 `asset` | Must be a valid contract address on a network returned by `mm chains list`. The currency choice is the server's offer confirmed by the user; the script keeps no currency allowlist. |
| x402 `payTo` / authorization `to` | Must match `^0x[0-9a-fA-F]{40}$` and equal the recipient in the `402` |
| x402 `value` | Atomic-unit integer that exactly equals the offered amount (the `exact` scheme is not a maximum) |
| x402 resource URL | Must be `https://`. Reject a `402` reached via an unexpected cross-host redirect |

Do not pass unvalidated user input into any command.

Expand All @@ -230,6 +236,7 @@ Do not pass unvalidated user input into any command.
| Message signing | Always show exact message and chain before signing |
| Typed-data signing | Always show domain, primary type, chain, verifying contract, and message summary before signing |
| Swaps / bridges | Always confirm from/to tokens, amount, source/destination chain, slippage, quoted output, recipient address (if `--to-address` is set), and the destination gas top-up (if `--refuel` is set) before executing |
| x402 payments | Always confirm asset, decimals-correct amount, network, `payTo`, and resource URL before signing the authorization. One payment attempt per resource, never auto-retry a payment. Autonomous auto-pay is not supported. |
| Perps trading | Always confirm symbol, side, size, leverage, venue, order type, and limit price if present before executing |
| Perps deposit/withdraw | Always confirm amount, asset, venue, network, and destination where applicable before executing |
| Predict trading | Always confirm token ID, side, size, price, order type, market, and outcome before executing |
Expand Down
114 changes: 114 additions & 0 deletions skills/metamask-agent-wallet/references/x402.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
# x402 Payments (buyer / payer)

Use this when an HTTP request returns **`402 Payment Required`** following the
[x402 protocol](https://docs.x402.org), or when the user asks to pay for / fetch a paywalled API,
endpoint, file, or resource over HTTP.

`scripts/x402_pay.py` performs the payment: it fetches the URL, reads the server's payment
requirements, signs an EIP-3009 authorization with `mm wallet sign-typed-data`, retries with the
payment header, and reports the settlement. Signing is delegated to `mm`, so the private key stays
in the wallet. The script is pure Python standard library (run with `python3`).

## How x402 works (exact scheme, EVM)

1. The client requests a resource. The server replies `402` with 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 (no on-chain tx from the payer) permitting 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 (tx hash).

The script handles both protocol versions: v1 (requirements in the `402` body, retry header
`X-PAYMENT`) and v2 (requirements in the `PAYMENT-REQUIRED` header, retry header
`PAYMENT-SIGNATURE`). The payload envelope also differs: v1 puts `scheme`/`network` at the top
level, while v2 nests the chosen requirements under `accepted` and forwards the top-level
`resource` (see the x402 v2 spec, PaymentPayload schema). The script builds the correct envelope
per version.

### Supported

- The `exact` scheme on EVM networks (`eip155:*`) using EIP-3009
`transferWithAuthorization`, protocol v1 and v2.

### Not supported (rejected with a clear error)

- The Permit2 asset transfer method (`extra.assetTransferMethod: "permit2"`) and its gas-sponsoring
extensions. An EIP-3009 option on the same asset is preferred when offered; a Permit2-only offer
is reported as unsupported. Signing a Permit2 authorization is a separate flow.
- Other schemes such as `upto`, and non-EVM networks (e.g. Solana).
- Offers that omit the EIP-712 domain `name`/`version` in `extra`. The reference client falls back
to reading them on-chain; this script does not, so it asks for an offer that includes them rather
than risk signing the wrong domain.

## Usage

`scripts/x402_pay.py` is a helper script (not an `mm` subcommand). Two things follow from that:
call it by its **full path inside this skill's directory**, since the shell's working directory is
not stable between commands and a bare `scripts/x402_pay.py` will not be found; and **do not pass
the global `--toon`/`--format` flags** to it, as it always prints JSON (it accepts and ignores them
if passed). Let `SKILL_DIR` be this skill's base directory (the folder containing `SKILL.md`).

Inspect first (read-only: no signing, no spending), show the result to the user, then pay.

```bash
python3 "$SKILL_DIR/scripts/x402_pay.py" inspect <url> [--method M] [--data BODY]
python3 "$SKILL_DIR/scripts/x402_pay.py" pay <url> --confirm [--method M] [--data BODY] [--asset <contract>] [--network <network>]
```

`inspect` prints the payment requirement(s) as JSON, including the human-readable amount, asset
symbol, network, `payTo`, and resource. `pay` runs the payment for a single eligible option and
prints the settlement (`transaction`) and the resource body. It requires `--confirm`. When the
`402` offers more than one eligible option, choose one with `--asset` or `--network`.

The resource may use any HTTP method. For a non-GET endpoint pass `--method` (and `--data` for a
request body); the same request is replayed with the payment attached, so a paid `POST` works the
same as a `GET`. `--data` defaults to a JSON content type, overridable with `--content-type`.

### Example

```bash
python3 "$SKILL_DIR/scripts/x402_pay.py" inspect https://api.example.com/premium
# review the amount / payTo / resource with the user, then:
python3 "$SKILL_DIR/scripts/x402_pay.py" pay https://api.example.com/premium --confirm
```

## What the script checks

It pays an option whose `scheme` is `exact` on a network `mm` supports (resolved from
`mm chains list`). Before signing it verifies the amount is a positive atomic-unit integer, the
asset and `payTo` are valid addresses, the EIP-712 domain (`name`/`version`) is present, and the
URL is `https://` (plain `http` is allowed only on loopback for local testing). It does not follow
redirects, so a cross-host redirect cannot divert payment. After paying it makes a single retry
and reports settlement; it never retries a payment.

These are protocol-correctness checks. Which currencies and amounts are allowed is the wallet's
decision: the asset comes from the server's offer, the user confirms it, and `mm` signs (and is
where spend policy applies). The script does not keep its own currency allowlist.

## Assets and decimals

The server chooses which assets it accepts; the client can only pay one the server offered. The
script reads the asset's symbol and decimals from `mm token assets` for display. When `mm` cannot
resolve them (for example on testnets the Token API does not index), it shows the raw atomic
amount; the signed value is the server's atomic amount either way.

## Wallet modes

- **Server-wallet:** signing runs synchronously via `--wait` (guard mode permits EIP-712 signing).
The x402 window is short, so if a signature needs manual approval and is slow, the authorization
can expire; rerun `pay` to sign again with fresh values.
- **BYOK:** signing returns immediately. Set `MM_PASSWORD` for an encrypted mnemonic so signing is
non-interactive.

## Confirmation

Run `inspect` and show the user the asset, amount, network, `payTo`, and resource URL. Run
`pay ... --confirm` only after the user approves. A signature authorizes a real token debit.

## Idempotency

The script is stateless. The EIP-3009 nonce prevents the same signed authorization from settling
twice, and each run makes one payment, but rerunning `pay` for the same resource makes a new
payment. Guard repeated calls at the caller. A local idempotency ledger (a caller-supplied key
mapped to prior settlements) is a possible future improvement.
Loading