diff --git a/contract-dev/first-smart-contract.mdx b/contract-dev/first-smart-contract.mdx
index 773cebc10..05b5d48ec 100644
--- a/contract-dev/first-smart-contract.mdx
+++ b/contract-dev/first-smart-contract.mdx
@@ -3,288 +3,263 @@ 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.
-
-## What you'll learn
-
-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
-
-## What is a TON smart contract?
-
-### Understanding the basics
-
-A **smart contract** is a computer program stored on TON Blockchain — 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.
-
-The contract is made of two parts:
-
-- **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 TON Blockchain, a unique identifier for each smart contract.
+This tutorial covers building, deploying, and interacting with a smart contract on TON from start to finish.
## Prerequisites
-- **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/)
+- 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**
+- Installed [TON wallet](/ecosystem/wallet-apps/web) with [Toncoin on testnet](/ecosystem/wallet-apps/get-coins)
-## Tutorial overview
+## Development environment
-This tutorial is organized into six clear steps that build upon each other:
+
+
+ Use the [Blueprint](/contract-dev/blueprint/overview) development toolkit for smart contracts. Start a new project with:
-| 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 |
+ ```bash
+ npm create ton@latest -- Example --contractName FirstContract --type tolk-empty
+ ```
-Let's dive into development!
+ This command creates a project named "Example", containing a contract named "FirstContract".
-## Step 1: Development environment setup
+ The generated project structure is:
-We'll use [**Blueprint**](/contract-dev/blueprint/overview) as our 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
+
-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
-```
+
+
-
+
+ ```bash
+ cd Example
+ ```
+
+
-Now, move into the project directory:
+## What is a smart contract
-```bash
-cd Example
-```
+A smart contract is a program stored on TON blockchain and executed by the TVM.
+On-chain, every contract consists of two components:
-## Step 2: Understanding smart contract architecture
+- Code — compiled [TVM instructions](/tvm/instructions), defines the contract's logic.
+- Data — persistent state, stores information between interactions.
-Every smart contract in TON is typically divided into three sections: **storage**, **messages**, and **getters**.
+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).
-- **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/messages/ordinary-tx). Each processed message produces a [transaction](/foundations/messages/ordinary-tx) — 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.
+### Smart contract layout
+
+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 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.
-## Step 3: Writing the smart contract
-
-We’ll build a simple **counter** contract:
-
-- 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.
-
-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
-
-First, we need a way to store the counter value. Tolk makes this simple with structures:
-
-```tolk title="./contracts/first_contract.tolk"
-struct Storage {
- counter: uint64; // the current counter value
-}
-
-// load contract data from persistent storage
-fun Storage.load() {
- return Storage.fromCell(contract.getData())
-}
-
-// 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:
-
-- 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
-
-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.
-
-Tolk structures are also useful for defining message bodies. In our case, we’ll define two messages:
-
-- `IncreaseCounter` — with one field `increaseBy`, used to increment the counter.
-- `ResetCounter` — used to reset the counter to zero.
+## Write a smart contract
-Each structure has a unique prefix (`0x7e8764ef` and `0x3a752f06`), widely called opcodes, that lets the contract distinguish between them.
+To build a simple counter contract:
-```tolk title="./contracts/first_contract.tolk"
-struct(0x7e8764ef) IncreaseCounter {
- increaseBy: uint32
-}
-
-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:
-
-```tolk title="./contracts/first_contract.tolk"
-type AllowedMessage = IncreaseCounter | ResetCounter;
-```
+- Start with an initial `counter` value.
+- Send `increase` messages to add to the counter or `reset` messages to set it to 0.
+- Call a get method to return the current `counter` value.
-Now we can write our message handler:
+The contract uses [**Tolk**](/languages/tolk) language.
-```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);
+
+
+ Open the `./contracts/first_contract.tolk` file.
- // matching our 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();
- }
+ To define contract storage, store the `counter` value. Tolk makes it simple with structures:
- // 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
- }
+ ```tolk title="./contracts/first_contract.tolk"
+ struct Storage {
+ // the current counter value
+ counter: uint64;
}
-}
-```
-
-
-### 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 {
- val storage = lazy Storage.load();
- return storage.counter;
-}
-```
+ // load contract data from persistent storage
+ fun Storage.load() {
+ return Storage.fromCell(contract.getData())
+ }
-### 3.4 Complete contract code
+ // save contract data to persistent storage
+ fun Storage.save(self) {
+ contract.setData(self.toCell())
+ }
+ ```
-We now have a complete smart contract with:
+ 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.
+
-- **Storage**: persistent `counter` value
-- **Messages**: `IncreaseCounter` and `ResetCounter` handlers
-- **Getter**: `currentCounter`
+
+ 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.
-Here’s the full source code of `contracts/first_contract.tolk`:
+ Define two message structures:
-```tolk title="./contracts/first_contract.tolk" expandable
-struct Storage {
- counter: uint64;
-}
+ - `IncreaseCounter` — contains one field `increaseBy` to increment the counter.
+ - `ResetCounter` — resets the counter to 0.
-fun Storage.load() {
- return Storage.fromCell(contract.getData());
-}
+ Each structure has a unique prefix —`0x7e8764ef` and `0x3a752f06`— called opcodes, that which allows the contract to distinguish between messages.
-fun Storage.save(self) {
- contract.setData(self.toCell());
-}
+ ```tolk title="./contracts/first_contract.tolk"
+ struct(0x7e8764ef) IncreaseCounter {
+ increaseBy: uint32
+ }
-struct(0x7e8764ef) IncreaseCounter {
- increaseBy: uint32
-}
+ struct(0x3a752f06) ResetCounter {}
+ ```
-struct(0x3a752f06) ResetCounter {}
+ 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.
-type AllowedMessage = IncreaseCounter | ResetCounter;
+ ```tolk title="./contracts/first_contract.tolk"
+ type AllowedMessage = IncreaseCounter | ResetCounter;
+ ```
-fun onInternalMessage(in: InMessage) {
- val msg = lazy AllowedMessage.fromSlice(in.body);
+ Now implement the message handler:
- match (msg) {
- IncreaseCounter => {
- var storage = lazy Storage.load();
- storage.counter += msg.increaseBy;
- storage.save();
- }
+ ```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);
- ResetCounter => {
- var storage = lazy Storage.load();
- storage.counter = 0;
- storage.save();
+ // 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();
}
- else => {
- assert(in.body.isEmpty()) throw 0xFFFF;
+ 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
+ }
}
}
-}
-
-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:
+ ```
+
+
+
+ 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;
+ }
+ ```
+
+
+
+ The contract now includes:
+
+ - Storage — persistent `counter` value
+ - Messages — `IncreaseCounter` and `ResetCounter` handlers
+ - Get methods — `currentCounter`
+
+
+ ```tolk title="./contracts/first_contract.tolk"
+ struct Storage {
+ counter: uint64;
+ }
+
+ fun Storage.load() {
+ return Storage.fromCell(contract.getData());
+ }
+
+ fun Storage.save(self) {
+ contract.setData(self.toCell());
+ }
+
+ struct(0x7e8764ef) IncreaseCounter {
+ 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;
+ }
+ }
+ }
+
+ get fun currentCounter(): int {
+ 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:
```bash
npx blueprint build FirstContract
@@ -307,354 +282,389 @@ 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, create a wrapper class. Wrappers make it easy to interact with contracts from TypeScript.
-To deploy, we first need a **wrapper class**. Wrappers implement the `Contract` interface and make it easy to interact with contracts from TypeScript.
+ Open the `./wrappers/FirstContract.ts` file and replace its content with the following code:
-Create a file `./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 {
+ constructor(
+ readonly address: Address,
+ readonly init?: { code: Cell; data: Cell },
+ ) {}
-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);
+ }
- 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,
+ });
+ }
}
-
- 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` 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.
+
+
+
+ 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.
+
+
+
+ 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';
+ 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')
+ )
+ );
+
+ await firstContract.sendDeploy(provider.sender(), toNano('0.05'));
+
+ await provider.waitForDeploy(firstContract.address);
}
-}
-```
-
-### 5.1 Understanding the wrapper class
-
-- 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`](/foundations/messages/deploy), 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:
-
-- **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.
-
-### 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';
-
-export async function run(provider: NetworkProvider) {
- const firstContract = provider.open(
- 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.
-
-Run the script with ([learn more about Blueprint deployment](/contract-dev/blueprint/deploy)):
-
-```bash
-npx blueprint run deployFirstContract --testnet --tonconnect --tonviewer
-```
+ ```
+
+ 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
+ npx blueprint run deployFirstContract --testnet --tonconnect --tonviewer
+ ```
+
+ For flags and options, see the [Blueprint deployment guide](/contract-dev/blueprint/deploy).
+
+
+
+
+
+ Scan the QR code displayed in the console, and confirm the transaction in the wallet app.
+
+ Expected output:
+
+ ```text
+ Using file: deployFirstContract
+ ? Choose your wallet Tonkeeper
+
+
+
+ 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
+ ```
+
+ The link opens the contract on [Tonviewer](/ecosystem/explorers/tonviewer), a [blockchain explorer](/ecosystem/explorers/overview) showing transactions, messages and [account states](/foundations/status).
+
+ Next, interact with the contract by sending messages and calling getter functions.
+
+
+
+## Contract interaction
+
+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.
+
+
+
+ Update the wrapper class with three methods: `sendIncrease`, `sendReset`, and `getCounter`:
+
+ ```typescript title="./wrappers/FirstContract.ts" expandable
+ 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);
+ }
-Choose your wallet, scan the QR code shown in the console, and approve the transaction in your wallet app.
+ async sendDeploy(provider: ContractProvider, via: Sender, value: bigint) {
+ await provider.internal(via, {
+ value,
+ sendMode: SendMode.PAY_GAS_SEPARATELY,
+ body: beginCell().endCell(),
+ });
+ }
-Expected output:
+ 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(),
+ });
+ }
-```text
-Using file: deployFirstContract
-? Choose your wallet Tonkeeper
+ 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 getCounter(provider: ContractProvider) {
+ const result = await provider.get('currentCounter', []);
+ return result.stack.readNumber();
+ }
+ }
+ ```
-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
-```
+ The main difference from the deploy message is that these methods include a message body. The body is a cell that contains the instructions.
-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.
+ **Building message bodies**
-🎉 Congratulations! Your contract is live on testnet. Let's interact with it by sending messages and calling get methods.
+ Cells are constructed using the `beginCell` method:
-## Step 6: Contract interaction
+ - `beginCell()` creates a new cell builder.
+ - `storeUint(value, bits)` appends an unsigned integer with a fixed bit length.
+ - `endCell()` finalizes the cell.
-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.
+ **Example**
-First of all, we should update our wrapper class with three methods: `sendIncrease`, `sendReset`, and `getCounter`:
+ `beginCell().storeUint(0x7e8764ef, 32).storeUint(42, 32).endCell()`
-```typescript title="./wrappers/FirstContract.ts"
-import { Address, beginCell, Cell, Contract, contractAddress, ContractProvider, Sender, SendMode } from '@ton/core';
+ - First 32 bits: `0x7e8764ef` — opcode for "increase"
+ - Next 32 bits: `42` — increase by this amount
+
-export class FirstContract implements Contract {
- constructor(
- readonly address: Address,
- readonly init?: { code: Cell; data: Cell },
- ) {}
+
+ With the contract deployed and wrapper methods in place, the next step is to send messages to it.
- 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);
- }
+ Create a script `./scripts/sendIncrease.ts` that increases the counter:
- async sendDeploy(provider: ContractProvider, via: Sender, value: bigint) {
- await provider.internal(via, {
- value,
- sendMode: SendMode.PAY_GAS_SEPARATELY,
- body: beginCell().endCell(),
- });
- }
+ ```typescript title="./scripts/sendIncrease.ts"
+ import { Address, toNano } from '@ton/core';
+ import { FirstContract } from '../wrappers/FirstContract';
+ import { NetworkProvider } from '@ton/blueprint';
- 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(),
- });
- }
+ // `Address.parse()` converts string to address object
+ const contractAddress = Address.parse('');
- 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(),
- });
+ 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();
}
-
- async getCounter(provider: ContractProvider) {
- const result = await provider.get('currentCounter', []);
- return result.stack.readNumber();
+ ```
+
+ Replace `` with the address obtained in the deployment step.
+
+
+
+ To run this script:
+
+ ```bash
+ npx blueprint run sendIncrease --testnet --tonconnect --tonviewer
+ ```
+
+ Expected result:
+
+ ```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
+ ```
+
+ 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; inspect it in the explorer.
+
+
+
+
+
+ To reset the counter, create a script `./scripts/sendReset.ts`:
+
+ ```typescript title="./scripts/sendReset.ts"
+ import { Address, toNano } from '@ton/core';
+ import { FirstContract } from '../wrappers/FirstContract';
+ import { NetworkProvider } from '@ton/blueprint';
+
+ const contractAddress = Address.parse('');
+
+ 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();
}
-}
-```
-
-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.
-
-### Building message bodies
-
-Construction of cells starts with the `beginCell` method ([learn more about cell serialization](/foundations/serialization/cells)):
-
-- `beginCell()` - creates a new cell builder
-- `storeUint(value, bits)` - adds an unsigned integer of specified bit length
-- `endCell()` - finalizes the cell
-
-**Example**: `beginCell().storeUint(0x7e8764ef, 32).storeUint(42, 32).endCell()`
-
-- First 32 bits: `0x7e8764ef` (opcode for "increase")
-- Next 32 bits: `42` (increase by this amount)
-
-### 6.1 Sending messages to your contract
-
-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:
-
-```typescript title="./scripts/sendIncrease.ts"
-import { Address, toNano } from '@ton/core';
-import { FirstContract } from '../wrappers/FirstContract';
-import { NetworkProvider } from '@ton/blueprint';
-
-const contractAddress = Address.parse('');
-
-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();
-}
-```
-
-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
-
-To run this script:
-
-```bash
-npx blueprint run sendIncrease --testnet --tonconnect --tonviewer
-```
-
-Expected result:
-
-```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
-```
-
-#### 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';
-
-const contractAddress = Address.parse('');
-
-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();
-}
-```
-
-To run this script:
-
-```bash
-npx blueprint run sendReset --testnet --tonconnect --tonviewer
-```
-
-Expected result:
-
-```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
-```
-
-### 6.2 Reading contract data with get methods
-
-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()`:
-
-```typescript title="./scripts/getCounter.ts"
-import { Address } from '@ton/core';
-import { FirstContract } from '../wrappers/FirstContract';
-import { NetworkProvider } from '@ton/blueprint';
-
-const contractAddress = Address.parse('');
-
-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
-
-
-
-To run this script:
-
-```bash
-npx blueprint run getCounter --testnet --tonconnect
-```
-
-Expected output:
-
-```bash
-Using file: getCounter
-Counter: 42
-```
-
-## 🎉 Tutorial complete!
-
-**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
-
-Ready to build more advanced contracts? Here's your roadmap:
-
-#### **Next Steps**
-
-- [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
-
-#### **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! 🚀
+ ```
+
+ To run this script:
+
+ ```bash
+ npx blueprint run sendReset --testnet --tonconnect --tonviewer
+ ```
+
+ Expected result:
+
+ ```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 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 `getCounter()`, which calls the contract's getter `provider.get('currentCounter')`:
+
+ ```typescript title="./scripts/getCounter.ts"
+ import { Address } from '@ton/core';
+ import { FirstContract } from '../wrappers/FirstContract';
+ import { NetworkProvider } from '@ton/blueprint';
+
+ const contractAddress = Address.parse('');
+
+ export async function run(provider: NetworkProvider) {
+ const firstContract = provider.open(new FirstContract(contractAddress));
+ // `getCounter()` сalls the contract's `currentCounter` getter
+ const counter = await firstContract.getCounter(); // returns instantly
+ console.log('Counter: ', counter); // wrapper parses stack into JS number
+ }
+ ```
+
+
+
+
+
+ To run this script:
+
+ ```bash
+ npx blueprint run getCounter --testnet --tonconnect
+ ```
+
+ Expected output:
+
+ ```bash
+ Using file: getCounter
+ Counter: 42
+ ```
+
+
+
+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.