@witniumtech/chain-sdk
v0.8.0
Published
TypeScript SDK for the WitniumChain API - create and verify blockchain witnesses
Maintainers
Readme
@witnium/chain-sdk
TypeScript SDK for the WitniumChain API. Create blockchain witnesses with a simple one-liner.
Installation
# From npm (recommended)
npm install @witniumtech/chain-sdk
# From GitHub Packages
npm install @witnium/chain-sdkGetting Started
1. Generate a keypair
import { generateKeyPair } from '@witniumtech/chain-sdk';
const { publicKey, privateKey } = generateKeyPair();
console.log('Public key:', publicKey); // Share this with the WitniumChain admin
console.log('Private key:', privateKey); // Store securely — never share this2. Get your contract deployed
Send your public key to the WitniumChain admin. They will deploy a smart contract configured with your key and give you back a contract address (e.g. 0x1234...).
3. Create witnesses
import { WitniumChainClient } from '@witniumtech/chain-sdk';
const client = new WitniumChainClient({
baseUrl: 'https://api.witniumchain.com',
contractAddress: '0x...', // From step 2
signingPrivateKey: privateKey,
});
const result = await client.createWitness([
{ key: 'fileHash', value: 'sha256:abc123...' },
{ key: 'filename', value: 'document.pdf' },
]);
console.log('Witness ID:', result.witnessId);
console.log('Transaction:', result.transactionHash);The SDK handles all the complexity internally:
- Computing a SHA256 hash of your data locally (the raw data never leaves your system)
- Two-step prepare/finalize flow
- Ed25519 signature generation
Key Generation
import { generateKeyPair, getPublicKey } from '@witniumtech/chain-sdk';
// Generate a new keypair
const { publicKey, privateKey } = generateKeyPair();
// Derive public key from an existing private key
const pub = getPublicKey(privateKey);
console.log(pub === publicKey); // trueBoth functions use the Node.js crypto module (Ed25519). Keys are returned as 64-character hex strings (32 bytes).
API Reference
Creating Witnesses
// Fire-and-forget (returns immediately after transaction broadcast)
const result = await client.createWitness([
{ key: 'fileHash', value: 'sha256:abc123...' },
{ key: 'filename', value: 'document.pdf' },
]);
// With witness chaining
const result = await client.createWitness(data, {
previousWitnessId: 'abc123...', // Link to previous version
});
// Wait for blockchain confirmation
const confirmed = await client.createWitnessAndWait([
{ key: 'fileHash', value: 'sha256:abc123...' },
]);
console.log('Confirmed at block:', confirmed.blockNumber);Checking Transaction Status
// Poll for confirmation manually
const status = await client.transactions.getStatus(result.transactionHash);
if (status.success && status.data.status === 'confirmed') {
console.log('Confirmed at block:', status.data.blockNumber);
}
// Get detailed transaction info
const details = await client.transactions.getDetails(result.transactionHash);Querying Witnesses
// Get a witness from the blockchain (uses client's configured contract address)
const witness = await client.witnesses.get(witnessId);
if (witness.success) {
console.log('Data ID:', witness.data.dataId);
console.log('Timestamp:', witness.data.timestamp);
console.log('Signature R:', witness.data.signatureR);
console.log('Signature S:', witness.data.signatureS);
}Validating Witnesses
The validate() method fetches comprehensive blockchain data for witness validation in a single call:
// Validate a witness with full blockchain details
const validation = await client.witnesses.validate(witnessId, transactionHash);
if (validation.success && validation.data.exists) {
// Witness data
console.log('Witness ID:', validation.data.witness.witnessId);
console.log('Data ID:', validation.data.witness.dataId);
console.log('Block:', validation.data.witness.blockNumber);
// Transaction details
console.log('TX Hash:', validation.data.transaction.transactionHash);
console.log('Gas Used:', validation.data.transaction.gasUsed);
// Network/chain status
console.log('Network:', validation.data.network.networkName);
console.log('Platform:', validation.data.network.platform);
console.log('Consensus:', validation.data.network.consensus);
console.log('Current Block:', validation.data.network.currentBlockNumber);
console.log('Confirmations:', validation.data.network.confirmations);
console.log('Block Time:', validation.data.network.blockTimeSeconds, 'seconds');
console.log('Chain Status:', validation.data.network.status);
// Contract info
console.log('Public Key:', validation.data.contract.signingPublicKey);
console.log('Total Witnesses:', validation.data.contract.totalWitnessCount);
}The validation response includes:
- Witness data: witnessId, dataId, timestamp, blockNumber, nonce, signatures, contractVersion
- Transaction details: hash, block info, gas costs, addresses
- Network status: current block, confirmations, chain health, platform info (Hyperledger Besu, QBFT consensus)
- Contract info: signing public key, total witness count
Note: The actual witnessed data (key-value pairs) and data signature are stored off-chain. To complete validation, verify that SHA256(yourWitnessedData) === validation.data.witness.dataId.
Chain Status
Get live network status — the same data shown on the Grafana WitniumChain Overview dashboard. This is a public endpoint (no authentication required).
const status = await client.status.get();
if (status.success) {
// Chain metrics
console.log('Block height:', status.data.chain.blockHeight);
console.log('Avg block time:', status.data.chain.avgBlockTimeSeconds, 's');
console.log('Blocks (5 min):', status.data.chain.blocksLast5Min);
// Validators
console.log('Validators:', status.data.validators.online, '/', status.data.validators.total);
for (const node of status.data.validators.nodes) {
console.log(` ${node.name}: ${node.status} block=${node.blockHeight} peers=${node.peerCount}`);
}
// Network
console.log('Total peers:', status.data.network.totalPeers);
console.log('Block spread:', status.data.network.blockHeightSpread);
console.log('TX pool:', status.data.network.transactionPool.size);
}
// Get time series history for charts
const history = await client.status.getHistory('1h'); // '1h' | '6h' | '24h' | '7d'
if (history.success) {
console.log('Data points:', history.data.chain.timestamps.length);
console.log('Block heights:', history.data.chain.blockHeight);
console.log('Peer counts:', history.data.network.totalPeers);
}Querying Contracts
// Get contract info
const info = await client.contracts.getInfo(contractAddress);
// Get witness count
const count = await client.contracts.getWitnessCount(contractAddress);
// Get signing public key
const key = await client.contracts.getSigningPublicKey(contractAddress);Querying Wallet Balances
// Get wallet balance
const balance = await client.wallets.getBalance('0x...');
if (balance.success) {
console.log('Balance:', balance.data.balanceEth, 'ETH');
console.log('Balance (Wei):', balance.data.balanceWei);
}
// Check if wallet needs funding
if (balance.success && parseFloat(balance.data.balanceEth) < 0.1) {
console.warn('Wallet balance low - may need funding');
}Ethereum Mainnet Anchoring
Witnesses are periodically anchored to Ethereum mainnet for additional security.
// Verify a witness is anchored
const verification = await client.anchors.verify(witnessId);
if (verification.data.verified) {
console.log('Anchored in:', verification.data.anchor.anchorId);
console.log('Ethereum TX:', verification.data.anchor.ethereumTxHash);
}
// List all anchors
const anchors = await client.anchors.list({ page: 1, limit: 10 });Admin Client
The WitniumChainAdminClient provides contract provisioning and wallet management for server-side applications with admin access.
Setup
import { WitniumChainAdminClient } from '@witniumtech/chain-sdk';
const admin = new WitniumChainAdminClient({
baseUrl: 'https://api.witniumchain.com',
adminToken: process.env.WITNIUMCHAIN_ADMIN_TOKEN!,
});Provision a Contract (Full Onboarding)
// Auto-generates a keypair, deploys the contract, and returns everything
const result = await admin.provisionContract({ contractId: 'workspace-123' });
console.log('Contract:', result.contractAddress);
console.log('Private key:', result.signingKeyPair!.privateKey); // Store securely!
// Use the result directly to create a regular client
const client = new WitniumChainClient(result.clientConfig!);
const witness = await client.createWitness([{ key: 'hello', value: 'world' }]);Or provide your own public key:
const result = await admin.provisionContract({
contractId: 'workspace-456',
signingPublicKey: existingPublicKey, // 64 hex chars
metadata: { team: 'engineering' },
});
// result.signingKeyPair is null (caller manages their own key)
// result.clientConfig is null (caller builds their own config)Low-Level Admin Methods
// Deploy a contract
const deploy = await admin.deployContract({
contractId: 'my-contract',
signingPublicKey: publicKey,
});
// Fund a wallet
const fund = await admin.fundWallet({
walletAddress: '0x...',
amountEth: '10.0',
});
// Get contract info
const info = await admin.getContractInfo('0x...');Configuration
const client = new WitniumChainClient({
// Required
baseUrl: 'https://api.witniumchain.com',
contractAddress: '0x1234...',
signingPrivateKey: 'ed25519-private-key-hex', // 64 or 128 hex chars
// Optional
token: 'bearer-token', // For endpoints that require auth
timeout: 60000, // Request timeout in ms (default: 30000)
fetch: customFetch, // Custom fetch implementation
});Key Management
Use generateKeyPair() to create a new Ed25519 keypair, or bring your own key. The private key:
- Never leaves your system — only signatures and data hashes are sent to the API
- Should be stored securely (e.g., environment variables, secrets manager)
Accepted private key formats:
- 64 hex chars (32 bytes) - seed format (output of
generateKeyPair()) - 128 hex chars (64 bytes) - NaCl format (seed + public key)
Privacy-First Architecture
The raw witness data never leaves your system. The SDK computes dataId = SHA256(canonicalized data) locally and only sends the hash to the API. This means:
- The API acts as a pure notary — it timestamps and signs hashes without ever seeing the underlying data
- Your data stays private even in transit
- You can independently verify a witness by recomputing
SHA256(yourData)and comparing with the on-chaindataId
Use computeDataId() to compute the hash independently:
import { computeDataId } from '@witniumtech/chain-sdk';
const dataId = computeDataId([
{ key: 'fileHash', value: 'sha256:abc123...' },
{ key: 'filename', value: 'document.pdf' },
]);
// dataId is a 64-char hex SHA256 hash — compare with the on-chain valueQuadruple-Layer Protection
Every witness is protected by four independent cryptographic layers:
- Data Signature - Your Ed25519 signature of the data hash (computed locally)
- Witness Signature - Your Ed25519 signature of the witness payload (stored on blockchain)
- SHA256 Hash - Data ID is computed client-side from the canonicalized data
- Blockchain Seal - Immutable record with growing confirmations
Error Handling
try {
const result = await client.createWitness(data);
} catch (error) {
if (error instanceof WitniumApiError) {
console.error('API Error:', error.message);
console.error('Status:', error.status);
console.error('Code:', error.code);
}
}Advanced: Low-Level API
For full control, you can use the low-level prepare/finalize methods:
import { computeDataId, signMessage, parsePrivateKey } from '@witniumtech/chain-sdk';
const seed = parsePrivateKey(privateKeyHex);
// Step 1: Compute dataId and sign it
const dataId = computeDataId(yourData);
const dataSignature = signMessage(dataId, seed);
// Step 2: Prepare (API only receives the hash)
const prepare = await client.witnesses.prepare(contractAddress, {
dataId,
dataSignature,
});
// Step 3: Sign witness payload and finalize
const finalize = await client.witnesses.finalize(witnessId, {
witnessSignature: 'your-signature',
});Complete Resource Reference
The SDK provides the following resource namespaces:
| Resource | Description | Key Methods |
|----------|-------------|-------------|
| client.witnesses | Create, query, and validate witnesses | prepare(), finalize(), get(), validate() |
| client.transactions | Query transaction status | getStatus(), getDetails() |
| client.contracts | Query contract info | getInfo(), verify(), getWitnessCount(), getSigningPublicKey() |
| client.anchors | Ethereum anchoring | list(), getLatest(), get(), verify(), verifyOnChain(), getSchedulerStatus(), getEthereumHealth() |
| client.wallets | Query wallet balances | getBalance() |
| client.health | API health checks | check() |
| client.status | Chain status (Grafana dashboard data) | get(), getHistory() |
Admin Client
| Method | Description |
|--------|-------------|
| admin.provisionContract(options) | Full onboarding: generate keypair + deploy + verify |
| admin.deployContract(request) | Deploy a WitnessRegistry contract |
| admin.fundWallet(request) | Fund a wallet with ETH |
| admin.getContractInfo(address) | Get contract info |
High-Level Methods
For common operations, use the high-level client methods:
| Method | Description |
|--------|-------------|
| client.createWitness(data, options?) | Create a witness (fire-and-forget) |
| client.createWitnessAndWait(data, options?) | Create and wait for confirmation |
All Response Types
All API responses return ApiResult<T>:
type ApiResult<T> =
| { success: true; data: T; status: number }
| { success: false; error: ApiError };Always check result.success before accessing result.data.
Requirements
- Node.js 18+ (uses native Ed25519 crypto)
- For browser usage, use the low-level API with your own signing implementation
License
MIT
