stxer 0.6.1 → 0.7.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/src/types.ts CHANGED
@@ -194,14 +194,62 @@ export interface ExecutionCost {
194
194
  runtime: number;
195
195
  }
196
196
 
197
+ /**
198
+ * Receipt for a transaction that the engine executed to completion.
199
+ *
200
+ * "Successful execution" does NOT imply contract-level success. Four
201
+ * failure signals to check, in this order:
202
+ * 1. Outer `Err` on `Result.Transaction` — engine could not run the tx
203
+ * at all (deserialization failure etc.); no receipt is produced.
204
+ * 2. `post_condition_aborted: true` — execution ran, post-condition
205
+ * tripped, state was rolled back.
206
+ * 3. `vm_error: string` (without `post_condition_aborted`) — Clarity
207
+ * VM raised a runtime error or static analysis failed.
208
+ * 4. `(err uX)` inside `result` — contract returned a Clarity error
209
+ * response. Application-level; NOT signalled by any field above.
210
+ * Decode `result` to detect.
211
+ *
212
+ * `post_condition_aborted` and `vm_error` are NOT independent: when a
213
+ * PC trips the upstream sets `post_condition_aborted: true` AND writes
214
+ * the PC abort reason into `vm_error` as a side effect. The reverse is
215
+ * not true — `vm_error` alone (with `post_condition_aborted: false`)
216
+ * means a VM / analysis failure that is not a PC abort.
217
+ */
197
218
  export interface TransactionReceipt {
219
+ /**
220
+ * Clarity return value, SIP-005 hex-serialized. For contract-call txs
221
+ * this includes the `(ok ...)` / `(err ...)` response wrapper —
222
+ * Clarity-level `(err uX)` lives here, NOT on `vm_error` or the outer
223
+ * `Err`.
224
+ */
198
225
  result: string;
199
226
  stx_burned: number;
200
227
  tx_index: number;
228
+ /**
229
+ * Error message from the upstream Clarity VM. `null` when the tx had
230
+ * no VM-level issue. When `post_condition_aborted` is `true` this
231
+ * field is also populated with the PC abort reason — check
232
+ * `post_condition_aborted` first to disambiguate.
233
+ */
201
234
  vm_error: string | null;
235
+ /**
236
+ * `true` when one or more post-conditions failed and the tx was
237
+ * aborted. Implies `vm_error` is also set (to the abort reason); the
238
+ * reverse does not hold.
239
+ */
202
240
  post_condition_aborted: boolean;
241
+ /** Wall-clock simulation time in milliseconds. */
203
242
  costs: number;
204
243
  execution_cost: ExecutionCost;
244
+ /**
245
+ * Events emitted during execution (contract logs, STX transfers,
246
+ * FT/NFT events, etc.). Each entry is a JSON-encoded **string** —
247
+ * call `JSON.parse(events[i])` to get the event object. Items are
248
+ * NOT JSON objects in the array.
249
+ *
250
+ * For typed access, use {@link parseSimulationEvent} or cast:
251
+ * `JSON.parse(events[i]) as SimulationEvent`.
252
+ */
205
253
  events: string[];
206
254
  }
207
255
 
@@ -213,33 +261,226 @@ export interface TransactionErrResult {
213
261
  Err: string;
214
262
  }
215
263
 
