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

@quantus-network/wasm

v0.1.2

Published

Quantus account derivation and ML-DSA-87 extrinsic signing, compiled from the chain's own crypto crates to WebAssembly.

Readme

@quantus-network/wasm

Quantus account derivation and ML-DSA-87 transaction signing for JavaScript/TypeScript.

This package is compiled to WebAssembly from the Quantus chain's own crypto crates — addresses come from qp-poseidon-core (Poseidon2 over Goldilocks) and signatures from qp-rusty-crystals-dilithium (ML-DSA-87), the exact code the runtime uses. Nothing about address derivation or extrinsic encoding is re-implemented in JS, so there is no second implementation to drift out of sync with the chain.

  • account(seed) → ML-DSA-87 keypair → Poseidon AccountId32 → SS58 address (prefix 189).
  • signTransfer(seed, params) → a signed v4 extrinsic, ready for author_submitExtrinsic.
  • signCall(seed, call, params) → sign any call (build it with polkadot.js, sign it here).
  • BIP39 mnemonic helpers using the canonical Quantus HD path.

Install

npm install @quantus-network/wasm

Requires Node.js >= 18. The package ships prebuilt wasm (nodejs target) plus TypeScript types.

Quick start

import { account, signTransfer } from "@quantus-network/wasm";

// 32-byte seed (e.g. from your KMS / secure storage).
const seed = new Uint8Array(32); // ...fill with real entropy

const acct = account(seed);
console.log(acct.address); // qz... (SS58, prefix 189)

const extrinsicHex =
  "0x" +
  Buffer.from(
    signTransfer(seed, {
      recipient: "qzk1Nxai3dZD9Cn5kwGcgL6mKxsfxwqdis7kDQJ52aJS2vSn7",
      amount: 1_000_000_000_000n, // plancks
      nonce: 0,
      genesisHash: "0x...", // chain.getBlockHash(0)
      specVersion: 100, // state.getRuntimeVersion()
      transactionVersion: 1,
    })
  ).toString("hex");

// await rpc("author_submitExtrinsic", [extrinsicHex]);

API

account(seed: Uint8Array): QuantusAccount

Derives the keypair and address from a 32-byte seed.

interface QuantusAccount {
  publicKey: Uint8Array; // ML-DSA-87 public key (2592 bytes)
  secretKey: Uint8Array; // ML-DSA-87 secret key (4896 bytes)
  accountId: Uint8Array; // 32-byte Poseidon AccountId32
  address: string;       // SS58, Quantus prefix (189)
}

signTransfer(seed: Uint8Array, params: TransferParams): Uint8Array

Builds and signs a v4 extrinsic for a balances or assets transfer. Returns the SCALE-encoded bytes (prefix with 0x for author_submitExtrinsic). All chain context is supplied by the caller, so signing is fully offline.

interface TransferParams {
  recipient: string | Uint8Array; // SS58, 0x-hex 32-byte id, or raw 32 bytes
  amount: bigint | string | number; // plancks (u128)
  assetId?: number;     // set => assets.transfer; omitted => balances.transfer_allow_death
  nonce: number | bigint;
  tip?: bigint | string | number; // default 0
  period?: number | bigint; // mortal era length in blocks; 0/omitted => immortal
  blockNumber?: number | bigint; // era anchor block (required for mortal eras)
  genesisHash: string | Uint8Array;
  blockHash?: string | Uint8Array; // required when period > 0
  specVersion: number;
  transactionVersion: number;
}

Notes:

  • Immortal by default. Omit period for an immortal transaction; the era checkpoint is the genesis hash.
  • Mortal eras require period, blockNumber, and blockHash, where blockHash is the hash of blockNumber and blockNumber is an era boundary for the period.
  • Hashes accept either 0x-hex strings or raw Uint8Array. Amounts accept bigint (recommended), decimal strings, or safe integers.

signCall(seed: Uint8Array, call: Call, params: CallParams): Uint8Array

Signs an already-encoded RuntimeCall, returning the SCALE-encoded v4 extrinsic. This is the generic primitive behind signTransfer: encode the call with polkadot.js (whose codec handles the call fine — only the 7219-byte Dilithium signature exceeds its limits), then sign it here.

Encode the call directly via the registry — do not build a SubmittableExtrinsic (e.g. api.tx.balances.transferAllowDeath(...)), as that forces polkadot.js to instantiate the oversized signature type and throws:

import { ApiPromise } from "@polkadot/api";
import { signCall } from "@quantus-network/wasm";

