mcpField
S
SendCheck — EVM address verification (x402)

SendCheck — EVM address verification (x402)

远程服务
github.com/pennyforgeorg安全07 周前更新
代码仓库

关于 SendCheck — EVM address verification (x402)

SendCheck 是一个零依赖客户端,可在 x402 客户端付款前检查 EVM 地址。它结合免费的校验和预检、签名服务卡验证与付款挑战验证。

主要功能

  1. 01免费的 EVM 地址预检
  2. 02离线地址格式校验
  3. 03ES256 签名卡验证
  4. 04挑战地址与价格检查
  5. 05检测固定密钥轮换

适用场景

  1. 01付款前拦截格式错误的地址
  2. 02依据签名条款检查 x402 挑战
  3. 03发现服务签名密钥变更

MCP 相关

此软件包是 x402 API 客户端,而非 MCP 服务;README 未说明其支持 MCP。

配置

远程服务无需本地安装。选择你使用的客户端,复制配置或使用一键安装。

服务地址https://api.pennyforge.org/mcp
一键复制安装命令
Claude CodeTerminal
Cursor.cursor/mcp.json
VS Code.vscode/mcp.json
Claude Desktopclaude_desktop_config.json
Windsurf~/.codeium/windsurf/mcp_config.json

命令在终端中运行;JSON 粘贴到对应客户端的 MCP 配置后重启。需要授权的服务会在首次连接时提示登录。

工具

3
参数类型必填说明
addressstring是EVM 地址,0x + 40 个十六进制字符(大小写均可)

详细介绍

sendcheck-verify

Listed on mcpservers.org

付款前先验证。 一个零依赖客户端,用于免费调用 GET /validate 对 SendCheck x402 API 进行预检查 — 这道仅需 10 行代码的防护,可阻止你的 Agent 向拼写错误、不匹配或遭篡改的结算地址签署付款。

x402 客户端向某项服务付款时,会向该服务告知的结算地址付款。只要有一个字符错误(大小写颠倒、漏掉一位数字、替换了地址),USDC 就会永远流向别处。/validate 是免费的、无需密钥、无需账户的预检查:在投入真金白银前,这个地址是否确实格式正确,且 EVM 地址大小写校验无误?

从 v0.2.0 起,这个软件包还会验证服务的签名服务卡片 — 这是一个针对 payTo 和每条路由 maxPrice 签署的 ES256 JWS,工作进程会在每次部署时重新签署 — 因此,只要客户端曾固定过公钥一次,就能在付款前以密码学方式确认挑战中的 payTo。这是防地址漂移检查的参考实现(地址漂移文章中的“签名服务卡片”)。

为什么需要它

SendCheck 的付费端点通过 x402 收费:单条链 $0.01,全部五条链 $0.05 — 使用 Base 上的 USDC,无需账户或 API 密钥。但大多数“这个地址是不是无效?”检查都不需要链上数据:仅 EIP-55 校验和就能发现最常见、代价最高的问题(拼写错误、字符缺失、大小写遭篡改)。因此 /validate 免费,而这个软件包让调用它只需一行代码。

签名服务卡片(v0.2.0)

付款前检查地址有一个漏洞:客户端用于比对的“预期 payTo”通常来自刚刚获取的同一份发现文档 — 因此,被攻陷的服务可以把你指向自己的新地址;对于经常轮换地址的服务,等检查完成时,每个记住的地址都已过时。

SendCheck 通过签署其付款详情来堵上这个漏洞。工作进程在每次部署时,都会使用稳定的 ES256(EC P-256)密钥签署结算地址和每条路由的最高价格,并在三个位置提供已签名区块 { jws, key }:

<origin>/.well-known/x402   →  top-level "attestation"
<origin>/openapi.json       →  info["x-attestation"]
the 402 challenge itself    →  extensions["x-sendcheck-attestation"]

SendCheck 在每次部署时都使用稳定密钥签署其付款详情,因此,任何曾固定过该密钥一次的客户端,都能在付款前以密码学方式确认付款挑战中的地址确实由我们签署;首次联系仍遵循首次使用时信任(TOFU)。

