Sway编程语言-更新中(The Sway Programming Language-Updatin
  • Sway编程语言(The Sway Programming Language)
  • 1. 导言(Introduction)
    • 1.1 安装(Installation)
    • 1.2 Sway快速入门 (Sway Quickstart)
    • 1.3 Fuel工具链 (The Fuel Toolchain)
    • 1.4 一个Forc项目 (A Forc Project)
    • 1.5 标准库 (Standard Library)
  • 2. 示例(Example)
    • 2.1计数器(Counter)
    • 2.2子货币(Subcurrency)
    • 2.3 FizzBuzz
    • 2.4 钱包智能合约(Wallet Smart Contract)
  • 3.Sway编程类型(Sway Program Types)
    • 3.1 合约(Contracts)
    • 3.2 库 (Libraries)
    • 3.3 脚本(Scripts)
    • 3.4 谓词 (Predicates)
  • 4. Sway语言基础 (Sway Language basics)
    • 4.1 变量 (Variables)
    • 4.2 内置类型(Built-in Types)
    • 4.3 常用库类型(Commonly Used Library Types)
    • 4.4 区块链类 (Blockchain Types)
    • 4.5 函数 (Functions)
    • 4.6 结构、元祖和穷举 (Structs, Tuples, and Enums)
    • 4.7 方法和关联函数 (Methods and Associated Functions)
    • 4.8 注释和日志 (Comments and Logging)
    • 4.9 控制流 (Control Flow)
  • 5. 用Sway部署区块链 (Blockchain Development with Sway)
    • 5.1 哈希和加密学 (Hashing and Cryptography)
    • 5.2 合约存储(Contract Storage)
    • 5.3 函数纯度 (Function Purity)
    • 5.4 标识符(Identifiers)
    • 5.5 原生资产(Native Assets)
    • 5.6 访问控制 (Access Control)
    • 5.7 调用合约(Calling Contracts)
  • 6. 高级概念 (Advanced Concepts)
    • 6.1 高级类型 (Advanced Types)
    • 6.2 通用类型 (Generic Types)
    • 6.3 特征 (Traits)
    • 6.4 集 (Assembly)
  • 7. 一般集聚 (Common Collections)
    • 7.1 堆上的向量(Vectors on the Heap)
    • 7.2 存储向量 (Storage Vectors)
    • 7.3 存储映射 (Storage Maps)
  • 8.测试(Testing)
    • 8.1 单元测试(Unit Testing)
    • 8.2 用Rust来测试 (Testing with Rust)
  • 9.应用前端开发 (Application Frontend Development)
    • 9.1 TypeScript SDK
  • 10.Sway应用(Sway Reference)
    • 10.1 编译器内部函数(Compiler Intrinsics)
    • 10.2 属性(Attributes)
    • 10.3 风格向导(Style Guide)
    • 10.4 已知各类问题(Known Issues and Workarounds)
    • 10.5 与Solidity的不同之处 (Differences From Solidity)
    • 10.6 与Rust的不同之处 (Differences From Rust)
    • 10.7 向Sway贡献 (Contributing To Sway)
  • 11. Forc引用 (Forc Reference)
    • 11.1清单参考 (Manifest Reference)
    • 11.2 工作区(Workspaces)
    • 11.3 依赖(Dependencies)
    • 11.4 命令(Commands)
      • 11.4.1 forc-addr2line
      • 11.4.2 forc-build
      • 11.4.3 forc-check
Powered by GitBook
On this page
  • 什么是智能合约?(What is a Smart Contract?)
  • 智能合约的语法 (Syntax of a Smart Contract)
  • 给智能合约实施 ABI (Implementing an ABI for a Smart Contract)
  • 从脚本调用智能合约 (Calling a Smart Contract from a Script)
  1. 3.Sway编程类型(Sway Program Types)

3.1 合约(Contracts)

Previous3.Sway编程类型(Sway Program Types)Next3.2 库 (Libraries)

Last updated 1 year ago

什么是智能合约?(What is a Smart Contract?)

A smart contract is no different than a script or predicate in that it is a piece of bytecode that is deployed to the blockchain via a . The main features of a smart contract that differentiate it from scripts or predicates are that it is callable and stateful. Put another way, a smart contract is analogous to a deployed API with some database state. The interface of a smart contract, also just called a contract, must be defined strictly with an . See for an example.

智能合约与脚本或谓词没有什么不同,因为它是一段字节码,通过一笔 部署到区块链上.智能合约区别于脚本或谓词的主要特征是它是 callable 和 stateful。换句话说,智能合约类似于具有某些数据库状态的已部署 API。智能合约的接口,也简称为合约,必须使用 [ABI 声明](https://fuellabs.github.io/sway/v0.38.0/book/sway-program-types/smart_contracts. html#the-abi-声明)。有关示例,请参见。

智能合约的语法 (Syntax of a Smart Contract)

As with any Sway program, the program starts with a declaration of what it is. A contract must also either define or import an and implement it. It is considered good practice to define your ABI in a separate library and import it into your contract. This allows callers of your contract to simply import the ABI directly and use it in their scripts to call your contract. Let's take a look at an ABI declaration in a library:

与任何 Sway 程序一样,该程序用 的声明开始。合约还必须定义或导入 并实施。一种很好的做法是在单独的库中定义 ABI 并将其导入到您的合约中。这允许您的合约调用者直接导入 ABI 并在他们的脚本中使用其来调用合约。让我们看一下库中的 ABI 声明:

library;

abi Wallet {
    #[storage(read, write), payable]
    fn receive_funds();

    #[storage(read, write)]
    fn send_funds(amount_to_send: u64, recipient_address: Address);
}

Let's focus on the ABI declaration and inspect it line-by-line.

让我们关注 ABI 声明并逐行检查。

ABI 声明 (The ABI Declaration)

abi Wallet {
    #[storage(read, write), payable]
    fn receive_funds();

    #[storage(read, write)]
    fn send_funds(amount_to_send: u64, recipient_address: Address);
}

In the first line, abi Wallet {, we declare the name of this Application Binary Interface, or ABI. We are naming this ABI Wallet. To import this ABI into either a script for calling or a contract for implementing, you would use

在第一行,abi Wallet {,我们声明了这个 Application Binary Interface 或 ABI 的名称。我们将此 ABI 命名为“钱包”。要将此 ABI 导入到调用脚本或实施合同中,您可以使用

use wallet_abi::Wallet;

In the second line, 在第二行,

    #[storage(read, write), payable]
    fn receive_funds();

In the third line, 在第三行,

    #[storage(read, write)]
    fn send_funds(amount_to_send: u64, recipient_address: Address);

we are declaring another ABI method, this time called send_funds. It takes two parameters: the amount to send, and the address to send the funds to.

我们正在声明另一个 ABI 方法,这次称为 send_funds。它有两个参数:发送的金额和发送资金的地址。

给智能合约实施 ABI (Implementing an ABI for a Smart Contract)

Now that we've discussed how to define the interface, let's discuss how to use it. We will start by implementing the above ABI for a specific contract.

现在我们已经讨论了如何定义接口,让我们讨论如何使用它。我们将从为特定合约实施上述 ABI 开始。

Implementing an ABI for a contract is accomplished with impl <ABI name> for Contract syntax. The for Contract syntax can only be used to implement an ABI for a contract; implementing methods for a struct should use impl Foo syntax.

为合同实施 ABI 是通过 impl <ABI name> for Contract 语法完成的。 for Contract 语法只能用于为合约实现 ABI;结构的实现方法应该使用 impl Foo 语法。

impl Wallet for Contract {
    #[storage(read, write), payable]
    fn receive_funds() {
        if msg_asset_id() == BASE_ASSET_ID {
            // If we received `BASE_ASSET_ID` then keep track of the balance.
            // Otherwise, we're receiving other native assets and don't care
            // about our balance of tokens.
            storage.balance.write(storage.balance.read() + msg_amount());
        }
    }

    #[storage(read, write)]
    fn send_funds(amount_to_send: u64, recipient_address: Address) {
        let sender = msg_sender().unwrap();
        match sender {
            Identity::Address(addr) => assert(addr == OWNER_ADDRESS),
            _ => revert(0),
        };

        let current_balance = storage.balance.read();
        assert(current_balance >= amount_to_send);

        storage.balance.write(current_balance - amount_to_send);

        // Note: `transfer_to_address()` is not a call and thus not an
        // interaction. Regardless, this code conforms to
        // checks-effects-interactions to avoid re-entrancy.
        transfer_to_address(amount_to_send, BASE_ASSET_ID, recipient_address);
    }
}

从脚本调用智能合约 (Calling a Smart Contract from a Script)

Now that we have defined our interface and implemented it for our contract, we need to know how to actually call our contract. Let's take a look at a contract call:

现在我们已经定义了我们的接口并为我们的合约实现了它,我们需要知道如何实际 调用 我们的合约。让我们看一下合约调用:

script;

use std::constants::ZERO_B256;
use wallet_abi::Wallet;

fn main() {
    let contract_address = 0x9299da6c73e6dc03eeabcce242bb347de3f5f56cd1c70926d76526d7ed199b8b;
    let caller = abi(Wallet, contract_address);
    let amount_to_send = 200;
    let recipient_address = Address::from(0x9299da6c73e6dc03eeabcce242bb347de3f5f56cd1c70926d76526d7ed199b8b);
    caller.send_funds {
        gas: 10000,
        coins: 0,
        asset_id: ZERO_B256,
    }(amount_to_send, recipient_address);
}

The main new concept is the abi cast: abi(AbiName, contract_address). This returns a ContractCaller type which can be used to call contracts. The methods of the ABI become the methods available on this contract caller: send_funds and receive_funds. We then directly call the contract ABI method as if it was just a regular method. You also have the option of specifying the following special parameters inside curly braces right before the main list of parameters:

主要的新概念是 abi cast:abi(AbiName, contract_address)。这将返回一个可用于调用合约的ContractCaller 类型。 ABI 的方法成为此合约调用方可用的方法:send_funds 和 receive_funds。然后我们直接调用合约 ABI 方法,就好像其只是一个常规方法一样。您还可以选择在主参数列表之前的花括号内指定以下特殊参数:

  1. gas: a u64 that represents the gas being forwarded to the contract when it is called. gas:a u64 表示调用时转发给合约的 gas

  2. coins: a u64 that represents how many coins are being forwarded with this call. coins:一个 u64 表示通过此调用转发了多少代币

  3. asset_id: a b256 that represents the ID of the asset type of the coins being forwarded. asset_id:a b256 表示被转发的币的 资产类型 的 ID

Each special parameter is optional and assumes a default value when skipped:

每个特殊参数都是可选的,并在跳过时采用默认值:

  1. The default value for coins is 0. coins 的默认值为 0

  2. The default value for asset_id is ZERO_B256. asset_id 的默认值为 ZERO_B256

we are declaring an ABI method called receive_funds which, when called, should receive funds into this wallet. Note that we are simply defining an interface here, so there is no function body or implementation of the function. We only need to define the interface itself. In this way, ABI declarations are similar to . This particular ABI method does not take any parameters.

我们正在声明一个名为 receive_funds 的 ABI 方法,该方法在被调用时应该将资金接收到钱包。注意,我们在这里只是定义了一个接口,因此没有 function body 函数主体 或函数的实现。我们只需要定义接口本身。这样,ABI 声明类似于 。这个特殊的 ABI 方法不接受任何参数。

Note: The ABI methods receive_funds and send_funds also require the annotation #[storage(read, write)] because their implementations require reading and writing a storage variable that keeps track of the wallet balance, as we will see shortly. Refer to for more information on storage annotations. 注意:ABI 方法receive_funds 和 send_funds 也需要注释#[storage(read, write)] 因为它们的实现需要读取和写入一个存储变量来跟踪钱包余额,我们很快就会看到。有关存储注释的更多信息,请参阅 。

You may notice once again the similarities between and ABIs. And, indeed, as a bonus, you can specify methods in addition to the interface surface of an ABI, just like a trait. By implementing the methods in the interface surface, you get the extra method implementations For Free™.

您可能会再次注意到 和 ABI 之间的相似之处。而且,事实上,作为奖励,除了 ABI 的接口表面之外,您还可以指定方法,就像特征一样。通过在接口表面中实现方法,您可以获得额外的方法实现 For Free™。

Note that the above implementation of the ABI follows the pattern.

请注意,ABI 的上述实现遵循 模式。

Note: In most cases, calling a contract should be done from the or the which provide a more ergonomic UI for interacting with a contract. However, there are situations where manually writing a script to call a contract is required. 注意:在大多数情况下,应从 [Rust SDK](https://fuellabs.github.io/sway/v0.38.0/book/testing/testing-with-rust. html) 或 提供更符合人体工学的用户界面,来与合约交互。但是,有些情况需要手动编写脚本来调用合约。

The default value for gas is the context gas (i.e. the content of the special register $cgas). Refer to the for more information about context gas. gas 的默认值是上下文气体(即特殊寄存器 $cgas 的内容)。有关上下文气体的更多信息,请参阅

transaction
ABI declaration
this contract
交易
本合同
program type
ABI declaration
程序类型
ABI 声明
trait declarations
特性声明
Purity
Purity
traits
traits 特征
Checks, Effects, Interactions
检查、效果、交互
Rust SDK
TypeScript SDK
TypeScript SDK
FuelVM specifications
FuelVM 规范