@yusufolosun/stx-utils
v2.0.2
Published
Lightweight, zero-dependency utilities for Stacks (STX) dApp development — formatting, validation, addresses, Clarity decoding, PoX stacking, memos, and more.
Maintainers
Readme
@yusufolosun/stx-utils
Lightweight, zero-dependency utilities for Stacks (STX) dApp development.
- 10 modules — formatting, addresses, blocks, validation, errors, time, explorer, Clarity decoder, memos, and PoX stacking
- Dual format — ESM + CommonJS with full TypeScript declarations
- Tree-shakeable — import only what you need
- 259 tests — comprehensive coverage including edge cases
Install
# npm
npm install @yusufolosun/stx-utils
# yarn
yarn add @yusufolosun/stx-utils
# pnpm
pnpm add @yusufolosun/stx-utilsModules
| Module | Description | |---|---| | Formatting | Convert between STX / microSTX, compact display (K/M/B) | | Address | Validate, shorten, and parse Stacks principals | | Blocks | Estimate durations from block counts, "time ago" helpers | | Validation | Validate names, stake amounts, and principals | | Errors | Decode Clarity error codes into human-readable messages | | Time | Format dates and relative timestamps | | Explorer | Build Hiro explorer URLs for txs, addresses, contracts, blocks | | Clarity | Decode hex-encoded Clarity values (SIP-005) into JS objects | | Memo | Encode/decode 34-byte STX transfer memos | | Stacking | PoX reward cycle calculations and progress tracking |
Quick Start
import {
formatSTX,
toMicroSTX,
formatSTXCompact,
shortenAddress,
isValidAddress,
blocksToTime,
blocksAgo,
validateStake,
decodeError,
txUrl,
blockUrl,
apiUrl,
decodeClarityValue,
encodeMemo,
blockToCycle,
} from '@yusufolosun/stx-utils';
// STX formatting
formatSTX(1_500_000); // "1.50"
toMicroSTX(2.5); // 2_500_000
formatSTXCompact(1_500_000_000); // "1.5K STX"
// Addresses
shortenAddress('SP1N3809W9CBWWX04KN3TCQHP8A9GN520BD4JMP8Z');
// → "SP1M46...G193"
isValidAddress('SP1N3809W9CBWWX04KN3TCQHP8A9GN520BD4JMP8Z'); // true
// Block time
blocksToTime(144); // "1 day"
blocksAgo(1000, 994); // "~1h ago"
// Validation
validateStake(0.5); // null (valid)
validateStake(0.01); // "Minimum stake is 0.02 STX"
// Error decoding
decodeError(105); // "Already checked in today"
// Explorer URLs
txUrl('0xabc123'); // "https://explorer.hiro.so/txid/0xabc123?chain=mainnet"
txUrl('deadbeef'); // auto-prepends 0x
blockUrl('0xabc', 'testnet');
apiUrl('mainnet'); // "https://stacks-node-api.mainnet.stacks.co"
// Clarity value decoding
const cv = decodeClarityValue('0x0100000000000000000000000000000064');
// → { type: 'uint', value: 100n }
// Memo encoding
const memo = encodeMemo('Hello Stacks');
// → Uint8Array(34) [ 72, 101, 108, ... 0, 0 ]
// PoX stacking
blockToCycle(670000); // → 1 (reward cycle number)Runtime validation behavior
validatePrincipal(value)returns:nullfor valid standard principals (SP.../ST...) and valid contract principals (SP....contract-name)"Invalid contract name"for malformed contract principals (including multiple dots)"Invalid Stacks address"for malformed standard principals
parseContractPrincipal(value)returnsnullunless input is a strictaddress.contract-namewith one dot and a valid contract name (^[a-zA-Z][\\w-]{0,127}$).memoFromHex(hex)throws:RangeErrorwhen length is not 68 hex characters (34 bytes)Errorwhen any character is outside[0-9a-fA-F]
API Reference
Formatting
| Function | Description |
|---|---|
| formatSTX(microSTX, decimals?) | Convert microSTX to display string |
| toMicroSTX(stx) | Convert STX to microSTX |
| toSTX(microSTX) | Convert microSTX to numeric STX |
| formatSTXWithUnit(microSTX) | Format with automatic unit suffix (uSTX or STX) |
| formatSTXCompact(microSTX) | Compact format with K/M/B suffixes |
| MICRO_PER_STX | Constant: 1_000_000 |
Address
| Function | Description |
|---|---|
| isValidAddress(address) | Check standard principal validity |
| isContractPrincipal(address) | Check contract principal validity |
| getAddressNetwork(address) | Returns "mainnet", "testnet", or null |
| shortenAddress(address, startChars?, endChars?) | Truncate for display |
| parseContractPrincipal(principal) | Extract [address, name] from strict address.contract-name input |
Blocks
| Function | Description |
|---|---|
| blocksToTime(blocks) | Human-readable duration from block count |
| blocksToSeconds(blocks) | Convert blocks to seconds |
| secondsToBlocks(seconds) | Convert seconds to blocks |
| blocksAgo(currentBlock, targetBlock) | Relative block time string |
| estimateBlockDate(targetBlock, currentBlock, now?) | Estimated Date object |
| SECONDS_PER_BLOCK | Constant: 600 |
| BLOCKS_PER_DAY | Constant: 144 |
Validation
| Function | Description |
|---|---|
| validateName(name, maxLength?) | Validate a Clarity string input |
| validateStake(stx, minMicroSTX?) | Validate stake amount (rejects NaN, Infinity) |
| validatePrincipal(principal) | Validate standard or contract principal |
| DEFAULT_MIN_STAKE | Constant: 20_000 (0.02 STX in microSTX) |
| DEFAULT_MAX_NAME_LENGTH | Constant: 50 |
Errors
| Function | Description |
|---|---|
| decodeError(code) | Look up a Clarity error code |
| registerErrors(errors) | Add or override error codes |
| getErrorRegistry() | Get snapshot of all registered codes |
Time
| Function | Description |
|---|---|
| formatDate(timestamp, locale?) | Format a UNIX timestamp |
| timeAgo(timestamp) | Relative time string |
Explorer
| Function | Description |
|---|---|
| txUrl(txId, network?) | Transaction explorer link (auto-prepends 0x) |
| addressUrl(address, network?) | Address explorer link |
| contractUrl(principal, network?) | Contract explorer link |
| blockUrl(blockHash, network?) | Block explorer link |
| apiUrl(network?) | Stacks node API base URL |
Clarity
| Function | Description |
|---|---|
| decodeClarityValue(hex) | Decode hex-encoded Clarity value to typed JS object |
| unwrapResponse(cv) | Unwrap an ok response or throw on err |
| extractValue(cv) | Recursively extract plain JS values from Clarity types |
Supported types: int, uint, bool, buffer, string-ascii, string-utf8, none, some, ok, err, list, tuple, principal.
Memo
| Function | Description |
|---|---|
| encodeMemo(text) | Encode UTF-8 string to 34-byte memo buffer |
| decodeMemo(bytes) | Decode 34-byte memo buffer to string |
| memoToHex(text) | Encode memo and return hex string |
| memoFromHex(hex) | Decode hex memo to string (throws on invalid length or non-hex chars) |
| MEMO_MAX_BYTES | Constant: 34 |
Stacking (PoX)
| Function | Description |
|---|---|
| blockToCycle(burnBlockHeight, startHeight?, cycleLength?) | Get cycle number from block height |
| cycleToBlock(cycle, startHeight?, cycleLength?) | Get first block of a cycle |
| cycleProgress(burnBlockHeight, startHeight?, cycleLength?) | Blocks into cycle + progress ratio |
| blocksUntilNextCycle(burnBlockHeight, startHeight?, cycleLength?) | Blocks remaining in current cycle |
| isInPreparePhase(burnBlockHeight, startHeight?, cycleLength?, prepareLength?) | Whether block is in prepare phase |
| BLOCKS_PER_CYCLE | Constant: 2100 |
| POX_START_HEIGHT | Constant: 666050 |
License
MIT