const api = await ApiPromise.create({ provider });
const call = api.registry
  .createType("Call", {
    callIndex: api.tx.balances.transferAllowDeath.callIndex,
    args: { dest, value },
  })
  .toHex();

const extrinsic = signCall(seed, call, {
  nonce: 0,
  genesisHash: api.genesisHash.toHex(),
  specVersion: api.runtimeVersion.specVersion.toNumber(),
  transactionVersion: api.runtimeVersion.transactionVersion.toNumber(),
});

// Submit via raw JSON-RPC; the signed extrinsic is too large for api.rpc to re-decode:
// await rpc("author_submitExtrinsic", ["0x" + Buffer.from(extrinsic).toString("hex")]);

The call is a 0x-hex string or Uint8Array. CallParams is the chain context shared by every signed extrinsic — i.e. TransferParams minus the call-specific recipient/amount/assetId (in fact TransferParams extends CallParams):

type Call = Uint8Array | string; // SCALE-encoded RuntimeCall

interface CallParams {
  nonce: number | bigint;
  tip?: bigint | string | number; // default 0
  period?: number | bigint; // mortal era length in blocks; 0/omitted => immortal
  blockNumber?: number | bigint; // era anchor block (required for mortal eras)
  genesisHash: string | Uint8Array;
  blockHash?: string | Uint8Array; // required when period > 0
  specVersion: number;
  transactionVersion: number;
}

The same notes about immortal/mortal eras and hash/amount input formats apply.

accountFromMnemonic(mnemonic: string, opts?: MnemonicOptions): QuantusAccount

Derives an account from a BIP39 mnemonic using the Quantus HD path m/44'/189189'/<account>'/<change>'/<addressIndex>'. Produces the same addresses as the Quantus wallets.

interface MnemonicOptions {
  account?: number;      // default 0
  change?: number;       // default 0
  addressIndex?: number; // default 0
  passphrase?: string;   // optional BIP39 passphrase
}

signTransferFromMnemonic(mnemonic, params, opts?): Uint8Array

Same as signTransfer, but keyed from a mnemonic at the given HD indices.

signCallFromMnemonic(mnemonic, call, params, opts?): Uint8Array

Same as signCall, but keyed from a mnemonic at the given HD indices.

mnemonicToSeed(mnemonic: string, passphrase?: string): Uint8Array

Returns the 64-byte BIP39 seed. Use the first 32 bytes with account / signTransfer to bridge to the seed-based API.

Trust & verification

Correctness is validated byte-for-byte against the canonical chain crates and frozen golden vectors (see src/ext.rs and test/smoke.test.js):

  • Addresses match qp-dilithium-crypto's IdentifyAccount, and reproduce known chain-spec mnemonic vectors.
  • Era encoding matches sp-runtime::generic::Era.
  • Signatures are deterministic ML-DSA-87, frozen as golden vectors and verified under the canonical crate.
  • Transaction extensions match the runtime's TxExtension (CheckMortality, CheckNonce, ChargeTransactionPayment, CheckMetadataHash, and the custom Reversible/Wormhole extensions, which contribute no signed bytes).

Examples

A runnable script exercising every documented function (offline):

npm run build
npm run example

See examples/usage.js.

CLI wallet

examples/wallet.mjs is a minimal command-line wallet that talks to a live node. It uses polkadot.js only for connecting, reading storage (balance/nonce), and SCALE-encoding the call; this package produces the post-quantum signature, and the signed extrinsic is submitted via raw author_submitExtrinsic (it is too large for polkadot.js to re-decode).

export MNEMONIC="your twelve or twenty-four word phrase"

npm run wallet -- address
npm run wallet -- balance                 # balance of your own account
npm run wallet -- balance <address>       # balance of any address
npm run wallet -- send --to <address> --amount 1000000000000

The endpoint defaults to https://a1-planck.quantus.cat; override it with --rpc <url> or the QUANTUS_RPC env var. Pass --account N to use a different HD account index.

Build from source

Requires the Rust toolchain, the wasm32-unknown-unknown target, and wasm-pack.

npm install
npm run build   # wasm-pack (nodejs target) -> tsc
npm test        # cargo test + JS golden vectors

Publishing

Published from CI via npm Trusted Publishing (OIDC) — no token or secret required. Cut a release with scripts/create-release.sh <patch|minor|major|x.y.z> (see CREATE_RELEASE.md); publishing a GitHub Release triggers the publish workflow, which builds, tests, and runs npm publish with automatic provenance.

License

MIT