Stacks
March 10, 2026
A viem-style SDK for Stacks. One package, zero polyfills, full tree-shaking. 23.8 KB gzipped with 6 runtime dependencies — 11.6x smaller than stacks.js.
Install with bun add @secondlayer/stacks.
Getting started
Create a public client for read-only operations, or a wallet client for signing transactions. Install with bun add @secondlayer/stacks.
import { createPublicClient, createWalletClient, http } from "@secondlayer/stacks"
import { mainnet } from "@secondlayer/stacks/chains"
import { privateKeyToAccount } from "@secondlayer/stacks/accounts"
const publicClient = createPublicClient({
chain: mainnet,
transport: http(),
})
const wallet = createWalletClient({
chain: mainnet,
transport: http(),
account: privateKeyToAccount("..."),
})Clients
Three client types cover every use case. createPublicClient for reads, createWalletClient for signing, and createMultiSigClient for multi-signature transactions. Clients are extensible with .extend() for BNS, PoX, and StackingDAO modules.
Transports are composable: http(), webSocket(), custom(), and fallback() for automatic failover.
import { createPublicClient, http, webSocket, fallback } from "@secondlayer/stacks"
import { mainnet } from "@secondlayer/stacks/chains"
// Fallback transport — tries HTTP first, falls back to WebSocket
const publicClient = createPublicClient({
chain: mainnet,
transport: fallback([
http(),
webSocket(),
]),
})
// Read-only actions
const balance = await publicClient.getBalance("SP1234...")
const height = await publicClient.getBlockHeight()
const nonce = await publicClient.getNonce("SP1234...")
const fee = await publicClient.estimateFee({ ... })Contracts
Read and call Clarity contracts with full type safety. Method names are automatically converted from kebab-case to camelCase.
import { readContract, callContract } from "@secondlayer/stacks/actions"
// Read-only call
const balance = await readContract(publicClient, {
contract: "SP2C2YFP12AJZB1MAERTSVAR6NQJHQ5MEH0GH33C.usda-token",
method: "getBalance", // auto-camelCased from get-balance
args: { owner: "SP1234..." },
})
// State-changing call
const txId = await callContract(wallet, {
contract: "SP2C2YFP12AJZB1MAERTSVAR6NQJHQ5MEH0GH33C.usda-token",
method: "transfer",
args: { amount: 1000n, sender: "SP1234...", recipient: "SP5678..." },
})
// Simulate without broadcasting
const result = await simulateCall(publicClient, {
contract: "SP2C2YFP12AJZB1MAERTSVAR6NQJHQ5MEH0GH33C.usda-token",
method: "getBalance",
args: { owner: "SP1234..." },
})
// Batch multiple reads in a single call
const results = await multicall(publicClient, [
{ contract: "SP...::token-a", method: "getBalance", args: { owner: "SP..." } },
{ contract: "SP...::token-b", method: "getBalance", args: { owner: "SP..." } },
])Transfers
STX transfers with post-conditions for safety.
import { transferStx } from "@secondlayer/stacks/actions"
import { Pc } from "@secondlayer/stacks/postconditions"
const txId = await transferStx(wallet, {
recipient: "SP5678...",
amount: 1_000_000n, // 1 STX in microSTX
memo: "payment",
postConditions: [
Pc.principal("SP1234...").willSendLte(1_000_000n).ustx(),
],
})Subscriptions
Subscribe to real-time blockchain events over WebSocket.
import { watchBlocks, watchMempool, watchTransaction,
watchAddress, watchAddressBalance } from "@secondlayer/stacks/subscriptions"
const unwatch = watchBlocks(publicClient, {
onBlock: (block) => console.log("New block:", block.height),
})
const unwatchMempool = watchMempool(publicClient, {
onTransaction: (tx) => console.log("Pending:", tx.txId),
})
// Watch a specific transaction until confirmed
watchTransaction(publicClient, {
txId: "0x...",
onStatusChange: (status) => console.log("Status:", status),
})
// Watch an address for activity
watchAddress(publicClient, {
address: "SP1234...",
onTransaction: (tx) => console.log("Activity:", tx),
})BNS
Bitcoin Name System — register and resolve .btc names.
import { resolveName, registerName } from "@secondlayer/stacks/bns"
const address = await resolveName(publicClient, { name: "alice.btc" })
const txId = await registerName(wallet, {
name: "myname",
namespace: "btc",
zonefile: "...",
})