Skip to content

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 ​

sh
npm install stxer
# or
bun add stxer

It works in Node, browsers and workers. Most functions take an optional stxerApi to point at testnet:

ts
import { STXER_API_MAINNET, STXER_API_TESTNET } from 'stxer'
// https://api.stxer.xyz, https://testnet-api.stxer.xyz

Which function ​

GoalUse
Preview one transaction before sending (no trace, not stored)instantSimulation
Scripted multi-step simulation, viewable in the inspectorSimulationBuilder
Tests with assertions on each stepcreateSimulationSession + submitSimulationSteps + the session helpers
Burn block and tenure scenariosaddAdvanceBlocks + getSimulationTip
Bulk reads against current chain statebatchRead, BatchProcessor
Bulk reads against a session's statesimulationBatchReads
Read-only calls with ABI decodingcallReadonly, readVariable, readMap
How a transaction executedgetTransactionTrace, getSimulationTrace

SimulationBuilder ​

ts
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 ​

ts
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 ​

ts
import { instantSimulation } from 'stxer'

const { receipt, reads } = await instantSimulation({
  transaction: '0x…',
  reads: [{ StxBalance: 'SP…' }],
})

Debug traces ​

ts
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 Trace is { block_hash, txid, root }; each TraceNode is { id, code, func, args, result, costs: [before, after], children }.
  • args and result are decoded ClarityValues, or a string when the expression produced no value.
  • traceNodeCost is inclusive; traceNodeSelfCost excludes children, and self costs sum to the root's cost.
  • flattenTrace lists nodes in evaluation order with depth and the resolved contractId.
  • Map a node to source: index the contract's AST with indexExpressions(ast.expressions), look up node.id, and sliceSpan(ast.source_code, expression.span). Use getContractAST for on-chain contracts and parseContract for ones deployed inside a simulation.
  • decodeTrace decodes a blob you fetched yourself; it is pure JavaScript.
  • Errors: TraceFetchError (.status, 404 = no trace) from getTransactionTrace; SimulationError from getSimulationTrace; TraceDecodeError (.offset) for unreadable input.

Contract AST ​

ts
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 ​

ts
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 ​

ts
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? }) and setSender(tx, sender) build unsigned transactions for Transaction steps.
  • forgeBitcoinTx, buildBitcoinHeader, merkleProof, verifyMerkleProof and script builders support bridge peg-in scenarios together with AdvanceBlocks' burn_header_hashes.

More in Examples and the changelog.