A signed, pay-per-call sanctions verdict from nsgoods, embedded and cryptographically verified inside a Walpulse wallet-analysis report. Published with Walpulse's permission.
Walpulse runs on-chain wallet analysis. When a report needs a sanctions check, a server-side edge function calls the nsgoods Sanctions Screen endpoint, pays for the single call over the x402 protocol, verifies the response signature, and renders the resulting verdict inside the report. Because the verdict is signed, Walpulse's UI can display SIGNATURE VERIFIED YES — the reader is not trusting Walpulse's word or ours, they are checking a signature.
402 Payment Required; the client pays the exact amount in USDC and retries.The snippet below is a representative minimal example written by nsgoods to illustrate the call, the payment, and — the part that matters — the signature check. It is not Walpulse's code and does not describe their internals; any x402-capable HTTP client works in place of x402Fetch.
import { recoverMessageAddress, hashMessage } from "npm:viem";
// The signer that nsgoods publishes for the sanctions family, pinned in the
// signed proof manifest at https://x402.nsgoods.org/proof/index.json
const PINNED_SIGNER = "0x57fF0F084Cba33e6761503f90eEF0Da9F159350c";
// x402Fetch: any wrapper that, on a 402, pays the quoted USDC amount and retries.
// (Base or Solana rail; the amount and payTo come from the 402 challenge itself.)
async function screen(address: string) {
const url = `https://sanctions.nsgoods.org/screen?address=${address}&chain=ethereum`;
const res = await x402Fetch(url); // handles 402 -> pay -> 200
const body = await res.json();
// Verify the signature: strip the two signature fields, canonicalise the rest
// exactly as the signer did (sorted keys, compact separators), then EIP-191 recover.
const { signature, signed_by, ...rest } = body;
const canonical = canonicalJson(rest); // JSON.stringify with sorted keys, no spaces
const recovered = await recoverMessageAddress({ message: canonical, signature });
if (recovered.toLowerCase() !== PINNED_SIGNER.toLowerCase()) {
throw new Error("signature verification failed"); // never render an unverified verdict
}
return body; // verdict is now trustworthy: render it
}
// Deterministic canonical JSON: object keys sorted recursively, compact separators.
function canonicalJson(v: unknown): string {
if (Array.isArray(v)) return "[" + v.map(canonicalJson).join(",") + "]";
if (v && typeof v === "object")
return "{" + Object.keys(v as object).sort()
.map(k => JSON.stringify(k) + ":" + canonicalJson((v as any)[k])).join(",") + "}";
return JSON.stringify(v);
}
nsgoods exposes two sanctions endpoints. They share the same signer, the same signature scheme, and the same dual-rail payment (USDC on Base or Solana). They differ only in list coverage and price, so a report can route per call.
| Endpoint | Coverage | Price / call | When to use |
|---|---|---|---|
/screen |
OFAC SDN exact-address, all chains | $0.005 | The default check: is this exact address on the U.S. Treasury SDN list. |
/screen-multi |
Four lists: OFAC · UN · EU · UK (HMT/OFSI), each with its own version date | $0.01 | When a report needs multi-jurisdiction coverage in one signed call. |
The example below is taken from the public /screen-multi/preview — a fixed demo address, never client data. The headline verdict keeps the exact /screen semantics (deny only on an OFAC SDN match); the additive lists[] block reports each list separately, with matched/clear and that list's version date, all inside the one signed body.
| List | Result | List version date | Source note |
|---|---|---|---|
| OFAC (US SDN) | matched | 2026-09-04 | — |
| UN Consolidated | clear | 2026-09-07 | — |
| EU FSF | clear | 2026-08-05 | official (public token) |
| UK OFSI (HMT) | clear | 03/06/2026 | — |
Two principles are worth calling out:
list_health entry; if a feed cannot be reached, its result is reported as unavailable with a note — the endpoint never lets a broken feed masquerade as a clean result.Every verdict is signed with an EIP-191 personal-sign over the canonical JSON body. The signer address for the sanctions family is published, not asserted: it is pinned in the signed proof manifest at x402.nsgoods.org/proof/index.json as 0x57fF0F084Cba33e6761503f90eEF0Da9F159350c.
To verify any response independently:
signature and signed_by fields (and, for a preview response, the four preview-only fields).A verdict that does not recover to the pinned signer should never be rendered. That single check is what turns "a vendor said clean" into "a signed statement anyone can verify."
Each list is backed by a public, hash-chained log of its versions, so a claim like "checked against the OFAC list of 2026-09-04" can be verified independently rather than taken on trust:
Update 29 September 2026: the UK leg now uses the UK Sanctions List (FCDO). The OFSI Consolidated List closed on 28 January 2026.