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

@alea-drand/sdk

v0.2.0

Published

TypeScript SDK for Alea — drand BN254 randomness verification on Solana

Readme

@alea-drand/sdk

Verified drand randomness on Solana in one call.

v0.1.x is DEVNET only — mainnet deployment pending. Alea's program ID is cluster-agnostic; DEVNET_PROGRAM_ID and MAINNET_PROGRAM_ID point to the same bytes. Using a mainnet Connection before mainnet deploys fails at the Solana RPC layer ("program not found"). Read CAVEATS.md before production use.

Install

npm install @alea-drand/sdk @solana/web3.js @coral-xyz/anchor

@solana/web3.js and @coral-xyz/anchor are peer dependencies — consumers install them directly so your bundle has one copy of each (prevents class-identity issues with PublicKey instances across mismatched versions).

Requires Node 18+ and ESM. This package is ESM-only; use import, not require(). Works in browsers with any modern bundler (Vite, webpack 5, Next.js App Router, esbuild) — no polyfills needed.

Quick Start — Browser (user pays, via wallet-adapter)

import { getVerifiedRandomness } from "@alea-drand/sdk";
import { useWallet } from "@solana/wallet-adapter-react";
import { useConnection } from "@solana/wallet-adapter-react";

function RandomnessButton() {
  const { connection } = useConnection();
  const wallet = useWallet(); // WalletContextState

  async function draw() {
    // User approves a single popup. Returns 32 bytes of verified randomness.
    const randomness = await getVerifiedRandomness({
      connection,
      signer: wallet,
    });
    console.log(`Randomness: ${Buffer.from(randomness).toString("hex")}`);
  }

  return <button onClick={draw}>Draw</button>;
}

Quick Start — Server (developer pays, via Keypair)

import { getVerifiedRandomness } from "@alea-drand/sdk";
import { Keypair, Connection } from "@solana/web3.js";
import { readFileSync } from "node:fs";

const keypair = Keypair.fromSecretKey(
  new Uint8Array(JSON.parse(readFileSync(process.env.KEYPAIR_PATH!, "utf8"))),
);
const connection = new Connection("https://api.devnet.solana.com", "confirmed");

const randomness = await getVerifiedRandomness({
  connection,
  signer: keypair,
});
console.log(Buffer.from(randomness).toString("hex"));

Testing on Devnet

Before integrating into prod, run the SDK against live devnet:

# 1. Install the SDK
npm install @alea-drand/sdk @solana/web3.js @coral-xyz/anchor

# 2. Generate or load a Solana devnet keypair
solana-keygen new --outfile ~/.config/solana/alea-test.json

# 3. Fund it with devnet SOL
solana airdrop 1 ~/.config/solana/alea-test.json --url devnet
# Backup faucet if solana-labs is dry: 76 Devs Discord / LamportDAO

# 4. Run the quick-start above against devnet
# Expected: 32 bytes of randomness (hex) printed in under 10 seconds

Live devnet program: ALEAydzHd4cN2EWcdHKp4hehAE4B88b16gqVtVqsck2U.

API Reference

getVerifiedRandomness(options)

High-level entry point. Fetches a drand beacon, submits a Solana transaction, and returns 32 bytes of verified randomness.

async function getVerifiedRandomness(options: {
  connection: Connection;
  signer: Keypair | Wallet;         // Keypair (Node) or wallet-adapter WalletContextState
  programId?: PublicKey;            // defaults to DEVNET_PROGRAM_ID
  round?: bigint;                   // defaults to latest available round
  computeUnits?: number;            // defaults to 900_000
}): Promise<Uint8Array>             // 32 bytes

verifyDrandBeacon(args)

Lower-level IDL-based submission. Use when you have a round + signature fetched out-of-band.

async function verifyDrandBeacon(args: {
  connection: Connection;
  signer: Keypair | Wallet;
  round: bigint;                    // [1, 2^64-1]
  signature: Uint8Array;            // exactly 64 bytes, G1 uncompressed x||y
  programId?: PublicKey;
  computeUnits?: number;
}): Promise<Uint8Array>             // 32 bytes

verifyDrandBeaconWithMeta(args) — since 0.2.0

Same as verifyDrandBeacon but returns the full tx metadata alongside the randomness. Use when you need to link to Explorer, report compute units / fees, or surface the slot to end users.

type VerifyMeta = {
  randomness: Uint8Array;           // 32 bytes
  tx: string;                       // base58 Solana tx signature
  slot: number;                     // confirmed-commitment slot
  computeUnitsUsed: number;         // from tx meta.computeUnitsConsumed
  costLamports: number;             // from tx meta.fee
};

async function verifyDrandBeaconWithMeta(args: {
  connection: Connection;
  signer: Keypair | Wallet;
  round: bigint;
  signature: Uint8Array;
  programId?: PublicKey;
  computeUnits?: number;
  signal?: AbortSignal;
  skipPreflight?: boolean;
}): Promise<VerifyMeta>

getVerifiedRandomnessWithMeta(options) — since 0.2.0

One-shot variant of getVerifiedRandomness that returns the drand round + drand signature + full on-chain meta in a single call. Used by the alea.so public relayer; useful anywhere you want to display end-to-end provenance.

async function getVerifiedRandomnessWithMeta(options: {
  connection: Connection;
  signer: Keypair | Wallet;
  programId?: PublicKey;
  round?: bigint;
  computeUnits?: number;
  signal?: AbortSignal;
  skipPreflight?: boolean;
}): Promise<VerifyMeta & {
  round: bigint;                    // drand round that was verified
  signature: Uint8Array;            // drand sig (G1, 64 bytes)
}>

