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

@verify-network/protocol

v0.2.0

Published

The Verify Network VRF protocol off-chain: ECVRF prove and verify, request ids, fulfillment typed data, router events and fees, the router watch and its request tracker, and the direct-request client.

Readme

@verify-network/protocol

The off-chain half of the Verify Network VRF protocol. Use it to verify a fulfillment the router delivered, to sign and send a direct request to a node, and to compute request ids, fees, and the typed data the router checks. Every function mirrors the router byte for byte.

Install

npm install @verify-network/protocol viem effect

viem (^2.56.3) and effect (^4.0.0) are peer dependencies. Node 22 or later.

Entry points

| Import | Contents | | -------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------- | | @verify-network/protocol | Everything below, plus the direct-request client (DirectClient), the router quote (Quote), the router watch and its request tracker, and the schemas | | @verify-network/protocol/ecvrf | ECVRF-SECP256K1-SHA256-TAI (RFC 9381): prove, verify, deriveRandomness, proofCommitment, isSentinel, isFulfillable | | @verify-network/protocol/event | The router's RandomnessRequested and RandomnessFulfilled events and their decoders | | @verify-network/protocol/fee | The reservation, the charge, and the settlement, as the router computes them | | @verify-network/protocol/fulfillment | The EIP-712 typed data an enclave signs, and its digest | | @verify-network/protocol/request | requestId, the stale delay, and the callback data limit |

The subpath entries do not load Effect. Import from them in a browser bundle. The root entry loads Effect for its schemas, the quote, the router watch and its request tracker, and the direct-request client.

Verify a fulfillment

A fulfillment is valid when three things hold. The enclave signature recovers to the request's fulfiller. The proof verifies under that node's key for the request id. The randomness is the one the proof derives.

In a browser, import the same names from /ecvrf, /event, and /fulfillment instead of the root.

import {
  decodeRandomnessFulfilled,
  decodeRandomnessRequested,
  deriveRandomness,
  fulfillmentDigest,
  isFulfillable,
  isSentinel,
  proofCommitment,
  randomnessFulfilledEvent,
  randomnessRequestedEvent,
  verify,
} from "@verify-network/protocol";
import {
  isAddressEqual,
  parseAbi,
  recoverAddress,
  type Address,
  type Hex,
  type PublicClient,
} from "viem";

const nodes = parseAbi(["function publicKeyOf(address node) view returns (uint256[2])"]);

export const checkFulfillment = async ({
  publicClient,
  router,
  requestId,
  fromBlock,
}: {
  publicClient: PublicClient;
  router: Address;
  requestId: Hex;
  fromBlock: bigint;
}) => {
  const [requested] = await publicClient.getLogs({
    address: router,
    event: randomnessRequestedEvent,
    args: { requestId },
    fromBlock,
  });
  const [fulfilled] = await publicClient.getLogs({
    address: router,
    event: randomnessFulfilledEvent,
    args: { requestId },
    fromBlock,
  });
  if (requested === undefined || fulfilled === undefined) throw new Error("not fulfilled yet");

  const { request } = decodeRandomnessRequested(requested);
  const { proof, randomness, enclaveSignature } = decodeRandomnessFulfilled(fulfilled);
  const chainId = await publicClient.getChainId();
  const publicKey = await publicClient.readContract({
    address: router,
    abi: nodes,
    functionName: "publicKeyOf",
    args: [request.fulfiller],
  });

  const signer = await recoverAddress({
    hash: fulfillmentDigest({
      chainId,
      router,
      requestId,
      proofCommitment: proofCommitment(proof),
    }),
    signature: enclaveSignature,
  });
  const proven = isSentinel(proof)
    ? !isFulfillable(publicKey, requestId)
    : verify({ publicKey, proof, alpha: requestId });
  return (
    isAddressEqual(signer, request.fulfiller) && proven && deriveRandomness(proof) === randomness
  );
};

A fulfillment that fails this check is evidence for challengeFulfillment(request, proof, enclaveSignature) on the router. Anyone may send it while the node still holds stake.

Send a direct request

A direct request skips the consumer's own transaction. A signer signs an authorization, posts it to one node, and the node lands the request and its fulfillment in one transaction. The signer's balance on the router pays.

DirectClient finds the fastest serving node on the router, signs, posts, and waits until the fulfillment lands. Its methods return Effects. run turns one into a promise, so a caller needs no Effect code.

import { DirectClient, run } from "@verify-network/protocol";
import { createPublicClient, http, toHex, type Chain } from "viem";
import { privateKeyToAccount } from "viem/accounts";
import { base } from "viem/chains";

// Widened to `Chain`: `DirectClient` takes a `PublicClient` of any chain.
const publicClient = createPublicClient({ chain: base as Chain, transport: http() });
const client = await run(
  DirectClient.connect({
    publicClient,
    chainId: base.id,
    router: "0x…",
    account: privateKeyToAccount("0x…"), // a session key or a backend key, funded on the router
  }),
);

const result = await run(client.request({ consumer: "0x…", callbackData: toHex("round-1") }));
if (result._tag === "Landed") {
  console.log(result.requestId, result.randomness, result.hash);
} else {
  // NotLanded: the deadline passed on the chain's clock and nothing landed. Fall back to an on-chain request.
}

The consumer contract implements IDirectVrfReceiver from @verify-network/contracts. The signer is passed to its callback, so the consumer decides which signers it accepts.

To sign an authorization yourself, use signDirectRequest and directRequestId. validateEndpoint checks an endpoint read from the chain before you connect to it.

License

MIT