Skip to content

与 FunC 的兼容性

Tact 本身编译为 FunC,并将其所有实体直接映射到各种 FunC 和 TL-B 类型。

类型转换

Tact 中的原始类型直接映射到 FunC 的对应类型。

关于变量复制的所有规则都是相同的。最大的区别之一是 Tact 中没有可见的变异操作符,而大多数 Slice 操作会就地修改变量。

序列化转换

与 FunC 需要手动定义序列化逻辑不同,Tact 中的结构体和消息的序列化是自动的。

Tact 的自动布局算法是贪婪的。这意味着它会取下一个变量,计算其大小,并尝试将其放入当前单元格。如果放不下,它会创建一个新单元格并继续。所有用于自动布局的内部结构体在分配前都会被扁平化。

所有可选类型都序列化为 TL-B 中的 Maybe,地址类型除外。

由于在某些情况下不定义序列化时选择什么,因此不支持 Either。

示例

solidity
// _ value1:int257 = SomeValue;
struct SomeValue {
    value1: Int; // 默认为 257 位
}

// _ value1:int256 value2:uint32 = SomeValue;
struct SomeValue {
    value1: Int as int256;
    value2: Int as uint32;
}

// _ value1:bool value2:Maybe bool = SomeValue;
struct SomeValue {
    value1: Bool;
    value2: Bool?;
}

// _ cell:^cell = SomeValue;
struct SomeValue {
    cell: Cell; // 总是作为引用存储
}

// _ cell:^slice = SomeValue;
struct SomeValue {
    cell: Slice; // 总是作为引用存储
}

// _ value1:int256 value2:int256 value3:int256 ^[value4:int256] = SomeValue;
struct SomeValue {
    value1: Int as int256;
    value2: Int as int256;
    value3: Int as int256;
    value4: Int as int256;
}

// _ value1:int256 value2:int256 value3:int256 ^[value4:int256 flag:bool] = SomeValue;
struct SomeValue {
    value1: Int as int256;
    value2: Int as int256;
    value3: Int as int256;
    flag: Bool; // 为避免自动布局将 flag 分配到下一个单元格,flag 在 value4 之前写入
    value4: Int as int256;
}

// _ value1:int256 value2:int256 value3:int256 ^[value4:int256 flag:bool] = SomeValue;
struct SomeValue {
    value1: Int as int256;
    value2: Int as int256;
    value3: Int as int256;
    value4: Int as int256;
    flag: Bool;
}

// _ value1:int256 value2:^TailString value3:int256 = SomeValue;
struct SomeValue {
    value1: Int as int256;
    value2: String;
    value3: Int as int256;
}

## 将接收的消息转换为操作
Tact 为每个接收到的类型化消息生成一个唯一的操作码,但可以被覆盖。

FunC 中的代码:

```func
() recv_internal(int msg_value, cell in_msg_cell, slice in_msg) impure {
    ;; incoming message code...
 
    ;; Receive MessageWithGeneratedOp message
    if (op == 1180414602) {
        ;; code...
    }
 
    ;; Receive MessageWithOverwrittenOP message
    if (op == 291) {
        ;; code...
    }
 
}

在 Tact 中变为:

solidity
message MessageWithGeneratedOp {
    amount: Int as uint32;
}
 
message(0x123) MessageWithOverwrittenOP {
    amount: Int as uint32;
}
 
contract Contract {
    // Contract Body...
 
    receive(msg: MessageWithGeneratedOp) {
        // code...
    }
 
    receive(msg: MessageWithOverwrittenOP) {
        // code...
    }
 
}

转换 get 方法

您可以在 Tact 中表达除列表风格列表之外的所有内容,这些内容与 FunC 的 get 方法兼容。

原始返回类型

如果 FunC 中的 get 方法返回一个原始类型,您可以以相同的方式在 Tact 中实现它。

FunC 中的代码:

func
int seqno() method_id {
    return 0;
}

在 Tact 中变为:

solidity
get fun seqno(): Int {
    return 0;
}

张量返回类型

在 FunC 中,张量类型 (int, int) 和 (int, (int)) 之间存在差异,但对于 TVM 来说,它们都表示两个整数的堆栈。

要转换 FunC get 方法返回的张量,您需要定义一个结构体,其字段类型与张量相同且顺序相同。

FunC 中的代码:

func
(int, slice, slice, cell) get_wallet_data() method_id {
    return ...;
}

在 Tact 中变为:

solidity
struct JettonWalletData {
    balance: Int;
    owner: Address;
    master: Address;
    walletCode: Cell;
}
 
contract JettonWallet {
    get fun get_wallet_data(): JettonWalletData {
        return ...;
    }
}

元组返回类型

在 FunC 中,如果您返回一个元组而不是张量,您需要按照张量类型的过程操作,但需要将 get 方法的返回类型定义为可选的。

FunC 中的代码:

func
[int, int] get_contract_state() method_id {
    return ...;
}

在 Tact 中变为:

solidity
struct ContractState {
    valueA: Int;
    valueB: Int;
}
 
contract StatefulContract {
    get fun get_contract_state(): ContractState? {
        return ...;
    }
}

混合元组和张量返回类型

当一些张量是元组时,您需要按照前面的步骤定义一个结构体,元组部分必须定义为单独的结构体。

FunC 中的代码:

func
(int, [int, int]) get_contract_state() method_id {
    return ...;
}

在 Tact 中变为:

solidity
struct ContractStateInner {
    valueA: Int;
    valueB: Int;
}
 
struct ContractState {
    valueA: Int;
    valueB: ContractStateInner;
}
 
contract StatefulContract {
    get fun get_contract_state(): ContractState {
        return ...;
    }
}

参数映射

转换 get 方法的参数很直接。每个参数都按原样映射到 FunC 参数,每个元组映射到一个结构体。

FunC 中的代码:

func
(int, [int, int]) get_contract_state(int arg1, [int,int] arg2) method_id {
    return ...;
}

在 Tact 中变为:

solidity
struct ContractStateArg2 {
    valueA: Int;
    valueB: Int;
}
 
struct ContractStateInner {
    valueA: Int;
    valueB: Int;
}
 
struct ContractState {
    valueA: Int;
    valueB: ContractStateInner;
}
 
contract StatefulContract {
    get fun get_contract_state(arg1: Int, arg2: ContractStateArg2): ContractState {
        return ContractState{
            valueA: arg1,
            valueB: ContractStateInner{
                valueA: arg2.valueA,
                valueB: arg2.valueB
            }
        };
    }
}