SendCheck — EVM address verification (x402) について
SendCheck は、x402 クライアントの支払い前に EVM アドレスを検査する、依存関係のないクライアントです。無料のチェックサム事前確認に加え、署名付きサービスカードと支払いチャレンジを検証します。
主な機能
- 01無料の EVM アドレス事前確認
- 02オフラインでのアドレス形式検証
- 03ES256 署名カードの検証
- 04チャレンジのアドレスと価格確認
- 05固定鍵のローテーション検出
活用シーン
- 01支払い前に形式不正のアドレスを拒否
- 02署名済み条件に照らした x402 チャレンジの確認
- 03サービス署名鍵の変更検出
MCP 対応
このパッケージは x402 API クライアントであり、MCP サーバーではありません。README に MCP 対応の記載はありません。
設定
リモートサーバーはインストール不要です。クライアントを選んで設定をコピーするか、ワンクリックで導入できます。
https://api.pennyforge.org/mcpclaude mcp add --transport http org-pennyforge-api-sendcheck https://api.pennyforge.org/mcp{"mcpServers":{"org-pennyforge-api-sendcheck":{"type":"http","url":"https://api.pennyforge.org/mcp"}}}Cursor で開く{"servers":{"org-pennyforge-api-sendcheck":{"type":"http","url":"https://api.pennyforge.org/mcp"}}}VS Code で開く{"mcpServers":{"org-pennyforge-api-sendcheck":{"type":"http","url":"https://api.pennyforge.org/mcp"}}}{"mcpServers":{"org-pennyforge-api-sendcheck":{"serverUrl":"https://api.pennyforge.org/mcp"}}}コマンドはターミナルで実行し、JSON は各クライアントの MCP 設定に貼り付けて再起動します。認可が必要なサーバーは初回接続時にログインを求めます。
ツール
3| パラメーター | 型 | 必須 | 説明 |
|---|---|---|---|
| address | string | はい | EVM アドレス。0x + 40 桁の 16 進数(大文字・小文字どちらも可) |
詳細
sendcheck-verify
支払う前に検証しましょう。 無料の
GET /validate
事前チェック用の、依存関係ゼロのクライアントです。SendCheck x402 API を利用して、
入力ミスや不一致、改ざんのある決済先アドレスへの支払いにエージェントが署名するのを防ぐ、10 行のガードです。
x402 クライアントがサービスに支払う際、サービスから通知された決済先アドレスに支払います。たった 1 文字でも誤りがあれば(大文字と小文字の入れ替え、数字の欠落、別のアドレスへの置き換えなど)、USDC は二度と戻ってこない場所へ送られてしまいます。/validate は無料で、API キーもアカウントも不要な事前チェックです。実際のお金を支払う前に、このアドレスは正しい形式で、大文字と小文字も正しく使われた EVM アドレスになっていますか?
v0.2.0 から、このパッケージはもう 1 つの機能を備えています。サービスの署名付きサービスカードを検証します。これは、payTo とルートごとの maxPrice に対する ES256 JWS で、ワーカーがデプロイのたびに再署名します。公開鍵を一度ピン留めしたクライアントは、支払い前にチャレンジの payTo を暗号学的に確認できます。これは、アドレスの変動を防ぐチェックのリファレンス実装です(アドレス変動に関する記事の「署名付きサービスカード」です)。
これが必要な理由
SendCheck の有料エンドポイントは、x402 経由で 0.01 ドル(1 つのチェーン)または 0.05 ドル(5 つすべてのチェーン)です。Base 上の USDC を使い、アカウントも API キーも必要ありません。しかし、「このアドレスは無効ではないか?」というチェックの多くは、チェーンのデータを必要としません。EIP-55 チェックサムだけで、最もよくある、最も損失の大きい失敗(入力ミス、文字の欠落、大文字と小文字の改ざん)を検出できます。そのため /validate は無料で、このパッケージを使えば 1 行で呼び出せます。
署名付きサービスカード(v0.2.0)
支払い前のアドレスチェックには抜け穴があります。クライアントが照合する「想定 payTo」は、通常、たった今取得した同じ検出用ドキュメントから得られるため、侵害されたサービスは独自の新しいアドレスに誘導できます。また、アドレスを頻繁にローテーションするサービスでは、チェックが終わる前に、記憶していたアドレスがすべて古くなってしまいます。
SendCheck は支払い情報に署名することで、この抜け穴を塞ぎます。ワーカーは安定した ES256(EC P-256)鍵を使って、デプロイのたびに決済先アドレスとルートごとの最大価格に署名し、次の 3 か所で署名済みブロック { jws, key } を提供します。
<origin>/.well-known/x402 → top-level "attestation"
<origin>/openapi.json → info["x-attestation"]
the 402 challenge itself → extensions["x-sendcheck-attestation"]
SendCheck は安定した鍵を使ってデプロイのたびに支払い情報に署名するため、その鍵を一度ピン留めしたクライアントは、支払い前に、支払いチャレンジ内のアドレスが SendCheck の署名したものであることを暗号学的に確認できます。初回の接続では、引き続き TOFU(初回利用時の信頼)が必要です。
この署名で得られるものは、再訪するステートフルなクライアントにおける鍵の継続性です。ワーカー、DNS、CDN が侵害されても支払い先を密かに変更できず、鍵のローテーションも明確に検知できるイベントになります。この署名で得られないものは(意図的に主張を控えています)、初回訪問時の真正性(これは TOFU です)、鍵をピン留めしていない一時的なエージェントの保護、署名済み 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 トークンを使用できます)。トークンをお持ちでない場合は、公開リポジトリからインストールしてください。
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 桁の 16 進数です。opts.baseUrl— API ホストを上書きします(デフォルト:稼働中の worker)。opts.fetchFn— fetch の実装を注入します(テスト/プロキシ用)。opts.throwOnError— デフォルトはtrueです。常に結果を受け取るにはfalseを指定します。
動作に関する注意:
0x+40 桁の 16 進数形式ですらない文字列は、ローカルの形式チェックで失敗し、リクエストを送信せずに例外をスローします(または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 秒先の時刻まで許容されます。30 日を超えて古い iat は有効ですが、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 }] })です。base64 エンコードされた PAYMENT-REQUIRED ヘッダーは、JSON.parse(Buffer.from(hdr, "base64").toString("utf8")) でデコードしてください。ルートは 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、1 つのチェーン:ウォレットとコントラクトの判定、アクティビティ、残高、判定結果)と POST /deep($0.05、5 つすべてのチェーン + ネットワーク違いの検出)では、x402(Base 上の USDC)を使用します。機械可読なドキュメントは、同じホスト上の
llms.txt と
openapi.json
です。
運営者
SendCheck は、1 人で運営するスタジオ(Pennyforge)です。worker は Cloudflare
Workers 上で稼働しています。アドレスエンジンは MIT ライセンスのオープンソースで、こちらから公開されています。無料エンドポイントの移転が発生した場合、変更が必要なのは opts.baseUrl だけです。
ライセンス
MIT — LICENSE を参照してください。
コメント
AI アプリケーションが外部のツールやデータソースに統一的な方法で接続するためのオープンなプロトコルです。クライアントはモデルとの対話を担い、MCP サーバーはツール・リソース・プロンプトテンプレートを提供します。標準メッセージでやり取りするため、1 つのサーバーを複数のクライアントで再利用できます。