
Security News
Happy Birthday, Shai-Hulud
It has been one year since Shai-Hulud made its first appearance on npm.
@payperbyte/sdk
Advanced tools
PayPerByte TypeScript SDK for the BYTE Library — cryptographically attested, provenance-verifiable data for AI agents (proves who signed the exact bytes, not data correctness). No token; direct-allowance USDC settlement on Arbitrum.
TypeScript SDK for PayPerByte (the BYTE Library) — the cryptographically attested, provenance-verifiable data layer for AI agents. Discover first-party feeds, subscribe, stream payloads, and verify every payload against its on-chain EIP-712 attestation (provenance + tamper-evidence — who signed these exact bytes — not a correctness guarantee). No token; USDC settlement on Arbitrum.
npm install @payperbyte/sdk
import {
ByteClient,
Subscriber,
Mercat,
verifyPayload,
ARBITRUM_SEPOLIA,
} from "@payperbyte/sdk";
// `network` is a NetworkConfig object (ARBITRUM_SEPOLIA / LOCAL_ANVIL),
// not a string. RPC URL + contract addresses come from that config.
const client = new ByteClient({ network: ARBITRUM_SEPOLIA });
// Discover publishers and their feeds via the indexer (Mercat).
const mercat = new Mercat(ARBITRUM_SEPOLIA.indexerUrl);
const publishers = await mercat.search({ topic: "eth-price" });
// Subscribe to a data feed — r2 DIRECT-ALLOWANCE model. There is NO escrow.
// subscribe(publisher, allowanceUsdc) does two on-chain things:
// 1. dataRegistry.subscribe(publisher) — the social-registry flag, and
// 2. usdc.approve(dataStream, cap) — the spending cap the publisher's
// streamData/streamBroadcast transferFrom-pulls each per-message fee from.
const subscriber = new Subscriber({
network: ARBITRUM_SEPOLIA,
privateKey: "0x...",
});
await subscriber.subscribe(publishers[0].address, 10.0); // $10 allowance cap
// Verify received bytes against the publisher's on-chain attested hash.
// Signature: verifyPayload(payloadBytes, expectedHash).
// Throws HashMismatchError if the bytes don't match what was attested.
verifyPayload(receivedBytes, message.payloadHash);
For one-off, pay-per-call access there is the keyless x402 GatewayClient. A
wallet signs the payment (gasless EIP-3009 transferWithAuthorization — the
facilitator broadcasts and pays gas). There is no API key: the wallet is the
credential. The @x402/core + @x402/evm packages are optional peer deps,
loaded only if you use the gateway.
import { privateKeyToAccount } from "viem/accounts";
import { createPublicClient, http } from "viem";
import { arbitrumSepolia } from "viem/chains";
import { GatewayClient } from "@payperbyte/sdk";
const account = privateKeyToAccount(process.env.AGENT_PRIVATE_KEY as `0x${string}`);
const publicClient = createPublicClient({ chain: arbitrumSepolia, transport: http() });
// Defaults to https://x402.payperbyte.io; pass baseUrl for local dev (:3402).
const gw = new GatewayClient({ signer: account, publicClient });
// Discover the catalog (free) — each feed carries its priceAtomic.
const { feeds } = await gw.discover();
// Pay-per-call a GET feed: unpaid → 402 → wallet signs USDC → retry → data.
const { data, settlement, disclaimerCategory } = await gw.fetchFeed("crypto-top100");
console.log(settlement?.transaction); // on-chain settlement tx hash
// POST oracle (fact-oracle): subscriber_address must ALREADY be a registered,
// allowance-granting on-chain subscriber (a prior Subscriber.subscribe) — the
// answer is broadcast on-chain and its fee is pulled from that allowance.
await gw.fetchFeed("fact-oracle", {
body: { question: "…", subscriber_address: account.address },
});
Two distinct USDC flows: the on-chain direct-allowance
approve(dataStream)at subscribe time (Subscriber) is independent of the x402 EIP-3009 sign at fetch time (GatewayClient).fact-oracleneeds the subscriber registered with a live DataStream allowance first.
The Foreseal Kit is the SDK's headline primitive: sign, verify, and read a publisher's quality score — so any agent can produce and fully verify a PayPerByte PayloadAttestation without us in the request path.
The legacy verifyPayload() checks only the hash (keccak256(bytes) == attestedHash).
The Foreseal Kit adds the missing signer leg: it recovers the EIP-712 attestation
signer and confirms it is the publisher the catalog says it is. A single Verdict
composes both legs.
import {
signAttestation,
verifyAttestation,
verifyFromEvent,
verifyFromGatewayResponse,
getPQS,
ARBITRUM_SEPOLIA,
} from "@payperbyte/sdk";
// 1) verify — hash AND signer recovery, before acting on any bytes.
const verdict = await verifyAttestation({
payloadBytes: receivedBytes, // the bytes you're about to act on
attestation: event.attestation, // 65-byte sig (on-chain event OR gateway header)
expectedPublisher: publisherAddr, // who the catalog/registry says the publisher is
payloadHash: event.payloadHash,
payloadLength: event.payloadLength,
deadline: event.attestationDeadline,
net: ARBITRUM_SEPOLIA,
});
// Verdict: { verified, hashMatch, signerMatch, recovered, expired, reason }
if (!verdict.verified) refuse(verdict.reason);
// Wrappers for the two on-the-wire anchors (same EIP-712 domain):
await verifyFromEvent(event, receivedBytes, ARBITRUM_SEPOLIA); // on-chain
await verifyFromGatewayResponse(body, xByteAttestationHeader, ARBITRUM_SEPOLIA, // gateway
knownGatewayAttester);
// 2) sign — produce an attestation (any viem WalletClient/Account).
const sig = await signAttestation(
{ publisher: account.address, payloadHash, payloadLength, deadline },
account,
ARBITRUM_SEPOLIA,
);
// 3) getPQS — read the indexer delivery-quality composite (BPS 0-10000).
const pqs = await getPQS(publisherAddr, ARBITRUM_SEPOLIA.indexerUrl);
// { composite, dispute, retention, freshness, revenueQuality, asOf }
// composite === null → publisher not yet scored.
Verdict rules (these are the contract):
| Case | hashMatch | signerMatch | verified |
|---|---|---|---|
| Known-good | true | true | true |
| Tampered bytes | false | — | false |
| Wrong/forged signer | true | false | false |
| Empty/missing attestation | (computed) | null | false — fail-closed |
"0x") or null
attestation yields signerMatch=null and verified=false. We never "pass on the
hash alone" — provenance is unproven without the publisher's signature.now+300s deadline elapses on
every aged feed. verifyAttestation sets expired=true but does not fail
verified on the immutable on-chain anchor — staleness belongs to a freshness
axis, not the provenance verdict. The caller decides policy.getPQS is off-chain, advisory, and may
be absent.BYTE Library EIP-712 domain literal is consensus-critical and identical
across the on-chain contract, gateway, MCP, and SDK. It is never renamed.approve(dataStream), no escrow)keccak256(bytes) against the on-chain hash before acting on the data| Network | Chain ID | Status |
|---|---|---|
| Arbitrum Sepolia | 421614 | Live (testnet) |
| Arbitrum One | 42161 | Planned (mainnet, audit-gated) |
PayPerByte runs on the BYTE Library — a lean 3-contract core. No token; all settlement is in USDC via a direct-allowance model (the subscriber approves DataStream; the publisher transferFrom-pulls each per-message fee — there is no escrow contract). Each payload carries an EIP-712 PayloadAttestation so subscribers can confirm exactly what they received and from whom.
| Contract | Role |
|---|---|
| DataRegistryLib | Publisher registration, feed/subscriber discovery |
| DataStreamLib | Per-call / per-byte payload delivery + settlement |
| SchemaRegistry | Feed schema + methodology references |
Contract addresses are resolved per-network by the SDK (ARBITRUM_SEPOLIA, LOCAL_ANVIL).
ByteClient — low-level client holding the viem clients and contract instances (used by Publisher/Subscriber)Publisher — register a feed, publish data, sign EIP-712 PayloadAttestationsSubscriber — subscribe, receive payloads, stream eventsverifyPayload / verifyEventPayload / fetchAndVerify — subscriber-side hash-only payload verification against on-chain attestationssignAttestation, verifyAttestation / verify (hash and signer recovery), verifyFromEvent, verifyFromGatewayResponse, getPQSMercat — feed search and discovery (connects to the indexer API)GatewayClient — keyless x402 pay-per-call client (a wallet signs, not an API key); discover, discoverResources, fetchFeedMIT
FAQs
PayPerByte TypeScript SDK — cryptographically attested, provenance-verifiable data for AI agents: proves which publisher signed the exact bytes (authenticity + tamper-evidence, not data correctness). Pay-per-call via x402 in USDC on Base mainnet; every pa
The npm package @payperbyte/sdk receives a total of 38 weekly downloads. As such, @payperbyte/sdk popularity was classified as not popular.
We found that @payperbyte/sdk demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.

Security News
It has been one year since Shai-Hulud made its first appearance on npm.

Research
/Security News
Operators behind PolinRider used a compromised GitHub account to plant malware in four development versions of a Packagist package with 700,000+ downloads.

Security News
GitHub Actions now supports cache-mode, a least-privilege control on the Actions cache aimed at the cache poisoning technique behind recent compromises.