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

@lucid-evolution/uplc

v0.5.3

Published

## 1. Enter Development Environment

Readme

Development Environment Setup

1. Enter Development Environment

To start working in the development environment, run the following command:

nix develop

2. Build the Rust Project & Generate WASM Files

Before continuing, please note that this step is not part of the CI process. You'll need to run it locally to build the Rust project and generate the required WASM files:

pnpm build-local

The browser builds are made with wasm-pack. The Node.js builds need wasm-bindgen's --experimental-reset-state-function, which wasm-pack cannot pass, so scripts/build-node.sh runs cargo, the wasm-bindgen CLI and wasm-opt itself: both must be on the PATH, with the wasm-bindgen CLI at the version of wasm-bindgen in rust/Cargo.lock (cargo install wasm-bindgen-cli --version <version>).

3. Build the UPLC Package

Once you've completed the previous step, you can build the UPLC package by running:

pnpm build

Speed and size builds

The package ships two builds of the evaluator:

  • speed (-O3, ~1.93 MB wasm): faster script evaluation.
  • size (-Oz, ~1.03 MB wasm): smaller download.

@lucid-evolution/uplc resolves to the speed build on Node, Bun and Deno, and to the size build in browser bundles and edge runtimes (browser, worker, workerd and edge-light export conditions). To pick a variant explicitly, import @lucid-evolution/uplc/speed or @lucid-evolution/uplc/size.

Recovering from a wasm trap

On Node.js (the default export condition), the bindings recover from a wasm trap. A trap or a stack overflow inside wasm leaves the instance unable to run anything after it, so after any binding throws, the next call first replaces the instance with a fresh one, and the error itself is rethrown unchanged. A result returned before the replacement throws when read afterwards, and freeing it, explicitly or by garbage collection, does not touch the new instance.

The browser, worker, workerd and edge-light builds do not recover: a bundler instantiates their wasm once, and wasm-bindgen cannot replace that instance. After a trap there, load the package again (for example in a new worker).

Evaluating a program

eval_program_raw evaluates a UPLC program applied to Data arguments, outside of any transaction. The caller builds whatever arguments the program expects, including its script context.

import { eval_program_raw } from "@lucid-evolution/uplc";

const result = eval_program_raw(
  programFlat, // Uint8Array: the program, flat-encoded without a CBOR wrapper
  [datum, redeemer, context], // Uint8Array[]: each argument as CBOR-encoded Data
  3, // Plutus version: 1, 2 or 3
  11, // protocol major version: 5 to 11
  costModel, // BigInt64Array: every cost model parameter for this Plutus version
  10_000_000_000n, // CPU budget
  14_000_000n, // memory budget
  true, // charge every step, and stop as soon as the budget runs out
);

result.ok; // whether the program succeeded (for Plutus V3, returned unit)
result.error_kind; // 0 ok, 1 over budget, 2 failed, 3 Plutus V3 result not unit
result.cpu; // bigint
result.mem; // bigint
result.logs; // string[]: the program's traces

With false as the last argument, steps are charged and the budget is checked every 200 steps as the ledger does. That only changes the cost reported for a program that fails, as the ledger does not charge the steps it took since the budget was last checked; the Haskell evaluator reports the same cost. It throws only when the inputs are malformed or unsupported.

Evaluating a builtin

eval_builtin_raw evaluates one builtin applied to constant arguments as the evaluator does for a Plutus V3 script at a protocol version (9 to 12), for callers that step through UPLC themselves.

import {
  BuiltinErrorKind,
  BuiltinValueKind,
  eval_builtin_raw,
} from "@lucid-evolution/uplc";

const result = eval_builtin_raw(
  0, // the builtin's flat tag: 0 is addInteger
  [one, two], // Uint8Array[]: each argument, encoded as its kind says
  Uint8Array.of(BuiltinValueKind.Flat, BuiltinValueKind.Flat),
  11, // protocol major version: 9 to 12
);

result.ok; // whether the builtin returned a value
result.error_kind; // a BuiltinErrorKind: Ok, NotAvailable, RejectedArguments or Failed
result.result_kind; // a BuiltinValueKind
result.result; // Uint8Array: the value, encoded as result_kind says
result.cpu; // bigint
result.mem; // bigint
result.error; // the evaluator's message when the builtin did not return a value

A Flat value is a flat-encoded (program 1.1.0 (con …)). Flat cannot encode BLS12-381 points, so a point crosses as its compressed bytes (G1, G2), and a list or array of points as the compressed points one after the other (G1List, G2List, G1Array, G2Array). The Miller-loop builtins (68 to 70) are not supported. cpu and mem are the builtin's charge under Plutus' default Plutus V3 cost model for the protocol version, excluding the machine's per-step costs; they are 0 when the builtin is not available or rejects its arguments, as the machine fails before costing it. It throws only when the inputs are malformed or unsupported.

uplc_build_info() returns JSON that describes the build: the uplc crate it was built from, the latest protocol version it supports, each Plutus version's cost model length, a digest of what a fixed set of programs evaluate to, and whether those programs give the expected results ("selfTest": "pass").

Tests

pnpm test

test/fixtures/builtins.json holds builtin applications with the outcome and cost the evaluator gives them. It is generated by the crate's tests (packages/uplc/rust/src/builtin/tests.rs), which check each one against the machine; rerun cargo test with UPDATE_BUILTIN_FIXTURE=1 after changing the cases.

test/fixtures/programs.json holds programs with their outcome and cost under Plutus V3 and protocol version 11, as given by the Haskell evaluator (plutus-core 1.71).