> ## Documentation Index
> Fetch the complete documentation index at: https://docs.ton.org/llms.txt
> Use this file to discover all available pages before exploring further.

<AgentInstructions>

## Submitting Feedback

If you encounter incorrect, outdated, or confusing documentation on this page, submit feedback:

POST https://docs.ton.org/feedback

```json
{
  "path": "/contract-dev/first-smart-contract",
  "feedback": "Description of the issue"
}
```

Only submit feedback when you have something specific and actionable to report.

</AgentInstructions>

# Your first smart contract

export const FenceTable = ({children}) => {
  return <pre style={{
    'font-family': 'monospace',
    'white-space': 'pre',
    'overflow-x': 'auto',
    'font-size': '14px'
  }}>
    {children}
  </pre>;
};

export const Aside = ({type = "note", title = "", icon = "", iconType = "regular", children}) => {
  const asideVariants = ["note", "tip", "caution", "danger"];
  const asideComponents = {
    note: {
      outerStyle: "border-sky-500/20 bg-sky-50/50 dark:border-sky-500/30 dark:bg-sky-500/10",
      innerStyle: "text-sky-900 dark:text-sky-200",
      calloutType: "note",
      icon: <svg width="14" height="14" viewBox="0 0 14 14" fill="currentColor" xmlns="http://www.w3.org/2000/svg" className="w-4 h-4 text-sky-500" aria-label="Note">
          <path fill-rule="evenodd" clip-rule="evenodd" d="M7 1.3C10.14 1.3 12.7 3.86 12.7 7C12.7 10.14 10.14 12.7 7 12.7C5.48908 12.6974 4.0408 12.096 2.97241 11.0276C1.90403 9.9592 1.30264 8.51092 1.3 7C1.3 3.86 3.86 1.3 7 1.3ZM7 0C3.14 0 0 3.14 0 7C0 10.86 3.14 14 7 14C10.86 14 14 10.86 14 7C14 3.14 10.86 0 7 0ZM8 3H6V8H8V3ZM8 9H6V11H8V9Z"></path>
        </svg>
    },
    tip: {
      outerStyle: "border-emerald-500/20 bg-emerald-50/50 dark:border-emerald-500/30 dark:bg-emerald-500/10",
      innerStyle: "text-emerald-900 dark:text-emerald-200",
      calloutType: "tip",
      icon: <svg width="11" height="14" viewBox="0 0 11 14" fill="currentColor" xmlns="http://www.w3.org/2000/svg" className="text-emerald-600 dark:text-emerald-400/80 w-3.5 h-auto" aria-label="Tip">
          <path d="M3.12794 12.4232C3.12794 12.5954 3.1776 12.7634 3.27244 12.907L3.74114 13.6095C3.88471 13.8248 4.21067 14 4.46964 14H6.15606C6.41415 14 6.74017 13.825 6.88373 13.6095L7.3508 12.9073C7.43114 12.7859 7.49705 12.569 7.49705 12.4232L7.50055 11.3513H3.12521L3.12794 12.4232ZM5.31288 0C2.52414 0.00875889 0.5 2.26889 0.5 4.78826C0.5 6.00188 0.949566 7.10829 1.69119 7.95492C2.14321 8.47011 2.84901 9.54727 3.11919 10.4557C3.12005 10.4625 3.12175 10.4698 3.12261 10.4771H7.50342C7.50427 10.4698 7.50598 10.463 7.50684 10.4557C7.77688 9.54727 8.48281 8.47011 8.93484 7.95492C9.67728 7.13181 10.1258 6.02703 10.1258 4.78826C10.1258 2.15486 7.9709 0.000106649 5.31288 0ZM7.94902 7.11267C7.52078 7.60079 6.99082 8.37878 6.6077 9.18794H4.02051C3.63739 8.37878 3.10743 7.60079 2.67947 7.11294C2.11997 6.47551 1.8126 5.63599 1.8126 4.78826C1.8126 3.09829 3.12794 1.31944 5.28827 1.3126C7.2435 1.3126 8.81315 2.88226 8.81315 4.78826C8.81315 5.63599 8.50688 6.47551 7.94902 7.11267ZM4.87534 2.18767C3.66939 2.18767 2.68767 3.16939 2.68767 4.37534C2.68767 4.61719 2.88336 4.81288 3.12521 4.81288C3.36705 4.81288 3.56274 4.61599 3.56274 4.37534C3.56274 3.6515 4.1515 3.06274 4.87534 3.06274C5.11719 3.06274 5.31288 2.86727 5.31288 2.62548C5.31288 2.38369 5.11599 2.18767 4.87534 2.18767Z"></path>
        </svg>
    },
    caution: {
      outerStyle: "border-amber-500/20 bg-amber-50/50 dark:border-amber-500/30 dark:bg-amber-500/10",
      innerStyle: "text-amber-900 dark:text-amber-200",
      calloutType: "warning",
      icon: <svg className="flex-none w-5 h-5 text-amber-400 dark:text-amber-300/80" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2" aria-label="Warning">
          <path stroke-linecap="round" stroke-linejoin="round" d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z"></path>
        </svg>
    },
    danger: {
      outerStyle: "border-red-500/20 bg-red-50/50 dark:border-red-500/30 dark:bg-red-500/10",
      innerStyle: "text-red-900 dark:text-red-200",
      calloutType: "danger",
      icon: <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" fill="currentColor" className="text-red-600 dark:text-red-400/80 w-4 h-4" aria-label="Danger">
          <path d="M17.1 292c-12.9-22.3-12.9-49.7 0-72L105.4 67.1c12.9-22.3 36.6-36 62.4-36l176.6 0c25.7 0 49.5 13.7 62.4 36L494.9 220c12.9 22.3 12.9 49.7 0 72L406.6 444.9c-12.9 22.3-36.6 36-62.4 36l-176.6 0c-25.7 0-49.5-13.7-62.4-36L17.1 292zm41.6-48c-4.3 7.4-4.3 16.6 0 24l88.3 152.9c4.3 7.4 12.2 12 20.8 12l176.6 0c8.6 0 16.5-4.6 20.8-12L453.4 268c4.3-7.4 4.3-16.6 0-24L365.1 91.1c-4.3-7.4-12.2-12-20.8-12l-176.6 0c-8.6 0-16.5 4.6-20.8 12L58.6 244zM256 128c13.3 0 24 10.7 24 24l0 112c0 13.3-10.7 24-24 24s-24-10.7-24-24l0-112c0-13.3 10.7-24 24-24zM224 352a32 32 0 1 1 64 0 32 32 0 1 1 -64 0z"></path>
        </svg>
    }
  };
  let variant = type;
  let gotInvalidVariant = false;
  if (!asideVariants.includes(type)) {
    gotInvalidVariant = true;
    variant = "danger";
  }
  const iconVariants = ["regular", "solid", "light", "thin", "sharp-solid", "duotone", "brands"];
  if (!iconVariants.includes(iconType)) {
    iconType = "regular";
  }
  return <>
      <div className={`callout my-4 px-5 py-4 overflow-hidden rounded-2xl flex gap-3 border ${asideComponents[variant].outerStyle}`} data-callout-type={asideComponents[variant].calloutType}>
        <div className="mt-0.5 w-4" data-component-part="callout-icon">
          {}
          {icon === "" ? asideComponents[variant].icon : <Icon icon={icon} iconType={iconType} size={14} />}
        </div>
        <div className={`text-sm prose min-w-0 w-full ${asideComponents[variant].innerStyle}`} data-component-part="callout-content">
          {gotInvalidVariant ? <p>
              <span className="font-bold">
                Invalid <code>type</code> passed!
              </span>
              <br />
              <span className="font-bold">Received: </span>
              {type}
              <br />
              <span className="font-bold">Expected one of: </span>
              {asideVariants.join(", ")}
            </p> : <>
              {title && <p className="font-bold">{title}</p>}
              {children}
            </>}
        </div>
      </div>
    </>;
};

