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

@sumchain/sdk

v0.2.5

Published

TypeScript SDK for SUM Chain - A Rust-based blockchain with Koppa (Ϙ) native currency

Readme

SUM Chain TypeScript SDK

Official TypeScript/JavaScript SDK for interacting with SUM Chain.

Native Currency: Koppa (Ϙ) with 9 decimal places

Installation

npm install @sumchain/sdk

Or with yarn:

yarn add @sumchain/sdk

Quick Start

import { Provider, koppaToBaseUnits, formatKoppa } from '@sumchain/sdk';

// Connect to a node
const provider = new Provider('http://localhost:8545');

// Get account balance
const balance = await provider.getBalance('5HqX...');
console.log(formatKoppa(balance)); // "100 Ϙ"

// Get current block
const block = await provider.getLatestBlock();
console.log(`Block #${block.height}`);

// Get block height
const height = await provider.getBlockNumber();
console.log(`Current height: ${height}`);

Currency Conversion

The SDK provides utilities for working with Koppa (Ϙ) amounts:

import { koppaToBaseUnits, baseUnitsToKoppa, formatKoppa } from '@sumchain/sdk';

// Convert Koppa to base units
const baseUnits = koppaToBaseUnits("1.5");  // 1500000000n
const baseUnits2 = koppaToBaseUnits(1.5);    // 1500000000n

// Convert base units to Koppa
const koppa = baseUnitsToKoppa(1500000000n); // "1.5"

// Format for display
const formatted = formatKoppa(1500000000n);  // "1.5 Ϙ"

API Reference

Provider

Constructor

const provider = new Provider('http://localhost:8545');

// Or with options
const provider = new Provider({
  url: 'http://localhost:8545',
  timeout: 30000,
  headers: {
    'Authorization': 'Bearer token'
  }
});

Methods

getBlockNumber()

Get the current block height.

const height = await provider.getBlockNumber();
console.log(height); // 1234
getBlockByHeight(height)

Get block information by height.

const block = await provider.getBlockByHeight(100);
if (block) {
  console.log(`Block #${block.height}`);
  console.log(`Hash: ${block.hash}`);
  console.log(`Transactions: ${block.tx_count}`);
}
getLatestBlock()

Get the latest block.

const block = await provider.getLatestBlock();
console.log(`Latest block: #${block.height}`);
getBalance(address)

Get account balance in base units.

const balance = await provider.getBalance('5HqX...');
console.log(formatKoppa(balance)); // "100 Ϙ"
getNonce(address)

Get account nonce (transaction count).

const nonce = await provider.getNonce('5HqX...');
console.log(`Nonce: ${nonce}`);
sendRawTransaction(rawTx)

Broadcast a signed transaction.

const txHash = await provider.sendRawTransaction('0x...');
console.log(`Transaction sent: ${txHash}`);
getTransaction(txHash)

Get transaction details.

const tx = await provider.getTransaction('0x...');
if (tx) {
  console.log(`From: ${tx.from}`);
  console.log(`To: ${tx.to}`);
  console.log(`Amount: ${formatKoppa(tx.amount)}`);
  console.log(`Fee: ${formatKoppa(tx.fee)}`);
  console.log(`Status: ${tx.status}`);
}
getReceipt(txHash)

Get transaction receipt.

const receipt = await provider.getReceipt('0x...');
if (receipt) {
  console.log(`Block: ${receipt.block_height}`);
  console.log(`Status: ${receipt.status}`);
  console.log(`Fee Paid: ${formatKoppa(receipt.fee_paid)}`);
}
getPendingTransactions()

Get pending transactions in mempool.

const pending = await provider.getPendingTransactions();
console.log(`Pending: ${pending.length} transactions`);
getValidators()

Get current validator set.

const validators = await provider.getValidators();
console.log(`Validators: ${validators.validators.length}`);
console.log(`Current proposer: ${validators.current_proposer_index}`);
getHealth()

Get node health status.

const health = await provider.getHealth();
console.log(`Version: ${health.version}`);
console.log(`Chain ID: ${health.chain_id}`);
console.log(`Height: ${health.current_height}`);
console.log(`Peers: ${health.peer_count}`);
console.log(`Validator: ${health.is_validator}`);
getChainId()

Get chain ID.

const chainId = await provider.getChainId();
console.log(`Chain ID: ${chainId}`);
waitForReceipt(txHash, timeout?, interval?)

Wait for transaction to be included in a block.

const receipt = await provider.waitForReceipt(txHash, 60000);
console.log(`Transaction confirmed in block ${receipt.block_height}`);
waitForConfirmation(txHash, confirmations?, timeout?)

