stxer 0.7.0 → 0.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md ADDED
@@ -0,0 +1,141 @@
1
+ # Changelog
2
+
3
+ All notable changes to the `stxer` SDK are documented here. The format
4
+ loosely follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/);
5
+ versioning is [SemVer](https://semver.org/).
6
+
7
+ ## 0.9.0
8
+
9
+ Adopts Stacks **Epoch 4.0 / Clarity 6** (stacks-core 4.0.1).
10
+
11
+ ### Added
12
+
13
+ - `'Epoch40'` member on the `ClarityEpoch` union and `'Clarity6'` on
14
+ `ClarityVersionName`; `parseContract` now accepts
15
+ `clarityVersion: '6'`.
16
+ - `ClarityVersion.Clarity6` accepted by `addContractDeploy` /
17
+ `addSetContractCode` (via the upgraded `@stacks/transactions`), and
18
+ serialized as wire value `6` for `SetContractCode` steps.
19
+
20
+ ### Changed
21
+
22
+ - `@stacks/transactions` bumped `7.4.0` → `7.5.0` (first release whose
23
+ `ClarityVersion` enum includes `Clarity6`).
24
+ - Unknown future clarity versions now serialize as `6` (previously
25
+ silently clamped to `5`).
26
+ - Deploy defaults remain `ClarityVersion.Clarity5` until Epoch 4.0
27
+ activates on mainnet (burn height 960,230); pass
28
+ `clarity_version: ClarityVersion.Clarity6` explicitly to opt in.
29
+
30
+ ## 0.8.0
31
+
32
+ Pairs with **stxer-api ≥ schema-v2** (the simulator build that ships
33
+ `AdvanceBlocks` + `/tip` + the typed 409 / 410 status codes). Older
34
+ deployments respond `404` for `getSimulationTip` and reject
35
+ `AdvanceBlocks` step variants.
36
+
37
+ ### Added
38
+
39
+ - **`addAdvanceBlocks(request)` on `SimulationBuilder`** plus the
40
+ `{ AdvanceBlocks: AdvanceBlocksRequest }` variant on
41
+ `SimulationStepInput`. Synthesizes bitcoin / stacks blocks on top of
42
+ the simulation's pinned parent tip — used to model burn-block /
43
+ tenure boundaries (PoX cycles, locked-STX unlock, time-locked
44
+ redemptions, bridge contract finalization). See the
45
+ [`AdvanceBlocks` section in the README](./README.md#advanceblocks-burn-block-scenarios)
46
+ and the worked examples under `src/sample/`.
47
+ - **`getSimulationTip(sessionId, options?)`** — reads the current tip
48
+ of a simulation session. Returns the latest synthetic tip when at
49
+ least one `AdvanceBlocks` step has run (`synthetic: true`, includes
50
+ `vrf_seed` and `tenure_change`); otherwise returns the parent
51
+ metadata pinned at session start.
52
+ - **Typed `SimulationError`** thrown by every `simulation-api.ts`
53
+ fetch wrapper. Carries `.status` (HTTP code), `.marker` (typed
54
+ `'simulation_busy' | 'simulation_outdated' | null`), and `.body`
55
+ (raw upstream message). Branch on `.marker` to distinguish a
56
+ retry-the-same-request 409 from a start-a-new-session 410. Pre-0.8.0
57
+ threw plain `Error`; the message format
58
+ (`${operation} (HTTP ${status}): ${body}`) is preserved so log
59
+ scrapers keep working.
60
+ - **`src/sim-helpers.ts`** — session-bound wrappers: `callContract`,
61
+ `getStxBalance`, `getFtBalance`, `getNonce`, `readDataVar`. Uses
62
+ `simulationBatchReads` underneath so demos can lean on typed reads
63
+ without hand-rolling the batch envelope.
64
+ - **`src/transaction.ts`** — `setSender`, `buildUnsignedContractCallHex`,
65
+ `ftPrincipal`, `ContractCallTxArgs`. Extracted from `simulation.ts`
66
+ and the old `sample/_helpers.ts` so consumers can build unsigned tx
67
+ hex without instantiating `SimulationBuilder`.
68
+ - **`src/bitcoin.ts`** — SPV / merkle-proof / forged-tx primitives used
69
+ by the bridge demos: `sha256`, `sha256d`, `hexToBytes`, `bytesToHex`,
70
+ `p2wpkhScript`, `p2pkhScript`, `opReturnScript`, `forgeBitcoinTx`,
71
+ `buildBitcoinHeader`, `singleTxMerkleRoot`, `merkleProof`,
72
+ `verifyMerkleProof`. Pairs with `addAdvanceBlocks`'
73
+ `burn_header_hashes` override for sBTC / Brotocol bridge scenarios.
74
+ - **`addTenureExtend(cause?)`** now accepts an optional
75
+ `TenureExtendCause` (`'Extended' | 'ExtendedRuntime' | ...`) so
76
+ callers can reset a single SIP-034 cost dimension.
77
+ - **Six new vitest demos** under `src/sample/*-vitest.test.ts`:
78
+ `locked-stx`, `sbtc-deposit`, `brotocol-pegin`, `hbtc-vault`,
79
+ `zest-borrow`, `granite-leverage`. **The `src/sample` directory is
80
+ intentionally excluded from the npm tarball** to keep package size
81
+ down — browse them on
82
+ [GitHub](https://github.com/stxer/stxer-sdk/tree/master/src/sample).
83
+
84
+ ### Changed (breaking)
85
+
86
+ - **`addTenureExtend()` zero-arg now emits the modern wire shape**
87
+ (`{ TenureExtend: { cause: 'Extended' } }`) instead of the legacy
88
+ `{ TenureExtend: [] }`. The TypeScript signature is back-compat —
89
+ zero-arg call sites keep compiling — but anyone snapshotting JSON
90
+ request bodies will see the new shape. The server still parses the
91
+ legacy `[]` form for raw consumers.
92
+ - **`SimulationStepResult.TenureExtend` summaries always carry
93
+ `{ cause }`.** Previously typed as `[] | { cause }`; the server
94
+ normalizes legacy `[]` inputs to `{ cause: 'Extended' }` at parse
95
+ time, so the summary echo can never carry `[]`. The narrower type
96
+ is now reflected on `TenureExtendStepSummary.TenureExtend`.
97
+ - **HTTP responses now propagate as 4xx where they used to be masked
98
+ as 200.** The stxer-api proxy was forwarding upstream
99
+ `simulation_busy:` / `simulation_outdated:` / 4xx bodies with status
100
+ 200; the proxy now forwards the upstream status verbatim. SDK
101
+ callers are unaffected (the fetch wrappers already threw on `!ok`),
102
+ but raw-curl consumers reading 200 as success will now see
103
+ exceptions on those paths. The body content is unchanged.
104
+ - **`BatchReadsResult.tip` renamed to `BatchReadsResult.index_block_hash`**
105
+ to match the wire field name.
106
+ - **Numeric u64 / u128 fields are typed as `U64` / `U128`** (`number |
107
+ string`) instead of plain `number` to avoid silent precision loss
108
+ above 2^53. Affected fields: `TransactionReceipt.stx_burned`
109
+ (u128), `ExecutionCost.{read_count,read_length,write_count,
110
+ write_length,runtime}` (u64), `AdvancedBlockSummary.{stacks_height,
111
+ block_time,burn_block_time}` (u64), `SimulationTipResponse.
112
+ {stacks_height,block_time,burn_block_time}` (u64),
113
+ `SimulationMetadata.block_height` (u64), `SidecarTip.
114
+ {block_height,block_time,burn_block_time,tenure_height}` (u64),
115
+ `TenureCost.*` (u64), `AdvanceBlocksRequest.bitcoin_interval_secs`
116
+ and `AdvanceBlocksStepEcho.bitcoin_interval_secs` (u64),
117
+ `CreateSimulationRequest.block_height` /
118
+ `InstantSimulationRequest.block_height` (u64). Use `BigInt(x)` to
119
+ normalize before arithmetic.
120
+ - **`ClarityVersion` (the SDK string-literal type) renamed to
121
+ `ClarityVersionName`** to disambiguate from the numeric enum
122
+ re-exported by `@stacks/transactions`. The old name is preserved as
123
+ a deprecated alias for one major; use `ClarityVersionName` for
124
+ `ClarityAbi.clarity_version` matches and `@stacks/transactions`'s
125
+ numeric `ClarityVersion` enum (`ClarityVersion.Clarity4` → `4`) for
126
+ builder calls.
127
+
128
+ ### Server-side note
129
+
130
+ This release is paired with a server-side schema bump (`v=2`).
131
+ Simulation sessions created against an older simulator are rejected
132
+ with **HTTP 410 `simulation_outdated:`** after the cutover; SDK callers
133
+ see this as `SimulationError` with `marker: 'simulation_outdated'` and
134
+ should start a new session. Sim ids are random per-session and never
135
+ expected to persist across releases by design.
136
+
137
+ ## 0.7.0
138
+
139
+ See `git log` for prior releases. 0.7.0 was the last release without
140
+ `AdvanceBlocks` / `getSimulationTip` and treated all upstream errors as
141
+ plain `Error`.
package/README.md CHANGED
@@ -1,7 +1,11 @@
1
- # stxer SDK
1
+ # STXER SDK
2
2
 
3
3
  A powerful SDK for Stacks blockchain that provides transaction simulation, batch operations, contract AST parsing, and chain tip information.
4
4
 
5
+ Pairs with the [stxer-api](https://api.stxer.xyz) (mainnet) and
6
+ [testnet-api](https://testnet-api.stxer.xyz). See
7
+ [`CHANGELOG.md`](./CHANGELOG.md) for release notes.
8
+
5
9
  ## Installation
6
10
 
7
11
  ```bash
@@ -10,6 +14,30 @@ npm install stxer
10
14
  yarn add stxer
11
15
  ```
12
16
 
17
+ ## When to use what
18
+
19
+ Pick the right tool for the task — these are not interchangeable:
20
+
21
+ | Goal | Use |
22
+ |---|---|
23
+ | Wallet preview / pre-broadcast safety check (single tx, no session, **no debug tracing**) | [`instantSimulation`](#instant-simulation) |
24
+ | Quick scripted multi-step simulation, browsable in the [stxer debug UI](https://stxer.xyz) | [`SimulationBuilder`](#1-transaction-simulation-v2-api) |
25
+ | CI / Vitest contract test with custom assertions on per-step results | [`createSimulationSession`](#session-based-simulation) + [`submitSimulationSteps`](#session-based-simulation) + [`sim-helpers`](#sim-helpers-callcontract-getstxbalance-getftbalance-getnonce-readdatavar) |
26
+ | Burn-block / tenure scenarios (PoX cycles, locked-STX unlock, time-locked redemptions) | [`addAdvanceBlocks`](#advanceblocks-burn-block-scenarios) + [`getSimulationTip`](#advanceblocks-burn-block-scenarios) |
27
+ | Bridge / SPV peg-in (sBTC, Brotocol) | raw API + [`bitcoin.ts`](#bitcoin-spv--bridge-primitives) + [`transaction.ts`](#transaction-builders) — see the bridge demos in [`src/sample`](https://github.com/stxer/stxer-sdk/tree/master/src/sample) |
28
+ | Bulk read against current chain state | [`batchRead`](#batch-operations) (sidecar) or [`simulationBatchReads`](#session-based-simulation) (against a session's forked state) |
29
+ | Read-only contract calls with ABI decoding | [`callReadonly`](#clarity-api) / [`readVariable`](#clarity-api) / [`readMap`](#clarity-api) |
30
+
31
+ `instantSimulation` is intentionally transient — it has **no debug
32
+ tracing** and the simulation isn't viewable in the stxer UI. Use
33
+ sessions when you need either of those.
34
+
35
+ The bridge / `AdvanceBlocks` patterns deliberately bypass
36
+ `SimulationBuilder` because they need typed access to per-step results
37
+ (builder only returns the final `simulation_id`). The decision table
38
+ above is the canonical mapping; the in-tree bridge vitest demos are
39
+ the canonical worked examples.
40
+
13
41
  ## Features
14
42
 
15
43
  ### 1. Transaction Simulation (V2 API)
@@ -42,7 +70,7 @@ const simulationId = await SimulationBuilder.new({
42
70
  contract_name: 'my-contract',
43
71
  source_code: '(define-public (hello) (ok "world"))',
44
72
  deployer: 'SP...', // Optional: overrides default sender
45
- clarity_version: 4, // Optional: Clarity1, Clarity2, Clarity3, or Clarity4
73
+ clarity_version: 4, // 1 / 2 / 3 / 4 / 5 / 6 — or `ClarityVersion.Clarity6` from `@stacks/transactions`
46
74
  })
47
75
  .run();
48
76
 
@@ -51,10 +79,19 @@ const simulationId = await SimulationBuilder.new({
51
79
 
52
80
  #### Advanced V2 Step Types
53
81
 
54
- The SDK supports all V2 simulation step types:
82
+ The SDK supports all V2 simulation step types. Three of them — `Transaction`, `Eval`, and `EvalReadonly` (a `Reads` sub-type) — all execute Clarity but differ on side-effects, cost, and what they emit. Pick by **what you need to come out of the step**:
83
+
84
+ | Step | Side effects | Receipt + events | Fee / nonce | Post-conditions | When to use |
85
+ |---|---|---|---|---|---|
86
+ | `Transaction` | full tx execution | ✅ `TransactionReceipt` | ✅ | ✅ | Simulating a real user action; need a receipt; want PCs enforced |
87
+ | `Eval` | **write access** | ❌ | ❌ | ❌ | Stub state mid-session, run code with side-effects without tx ceremony |
88
+ | `EvalReadonly` (in `Reads`) | none — analyzer-enforced read-only | ❌ | ❌ | ❌ | Read-only contract calls / projections / custom expressions that need sender-context |
89
+
90
+ Cost order, cheapest first: `EvalReadonly` < `Eval` < `Transaction`. Use the cheapest variant that gives you what you need — running a `(var-get counter)` projection through `Eval` is wasteful when an `EvalReadonly` (or a plain `DataVar` read) gets the same answer for less.
55
91
 
56
92
  ```typescript
57
- import { SimulationBuilder, ClarityVersion } from 'stxer';
93
+ import { SimulationBuilder } from 'stxer';
94
+ import { ClarityVersion } from '@stacks/transactions';
58
95
 
59
96
  const simulationId = await SimulationBuilder.new()
60
97
  .withSender('SP...')
@@ -77,11 +114,11 @@ const simulationId = await SimulationBuilder.new()
77
114
  clarity_version: ClarityVersion.Clarity4,
78
115
  })
79
116
 
80
- // === Eval Steps ===
81
- // Read state
82
- .addEvalCode('SP...contract', '(var-get counter)')
83
-
84
- // Modify state
117
+ // === Eval Step (write access, no tx ceremony) ===
118
+ // Use Eval when you need to mutate contract state WITHOUT a real tx —
119
+ // no fee, no nonce, no post-conditions, no receipt; just the Clarity
120
+ // value or err. For pure reads, prefer the `Reads` batch below
121
+ // (`EvalReadonly` is cheaper and analyzer-enforced read-only).
85
122
  .addEvalCode('SP...contract', '(var-set counter u100)')
86
123
 
87
124
  // === SetContractCode Step ===
@@ -93,22 +130,61 @@ const simulationId = await SimulationBuilder.new()
93
130
  })
94
131
 
95
132
  // === Reads Batch Step ===
96
- // Batch multiple read operations in a single step
133
+ // Batch multiple read operations into one step. `EvalReadonly` is the
134
+ // sender-context read variant — analyzer-enforced no writes; use it
135
+ // for read-only contract calls / projections / custom expressions
136
+ // that need a specific sender principal in scope.
97
137
  .addReads([
98
138
  { DataVar: ['SP...contract', 'counter'] },
99
139
  { DataVar: ['SP...contract', 'enabled'] },
100
140
  { StxBalance: 'SP...' },
101
141
  { Nonce: 'SP...' },
102
142
  { EvalReadonly: ['SP...', '', 'SP...contract', '(get-counter)'] },
143
+ {
144
+ EvalReadonly: [
145
+ 'SP...',
146
+ '',
147
+ 'SP...oracle',
148
+ "(contract-call? .oracle get-value 'STX-USD)",
149
+ ],
150
+ },
103
151
  ])
104
152
 
105
153
  // === TenureExtend Step ===
106
- // Extend tenure (resets execution cost)
107
- .addTenureExtend()
154
+ // Extend tenure (resets execution cost). Defaults to 'Extended'
155
+ // (full reset); pass a SIP-034 cause to reset only one dimension.
156
+ .addTenureExtend('ExtendedRuntime')
157
+
158
+ // === AdvanceBlocks Step ===
159
+ // Synthesize bitcoin and stacks blocks on top of the pinned parent
160
+ // tip — used to model burn-block / tenure boundaries (bridge
161
+ // contracts, time-locked redemptions, locked-STX unlock).
162
+ .addAdvanceBlocks({ bitcoin_blocks: 1, stacks_blocks_per_bitcoin: 1 })
108
163
 
109
164
  .run();
110
165
  ```
111
166
 
167
+ #### Schema cutover (v0.8.0)
168
+
169
+ The 0.8.0 release coincides with a server-side schema bump for
170
+ simulation sessions. **Existing simulation session ids started before
171
+ the upgrade return `HTTP 410 Gone`** — start a fresh session via
172
+ `SimulationBuilder.run()` / `createSimulationSession()` to get a
173
+ schema-v=2 id. Sim ids are random per-call and not persisted across
174
+ releases by design, so this only affects in-flight callers.
175
+
176
+ The fetch wrappers in `simulation-api` now throw a typed
177
+ `SimulationError` (with `status` and `marker` fields) on non-2xx
178
+ responses; `marker` is `'simulation_busy'` (HTTP 409),
179
+ `'simulation_outdated'` (HTTP 410), or `null`. Pre-0.8.0 the SDK
180
+ threw a plain `Error` whose message embedded the body — message format
181
+ is unchanged so existing log scrapers keep working.
182
+
183
+ `addTenureExtend(cause?)` now accepts an optional `TenureExtendCause`.
184
+ The on-the-wire request shape is `{ TenureExtend: { cause } }`; the
185
+ legacy `{ TenureExtend: [] }` shape stays parseable on the server but
186
+ the SDK builder no longer emits it.
187
+
112
188
  #### Reads Batch Sub-Types
113
189
 
114
190
  The `Reads` step supports multiple read operation types:
@@ -170,6 +246,7 @@ import {
170
246
  createSimulationSession,
171
247
  submitSimulationSteps,
172
248
  getSimulationResult,
249
+ getSimulationTip,
173
250
  simulationBatchReads
174
251
  } from 'stxer';
175
252
 
@@ -188,18 +265,25 @@ const stepResults = await submitSimulationSteps(sessionId, {
188
265
  { DataVar: ['SP...contract', 'my-var'] },
189
266
  { StxBalance: 'SP...' }
190
267
  ]},
191
- { TenureExtend: [] }
268
+ { TenureExtend: { cause: 'Extended' } },
269
+ { AdvanceBlocks: { bitcoin_blocks: 1, stacks_blocks_per_bitcoin: 1 } }
192
270
  ]
193
271
  });
194
272
 
195
273
  console.log(`Executed ${stepResults.steps.length} steps`);
196
274
 
197
- // 3. Get full simulation results
275
+ // 3. Inspect the current tip — `synthetic` flips to `true` once
276
+ // `AdvanceBlocks` has run; `vrf_seed` and `tenure_change` are
277
+ // populated only on synthetic tips.
278
+ const tip = await getSimulationTip(sessionId);
279
+ console.log(tip.synthetic, tip.stacks_height, tip.burn_height);
280
+
281
+ // 4. Get full simulation results
198
282
  const result = await getSimulationResult(sessionId);
199
283
  console.log(result.metadata);
200
284
  console.log(result.steps);
201
285
 
202
- // 4. Batch reads from simulation state
286
+ // 5. Batch reads from simulation state
203
287
  const reads = await simulationBatchReads(sessionId, {
204
288
  vars: [['SP...contract', 'my-var']],
205
289
  maps: [['SP...contract', 'my-map', '0x...']],
@@ -286,7 +370,7 @@ console.log(ast.abi);
286
370
  const parsed = await parseContract({
287
371
  contractId: 'SP...contract-name',
288
372
  sourceCode: '(define-public (hello) (ok "world"))',
289
- clarityVersion: '4', // Optional: '1' | '2' | '3' | '4'
373
+ clarityVersion: '4', // Optional: '1' | '2' | '3' | '4' | '5' | '6'
290
374
  epoch: 'Epoch33' // Optional
291
375
  });
292
376
  ```
@@ -460,7 +544,15 @@ const ast = await getContractAST({
460
544
 
461
545
  ## Samples
462
546
 
463
- Runnable end-to-end examples live in [`src/sample/`](https://github.com/stxer/stxer-sdk/tree/master/src/sample) on GitHub. Samples track `master` and may evolve faster than published SDK versions; if you pin a specific SDK version, browse the matching git tag.
547
+ Runnable end-to-end examples live in
548
+ [`src/sample/`](https://github.com/stxer/stxer-sdk/tree/master/src/sample)
549
+ on GitHub. **The `src/sample/` directory is intentionally excluded from
550
+ the published npm tarball** to keep the package size down — clone the
551
+ repo to run them locally. Samples track `master` and may evolve faster
552
+ than published SDK versions; if you pin a specific SDK version, browse
553
+ the matching git tag.
554
+
555
+ ### Core flows
464
556
 
465
557
  | Sample | What it demonstrates |
466
558
  |---|---|
@@ -472,72 +564,161 @@ Runnable end-to-end examples live in [`src/sample/`](https://github.com/stxer/st
472
564
  | [`verify-types.ts`](https://github.com/stxer/stxer-sdk/blob/master/src/sample/verify-types.ts) | Runtime type-drift detector. Hits every endpoint, dereferences every documented field, asserts each value's runtime type matches the declared SDK type. Run it before publishing your client after upstream changes. |
473
565
  | [`read.ts`](https://github.com/stxer/stxer-sdk/blob/master/src/sample/read.ts) | `batchRead`, `BatchProcessor`, and the high-level `clarity-api` helpers (`callReadonly`, `readVariable`, `readMap`). |
474
566
 
567
+ ### `AdvanceBlocks` + bridge / time-locked scenarios (0.8.0)
568
+
569
+ The vitest demos below are the canonical reference for the new
570
+ `addAdvanceBlocks` / `getSimulationTip` / `bitcoin.ts` / `sim-helpers`
571
+ patterns. All target real **mainnet** contracts at pinned settled
572
+ blocks — every assertion is exact.
573
+
574
+ | Sample | What it demonstrates |
575
+ |---|---|
576
+ | [`locked-stx-vitest.test.ts`](https://github.com/stxer/stxer-sdk/blob/master/src/sample/locked-stx-vitest.test.ts) | PoX-4 locked-STX unlock: read `(stx-account ...)`, attempt pre-unlock transfer (`err u1`), `addAdvanceBlocks` past `unlock_height`, transfer the now-released amount. Includes the parent-burn-probe trick (advance with `bitcoin_blocks: 0` first to learn the parent burn height before computing N). |
577
+ | [`sbtc-deposit-vitest.test.ts`](https://github.com/stxer/stxer-sdk/blob/master/src/sample/sbtc-deposit-vitest.test.ts) | sBTC bridge deposit, end-to-end. Uses `forgeBitcoinTx` + `AdvanceBlocks { burn_header_hashes: ... }` so `(get-burn-block-info? header-hash …)` resolves to a value we control. |
578
+ | [`brotocol-pegin-vitest.test.ts`](https://github.com/stxer/stxer-sdk/blob/master/src/sample/brotocol-pegin-vitest.test.ts) | Brotocol BTC peg-in. Forges a Bitcoin tx + 2-tx Merkle proof + 80-byte block header; calls `finalize-peg-in-0`; asserts mint and replay rejection. The full `bitcoin.ts` SPV pipeline. |
579
+ | [`hbtc-vault-vitest.test.ts`](https://github.com/stxer/stxer-sdk/blob/master/src/sample/hbtc-vault-vitest.test.ts) | hBTC yield-bearing vault: deposit, request-redeem, `AdvanceBlocks +1 day` to cross the rewarder window, `log-reward`, fund-claim, `AdvanceBlocks +3 days` to clear the cooldown, redeem, transfer. Exact yield arithmetic. |
580
+ | [`zest-borrow-vitest.test.ts`](https://github.com/stxer/stxer-sdk/blob/master/src/sample/zest-borrow-vitest.test.ts) | Zest V2 lend / borrow / repay with a forged Pyth v4 price update. Patches `pyth-pnau-decoder-v3` via `SetContractCode` to bypass the Wormhole quorum / Merkle / data-source checks; `AdvanceBlocks +1` so storage's freshness gate has a synthetic-tip block_time. |
581
+ | [`granite-leverage-vitest.test.ts`](https://github.com/stxer/stxer-sdk/blob/master/src/sample/granite-leverage-vitest.test.ts) | Granite leverage open with a forged Pyth v3 price update. Same patch-decoder pattern as Zest, applied through Granite's gl-api → gl-oracle → pyth-oracle-v3 chain. |
582
+
475
583
  Run any of them locally by cloning the SDK repo and:
476
584
 
477
585
  ```bash
478
586
  pnpm install
479
587
  pnpm sample:counter # or sample:instant / failure-modes / batch-categories / verify-types
480
- pnpm sample:vitest # run the Vitest contract-test sample
588
+ pnpm sample:vitest # run the Vitest sample suite (counter + 6 bridge / locked-STX demos)
481
589
  ```
482
590
 
483
591
  ## API Reference
484
592
 
485
593
  ### Constants
486
594
 
487
- - `STXER_API_MAINNET` - Mainnet API endpoint (https://api.stxer.xyz)
488
- - `STXER_API_TESTNET` - Testnet API endpoint (https://testnet-api.stxer.xyz)
489
- - `DEFAULT_STXER_API` - Default API endpoint (same as STXER_API_MAINNET)
595
+ - `STXER_API_MAINNET` Mainnet API endpoint (`https://api.stxer.xyz`)
596
+ - `STXER_API_TESTNET` Testnet API endpoint (`https://testnet-api.stxer.xyz`)
597
+ - `DEFAULT_STXER_API` Default API endpoint (same as `STXER_API_MAINNET`)
490
598
 
491
- ### Simulation Builder (High-Level)
599
+ ### Simulation Builder (high-level)
492
600
 
493
- - `SimulationBuilder.new(options)` - Create a new simulation builder
494
- - `builder.useBlockHeight(height)` - Set block height for simulation
495
- - `builder.withSender(address)` - Set default sender address
601
+ - `SimulationBuilder.new(options)` Create a new simulation builder
602
+ - `builder.useBlockHeight(height)` Pin the parent block to fork at
603
+ - `builder.withSender(address)` Default sender address for unsigned txs
496
604
 
497
605
  **Transaction Steps:**
498
- - `builder.addContractCall(params)` - Add a contract call step
499
- - `builder.addSTXTransfer(params)` - Add an STX transfer step
500
- - `builder.addContractDeploy(params)` - Add a contract deployment step
606
+ - `builder.addContractCall(params)` Add a contract call step
607
+ - `builder.addSTXTransfer(params)` Add an STX transfer step
608
+ - `builder.addContractDeploy(params)` Add a contract deployment step
501
609
 
502
610
  **V2 Step Types:**
503
- - `builder.addEvalCode(contractId, code)` - Add arbitrary code evaluation (with state modification)
504
- - `builder.addSetContractCode(params)` - Directly set contract code without transaction
505
- - `builder.addReads(reads[])` - Batch read operations in a single step
506
- - `builder.addTenureExtend()` - Extend tenure (resets execution cost)
611
+ - `builder.addEvalCode(contractId, code)` Arbitrary code evaluation with write access
612
+ - `builder.addSetContractCode(params)` Replace contract code without a transaction
613
+ - `builder.addReads(reads[])` Batch read operations interleaved with other steps
614
+ - `builder.addTenureExtend(cause?)` Reset execution cost. Default `'Extended'` resets all dimensions; pass an explicit `TenureExtendCause` to reset only one SIP-034 dimension
615
+ - `builder.addAdvanceBlocks(request)` — *(0.8.0)* Synthesize bitcoin / stacks blocks on the fork. See the [`AdvanceBlocks` section](#advanceblocks-burn-block-scenarios)
507
616
 
508
617
  **Execution:**
509
- - `builder.run()` - Execute the simulation and return simulation ID
510
-
511
- ### Programmatic Simulation APIs (Low-Level)
512
-
513
- **Instant Simulation:**
514
- - `instantSimulation(request, options?)` - Simulate a single transaction without session
515
-
516
- **Session Management:**
517
- - `createSimulationSession(options?, apiOptions?)` - Create a new simulation session
518
- - `submitSimulationSteps(sessionId, request, options?)` - Submit steps to a session
519
- - `getSimulationResult(sessionId, options?)` - Get full simulation results
520
- - `simulationBatchReads(sessionId, request, options?)` - Batch reads from simulation state
521
-
522
- ### Chain Tip
523
-
524
- - `getTip(options?)` - Fetch current chain tip information
618
+ - `builder.run()` Submit the session and return the `simulation_id`. Note: returns only the id; if you need typed per-step results, use the low-level API + `sim-helpers` instead
619
+
620
+ ### Programmatic simulation APIs (low-level)
621
+
622
+ **Instant simulation:**
623
+ - `instantSimulation(request, options?)` Simulate a single transaction without a session. Transient: **no debug tracing**, not viewable in the stxer UI
624
+
625
+ **Session management:**
626
+ - `createSimulationSession(options?, apiOptions?)` Create a new session, returns `id: string`
627
+ - `submitSimulationSteps(sessionId, request, options?)` Submit one or more steps; returns typed per-step results
628
+ - `getSimulationResult(sessionId, options?)` Get full session results (metadata + step summaries)
629
+ - `getSimulationTip(sessionId, options?)` *(0.8.0)* Read the current synthetic tip after `AdvanceBlocks` steps. See the [`AdvanceBlocks` section](#advanceblocks-burn-block-scenarios)
630
+ - `simulationBatchReads(sessionId, request, options?)` — Batch-read the session's forked state without consuming a step slot
631
+
632
+ **Errors:**
633
+ - `class SimulationError extends Error` — *(0.8.0)* Typed error thrown by every fetch wrapper. Fields:
634
+ - `.status: number` — HTTP status (409 retry, 410 start-new-session, 400 validation, 404 not found, ...)
635
+ - `.marker: 'simulation_busy' | 'simulation_outdated' | null` — server-side classification
636
+ - `.body: string` — raw upstream message
637
+ - `.message: string` — formatted as `"${operation} (HTTP ${status}): ${body}"`
638
+ - `type SimulationErrorMarker` — *(0.8.0)* Exported union for `.marker`
639
+
640
+ ### Sim helpers (`callContract`, `getStxBalance`, `getFtBalance`, `getNonce`, `readDataVar`)
641
+
642
+ *New in 0.8.0.* Session-bound wrappers around `simulationBatchReads`
643
+ that produce typed reads without hand-rolling the batch envelope. Useful
644
+ for vitest-style tests that interleave reads with mutating steps.
645
+
646
+ - `callContract(sessionId, args, options?)` — Build an unsigned contract-call tx, submit it as one step, decode the result. Returns `{ result, vmError, pcAborted, events, txid, executionCost }` for direct `expect(...)` assertions
647
+ - `getStxBalance(sessionId, principal, options?): Promise<bigint>`
648
+ - `getFtBalance(sessionId, contractAndToken, principal, options?): Promise<bigint>`
649
+ - `getNonce(sessionId, principal, options?): Promise<bigint>` — session-bound (do not confuse with the Hiro-API `getOnChainNonce` in `src/sample/_helpers.ts`)
650
+ - `readDataVar(sessionId, contractId, varName, options?)` — Returns the deserialized Clarity value
651
+ - `parseSimulationEvent(eventJson)` — Parse one entry from `TransactionReceipt.events[]` into a typed `SimulationEvent`
652
+
653
+ ### Transaction builders
654
+
655
+ *New in 0.8.0.* Build unsigned transaction hex without `SimulationBuilder`
656
+ — useful when you want to control sender via the simulator's
657
+ no-signature trust model.
658
+
659
+ - `setSender(tx, sender)` — Rewrite an unsigned `StacksTransactionWire`'s spending condition so the simulator treats `sender` as the origin. Mutates and returns `tx`
660
+ - `buildUnsignedContractCallHex(args)` — `args: { sender, contract, functionName, functionArgs, fee?, nonce? }` → hex string
661
+ - `ftPrincipal(contractAndToken: 'SP....contract::token-name'): ClarityValue` — Build a `(contract-of (use-trait <ft-trait>))` literal for FT contract calls
662
+
663
+ ### Bitcoin SPV / bridge primitives
664
+
665
+ *New in 0.8.0.* Forge Bitcoin transactions and SPV proofs for bridge
666
+ peg-in scenarios. Pairs with `addAdvanceBlocks`'
667
+ `burn_header_hashes` override so on-chain
668
+ `(get-burn-block-info? header-hash …)` resolves to a value you control.
669
+
670
+ - `forgeBitcoinTx(opts)` — Build a Bitcoin tx with chosen inputs / outputs / OP_RETURN. Returns `{ rawTx, txid, inputs, outputs }`
671
+ - `buildBitcoinHeader(opts)` — 80-byte BTC block header with chosen prev-hash / merkle root / time / bits / nonce. Returns `{ rawHeader, hash }` where `hash` is the double-sha256 (display order, ready for `burn_header_hashes`)
672
+ - `singleTxMerkleRoot(txid: Uint8Array): Uint8Array` — 1-tx merkle root (the txid itself)
673
+ - `merkleProof(txids, txIndex): { hashes: Uint8Array[], treeDepth: number }`
674
+ - `verifyMerkleProof(txid, proof, root): boolean`
675
+ - `p2wpkhScript(pubKeyHash20)` / `p2pkhScript(pubKeyHash20)` / `opReturnScript(data)` — scriptPubKey builders
676
+ - `sha256(data)` / `sha256d(data)` / `hexToBytes(s)` / `bytesToHex(b)`
677
+
678
+ ### `AdvanceBlocks` (burn-block scenarios)
679
+
680
+ *New in 0.8.0.* Synthesize bitcoin / stacks blocks on top of the
681
+ simulation's pinned parent tip — used to model burn-block / tenure
682
+ boundaries (PoX cycles, locked-STX unlock, time-locked redemptions,
683
+ bridge contract finalization).
684
+
685
+ - `builder.addAdvanceBlocks(request)` — builder method
686
+ - `submitSimulationSteps(id, { steps: [{ AdvanceBlocks: ... }] }, opts)` — raw step
687
+ - `getSimulationTip(id, opts?)` — read the current synthetic tip; `synthetic: true` after at least one `AdvanceBlocks` step has run
688
+ - `AdvanceBlocksRequest` (key fields):
689
+ - `bitcoin_blocks: number` — burn blocks to synthesize
690
+ - `stacks_blocks_per_bitcoin: number`
691
+ - `bitcoin_interval_secs?: U64` — burn-block-time delta; defaults to 600s
692
+ - `burn_header_hashes?: Record<string, string>` — per-burn-index hash override (32-byte hex), keyed by 0-based index
693
+ - `pox_addrs?: Record<string, [PoxAddrInput[], U128]>` — per-burn-index PoX-payout override
694
+ - `vrf_seeds?: Record<string, string>` — per-burn-index VRF-seed override
695
+
696
+ For the canonical worked examples — including the parent-burn-probe
697
+ trick for computing N, the `burn_header_hashes` + Merkle-proof bridge
698
+ pattern, and the `SetContractCode` + `AdvanceBlocks` Pyth-decoder
699
+ pattern — see the
700
+ [bridge / time-locked vitest demos](#advanceblocks--bridge--time-locked-scenarios-080)
701
+ on GitHub.
702
+
703
+ ### Chain tip
704
+
705
+ - `getTip(options?)` — Global mainnet chain tip (sidecar). Distinct from `getSimulationTip` (per-session synthetic tip)
525
706
 
526
707
  ### Contract AST
527
708
 
528
- - `getContractAST({ contractId, stxerApi? })` - Fetch on-chain contract AST
529
- - `parseContract({ sourceCode, contractId, clarityVersion?, epoch?, stxerApi? })` - Parse source code to AST
709
+ - `getContractAST({ contractId, stxerApi? })` Fetch on-chain contract AST
710
+ - `parseContract({ sourceCode, contractId, clarityVersion?, epoch?, stxerApi? })` Parse source code to AST. `clarityVersion` is `ClarityVersionName` (`'Clarity1' | ... | 'Clarity6'`) — distinct from `@stacks/transactions`'s numeric `ClarityVersion` enum
530
711
 
531
- ### Batch Operations
712
+ ### Batch operations
532
713
 
533
- - `batchRead(reads, options?)` - Execute batch read operations
534
- - `new BatchProcessor({ stxerAPIEndpoint?, batchDelayMs })` - Create a batch processor
714
+ - `batchRead(reads, options?)` Execute batch read operations against current chain state via the sidecar
715
+ - `new BatchProcessor({ stxerAPIEndpoint?, batchDelayMs })` — Queue-based batch processor for high-throughput read pipelines
535
716
 
536
717
  ### Clarity API
537
718
 
538
- - `callReadonly(params)` - Call a read-only contract function
539
- - `readVariable(params)` - Read a contract variable
540
- - `readMap(params)` - Read from a contract map
719
+ - `callReadonly(params)` Call a read-only contract function
720
+ - `readVariable(params)` Read a contract variable
721
+ - `readMap(params)` Read from a contract map
541
722
 
542
723
  ## Support
543
724
 
package/dist/ast.d.ts CHANGED
@@ -20,7 +20,7 @@ export declare function getContractAST(options: GetContractAstOptions): Promise<
20
20
  export interface ParseContractOptions extends AstOptions {
21
21
  sourceCode: string;
22
22
  contractId: string;
23
- clarityVersion?: '1' | '2' | '3' | '4';
23
+ clarityVersion?: '1' | '2' | '3' | '4' | '5' | '6';
24
24
  epoch?: ClarityEpoch;
25
25
  }
26
26
  /**