Skip to content

Commit

Permalink
docs: .abi, .pkg, .ts, .boc (#1676)
Browse files Browse the repository at this point in the history
  • Loading branch information
novusnota authored Feb 3, 2025
1 parent 6a2974d commit 984e2f0
Show file tree
Hide file tree
Showing 8 changed files with 200 additions and 66 deletions.
1 change: 1 addition & 0 deletions dev-docs/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Illustrated how nested maps can be created: PR [#1593](https://github.com/tact-lang/tact/pull/1593)
- Improved Chinese localization of the documentation: PR [#1642](https://github.com/tact-lang/tact/pull/1642)
- Removed the notion of the non-standard TL-B syntax `remainder<X>`: PR [#1599](https://github.com/tact-lang/tact/pull/1599)
- Added description of `.boc`, `.ts`, `.abi`, `.pkg` files and completed Compilation page: PR [#1676](https://github.com/tact-lang/tact/pull/1676)

### Release contributors

Expand Down
2 changes: 1 addition & 1 deletion docs/src/content/docs/book/bounced.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ When a contract sends a message with a flag `bounce` set to `true{:tact}`, then

## Caveats

Currently, bounced messages in TON have only 224 usable data bits in the message body and don't have any references. This means that you can't recover much of the data from the bounced message. This is a limitation of the TON blockchain and will be fixed in the future. Tact helps you to check if your message fits the limit and in case it doesn't — suggests using a special type constructor `bounced<T>{:tact}` for the bounced message receiver, that would construct a partial representation of the message that fits into the required limits.
Currently, bounced messages in TON have only 224 usable data bits in the message body and don't have any references. This means that you can't recover much of the data from the bounced message. This is a limitation of the TON blockchain and will be fixed in the future. Tact helps you to check if your message fits the limit and in case it doesn't — suggests using a special type constructor `bounced<M>{:tact}` for the bounced message receiver, that would construct a partial representation of the message that fits into the required limits.

## Bounced message receiver

Expand Down
111 changes: 104 additions & 7 deletions docs/src/content/docs/book/compile.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,7 @@ prev:

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

:::note

This page is still being written as per [#1136](https://github.com/tact-lang/tact/issues/1136).

:::

The Tact compiler can produce various outputs, ranging from the [BoC](/book/cells#cells-boc) of the compiled contract to various supplementary files, such as the [compilation report](#report) or the [contract package](/ref/evolution/otp-006), which is the JSON file with the `.pkg` extension that one can use to [verify the smart contract's origin](https://verifier.ton.org).
The Tact compiler can produce various outputs, ranging from the [BoC][boc] of the [compiled contract](#boc) to various supplementary files, such as the [compilation report](#report) or the [contract package](#pkg).

With the proper [configuration settings](/book/config), you can customize the behavior of the compiler to skip the generation of some or all the [build artifacts](#artifacts), and even control the addition or exclusion of [getters for supported interfaces](/book/contracts#interfaces).

Expand Down Expand Up @@ -221,9 +215,112 @@ Thus, the following dependency diagram is produced:

![Contract dependency diagram of the JettonMinter](../../../assets/contract-dependency-diagram-3.png)

### Compiled contract, `.boc` {#boc}

The end result of compiling each contract is to get its code in the [BoC][boc] format, which is placed in a binary file with the `.boc` extension.

By combining the initial code with the initial data for the contract, you can locally and deterministically obtain the blockchain [`Address{:tact}`](/book/types#primitive-types) for the given contract.

From there, you'd only need to send the message containing the initial code and data, usually referred to as initial state or [`StateInit{:tact}`](/book/expressions#initof), to the computed address and provide enough Toncoin for the deployment.

But instead of doing this manually, prefer using the provided [TypeScript wrappers](#wrap-ts) and other [deployment facilities](/book/deploy).

:::note

When compiling with the [`fullWithDecompilation`](/book/config#projects-mode) mode set in the [Tact config](/book/config), the resulting `.boc` is then decompiled into intermediate assembly sources.

The `.boc` file and decompiled assembly sources are intended to be used by advanced users and are not required for regular [deployment](/book/deploy) and [debugging](/book/debug). For example, the `.boc` would be very handy when working with a language that doesn't yet have an officially supported [wrapper generation setup](#wrap).

:::

### Contract package, `.pkg` {#pkg}

The contract package is a way to bundle a compiled contract, its dependencies, and all related metadata into a single file. It's is a JSON file with the `.pkg` extension that one can use to [verify the smart contract's origin](https://verifier.ton.org).

Additionally, the [contract ABI](#abi) is included in the package, as a string.

Read more: [OTP-006: Contract Package](/ref/evolution/otp-006).

### Contract ABI, `.abi` {#abi}

Contract's ABI is a JSON file with the `.abi` extension, which describes the contract's data structures, receivers, getters, possible [exit codes](/book/exit-codes) (errors) and [interfaces](/book/contracts#interfaces).

Essentially, it's a [compilation report](#report) given in a machine-readable format, although without the diagrams.

Note that the contract ABI is included in the [contract package](#pkg) as a string.

Read more: [OTP-002: Contract ABI](/ref/evolution/otp-002).

### Bindings and wrappers {#wrap}

Using the [compiled `.boc`](#boc) directly is inconvenient and error-prone, which is why Tact also provides a number of contract wrappers in different general-purpose languages.

:::note

Currently, only [TypeScript wrappers](#wrap-ts) are provided. This [may change in the future](https://github.com/tact-lang/tact/issues/255), stay tuned.

:::

#### TypeScript wrappers, `.ts` {#wrap-ts}

To aid in [deployment](/book/deploy) and further interactions with the contract, after each successful compilation a `.ts` file with all needed wrappers is produced. The entities added there all use the [@ton/core](https://github.com/ton-org/ton-core) library.

All the [Structs][struct] and [Messages][message] observable in the [compilation report](#structures) are provided as new `type` definitions.

```ts
export type StateInit = {
$$type: 'StateInit';
code: Cell;
data: Cell;
}
```
For each such definition there are `storeStructureName(){:ts}` and `loadStructureName(){:ts}` functions to help compose and parse cells out of those structures.
```ts
export function storeStateInit(src: StateInit) {
return (builder: Builder) => {
const b_0 = builder;
b_0.storeRef(src.code);
b_0.storeRef(src.data);
};
}

export function loadStateInit(slice: Slice) {
const sc_0 = slice;
const _code = sc_0.loadRef();
const _data = sc_0.loadRef();
return { $$type: 'StateInit' as const, code: _code, data: _data };
}
```

Finally, the [ABI declarations](#abi) are defined and a contract wrapper is given. The latter is designed specifically for you to be able to easily [deploy](/book/deploy) and interact with the deployed contract.

```ts
export class Playground implements Contract {
// ...

static async fromInit() {
const init = await Playground_init(); // init code and data
const address = contractAddress(0, init);
return new Playground(address, init);
}

// ...
}
```

:::note

See how to apply TypeScript wrappers in scripts and tests of your [Blueprint][bp] projects: [Parsing body of the emitted message](/book/debug#logging-parsing).

:::

[struct]: /book/structs-and-messages#structs
[message]: /book/structs-and-messages#messages

[boc]: /book/cells#cells-boc

[tlb]: https://docs.ton.org/develop/data-formats/tl-b-language
[mm]: https://mermaid.js.org/
[bp]: https://github.com/ton-org/blueprint
Expand Down
7 changes: 7 additions & 0 deletions docs/src/content/docs/book/config.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -339,6 +339,8 @@ If set to `true{:json}`, enables inlining of all functions in contracts. This ca

#### `safety` {#options-safety}

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

Options that affect the safety of contracts.

```json filename="tact.config.json" {8,14}
Expand All @@ -358,6 +360,8 @@ Options that affect the safety of contracts.

##### `nullChecks` {#safety-nullChecks}

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

`true{:json}` by default.

If set to `true{:json}`, enables run-time null checks of the arguments of the unwrapping [non-null assertion `!!`](/book/operators/#unary-non-null-assert) operator. Setting the option to `false{:json}` will disable these checks and decrease gas consumption.
Expand Down Expand Up @@ -469,6 +473,9 @@ In [Blueprint][bp], `mode` is always set to `"full"{:json}` and cannot be overwr
"interfacesGetter": true,
"experimental": {
"inline": false
},
"safety": {
"nullChecks": false
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion docs/src/content/docs/book/debug.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -569,7 +569,7 @@ it('emits', async () => {

To parse the second emitted message, we could manually use a bunch of `.loadSomething(){:typescript}` functions, but that's way too brittle — if the fields of the `Ballroom{:tact}` [Struct][struct] even change, you'd need to start all over. That could really backfire when you have a lot of tests written in that manner.

Fortunately, Tact compiler auto-generates TypeScript bindings (or wrappers) for the contracts, and it's really easy to re-use them in your test suite. Not only they have a wrapper of the contract you're testing, but they also export a bunch of helper functions to store or load [Structs][struct] and [Messages][message] defined in the contract. The latter will be named just like the [Structs][struct] and [Messages][message] are, but with the `load` prefix in front.
Fortunately, Tact compiler auto-generates [TypeScript bindings (or wrappers)](/book/compile#wrap-ts) for the contracts, and it's really easy to re-use them in your test suite. Not only they have a wrapper of the contract you're testing, but they also export a bunch of helper functions to store or load [Structs][struct] and [Messages][message] defined in the contract. The latter will be named just like the [Structs][struct] and [Messages][message] are, but with the `load` prefix in front.

For example, in our case we'll need a function called `loadBallroom(){:typescript}`, for parsing a [`Slice{:tact}`][slice] into the `Ballroom{:tact}` [Struct][struct] in TypeScript. To import it, either type the name and let your IDE suggest auto-importing it for you, or take a look at the top of your test suite file — there should be a similar line:

Expand Down
4 changes: 3 additions & 1 deletion docs/src/content/docs/ecosystem/typescript.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,6 @@ The Tact language has built-in support for the [@ton/ton](https://github.com/ton

## Tact contract in TypeScript

The compiler generates files named `{project}_{contract}.ts` for each contract in your [project](/book/config#projects), which contain ready-to-use strongly typed wrappers for working with it in any TypeScript-powered environment: for [testing](/book/debug), [deployments](/book/deploy), etc.
The compiler generates files named `{project}_{contract}.ts` for each contract in your [project](/book/config#projects), which contain ready-to-use strongly typed wrappers for working with it in any TypeScript-powered environment: for [testing, debugging and scripting](/book/debug), [deployments](/book/deploy), etc.

Read more: [TypeScript wrappers on the Compilation page](/book/compile#wrap-ts).
96 changes: 59 additions & 37 deletions docs/src/content/docs/ref/evolution/otp-002.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -5,75 +5,97 @@ sidebar:
order: 2
---

ABI defines how to communicate with smart contracts. It contains information about the contract's receivers, data structures, etc.
The contract's Application Binary Interface (ABI) defines a format containing information about the contract's receivers, data structures, getters, etc.

## Motivation

ABI is an essential tool that allows developers to generate handy bindings, UIs, etc. One of the best consumer usages would be using a DAO and being able to confirm what exactly it is trying to do before signing a transaction.

## Guide

This OTP is based on types that are defined in TLB+ and it is advised to know them before reading this OTP.
ABI is a tool that allows developers to generate handy bindings, UIs, and so on. One of the best consumer usages would be using a DAO and being able to confirm what exactly it is trying to do before signing a transaction.

## Specification

ABI is a JSON file:
ABI is defined as a JSON file, usually with an `.abi` extension:

```json
{
"name": "MyContract",
"types": [
{
"name": "MyRequest",
"header": 12315123,
"name": "StateInit",
"header": null,
"fields": [
{
"name": "queryId",
"name": "code",
"type": {
"kind": "simple",
"type": "int",
"optional": false,
"format": "uint256"
"type": "cell",
"optional": false
}
},
{
"name": "data",
"type": {
"kind": "simple",
"type": "cell",
"optional": false
}
}
]
}
},
// ...etc.
],
"receivers": [
{ "type": "binary", "kind": "internal", "name": "MyRequest" },
{ "type": "binary", "kind": "internal" },
{ "type": "comment", "kind": "internal", "comment": "Vote!" },
{ "type": "comment", "kind": "internal" },
{ "type": "empty", "kind": "internal" }
{
"receiver": "internal",
"message": {
"kind": "text",
"text": "Vote!"
}
},
{
"receiver": "internal",
"message": {
"kind": "typed",
"type": "Deploy"
}
}
],
"getters": [
{ "name": "getOwner", "type": "address", "args": [] },
{
"name": "getBalance",
"type": "coins",
"args": [
{
"name": "invested",
"type": {
"kind": "simple",
"type": "uint",
"format": "coins"
}
}
]
"name": "gas",
"methodId": 92180,
"arguments": [],
"returnType": {
"kind": "simple",
"type": "int",
"optional": false,
"format": 257
}
}
],
"errors": {
"123": "Error description",
"124": "Division by zero"
}
"2": {
"message": "Stack underflow"
},
"3": {
"message": "Stack overflow"
}
// ...etc.
},
"interfaces": [
"org.ton.introspection.v0",
"org.ton.abi.ipfs.v0",
"org.ton.deploy.lazy.v0",
"org.ton.debug.v0"
]
}
```

## Drawbacks

- Binary and compact representation of ABI could be better, but it is not critical for now.
- ABI is in JSON format, which is both human and machine-readable, but not the most compact — binary representation could be better, but is not critical for now.

- ABI has no strict JSON or TypeScript schema defined, and thus is subject to frequent changes.

## Prior art

- OTP-001, that is complimentary to this OTP.
- [OTP-001](/ref/evolution/otp-001): A complementary proposal that provides additional context.
Loading

0 comments on commit 984e2f0

Please sign in to comment.