fetchBeacon(round?)

Fetches a drand beacon without Solana interaction. Uses 5-endpoint fallback with 3 retries, validates returned round matches requested.

WARNING: Returns UNVERIFIED data from the drand API. Use getVerifiedRandomness() for trustless randomness.

async function fetchBeacon(round?: bigint): Promise<{
  round: bigint;
  signature: Uint8Array;
  unverifiedRandomness: string;  // hex — NOT on-chain verified
}>

getCurrentRound() / getRoundAt(timestamp)

Compute drand round numbers (canonical bigint). getCurrentRound uses Date.now().

isRoundRecent(round, config, clock, maxAgeSeconds)

Pure function — symmetric with Rust CPI is_round_recent. Call before getVerifiedRandomness to cheaply reject obvious replay attempts.

Future rounds (roundTs > clock.unixTimestamp) return true — this matches Rust's saturating-sub semantics so the TS and Rust checks agree at the round-emission edge.

function isRoundRecent(
  round: bigint,
  config: { genesisTime: bigint; period: bigint },
  clock: { unixTimestamp: bigint },
  maxAgeSeconds: bigint,
): boolean

createVerifyInstruction(options)

Raw instruction builder for advanced use (multi-ix composition, versioned transactions). Use verifyDrandBeacon for the common path.

function createVerifyInstruction(options: {
  round: bigint;
  signature: Uint8Array;
  payer: PublicKey;                 // signer — included in keys automatically
  programId?: PublicKey;
}): TransactionInstruction

getConfigAddress(programId?)

Derives the Alea Config PDA address (seeds [b"config"]).

Constants

DRAND_CHAIN_HASH    // evmnet chain hash (hex, 64 chars)
DRAND_GENESIS_TIME  // 1727521075 (Unix seconds)
DRAND_PERIOD        // 3 (seconds per drand round)
DRAND_ENDPOINTS     // 5 fallback URLs (can be replaced for custom trust)
DEVNET_PROGRAM_ID   // ALEAydzHd4cN2EWcdHKp4hehAE4B88b16gqVtVqsck2U
MAINNET_PROGRAM_ID  // === DEVNET_PROGRAM_ID; cluster comes from your Connection

AleaError

class AleaError extends Error {
  readonly code: number;
}

Error Codes

On-chain errors (from alea-verifier) + SDK-side errors (6100+):

| Code | Name | Meaning | |------|------|---------| | 2001 | ConstraintHasOne | Signer is not the config authority (Anchor framework) | | 3010 | AccountNotSigner | Account passed without signature (Anchor framework) | | 6000 | InvalidSignature | BLS pairing check failed — wrong sig for this round | | 6001 | InvalidG1Point | Signature bytes are not on the BN254 G1 curve | | 6002 | RoundZero | Round must be > 0 (drand genesis sentinel) | | 6003 | InvalidFieldElement | Reserved (unreachable in v1) | | 6004 | NoSquareRoot | SVDW exhausted candidates (infrastructure failure) | | 6005 | InvalidG2Point | Reserved (unreachable) | | 6006 | PairingError | alt_bn128_pairing syscall failed (infrastructure) | | 6007 | WrongChainHash | Config.chain_hash does not match evmnet | | 6008 | WrongPubkey | Config.pubkey_g2 does not match evmnet (or alea-sdk owner check) | | 6009 | ReturnDataMissing | Reserved (unreachable under ADR 0030) | | 6010 | InvalidGenesisTime | Config.genesis_time mismatch | | 6011 | InvalidPeriod | Config.period mismatch | | 6012 | UnauthorizedInit | initialize signer is not the upgrade authority | | 6100 | DrandFetchFailed | SDK — all drand endpoints failed after retries | | 6101 | DrandRoundMismatch | SDK — endpoint returned a different round than requested (possible compromise) | | 6102 | InvalidInput | SDK — input validation failed at SDK boundary |

The ERRORS map is exported and frozen at module load (Object.freeze + Readonly<Record>).

Consumer Responsibility

This SDK is for off-chain consumers. If you're building an on-chain program that CPIs to Alea, see the alea-sdk Rust crate README for the mandatory seeds::program + is_round_recent constraints. Omitting either ships an exploitable program.

Program IDs

| Network | Program ID | |---------|-----------| | Devnet | ALEAydzHd4cN2EWcdHKp4hehAE4B88b16gqVtVqsck2U | | Mainnet | Same vanity ID; program not yet deployed on mainnet. Mainnet Connection will fail at the RPC layer with "program not found" until deploy. |

Zero Telemetry

@alea-drand/sdk sends no analytics, no telemetry, no phone-home. Your only network calls are:

  • Drand API endpoints (for beacon fetch, 5 URLs with fallback — fully replaceable via DRAND_ENDPOINTS override)
  • Solana RPC endpoint of your choice (passed in as connection)

Nothing else. Verify by inspecting src/client.ts and src/drand.ts.

How to Verify This Package

Every release carries an npm provenance attestation signed by Sigstore + the GitHub Actions publish workflow. Confirm before use:

npm audit signatures

Or visit @alea-drand/sdk on npm and look for the green "Provenance" badge. No badge → do not install.

Community & Support

License

Apache 2.0 — see LICENSE.