Wait for specified number of block confirmations.

const receipt = await provider.waitForConfirmation(txHash, 3);
console.log(`Transaction has 3 confirmations`);

Utility Functions

koppaToBaseUnits(koppa)

Convert Koppa amount to base units.

koppaToBaseUnits("1.5")    // 1500000000n
koppaToBaseUnits(1.5)      // 1500000000n
koppaToBaseUnits("0.001")  // 1000000n

baseUnitsToKoppa(baseUnits)

Convert base units to Koppa.

baseUnitsToKoppa(1500000000n)  // "1.5"
baseUnitsToKoppa("1000000000")  // "1"
baseUnitsToKoppa(1000000n)      // "0.001"

formatKoppa(baseUnits)

Format base units with Koppa symbol.

formatKoppa(1500000000n)      // "1.5 Ϙ"
formatKoppa("1000000000000")  // "1,000 Ϙ"

formatNumber(value)

Format number with comma separators.

formatNumber("1000")      // "1,000"
formatNumber("1000.5")    // "1,000.5"
formatNumber(1234567.89)  // "1,234,567.89"

isValidAddress(address)

Validate address format.

isValidAddress("5HqX...")  // true
isValidAddress("0x...")    // true
isValidAddress("invalid")  // false

isValidHash(hash)

Validate transaction/block hash format.

isValidHash("0x1234...")  // true
isValidHash("invalid")     // false

Constants

import {
  KOPPA_UNIT,      // 1000000000n
  KOPPA_SYMBOL,    // "Ϙ"
  KOPPA_NAME,      // "Koppa"
  KOPPA_DECIMALS   // 9
} from '@sumchain/sdk';

Transaction classification & token minters

Transactions returned by the SDK carry additive, read-time semantic fields (tx_type, action, asset_ref, asset_kind) derived server-side from the already-public payload. classifyTransaction maps them to a domain and a conservative human label — the same helper the explorer and SUMaillet use.

import { classifyTransaction, minterRole } from '@sumchain/sdk';

const tx = await provider.getTransaction('0x...');
if (tx) {
  const c = classifyTransaction(tx);
  console.log(c.domain);      // e.g. "snip"
  console.log(c.domainLabel); // "SNIP"
  console.log(c.action);      // e.g. "SNIP file registration" (or "Unknown transaction")
}

Labels are conservative: document-family subtypes (e.g. "diploma" vs "transcript") are not inferred, and an unknown type yields "Unknown transaction" rather than a guess.

Minter lookup is token-scoped — the owner and registered minters of a single token you already have in view. There is intentionally no address→tokens ("everything this address can mint") lookup.

const minters = await provider.getTokenMinters('0x<token_id>'); // { owner, minters } | null
if (minters) {
  const role = minterRole(minters, tx.from, 'ACME'); // { isOwner, isMinter, label }
  console.log(role.label); // e.g. "ACME minter", or null if not a minter
}

Examples

Query Account Information

import { Provider, formatKoppa } from '@sumchain/sdk';

const provider = new Provider('http://localhost:8545');
const address = '5HqX...';

// Get balance
const balance = await provider.getBalance(address);
console.log(`Balance: ${formatKoppa(balance)}`);

// Get nonce
const nonce = await provider.getNonce(address);
console.log(`Nonce: ${nonce}`);

Monitor New Blocks

import { Provider } from '@sumchain/sdk';

const provider = new Provider('http://localhost:8545');

async function monitorBlocks() {
  let lastHeight = await provider.getBlockNumber();

  setInterval(async () => {
    const currentHeight = await provider.getBlockNumber();

    if (currentHeight > lastHeight) {
      const block = await provider.getBlockByHeight(currentHeight);
      console.log(`New block #${block.height}`);
      console.log(`  Hash: ${block.hash}`);
      console.log(`  Transactions: ${block.tx_count}`);
      lastHeight = currentHeight;
    }
  }, 3000); // Poll every 3 seconds
}

monitorBlocks();

Send Transaction and Wait for Confirmation

import { Provider } from '@sumchain/sdk';

const provider = new Provider('http://localhost:8545');

// Sign transaction offline (using wallet CLI or other tool)
const signedTx = '0x...';

// Send transaction
const txHash = await provider.sendRawTransaction(signedTx);
console.log(`Transaction sent: ${txHash}`);

// Wait for receipt
const receipt = await provider.waitForReceipt(txHash);
console.log(`Confirmed in block ${receipt.block_height}`);
console.log(`Status: ${receipt.status}`);

