@ton/blueprint 0.34.0 → 0.35.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,21 @@ 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.35.0] - 2025-06-02
9
+
10
+ ### Added
11
+
12
+ - Added ton lite client network provider
13
+ - Added tolk verifier
14
+ - Wallet v4 extended support: added v4r1, v4 is treated as v4r2
15
+ - Added possibility to specify custom `manifestUrl` in blueprint configuration
16
+ - Added documentation about the [Tact plugin by TON Studio](https://plugins.jetbrains.com/plugin/27290-tact)
17
+ - Added tolk v0.13 support
18
+
19
+ ### Changed
20
+
21
+ - Updated documentation about Tact wrappers
22
+
8
23
  ## [0.34.0] - 2025-05-20
9
24
 
10
25
  ### Added
package/README.md CHANGED
@@ -55,6 +55,7 @@ Blueprint is an all-in-one development environment designed to enhance the proce
55
55
  1. Compiling FunC with https://github.com/ton-community/func-js
56
56
  2. Compiling Tolk with https://github.com/ton-blockchain/tolk-js
57
57
  3. Compiling Tact with https://github.com/tact-lang/tact
58
+ * Uses [`tact.config.json`](https://docs.tact-lang.org/book/config/) as the build configuration file
58
59
  4. Testing smart contracts with https://github.com/ton-org/sandbox
59
60
  5. Deploying smart contracts with [TON Connect 2](https://github.com/ton-connect) or a `ton://` deeplink
60
61
 
@@ -63,7 +64,9 @@ Blueprint is an all-in-one development environment designed to enhance the proce
63
64
  * [Node.js](https://nodejs.org) with a recent version like v18. Version can be verified with `node -v`
64
65
  * IDE with TON support:
65
66
  * [Visual Studio Code](https://code.visualstudio.com/) with the [FunC plugin](https://marketplace.visualstudio.com/items?itemName=tonwhales.func-vscode), [Tolk plugin](https://marketplace.visualstudio.com/items?itemName=ton-core.tolk-vscode) or [Tact plugin](https://marketplace.visualstudio.com/items?itemName=tonstudio.vscode-tact)
66
- * [IntelliJ IDEA](https://www.jetbrains.com/idea/) with the [TON Development plugin](https://plugins.jetbrains.com/plugin/23382-ton)
67
+ * [IntelliJ IDEA](https://www.jetbrains.com/idea/)
68
+ * [TON Development plugin](https://plugins.jetbrains.com/plugin/23382-ton) for FunC, Tolk and Fift
69
+ * [Tact plugin by TON Studio](https://plugins.jetbrains.com/plugin/27290-tact) for Tact
67
70
 
68
71
  ## Features overview
69
72
 
@@ -75,9 +78,11 @@ Blueprint is an all-in-one development environment designed to enhance the proce
75
78
  ### Directory structure
76
79
 
77
80
  * `contracts/` - Source code for all smart contracts and their imports
78
- * `wrappers/` - TypeScript interface classes for all contracts (implementing `Contract` from [@ton/core](https://www.npmjs.com/package/@ton/core))
79
- * include message [de]serialization primitives, getter wrappers and compilation functions
80
- * used by the test suite and client code to interact with the contracts from TypeScript
81
+ * `wrappers/` - TypeScript interface classes for all contracts **except Tact**.
82
+ * Tact-generated wrappers are located according to the build path defined in [`tact.config.json`](https://docs.tact-lang.org/book/config/)
83
+ * Each wrapper implements `Contract` interface from [@ton/core](https://www.npmjs.com/package/@ton/core)
84
+ * Includes message [de]serialization primitives, getter wrappers and compilation functions
85
+ * Used by the test suite and client code to interact with the contracts from TypeScript
81
86
  * `compilables/` - Compilations scripts for contracts
82
87
  * `tests/` - TypeScript test suite for all contracts (relying on [Sandbox](https://github.com/ton-org/sandbox) for in-process tests)
83
88
  * `scripts/` - Deployment scripts to mainnet/testnet and other scripts interacting with live contracts
@@ -126,7 +131,7 @@ To run scripts using a wallet by mnemonic authentication, you need to configure
126
131
 
127
132
  Start by adding the following environment variables to your `.env` file:
128
133
  * **`WALLET_MNEMONIC`**: Your wallet's mnemonic phrase (space-separated words).
129
- * **`WALLET_VERSION`**: The wallet contract version to use. Supported versions: `v1r1`, `v1r2`, `v1r3`, `v2r1`, `v2r2`, `v3r1`, `v3r2`, `v4`, `v5r1`.
134
+ * **`WALLET_VERSION`**: The wallet contract version to use. Supported versions: `v1r1`, `v1r2`, `v1r3`, `v2r1`, `v2r2`, `v3r1`, `v3r2`, `v4r1`, `v4r2` (or `v4`), `v5r1`.
130
135
 
131
136
  **Optional variables:**
132
137
  * **`WALLET_ID`**: The wallet ID (can be used with versions below `v5r1`).
@@ -292,6 +297,33 @@ npx blueprint run --custom https://toncenter.com/api/v2/jsonRPC --custom-version
292
297
 
293
298
  Properties of the `network` object have the same semantics as the `--custom` flags with respective names (see `blueprint help run`).
294
299
 
300
+ ### Liteclient Support
301
+
302
+ Lite client is supported through the following configuration:
303
+
304
+ ```ts
305
+ import { Config } from '@ton/blueprint';
306
+
307
+ export const config: Config = {
308
+ network: {
309
+ endpoint: 'https://ton.org/testnet-global.config.json', // Use https://ton.org/global.config.json for mainnet or any custom configuration
310
+ version: 'liteclient',
311
+ type: 'testnet',
312
+ }
313
+ };
314
+ ```
315
+
316
+ You can also provide these parameters via CLI:
317
+
318
+ ```bash
319
+ npx blueprint run \
320
+ --custom https://ton.org/testnet-global.config.json \
321
+ --custom-version liteclient \
322
+ --custom-type testnet
323
+ ```
324
+
325
+ #### Contract Verification Using Custom Network
326
+
295
327
  You can also use custom network to verify contracts, like so:
296
328
  ```bash
297
329
  npx blueprint verify --custom https://toncenter.com/api/v2/jsonRPC --custom-version v2 --custom-type mainnet --custom-key YOUR_API_KEY
@@ -310,6 +342,36 @@ export const config: Config = {
310
342
  };
311
343
  ```
312
344
 
345
+ ### Recursive wrappers
346
+
347
+ You can configure whether the `wrappers` or `compilables` directories should be searched recursively for contracts configs by setting the `recursiveWrappers` field.
348
+
349
+ ```typescript
350
+ import { Config } from '@ton/blueprint';
351
+
352
+ export const config: Config = {
353
+ recursiveWrappers: true,
354
+ };
355
+ ```
356
+
357
+ By default, this is set to `false`.
358
+
359
+ ### TonConnect manifest URL
360
+
361
+ If you're using a TonConnect provider, you can override the default manifest URL by specifying the `manifestUrl` field.
362
+ ```typescript
363
+ import { Config } from '@ton/blueprint';
364
+
365
+ export const config: Config = {
366
+ manifestUrl: 'https://yourdomain.com/custom-manifest.json',
367
+ };
368
+ ```
369
+
370
+ By default, the manifest URL is set to:
371
+ ```
372
+ https://raw.githubusercontent.com/ton-org/blueprint/main/tonconnect/manifest.json
373
+ ```
374
+
313
375
  ## Contributors
314
376
 
315
377
  Special thanks to [@qdevstudio](https://t.me/qdevstudio) for their logo for blueprint.
@@ -217,6 +217,27 @@ const verify = async (args, ui, context) => {
217
217
  senderAddress: senderAddress.toString(),
218
218
  };
219
219
  }
220
+ else if (result.lang === 'tolk') {
221
+ for (const f of result.snapshot) {
222
+ fd.append(f.filename, new Blob([f.content]), path_1.default.basename(f.filename));
223
+ }
224
+ src = {
225
+ compiler: 'tolk',
226
+ compilerSettings: {
227
+ tolkVersion: result.version,
228
+ },
229
+ knownContractAddress: addr,
230
+ knownContractHash: result.code.hash().toString('base64'),
231
+ sources: result.snapshot.map((s) => ({
232
+ includeInCommand: true,
233
+ isStdLib: false,
234
+ hasIncludeDirectives: true,
235
+ isEntrypoint: s === result.snapshot[0],
236
+ folder: path_1.default.dirname(s.filename),
237
+ })),
238
+ senderAddress: senderAddress.toString(),
239
+ };
240
+ }
220
241
  else {
221
242
  // future proofing
222
243
  throw new Error('Unsupported language ' + result.lang);
@@ -52,4 +52,10 @@ export interface Config {
52
52
  * @default false
53
53
  */
54
54
  recursiveWrappers?: boolean;
55
+ /**
56
+ * Manifest url passed to TonConnect provider.
57
+ *
58
+ * @default https://raw.githubusercontent.com/ton-org/blueprint/main/tonconnect/manifest.json
59
+ */
60
+ manifestUrl?: string;
55
61
  }
@@ -1,6 +1,6 @@
1
1
  export type CustomNetwork = {
2
2
  endpoint: string;
3
- version?: 'v2' | 'v4' | 'tonapi';
3
+ version?: 'v2' | 'v4' | 'tonapi' | 'liteclient';
4
4
  key?: string;
5
5
  type?: 'mainnet' | 'testnet' | 'custom';
6
6
  };
@@ -2,7 +2,8 @@ import { TonClient, TonClient4 } from '@ton/ton';
2
2
  import { Address, Cell, Contract, ContractProvider, OpenedContract, Sender } from '@ton/core';
3
3
  import { ContractAdapter } from '@ton-api/ton-adapter';
4
4
  import { UIProvider } from '../ui/UIProvider';
5
- export type BlueprintTonClient = TonClient4 | TonClient | ContractAdapter;
5
+ import { LiteClient } from "ton-lite-client";
6
+ export type BlueprintTonClient = TonClient4 | TonClient | ContractAdapter | LiteClient;
6
7
  /**
7
8
  * Interface representing a network provider for interacting with TON blockchain.
8
9
  */
@@ -30,6 +30,7 @@ const paths_1 = require("../paths");
30
30
  const crypto_1 = require("@ton/crypto");
31
31
  const MnemonicProvider_1 = require("./send/MnemonicProvider");
32
32
  const axios_1 = __importDefault(require("axios"));
33
+ const ton_lite_client_1 = require("ton-lite-client");
33
34
  const INITIAL_DELAY = 400;
34
35
  const MAX_ATTEMPTS = 4;
35
36
  exports.argSpec = {
@@ -216,6 +217,33 @@ async function createMnemonicProvider(client, network, ui) {
216
217
  network,
217
218
  });
218
219
  }
220
+ function intToIP(int) {
221
+ const part1 = int & 255;
222
+ const part2 = (int >> 8) & 255;
223
+ const part3 = (int >> 16) & 255;
224
+ const part4 = (int >> 24) & 255;
225
+ return `${(part4 + 256) % 256}.${(part3 + 256) % 256}.${(part2 + 256) % 256}.${(part1 + 256) % 256}`;
226
+ }
227
+ async function buildLiteClient(configEndpoint) {
228
+ const { data } = await axios_1.default.get(configEndpoint);
229
+ if (!Array.isArray(data.liteservers)) {
230
+ throw new Error(`Invalid liteclient configuration on ${configEndpoint}. Use https://ton.org/testnet-global.config.json for testnet or https://ton.org/global.config.json for mainnet.`);
231
+ }
232
+ const engines = data.liteservers.map((server) => {
233
+ if (typeof server?.ip !== 'number' ||
234
+ typeof server?.port !== 'number' ||
235
+ typeof server?.id !== 'object' ||
236
+ typeof server?.id?.key !== 'string') {
237
+ throw new Error(`Invalid liteclient configuration on ${configEndpoint}`);
238
+ }
239
+ return new ton_lite_client_1.LiteSingleEngine({
240
+ host: `tcp://${intToIP(server.ip)}:${server.port}`,
241
+ publicKey: Buffer.from(server.id.key, 'base64'),
242
+ });
243
+ });
244
+ const engine = new ton_lite_client_1.LiteRoundRobinEngine(engines);
245
+ return new ton_lite_client_1.LiteClient({ engine });
246
+ }
219
247
  class NetworkProviderBuilder {
220
248
  constructor(args, ui, config, allowCustom = true) {
221
249
  this.args = args;
@@ -283,7 +311,7 @@ class NetworkProviderBuilder {
283
311
  case 'tonconnect':
284
312
  if (network === 'custom')
285
313
  throw new Error('Tonkeeper cannot work with custom network.');
286
- provider = new TonConnectProvider_1.TonConnectProvider(new FSStorage_1.FSStorage(storagePath), this.ui, network);
314
+ provider = new TonConnectProvider_1.TonConnectProvider(new FSStorage_1.FSStorage(storagePath), this.ui, network, this.config?.manifestUrl);
287
315
  break;
288
316
  case 'mnemonic':
289
317
  provider = await createMnemonicProvider(client, network, this.ui);
@@ -349,6 +377,9 @@ class NetworkProviderBuilder {
349
377
  apiKey: configNetwork.key,
350
378
  }));
351
379
  }
380
+ else if (configNetwork.version === 'liteclient') {
381
+ tc = await buildLiteClient(configNetwork.endpoint);
382
+ }
352
383
  else {
353
384
  throw new Error('Unknown API version: ' + configNetwork.version);
354
385
  }
@@ -3,7 +3,8 @@ import { SendProvider } from './SendProvider';
3
3
  import { UIProvider } from '../../ui/UIProvider';
4
4
  import { BlueprintTonClient } from '../NetworkProvider';
5
5
  import { Network } from '../Network';
6
- export type WalletVersion = 'v1r1' | 'v1r2' | 'v1r3' | 'v2r1' | 'v2r2' | 'v3r1' | 'v3r2' | 'v4' | 'v5r1';
6
+ import { Buffer } from 'buffer';
7
+ import { WalletVersion } from './wallets';
7
8
  type MnemonicProviderParams = {
8
9
  version: WalletVersion;
9
10
  workchain?: number;
@@ -13,20 +13,9 @@ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (
13
13
  var _MnemonicProvider_wallet, _MnemonicProvider_secretKey, _MnemonicProvider_client, _MnemonicProvider_ui, _MnemonicProvider_network;
14
14
  Object.defineProperty(exports, "__esModule", { value: true });
15
15
  exports.MnemonicProvider = void 0;
16
- const ton_1 = require("@ton/ton");
17
16
  const core_1 = require("@ton/core");
18
17
  const crypto_1 = require("@ton/crypto");
19
- const wallets = {
20
- v1r1: ton_1.WalletContractV1R1,
21
- v1r2: ton_1.WalletContractV1R2,
22
- v1r3: ton_1.WalletContractV1R3,
23
- v2r1: ton_1.WalletContractV2R1,
24
- v2r2: ton_1.WalletContractV2R2,
25
- v3r1: ton_1.WalletContractV3R1,
26
- v3r2: ton_1.WalletContractV3R2,
27
- v4: ton_1.WalletContractV4,
28
- v5r1: ton_1.WalletContractV5R1,
29
- };
18
+ const wallets_1 = require("./wallets");
30
19
  class MnemonicProvider {
31
20
  constructor(params) {
32
21
  _MnemonicProvider_wallet.set(this, void 0);
@@ -34,8 +23,8 @@ class MnemonicProvider {
34
23
  _MnemonicProvider_client.set(this, void 0);
35
24
  _MnemonicProvider_ui.set(this, void 0);
36
25
  _MnemonicProvider_network.set(this, void 0);
37
- if (!(params.version in wallets)) {
38
- throw new Error(`Unknown wallet version ${params.version}`);
26
+ if (!(params.version in wallets_1.wallets)) {
27
+ throw new Error(`Unknown wallet version ${params.version}, expected one of ${Object.keys(wallets_1.wallets).join(', ')}`);
39
28
  }
40
29
  __classPrivateFieldSet(this, _MnemonicProvider_client, params.client, "f");
41
30
  __classPrivateFieldSet(this, _MnemonicProvider_network, params.network, "f");
@@ -50,7 +39,7 @@ class MnemonicProvider {
50
39
  }
51
40
  createWallet(params, kp) {
52
41
  if (params.version === 'v5r1') {
53
- return wallets[params.version].create({
42
+ return wallets_1.wallets[params.version].create({
54
43
  publicKey: kp.publicKey,
55
44
  walletId: {
56
45
  networkGlobalId: params.network === 'testnet' ? -3 : -239, // networkGlobalId: -3 for Testnet, -239 for Mainnet
@@ -62,7 +51,7 @@ class MnemonicProvider {
62
51
  },
63
52
  });
64
53
  }
65
- return wallets[params.version].create({
54
+ return wallets_1.wallets[params.version].create({
66
55
  workchain: params.workchain ?? 0,
67
56
  publicKey: kp.publicKey,
68
57
  walletId: params.walletId,
@@ -5,7 +5,7 @@ import { UIProvider } from '../../ui/UIProvider';
5
5
  import { Network } from '../Network';
6
6
  export declare class TonConnectProvider implements SendProvider {
7
7
  #private;
8
- constructor(storage: Storage, ui: UIProvider, network: Network);
8
+ constructor(storage: Storage, ui: UIProvider, network: Network, manifestUrl?: string);
9
9
  connect(): Promise<void>;
10
10
  address(): Address | undefined;
11
11
  private connectWallet;
@@ -39,13 +39,13 @@ function isRemote(walletInfo) {
39
39
  return 'universalLink' in walletInfo && 'bridgeUrl' in walletInfo;
40
40
  }
41
41
  class TonConnectProvider {
42
- constructor(storage, ui, network) {
42
+ constructor(storage, ui, network, manifestUrl = 'https://raw.githubusercontent.com/ton-org/blueprint/main/tonconnect/manifest.json') {
43
43
  _TonConnectProvider_connector.set(this, void 0);
44
44
  _TonConnectProvider_ui.set(this, void 0);
45
45
  _TonConnectProvider_network.set(this, void 0);
46
46
  __classPrivateFieldSet(this, _TonConnectProvider_connector, new sdk_1.default({
47
47
  storage: new TonConnectStorage(storage),
48
- manifestUrl: 'https://raw.githubusercontent.com/ton-org/blueprint/main/tonconnect/manifest.json',
48
+ manifestUrl,
49
49
  }), "f");
50
50
  __classPrivateFieldSet(this, _TonConnectProvider_ui, ui, "f");
51
51
  __classPrivateFieldSet(this, _TonConnectProvider_network, network, "f");
@@ -0,0 +1,25 @@
1
+ import { Buffer } from 'buffer';
2
+ import { WalletContractV4 as WalletContractV4R2 } from '@ton/ton/dist/wallets/WalletContractV4';
3
+ import { WalletContractV1R1, WalletContractV1R2, WalletContractV1R3, WalletContractV2R1, WalletContractV2R2, WalletContractV3R1, WalletContractV3R2, WalletContractV5R1 } from '@ton/ton';
4
+ export type WalletVersion = 'v1r1' | 'v1r2' | 'v1r3' | 'v2r1' | 'v2r2' | 'v3r1' | 'v3r2' | 'v4' | 'v4r1' | 'v4r2' | 'v5r1';
5
+ declare class WalletContractV4R1 {
6
+ static create(args: {
7
+ workchain: number;
8
+ publicKey: Buffer;
9
+ walletId?: number | null;
10
+ }): WalletContractV4R2;
11
+ }
12
+ export declare const wallets: {
13
+ v1r1: typeof WalletContractV1R1;
14
+ v1r2: typeof WalletContractV1R2;
15
+ v1r3: typeof WalletContractV1R3;
16
+ v2r1: typeof WalletContractV2R1;
17
+ v2r2: typeof WalletContractV2R2;
18
+ v3r1: typeof WalletContractV3R1;
19
+ v3r2: typeof WalletContractV3R2;
20
+ v4: typeof WalletContractV4R2;
21
+ v4r1: typeof WalletContractV4R1;
22
+ v4r2: typeof WalletContractV4R2;
23
+ v5r1: typeof WalletContractV5R1;
24
+ };
25
+ export {};
@@ -0,0 +1,30 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.wallets = void 0;
4
+ const buffer_1 = require("buffer");
5
+ const WalletContractV4_1 = require("@ton/ton/dist/wallets/WalletContractV4");
6
+ const core_1 = require("@ton/core");
7
+ const ton_1 = require("@ton/ton");
8
+ class WalletContractV4R1 {
9
+ static create(args) {
10
+ const wallet = WalletContractV4_1.WalletContractV4.create(args);
11
+ const { data } = wallet.init;
12
+ const code = core_1.Cell.fromBoc(buffer_1.Buffer.from('B5EE9C72410215010002F5000114FF00F4A413F4BCF2C80B010201200203020148040504F8F28308D71820D31FD31FD31F02F823BBF263ED44D0D31FD31FD3FFF404D15143BAF2A15151BAF2A205F901541064F910F2A3F80024A4C8CB1F5240CB1F5230CBFF5210F400C9ED54F80F01D30721C0009F6C519320D74A96D307D402FB00E830E021C001E30021C002E30001C0039130E30D03A4C8CB1F12CB1FCBFF1112131403EED001D0D3030171B0915BE021D749C120915BE001D31F218210706C7567BD228210626C6E63BDB022821064737472BDB0925F03E002FA403020FA4401C8CA07CBFFC9D0ED44D0810140D721F404305C810108F40A6FA131B3925F05E004D33FC8258210706C7567BA9131E30D248210626C6E63BAE30004060708020120090A005001FA00F404308210706C7567831EB17080185005CB0527CF165003FA02F40012CB69CB1F5210CB3F0052F8276F228210626C6E63831EB17080185005CB0527CF1624FA0214CB6A13CB1F5230CB3F01FA02F4000092821064737472BA8E3504810108F45930ED44D0810140D720C801CF16F400C9ED54821064737472831EB17080185004CB0558CF1622FA0212CB6ACB1FCB3F9410345F04E2C98040FB000201200B0C0059BD242B6F6A2684080A06B90FA0218470D4080847A4937D29910CE6903E9FF9837812801B7810148987159F31840201580D0E0011B8C97ED44D0D70B1F8003DB29DFB513420405035C87D010C00B23281F2FFF274006040423D029BE84C600201200F100019ADCE76A26840206B90EB85FFC00019AF1DF6A26840106B90EB858FC0006ED207FA00D4D422F90005C8CA0715CBFFC9D077748018C8CB05CB0222CF165005FA0214CB6B12CCCCC971FB00C84014810108F451F2A702006C810108D718C8542025810108F451F2A782106E6F746570748018C8CB05CB025004CF16821005F5E100FA0213CB6A12CB1FC971FB00020072810108D718305202810108F459F2A7F82582106473747270748018C8CB05CB025005CF16821005F5E100FA0214CB6A13CB1F12CB3FC973FB00000AF400C9ED5446A9F34F', 'hex'))[0];
13
+ wallet.init = { data, code };
14
+ wallet.address = (0, core_1.contractAddress)(args.workchain, wallet.init);
15
+ return wallet;
16
+ }
17
+ }
18
+ exports.wallets = {
19
+ v1r1: ton_1.WalletContractV1R1,
20
+ v1r2: ton_1.WalletContractV1R2,
21
+ v1r3: ton_1.WalletContractV1R3,
22
+ v2r1: ton_1.WalletContractV2R1,
23
+ v2r2: ton_1.WalletContractV2R2,
24
+ v3r1: ton_1.WalletContractV3R1,
25
+ v3r2: ton_1.WalletContractV3R2,
26
+ v4: WalletContractV4_1.WalletContractV4, // left for backward compatibility
27
+ v4r1: WalletContractV4R1,
28
+ v4r2: WalletContractV4_1.WalletContractV4,
29
+ v5r1: ton_1.WalletContractV5R1,
30
+ };
@@ -1,33 +1,33 @@
1
1
  {{snakeName}}.tolk
2
2
  // simple counter contract in Tolk language
3
3
 
4
- const OP_INCREASE = 0x7e8764ef; // arbitrary 32-bit number, equal to OP_INCREASE in wrappers/CounterContract.ts
4
+ // using unions to represent contract messages
5
5
 
6
- // storage variables
7
-
8
- // id is required to be able to create different instances of counters
9
- // since addresses in TON depend on the initial state of the contract
10
- global ctxID: int;
11
- global ctxCounter: int;
6
+ // the struct uses a 32-bit opcode prefix for message identification
7
+ struct (0x7e8764ef) IncreaseMessage {
8
+ queryID: uint64; // query id, typically included in messages
9
+ increaseBy: uint32;
10
+ }
12
11
 
13
- // loadData populates storage variables from persistent storage
14
- fun loadData() {
15
- var ds = contract.getData().beginParse();
12
+ // incoming message definition using a union for extensibility
13
+ // this union could be extended like below to support more message types
14
+ // type IncomingMessage = IncreaseMessage | DecreaseMessage | ...;
15
+ type IncomingMessage = IncreaseMessage;
16
16
 
17
- ctxID = ds.loadUint(32);
18
- ctxCounter = ds.loadUint(32);
17
+ // contract storage, auto-serialized to/from cells.
18
+ struct Storage {
19
+ id: uint32; // required to allow multiple independent counter instances, since contract address depends on initial state
20
+ counter: uint32;
21
+ }
19
22
 
20
- ds.assertEnd();
23
+ // load contract data using auto-deserialization
24
+ fun loadData() {
25
+ return Storage.fromCell(contract.getData());
21
26
  }
22
27
 
23
- // saveData stores storage variables as a cell into persistent storage
24
- fun saveData() {
25
- contract.setData(
26
- beginCell()
27
- .storeUint(ctxID, 32)
28
- .storeUint(ctxCounter, 32)
29
- .endCell()
30
- );
28
+ // save contract data into persistent storage using auto-serialization
29
+ fun saveData(data: Storage) {
30
+ contract.setData(data.toCell());
31
31
  }
32
32
 
33
33
  // onInternalMessage is the main entrypoint; it's called when a contract receives an internal message from other contracts
@@ -36,36 +36,39 @@ fun onInternalMessage(myBalance: int, msgValue: int, msgFull: cell, msgBody: sli
36
36
  return;
37
37
  }
38
38
 
39
- var cs: slice = msgFull.beginParse();
39
+ var cs = msgFull.beginParse();
40
40
  val flags = cs.loadMessageFlags();
41
41
  if (isMessageBounced(flags)) { // ignore all bounced messages
42
42
  return;
43
43
  }
44
44
 
45
- loadData(); // here we populate the storage variables
46
-
47
- val op = msgBody.loadMessageOp(); // by convention, the first 32 bits of incoming message is the op
48
- val queryID = msgBody.loadMessageQueryId(); // also by convention, the next 64 bits contain the "query id", although this is not always the case
49
-
50
- if (op == OP_INCREASE) {
51
- val increaseBy = msgBody.loadUint(32);
52
- ctxCounter += increaseBy;
53
- saveData();
54
- return;
45
+ val msg = IncomingMessage.fromSlice(msgBody); // 63 error code is thrown if the message opcode is unknown
46
+
47
+ match (msg) {
48
+ IncreaseMessage => {
49
+ var storage = loadData(); // here we load contract data
50
+ storage.counter += msg.increaseBy;
51
+ saveData(storage); // here we updating contract data
52
+ }
53
+ /* other messages could be supported via extending this match block
54
+ DecreaseMessage => {
55
+ var storage = loadData();
56
+ storage.counter -= msg.decreaseBy;
57
+ saveData(storage);
58
+ }
59
+ */
55
60
  }
56
-
57
- throw 0xffff; // if the message contains an op that is not known to this contract, we throw
58
61
  }
59
62
 
60
63
  // get methods are a means to conveniently read contract data using, for example, HTTP APIs
61
64
  // note that unlike in many other smart contract VMs, get methods cannot be called by other contracts
62
65
 
63
66
  get currentCounter(): int {
64
- loadData();
65
- return ctxCounter;
67
+ val storage = loadData();
68
+ return storage.counter;
66
69
  }
67
70
 
68
71
  get initialId(): int {
69
- loadData();
70
- return ctxID;
72
+ val storage = loadData();
73
+ return storage.id;
71
74
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ton/blueprint",
3
- "version": "0.34.0",
3
+ "version": "0.35.0",
4
4
  "description": "Framework for development of TON smart contracts",
5
5
  "main": "dist/index.js",
6
6
  "bin": "./dist/cli/cli.js",
@@ -21,10 +21,10 @@
21
21
  "devDependencies": {
22
22
  "@tact-lang/compiler": "^1.6.5",
23
23
  "@ton-community/func-js": "^0.9.0",
24
- "@ton/core": "^0.59.0",
24
+ "@ton/core": "^0.60.1",
25
25
  "@ton/crypto": "^3.3.0",
26
26
  "@ton/tolk-js": "^0.12.0",
27
- "@ton/ton": "^15.0.0",
27
+ "@ton/ton": "^15.2.1",
28
28
  "@types/inquirer": "^8.2.6",
29
29
  "@types/node": "^20.2.5",
30
30
  "@types/qrcode-terminal": "^0.12.0",
@@ -34,10 +34,10 @@
34
34
  "peerDependencies": {
35
35
  "@tact-lang/compiler": ">=1.6.5",
36
36
  "@ton-community/func-js": ">=0.9.0",
37
- "@ton/core": ">=0.59.0",
37
+ "@ton/core": ">=0.60.1",
38
38
  "@ton/crypto": ">=3.3.0",
39
- "@ton/tolk-js": ">=0.12.0",
40
- "@ton/ton": ">=15.0.0"
39
+ "@ton/tolk-js": ">=0.13.0",
40
+ "@ton/ton": ">=15.2.1"
41
41
  },
42
42
  "dependencies": {
43
43
  "@ton-api/client": "^0.2.0",
@@ -49,6 +49,7 @@
49
49
  "dotenv": "^16.1.4",
50
50
  "inquirer": "^8.2.5",
51
51
  "qrcode-terminal": "^0.12.0",
52
+ "ton-lite-client": "^3.1.0",
52
53
  "ts-node": "^10.9.1"
53
54
  },
54
55
  "packageManager": "yarn@4.3.1"