Skip to content

Provides JavaScript/TypeScript bindings for the official Rust ics23 crate, compiled to WebAssembly via wasm-bindgen and wasm-pack.

Notifications You must be signed in to change notification settings

helios-network/ics23.js

Repository files navigation

ics23.js

ICS23.js

Provides JavaScript/TypeScript bindings for the official Rust ics23 crate, compiled to WebAssembly via wasm-bindgen and wasm-pack. Offers a clean Node.js-ready API to verify membership or non-membership for single or batch proofs, build batch proofs, compress and decompress batch proofs, access default proof specs, and calculate existence roots.

This project follows the removal of the TypeScript implementation - see PR #353.

Build Status npm License: MIT

What is ICS-23?

ICS-23 is a cross-language standard for representing Merkle proofs over key-value stores. It defines a portable, unambiguous proof format that different data stores can emit and clients in different languages can verify. In the Cosmos ecosystem, it underpins light-client style verification and IBC, enabling proof of existence or non-existence of keys under a given state commitment (root). The standard targets lexicographically ordered, merklized stores (such as IAVL, Tendermint’s simple Merkle, and Sparse Merkle Trees) so new stores can be supported primarily through configuration rather than custom client code.

Installation

npm install @gldywn/ics23.js

Usage

Initialize once with await init(); before calling other functions. The spec must match the underlying store, use the provided default for your target.

Single proofs

import {
  init,
  defaultIavlSpec,
  verifyMembership,
  verifyNonMembership,
  calculateExistenceRoot,
} from '@gldywn/ics23.js';

// Initialize once
await init();

// Choose the spec that matches your underlying store (e.g. IAVL, Tendermint, SMT)
const spec = defaultIavlSpec();
// const spec = defaultTendermintSpec();
// const spec = defaultSmtSpec();

// ℹ️ Proof acquisition: see "Getting proofs" section below

// Verify membership (single proof)
const okMembership = verifyMembership({
  proof, // Uint8Array (protobuf-encoded CommitmentProof)
  spec,
  root,  // Uint8Array
  key,   // Uint8Array
  value, // Uint8Array
});

// Verify non-membership (single proof)
const okNonMembership = verifyNonMembership({
  proof, // Uint8Array (protobuf-encoded CommitmentProof)
  spec,
  root,
  key,
});

// Calculate existence root from a single ExistenceProof
const rootFromProof = calculateExistenceRoot(proof);

Batch proofs

import {
  buildBatchProof,
  verifyBatchMembership,
  verifyBatchNonMembership,
  compressBatchProof,
  decompressBatchProof,
} from '@gldywn/ics23.js';

// Build a batch proof from individual CommitmentProofs
const batch = buildBatchProof([proof1, proof2, proof3]);

// Verify membership (batch proof)
const okBatchMembership = verifyBatchMembership({
  proof: batch,
  spec,
  root,
  keys: [key1, key2],
  values: [value1, value2],
});

// Verify non-membership (batch proof)
const okBatchNonMembership = verifyBatchNonMembership({
  proof: batch,
  spec,
  root,
  keys: [absentKey1, absentKey2],
});

// Compress and decompress a batch proof
const compressed = compressBatchProof(batch);
const decompressed = decompressBatchProof(compressed);

Getting proofs

  • Use gRPC when verifying IBC state (client, connection, channel, packets). Endpoints return ibc.core.commitment.v1.MerkleProof, a container of ICS‑23 CommitmentProof entries you can pass as bytes. See proto: commitment.proto. Some methods: ibc.core.client.v1.Query/ClientState, ibc.core.connection.v1.Query/Connection, ibc.core.channel.v1.Query/Channel, ibc.core.channel.v1.Query/PacketCommitment.
  • Use CometBFT RPC for arbitrary module KV keys: call /abci_query?prove=true (e.g., path=/store/<store>/key, data=<key bytes>, height=H), then convert proofOps to an ICS‑23 CommitmentProof (see conversion in ibc‑go: utils.go).

When you need to verify many proofs, batch client‑side before verification with buildBatchProof.

Development

Prerequisites

  • Node.js v22.16+
  • Rust toolchain 1.60+

Build

npm run build:wasm    # Build Rust WASM via `wasm-pack` (./rust/pkg)
npm run build:ts      # Build TypeScript bundle via `tsup` (./dist)
npm run build         # Build WASM then TypeScript bundle

Test

npm run test          # Run unit tests via `jest`
npm run test:coverage # Run unit tests via `jest` and output coverage report

License

Licensed under the Apache License, Version 2.0. See LICENSE for details.