// Or wait for multiple confirmations
const finalReceipt = await provider.waitForConfirmation(txHash, 3);
console.log(`Transaction has 3 confirmations`);

Check Node Health

import { Provider } from '@sumchain/sdk';

const provider = new Provider('http://localhost:8545');

const health = await provider.getHealth();

console.log(`Version: ${health.version}`);
console.log(`Chain ID: ${health.chain_id}`);
console.log(`Height: ${health.current_height}`);
console.log(`Peers: ${health.peer_count}`);
console.log(`Mempool: ${health.mempool_size}`);
console.log(`Validator: ${health.is_validator}`);

List Validators

import { Provider } from '@sumchain/sdk';

const provider = new Provider('http://localhost:8545');

const validatorSet = await provider.getValidators();

console.log(`Validators at height ${validatorSet.current_height}:`);
validatorSet.validators.forEach((v, i) => {
  const marker = v.is_current_proposer ? ' ← current proposer' : '';
  console.log(`[${i}] ${v.address}${marker}`);
});

NFT (SUM-721) Support

The SDK includes full support for the SUM-721 native NFT standard.

Get Collection Info

import { Provider } from '@sumchain/sdk';

const provider = new Provider('http://localhost:8545');

const collection = await provider.getNftCollection('0x1234...');
if (collection) {
  console.log(`Collection: ${collection.name} (${collection.symbol})`);
  console.log(`Total supply: ${collection.total_supply}/${collection.max_supply || 'unlimited'}`);
  console.log(`Transferable: ${collection.transferable}`);
  console.log(`Royalty: ${collection.royalty_bps / 100}%`);
}

Get Token Info

const token = await provider.getNftToken('0x1234...', 42);
if (token) {
  console.log(`Token #${token.token_id}`);
  console.log(`Owner: ${token.owner}`);
  console.log(`Creator: ${token.creator}`);
  console.log(`Metadata: ${token.metadata}`);
  console.log(`Is Document: ${token.is_document}`);
}

List Owned NFTs

const owned = await provider.getNftsByOwner('SUM1abc...');
console.log(`Address owns ${owned.count} NFTs:`);

for (const ref of owned.tokens) {
  const token = await provider.getNftToken(ref.collection_id, ref.token_id);
  console.log(`  - ${token?.metadata || 'Unknown'}`);
}

Check NFT Balance

const balance = await provider.getNftBalance('SUM1abc...');
console.log(`NFT Balance: ${balance} tokens`);

Verify Document Certificate

// Check if a certified document NFT exists and is valid
const collectionId = '0x...'; // University degree collection
const tokenId = 42;

const exists = await provider.nftTokenExists(collectionId, tokenId);
if (exists) {
  const token = await provider.getNftToken(collectionId, tokenId);
  if (token?.is_document) {
    console.log('Valid certified document');
    console.log(`Issued to: ${token.owner}`);
    console.log(`Metadata: ${token.metadata}`);
  }
}

TypeScript Support

The SDK is written in TypeScript and includes full type definitions:

import type {
  BlockInfo,
  TransactionInfo,
  TransactionReceipt,
  ValidatorSetInfo,
  HealthResponse
} from '@sumchain/sdk';

const block: BlockInfo = await provider.getLatestBlock();
const tx: TransactionInfo | null = await provider.getTransaction(txHash);

Error Handling

import { Provider } from '@sumchain/sdk';

const provider = new Provider('http://localhost:8545');

try {
  const balance = await provider.getBalance(address);
  console.log(formatKoppa(balance));
} catch (error) {
  if (error instanceof Error) {
    console.error(`Error: ${error.message}`);
  }
}

Browser Support

The SDK works in both Node.js and browser environments. For browsers, you may need to polyfill fetch for older browsers.

<script type="module">
  import { Provider, formatKoppa } from 'https://cdn.skypack.dev/@sumchain/sdk';

  const provider = new Provider('http://localhost:8545');
  const balance = await provider.getBalance('5HqX...');
  console.log(formatKoppa(balance));
</script>

Building from Source

The compiled dist/ is generated, not committed:

npm ci
npm run build          # tsc → dist/ (index, provider, utils, types; .js + .d.ts)
npm pack               # runs prepare, then packs dist/ into the tarball
  • prepare builds dist/ on install-from-source (git/file: dependencies) and during npm pack.
  • prepublishOnly runs the build before npm publish.
  • Consumers installing the published package receive the prebuilt dist/ from the tarball — no build runs at install time.

The package is published as ESM ("type": "module"); relative imports in src/ use explicit .js extensions so the emitted dist/ resolves under both Node ESM (import '@sumchain/sdk') and bundlers.

License

MIT

Links