This tutorial covers building, deploying, and interacting with a smart contract on TON from start to finish.

## Prerequisites

* 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
* Installed [TON wallet](/ecosystem/wallet-apps/tonkeeper) with [Toncoin on testnet](/ecosystem/wallet-apps/get-coins)

## Development environment

<Steps>
  <Step title="Set up development environment">
    Use the [Blueprint](/contract-dev/blueprint/overview) development toolkit for smart contracts. Start a new project with:

    ```bash theme={"theme":{"light":"github-light-default","dark":"dark-plus"},"languages":{"custom":["/resources/grammars/tolk.tmLanguage.json","/resources/grammars/tlb.tmLanguage.json","/resources/grammars/fift.tmLanguage.json","/resources/grammars/tasm.tmLanguage.json","/resources/grammars/func.tmLanguage.json"]}}
    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:

    <FenceTable>
      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
    </FenceTable>
  </Step>

  <Step title="Move into the project directory">
    ```bash theme={"theme":{"light":"github-light-default","dark":"dark-plus"},"languages":{"custom":["/resources/grammars/tolk.tmLanguage.json","/resources/grammars/tlb.tmLanguage.json","/resources/grammars/fift.tmLanguage.json","/resources/grammars/tasm.tmLanguage.json","/resources/grammars/func.tmLanguage.json"]}}
    cd Example
    ```
  </Step>
</Steps>

## What is a smart contract

A smart contract is a program stored on <Tooltip tip="A distributed database that many computers maintain together." cta="Learn more" href="/foundations/shards">TON blockchain</Tooltip> and executed by the <Tooltip tip="The “computer” which executes smart contracts on TON blockchain." cta="Learn more" href="/tvm/overview">TVM</Tooltip>.
On-chain, every contract consists of two components:

* 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).

### 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.

  Due to the [TON architecture](/from-ethereum#on-chain-get-methods), get methods cannot be called from other contracts. Inter-contract communication uses **messages** only.

## Write a smart 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 get method to return the current `counter` value.

The contract uses [**Tolk**](/tolk/overview) language.

The TON ecosystem provides editor plugins with syntax support for IDEs and code editors. View them [here](/contract-dev/ide/overview).

<Steps>
  <Step title="Define contract storage">
    Open the `./contracts/first_contract.tolk` file.

    To define contract storage, store the `counter` value. Tolk makes it simple with <Tooltip tip="A structure is a composite data type that groups named fields, each having its own type, into one unit." cta="Learn more" href="/tolk/overview">structures</Tooltip>:

    ```tolk title="./contracts/first_contract.tolk" theme={"theme":{"light":"github-light-default","dark":"dark-plus"},"languages":{"custom":["/resources/grammars/tolk.tmLanguage.json","/resources/grammars/tlb.tmLanguage.json","/resources/grammars/fift.tmLanguage.json","/resources/grammars/tasm.tmLanguage.json","/resources/grammars/func.tmLanguage.json"]}}
    struct Storage {
        // the current counter value
        counter: uint64;
    }

    // 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())
    }
    ```

    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.
  </Step>

  <Step title="Implement 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.

    Define two message structures:

    * `IncreaseCounter` — contains one field `increaseBy` to increment the counter.
    * `ResetCounter` — resets the counter to 0.

    Each structure has a unique prefix —`0x7e8764ef` and `0x3a752f06`— called opcodes, that allows the contract to distinguish between messages.

    ```tolk title="./contracts/first_contract.tolk" theme={"theme":{"light":"github-light-default","dark":"dark-plus"},"languages":{"custom":["/resources/grammars/tolk.tmLanguage.json","/resources/grammars/tlb.tmLanguage.json","/resources/grammars/fift.tmLanguage.json","/resources/grammars/tasm.tmLanguage.json","/resources/grammars/func.tmLanguage.json"]}}
    struct(0x7e8764ef) IncreaseCounter {
        increaseBy: uint32
    }

    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.

    ```tolk title="./contracts/first_contract.tolk" theme={"theme":{"light":"github-light-default","dark":"dark-plus"},"languages":{"custom":["/resources/grammars/tolk.tmLanguage.json","/resources/grammars/tlb.tmLanguage.json","/resources/grammars/fift.tmLanguage.json","/resources/grammars/tasm.tmLanguage.json","/resources/grammars/func.tmLanguage.json"]}}
    type AllowedMessage = IncreaseCounter | ResetCounter;
    ```

    Now implement the message handler:

    ```tolk title="./contracts/first_contract.tolk" theme={"theme":{"light":"github-light-default","dark":"dark-plus"},"languages":{"custom":["/resources/grammars/tolk.tmLanguage.json","/resources/grammars/tlb.tmLanguage.json","/resources/grammars/fift.tmLanguage.json","/resources/grammars/tasm.tmLanguage.json","/resources/grammars/func.tmLanguage.json"]}}
    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
            }
        }
    }
    ```
  </Step>

  <Step title="Add getter functions">
    Write a getter function to return the current counter:

    ```tolk title="./contracts/first_contract.tolk" theme={"theme":{"light":"github-light-default","dark":"dark-plus"},"languages":{"custom":["/resources/grammars/tolk.tmLanguage.json","/resources/grammars/tlb.tmLanguage.json","/resources/grammars/fift.tmLanguage.json","/resources/grammars/tasm.tmLanguage.json","/resources/grammars/func.tmLanguage.json"]}}
    get fun currentCounter(): int {
        val storage = lazy Storage.load();
        return storage.counter;
    }
    ```
  </Step>

  <Step title="Complete contract code">
    The contract now includes:

    * Storage — persistent `counter` value
    * Messages — `IncreaseCounter` and `ResetCounter` handlers
    * Get methods — `currentCounter`

    <Accordion title="Full source code">
      ```tolk title="./contracts/first_contract.tolk" theme={"theme":{"light":"github-light-default","dark":"dark-plus"},"languages":{"custom":["/resources/grammars/tolk.tmLanguage.json","/resources/grammars/tlb.tmLanguage.json","/resources/grammars/fift.tmLanguage.json","/resources/grammars/tasm.tmLanguage.json","/resources/grammars/func.tmLanguage.json"]}}
      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;
      }
      ```
    </Accordion>
  </Step>
