@ton/sandbox 0.33.0-dev.20250613115101.21c0ffa → 0.33.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,7 +5,7 @@ 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
- ## Unreleased
8
+ ## [0.33.0] - 2025-06-16
9
9
 
10
10
  ### Added
11
11
 
@@ -18,6 +18,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
18
18
 
19
19
  - Fixed `now` not updating when running transaction through `blockchain.sendMessageIter`
20
20
  - Fixed `is` methods type and code mismatch
21
+ - Fixed `Blockchain.snapshot()` returning mutable references to internal blockchain state
21
22
 
22
23
  ## [0.32.2] - 2025-06-10
23
24
 
@@ -16,6 +16,7 @@ exports.SmartContract = exports.EmulationError = exports.TimeError = exports.Get
16
16
  const core_1 = require("@ton/core");
17
17
  const ec_1 = require("../utils/ec");
18
18
  const selector_1 = require("../utils/selector");
19
+ const deepcopy_1 = require("../utils/deepcopy");
19
20
  function createShardAccount(args) {
20
21
  let wc = args.workchain ?? 0;
21
22
  let address = args.address ?? (0, core_1.contractAddress)(wc, { code: args.code, data: args.data });
@@ -137,18 +138,18 @@ class SmartContract {
137
138
  this.blockchain = blockchain;
138
139
  }
139
140
  snapshot() {
140
- return {
141
+ return (0, deepcopy_1.deepcopy)({
141
142
  address: this.address,
142
143
  account: this.account,
143
144
  lastTxTime: __classPrivateFieldGet(this, _SmartContract_lastTxTime, "f"),
144
- verbosity: __classPrivateFieldGet(this, _SmartContract_verbosity, "f") === undefined ? undefined : { ...__classPrivateFieldGet(this, _SmartContract_verbosity, "f") },
145
- };
145
+ verbosity: __classPrivateFieldGet(this, _SmartContract_verbosity, "f"),
146
+ });
146
147
  }
147
148
  loadFrom(snapshot) {
148
149
  if (snapshot.address !== this.address) {
149
150
  throw new Error('Wrong snapshot address');
150
151
  }
151
- this.account = snapshot.account;
152
+ this.account = (0, deepcopy_1.deepcopy)(snapshot.account);
152
153
  __classPrivateFieldSet(this, _SmartContract_lastTxTime, snapshot.lastTxTime, "f");
153
154
  __classPrivateFieldSet(this, _SmartContract_verbosity, snapshot.verbosity === undefined ? undefined : { ...snapshot.verbosity }, "f");
154
155
  }
@@ -1,7 +1,12 @@
1
1
  /// <reference types="node" />
2
+ import { Address, Cell, Dictionary, DictionaryKeyTypes } from '@ton/core';
2
3
  type Primitive = undefined | null | boolean | number | string | bigint | symbol;
3
- type DeepCopiable = Primitive | Buffer | DeepCopiable[] | {
4
- [key: string | number | symbol]: DeepCopiable;
4
+ type DeepCopiable = Primitive | Buffer | Address | Cell | Map<DeepCopiable, DeepCopiable> | DeepCopiable[] | Partial<{
5
+ [key: Partial<string | number | symbol>]: DeepCopiable;
6
+ }> | Dictionary<DictionaryKeyTypes, DeepCopiable>;
7
+ type InterfaceToType<T> = {
8
+ [key in keyof T]: InterfaceToType<T[key]>;
5
9
  };
6
- export declare function deepcopy<T extends DeepCopiable>(obj: T): T;
10
+ type IsCopiable<T> = T extends DeepCopiable ? true : InterfaceToType<T> extends DeepCopiable ? true : false;
11
+ export declare function deepcopy<T extends IsCopiable<T> extends true ? unknown : DeepCopiable>(obj: T): T;
7
12
  export {};
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.deepcopy = void 0;
4
+ const core_1 = require("@ton/core");
4
5
  function deepcopyBuffer(buffer) {
5
6
  if (!buffer)
6
7
  return;
@@ -8,16 +9,41 @@ function deepcopyBuffer(buffer) {
8
9
  buffer.copy(newBuffer);
9
10
  return newBuffer;
10
11
  }
12
+ function deepcopyDict(dict) {
13
+ const rawDict = dict;
14
+ // TODO: make pr to @ton/core with key, value and map fields
15
+ // @ts-expect-error Accessing private constructor for cloning purposes
16
+ return new core_1.Dictionary(deepcopy(rawDict._map), rawDict._key, rawDict._value);
17
+ }
11
18
  function deepcopy(obj) {
12
19
  if (obj === null || obj === undefined)
13
20
  return obj;
14
21
  if (Buffer.isBuffer(obj)) {
15
22
  return deepcopyBuffer(obj);
16
23
  }
24
+ if (obj instanceof (core_1.Dictionary)) {
25
+ return deepcopyDict(obj);
26
+ }
27
+ if (core_1.Address.isAddress(obj)) {
28
+ return new core_1.Address(obj.workChain, deepcopyBuffer(obj.hash));
29
+ }
17
30
  if (Array.isArray(obj)) {
18
31
  return obj.map((item) => deepcopy(item));
19
32
  }
33
+ if (obj instanceof core_1.Cell) {
34
+ return obj;
35
+ }
36
+ if (obj instanceof Map) {
37
+ const newMap = new Map();
38
+ for (const [key, value] of obj) {
39
+ newMap.set(deepcopy(key), deepcopy(value));
40
+ }
41
+ return newMap;
42
+ }
20
43
  if (typeof obj === 'object') {
44
+ if (obj.constructor && obj.constructor.name !== 'Object') {
45
+ throw new Error(`Unknown class ${obj.constructor.name} passed to deepcopy`);
46
+ }
21
47
  const result = {};
22
48
  for (const [key, value] of Object.entries(obj)) {
23
49
  result[key] = deepcopy(value);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ton/sandbox",
3
- "version": "0.33.0-dev.20250613115101.21c0ffa",
3
+ "version": "0.33.0",
4
4
  "description": "TON transaction emulator",
5
5
  "main": "dist/index.js",
6
6
  "license": "MIT",