SDK
stxer is the TypeScript SDK for the stxer API: simulations, execution traces, contract ASTs, batch reads and chain tip. Source: github.com/stxer/stxer-sdk. Current version: 0.12.0.
Install
npm install stxer
# or
bun add stxerIt works in Node, browsers and workers. Most functions take an optional stxerApi to point at testnet:
import { STXER_API_MAINNET, STXER_API_TESTNET } from 'stxer'
// https://api.stxer.xyz, https://testnet-api.stxer.xyzWhich function
| Goal | Use |
|---|---|
| Preview one transaction before sending (no trace, not stored) | instantSimulation |
| Scripted multi-step simulation, viewable in the inspector | SimulationBuilder |
| Tests with assertions on each step | createSimulationSession + submitSimulationSteps + the session helpers |
| Burn block and tenure scenarios | addAdvanceBlocks + getSimulationTip |
| Bulk reads against current chain state | batchRead, BatchProcessor |
| Bulk reads against a session's state | simulationBatchReads |
| Read-only calls with ABI decoding | callReadonly, readVariable, readMap |
| How a transaction executed | getTransactionTrace, getSimulationTrace |
SimulationBuilder
import { SimulationBuilder } from 'stxer'
import { Pc, PostConditionMode, uintCV } from '@stacks/transactions'
const id = await SimulationBuilder.new({ network: 'mainnet', skipTracing: false })
.useBlockHeight(1044660) // optional: fork point; default is the tip
.withSender('SP…') // default sender for the following steps
.addContractCall({
contract_id: 'SP….my-contract',
function_name: 'my-function',
function_args: [uintCV(1)],
post_condition_mode: PostConditionMode.Deny, // default Allow
post_conditions: [Pc.origin().willSendLte(1_000_000).ustx()],
})
.addSTXTransfer({ recipient: 'SP…', amount: 1_000_000 })
.addContractDeploy({ contract_name: 'my-contract', source_code: '…' }) // Clarity 6 by default
.addEvalCode('SP….my-contract', '(var-set counter u100)')
.addSetContractCode({ contract_id: 'SP….other', source_code: '…' })
.addReads([{ DataVar: ['SP….my-contract', 'counter'] }, { StxBalance: 'SP…' }])
.addTenureExtend() // or a SIP-034 cause, e.g. 'ExtendedRuntime'
.addAdvanceBlocks({ bitcoin_blocks: 1, stacks_blocks_per_bitcoin: 1 })
.run()
// https://stxer.xyz/simulations/mainnet/${id}run() returns only the simulation id. For typed per-step results use the session functions below.
Sessions
import {
createSimulationSession, submitSimulationSteps, getSimulationResult,
getSimulationTip, simulationBatchReads, SimulationError,
} from 'stxer'
const id = await createSimulationSession({ skip_tracing: true })
const { steps } = await submitSimulationSteps(id, {
steps: [{ Transaction: '0x…' }, { Reads: [{ StxBalance: 'SP…' }] }],
})
const result = await getSimulationResult(id) // metadata + step summaries
const tip = await getSimulationTip(id) // { synthetic, stacks_height, burn_height, … }
const reads = await simulationBatchReads(id, { stx: ['SP…'], vars: [['SP….c', 'v']] })Every session call throws SimulationError on a non-2xx response, with .status, .body and .marker ('simulation_busy' for 409 — retry; 'simulation_outdated' for 410 — new session; otherwise null).
Session helpers build and decode common steps for you: callContract(id, { sender, contract, functionName, functionArgs }) returns { result, resultHex, vmError, pcAborted, txid, receipt }; getStxBalance, getFtBalance, getNonce return bigint; readDataVar returns the Clarity value.
Instant simulation
import { instantSimulation } from 'stxer'
const { receipt, reads } = await instantSimulation({
transaction: '0x…',
reads: [{ StxBalance: 'SP…' }],
})Debug traces
import {
getTransactionTrace, getSimulationTrace, decodeTrace,
flattenTrace, traceContractIds, traceNodeCost, traceNodeSelfCost,
getContractAST, parseContract, indexExpressions, sliceSpan,
} from 'stxer'
const trace = await getTransactionTrace({ blockHeight, blockHash, txid }) // 0x prefixes are fine
const simulated = await getSimulationTrace({ simulationId, txid })- A
Traceis{ block_hash, txid, root }; eachTraceNodeis{ id, code, func, args, result, costs: [before, after], children }. argsandresultare decodedClarityValues, or a string when the expression produced no value.traceNodeCostis inclusive;traceNodeSelfCostexcludes children, and self costs sum to the root's cost.flattenTracelists nodes in evaluation order withdepthand the resolvedcontractId.- Map a node to source: index the contract's AST with
indexExpressions(ast.expressions), look upnode.id, andsliceSpan(ast.source_code, expression.span). UsegetContractASTfor on-chain contracts andparseContractfor ones deployed inside a simulation. decodeTracedecodes a blob you fetched yourself; it is pure JavaScript.- Errors:
TraceFetchError(.status, 404 = no trace) fromgetTransactionTrace;SimulationErrorfromgetSimulationTrace;TraceDecodeError(.offset) for unreadable input.
Contract AST
const ast = await getContractAST({ contractId: 'SP102V8P0F7JX67ARQ77WEA3D3CFB5XW39REDT0AM.amm-pool-v2-01' })
const parsed = await parseContract({ contractId: 'SP….hello', sourceCode: '(define-public (hello) (ok "world"))', clarityVersion: '6' })Chain tip and batch reads
import { getTip, batchRead, BatchProcessor } from 'stxer'
const tip = await getTip() // block_height, block_hash, bitcoin_height, tenure_cost, …
const result = await batchRead({
variables: [{ contract, variableName: 'my-var' }],
maps: [{ contract, mapName: 'my-map', mapKey }],
readonly: [{ contract, functionName: 'get-value', functionArgs: [] }],
})
// result.index_block_hash, result.vars, result.maps, result.readonly
const processor = new BatchProcessor({ batchDelayMs: 1000 })
const value = await processor.read({ mode: 'variable', contractAddress: 'SP…', contractName: 'c', variableName: 'v' })BatchProcessor queues reads and sends them as one request after the delay.
Clarity helpers
import { callReadonly, readVariable, readMap } from 'stxer'
import { SIP010TraitABI } from 'clarity-abi/abis'
const supply = await callReadonly({
abi: SIP010TraitABI.functions,
functionName: 'get-total-supply',
contract: 'SP102V8P0F7JX67ARQ77WEA3D3CFB5XW39REDT0AM.token-alex',
})Transaction and Bitcoin helpers
buildUnsignedContractCallHex({ sender, contract, functionName, functionArgs, fee?, nonce? })andsetSender(tx, sender)build unsigned transactions forTransactionsteps.forgeBitcoinTx,buildBitcoinHeader,merkleProof,verifyMerkleProofand script builders support bridge peg-in scenarios together withAdvanceBlocks'burn_header_hashes.