---
title: Contracts
description: "Contracts in Tact are similar to classes in popular object-oriented languages, except that their instances are deployed on the blockchain and they can't be passed around like structs and Messages."
---

import { Badge } from '@astrojs/starlight/components';

Contracts in Tact are similar to classes in popular object-oriented languages, except that their instances are deployed on the blockchain and they can't be passed around like [structs and Messages](/book/structs-and-messages).

## Self-references {#self}

Contracts and [traits][trait] have a built-in [identifier](/book/expressions#identifiers) `self{:tact}`, which is used to refer to their fields (persistent state [variables](#variables) and [constants](#variables)) and methods ([internal functions](#internal-functions)):

```tact
contract Example {
    // persistent state variables
    foo: Int;

    init() {
        self.foo = 42; // <- referencing variable foo through self.
    }
}

contract ExampleParams(
    // persistent state variables
    foo: Int,
) {
    receive() {
        self.foo = 42; // <- referencing variable foo through self.
    }
}
```

## Structure

Each contract can be defined with or contain:

* [Inherited traits](#traits)
* [Supported interfaces](#interfaces)
* [Contract parameters](#parameters)
* [Persistent state variables](#variables)
* [Constructor function `init(){:tact}`](#init-function)
* [Contract constants](#constants)
* [Getter functions](#getter-functions)
* [Receiver functions](#receiver-functions)
* [Internal functions](#internal-functions)

### Inherited traits, `with` {#traits}

Contracts can inherit all declarations and definitions from [traits][trait] and override some of their default behaviors. In addition to that, every contract and trait implicitly inherits the special [`BaseTrait{:tact}` trait](/ref/core-base).

To inherit a [trait][trait], specify its name after the keyword `with{:tact}` in the contract's declaration. To inherit multiple traits at once, specify their names in a comma-separated list with an optional trailing comma.

```tact /with/
trait InheritMe {}
trait InheritMeToo {}

// A contract inheriting a single trait
contract Single with InheritMe {}

// A contract inheriting multiple traits
contract Plural with
    InheritMe,
    InheritMeToo, // trailing comma is allowed
{}
```

As [traits][trait] are not allowed to have an [`init(){:tact}` function](#init-function), a contract inheriting a trait with any [persistent state variables](#variables) declared must either provide its own [`init(){:tact}` function](#init-function) or declare [contract parameters](#parameters).

```tact
trait Supe { omelander: Bool }

// This contract will perform lazy initialization,
// setting its data on-chain after the initial deployment
contract LazyVot with Supe {
    init() { self.omelander = false }
}

// This contract will directly set its values with the
// initial data received from the deployment message
contract Vot(
    omelander: Bool,
) with Supe {}
```

If declared or defined in a trait, internal functions and constants can be marked as [virtual or abstract](/book/functions#inheritance) and overridden in contracts inheriting from the trait.

### Supported interfaces, `@interface(…)` {#interfaces}

It's hard to determine what a contract does and which [receivers](#receiver-functions) and [getters](#getter-functions) it has without examining its source code. Sometimes the source is unavailable or inaccessible, leaving one to try to disassemble and introspect the contract, which is a very messy and error-prone approach with diminishing returns and no real reproducibility.

To resolve this issue, an [OTP-001: Supported Interfaces](/ref/evolution/otp-001) was created. According to it, Tact contracts [can report](/book/config#options-interfacesgetter) the list of supported interfaces through a special `supported_interfaces` [getter](#getter-functions). That getter is accessible off-chain using any TON Blockchain explorer — one simply needs to specify `supported_interfaces` as a method to execute and obtain a list of hexadecimal values.

These hexadecimal values are truncated to the first 128 bits of [SHA-256](https://en.wikipedia.org/wiki/SHA-2#Hash_standard) hashes of the original [`String{:tact}`][p] values of the supported interfaces. The first value in this list **must** equal $\mathrm{0x5cec3d5d2cae7b1e84ec39d64a851b66}$ in [hexadecimal notation](/book/integers#hexadecimal), which is the first half of the SHA-256 hash for `"org.ton.introspection.v0"{:tact}`. If the first value is incorrect, you must stop trying to introspect the contract, as it does not conform to the [Supported Interfaces](/ref/evolution/otp-001) proposal.

To declare support for a certain interface, add one or more `@interface("…"){:tact}` attributes directly before contract and [trait][trait] declarations:

```tact
@interface("His name is")
@interface("John")
contract SeeNah with Misc {
    // ...
}

@interface("name_of_your_org - miscellaneous")
trait Misc {
    // ...
}
```

Tact provides a small set of interfaces under specific conditions:

* `"org.ton.abi.ipfs.v0"{:tact}`, according to [OTP-003: Self-ABI Reporting](/ref/evolution/otp-003) — opt-in via [`ipfsAbiGetter`](/book/config#options-ipfsabigetter) config property
* `"org.ton.deploy.lazy.v0"{:tact}`, according to [OTP-005: Argument-addressable contracts](/ref/evolution/otp-005)
* `"org.ton.debug.v0"{:tact}`, but only if [debug mode](/book/debug#debug-mode) is enabled

Some [traits][trait] in [standard libraries](/ref/standard-libraries) define their interfaces as well:

* [`Ownable{:tact}`](/ref/stdlib-ownable#ownable) trait specifies `"org.ton.ownable"{:tact}`
* [`OwnableTransferable{:tact}`](/ref/stdlib-ownable#ownabletransferable) trait specifies `"org.ton.ownable.transferable.v2"{:tact}`
* [`Stoppable{:tact}`](/ref/stdlib-stoppable#stoppable) trait specifies `"org.ton.stoppable"{:tact}`
* [`Resumable{:tact}`](/ref/stdlib-stoppable#resumable) trait specifies `"org.ton.resumable"{:tact}`

To enable the generation of the `supported_interfaces` [getter](#getter-functions) and use the `@interface(){:tact}` attribute in your Tact contracts, modify the [`tact.config.json`](/book/config) file in the root of your project (or create it if it does not yet exist), and [set the `interfacesGetter` property to `true{:json}`](/book/config#options-interfacesgetter).

If you are working on a [Blueprint][bp]-based project, you can enable `supported_interfaces` in the compilation configs of your contracts, which are located in a directory named `wrappers/`:

```typescript title="wrappers/YourContractName.compile.ts" {7}
import { CompilerConfig } from '@ton/blueprint';

export const compile: CompilerConfig = {
  lang: 'tact',
  target: 'contracts/your_contract_name.tact',
  options: {
    interfacesGetter: true, // ← that's the stuff!
  }
};
```

Additionally, [`tact.config.json`](/book/config) may still be used in [Blueprint][bp] projects. In such cases, values specified in [`tact.config.json`](/book/config) act as defaults unless modified in the `wrappers/`.

:::note

  If you have the `separateCompilables` option set to `true{:typescript}` in the [`blueprint.config.ts`][bp-config], then the `.compile.ts` files will be located in the `compilables/` directory, and **not** in `wrappers/`.

:::

:::caution

  Be aware that adding an interface does not guarantee that the contract actually implements any particular functionality or that it implements it in any particular way. It is simply an off-chain, verifiable promise indicating that a contract _might_ contain some specific code. It is your responsibility to trust, but verify, such claims.

  In addition, there is no guarantee that there will not be name clashes between different interfaces, although they are unlikely because even the first 128 bits of SHA-256 provide sufficient [collision resistance](https://en.wikipedia.org/wiki/Collision_resistance).

:::

### Contract parameters {#parameters}

<Badge text="Available since Tact 1.6" variant="tip" size="medium"/><p/>

Most contracts do not require any on-chain deployment logic that runs just once after the contract's deployment is completed. As such, the costly lazy deployment strategy provided by the [`init(){:tact}`](#init-function) function is generally discouraged in favor of simple, direct deployments with [initial code and initial data](/book/expressions#initof).

To declare [persistent state variables](#variables) and set their values during such deployments, use the following _contract parameters_ syntax:

```tact
contract ContractParameters(
    // persistent state variables declared via the contract parameters syntax
    val: Int,              // Int, implicitly serialized to a 257-bit signed
    val32: Int as uint32,  // Int, serialized to a 32-bit unsigned
    mapVal: map<Int, Int>, // Int keys to Int values
    optVal: Int?,          // Int or null
) {
    // ...
}
```

State variables declared in this way have **no** default value. Instead, they get their initial data only when the contract is deployed, which is much cheaper compared to deployments with an extra initialization step in the [`init(){:tact}`](#init-function) function.

The use of contract parameters syntax conflicts with using an `init(){:tact}` function or declaring persistent state variables via the [contract fields syntax](#variables). Whenever possible, prefer using contract parameters unless you need specific on-chain deployment logic that must be run exactly once, i.e. via the `init(){:tact}` function.

```tact
contract ParamParamParam(
    param1: Int,
    param2: Int,
) {
    // COMPILATION ERROR! init() cannot be used along with contract parameters
    init(param1: Int, param2: Int) {}
}
```

An empty parameter list is still a parameter list, meaning that the contract won't have an implicit or explicit `init(){:tact}` function and will enjoy storage write optimizations. Removing the empty list makes a contract use the delayed initialization with an implicit `init(){:tact}` function.

```tact
contract StillParam() {
    // COMPILATION ERROR! init() cannot be used along with contract parameters
    init() {}
}

contract LazyInit {
    // Everything's ok, and the following init() is redundant because there
    // would be an implicit empty init() anyway in the absence of contract parameters.
    init() {}
}
```

:::note

  To obtain the initial state of the target contract in [internal functions](#internal-functions), [receivers](#receiver-functions), or [getters](#getter-functions), use the [`initOf{:tact}`](/book/expressions#initof) expression.

  To obtain only the contract's code, use the [`codeOf{:tact}`](/book/expressions#codeof) expression.

:::

### Persistent state variables {#variables}

Contracts can define state variables that persist between contract calls, thus commonly referred to as _storage_ variables. Contracts in TON [pay rent](https://docs.ton.org/develop/smart-contracts/fees#storage-fee) in proportion to the amount of persistent space they consume, so [compact representations via serialization](/book/integers#serialization) are encouraged.

The storage variables can be defined by using [contract parameters](#parameters) or by using the following _contract fields_ syntax:

```tact
contract ContractFields {
    // persistent state variables declared via the contract fields syntax
    val: Int;              // Int, implicitly serialized to a 257-bit signed
    val32: Int as uint32;  // Int, serialized to a 32-bit unsigned
    mapVal: map<Int, Int>; // Int keys to Int values
    optVal: Int?;          // Int or null
}
```

State variables defined via the contract fields syntax must have a default value or be initialized in the [`init(){:tact}`](#init-function) function, which runs once on deployment of the contract. The only exception is for persistent state variables of type [`map<K, V>{:tact}`](/book/maps), since they are initialized empty by default.

The default value of state variables is assigned before any values can be assigned in the [`init(){:tact}`](#init-function) function.

```tact
contract Example {
    // persistent state variables
    var1: Int = 0; // initialized with default value 0

    // constructor function
    init() {
        self.var1 = 42; // overrides the default to 42
    }
}
```

As the contract state is updated at the very end of the [compute phase][compute] of the transaction, intermediate assignments of [`Int{:tact}`][int] values exceeding the limits specified by [serialization formats](/book/integers#serialization) won't fail immediately. Instead, such assignments would cause an [exit code 5](/book/exit-codes#5) only after all statements have been executed.

This is to be expected because the integers in the temporary [TVM][tvm] memory, which is used to process the [compute phase][compute], always have $257$ bits and are capable of holding values in the inclusive range from $-2^{256}$ to $2^{256} - 1$.

```tact
contract DeRanged {
    // Persistent state variables
    var: Int as uint8; // cannot store values outside the 0-255 range

    init() {
        self.var = -1;  // this won't fail immediately
        self.var = 500; // and this won't fail right away either

    } // only here, at the end of the compute phase,
      // would an error be thrown with exit code 5:
      // Integer out of expected range
}
```

In the end, this means that you cannot rely on intermediate out-of-bounds checks because there are none at [TVM][tvm] runtime, and only the last assignment of each state variable is used to update its persistent state value.

```tact
contract Zero {
    // Persistent state variables
    var: Int as uint8;  // cannot store values outside the 0-255 range
    var2: Int as uint4; // cannot store values outside the 0-15 range

    init() {
        self.var = -1; // this won't fail
        self.var = 0;  // this is in the range of `uint8`

        self.var2 = -1; // this won't fail
        self.var2 = 15; // this is in the range of `uint4`

    } // no errors, and now `self.var` is 0 and `self.var2` is 15
}
```

The above contract fields syntax for declaring persistent state variables conflicts with the use of [contract parameters](#parameters). Use one or the other, but not both.

```tact
contract ParamParamParam(
    param1: Int,
    param2: Int,
) {
    // COMPILATION ERROR! Cannot use contract fields along with contract parameters.
    field1: Int;
    field2: Int;
}
```

:::note

  Tact supports local, non-persistent state variables too. See: [Variable definition with `let{:tact}` statement](/book/statements#let).

:::

### Contract constants {#constants}

Unlike [variables](#variables), constants cannot change. Their values are calculated at _compile-time_ and cannot change during execution.

There isn't much difference between constants defined outside of a contract (global constants) and those inside the contract (contract constants). Those defined outside can be used by other contracts in your project.

Constant initialization must be relatively simple and only rely on values known during compilation. If you add two numbers, for example, the compiler will calculate the result during the build and put the result in your compiled code.

You can read constants both in [receivers](#receiver-functions) and in [getters](#getter-functions).

Unlike [contract variables](#variables), **contract constants don't consume space in persistent state**. Their values are stored directly in the code [`Cell{:tact}`](/book/cells#cells) of the contract.

```tact
// global constants are calculated at compile-time and cannot change
const GlobalConst1: Int = 1000 + ton("42") + pow(10, 9);

contract Example {
    // contract constants are also calculated at compile-time and cannot change
    const ContractConst1: Int = 2000 + ton("43") + pow(10, 9);

    // contract constants can be an easy alternative to enums
    const StateUnpaid: Int = 0;
    const StatePaid: Int = 1;
    const StateDelivered: Int = 2;
    const StateDisputed: Int = 3;

    get fun sum(): Int {
        // access constants from anywhere
        return GlobalConst1 + self.ContractConst1 + self.StatePaid;
    }
}
```

Read more about constants on their dedicated page: [Constants](/book/constants).

### Constructor function `init()` {#init-function}

On deployment of the contract, the constructor function `init(){:tact}` is run. Unlike [contract parameters](#parameters), it performs a delayed initialization of the contract data, setting the values of persistent state variables on-chain.

If a contract has any [persistent state variables](#variables) without default values specified, it must initialize them in this function.

```tact
contract Example {
    // persistent state variables
    var1: Int = 0; // initialized with default value 0
    var2: Int;     // must be initialized in the init() function
    var3: Int = 7; // initialized with default value 7

    // constructor function
    init() {
        self.var2 = 42;
        self.var3 = 32; // overrides the default to 32
    }
}
```

If a contract doesn't have any persistent state variables, or if they all have their default values specified, it may omit the `init(){:tact}` function declaration altogether. That is because unless explicitly declared, the empty `init(){:tact}` function is present by default in all contracts that do not declare [contract parameters](#parameters).

The following is an example of a valid empty contract:

```tact
contract IamEmptyAndIKnowIt {}
```

For your convenience, the parameter list of `init(){:tact}` can have a trailing comma:

```tact
contract TheySeeMeTrailing {
    init(
        param1: Int,
        param2: Int, // trailing comma is allowed
    ) {
        // ...
    }
}
```

<Badge text="Available since Tact 1.6.7" variant="tip" size="medium"/> The parameters of the `init(){:tact}` function can specify [serialization formats](/book/integers#serialization) using the `as` keyword, just like you can with contract fields:

```tact {4}
contract Example {
    param: Int as uint32;

    init(param: Int as uint32) {
        self.param = param;
    }
}
```

:::tip

  Always specify serialization formats for initialization parameters with same types as for contract fields that you want to initialize.

:::

Usage of the `init(){:tact}` function conflicts with the use of [contract parameters](#parameters). Use one or the other, but not both.

```tact
contract ParamParamParam(
    param1: Int,
    param2: Int,
) {
    // COMPILATION ERROR! init() cannot be used along with contract parameters
    init(param1: Int, param2: Int) {}
}
```

Note that even an empty contract parameter list counts as using [contract parameters syntax](#parameters) and means that the contract won't have any variables in its persistent state. Removing the empty list makes a contract use the delayed initialization with an implicit `init(){:tact}` function.

```tact
contract StillParam() {
    // COMPILATION ERROR! init() cannot be used along with contract parameters
    init() {}
}

contract LazyInit {
    // Everything's ok, and the following init() is redundant because there
    // would be an implicit empty init() anyway in the absence of contract parameters.
    init() {}
}
```

:::note

  To obtain the initial state of the target contract in [internal functions](#internal-functions), [receivers](#receiver-functions), or [getters](#getter-functions), use the [`initOf{:tact}`](/book/expressions#initof) expression.

  To obtain only the contract's code, use the [`codeOf{:tact}`](/book/expressions#codeof) expression.

:::

### Getter functions

[Getter functions](/book/functions#get) are **not accessible** from other contracts and are exported only to the off-chain world.

```tact
contract HelloWorld(foo: Int) {
    // Getter function with return type Int
    get fun foo(): Int {
        return self.foo + 42;
    }
}
```

Read more about them in their dedicated section: [Getter functions](/book/functions#get).

### Receiver functions

[Receiver functions](/book/functions#receivers) in Tact can be one of the following three kinds:

* [`receive(){:tact}`](/book/receive), which receives internal messages (from other contracts).
* [`bounced(){:tact}`](/book/bounced), which is called when an outgoing message from this contract bounces back.
* [`external(){:tact}`](/book/external), which doesn't have a sender and can be sent by anyone in the world.

```tact
message CanBounce {
    counter: Int;
}

contract HelloWorld {
    counter: Int;

    init() {
        self.counter = 0;
    }

    get fun counter(): Int {
        return self.counter;
    }

    // internal message receiver, which responds to a string message "increment"
    receive("increment") {
        self.counter += 1;

        // sending the message back to the sender
        send(SendParameters {
            to: sender(),
            value: 0,
            mode: SendRemainingValue | SendIgnoreErrors,
            body: CanBounce { counter: self.counter }.toCell(),
        });
    }

    // bounced message receiver, which is called when the message bounces back to this contract
    bounced(src: bounced<MsBounced>) {
        self.counter = 0; // reset the counter in case the message bounces
    }

    // external message receiver, which responds to off-chain message "hello, it's me"
    external("hello, it's me") {
        // can't be replied to as there's no sender!
        self.counter = 0;
    }
}
```

Naming a parameter of the receiver function with an underscore `_{:tact}` indicates that its value is unused and discarded. This is useful when you don't need to inspect the received message and only want it to convey a specific opcode:

```tact
message(42) UniverseCalls {}

contract Example {
    receive(_: UniverseCalls) {
        // Got a Message with opcode 42
    }
}
```

### Internal functions {#internal-functions}

These functions behave similarly to private methods in popular object-oriented languages — they're internal to contracts and can be called by prefixing them with a special [identifier `self{:tact}`](#self). That's why internal functions are sometimes referred to as "contract methods."

Internal functions can access the contract's [persistent state variables](#variables) and [constants](#constants).

They can only be called from [receivers](#receiver-functions), [getters](#getter-functions), and other internal functions, but not from other contracts or [`init(){:tact}`](#init-function).

```tact
contract Functions {
    val: Int = 0;

    // this contract method can only be called from within this contract and access its variables
    fun onlyZeros() {
        require(self.val == 0, "Only zeros are permitted!");
    }

    // receiver function, which calls the internal function onlyZeros
    receive("only zeros") {
        self.onlyZeros();
    }
}
```

Read more about them in their dedicated section: [Internal functions](/book/functions#fun-internal).

:::note

  Tact supports other kinds of functions too. See: [Functions](/book/functions).

:::

### Converting to Cell or Slice

<Badge text="Available since Tact 1.6.12" variant="tip" size="medium"/><p/>

You can convert a contract instance to a [`Cell{:tact}`](/book/cells#cells) or [`Slice{:tact}`](/book/cells#slices) using the `toCell(){:tact}` and `toSlice(){:tact}` methods.
These methods will build a new `Cell{:tact}` or `Slice{:tact}` with the contract data.

```tact
// ...

contract WalletV4(
    seqno: Int as uint32,
    walletId: Int as int32,
    publicKey: Int as uint256,
    extensions: map<Address, Bool>,
) {
    // ...
    external(msgSlice: Slice) {
        let msg = ExtRequest.fromSlice(msgSlice);
        throwIf(Expired, msg.validUntil < now());
        throwUnless(SeqnoMismatch, msg.seqno == self.seqno);
        throwUnless(WalletIdMismatch, msg.walletId == self.walletId);
        throwUnless(SignatureMismatch, msg.bundle.verifySignature(self.publicKey));

        acceptMessage();
        self.seqno += 1;
        setData(self.toCell()); // <- set the contract data explicitly for low level control
        commit();

        // ...
    }
}
```

This is useful when you need to explicitly set data of your contract for low level control of the contract data.

:::note

    If a contract doesn't use [contract parameters](/book/contracts#parameters), the resulting `Cell{:tact}` or `Slice{:tact}` will contain a leading one bit representing the [lazy initialization bit](/book/functions/#init).

:::

:::note[Useful links:]

  [`Contract.toCell(){:tact}` in Core library][ct-tc]\
  [`Contract.toSlice(){:tact}` in Core library][ct-ts]

:::

[p]: /book/types#primitive-types
[int]: /book/integers
[trait]: /book/types#traits

[compute]: https://docs.ton.org/learn/tvm-instructions/tvm-overview#compute-phase
[tvm]: https://docs.ton.org/learn/tvm-instructions/tvm-overview
[bp]: https://github.com/ton-org/blueprint
[bp-config]: https://github.com/ton-org/blueprint/tree/main?tab=readme-ov-file#configuration

[ct-tc]: /ref/core-cells#contracttocell
[ct-ts]: /ref/core-cells#contracttoslice