264
+ // =============================================================================
265
+ // Simulation Events
266
+ // =============================================================================
267
+ // Wire format for entries inside `TransactionReceipt.events[]` (each entry
268
+ // there is a JSON-encoded string carrying one of these payloads).
269
+ //
270
+ // Source of truth: `clarity/src/vm/events.rs` in
271
+ // https://github.com/stacks-network/stacks-core —
272
+ // `StacksTransactionEvent::json_serialize`. These types intentionally
273
+ // differ from `@stacks/stacks-blockchain-api-types.TransactionEvent`,
274
+ // which describes Hiro API responses with a different envelope.
275
+ //
276
+ // Numeric fields that the rust source emits via `format!("{}", u128)` /
277
+ // `format!("{}", u64)` are typed as `string`, not `number` — the wire
278
+ // carries them as decimal strings to preserve full precision.
279
+
280
+ /** Common envelope present on every event variant. */
281
+ interface SimulationEventBase {
282
+ /** Hex txid with leading `0x`. */
283
+ txid: string;
284
+ event_index: number;
285
+ /**
286
+ * `true` when the event was emitted from successfully committed code.
287
+ * `false` when the tx was rolled back (post-condition abort, vm_error).
288
+ * Tracks rust `tx_receipt.vm_error.is_none() && !post_condition_aborted`.
289
+ */
290
+ committed: boolean;
291
+ }
292
+
293
+ /** Payload for `print` events and other contract-emitted events. */
294
+ export interface SmartContractEventData {
295
+ /** `<address>.<contract_name>` of the contract that emitted the event. */
296
+ contract_identifier: string;
297
+ /** Topic key — `"print"` for `(print …)` calls. */
298
+ topic: string;
299
+ /**
300
+ * Structured Clarity Value JSON (the rust `Value` enum's serde output).
301
+ * The shape is complex and varies by Clarity type; prefer `raw_value`
302
+ * for typed decoding.
303
+ */
304
+ value: unknown;
305
+ /**
306
+ * SIP-005 hex of the value, with leading `0x`. Pass to
307
+ * `deserializeCV()` from `@stacks/transactions` for typed decoding.
308
+ */
309
+ raw_value: string;
310
+ }
311
+
312
+ export interface StxTransferEventData {
313
+ sender: string;
314
+ recipient: string;
315
+ /** uSTX amount as a decimal string (rust serializes u128 via Display). */
316
+ amount: string;
317
+ /** Hex memo, possibly empty. */
318
+ memo: string;
319
+ }
320
+
321
+ export interface StxMintEventData {
322
+ recipient: string;
323
+ amount: string;
324
+ }
325
+
326
+ export interface StxBurnEventData {
327
+ sender: string;
328
+ amount: string;
329
+ }
330
+
331
+ export interface StxLockEventData {
332
+ locked_amount: string;
333
+ /** Decimal string (rust serializes u64 via Display). */
334
+ unlock_height: string;
335
+ locked_address: string;
336
+ contract_identifier: string;
337
+ }
338
+
339
+ export interface NftTransferEventData {
340
+ /** `<contract_id>::<asset_name>`. */
341
+ asset_identifier: string;
342
+ sender: string;
343
+ recipient: string;
344
+ value: unknown;
345
+ raw_value: string;
346
+ }
347
+
348
+ export interface NftMintEventData {
349
+ asset_identifier: string;
350
+ recipient: string;
351
+ value: unknown;
352
+ raw_value: string;
353
+ }
354
+
355
+ export interface NftBurnEventData {
356
+ asset_identifier: string;
357
+ sender: string;
358
+ value: unknown;
359
+ raw_value: string;
360
+ }
361
+
362
+ export interface FtTransferEventData {
363
+ asset_identifier: string;
364
+ sender: string;
365
+ recipient: string;
366
+ amount: string;
367
+ }
368
+
369
+ export interface FtMintEventData {
370
+ asset_identifier: string;
371
+ recipient: string;
372
+ amount: string;
373
+ }
374
+
375
+ export interface FtBurnEventData {
376
+ asset_identifier: string;
377
+ sender: string;
378
+ amount: string;
379
+ }
380
+
381
+ /**
382
+ * Discriminated union of every event variant the simulator emits.
383
+ * The `type` discriminator names the per-variant payload key — e.g.
384
+ * `type: 'contract_event'` carries the payload at `event.contract_event`.
385
+ *
386
+ * ```ts
387
+ * const event = parseSimulationEvent(receipt.events[0]);
388
+ * if (event.type === 'contract_event') {
389
+ * // event.contract_event.{contract_identifier, topic, raw_value, value}
390
+ * }
391
+ * ```
392
+ */
393
+ export type SimulationEvent =
394
+ | (SimulationEventBase & {
395
+ type: 'contract_event';
396
+ contract_event: SmartContractEventData;
397
+ })
398
+ | (SimulationEventBase & {
399
+ type: 'stx_transfer_event';
400
+ stx_transfer_event: StxTransferEventData;
401
+ })
402
+ | (SimulationEventBase & {
403
+ type: 'stx_mint_event';
404
+ stx_mint_event: StxMintEventData;
405
+ })
406
+ | (SimulationEventBase & {
407
+ type: 'stx_burn_event';
408
+ stx_burn_event: StxBurnEventData;
409
+ })
410
+ | (SimulationEventBase & {
411
+ type: 'stx_lock_event';
412
+ stx_lock_event: StxLockEventData;
413
+ })
414
+ | (SimulationEventBase & {
415
+ type: 'nft_transfer_event';
416
+ nft_transfer_event: NftTransferEventData;
417
+ })
418
+ | (SimulationEventBase & {
419
+ type: 'nft_mint_event';
420
+ nft_mint_event: NftMintEventData;
421
+ })
422
+ | (SimulationEventBase & {
423
+ type: 'nft_burn_event';
424
+ nft_burn_event: NftBurnEventData;
425
+ })
426
+ | (SimulationEventBase & {
427
+ type: 'ft_transfer_event';
428
+ ft_transfer_event: FtTransferEventData;
429
+ })
430
+ | (SimulationEventBase & {
431
+ type: 'ft_mint_event';
432
+ ft_mint_event: FtMintEventData;
433
+ })
434
+ | (SimulationEventBase & {
435
+ type: 'ft_burn_event';
436
+ ft_burn_event: FtBurnEventData;
437
+ });
438
+
439
+ /** Convenience parser for `TransactionReceipt.events[i]`. */
440
+ export function parseSimulationEvent(raw: string): SimulationEvent {
441
+ return JSON.parse(raw) as SimulationEvent;
442
+ }
443
+
216
444
  // Read step types