签名带来的保障:为有状态的回访客户端提供密钥连续性 — 被攻陷的工作进程/DNS/CDN 无法悄悄重定向你的付款,密钥轮换也会成为可标记的显著事件。签名不提供的保障(我们有意不夸大):首次访问时的真实性(这属于 TOFU)、对没有固定密钥的临时 Agent 的保护,或低于已签名 maxPrice 的价格。

已签名负载还包含每条路由的 maxPrice,因此 verifyChallenge 会捕获价格悄然高于密钥签署上限的挑战。

防漂移接入方式
import { checkService, verifyChallenge, ATTESTATION_EXTENSION } from "@pennyforgeorg/sendcheck-verify";

const origin = "https://api.pennyforge.org";

// 1) Once: pin the public key (first contact = trust-on-first-use).
const first = await checkService(origin);          // { ok, keyId, key: JWK, payTo, … }
// persist { kid: first.keyId, x: first.key.x, y: first.key.y } somewhere durable

// 2) Every call: confirm the card still verifies and the key has not rotated.
const svc = await checkService(origin, { pinnedKey: storedPin });
if (svc.keyChanged) { /* loud: the key rotated — inspect before trusting */ }
if (!svc.ok) throw new Error("service card not valid: " + svc.attestation.reason);

// 3) At payment time: bind the 402 CHALLENGE to the signed card.
//    (challenge = decoded base64 PAYMENT-REQUIRED header, or the 402 JSON body)
const verdict = await verifyChallenge(challenge, svc.block, { origin });
if (!verdict.valid) throw new Error("challenge not signed: " + verdict.reason);
// …now sign the EIP-3009 payment to challenge.accepts[0].payTo.

verifyChallenge 会检查挑战中的 payTo 是否与已签名地址一致,并检查挑战价格是否超过该路由已签名的 maxPrice。失败原因:signature_invalid、challenge_payto_mismatch、price_exceeded、route_not_signed、expired、iat_future、service_mismatch、kid_mismatch、malformed。

安装

# GitHub npm registry (v0.2.0 published 2026-09-08)
npm install @pennyforgeorg/sendcheck-verify --registry https://npm.pkg.github.com

即使是读取公开内容,GitHub 的 npm 注册表也会要求提供任意有效的 GitHub 令牌 — 在 .npmrc 中添加 //npm.pkg.github.com/:_authToken=<your GH token>(classic PAT 或具有 Packages:Read 权限的 fine-grained token 均可)。手头没有令牌?从公开仓库安装:

npm install github:pennyforgeorg/sendcheck-verify

需要 Node 18+(使用全局 fetch)。零依赖。MIT。

快速开始

import { verifyBeforePay } from "@pennyforgeorg/sendcheck-verify";

// Throws SendCheckVerifyError unless the address passes the free pre-check.
await verifyBeforePay("0x9504A5939AB5be2B2B1F8beA7D7ebeCcd96c485D");

// …then sign your x402 payment.

CommonJS:

const { verifyBeforePay } = require("@pennyforgeorg/sendcheck-verify");

在 x402 客户端中的典型接线方式:

import { verifyBeforePay } from "@pennyforgeorg/sendcheck-verify";
import { wrapFetchWithPayment } from "x402-fetch"; // or your own x402 stack

const pay = wrapFetchWithPayment(fetch, { wallet });

async function call(serviceUrl, address, body) {
  await verifyBeforePay(address);          // free — catch bad addresses here
  const res = await pay(serviceUrl, {      // paid only when the address is clean
    method: "POST",
    headers: { "content-type": "application/json" },
    body: JSON.stringify(body),
  });
  return res.json();
}

如果你已在自己的环境中规范化地址,只想获取结果对象(不抛出异常):

const r = await verifyBeforePay(addr, { throwOnError: false });
// { valid, status: "valid" | "plain" | "mismatch" | "format" | "network" | "http",
//   message, normalized, checked }

API

