Skip to content

Commit

Permalink
Merge branch 'main' into stdlib-extension-with-mathlib
Browse files Browse the repository at this point in the history
  • Loading branch information
novusnota authored Feb 5, 2025
2 parents a2841c7 + 524b030 commit 4f2dcf1
Show file tree
Hide file tree
Showing 32 changed files with 648 additions and 58 deletions.
4 changes: 4 additions & 0 deletions dev-docs/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Incorrect call generation to a mutation function: PR [#1608](https://github.com/tact-lang/tact/pull/1608)
- Allow constant/trait constants depend on each other: PR [#1622](https://github.com/tact-lang/tact/pull/1622)
- Combine all generated FunC code into a single file: PR [#1698](https://github.com/tact-lang/tact/pull/1698)
- Runtime `sha256` now work for arbitrary strings with length >= 128: PR [#1626](https://github.com/tact-lang/tact/pull/1626)
- Generated code in TypeScript wrappers for contract with `init(init: Init)`: PR [#1709](https://github.com/tact-lang/tact/pull/1709)
- Error message for comment (text) receivers with 124 bytes or more: PR [#1711](https://github.com/tact-lang/tact/pull/1711)

### Docs

Expand Down Expand Up @@ -112,6 +115,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- 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)
- Marked gas-expensive functions and expressions: PR [#1703](https://github.com/tact-lang/tact/pull/1703)

### Release contributors

Expand Down
4 changes: 4 additions & 0 deletions docs/src/content/docs/book/expressions.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ title: Expressions
description: "This page lists all the expressions in Tact"
---

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

Every operator in Tact forms an expression, but there's much more to uncover as Tact offers a wide range of expressive options to choose from.

:::note
Expand Down Expand Up @@ -252,6 +254,8 @@ contract ExampleContract {

## `initOf`

<Badge text="Gas-expensive" title="Uses 500 gas units or more" variant="danger" size="medium"/><p/>

Expression `initOf{:tact}` computes initial state, i.e. `StateInit{:tact}` of a [contract](/book/contracts):

```tact
Expand Down
1 change: 1 addition & 0 deletions docs/src/content/docs/book/maps.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -359,6 +359,7 @@ if (fizz == null) {

### Compare with `.deepEquals()` {#deepequals}

<Badge text="Gas-expensive" title="Uses 500 gas units or more" variant="danger" size="medium"/>
<Badge text="Available since Tact 1.5" variant="tip" size="medium"/><p/>

```tact
Expand Down
2 changes: 1 addition & 1 deletion docs/src/content/docs/book/receive.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ To receive a message of the required type, you need to declare a receiver functi
There are several receiver functions. All receiver functions are processed in the order they are listed below:

* `receive(){:tact}` - called when an empty message is sent to the contract
* `receive("message"){:tact}` - called when a text message with a specific comment is sent to the contract
* `receive("message"){:tact}` - called when a text message with a specific comment is sent to the contract (maximum `"message"{:tact}` length is 123 bytes)
* `receive(str: String){:tact}` - called when an arbitrary text message is sent to the contract
* `receive(msg: MyMessage){:tact}` - called when a binary message of type `MyMessage` is sent to the contract
* `receive(msg: Slice){:tact}` - called when binary message of unknown type is sent to the contract
Expand Down
1 change: 1 addition & 0 deletions docs/src/content/docs/ref/core-advanced.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -597,6 +597,7 @@ Attempts to queue more than $255$ messages throw an exception with an [exit code

## nativeSendMessageReturnForwardFee

<Badge text="Gas-expensive" title="Uses 500 gas units or more" variant="danger" size="medium"/>
<Badge text="Available since Tact 1.5" variant="tip" size="medium"/><p/>

```tact
Expand Down
10 changes: 10 additions & 0 deletions docs/src/content/docs/ref/core-cells.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ let fizz: Builder = beginCell();

## emptyCell

<Badge text="Gas-expensive" title="Uses 500 gas units or more" variant="danger" size="medium"/><p/>

```tact
fun emptyCell(): Cell;
```
Expand All @@ -52,6 +54,8 @@ fizz == buzz; // true

## emptySlice

<Badge text="Gas-expensive" title="Uses 500 gas units or more" variant="danger" size="medium"/><p/>

```tact
fun emptySlice(): Slice;
```
Expand Down Expand Up @@ -187,6 +191,8 @@ A section to group all extension and extension mutation functions for the [`Buil

### Builder.endCell

<Badge text="Gas-expensive" title="Uses 500 gas units or more" variant="danger" size="medium"/><p/>

```tact
extends fun endCell(self: Builder): Cell;
```
Expand Down Expand Up @@ -1254,6 +1260,8 @@ try {

### Slice.hash

<Badge text="Gas-expensive" title="Uses 500 gas units or more" variant="danger" size="medium"/><p/>

```tact
extends fun hash(self: Slice): Int;
```
Expand All @@ -1271,6 +1279,8 @@ let fizz: Int = s.hash();

### Slice.asCell

<Badge text="Gas-expensive" title="Uses 500 gas units or more" variant="danger" size="medium"/><p/>

```tact
extends fun asCell(self: Slice): Cell;
```
Expand Down
10 changes: 10 additions & 0 deletions docs/src/content/docs/ref/core-common.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,8 @@ require(ctx.value != 68 + 1, "Invalid amount of nanoToncoins, bye!");

### newAddress

<Badge text="Gas-expensive" title="Uses 500 gas units or more" variant="danger" size="medium"/><p/>

```tact
fun newAddress(chain: Int, hash: Int): Address;
```
Expand Down Expand Up @@ -156,6 +158,8 @@ let oldTonFoundationAddr: Address =

### contractAddress

<Badge text="Gas-expensive" title="Uses 500 gas units or more" variant="danger" size="medium"/><p/>

```tact
fun contractAddress(s: StateInit): Address;
```
Expand All @@ -170,6 +174,8 @@ let foundMeSome: Address = contractAddress(initOf SomeContract());

### contractAddressExt

<Badge text="Gas-expensive" title="Uses 500 gas units or more" variant="danger" size="medium"/><p/>

```tact
fun contractAddressExt(chain: Int, code: Cell, data: Cell): Address;
```
Expand All @@ -191,6 +197,8 @@ let hereBeDragons: Address = contractAddressExt(0, initPkg.code, initPkg.data);

### send

<Badge text="Gas-expensive" title="Uses 500 gas units or more" variant="danger" size="medium"/><p/>

```tact
fun send(params: SendParameters);
```
Expand Down Expand Up @@ -219,6 +227,8 @@ send(SendParameters{

### emit

<Badge text="Gas-expensive" title="Uses 500 gas units or more" variant="danger" size="medium"/><p/>

```tact
fun emit(body: Cell);
```
Expand Down
6 changes: 6 additions & 0 deletions docs/src/content/docs/ref/core-debug.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ title: Debug
description: "Various debugging functions from the Core library of Tact"
---

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

List of functions commonly used for debugging smart contracts in Tact.

Read more about debugging on the dedicated page: [Debugging](/book/debug).
Expand Down Expand Up @@ -40,6 +42,8 @@ try {

## dump

<Badge text="Gas-expensive" title="Uses 500 gas units or more" variant="danger" size="medium"/><p/>

```tact
fun dump(arg);
```
Expand Down Expand Up @@ -102,6 +106,8 @@ dump(emit("msg".asComment())); // As emit() function doesn't return a value, dum

## dumpStack

<Badge text="Gas-expensive" title="Uses 500 gas units or more" variant="danger" size="medium"/><p/>

```tact
fun dumpStack();
```
Expand Down
4 changes: 4 additions & 0 deletions docs/src/content/docs/ref/core-math.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -360,6 +360,8 @@ contract Example {

## checkSignature

<Badge text="Gas-expensive" title="Uses 500 gas units or more" variant="danger" size="medium"/><p/>

```tact
fun checkSignature(hash: Int, signature: Slice, public_key: Int): Bool;
```
Expand Down Expand Up @@ -401,6 +403,8 @@ contract Showcase {

## checkDataSignature

<Badge text="Gas-expensive" title="Uses 500 gas units or more" variant="danger" size="medium"/><p/>

```tact
fun checkDataSignature(data: Slice, signature: Slice, public_key: Int): Bool;
```
Expand Down
18 changes: 18 additions & 0 deletions docs/src/content/docs/ref/core-strings.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ title: Strings and StringBuilders
description: "Various String and StringBuilder functions from the Core library of Tact"
---

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

Strings are immutable sequences of characters, which means that once a [`String{:tact}`][p] is created, it cannot be changed. Strings are useful to store text, and so they can be converted to [`Cell{:tact}`][cell] type to be used as message bodies.

To be able to concatenate strings in a gas-efficient way, use a [`StringBuilder{:tact}`][p].
Expand Down Expand Up @@ -105,6 +107,8 @@ let fizz: StringBuilder = beginString()

## StringBuilder.toString

<Badge text="Gas-expensive" title="Uses 500 gas units or more" variant="danger" size="medium"/><p/>

```tact
extends fun toString(self: StringBuilder): String;
```
Expand All @@ -122,6 +126,8 @@ let buzz: String = fizz.toString();

## StringBuilder.toCell

<Badge text="Gas-expensive" title="Uses 500 gas units or more" variant="danger" size="medium"/><p/>

```tact
extends fun toCell(self: StringBuilder): Cell;
```
Expand All @@ -139,6 +145,8 @@ let buzz: Cell = fizz.toCell();

## StringBuilder.toSlice

<Badge text="Gas-expensive" title="Uses 500 gas units or more" variant="danger" size="medium"/><p/>

```tact
extends fun toSlice(self: StringBuilder): Slice;
```
Expand Down Expand Up @@ -187,6 +195,8 @@ fizz == buzz; // true, but be careful as it's not always the case

## String.asComment

<Badge text="Gas-expensive" title="Uses 500 gas units or more" variant="danger" size="medium"/><p/>

```tact
extends fun asComment(self: String): Cell;
```
Expand Down Expand Up @@ -277,6 +287,8 @@ let fizz: Slice = s.fromBase64();

## Int.toString

<Badge text="Gas-expensive" title="Uses 500 gas units or more" variant="danger" size="medium"/><p/>

```tact
extends fun toString(self: Int): String;
```
Expand All @@ -293,6 +305,8 @@ let fizz: String = (84 - 42).toString();

## Int.toFloatString

<Badge text="Gas-expensive" title="Uses 500 gas units or more" variant="danger" size="medium"/><p/>

```tact
extends fun toFloatString(self: Int, digits: Int): String;
```
Expand All @@ -311,6 +325,8 @@ let fizz: String = (42).toFloatString(9); // "0.000000042"

## Int.toCoinsString

<Badge text="Gas-expensive" title="Uses 500 gas units or more" variant="danger" size="medium"/><p/>

```tact
extends fun toCoinsString(self: Int): String;
```
Expand All @@ -333,6 +349,8 @@ fizz == buzz; // true, both store "0.000000042"

## Address.toString

<Badge text="Gas-expensive" title="Uses 500 gas units or more" variant="danger" size="medium"/><p/>

```tact
extends fun toString(self: Address): String;
```
Expand Down
10 changes: 4 additions & 6 deletions src/abi/global.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import { writeExpression } from "../generator/writers/writeExpression";
import { throwCompilationError } from "../error/errors";
import { getErrorId } from "../types/resolveErrors";
import { AbiFunction } from "./AbiFunction";
import { sha256_sync } from "@ton/crypto";
import path from "path";
import { cwd } from "process";
import { posixNormalize } from "../utils/filePath";
Expand All @@ -20,6 +19,7 @@ import {
interpretEscapeSequences,
} from "../optimizer/interpreter";
import { isLiteral } from "../ast/ast-helpers";
import { sha256 } from "../utils/sha256";

export const GlobalFunctions: Map<string, AbiFunction> = new Map([
[
Expand Down Expand Up @@ -383,14 +383,12 @@ export const GlobalFunctions: Map<string, AbiFunction> = new Map([
// FIXME: This one does not need fixing, because it is carried out inside a "isLiteral" check.
// Remove this comment once the optimization step is added
const str = ensureSimplifiedString(resolved0).value;
return BigInt(
"0x" + sha256_sync(str).toString("hex"),
).toString(10);
return sha256(str).value.toString(10);
}

// Otherwise, revert back to runtime hash through SHA256U
// Otherwise, revert back to runtime hash through HASHEXT_SHA256
const exp = writeExpression(resolved[0]!, ctx);
return `string_hash(${exp})`;
return `__tact_sha256(${exp})`;
}

// Slice case
Expand Down
6 changes: 3 additions & 3 deletions src/bindings/writeTypescript.ts
Original file line number Diff line number Diff line change
Expand Up @@ -290,10 +290,10 @@ export function writeTypescript(
);
w.inIndent(() => {
w.append(
`const init = await ${abi.name}_init(${init!.args.map((v) => v.name).join(", ")});`,
`const __gen_init = await ${abi.name}_init(${init!.args.map((v) => v.name).join(", ")});`,
);
w.append(`const address = contractAddress(0, init);`);
w.append(`return new ${abi.name}(address, init);`);
w.append(`const address = contractAddress(0, __gen_init);`);
w.append(`return new ${abi.name}(address, __gen_init);`);
});
w.append(`}`);
w.append();
Expand Down
5 changes: 3 additions & 2 deletions src/generator/Writer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { CompilerContext } from "../context/context";
import { escapeUnicodeControlCodes, trimIndent } from "../utils/text";
import { topologicalSort } from "../utils/utils";
import { Writer } from "../utils/Writer";
import { TactInternalCompilerError } from "../error/errors";

type Flag = "inline" | "impure" | "inline_ref";

Expand Down Expand Up @@ -83,10 +84,10 @@ export class WriterContext {
}
}
if (missing.size > 0) {
throw new Error(
throw new TactInternalCompilerError(
`Functions ${Array.from(missing.keys())
.map((v) => `"${v}"`)
.join(", ")} wasn't rendered`,
.join(", ")} wasn't processed and generated`,
);
}

Expand Down
22 changes: 17 additions & 5 deletions src/generator/writers/writeRouter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,21 @@ import { ops } from "./ops";
import { resolveFuncType } from "./resolveFuncType";
import { resolveFuncTypeUnpack } from "./resolveFuncTypeUnpack";
import { writeStatement } from "./writeFunction";
import { AstNumber } from "../../ast/ast";
import { AstNumber, AstReceiver } from "../../ast/ast";
import { throwCompilationError } from "../../error/errors";

export function commentPseudoOpcode(comment: string, ast: AstReceiver): string {
const buffer = Buffer.from(comment, "utf8");
if (buffer.length > 123) {
throwCompilationError(
`receiver message is too long, max length is 123 bytes, but given ${buffer.length}`,
ast.loc,
);
}

export function commentPseudoOpcode(comment: string): string {
return beginCell()
.storeUint(0, 32)
.storeBuffer(Buffer.from(comment, "utf8"))
.storeBuffer(buffer)
.endCell()
.hash()
.toString("hex", 0, 64);
Expand Down Expand Up @@ -206,7 +215,10 @@ export function writeRouter(
selector.kind ===
(internal ? "internal-comment" : "external-comment")
) {
const hash = commentPseudoOpcode(selector.comment);
const hash = commentPseudoOpcode(
selector.comment,
r.ast,
);
ctx.append();
ctx.append(
`;; Receive "${selector.comment}" message`,
Expand Down Expand Up @@ -365,7 +377,7 @@ export function writeReceiver(
selector.kind === "internal-comment" ||
selector.kind === "external-comment"
) {
const hash = commentPseudoOpcode(selector.comment);
const hash = commentPseudoOpcode(selector.comment, f.ast);
ctx.append(
`(${selfType}, ()) ${ops.receiveText(self.name, selector.kind === "internal-comment" ? "internal" : "external", hash)}(${selfType + " " + funcIdOf("self")}) impure inline {`,
);
Expand Down
Loading

0 comments on commit 4f2dcf1

Please sign in to comment.