npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@oceanalt/metamask-agent-wallet

v0.1.0

Published

MetaMask Agent Wallet (mm) plugin: check x402 payment signatures, token transfers and approvals with OceanAlt before MetaMask signs them. Allow, ask a human, or block. No keys, no custody.

Readme

@oceanalt/metamask-agent-wallet

A MetaMask Agent Wallet (mm) plugin. Before MetaMask signs an x402 payment authorization, a token transfer or an approval, it checks the request with OceanAlt's public API and returns one of three results:

| Result | What happens | |---|---| | allow | The request goes to MetaMask, which still applies its own policy, threat scanning and 2FA. | | confirm | A human must agree first. Interactive: a yes/no prompt. Headless: status: "needs_confirmation" plus a code bound to this exact request; rerun with --confirm <code>. | | block | Nothing is signed. There is no override. |

The plugin holds no keys and moves no funds. Signing is done by MetaMask through ctx.walletExecutor. If a check can't run (network error, HTTP error, unknown answer), the result is confirm, never allow.

Why signatures are checked too

An x402 payment is an EIP-3009 TransferWithAuthorization signature, not a transaction. MetaMask documents its Guard Mode outflow limit in terms of outgoing transfers. Public tests (bfullam/x402-guard, gap-test/) show a Guard Mode wallet signing such authorizations to sanctioned and mixer addresses without a prompt. This plugin puts typed-data signatures through the same checks as transactions. It can also count them toward a local 24h USDC cap.

Important limit: this is not an interception hook

The Agent Wallet plugin API (@metamask/agent-wallet/plugin, 7.1.0) lets a plugin add commands. It has no hook that runs before mm wallet sign-typed-data or mm wallet send-transaction. So this plugin only protects requests that go through its own commands. An agent can still call mm wallet … directly and skip it. skills/oceanalt-guard/SKILL.md tells agents to use these commands. That is guidance, not enforcement. Enforcement that can't be bypassed would have to live in MetaMask's own signing pipeline.

Commands

mm oceanalt check            --chain-id <id> (--payload '<typed data>' | --to <addr> [--data 0x…] [--value <wei>]) [context]
mm oceanalt sign-typed-data  --chain-id <id> --payload '<typed data>' [context] [--confirm <code>]
mm oceanalt send-transaction --chain-id <id> --to <addr> [--data 0x…] [--value <wei>] [context] [--confirm <code>]
mm oceanalt config           [--api-key <key>|none] [--max-validity <s>] [--daily-cap <usdc>|none] [--require-signed-requirements true|false]

context: [--url <x402 resource url>] [--payment-required '<PAYMENT-REQUIRED header or JSON>'] [--intent-to <payee>] [--intent-amount <atomic units>]

check signs nothing and needs no capabilities. sign-typed-data and send-transaction need wallet-submit, which you approve at install time. sign-typed-data takes the same --chain-id / --payload as mm wallet sign-typed-data.

What is checked

| Check | Source | Result | |---|---|---| | Decode the request | local | EIP-3009 Transfer/ReceiveWithAuthorization, EIP-2612 Permit, Permit2 (PermitSingle/Batch, PermitTransferFrom/Witness), native transfer, ERC-20 transfer, transferFrom, approve, increaseAllowance, permit, setApprovalForAll. Anything else, including any other contract call: confirm. | | Counterparty (payee, spender, or called contract) | POST /api/decide {to, amountUsdc?, network} | decline → block, allow → allow, review / anything else / error → confirm. amountUsdc is sent only when the token is Circle USDC on a known chain. | | Calldata vs declared payment (transactions) | POST /api/intent/check | mismatch (for example approve where a payment was declared) → block, unknown / error → confirm. Runs when --intent-to is given or the calldata is a transfer. | | Typed data vs declared payment | local, same rules | A permit or Permit2 signature where a payment was declared, or in an x402 context (--url / --payment-required) → block. EIP-3009 payee or amount different from --intent-* → block. | | Unlimited approval with no declared intent | local | confirm | | Signature validity window | local | validBefore / deadline more than maxValiditySeconds (default 3600) ahead → confirm | | x402 signed payment requirements | POST /api/x402/verify-requirements, or offline with pinned keys in config | tampered, bad signature, payTo/amount not signed → block. The signed payTo isn't among the 402's accepts → block. No seller signature → allow (confirm with --require-signed-requirements true). Key unavailable / error → confirm. | | Payment endpoint | GET /api/endpoint?url= | risky → block, clear → allow, caution / unknown / error → confirm | | Chain | local | A chain OceanAlt doesn't screen natively, or a typed-data domain chainId different from the signing chain → confirm | | 24h USDC cap (off by default) | local file ~/.oceanalt/metamask-agent-wallet-ledger.json | Counts USDC signed or sent through this plugin, signatures included. Over the cap → confirm. Non-USDC payments with a cap set → confirm. |

What is not checked

  • Requests signed outside this plugin's commands (see the limit above).
  • personal_sign messages (result is always confirm).
  • Whether a token contract is genuine. Only Circle USDC addresses are recognised, and only for amounts.
  • The effects of arbitrary contract calls, multicalls, Permit2 witness contents and non-EVM chains.
  • Whether the seller delivers what was paid for.
  • An OceanAlt allow is a screening result over public data. It isn't a guarantee.

Configuration

No API key is needed for the free endpoints. If you set one (mm oceanalt config --api-key … or OCEANALT_API_KEY), it is sent as x-api-key, and only to the OceanAlt host. Config lives in ~/.oceanalt/metamask-agent-wallet.json, written with file mode 0600 (the key is stored in plaintext; prefer the environment variable on shared machines). OCEANALT_BASE_URL and OCEANALT_MM_DIR override the host and the directory.

Every check sends to OceanAlt the counterparty address, chain, USDC amount and, for transactions, the target and calldata. When given, it also sends the payment URL and 402 requirements. Nothing else is sent, and no telemetry.

Install (local development)

npm install && npm run build      # tsc + oclif manifest
mm config set experimentalPlugins true
mm config set experimentalAllowUnverifiedInstalls true
mm plugins install "file:$PWD" --accept-permissions

Plugins are a beta feature of mm and are off by default.

Library use

The checks are in lib/guard.mjs and have no MetaMask dependency:

import { createClient, screen } from "@oceanalt/metamask-agent-wallet";
const r = await screen({ kind: "typed-data", chainId: 8453, typedData }, { url, paymentRequired }, { client: createClient() });
// r.action: "allow" | "confirm" | "block"; r.findings: [{ check, outcome, code, detail }]

Tests

npm test     # node:test, fetch mocked; no network

License

MIT