verifyBeforePay(address, opts?)
  • address — EVM 地址,格式为 0x + 40 位十六进制字符。
  • opts.baseUrl — 覆盖 API 主机(默认:线上 Worker)。
  • opts.fetchFn — 注入 fetch 实现(用于测试/代理)。
  • opts.throwOnError — 默认值为 true;传入 false 可始终获取结果。

行为说明:

  • 不符合 0x+40 位十六进制格式的字符串会在本地格式检查时失败,并抛出异常(或返回 checked: false),不会发送请求——你无需为无效输入支付一次往返请求。
  • status: "plain" = 有效地址,全小写或全大写(不包含大小写校验信息)。这类地址可以正常支付;响应中会包含规范化后的 EIP-55 格式。
  • status: "mismatch" = 大小写与地址哈希不匹配——通常是输入错误或遭到篡改。这是唯一应视为硬性失败的情况。
looksLikeAddress(addr) — 离线格式检查,不访问网络。
verifyAttestation(attestation, opts?)

验证已签名区块 { jws, key }(针对规范 JSON 负载的 ES256 JWS)。 纯异步操作(WebCrypto);不访问网络。返回 { valid, reason?, payload, keyId, signedAt, expiresAt, warning? }。 opts:origin、expectedPayTo、challengePayTo、route、 challengeMaxAmount(原子单位的 USDC 字符串)、now(Unix 秒,用于测试)。 时间窗口:exp 超时超过 60 秒时硬性拒绝;iat 最多可比当前时间晚 60 秒;iat 早于 30 天仍然有效,但会返回 warning: "stale"。reason 代码:malformed、header_mismatch、 kid_mismatch、signature_invalid、service_mismatch、payto_mismatch、 challenge_payto_mismatch、route_not_signed、price_exceeded、expired、 iat_future。

checkService(origin, opts?)

获取 <origin>/.well-known/x402,根据文档自身公布的 payTo 验证其签名卡片,并报告已固定的密钥是否发生变化。返回 { ok, origin, payTo, keyId, signedAt, expiresAt, warning?, attestation, keyChanged, endpoints: [{resource, amount}] }。opts.fetchFn(注入 fetch)、 opts.pinnedKey({kid} 或 {kid,x,y})、opts.throwOnError。keyChanged 是 明确的密钥轮换信号。

verifyChallenge(challenge, attestation, opts?)

将 402 挑战与签名卡片绑定。challenge 是解码后的 402 声明({ resource: { url }, accepts: [{ payTo, maxAmountRequired }] }) ——使用 JSON.parse(Buffer.from(hdr, "base64").toString("utf8")) 解码 base64 PAYMENT-REQUIRED 标头。路由根据 resource.url 推导。返回 verifyAttestation 的结果。

ATTESTATION_EXTENSION — "x-sendcheck-attestation",签名区块在 402 挑战的 extensions 映射中使用的扩展名。
canonicalJson(value) — 类似 RFC-8785 的规范 JSON(递归排序键)——导出供任何重新实现签名器的人使用。
SendCheckVerifyError — 非有效结果时抛出;err.result 包含完整结果对象。

通俗解释这个端点

GET https://api.pennyforge.org/validate?address=0x…
→ 200 { "valid": true, "status": "valid", "message": "Valid EIP-55 checksum.",
        "normalized": "0x…" }

免费。无需密钥。无需账户。输入 JSON,输出 JSON。付费的同类端点——POST /check ($0.01,一条链:钱包与合约对比、活动、余额、判定)和 POST /deep($0.05,全部五条链 + 错误网络检测)——使用 x402 (Base 上的 USDC)。机器可读文档: 同一主机上的 llms.txt 和 openapi.json。

由谁运营

SendCheck 是一家由个人运营的工作室(Pennyforge)。Worker 运行在 Cloudflare Workers 上;地址引擎采用 MIT 许可证并公开托管于 此处。如果免费端点将来迁移,你只需更改 opts.baseUrl。

许可证

MIT — 参见 LICENSE。

评论

支持 Markdown

第一次接触 MCP?

从协议是什么,到在客户端里装上第一个服务,这几条回答覆盖了大多数入门问题。

一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。