From 9342f4bcb10ff109da1f17637708fdc6a31e6db5 Mon Sep 17 00:00:00 2001
From: aigerimu <89766357+aigerimu@users.noreply.github.com>
Date: Tue, 28 Oct 2025 23:08:32 +0700
Subject: [PATCH 01/10] /
---
contract-dev/first-smart-contract.mdx | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/contract-dev/first-smart-contract.mdx b/contract-dev/first-smart-contract.mdx
index e82cff932..5da114878 100644
--- a/contract-dev/first-smart-contract.mdx
+++ b/contract-dev/first-smart-contract.mdx
@@ -10,10 +10,10 @@ Welcome to your journey into TON smart contract development! In this comprehensi
By the end of this tutorial, you'll have:
-- ✅ **Built** a complete smart contract in Tolk
-- ✅ **Deployed** it to TON testnet
-- ✅ **Interacted** with it using TypeScript scripts
-- ✅ **Mastered** the fundamentals of TON development
+- **Built** a complete smart contract in Tolk
+- **Deployed** it to TON testnet
+- **Interacted** with it using TypeScript scripts
+- **Mastered** the fundamentals of TON development
## What is a TON smart contract?
From 476a337bb0d80439a77422bd711476d9bf3e4f13 Mon Sep 17 00:00:00 2001
From: aigerimu <89766357+aigerimu@users.noreply.github.com>
Date: Fri, 14 Nov 2025 02:02:02 +0700
Subject: [PATCH 02/10] mid
---
contract-dev/first-smart-contract.mdx | 885 +++++++++++++-------------
1 file changed, 447 insertions(+), 438 deletions(-)
diff --git a/contract-dev/first-smart-contract.mdx b/contract-dev/first-smart-contract.mdx
index 5da114878..6a4583e77 100644
--- a/contract-dev/first-smart-contract.mdx
+++ b/contract-dev/first-smart-contract.mdx
@@ -3,91 +3,78 @@ title: "Your first smart contract"
---
import { Aside } from "/snippets/aside.jsx";
+import { FenceTable } from "/snippets/fence-table.jsx";
-Welcome to your journey into TON smart contract development! In this comprehensive tutorial, you'll learn to build, deploy, and interact with a smart contract from scratch.
+This tutorial covers building, deploying, and interacting with a smart contract on TON from start to finish.
-## What you'll learn
+## Prerequisites
-By the end of this tutorial, you'll have:
+- Basic programming: variables, functions, if/else statements
+- Basic familiarity with a command‑line interface and executing commands
+- Node.js—v22 or later— [download here](https://nodejs.org/)
+ - Check if installed: `node -v` in terminal
+- [TON wallet](/ecosystem/wallet-apps/overview)
-- **Built** a complete smart contract in Tolk
-- **Deployed** it to TON testnet
-- **Interacted** with it using TypeScript scripts
-- **Mastered** the fundamentals of TON development
-## What is a TON smart contract?
+## Development environment
-### Understanding the basics
+
+
-A **smart contract** is a computer program stored on [TON Blockchain](/foundations/overview) — a distributed database that many computers maintain together. It runs on the [TVM](/tvm/overview) (TON Virtual Machine) — the "computer" that runs smart contract code on TON.
+ Use the [Blueprint](/contract-dev/blueprint/overview) development toolkit for smart contracts. Start a new project with:
-The contract is made of two parts:
+ ```bash
+ npm create ton@latest -- Example --contractName FirstContract --type tolk-empty
+ ```
-- **Code** (compiled TVM instructions) - the "rules" or "program logic"
-- **Data** (persistent state) - the "memory" that remembers things between interactions
+ This command creates a project named "Example", containing a contract named "FirstContract".
-Both are stored at a specific **address** on TON Blockchain, a unique identifier for each smart contract.
+ The generated project structure is:
-## Prerequisites
+
+ Example/
+ ├──contracts/ # smart contract source code
+ │ └── first_contract.tolk # main contract file
+ ├── scripts/ # deployment and on-chain interaction scripts
+ │ └── deployFirstContract.ts # script to deploy the contract
+ ├── tests/ # testing specifications
+ │ └── FirstContract.spec.ts # contract test file
+ ├── wrappers/ # TypeScript wrappers for contract interaction
+ │ ├── FirstContract.ts # wrapper class for the smart contract
+ │ └── FirstContract.compile.ts # configuration for compiling contract
-- **Basic programming** - Understanding of variables, functions, if/else statements
-- **Command line basics** - Comfortable opening terminal and running commands
-- **Node.js** (v22 or later) — [Download here](https://nodejs.org/)
- - Check if installed: `node -v` in terminal
-- **TON wallet** - see the [wallet apps overview](/ecosystem/wallet-apps/overview)
+
-## Tutorial overview
+
-This tutorial is organized into six clear steps that build upon each other:
+
-| Step | What You'll Do | Key Skills |
-| ------------------------------------------------------------------ | --------------------------- | ---------------------------------------------------- |
-| **[Step 1](#step-1%3A-development-environment-setup)** | Set up Blueprint toolkit | Project structure, development environment |
-| **[Step 2](#step-2%3A-understanding-smart-contract-architecture)** | Learn contract architecture | Storage, messages, getters concept |
-| **[Step 3](#step-3%3A-writing-the-smart-contract)** | Write contract in Tolk | Programming, message handling, data structures |
-| **[Step 4](#step-4%3A-compiling-your-contract)** | Compile to bytecode | Build process, TVM compilation |
-| **[Step 5](#step-5%3A-deploying-to-testnet)** | Deploy to blockchain | Testnet deployment, wallet integration |
-| **[Step 6](#step-6%3A-contract-interaction)** | Interact with contract | Message sending, get methods, TypeScript integration |
+
-Let's dive into development!
+ ```bash
+ cd Example
+ ```
-## Step 1: Development environment setup
+
+
-We'll use [**Blueprint**](/contract-dev/blueprint/overview) as our development toolkit for smart contracts. Start a new project with:
-```bash
-npm create ton@latest -- Example --contractName FirstContract --type tolk-empty
-```
-
-This will create a project **Example** with a contract **FirstContract**.
-
-The project structure will look like this:
-
-```text
-Example/
-├── contracts/ # Smart contract source code
-│ └── first_contract.tolk # Main contract file
-├── scripts/ # Deployment and on-chain interaction scripts
-│ └── deployFirstContract.ts # Script to deploy the contract
-├── tests/ # Testing specifications
-│ └── FirstContract.spec.ts # Contract test file
-└── wrappers/ # TypeScript wrappers for contract interaction
- ├── FirstContract.ts # Wrapper class for the smart contract
- └── FirstContract.compile.ts # Configuration for compiling contract
-```
+## Smart contract architecture
-
+A **smart contract** is a computer program stored on [TON Blockchain](/foundations/overview) — a distributed database that many computers maintain together. It runs on the [TVM](/tvm/overview) (TON Virtual Machine) — the "computer" that runs smart contract code on TON.
-Now, move into the project directory:
+The contract is made of two parts:
-```bash
-cd Example
-```
+- **Code** (compiled TVM instructions) - the "rules" or "program logic"
+- **Data** (persistent state) - the "memory" that remembers things between interactions
-## Step 2: Understanding smart contract architecture
+Both are stored at a specific **address** on TON Blockchain, a unique identifier for each smart contract.
Every smart contract in TON is typically divided into three sections: **storage**, **messages**, and **getters**.
@@ -102,189 +89,188 @@ Every smart contract in TON is typically divided into three sections: **storage*
Inter-contract communication is possible only through **messages**.
-## Step 3: Writing the smart contract
+## Write the smart contract
-We’ll build a simple **counter** contract:
+To build a simple counter contract:
+- Start with an initial counter value.
+- Send `increase` messages to add to the counter or `reset` messages to set it to 0.
+- Call a `getter` to return the current counter value.
-- The counter starts from an initial number.
-- Users can send an `increase` message to increment it, or a `reset` message to drop it to zero.
-- A `getter` function will let anyone query the current counter value.
+The contract uses [**Tolk**](/languages/tolk). Tolk syntax is similar to TypeScript and Rust, designed for smart contract development.
-We'll use [**Tolk**](/languages/tolk) to implement this. Tolk looks familiar if you know TypeScript or Rust, but it's designed specifically for smart contract development.
+
+
-### 3.1 Defining contract storage
+ To define contract storage, store the counter value. Tolk makes it simple with structures:
-First, we need a way to store the counter value. Tolk makes this simple with structures:
-
-```tolk title="./contracts/first_contract.tolk"
-struct Storage {
+ ```tolk title="./contracts/first_contract.tolk"
+ struct Storage {
counter: uint64; // the current counter value
-}
+ }
-// load contract data from persistent storage
-fun Storage.load() {
+ // load contract data from persistent storage
+ fun Storage.load() {
return Storage.fromCell(contract.getData())
-}
+ }
-// save contract data to persistent storage
-fun Storage.save(self) {
+ // save contract data to persistent storage
+ fun Storage.save(self) {
contract.setData(self.toCell())
-}
-```
+ }
+ ```
-Behind the scenes, structures know how to serialize and deserialize themselves into [cells](/foundations/serialization/cells) — the fundamental way TON stores data. This happens through the `fromCell` and `toCell` functions - Tolk automatically converts between your nice structures and the cell format that TON understands.
-You may think of cells like containers that hold data on TON:
+ Structures serialize and deserialize automatically into [cells](/foundations/serialization/cells), the storage unit in TON. The `fromCell` and `toCell` functions handle conversion between structures and cells.
-- Each cell can store up to 1023 bits of data.
-- Cells can reference other cells (like links).
-- Everything on TON (contracts, messages, storage) is made of cells.
+
-Now that we can store data, let’s handle our first messages.
+
-### 3.2 Implementing message handlers
+ To process messages, implement the `onInternalMessage` function. It receives one argument — the incoming message. Focus on the `body` field, which contains the payload sent by a user or another contract.
-The main entry point for processing messages in a Tolk contract is the `onInternalMessage` function. It receives one argument — the incoming message. Among its fields, the most important one for us is `body`, which contains the payload sent by a user or another contract.
+ Define two message structures:
-Tolk structures are also useful for defining message bodies. In our case, we’ll define two messages:
+ - `IncreaseCounter` — contains one field `increaseBy` to increment the counter.
+ - `ResetCounter` — resets the counter to 0.
-- `IncreaseCounter` — with one field `increaseBy`, used to increment the counter.
-- `ResetCounter` — used to reset the counter to zero.
+ Each structure has a unique prefix —`0x7e8764ef` and `0x3a752f06`— called opcodes, that which allows the contract to distinguish between messages.
-Each structure has a unique prefix (`0x7e8764ef` and `0x3a752f06`), widely called opcodes, that lets the contract distinguish between them.
-```tolk title="./contracts/first_contract.tolk"
-struct(0x7e8764ef) IncreaseCounter {
+ ```tolk title="./contracts/first_contract.tolk"
+ struct(0x7e8764ef) IncreaseCounter {
increaseBy: uint32
-}
+ }
-struct(0x3a752f06) ResetCounter {}
-```
+ struct(0x3a752f06) ResetCounter {}
+ ```
-To group them together, we'll use a union. Unions allow multiple types to be bundled into a single type that can be serialized and deserialized automatically:
+ Group the messages into a union. A union bundles multiple types into a single type and supports automatic serialization and deserialization:
-```tolk title="./contracts/first_contract.tolk"
-type AllowedMessage = IncreaseCounter | ResetCounter;
-```
+ ```tolk title="./contracts/first_contract.tolk"
+ type AllowedMessage = IncreaseCounter | ResetCounter;
+ ```
-Now we can write our message handler:
+ Now implement the message handler:
-```tolk title="./contracts/first_contract.tolk"
-fun onInternalMessage(in: InMessage) {
+ ```tolk title="./contracts/first_contract.tolk"
+ fun onInternalMessage(in: InMessage) {
// use `lazy` to defer parsing until fields are accessed
val msg = lazy AllowedMessage.fromSlice(in.body);
- // matching our union to determine body structure
+ // matching the union to determine body structure
match (msg) {
- IncreaseCounter => {
- // load contract storage lazily (efficient for large or partial reads/updates)
- var storage = lazy Storage.load();
- storage.counter += msg.increaseBy;
- storage.save();
- }
-
- ResetCounter => {
- var storage = lazy Storage.load();
- storage.counter = 0;
- storage.save();
- }
-
- // this match branch would be executed if the message body does not match IncreaseCounter or ResetCounter structures
- else => {
- // reject user message (throw) if body is not empty
- assert(in.body.isEmpty()) throw 0xFFFF
- }
- }
-}
-```
-
-
-
-### 3.3 Adding getter functions
-
-Finally, let’s implement a getter so users can read the current counter value:
-
-```tolk title="./contracts/first_contract.tolk"
-get fun currentCounter(): int {
+ IncreaseCounter => {
+ // load contract storage lazily (efficient for large or partial reads/updates)
+ var storage = lazy Storage.load();
+ storage.counter += msg.increaseBy;
+ storage.save();
+ }
+
+ ResetCounter => {
+ var storage = lazy Storage.load();
+ storage.counter = 0;
+ storage.save();
+ }
+
+ // this match branch would be executed if the message body does not match IncreaseCounter or ResetCounter structures
+ else => {
+ // reject user message (throw) if body is not empty
+ assert(in.body.isEmpty()) throw 0xFFFF
+ }
+ }
+ }
+ ```
+
+
+
+
+ Write a getter function to return the current counter:
+
+ ```tolk title="./contracts/first_contract.tolk"
+ get fun currentCounter(): int {
val storage = lazy Storage.load();
return storage.counter;
-}
-```
+ }
+ ```
-### 3.4 Complete contract code
+
-We now have a complete smart contract with:
+
-- **Storage**: persistent `counter` value
-- **Messages**: `IncreaseCounter` and `ResetCounter` handlers
-- **Getter**: `currentCounter`
+ The contract now includes:
+ - Storage — persistent `counter` value
+ - Messages — `IncreaseCounter` and `ResetCounter` handlers
+ - Getter — `currentCounter` function
-Here’s the full source code of `contracts/first_contract.tolk`:
+
-```tolk title="./contracts/first_contract.tolk" expandable
-struct Storage {
- counter: uint64;
-}
+ ```tolk title="./contracts/first_contract.tolk"
+ struct Storage {
+ counter: uint64;
+ }
-fun Storage.load() {
- return Storage.fromCell(contract.getData());
-}
+ fun Storage.load() {
+ return Storage.fromCell(contract.getData());
+ }
-fun Storage.save(self) {
- contract.setData(self.toCell());
-}
+ fun Storage.save(self) {
+ contract.setData(self.toCell());
+ }
-struct(0x7e8764ef) IncreaseCounter {
- increaseBy: uint32
-}
+ struct(0x7e8764ef) IncreaseCounter {
+ increaseBy: uint32
+ }
-struct(0x3a752f06) ResetCounter {}
+ struct(0x3a752f06) ResetCounter {}
-type AllowedMessage = IncreaseCounter | ResetCounter;
+ type AllowedMessage = IncreaseCounter | ResetCounter;
-fun onInternalMessage(in: InMessage) {
- val msg = lazy AllowedMessage.fromSlice(in.body);
+ fun onInternalMessage(in: InMessage) {
+ val msg = lazy AllowedMessage.fromSlice(in.body);
- match (msg) {
- IncreaseCounter => {
- var storage = lazy Storage.load();
- storage.counter += msg.increaseBy;
- storage.save();
- }
+ match (msg) {
+ IncreaseCounter => {
+ var storage = lazy Storage.load();
+ storage.counter += msg.increaseBy;
+ storage.save();
+ }
- ResetCounter => {
- var storage = lazy Storage.load();
- storage.counter = 0;
- storage.save();
- }
+ ResetCounter => {
+ var storage = lazy Storage.load();
+ storage.counter = 0;
+ storage.save();
+ }
- else => {
- assert(in.body.isEmpty()) throw 0xFFFF;
- }
+ else => {
+ assert(in.body.isEmpty()) throw 0xFFFF;
+ }
+ }
}
-}
-get fun currentCounter(): int {
- val storage = lazy Storage.load();
- return storage.counter;
-}
-```
+ get fun currentCounter(): int {
+ val storage = lazy Storage.load();
+ return storage.counter;
+ }
+ ```
-🎉 Congratulations — you've built your first smart contract in **Tolk**!
+
-
+
+
+
-## Step 4: Compiling your contract
-The next step is to build our contract — compile it into bytecode that can be executed by the TVM. With **Blueprint**, this takes one command:
+## Compile the contract
+
+To build the contract, compile it into bytecode for execution by the TVM. Use Blueprint with command:
```bash
npx blueprint build FirstContract
@@ -307,354 +293,377 @@ Build script running, compiling FirstContract
✅ Wrote compilation artifact to build/FirstContract.compiled.json
```
-This compilation artifact contains the **contract bytecode** and will be used in the deployment step.
+The compilation artifact contains the contract bytecode. This file is required for deployment.
-In the next section, we'll learn how to **deploy this contract to the TON blockchain** and interact with it using scripts and wrappers.
+Next, deploy the contract to the TON blockchain and interact with it using scripts and wrappers.
-## Step 5: Deploying to testnet
+## Deploy to testnet
-Ready to put your contract on-chain? 🚀
+
+
-To deploy, we first need a **wrapper class**. Wrappers implement the `Contract` interface and make it easy to interact with contracts from TypeScript.
+ Create a wrapper class to deploy and interact with the contract. Wrappers implement the `Contract` interface and TypeScript integration.
-Create a file `./wrappers/FirstContract.ts` with the following code:
+ Create `./wrappers/FirstContract.ts` with the following code:
-```typescript title="./wrappers/FirstContract.ts"
-import { Address, beginCell, Cell, Contract, contractAddress, ContractProvider, Sender, SendMode } from '@ton/core';
+ ```typescript title="./wrappers/FirstContract.ts"
+ import { Address, beginCell, Cell, Contract, contractAddress, ContractProvider, Sender, SendMode } from '@ton/core';
-export class FirstContract implements Contract {
+ export class FirstContract implements Contract {
constructor(
- readonly address: Address,
- readonly init?: { code: Cell; data: Cell },
+ readonly address: Address,
+ readonly init?: { code: Cell; data: Cell },
) {}
static createFromConfig(config: { counter: number }, code: Cell, workchain = 0) {
- const data = beginCell().storeUint(config.counter, 64).endCell();
- const init = { code, data };
- return new FirstContract(contractAddress(workchain, init), init);
- }
+ const data = beginCell().storeUint(config.counter, 64).endCell();
+ const init = { code, data };
+ return new FirstContract(contractAddress(workchain, init), init);
+ }
async sendDeploy(provider: ContractProvider, via: Sender, value: bigint) {
- await provider.internal(via, {
- value,
- sendMode: SendMode.PAY_GAS_SEPARATELY,
- });
- }
-}
-```
+ await provider.internal(via, {
+ value,
+ sendMode: SendMode.PAY_GAS_SEPARATELY,
+ });
+ }
+ }
+ ```
+
+ Wrapper class details:
-### 5.1 Understanding the wrapper class
+ - [`@ton/core`](https://www.npmjs.com/package/@ton/core) — a library with base TON types.
+ - The function `createFromConfig` builds a wrapper using:
+ - code — compiled bytecode
+ - data — the initial storage layout
+ - The contract [address](/foundations/addresses/overview) is derived deterministically from `code + data` using `contractAddress`.
+ - The method `sendDeploy` sends the first message with `stateInit`, triggering deployment. In practice, this can be an empty message with Toncoin attached.
-- We depend on [`@ton/core`](https://www.npmjs.com/package/@ton/core) — a library with base TON types.
-- The function `createFromConfig` constructs a wrapper using **code** (compiled bytecode) and **data** (the initial storage layout).
-- The contract [address](/foundations/addresses/overview) is derived deterministically from `code + data` using `contractAddress`. If two contracts have the same code and init data, the calculation of the address will result in the same value.
-- The method `sendDeploy` sends the first message with `stateInit`, which triggers deployment. In practice, this can be an empty message with some TON coins attached.
+
-### 5.2 Choosing your network
+
-TON has two networks available for deployment:
+ TON provides two networks for deployment:
-- **testnet** — developer sandbox.
-- **mainnet** — production blockchain.
+ - **testnet** — developer sandbox.
+ - **mainnet** — production blockchain.
-For this tutorial, we'll use **testnet** since it's free and perfect for learning. You can always deploy to mainnet later once you're confident in your contract.
+ This tutorial uses testnet. Mainnet deployment is possible once the contract is verified and ready for production.
-### 5.3 Creating the deployment script
+
-Blueprint makes deployment simple. Create a new script `./scripts/deployFirstContract.ts`:
+
-```typescript title="./scripts/deployFirstContract.ts"
-import { toNano } from '@ton/core';
-import { FirstContract } from '../wrappers/FirstContract';
-import { compile, NetworkProvider } from '@ton/blueprint';
+ Write a script `./scripts/deployFirstContract.ts` to deploy the contract:
-export async function run(provider: NetworkProvider) {
+ ```typescript title="./scripts/deployFirstContract.ts"
+ import { toNano } from '@ton/core';
+ import { FirstContract } from '../wrappers/FirstContract';
+ import { compile, NetworkProvider } from '@ton/blueprint';
+
+ export async function run(provider: NetworkProvider) {
const firstContract = provider.open(
- FirstContract.createFromConfig(
- { counter: Math.floor(Math.random() * 10000000) },
- await compile('FirstContract')
- )
+ FirstContract.createFromConfig(
+ { counter: Math.floor(Math.random() * 10000000) },
+ await compile('FirstContract')
+ )
);
await firstContract.sendDeploy(provider.sender(), toNano('0.05'));
await provider.waitForDeploy(firstContract.address);
-}
-```
+ }
+ ```
-The `sendDeploy` method accepts three arguments, but we only pass two because `provider.open` automatically supplies the ContractProvider as the first argument.
+ The `sendDeploy` method accepts three arguments. Only two arguments are passed because `provider.open` automatically provides the `ContractProvider` as the first argument.
-Run the script with ([learn more about Blueprint deployment](/contract-dev/blueprint/deploy)):
+
-```bash
-npx blueprint run deployFirstContract --testnet --tonconnect --tonviewer
-```
+
-Choose your wallet, scan the QR code shown in the console, and approve the transaction in your wallet app.
+ Run the script with:
-Expected output:
+ ```bash
+ npx blueprint run deployFirstContract --testnet --tonconnect --tonviewer
+ ```
-```text
-Using file: deployFirstContract
-? Choose your wallet Tonkeeper
+ Learn more about [Blueprint deployment](/contract-dev/blueprint/deploy).
-
+
+
-Connected to wallet at address: ...
-Sending transaction. Approve in your wallet...
-Sent transaction
-Contract deployed at address kQBz-OQQ0Olnd4IPdLGZCqHkpuAO3zdPqAy92y6G-UUpiC_o
-You can view it at https://testnet.tonviewer.com/kQBz-OQQ0Olnd4IPdLGZCqHkpuAO3zdPqAy92y6G-UUpiC_o
-```
+
+
+ Choose the wallet, scan the QR code displayed in the console, and confirm the transaction in your wallet app.
+
+ Expected output:
+
+ ```text
+ Using file: deployFirstContract
+ ? Choose your wallet Tonkeeper
-Follow the link in the console to see your contract on the **Tonviewer**. Blockchain explorers like [Tonviewer](/ecosystem/explorers/tonviewer) allow you to inspect transactions, smart contracts, and account states on the TON blockchain.
+
-🎉 Congratulations! Your contract is live on testnet. Let's interact with it by sending messages and calling get methods.
+ Connected to wallet at address: ...
+ Sending transaction. Approve in your wallet...
+ Sent transaction
+ Contract deployed at address kQBz-OQQ0Olnd4IPdLGZCqHkpuAO3zdPqAy92y6G-UUpiC_o
+ You can view it at https://testnet.tonviewer.com/kQBz-OQQ0Olnd4IPdLGZCqHkpuAO3zdPqAy92y6G-UUpiC_o
+ ```
-## Step 6: Contract interaction
+ The link opens the contract on [Tonviewer](/ecosystem/explorers/tonviewer), a [blockchain explorer](/ecosystem/explorers/overview) showing transactions, messages, and account data.
+
+ Next, interact with the contract by sending messages and calling getter functions.
+
+
+
+
+
+## Contract interaction
Technically speaking, we've already sent messages to the contract - the deploy message in previous steps. Now let's see how to send messages with a body.
-First of all, we should update our wrapper class with three methods: `sendIncrease`, `sendReset`, and `getCounter`:
-```typescript title="./wrappers/FirstContract.ts"
-import { Address, beginCell, Cell, Contract, contractAddress, ContractProvider, Sender, SendMode } from '@ton/core';
+
-export class FirstContract implements Contract {
- constructor(
- readonly address: Address,
- readonly init?: { code: Cell; data: Cell },
- ) {}
+
+ Update our wrapper class with three methods: `sendIncrease`, `sendReset`, and `getCounter`:
- static createFromConfig(config: { counter: number }, code: Cell, workchain = 0) {
- const data = beginCell().storeUint(config.counter, 64).endCell();
- const init = { code, data };
- return new FirstContract(contractAddress(workchain, init), init);
- }
+ ```typescript title="./wrappers/FirstContract.ts" expandable
+ import { Address, beginCell, Cell, Contract, contractAddress, ContractProvider, Sender, SendMode } from '@ton/core';
- async sendDeploy(provider: ContractProvider, via: Sender, value: bigint) {
- await provider.internal(via, {
- value,
- sendMode: SendMode.PAY_GAS_SEPARATELY,
- body: beginCell().endCell(),
- });
+ export class FirstContract implements Contract {
+ constructor(
+ readonly address: Address,
+ readonly init?: { code: Cell; data: Cell },
+ ) {}
+
+ static createFromConfig(config: { counter: number }, code: Cell, workchain = 0) {
+ const data = beginCell().storeUint(config.counter, 64).endCell();
+ const init = { code, data };
+ return new FirstContract(contractAddress(workchain, init), init);
}
- async sendIncrease(
- provider: ContractProvider,
- via: Sender,
- opts: {
- increaseBy: number;
- value: bigint;
- },
- ) {
- await provider.internal(via, {
- value: opts.value,
- sendMode: SendMode.PAY_GAS_SEPARATELY,
- body: beginCell().storeUint(0x7e8764ef, 32).storeUint(opts.increaseBy, 32).endCell(),
- });
+ async sendDeploy(provider: ContractProvider, via: Sender, value: bigint) {
+ await provider.internal(via, {
+ value,
+ sendMode: SendMode.PAY_GAS_SEPARATELY,
+ body: beginCell().endCell(),
+ });
}
- async sendReset(
- provider: ContractProvider,
- via: Sender,
- opts: {
- value: bigint;
- },
- ) {
- await provider.internal(via, {
- value: opts.value,
- sendMode: SendMode.PAY_GAS_SEPARATELY,
- body: beginCell().storeUint(0x3a752f06, 32).endCell(),
- });
+ async sendIncrease(
+ provider: ContractProvider,
+ via: Sender,
+ opts: {
+ increaseBy: number;
+ value: bigint;
+ },
+ ) {
+ await provider.internal(via, {
+ value: opts.value,
+ sendMode: SendMode.PAY_GAS_SEPARATELY,
+ body: beginCell().storeUint(0x7e8764ef, 32).storeUint(opts.increaseBy, 32).endCell(),
+ });
}
- async getCounter(provider: ContractProvider) {
- const result = await provider.get('currentCounter', []);
- return result.stack.readNumber();
+ async sendReset(
+ provider: ContractProvider,
+ via: Sender,
+ opts: {
+ value: bigint;
+ },
+ ) {
+ await provider.internal(via, {
+ value: opts.value,
+ sendMode: SendMode.PAY_GAS_SEPARATELY,
+ body: beginCell().storeUint(0x3a752f06, 32).endCell(),
+ });
}
-}
-```
-The only difference from the deploy message is that we pass a **body** to it — remember the cells I talked about previously? The message body is a cell that contains our instructions.
+ async getCounter(provider: ContractProvider) {
+ const result = await provider.get('currentCounter', []);
+ return result.stack.readNumber();
+ }
+ }
+ ```
-### Building message bodies
+ The only difference from the deploy message is that we pass a **body** to it — remember the cells I talked about previously? The message body is a cell that contains our instructions.
-Construction of cells starts with the `beginCell` method ([learn more about cell serialization](/foundations/serialization/cells)):
+ **Building message bodies**
-- `beginCell()` - creates a new cell builder
-- `storeUint(value, bits)` - adds an unsigned integer of specified bit length
-- `endCell()` - finalizes the cell
+ Construction of cells starts with the `beginCell` method:
-**Example**: `beginCell().storeUint(0x7e8764ef, 32).storeUint(42, 32).endCell()`
+ - `beginCell()` - creates a new cell builder
+ - `storeUint(value, bits)` - adds an unsigned integer of specified bit length
+ - `endCell()` - finalizes the cell
-- First 32 bits: `0x7e8764ef` (opcode for "increase")
-- Next 32 bits: `42` (increase by this amount)
+ **Example**: `beginCell().storeUint(0x7e8764ef, 32).storeUint(42, 32).endCell()`
-### 6.1 Sending messages to your contract
+ - First 32 bits: `0x7e8764ef` (opcode for "increase")
+ - Next 32 bits: `42` (increase by this amount)
+
-Now that our contract is deployed and we have wrapper methods, let's interact with it by sending messages.
+
-Let's create a script `./scripts/sendIncrease.ts` that would increase the counter:
+ Now that our contract is deployed and we have wrapper methods, let's interact with it by sending messages.
-```typescript title="./scripts/sendIncrease.ts"
-import { Address, toNano } from '@ton/core';
-import { FirstContract } from '../wrappers/FirstContract';
-import { NetworkProvider } from '@ton/blueprint';
+ Let's create a script `./scripts/sendIncrease.ts` that would increase the counter:
-const contractAddress = Address.parse('');
+ ```typescript title="./scripts/sendIncrease.ts"
+ import { Address, toNano } from '@ton/core';
+ import { FirstContract } from '../wrappers/FirstContract';
+ import { NetworkProvider } from '@ton/blueprint';
-export async function run(provider: NetworkProvider) {
- const firstContract = provider.open(new FirstContract(contractAddress));
- await firstContract.sendIncrease(provider.sender(), { value: toNano('0.05'), increaseBy: 42 });
- await provider.waitForLastTransaction();
-}
-```
+ const contractAddress = Address.parse('');
-Do not forget to replace `` with your actual contract address from Step 5!
+ export async function run(provider: NetworkProvider) {
+ const firstContract = provider.open(new FirstContract(contractAddress));
+ await firstContract.sendIncrease(provider.sender(), { value: toNano('0.05'), increaseBy: 42 });
+ await provider.waitForLastTransaction();
+ }
+ ```
-#### Understanding the script breakdown:
+ Do not forget to replace `` with your actual contract address from Step 5!
-- **Address parsing**: `Address.parse()` converts the string address to a TON Address object
-- **Contract opening**: `provider.open()` creates a connection to the deployed contract
-- **Value attachment**: `toNano('0.05')` converts 0.05 TON to nanotons (the smallest TON unit)
-- **Message parameters**: `increaseBy: 42` tells the contract to increase the counter by 42
-- **Transaction waiting**: `waitForLastTransaction()` waits for the transaction to be processed on-chain
+ **Understanding the script breakdown:**
-To run this script:
+ - **Address parsing**: `Address.parse()` converts the string address to a TON Address object
+ - **Contract opening**: `provider.open()` creates a connection to the deployed contract
+ - **Value attachment**: `toNano('0.05')` converts 0.05 TON to nanotons (the smallest TON unit)
+ - **Message parameters**: `increaseBy: 42` tells the contract to increase the counter by 42
+ - **Transaction waiting**: `waitForLastTransaction()` waits for the transaction to be processed on-chain
-```bash
-npx blueprint run sendIncrease --testnet --tonconnect --tonviewer
-```
+ To run this script:
-Expected result:
+ ```bash
+ npx blueprint run sendIncrease --testnet --tonconnect --tonviewer
+ ```
-```text
-Using file: sendIncrease
-Connected to wallet at address: ...
-Sending transaction. Approve in your wallet...
-Sent transaction
-Transaction 0fc1421b06b01c65963fa76f5d24473effd6d63fc4ea3b6ea7739cc533ba62ee successfully applied!
-You can view it at https://testnet.tonviewer.com/transaction/fe6380dc2e4fab5c2caf41164d204e2f41bebe7a3ad2cb258803759be41b5734
-```
+ Expected result:
-#### What happens during execution:
+ ```text
+ Using file: sendIncrease
+ Connected to wallet at address: ...
+ Sending transaction. Approve in your wallet...
+ Sent transaction
+ Transaction 0fc1421b06b01c65963fa76f5d24473effd6d63fc4ea3b6ea7739cc533ba62ee successfully applied!
+ You can view it at https://testnet.tonviewer.com/transaction/fe6380dc2e4fab5c2caf41164d204e2f41bebe7a3ad2cb258803759be41b5734
+ ```
-1. **Wallet Connection**: Blueprint connects to your wallet using [TON Connect](/ecosystem/ton-connect/overview) protocol
-1. **Transaction Building**: The script creates a transaction with the message body containing the opcode `0x7e8764ef` and the value `42`
-1. **User Approval**: Your wallet app shows the transaction details for approval
-1. **Blockchain Processing**: Once approved, the transaction is sent to the TON network
-1. **Validator Consensus**: Validators need to produce a new block containing your transaction
-1. **Contract Execution**: The contract receives the message, processes it in the `onInternalMessage` function, and updates the counter
-1. **Confirmation**: The transaction hash is returned, and you can view it on the explorer
+ **What happens during execution:**
-
+ 1. **Wallet Connection**: Blueprint connects to your wallet using [TON Connect](/ecosystem/ton-connect/overview) protocol
+ 1. **Transaction Building**: The script creates a transaction with the message body containing the opcode `0x7e8764ef` and the value `42`
+ 1. **User Approval**: Your wallet app shows the transaction details for approval
+ 1. **Blockchain Processing**: Once approved, the transaction is sent to the TON network
+ 1. **Validator Consensus**: Validators need to produce a new block containing your transaction
+ 1. **Contract Execution**: The contract receives the message, processes it in the `onInternalMessage` function, and updates the counter
+ 1. **Confirmation**: The transaction hash is returned, and you can view it on the explorer
-Let's create a script `./scripts/sendReset.ts` that would reset the counter:
+
+
-```typescript title="./scripts/sendReset.ts"
-import { Address, toNano } from '@ton/core';
-import { FirstContract } from '../wrappers/FirstContract';
-import { NetworkProvider } from '@ton/blueprint';
+
+ Let's create a script `./scripts/sendReset.ts` that would reset the counter:
-const contractAddress = Address.parse('');
+ ```typescript title="./scripts/sendReset.ts"
+ import { Address, toNano } from '@ton/core';
+ import { FirstContract } from '../wrappers/FirstContract';
+ import { NetworkProvider } from '@ton/blueprint';
-export async function run(provider: NetworkProvider) {
- const firstContract = provider.open(new FirstContract(contractAddress));
- await firstContract.sendReset(provider.sender(), { value: toNano('0.05') });
- await provider.waitForLastTransaction();
-}
-```
+ const contractAddress = Address.parse('');
-To run this script:
+ export async function run(provider: NetworkProvider) {
+ const firstContract = provider.open(new FirstContract(contractAddress));
+ await firstContract.sendReset(provider.sender(), { value: toNano('0.05') });
+ await provider.waitForLastTransaction();
+ }
+ ```
-```bash
-npx blueprint run sendReset --testnet --tonconnect --tonviewer
-```
+ To run this script:
-Expected result:
+ ```bash
+ npx blueprint run sendReset --testnet --tonconnect --tonviewer
+ ```
-```text
-Using file: sendReset
-Connected to wallet at address: ...
-Sending transaction. Approve in your wallet...
-Sent transaction
-Transaction 0fc1421b06b01c65963fa76f5d24473effd6d63fc4ea3b6ea7739cc533ba62ee successfully applied!
-You can view it at https://testnet.tonviewer.com/transaction/fe6380dc2e4fab5c2caf41164d204e2f41bebe7a3ad2cb258803759be41b5734
-```
+ Expected result:
-### 6.2 Reading contract data with get methods
+ ```text
+ Using file: sendReset
+ Connected to wallet at address: ...
+ Sending transaction. Approve in your wallet...
+ Sent transaction
+ Transaction 0fc1421b06b01c65963fa76f5d24473effd6d63fc4ea3b6ea7739cc533ba62ee successfully applied!
+ You can view it at https://testnet.tonviewer.com/transaction/fe6380dc2e4fab5c2caf41164d204e2f41bebe7a3ad2cb258803759be41b5734
+ ```
-Get methods are special functions in TON smart contracts that allow you to read data without modifying the contract state or spending gas fees. Unlike message-based interactions, get methods:
+
-- **Cost nothing**: No gas fees required since they don't modify blockchain state
-- **Execute instantly**: No need to wait for blockchain confirmation
-- **Read-only**: Cannot change contract storage or send messages
+
-To call a get method, use `provider.get()`:
+ Get methods are special functions in TON smart contracts that allow you to read data without modifying the contract state or spending gas fees. Unlike message-based interactions, get methods:
-```typescript title="./scripts/getCounter.ts"
-import { Address } from '@ton/core';
-import { FirstContract } from '../wrappers/FirstContract';
-import { NetworkProvider } from '@ton/blueprint';
+ - **Cost nothing**: No gas fees required since they don't modify blockchain state
+ - **Execute instantly**: No need to wait for blockchain confirmation
+ - **Read-only**: Cannot change contract storage or send messages
-const contractAddress = Address.parse('');
+ To call a get method, use `provider.get()`:
-export async function run(provider: NetworkProvider) {
- const firstContract = provider.open(new FirstContract(contractAddress));
- const counter = await firstContract.getCounter();
- console.log('Counter: ', counter);
-}
-```
-
-#### Understanding the get method execution:
-
-1. **Direct contract call**: The `getCounter()` method directly calls the contract's `currentCounter` getter
-1. **Instant response**: The result is returned immediately without blockchain confirmation
-1. **Data parsing**: Our wrapper automatically converts the returned stack value to a JavaScript number
+ ```typescript title="./scripts/getCounter.ts"
+ import { Address } from '@ton/core';
+ import { FirstContract } from '../wrappers/FirstContract';
+ import { NetworkProvider } from '@ton/blueprint';
-
-
-To run this script:
-
-```bash
-npx blueprint run getCounter --testnet --tonconnect
-```
+ const contractAddress = Address.parse('');
-Expected output:
+ export async function run(provider: NetworkProvider) {
+ const firstContract = provider.open(new FirstContract(contractAddress));
+ const counter = await firstContract.getCounter();
+ console.log('Counter: ', counter);
+ }
+ ```
-```bash
-Using file: getCounter
-Counter: 42
-```
+ **Understanding the get method execution:**
-## 🎉 Tutorial complete!
+ 1. **Direct contract call**: The `getCounter()` method directly calls the contract's `currentCounter` getter
+ 1. **Instant response**: The result is returned immediately without blockchain confirmation
+ 1. **Data parsing**: Our wrapper automatically converts the returned stack value to a JavaScript number
-**Congratulations!** You've successfully built, deployed, and interacted with your first TON smart contract from scratch. This is a significant achievement in your blockchain development journey!
+
-### Continue Your Learning Journey
+ To run this script:
-Ready to build more advanced contracts? Here's your roadmap:
+ ```bash
+ npx blueprint run getCounter --testnet --tonconnect
+ ```
-#### **Next Steps**
+ Expected output:
-- [Tolk Language Guide](/languages/tolk) - Master advanced Tolk features and syntax
-- [Blueprint Documentation](/contract-dev/blueprint/overview) - Learn advanced development patterns
-- [Tutorial Example Repository](https://github.com/ton-org/docs-examples/tree/main/guidebook/first-smart-contract/Example) - Complete working code from this tutorial
+ ```bash
+ Using file: getCounter
+ Counter: 42
+ ```
-#### **Advanced Topics**
+
-- [Gas Optimization](/contract-dev/gas) - Reduce transaction costs
-- [Security Best Practices](/contract-dev/security) - Protect your contracts
+
-**🎉 Happy coding on TON!** You're now equipped with the fundamentals to build amazing smart contracts. The blockchain world awaits your innovations! 🚀
+
+
From df95910bf691a41ea97385015f3395a3736acda4 Mon Sep 17 00:00:00 2001
From: aigerimu <89766357+aigerimu@users.noreply.github.com>
Date: Fri, 14 Nov 2025 13:40:01 +0700
Subject: [PATCH 03/10] upd
---
contract-dev/first-smart-contract.mdx | 115 ++++++++++++--------------
1 file changed, 52 insertions(+), 63 deletions(-)
diff --git a/contract-dev/first-smart-contract.mdx b/contract-dev/first-smart-contract.mdx
index 6a4583e77..07829fc75 100644
--- a/contract-dev/first-smart-contract.mdx
+++ b/contract-dev/first-smart-contract.mdx
@@ -65,28 +65,26 @@ This tutorial covers building, deploying, and interacting with a smart contract
-## Smart contract architecture
+## Smart contract layout
-A **smart contract** is a computer program stored on [TON Blockchain](/foundations/overview) — a distributed database that many computers maintain together. It runs on the [TVM](/tvm/overview) (TON Virtual Machine) — the "computer" that runs smart contract code on TON.
+A smart contract is a program stored on [TON Blockchain](/foundations/overview) and executed by the [TVM](/tvm/overview).
+On-chain, every contract consists of two components:
-The contract is made of two parts:
+- Code — compiled [TVM instructions](), defines the contract's logic
+- Data — persistent state, stores information between interactions
-- **Code** (compiled TVM instructions) - the "rules" or "program logic"
-- **Data** (persistent state) - the "memory" that remembers things between interactions
+Both are stored at a specific [address]() on the TON Blockchain, which uniquely identifies each smart contract.
-Both are stored at a specific **address** on TON Blockchain, a unique identifier for each smart contract.
+A contract's data is organized into three functional sections: storage, messages, and getters:
-Every smart contract in TON is typically divided into three sections: **storage**, **messages**, and **getters**.
-
-- **Storage**: Defines the contract’s persistent data. For example, our _counter_ variable must keep its value across calls from different users.
-- **Messages**: Define how the contract reacts to incoming messages. On TON, the primary way to interact with contracts is by sending [messages](/foundations/transaction). Each processed message produces a [transaction](/foundations/transaction) — a recorded change on the blockchain (like "Alice sent 5 TON to Bob").
-- **Getters**: Provide read-only access to contract data without modifying state. For example, we’ll create a getter to return the current value of the counter.
+- Storage holds the contract’s persistent state. Example: the counter variable keeps its value across calls from different users.
+- Messages define how the contract reacts to incoming messages. On TON, the main way to interact with contracts is by sending [messages](). Each processed message produces a [transaction](), a recorded change on the blockchain. For example, a transfer of TON between accounts.
+- Getters are read-only functions that return contract data without modifying state. Example: a getter that returns the current counter value.
## Write the smart contract
@@ -427,8 +425,7 @@ Next, deploy the contract to the TON blockchain and interact with it using scrip
## Contract interaction
-Technically speaking, we've already sent messages to the contract - the deploy message in previous steps. Now let's see how to send messages with a body.
-
+Deployment also counts as a message sent to the contract. The next step is to send a message with a body to trigger contract logic.
@@ -494,51 +491,50 @@ Technically speaking, we've already sent messages to the contract - the deploy m
}
```
- The only difference from the deploy message is that we pass a **body** to it — remember the cells I talked about previously? The message body is a cell that contains our instructions.
+ The main difference from the deploy message is that these methods include a message body. The body is a cell that contains the instructions.
**Building message bodies**
- Construction of cells starts with the `beginCell` method:
+ Cells are constructed using the `beginCell` method:
+
+ - `beginCell()` creates a new cell builder.
+ - `storeUint(value, bits)` appends an unsigned integer with a fixed bit length.
+ - `endCell()` finalizes the cell.
- - `beginCell()` - creates a new cell builder
- - `storeUint(value, bits)` - adds an unsigned integer of specified bit length
- - `endCell()` - finalizes the cell
+ **Example**
- **Example**: `beginCell().storeUint(0x7e8764ef, 32).storeUint(42, 32).endCell()`
+ `beginCell().storeUint(0x7e8764ef, 32).storeUint(42, 32).endCell()`
- - First 32 bits: `0x7e8764ef` (opcode for "increase")
- - Next 32 bits: `42` (increase by this amount)
+ - First 32 bits: `0x7e8764ef` — opcode for "increase"
+ - Next 32 bits: `42` — increase by this amount
- Now that our contract is deployed and we have wrapper methods, let's interact with it by sending messages.
+ With the contract deployed and wrapper methods in place, the next step is to send messages to it.
- Let's create a script `./scripts/sendIncrease.ts` that would increase the counter:
+ Create a script `./scripts/sendIncrease.ts` that increases the counter:
```typescript title="./scripts/sendIncrease.ts"
import { Address, toNano } from '@ton/core';
import { FirstContract } from '../wrappers/FirstContract';
import { NetworkProvider } from '@ton/blueprint';
+ // `Address.parse()` converts string to address object
const contractAddress = Address.parse('');
export async function run(provider: NetworkProvider) {
+ // `provider.open()` creates a connection to the deployed contract
const firstContract = provider.open(new FirstContract(contractAddress));
+ // `toNano('0.05')` converts 0.05 TON to nanotons
+ // `increaseBy: 42` tells the contract to increase the counter by 42
await firstContract.sendIncrease(provider.sender(), { value: toNano('0.05'), increaseBy: 42 });
+ // `waitForLastTransaction()` waits for the transaction to be processed on-chain
await provider.waitForLastTransaction();
}
```
- Do not forget to replace `` with your actual contract address from Step 5!
-
- **Understanding the script breakdown:**
-
- - **Address parsing**: `Address.parse()` converts the string address to a TON Address object
- - **Contract opening**: `provider.open()` creates a connection to the deployed contract
- - **Value attachment**: `toNano('0.05')` converts 0.05 TON to nanotons (the smallest TON unit)
- - **Message parameters**: `increaseBy: 42` tells the contract to increase the counter by 42
- - **Transaction waiting**: `waitForLastTransaction()` waits for the transaction to be processed on-chain
+ Replace `` with the address obtained in the deployment step.
To run this script:
@@ -557,23 +553,24 @@ Technically speaking, we've already sent messages to the contract - the deploy m
You can view it at https://testnet.tonviewer.com/transaction/fe6380dc2e4fab5c2caf41164d204e2f41bebe7a3ad2cb258803759be41b5734
```
- **What happens during execution:**
+ What happens during execution:
+
+ 1. Blueprint connects to the wallet using the [TON Connect](/ecosystem/ton-connect/overview) protocol.
+ 1. The script builds a transaction with a message body containing opcode `0x7e8764ef` and value `42`.
+ 1. The wallet displays transaction details for confirmation.
+ 1. After approval, the transaction is sent to the network.
+ 1. Validators include the transaction in a newly produced block.
+ 1. The contract receives the message, processes it in `onInternalMessage`, and updates the counter.
+ 1. The script returns the resulting transaction hash, and you can inspect it in the explorer.
- 1. **Wallet Connection**: Blueprint connects to your wallet using [TON Connect](/ecosystem/ton-connect/overview) protocol
- 1. **Transaction Building**: The script creates a transaction with the message body containing the opcode `0x7e8764ef` and the value `42`
- 1. **User Approval**: Your wallet app shows the transaction details for approval
- 1. **Blockchain Processing**: Once approved, the transaction is sent to the TON network
- 1. **Validator Consensus**: Validators need to produce a new block containing your transaction
- 1. **Contract Execution**: The contract receives the message, processes it in the `onInternalMessage` function, and updates the counter
- 1. **Confirmation**: The transaction hash is returned, and you can view it on the explorer
-
- Let's create a script `./scripts/sendReset.ts` that would reset the counter:
+ To reset the counter, create a script `./scripts/sendReset.ts`:
```typescript title="./scripts/sendReset.ts"
import { Address, toNano } from '@ton/core';
@@ -610,11 +607,11 @@ Technically speaking, we've already sent messages to the contract - the deploy m
- Get methods are special functions in TON smart contracts that allow you to read data without modifying the contract state or spending gas fees. Unlike message-based interactions, get methods:
- - **Cost nothing**: No gas fees required since they don't modify blockchain state
- - **Execute instantly**: No need to wait for blockchain confirmation
- - **Read-only**: Cannot change contract storage or send messages
+ Get methods are special functions in TON smart contracts that run locally on a node. Unlike message-based interactions, get methods are:
+ - Free — no gas fees, as the call does not modify the blockchain state.
+ - Instant — no need to wait for blockchain confirmation.
+ - Read-only — can only read data; cannot modify storage or send messages.
To call a get method, use `provider.get()`:
@@ -627,19 +624,14 @@ Technically speaking, we've already sent messages to the contract - the deploy m
export async function run(provider: NetworkProvider) {
const firstContract = provider.open(new FirstContract(contractAddress));
- const counter = await firstContract.getCounter();
- console.log('Counter: ', counter);
+ // `getCounter()` сalls the contract's `currentCounter` getter
+ const counter = await firstContract.getCounter(); // returns instantly
+ console.log('Counter: ', counter); // wrapper parses stack into JS number
}
```
- **Understanding the get method execution:**
-
- 1. **Direct contract call**: The `getCounter()` method directly calls the contract's `currentCounter` getter
- 1. **Instant response**: The result is returned immediately without blockchain confirmation
- 1. **Data parsing**: Our wrapper automatically converts the returned stack value to a JavaScript number
-
To run this script:
@@ -659,11 +651,8 @@ Technically speaking, we've already sent messages to the contract - the deploy m
-
+The full code for this tutorial is available in the [GitHub repository](https://github.com/ton-org/docs-examples/tree/main/guidebook/first-smart-contract/Example). It includes all contract files, scripts, and wrappers ready to use.
+
From dcd682c0027dcb6b580ce75fb7cb8af626b0901a Mon Sep 17 00:00:00 2001
From: aigerimu <89766357+aigerimu@users.noreply.github.com>
Date: Fri, 14 Nov 2025 21:39:50 +0700
Subject: [PATCH 04/10] upd
---
contract-dev/first-smart-contract.mdx | 732 +++++++++++++-------------
1 file changed, 361 insertions(+), 371 deletions(-)
diff --git a/contract-dev/first-smart-contract.mdx b/contract-dev/first-smart-contract.mdx
index 07829fc75..94f85e947 100644
--- a/contract-dev/first-smart-contract.mdx
+++ b/contract-dev/first-smart-contract.mdx
@@ -11,122 +11,119 @@ This tutorial covers building, deploying, and interacting with a smart contract
- Basic programming: variables, functions, if/else statements
- Basic familiarity with a command‑line interface and executing commands
-- Node.js—v22 or later— [download here](https://nodejs.org/)
+- Node.js—`v22` or later— [download here](https://nodejs.org/)
- Check if installed: `node -v` in terminal
-- [TON wallet](/ecosystem/wallet-apps/overview)
-
+- Installed [TON wallet](/ecosystem/wallet-apps/overview) with [Toncoin on testnet](/contract-dev/testing/testnet-tokens)
## Development environment
-
-
-
- Use the [Blueprint](/contract-dev/blueprint/overview) development toolkit for smart contracts. Start a new project with:
-
- ```bash
- npm create ton@latest -- Example --contractName FirstContract --type tolk-empty
- ```
-
- This command creates a project named "Example", containing a contract named "FirstContract".
-
- The generated project structure is:
+
+
+ Use the [Blueprint](/contract-dev/blueprint/overview) development toolkit for smart contracts. Start a new project with:
-
- Example/
- ├──contracts/ # smart contract source code
- │ └── first_contract.tolk # main contract file
- ├── scripts/ # deployment and on-chain interaction scripts
- │ └── deployFirstContract.ts # script to deploy the contract
- ├── tests/ # testing specifications
- │ └── FirstContract.spec.ts # contract test file
- ├── wrappers/ # TypeScript wrappers for contract interaction
- │ ├── FirstContract.ts # wrapper class for the smart contract
- │ └── FirstContract.compile.ts # configuration for compiling contract
+ ```bash
+ npm create ton@latest -- Example --contractName FirstContract --type tolk-empty
+ ```
-
+ This command creates a project named "Example", containing a contract named "FirstContract".
-
+ The generated project structure is:
-
+
+ Example/
+ ├──contracts/ # smart contract source code
+ │ └── first\_contract.tolk # main contract file
+ ├── scripts/ # deployment and on-chain interaction scripts
+ │ └── deployFirstContract.ts # script to deploy the contract
+ ├── tests/ # testing specifications
+ │ └── FirstContract.spec.ts # contract test file
+ ├── wrappers/ # TypeScript wrappers for contract interaction
+ │ ├── FirstContract.ts # wrapper class for the smart contract
+ │ └── FirstContract.compile.ts # configuration for compiling contract
+
+
+
+
- ```bash
- cd Example
- ```
-
-
-
-
+
+ ```bash
+ cd Example
+ ```
+
+
-## Smart contract layout
+## What is a smart contract
-A smart contract is a program stored on [TON Blockchain](/foundations/overview) and executed by the [TVM](/tvm/overview).
+A smart contract is a program stored on TON blockchain and executed by the TVM.
On-chain, every contract consists of two components:
-- Code — compiled [TVM instructions](), defines the contract's logic
-- Data — persistent state, stores information between interactions
+- Code — compiled [TVM instructions](/tvm/instructions), defines the contract's logic.
+- Data — persistent state, stores information between interactions.
+
+Both are stored at a specific [address](/foundations/addresses/overview) on TON blockchain, which is a unique identifier for each smart contract. Smart contracts interact with each other only through [messages](/foundations/messages/overview).
-Both are stored at a specific [address]() on the TON Blockchain, which uniquely identifies each smart contract.
+### Smart contract layout
-A contract's data is organized into three functional sections: storage, messages, and getters:
+A contract's code consists of three functional sections: storage, messages, and get methods:
-- Storage holds the contract’s persistent state. Example: the counter variable keeps its value across calls from different users.
-- Messages define how the contract reacts to incoming messages. On TON, the main way to interact with contracts is by sending [messages](). Each processed message produces a [transaction](), a recorded change on the blockchain. For example, a transfer of TON between accounts.
-- Getters are read-only functions that return contract data without modifying state. Example: a getter that returns the current counter value.
+- Storage holds the contract’s persistent state. Example: the `counter` variable keeps its value across calls from different users.
+- Messages are receivers defined in the contract’s code that specify how the contract should react to each incoming message. Each message triggers a specific action or changes the state according to the contract's logic.
+- [Get methods](/tvm/get-method) are read-only functions that return contract data without modifying state. Example: a get method that returns the current `counter` value.
-## Write the smart contract
+## Write a smart contract
To build a simple counter contract:
-- Start with an initial counter value.
+
+- Start with an initial `counter` value.
- Send `increase` messages to add to the counter or `reset` messages to set it to 0.
-- Call a `getter` to return the current counter value.
+- Call a get method to return the current `counter` value.
-The contract uses [**Tolk**](/languages/tolk). Tolk syntax is similar to TypeScript and Rust, designed for smart contract development.
+The contract uses [**Tolk**](/languages/tolk) language.
+ Open the `./contracts/first_contract.tolk` file.
- To define contract storage, store the counter value. Tolk makes it simple with structures:
+ To define contract storage, store the `counter` value. Tolk makes it simple with structures:
```tolk title="./contracts/first_contract.tolk"
struct Storage {
- counter: uint64; // the current counter value
- }
+ counter: uint64; // the current counter value
+ }
// load contract data from persistent storage
fun Storage.load() {
- return Storage.fromCell(contract.getData())
- }
+ return Storage.fromCell(contract.getData())
+ }
// save contract data to persistent storage
fun Storage.save(self) {
- contract.setData(self.toCell())
- }
+ contract.setData(self.toCell())
+ }
```
Structures serialize and deserialize automatically into [cells](/foundations/serialization/cells), the storage unit in TON. The `fromCell` and `toCell` functions handle conversion between structures and cells.
-
-
To process messages, implement the `onInternalMessage` function. It receives one argument — the incoming message. Focus on the `body` field, which contains the payload sent by a user or another contract.
Define two message structures:
@@ -136,16 +133,15 @@ The contract uses [**Tolk**](/languages/tolk). Tolk syntax is similar to TypeScr
Each structure has a unique prefix —`0x7e8764ef` and `0x3a752f06`— called opcodes, that which allows the contract to distinguish between messages.
-
```tolk title="./contracts/first_contract.tolk"
struct(0x7e8764ef) IncreaseCounter {
- increaseBy: uint32
- }
+ increaseBy: uint32
+ }
struct(0x3a752f06) ResetCounter {}
```
- Group the messages into a union. A union bundles multiple types into a single type and supports automatic serialization and deserialization:
+ To avoid manual deserialization of each message, group the messages into a union. A union bundles multiple types into a single type and supports automatic serialization and deserialization.
```tolk title="./contracts/first_contract.tolk"
type AllowedMessage = IncreaseCounter | ResetCounter;
@@ -155,33 +151,32 @@ The contract uses [**Tolk**](/languages/tolk). Tolk syntax is similar to TypeScr
```tolk title="./contracts/first_contract.tolk"
fun onInternalMessage(in: InMessage) {
- // use `lazy` to defer parsing until fields are accessed
- val msg = lazy AllowedMessage.fromSlice(in.body);
-
- // matching the union to determine body structure
- match (msg) {
- IncreaseCounter => {
- // load contract storage lazily (efficient for large or partial reads/updates)
- var storage = lazy Storage.load();
- storage.counter += msg.increaseBy;
- storage.save();
- }
-
- ResetCounter => {
- var storage = lazy Storage.load();
- storage.counter = 0;
- storage.save();
- }
-
- // this match branch would be executed if the message body does not match IncreaseCounter or ResetCounter structures
- else => {
- // reject user message (throw) if body is not empty
- assert(in.body.isEmpty()) throw 0xFFFF
- }
- }
- }
- ```
+ // use `lazy` to defer parsing until fields are accessed
+ val msg = lazy AllowedMessage.fromSlice(in.body);
+
+ // matching the union to determine body structure
+ match (msg) {
+ IncreaseCounter => {
+ // load contract storage lazily (efficient for large or partial reads/updates)
+ var storage = lazy Storage.load();
+ storage.counter += msg.increaseBy;
+ storage.save();
+ }
+ ResetCounter => {
+ var storage = lazy Storage.load();
+ storage.counter = 0;
+ storage.save();
+ }
+
+ // this match branch would be executed if the message body does not match IncreaseCounter or ResetCounter structures
+ else => {
+ // reject user message (throw) if body is not empty
+ assert(in.body.isEmpty()) throw 0xFFFF
+ }
+ }
+ }
+ ```
-
The contract now includes:
+
- Storage — persistent `counter` value
- Messages — `IncreaseCounter` and `ResetCounter` handlers
- - Getter — `currentCounter` function
+ - Get methods — `currentCounter`
-
+ title="Full source code"
+ >
```tolk title="./contracts/first_contract.tolk"
struct Storage {
- counter: uint64;
- }
+ counter: uint64;
+ }
fun Storage.load() {
- return Storage.fromCell(contract.getData());
- }
+ return Storage.fromCell(contract.getData());
+ }
fun Storage.save(self) {
- contract.setData(self.toCell());
- }
+ contract.setData(self.toCell());
+ }
struct(0x7e8764ef) IncreaseCounter {
- increaseBy: uint32
- }
+ increaseBy: uint32
+ }
struct(0x3a752f06) ResetCounter {}
type AllowedMessage = IncreaseCounter | ResetCounter;
fun onInternalMessage(in: InMessage) {
- val msg = lazy AllowedMessage.fromSlice(in.body);
-
- match (msg) {
- IncreaseCounter => {
- var storage = lazy Storage.load();
- storage.counter += msg.increaseBy;
- storage.save();
- }
-
- ResetCounter => {
- var storage = lazy Storage.load();
- storage.counter = 0;
- storage.save();
- }
-
- else => {
- assert(in.body.isEmpty()) throw 0xFFFF;
- }
- }
- }
+ val msg = lazy AllowedMessage.fromSlice(in.body);
+
+ match (msg) {
+ IncreaseCounter => {
+ var storage = lazy Storage.load();
+ storage.counter += msg.increaseBy;
+ storage.save();
+ }
+
+ ResetCounter => {
+ var storage = lazy Storage.load();
+ storage.counter = 0;
+ storage.save();
+ }
+
+ else => {
+ assert(in.body.isEmpty()) throw 0xFFFF;
+ }
+ }
+ }
get fun currentCounter(): int {
- val storage = lazy Storage.load();
- return storage.counter;
- }
+ val storage = lazy Storage.load();
+ return storage.counter;
+ }
```
-
-
-
-
## Compile the contract
To build the contract, compile it into bytecode for execution by the TVM. Use Blueprint with command:
@@ -301,62 +291,60 @@ Next, deploy the contract to the TON blockchain and interact with it using scrip
+ To deploy, create a wrapper class. Wrappers make it easy to interact with contracts from TypeScript.
- Create a wrapper class to deploy and interact with the contract. Wrappers implement the `Contract` interface and TypeScript integration.
-
- Create `./wrappers/FirstContract.ts` with the following code:
+ Open the `./wrappers/FirstContract.ts` file and replace its content with the following code:
```typescript title="./wrappers/FirstContract.ts"
import { Address, beginCell, Cell, Contract, contractAddress, ContractProvider, Sender, SendMode } from '@ton/core';
export class FirstContract implements Contract {
- constructor(
- readonly address: Address,
- readonly init?: { code: Cell; data: Cell },
- ) {}
-
- static createFromConfig(config: { counter: number }, code: Cell, workchain = 0) {
- const data = beginCell().storeUint(config.counter, 64).endCell();
- const init = { code, data };
- return new FirstContract(contractAddress(workchain, init), init);
- }
-
- async sendDeploy(provider: ContractProvider, via: Sender, value: bigint) {
- await provider.internal(via, {
- value,
- sendMode: SendMode.PAY_GAS_SEPARATELY,
- });
- }
- }
+ constructor(
+ readonly address: Address,
+ readonly init?: { code: Cell; data: Cell },
+ ) {}
+
+ static createFromConfig(config: { counter: number }, code: Cell, workchain = 0) {
+ const data = beginCell().storeUint(config.counter, 64).endCell();
+ const init = { code, data };
+ return new FirstContract(contractAddress(workchain, init), init);
+ }
+
+ async sendDeploy(provider: ContractProvider, via: Sender, value: bigint) {
+ await provider.internal(via, {
+ value,
+ sendMode: SendMode.PAY_GAS_SEPARATELY,
+ });
+ }
+ }
```
Wrapper class details:
- [`@ton/core`](https://www.npmjs.com/package/@ton/core) — a library with base TON types.
- The function `createFromConfig` builds a wrapper using:
- - code — compiled bytecode
- - data — the initial storage layout
- - The contract [address](/foundations/addresses/overview) is derived deterministically from `code + data` using `contractAddress`.
- - The method `sendDeploy` sends the first message with `stateInit`, triggering deployment. In practice, this can be an empty message with Toncoin attached.
-
+ - code — compiled bytecode
+ - data — the initial storage layout
+ - The contract [address](/foundations/addresses/overview) is derived deterministically from `code` and `data` using `contractAddress`.
+ - The method `sendDeploy` sends the first message with `stateInit`, the structure holding the contract's initial code and data, which triggers deployment. In practice, this can be an empty message with Toncoin attached.
-
+ title="Choose the network"
+ >
TON provides two networks for deployment:
- **testnet** — developer sandbox.
- **mainnet** — production blockchain.
This tutorial uses testnet. Mainnet deployment is possible once the contract is verified and ready for production.
-
-
- Write a script `./scripts/deployFirstContract.ts` to deploy the contract:
+ title="Create the deployment script"
+ >
+ Open the `./scripts/deployFirstContract.ts` file and replace its content with the following code.
+ It deploys the contract.
```typescript title="./scripts/deployFirstContract.ts"
import { toNano } from '@ton/core';
@@ -364,25 +352,25 @@ Next, deploy the contract to the TON blockchain and interact with it using scrip
import { compile, NetworkProvider } from '@ton/blueprint';
export async function run(provider: NetworkProvider) {
- const firstContract = provider.open(
- FirstContract.createFromConfig(
- { counter: Math.floor(Math.random() * 10000000) },
- await compile('FirstContract')
- )
- );
+ const firstContract = provider.open(
+ FirstContract.createFromConfig(
+ { counter: Math.floor(Math.random() * 10000000) },
+ await compile('FirstContract')
+ )
+ );
- await firstContract.sendDeploy(provider.sender(), toNano('0.05'));
+ await firstContract.sendDeploy(provider.sender(), toNano('0.05'));
- await provider.waitForDeploy(firstContract.address);
- }
+ await provider.waitForDeploy(firstContract.address);
+ }
```
The `sendDeploy` method accepts three arguments. Only two arguments are passed because `provider.open` automatically provides the `ContractProvider` as the first argument.
-
-
-
+
Run the script with:
```bash
@@ -390,15 +378,19 @@ Next, deploy the contract to the TON blockchain and interact with it using scrip
```
Learn more about [Blueprint deployment](/contract-dev/blueprint/deploy).
-
-
-
With the contract deployed and wrapper methods in place, the next step is to send messages to it.
From cfbf7a18ca8ba0996602e45c9c4ab8018371689c Mon Sep 17 00:00:00 2001
From: aigerimu <89766357+aigerimu@users.noreply.github.com>
Date: Wed, 19 Nov 2025 16:43:33 +0700
Subject: [PATCH 07/10] ai
---
contract-dev/first-smart-contract.mdx | 28 ++++++++++++++++++++++++---
1 file changed, 25 insertions(+), 3 deletions(-)
diff --git a/contract-dev/first-smart-contract.mdx b/contract-dev/first-smart-contract.mdx
index 42376681e..de3cf4a5c 100644
--- a/contract-dev/first-smart-contract.mdx
+++ b/contract-dev/first-smart-contract.mdx
@@ -13,7 +13,7 @@ This tutorial covers building, deploying, and interacting with a smart contract
- Basic familiarity with a command‑line interface and executing commands
- Node.js—`v22` or later— [download here](https://nodejs.org/)
- Check if installed: `node -v` in terminal
-- Installed [TON wallet](/ecosystem/wallet-apps/overview) with [Toncoin on testnet](/contract-dev/testing/testnet-tokens)
+- Installed [TON wallet](/ecosystem/wallet-apps/web) with [Toncoin on testnet](/contract-dev/testing/testnet-tokens)
## Development environment
@@ -371,6 +371,14 @@ Next, deploy the contract to the TON blockchain and interact with it using scrip
+
+
+
Run the script with:
```bash
@@ -387,7 +395,7 @@ Next, deploy the contract to the TON blockchain and interact with it using scrip
title="Wallet required"
type="note"
>
- If a wallet is not installed, check the [wallets overview](/ecosystem/wallet-apps/overview) to select and install a wallet before deploying the contract. Make sure the wallet is funded with [Toncoin on the testnet](/contract-dev/testing/testnet-tokens).
+ If a wallet is not installed, check the [wallet](/ecosystem/wallet-apps/web) to select and install a wallet before deploying the contract. Make sure the wallet is funded with [Toncoin on the testnet](/contract-dev/testing/testnet-tokens).
Scan the QR code displayed in the console, and confirm the transaction in the wallet app.
@@ -528,6 +536,13 @@ Deployment also counts as a message sent to the contract. The next step is to se
Replace `` with the address obtained in the deployment step.
+
+
To run this script:
```bash
@@ -609,7 +624,7 @@ Deployment also counts as a message sent to the contract. The next step is to se
- Instant — no need to wait for blockchain confirmation.
- Read-only — can only read data; cannot modify storage or send messages.
- To call a get method, use `provider.get()`:
+ To call a get method, use `provider.get('currentCounter')`:
```typescript title="./scripts/getCounter.ts"
import { Address } from '@ton/core';
@@ -630,6 +645,13 @@ Deployment also counts as a message sent to the contract. The next step is to se
Get methods are available **off-chain only** — JavaScript clients, web apps, etc. — through RPC providers. Contracts cannot call getters on other contracts — inter-contract interaction uses only messages.
+
+
To run this script:
```bash
From e95a3607cbebcc3e2474ab7676f4916b997f7187 Mon Sep 17 00:00:00 2001
From: aigerimu <89766357+aigerimu@users.noreply.github.com>
Date: Wed, 19 Nov 2025 16:47:20 +0700
Subject: [PATCH 08/10] ci
---
contract-dev/first-smart-contract.mdx | 13 ++++++-------
1 file changed, 6 insertions(+), 7 deletions(-)
diff --git a/contract-dev/first-smart-contract.mdx b/contract-dev/first-smart-contract.mdx
index de3cf4a5c..c0f7332d5 100644
--- a/contract-dev/first-smart-contract.mdx
+++ b/contract-dev/first-smart-contract.mdx
@@ -371,13 +371,12 @@ Next, deploy the contract to the TON blockchain and interact with it using scrip
-
-
+ On-chain deployments spend Toncoin and are irreversible. Verify the network before executing. Use testnet for practice; use mainnet only for actual deployment.
+
Run the script with:
@@ -395,7 +394,7 @@ Next, deploy the contract to the TON blockchain and interact with it using scrip
title="Wallet required"
type="note"
>
- If a wallet is not installed, check the [wallet](/ecosystem/wallet-apps/web) to select and install a wallet before deploying the contract. Make sure the wallet is funded with [Toncoin on the testnet](/contract-dev/testing/testnet-tokens).
+ If a wallet is not installed, check the [wallet section](/ecosystem/wallet-apps/web) to select and install a wallet before deploying the contract. Make sure the wallet is funded with [Toncoin on the testnet](/contract-dev/testing/testnet-tokens).
Scan the QR code displayed in the console, and confirm the transaction in the wallet app.
From 7fba5a2f973de3db7e7408c23f5c580fa841b740 Mon Sep 17 00:00:00 2001
From: aigerimu <89766357+aigerimu@users.noreply.github.com>
Date: Wed, 19 Nov 2025 18:11:47 +0700
Subject: [PATCH 09/10] upd
---
contract-dev/first-smart-contract.mdx | 7 ++++---
1 file changed, 4 insertions(+), 3 deletions(-)
diff --git a/contract-dev/first-smart-contract.mdx b/contract-dev/first-smart-contract.mdx
index c0f7332d5..9774e8fb8 100644
--- a/contract-dev/first-smart-contract.mdx
+++ b/contract-dev/first-smart-contract.mdx
@@ -104,7 +104,8 @@ The contract uses [**Tolk**](/languages/tolk) language.
```tolk title="./contracts/first_contract.tolk"
struct Storage {
- counter: uint64; // the current counter value
+ // the current counter value
+ counter: uint64;
}
// load contract data from persistent storage
@@ -384,7 +385,7 @@ Next, deploy the contract to the TON blockchain and interact with it using scrip
npx blueprint run deployFirstContract --testnet --tonconnect --tonviewer
```
- Learn more about [Blueprint deployment](/contract-dev/blueprint/deploy).
+ For flags and options, see the [Blueprint deployment guide](/contract-dev/blueprint/deploy).
Date: Wed, 26 Nov 2025 12:47:35 +0700
Subject: [PATCH 10/10] link
---
contract-dev/first-smart-contract.mdx | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/contract-dev/first-smart-contract.mdx b/contract-dev/first-smart-contract.mdx
index 9774e8fb8..05b5d48ec 100644
--- a/contract-dev/first-smart-contract.mdx
+++ b/contract-dev/first-smart-contract.mdx
@@ -13,7 +13,7 @@ This tutorial covers building, deploying, and interacting with a smart contract
- Basic familiarity with a command‑line interface and executing commands
- Node.js—`v22` or later— [download here](https://nodejs.org/)
- Check if installed: `node -v` in terminal
-- Installed [TON wallet](/ecosystem/wallet-apps/web) with [Toncoin on testnet](/contract-dev/testing/testnet-tokens)
+- Installed [TON wallet](/ecosystem/wallet-apps/web) with [Toncoin on testnet](/ecosystem/wallet-apps/get-coins)
## Development environment
@@ -395,7 +395,7 @@ Next, deploy the contract to the TON blockchain and interact with it using scrip
title="Wallet required"
type="note"
>
- If a wallet is not installed, check the [wallet section](/ecosystem/wallet-apps/web) to select and install a wallet before deploying the contract. Make sure the wallet is funded with [Toncoin on the testnet](/contract-dev/testing/testnet-tokens).
+ If a wallet is not installed, check the [wallet section](/ecosystem/wallet-apps/web) to select and install a wallet before deploying the contract. Make sure the wallet is funded with [Toncoin on the testnet](/ecosystem/wallet-apps/get-coins).
Scan the QR code displayed in the console, and confirm the transaction in the wallet app.