@ton/sandbox 0.38.0-dev.20251014114055.f2fd72c → 0.39.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 CHANGED
@@ -5,6 +5,22 @@ All notable changes to this project will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [0.39.0] - 2025-10-29
9
+
10
+ ### Changed
11
+
12
+ - Updated emulator WASM binary
13
+
14
+ ## [0.38.0] - 2025-10-15
15
+
16
+ ### Added
17
+
18
+ - Added support for TVM v12
19
+
20
+ ### Changed
21
+
22
+ - Failed actions are now partially handled when parsing send modes for transactions
23
+
8
24
  ## [0.37.2] - 2025-09-23
9
25
 
10
26
  ### Fixed
@@ -4,6 +4,7 @@ exports.blockIdToSerializable = blockIdToSerializable;
4
4
  exports.snapshotToSerializable = snapshotToSerializable;
5
5
  exports.snapshotFromSerializable = snapshotFromSerializable;
6
6
  const core_1 = require("@ton/core");
7
+ const SmartContract_1 = require("./SmartContract");
7
8
  const Event_1 = require("../event/Event");
8
9
  function blockIdToSerializable(blockId) {
9
10
  return {
@@ -48,7 +49,9 @@ function snapshotToSerializable(snapshot) {
48
49
  debugLogs: transaction.debugLogs,
49
50
  oldStorage: transaction.oldStorage?.toBoc().toString('base64'),
50
51
  newStorage: transaction.newStorage?.toBoc().toString('base64'),
51
- outActions: transaction.outActions ? writableToBase64((0, core_1.storeOutList)(transaction.outActions)) : undefined,
52
+ outActions: transaction.outActions
53
+ ? writableToBase64((0, SmartContract_1.storeOutListExt)(transaction.outActions))
54
+ : undefined,
52
55
  externals: transaction.externals.map((external) => writableToBase64((0, core_1.storeMessageRelaxed)(external))),
53
56
  mode: transaction.mode,
54
57
  parentHash: transaction.parent?.hash().toString('hex'),
@@ -76,7 +79,7 @@ function snapshotFromSerializable(serialized) {
76
79
  debugLogs: t.debugLogs,
77
80
  oldStorage: t.oldStorage ? core_1.Cell.fromBase64(t.oldStorage) : undefined,
78
81
  newStorage: t.newStorage ? core_1.Cell.fromBase64(t.newStorage) : undefined,
79
- outActions: t.outActions ? (0, core_1.loadOutList)(core_1.Cell.fromBase64(t.outActions).beginParse()) : undefined,
82
+ outActions: t.outActions ? (0, SmartContract_1.loadOutListExt)(core_1.Cell.fromBase64(t.outActions).beginParse()) : undefined,
80
83
  events: (0, Event_1.extractEvents)(transaction),
81
84
  mode: t.mode,
82
85
  externals: t.externals.map((ext) => (0, core_1.loadMessageRelaxed)(core_1.Cell.fromBase64(ext).beginParse())),
@@ -1,4 +1,4 @@
1
- import { Address, Cell, Message, OutAction, ShardAccount, Transaction, TupleItem, TupleReader } from '@ton/core';
1
+ import { Address, Builder, Cell, Message, OutAction, ShardAccount, Slice, Transaction, TupleItem, TupleReader } from '@ton/core';
2
2
  import { Blockchain } from './Blockchain';
3
3
  import { ExtraCurrency } from '../utils/ec';
4
4
  import { EmulationResult, RunCommonArgs, TickOrTock } from '../executor/Executor';
@@ -10,6 +10,15 @@ export declare function createShardAccount(args: {
10
10
  workchain?: number;
11
11
  }): ShardAccount;
12
12
  export declare function createEmptyShardAccount(address: Address): ShardAccount;
13
+ type ExtendedActionType = OutAction['type'] | 'unknown';
14
+ export type OutActionMalformed = {
15
+ type: 'malformed';
16
+ subtype: ExtendedActionType;
17
+ data: Cell;
18
+ };
19
+ export type OutActionExtended = OutAction | OutActionMalformed;
20
+ export declare function storeOutListExt(actions: OutActionExtended[]): (builder: Builder) => void;
21
+ export declare function loadOutListExt(data: Slice): OutActionExtended[];
13
22
  export type Verbosity = 'none' | 'vm_logs' | 'vm_logs_location' | 'vm_logs_gas' | 'vm_logs_full' | 'vm_logs_verbose';
14
23
  export type LogsVerbosity = {
15
24
  print: boolean;
@@ -23,7 +32,7 @@ export type SmartContractTransaction = Transaction & {
23
32
  debugLogs: string;
24
33
  oldStorage?: Cell;
25
34
  newStorage?: Cell;
26
- outActions?: OutAction[];
35
+ outActions?: OutActionExtended[];
27
36
  };
28
37
  export type MessageParams = Partial<{
29
38
  now: number;
@@ -73,9 +82,13 @@ export type SmartContractSnapshot = {
73
82
  verbosity?: Partial<LogsVerbosity>;
74
83
  };
75
84
  export declare class SmartContract {
76
- #private;
77
85
  readonly address: Address;
78
86
  readonly blockchain: Blockchain;
87
+ private _account;
88
+ private parsedAccount?;
89
+ private lastTxTime;
90
+ private _verbosity?;
91
+ private _debug?;
79
92
  constructor(shardAccount: ShardAccount, blockchain: Blockchain);
80
93
  snapshot(): SmartContractSnapshot;
81
94
  loadFrom(snapshot: SmartContractSnapshot): void;
@@ -106,3 +119,4 @@ export declare class SmartContract {
106
119
  get debug(): boolean;
107
120
  setDebug(debug: boolean | undefined): void;
108
121
  }
122
+ export {};
@@ -3,6 +3,8 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.SmartContract = exports.EmulationError = exports.TimeError = exports.GetMethodError = void 0;
4
4
  exports.createShardAccount = createShardAccount;
5
5
  exports.createEmptyShardAccount = createEmptyShardAccount;
6
+ exports.storeOutListExt = storeOutListExt;
7
+ exports.loadOutListExt = loadOutListExt;
6
8
  const core_1 = require("@ton/core");
7
9
  const ec_1 = require("../utils/ec");
8
10
  const selector_1 = require("../utils/selector");
@@ -62,6 +64,73 @@ function createEmptyShardAccount(address) {
62
64
  lastTransactionHash: 0n,
63
65
  };
64
66
  }
67
+ function preloadActionType(data) {
68
+ if (data.remainingBits < 32) {
69
+ return 'unknown';
70
+ }
71
+ const tag = data.preloadUint(32);
72
+ /*
73
+ * action_send_msg#0ec3c86d mode:(## 8)
74
+ * out_msg:^(MessageRelaxed Any) = OutAction;
75
+ *
76
+ * action_set_code#ad4de08e new_code:^Cell = OutAction;
77
+ *
78
+ * action_reserve_currency#36e6b809 mode:(## 8)
79
+ * currency:CurrencyCollection = OutAction;
80
+ *
81
+ * action_change_library#26fa1dd4 mode:(## 7)
82
+ * libref:LibRef = OutAction;
83
+ *
84
+ */
85
+ switch (tag) {
86
+ case 0x0ec3c86d:
87
+ return 'sendMsg';
88
+ case 0xad4de08e:
89
+ return 'setCode';
90
+ case 0x36e6b809:
91
+ return 'reserve';
92
+ case 0x26fa1dd4:
93
+ return 'changeLibrary';
94
+ default:
95
+ return 'unknown';
96
+ }
97
+ }
98
+ function storeActionExt(action) {
99
+ if (action.type === 'malformed') {
100
+ return (builder) => {
101
+ builder.storeSlice(action.data.beginParse());
102
+ };
103
+ }
104
+ return (0, core_1.storeOutAction)(action);
105
+ }
106
+ function storeOutListExt(actions) {
107
+ const cell = actions.reduce((cell, action) => (0, core_1.beginCell)().storeRef(cell).store(storeActionExt(action)).endCell(), (0, core_1.beginCell)().endCell());
108
+ return (builder) => {
109
+ builder.storeSlice(cell.beginParse());
110
+ };
111
+ }
112
+ // loadOutList from @ton/core, but with exception handling
113
+ function loadOutListExt(data) {
114
+ const actions = [];
115
+ while (data.remainingRefs) {
116
+ const nextCell = data.loadRef();
117
+ const dataOrig = data.clone();
118
+ const dataCell = data.asCell();
119
+ try {
120
+ actions.push((0, core_1.loadOutAction)(data));
121
+ }
122
+ catch {
123
+ const actionType = preloadActionType(dataOrig);
124
+ actions.push({
125
+ type: 'malformed',
126
+ subtype: actionType,
127
+ data: dataCell,
128
+ });
129
+ }
130
+ data = nextCell.beginParse();
131
+ }
132
+ return actions.reverse();
133
+ }
65
134
  const verbosityToExecutorVerbosity = {
66
135
  none: 'short',
67
136
  vm_logs: 'full',
@@ -130,24 +199,24 @@ exports.EmulationError = EmulationError;
130
199
  class SmartContract {
131
200
  address;
132
201
  blockchain;
133
- #account;
134
- #parsedAccount;
135
- #lastTxTime;
136
- #verbosity;
137
- #debug;
202
+ _account;
203
+ parsedAccount;
204
+ lastTxTime;
205
+ _verbosity;
206
+ _debug;
138
207
  constructor(shardAccount, blockchain) {
139
208
  this.address = shardAccount.account.addr;
140
- this.#account = (0, core_1.beginCell)().store((0, core_1.storeShardAccount)(shardAccount)).endCell().toBoc().toString('base64');
141
- this.#parsedAccount = shardAccount;
142
- this.#lastTxTime = shardAccount.account?.storageStats.lastPaid ?? 0;
209
+ this._account = (0, core_1.beginCell)().store((0, core_1.storeShardAccount)(shardAccount)).endCell().toBoc().toString('base64');
210
+ this.parsedAccount = shardAccount;
211
+ this.lastTxTime = shardAccount.account?.storageStats.lastPaid ?? 0;
143
212
  this.blockchain = blockchain;
144
213
  }
145
214
  snapshot() {
146
215
  return (0, deepcopy_1.deepcopy)({
147
216
  address: this.address,
148
217
  account: this.account,
149
- lastTxTime: this.#lastTxTime,
150
- verbosity: this.#verbosity,
218
+ lastTxTime: this.lastTxTime,
219
+ verbosity: this._verbosity,
151
220
  });
152
221
  }
153
222
  loadFrom(snapshot) {
@@ -155,8 +224,8 @@ class SmartContract {
155
224
  throw new Error('Wrong snapshot address');
156
225
  }
157
226
  this.account = (0, deepcopy_1.deepcopy)(snapshot.account);
158
- this.#lastTxTime = snapshot.lastTxTime;
159
- this.#verbosity = snapshot.verbosity === undefined ? undefined : { ...snapshot.verbosity };
227
+ this.lastTxTime = snapshot.lastTxTime;
228
+ this._verbosity = snapshot.verbosity === undefined ? undefined : { ...snapshot.verbosity };
160
229
  }
161
230
  get ec() {
162
231
  return (0, ec_1.extractEc)(this.account.account?.storage.balance.other ??
@@ -191,15 +260,15 @@ class SmartContract {
191
260
  return this.account.account?.storage.state;
192
261
  }
193
262
  get account() {
194
- if (this.#parsedAccount === undefined) {
195
- this.#parsedAccount = (0, core_1.loadShardAccount)(core_1.Cell.fromBase64(this.#account).beginParse());
263
+ if (this.parsedAccount === undefined) {
264
+ this.parsedAccount = (0, core_1.loadShardAccount)(core_1.Cell.fromBase64(this._account).beginParse());
196
265
  }
197
- return this.#parsedAccount;
266
+ return this.parsedAccount;
198
267
  }
199
268
  set account(account) {
200
- this.#account = (0, core_1.beginCell)().store((0, core_1.storeShardAccount)(account)).endCell().toBoc().toString('base64');
201
- this.#parsedAccount = account;
202
- this.#lastTxTime = account.account?.storageStats.lastPaid ?? 0;
269
+ this._account = (0, core_1.beginCell)().store((0, core_1.storeShardAccount)(account)).endCell().toBoc().toString('base64');
270
+ this.parsedAccount = account;
271
+ this.lastTxTime = account.account?.storageStats.lastPaid ?? 0;
203
272
  }
204
273
  static create(blockchain, args) {
205
274
  return new SmartContract(createShardAccount(args), blockchain);
@@ -209,14 +278,14 @@ class SmartContract {
209
278
  }
210
279
  createCommonArgs(params) {
211
280
  const now = params?.now ?? this.blockchain.now ?? Math.floor(Date.now() / 1000);
212
- if (now < this.#lastTxTime) {
213
- throw new TimeError(this.address, this.#lastTxTime, now);
281
+ if (now < this.lastTxTime) {
282
+ throw new TimeError(this.address, this.lastTxTime, now);
214
283
  }
215
284
  return {
216
285
  config: this.blockchain.configBase64,
217
286
  libs: this.blockchain.libs ?? null,
218
287
  verbosity: verbosityToExecutorVerbosity[this.verbosity.vmLogs],
219
- shardAccount: this.#account,
288
+ shardAccount: this._account,
220
289
  now,
221
290
  lt: this.blockchain.lt,
222
291
  randomSeed: params?.randomSeed ?? this.blockchain.random ?? Buffer.alloc(32),
@@ -272,16 +341,16 @@ class SmartContract {
272
341
  console.log(res.debugLogs);
273
342
  }
274
343
  const tx = (0, core_1.loadTransaction)(core_1.Cell.fromBase64(res.result.transaction).beginParse());
275
- this.#account = res.result.shardAccount;
276
- this.#parsedAccount = undefined;
277
- this.#lastTxTime = tx.now;
344
+ this._account = res.result.shardAccount;
345
+ this.parsedAccount = undefined;
346
+ this.lastTxTime = tx.now;
278
347
  let newStorage = undefined;
279
348
  if (this.blockchain.recordStorage && this.account.account?.storage.state.type === 'active') {
280
349
  newStorage = this.account.account?.storage.state.state.data ?? undefined;
281
350
  }
282
351
  let outActions = undefined;
283
352
  if (res.result.actions) {
284
- outActions = (0, core_1.loadOutList)(core_1.Cell.fromBase64(res.result.actions).beginParse());
353
+ outActions = loadOutListExt(core_1.Cell.fromBase64(res.result.actions).beginParse());
285
354
  }
286
355
  return {
287
356
  ...tx,
@@ -367,7 +436,7 @@ class SmartContract {
367
436
  get verbosity() {
368
437
  return {
369
438
  ...this.blockchain.verbosity,
370
- ...this.#verbosity,
439
+ ...this._verbosity,
371
440
  };
372
441
  }
373
442
  set verbosity(value) {
@@ -375,21 +444,21 @@ class SmartContract {
375
444
  }
376
445
  setVerbosity(verbosity) {
377
446
  if (typeof verbosity === 'string') {
378
- this.#verbosity = {
379
- ...this.#verbosity,
447
+ this._verbosity = {
448
+ ...this._verbosity,
380
449
  vmLogs: verbosity,
381
450
  blockchainLogs: verbosity !== 'none',
382
451
  };
383
452
  }
384
453
  else {
385
- this.#verbosity = verbosity;
454
+ this._verbosity = verbosity;
386
455
  }
387
456
  }
388
457
  get debug() {
389
- return this.#debug ?? this.blockchain.debug;
458
+ return this._debug ?? this.blockchain.debug;
390
459
  }
391
460
  setDebug(debug) {
392
- this.#debug = debug;
461
+ this._debug = debug;
393
462
  }
394
463
  }
395
464
  exports.SmartContract = SmartContract;