217
445
  export interface MapEntryStep {
218
- MapEntry: [string, string, string]; // [contract_id, map_name, key_hex]
446
+ MapEntry: [contract_id: string, map_name: string, key_hex: string];
219
447
  }
220
448
 
221
449
  export interface DataVarStep {
222
- DataVar: [string, string]; // [contract_id, variable_name]
450
+ DataVar: [contract_id: string, variable_name: string];
223
451
  }
224
452
 
225
453
  export interface EvalReadonlyStep {
226
- EvalReadonly: [string, string, string, string]; // [sender, sponsor, contract_id, code]
454
+ /** `sponsor` is `""` (empty string) when there is no sponsor. */
455
+ EvalReadonly: [
456
+ sender: string,
457
+ sponsor: string,
458
+ contract_id: string,
459
+ code: string,
460
+ ];
227
461
  }
228
462
 
229
463
  export interface StxBalanceStep {
230
- StxBalance: string; // principal
464
+ /** Principal whose STX balance to read. */
465
+ StxBalance: string;
231
466
  }
232
467
 
233
468
  export interface FtBalanceStep {
234
- FtBalance: [string, string, string]; // [contract_id, token_name, principal]
469
+ /**
470
+ * Reads the FT balance via three separate parameters. Note: the batch
471
+ * `ft_balance` field on `SimulationBatchReadsRequest` uses a different
472
+ * `<contract_id>::<token_name>` combined identifier shape.
473
+ */
474
+ FtBalance: [contract_id: string, token_name: string, principal: string];
235
475
  }
236
476
 
237
477
  export interface FtSupplyStep {
238
- FtSupply: [string, string]; // [contract_id, token_name]
478
+ FtSupply: [contract_id: string, token_name: string];
239
479
  }
240
480
 
241
481
  export interface NonceStep {
242
- Nonce: string; // principal
482
+ /** Principal whose nonce to read. */
483
+ Nonce: string;
243
484
  }
244
485
 
245
486
  export type ReadStep =