</Steps>

## Compile the contract

To build the contract, compile it into bytecode for execution by the TVM. Use Blueprint with command:

```bash theme={"theme":{"light":"github-light-default","dark":"dark-plus"},"languages":{"custom":["/resources/grammars/tolk.tmLanguage.json","/resources/grammars/tlb.tmLanguage.json","/resources/grammars/fift.tmLanguage.json","/resources/grammars/tasm.tmLanguage.json","/resources/grammars/func.tmLanguage.json"]}}
npx blueprint build FirstContract
```

Expected output:

```ansi theme={"theme":{"light":"github-light-default","dark":"dark-plus"},"languages":{"custom":["/resources/grammars/tolk.tmLanguage.json","/resources/grammars/tlb.tmLanguage.json","/resources/grammars/fift.tmLanguage.json","/resources/grammars/tasm.tmLanguage.json","/resources/grammars/func.tmLanguage.json"]}}
Build script running, compiling FirstContract
🔧 Using tolk version 1.1.0...

✅ Compiled successfully! Cell BOC result:

{
  "hash": "fbfb4be0cf4ed74123b40d07fb5b7216b0f7d3195131ab21115dda537bad2baf",
  "hashBase64": "+/tL4M9O10EjtA0H+1tyFrD30xlRMashEV3aU3utK68=",
  "hex": "b5ee9c7241010401005b000114ff00f4a413f4bcf2c80b0102016202030078d0f891f24020d72c23f43b277c8e1331ed44d001d70b1f01d70b3fa0c8cb3fc9ed54e0d72c21d3a9783431983070c8cb3fc9ed54e0840f01c700f2f40011a195a1da89a1ae167fe3084b2d"
}

✅ Wrote compilation artifact to build/FirstContract.compiled.json
```

