@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/sdkOr with yarn:
yarn add @sumchain/sdkQuick 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); // 1234getBlockByHeight(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") // 1000000nbaseUnitsToKoppa(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") // falseisValidHash(hash)
Validate transaction/block hash format.
isValidHash("0x1234...") // true
isValidHash("invalid") // falseConstants
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 tarballpreparebuildsdist/on install-from-source (git/file:dependencies) and duringnpm pack.prepublishOnlyruns the build beforenpm 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