@@ -261,9 +502,27 @@ export interface ReadErrResult {
261
502
 
262
503
  export type ReadResult = ReadOkResult | ReadErrResult;
263
504
 
505
+ /**
506
+ * Per-step result returned by `POST /devtools/v2/simulations/{id}` (the
507
+ * "submit steps" endpoint). Mirrors the rust `RunSimulationStepResult`
508
+ * enum — externally tagged, exactly one variant key present.
509
+ *
510
+ * Distinct from `SimulationStepSummary`, which is what
511
+ * `GET /devtools/v2/simulations/{id}` returns and includes the original
512
+ * step input alongside the result.
513
+ */
514
+ export type SimulationStepResult =
515
+ | { Transaction: TransactionOkResult | TransactionErrResult }
516
+ | { Eval: { Ok: string } | { Err: string } }
517
+ | { SetContractCode: { Ok: null } | { Err: string } }
518
+ | { Reads: ReadResult[] }
519
+ | { TenureExtend: ExecutionCost };
520
+
264
521
  // Simulation step types (summary format from GET /devtools/v2/simulations/{id})
265
522
  export interface TransactionStepSummary {
266
- Transaction: string; // tx hex
523
+ /** Transaction serialized to hex. */
524
+ Transaction: string;
525
+ /** Hex-encoded txid. Empty string `""` when the tx failed engine-level. */
267
526
  TxId: string;
268
527
  Result: {
269
528
  Transaction: TransactionOkResult | TransactionErrResult;
@@ -279,14 +538,15 @@ export interface ReadsStepSummary {
279
538
  }
280
539
 
281
540
  export interface SetContractCodeStepSummary {
282
- SetContractCode: [string, string, number]; // [contract_id, code, clarity_version]
541
+ SetContractCode: [contract_id: string, code: string, clarity_version: number];
283
542
  Result: {
284
543
  SetContractCode: { Ok: null } | { Err: string };
285
544
  };
286
545
  }
287
546
 
288
547
  export interface EvalStepSummary {
289
- Eval: [string, string, string, string]; // [sender, sponsor, contract_id, code]
548
+ /** `sponsor` is `""` (empty string) when there is no sponsor. */
549
+ Eval: [sender: string, sponsor: string, contract_id: string, code: string];
290
550
  Result: {
291
551
  Eval: { Ok: string } | { Err: string };
292
552
  };
@@ -307,7 +567,6 @@ export type SimulationStepSummary =
307
567
 
308
568
  // Simulation metadata
309
569
  export interface SimulationMetadata {
310
- ast_rules: 0 | 1;
311
570
  block_height: number;
312
571
  block_hash: string;
313
572
  burn_block_height: number;
@@ -338,9 +597,23 @@ export interface CreateSimulationResponse {
338
597
 
339
598
  // Submit steps request
340
599
  export type SimulationStepInput =
341
- | { Transaction: string } // tx hex
342
- | { Eval: [string, string, string, string] } // [sender, sponsor, contract_id, code]
343
- | { SetContractCode: [string, string, number] } // [contract_id, code, clarity_version]
600
+ | { Transaction: string }
601
+ | {
602
+ /** `sponsor` is `""` when there is no sponsor. */
603
+ Eval: [
604
+ sender: string,
605
+ sponsor: string,
606
+ contract_id: string,
607
+ code: string,
608
+ ];
609
+ }
610
+ | {
611
+ SetContractCode: [
612
+ contract_id: string,
613
+ code: string,
614
+ clarity_version: number,
615
+ ];
616
+ }
344
617
  | { Reads: ReadStep[] }
345
618
  | { TenureExtend: [] };
346
619
 
@@ -349,44 +622,79 @@ export interface SubmitSimulationStepsRequest {
349
622
  }
350
623
 
351
624
  export interface SubmitSimulationStepsResponse {
352
- steps: SimulationStepSummary[];
625
+ steps: SimulationStepResult[];
353
626
  }
354
627
 
355
628
  // Batch reads from simulation
356
629
  export interface SimulationBatchReadsRequest {
357
- vars?: [string, string][]; // [contract_id, variable_name]
358
- maps?: [string, string, string][]; // [contract_id, map_name, key_hex]
359
- readonly?: Array<string | [string, string, string, string]>; // [contract_id, function_name, ...args]
360
- readonly_with_sender?: Array<
361
- // [sender, sponsor, contract_id, function_name, ...args]
362
- [string, string, string, string, ...string[]]
363
- >;
364
- stx?: string[]; // principals
365
- nonces?: string[]; // principals
366
- ft_balance?: [string, string][]; // [token_identifier, principal]
367
- ft_supply?: [string, string][]; // [contract_id, ft_token_name]
630
+ /** `[contract_id, variable_name]` per entry. */
631
+ vars?: [contract_id: string, variable_name: string][];
632
+ /** `[contract_id, map_name, key_hex]` per entry. */
633
+ maps?: [contract_id: string, map_name: string, key_hex: string][];
634
+ /**
635
+ * `[contract_id, function_name, ...arg_hex]` per entry. The first two
636
+ * positions are fixed; remaining elements are hex-encoded Clarity
637
+ * values, one per function argument (so the length matches the
638
+ * function's arity, not arbitrary).
639
+ */
640
+ readonly?: [
641
+ contract_id: string,
642
+ function_name: string,
643
+ ...args_hex: string[],
644
+ ][];
645
+ /**
646
+ * `[sender, sponsor, contract_id, function_name, ...arg_hex]` per
647
+ * entry. The first four positions are fixed (`sponsor` is `""` when
648
+ * there is no sponsor); remaining elements are hex-encoded Clarity
649
+ * values, one per function argument.
650
+ */
651
+ readonly_with_sender?: [
652
+ sender: string,
653
+ sponsor: string,
654
+ contract_id: string,
655
+ function_name: string,
656
+ ...args_hex: string[],
657
+ ][];
658
+ /** Principals to read STX balances for. */
659
+ stx?: string[];
660
+ /** Principals to read nonces for. */
661
+ nonces?: string[];
662
+ /** `[<contract_id>::<token_name>, principal]` per entry. */
663
+ ft_balance?: [token_identifier: string, principal: string][];
664
+ /**
665
+ * Flat array of FT identifiers in `<contract_id>::<token_name>` form,
666
+ * one entry per token to look up. Any length.
667
+ */
668
+ ft_supply?: string[];
368
669
  }
369
670
 
671
+ /**
672
+ * Each category is omitted from the JSON response when the corresponding
673
+ * request field was empty/absent (rust uses
674
+ * `serde(skip_serializing_if = "Vec::is_empty")` per field).
675
+ */
370
676
  export interface SimulationBatchReadsResponse {
371
- vars: ReadResult[];
372
- maps: ReadResult[];
373
- readonly: ReadResult[];
374
- readonly_with_sender: ReadResult[];
375
- stx: ReadResult[];
376
- nonces: ReadResult[];
377
- ft_balance: ReadResult[];
378
- ft_supply: ReadResult[];
677
+ vars?: ReadResult[];
678
+ maps?: ReadResult[];
679
+ readonly?: ReadResult[];
680
+ readonly_with_sender?: ReadResult[];
681
+ stx?: ReadResult[];
682
+ nonces?: ReadResult[];
683
+ ft_balance?: ReadResult[];
684
+ ft_supply?: ReadResult[];
379
685
  }
380
686
 
381
687
  // Instant simulation
382
688
  export interface InstantSimulationRequest {
383
- transaction: string; // tx hex
689
+ /** Transaction serialized to hex. */
690
+ transaction: string;
384
691
  block_height?: number;
385
692
  block_hash?: string;
386
693
  reads?: ReadStep[];
387
694
  }
388
695
 
389
696
  export interface InstantSimulationResponse {
390
- reads?: ReadResult[];
697
+ /** Always present (may be `[]`). Aligned positionally with the request `reads`. */
698
+ reads: ReadResult[];
391
699
  receipt: TransactionReceipt;
392
700
  }