The compilation artifact contains the contract bytecode. This file is required for deployment.

Next, deploy the contract to the TON blockchain and interact with it using scripts and wrappers.

## Deploy to testnet

<Steps>
  <Step title="Create a wrapper file">
    To deploy, create a wrapper class. Wrappers make it easy to interact with contracts from TypeScript.

    Open the `./wrappers/FirstContract.ts` file and replace its content with the following code:

    ```typescript title="./wrappers/FirstContract.ts" theme={"theme":{"light":"github-light-default","dark":"dark-plus"},"languages":{"custom":["/resources/grammars/tolk.tmLanguage.json","/resources/grammars/tlb.tmLanguage.json","/resources/grammars/fift.tmLanguage.json","/resources/grammars/tasm.tmLanguage.json","/resources/grammars/func.tmLanguage.json"]}}
    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,
            });
        }
    }
    ```

    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.
  </Step>

  <Step 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" theme={"theme":{"light":"github-light-default","dark":"dark-plus"},"languages":{"custom":["/resources/grammars/tolk.tmLanguage.json","/resources/grammars/tlb.tmLanguage.json","/resources/grammars/fift.tmLanguage.json","/resources/grammars/tasm.tmLanguage.json","/resources/grammars/func.tmLanguage.json"]}}
    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. Only two arguments are passed because `provider.open` automatically provides the `ContractProvider` as the first argument.
  </Step>

  <Step title="Run the script">
    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.

    <Aside type="danger" title="Funds at risk">
      On-chain deployments spend Toncoin and are irreversible. Verify the network before executing. Use testnet for practice; use mainnet only for actual deployment.
    </Aside>

    Run the script with:

    ```bash theme={"theme":{"light":"github-light-default","dark":"dark-plus"},"languages":{"custom":["/resources/grammars/tolk.tmLanguage.json","/resources/grammars/tlb.tmLanguage.json","/resources/grammars/fift.tmLanguage.json","/resources/grammars/tasm.tmLanguage.json","/resources/grammars/func.tmLanguage.json"]}}
    npx blueprint run deployFirstContract --testnet --tonconnect --tonviewer
    ```

    For flags and options, see the [Blueprint deployment guide](/contract-dev/blueprint/deploy).
  </Step>

  <Step title="Confirm transaction">
    <Aside title="Wallet required" type="note">
      If a wallet is not installed, check the [wallet section](/ecosystem/wallet-apps/tonkeeper) 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).
    </Aside>

    Scan the QR code displayed in the console, and confirm the transaction in the wallet app.

    Expected output:

    ```text theme={"theme":{"light":"github-light-default","dark":"dark-plus"},"languages":{"custom":["/resources/grammars/tolk.tmLanguage.json","/resources/grammars/tlb.tmLanguage.json","/resources/grammars/fift.tmLanguage.json","/resources/grammars/tasm.tmLanguage.json","/resources/grammars/func.tmLanguage.json"]}}
    Using file: deployFirstContract
    ? Choose your wallet Tonkeeper

    <QR_CODE_HERE>

    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.
  </Step>
</Steps>

## 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.

<Steps>
  <Step title="Update wrapper class">
    Update the wrapper class with three methods: `sendIncrease`, `sendReset`, and `getCounter`:

    ```typescript title="./wrappers/FirstContract.ts" expandable theme={"theme":{"light":"github-light-default","dark":"dark-plus"},"languages":{"custom":["/resources/grammars/tolk.tmLanguage.json","/resources/grammars/tlb.tmLanguage.json","/resources/grammars/fift.tmLanguage.json","/resources/grammars/tasm.tmLanguage.json","/resources/grammars/func.tmLanguage.json"]}}
    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,
                body: beginCell().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 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();
        }
    }
    ```

    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**

    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.

    **Example**

    `beginCell().storeUint(0x7e8764ef, 32).storeUint(42, 32).endCell()`

    * First 32 bits: `0x7e8764ef` — opcode for "increase"
    * Next 32 bits: `42` — increase by this amount
  </Step>

  <Step title="Send messages to the contract">
    With the contract deployed and wrapper methods in place, the next step is to send messages to it.

    Create a script `./scripts/sendIncrease.ts` that increases the counter:

    ```typescript title="./scripts/sendIncrease.ts" theme={"theme":{"light":"github-light-default","dark":"dark-plus"},"languages":{"custom":["/resources/grammars/tolk.tmLanguage.json","/resources/grammars/tlb.tmLanguage.json","/resources/grammars/fift.tmLanguage.json","/resources/grammars/tasm.tmLanguage.json","/resources/grammars/func.tmLanguage.json"]}}
    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('<CONTRACT_ADDRESS>');

    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();
    }
    ```

    Replace `<CONTRACT_ADDRESS>` with the address obtained in the deployment step.

    <Aside type="danger" title="Funds at risk">
      On-chain deployments spend Toncoin and are irreversible. Verify the network before executing. Use testnet for practice; use mainnet only for actual deployment.
    </Aside>

    To run this script:

    ```bash theme={"theme":{"light":"github-light-default","dark":"dark-plus"},"languages":{"custom":["/resources/grammars/tolk.tmLanguage.json","/resources/grammars/tlb.tmLanguage.json","/resources/grammars/fift.tmLanguage.json","/resources/grammars/tasm.tmLanguage.json","/resources/grammars/func.tmLanguage.json"]}}
    npx blueprint run sendIncrease --testnet --tonconnect --tonviewer
    ```

    Expected result:

    ```text theme={"theme":{"light":"github-light-default","dark":"dark-plus"},"languages":{"custom":["/resources/grammars/tolk.tmLanguage.json","/resources/grammars/tlb.tmLanguage.json","/resources/grammars/fift.tmLanguage.json","/resources/grammars/tasm.tmLanguage.json","/resources/grammars/func.tmLanguage.json"]}}
    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.
    2. The script builds a transaction with a message body containing opcode `0x7e8764ef` and value `42`.
    3. The wallet displays transaction details for confirmation.
    4. After approval, the transaction is sent to the network.
    5. Validators include the transaction in a newly produced block.
    6. The contract receives the message, processes it in `onInternalMessage`, and updates the counter.
    7. The script returns the resulting transaction hash; inspect it in the explorer.

    <Aside title={"Composability"} type={"tip"}>
      Other contracts can also send messages to this contract. This enables composition: different contracts can combine their logic with this one, reuse it as a component, and build new behaviors that were not originally anticipated.
    </Aside>
  </Step>

  <Step title="Reset the counter">
    To reset the counter, create a script `./scripts/sendReset.ts`:

    ```typescript title="./scripts/sendReset.ts" theme={"theme":{"light":"github-light-default","dark":"dark-plus"},"languages":{"custom":["/resources/grammars/tolk.tmLanguage.json","/resources/grammars/tlb.tmLanguage.json","/resources/grammars/fift.tmLanguage.json","/resources/grammars/tasm.tmLanguage.json","/resources/grammars/func.tmLanguage.json"]}}
    import { Address, toNano } from '@ton/core';
    import { FirstContract } from '../wrappers/FirstContract';
    import { NetworkProvider } from '@ton/blueprint';

    const contractAddress = Address.parse('<CONTRACT_ADDRESS>');

    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 theme={"theme":{"light":"github-light-default","dark":"dark-plus"},"languages":{"custom":["/resources/grammars/tolk.tmLanguage.json","/resources/grammars/tlb.tmLanguage.json","/resources/grammars/fift.tmLanguage.json","/resources/grammars/tasm.tmLanguage.json","/resources/grammars/func.tmLanguage.json"]}}
    npx blueprint run sendReset --testnet --tonconnect --tonviewer
    ```

    Expected result:

    ```text theme={"theme":{"light":"github-light-default","dark":"dark-plus"},"languages":{"custom":["/resources/grammars/tolk.tmLanguage.json","/resources/grammars/tlb.tmLanguage.json","/resources/grammars/fift.tmLanguage.json","/resources/grammars/tasm.tmLanguage.json","/resources/grammars/func.tmLanguage.json"]}}
    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
    ```
  </Step>

  <Step title="Read contract data with get methods">
    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" theme={"theme":{"light":"github-light-default","dark":"dark-plus"},"languages":{"custom":["/resources/grammars/tolk.tmLanguage.json","/resources/grammars/tlb.tmLanguage.json","/resources/grammars/fift.tmLanguage.json","/resources/grammars/tasm.tmLanguage.json","/resources/grammars/func.tmLanguage.json"]}}
    import { Address } from '@ton/core';
    import { FirstContract } from '../wrappers/FirstContract';
    import { NetworkProvider } from '@ton/blueprint';

    const contractAddress = Address.parse('<CONTRACT_ADDRESS>');

      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
      }
    ```

    <Aside>
      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.
    </Aside>

    <Aside type="danger" title="Funds at risk">
      On-chain deployments spend Toncoin and are irreversible. Verify the network before executing. Use testnet for practice; use mainnet only for actual deployment.
    </Aside>

    To run this script:

    ```bash theme={"theme":{"light":"github-light-default","dark":"dark-plus"},"languages":{"custom":["/resources/grammars/tolk.tmLanguage.json","/resources/grammars/tlb.tmLanguage.json","/resources/grammars/fift.tmLanguage.json","/resources/grammars/tasm.tmLanguage.json","/resources/grammars/func.tmLanguage.json"]}}
    npx blueprint run getCounter --testnet --tonconnect
    ```

    After resetting the counter, the expected output:

    ```bash theme={"theme":{"light":"github-light-default","dark":"dark-plus"},"languages":{"custom":["/resources/grammars/tolk.tmLanguage.json","/resources/grammars/tlb.tmLanguage.json","/resources/grammars/fift.tmLanguage.json","/resources/grammars/tasm.tmLanguage.json","/resources/grammars/func.tmLanguage.json"]}}
    Using file: getCounter
    Counter: 0
    ```
  </Step>
</Steps>

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.
