1.1构建智能合约 (Building A Smart Contract)

安装 (Installation)

Start by installing the Rust toolchain安装 Rust 工具链 开始。

Then, install the Fuel toolchain. 然后,安装 Fuel 工具链

Make sure you have the latest version of fuelup by running the following command: 运行以下命令保证您拥有最新版本的fuelup

$ fuelup self update
Fetching binary from https://github.com/FuelLabs/fuelup/releases/download/v0.18.0/fuelup-0.18.0-aarch64-apple-darwin.tar.gz
Downloading component fuelup without verifying checksum
Unpacking and moving fuelup to /var/folders/tp/0l8zdx9j4s9_n609ykwxl0qw0000gn/T/.tmpiNJQHt
Moving /var/folders/tp/0l8zdx9j4s9_n609ykwxl0qw0000gn/T/.tmpiNJQHt/fuelup to /Users/.fuelup/bin/fuelup

Then run fuelup toolchain install beta-3 to install the beta-3 toolchain.

然后运行fuelup toolchain install beta-3来安装beta-3工具链。

Finally, set the beta-3 toolchain as your default distribution with the following command:

最后,使用以下命令将 beta-3 工具链设置为默认发行版:

$ fuelup default beta-3
default toolchain set to 'beta-3-aarch64-apple-darwin'

You can check your current toolchain anytime by running fuelup show. 您可以通过运行 fuelup show 随时检查您当前的工具链。

Having problems with this part? Post your question on our forum https://forum.fuel.network/. To help you as efficiently as possible, include the output of this command in your post: fuelup show.

这部分您还有问题吗?在我们的论坛 https://forum.fuel.network/ 上发布您的问题。为了尽可能高效地帮助您,请在您的帖子中包含此命令的输出:fuelup show。

你的第一个 Sway 项目 (Your First Sway Project)

We'll build a simple counter contract with two functions: one to increment the counter, and one to return the value of the counter.

我们将构建一个包含两个函数的简单计数器合约:一个用于增加计数器,一个用于返回计数器的值。

Start by creating a new, empty folder. We'll call it fuel-project.

首先创建一个新的空文件夹。我们称它为 fuel-project

写入合约 (Writing the Contract)

Create a contract project inside of your fuel-project folder:

在您的 fuel-project 文件夹中创建一个合约项目:

$ cd fuel-project
$ forc new counter-contract
To compile, use `forc build`, and to run tests use `forc test`

----

Read the Docs:
- Sway Book: https://fuellabs.github.io/sway/latest
- Rust SDK Book: https://fuellabs.github.io/fuels-rs/latest
- TypeScript SDK: https://fuellabs.github.io/fuels-ts/

Join the Community:
- Follow us @SwayLang: https://twitter.com/SwayLang
- Ask questions on Discourse: https://forum.fuel.network/

Report Bugs:
- Sway Issues: https://github.com/FuelLabs/sway/issues/new

Here is the project that Forc has initialized: 这是 Forc 已初始化的项目:

$ tree counter-contract
counter-contract
├── Forc.toml
└── src
    └── main.sw

Forc.toml is the manifest file (similar to Cargo.toml for Cargo or package.json for Node) and defines project metadata such as the project name and dependencies.

Forc.tomlmanifest 文件(类似于用于 Cargo 的Cargo.toml 或用于 Node 的package.json)并定义项目元数据,例如项目名称和依赖。

Open your project in a code editor and delete the boilerplate code in src/main.sw so that you start with an empty file.

在代码编辑器中打开您的项目并删除 src/main.sw 中的样板代码,您就可以从一个空文件开始。

Every Sway file must start with a declaration of what type of program the file contains; here, we've declared that this file is a contract.

每个 Sway 文件都必须以文件包含的程序类型为声明来开头;在这里,我们已经声明这个文件是一个合约。

contract;

Next, we'll define a storage value. In our case, we have a single counter that we'll call counter of type 64-bit unsigned integer and initialize it to 0.

接下来,我们将定义一个存储值。在我们的例子中,我们有一个计数器,我们将其称为 64 位无符号整数类型的 counter 并将其初始化为 0。

storage {
    counter: u64 = 0,
}

ABI

An ABI defines an interface, and there is no function body in the ABI. A contract must either define or import an ABI declaration and implement it. It is considered best practice to define your ABI in a separate library and import it into your contract because this allows callers of the contract to import and use the ABI in scripts to call your contract.

ABI定义了一个接口,但其中没有函数主体。一个合约必须定义或导入ABI声明且实施它。人们认为最好的做法是在一个单独的库中定义你的ABI,并将其导入你的合约中,因为这使得合约的调用者可以在脚本中导入并使用ABI来调用你的合约。

For simplicity, we will define the ABI directly in the contract file.

简单起见,我们直接在合约文件中定义ABI。

abi Counter {
    #[storage(read, write)]
    fn increment();

    #[storage(read)]
    fn count() -> u64;
}

实施ABI (Implement ABI)

Below your ABI definition, you will write the implementation of the functions defined in your ABI.

在你的ABI定义下面,你将写入ABI中定义的函数的实现。

impl Counter for Contract {
    #[storage(read)]
    fn count() -> u64 {
        storage.counter
    }

    #[storage(read, write)]
    fn increment() {
        storage.counter = storage.counter + 1;
    }
}

Note: storage.counter is an implicit return and is equivalent to return storage.counter;. 注意storage.counter是一个隐含的返回,等同于return storage.counter;

Here's what your code should look like so far: 到目前为止,您的代码应该是这样的:

File: ./counter-contract/src/main.sw 文件:./counter-contract/src/main.sw

contract;

storage {
    counter: u64 = 0,
}

abi Counter {
    #[storage(read, write)]
    fn increment();

    #[storage(read)]
    fn count() -> u64;
}

impl Counter for Contract {
    #[storage(read)]
    fn count() -> u64 {
        storage.counter
    }

    #[storage(read, write)]
    fn increment() {
        storage.counter = storage.counter + 1;
    }
}

构建合约 (Build the Contract)

From inside the fuel-project/counter-contract directory, run the following command to build your contract:

fuel-project/counter-contract 目录中,运行以下命令来构建您的合约:

$ forc build
  Compiled library "core".
  Compiled library "std".
  Compiled contract "counter-contract".
  Bytecode size is 232 bytes.

Let's have a look at the content of the counter-contract folder after building:

我们来看看构建后的counter-contract文件夹的内容:

$ tree .
.
├── Forc.lock
├── Forc.toml
├── out
│   └── debug
│       ├── counter-contract-abi.json
│       ├── counter-contract-contract-id
│       ├── counter-contract-storage_slots.json
│       └── counter-contract.bin
└── src
    └── main.sw

We now have an out directory that contains our build artifacts such as the JSON representation of our ABI and the contract bytecode.

我们现在有一个 out 目录,其中包含我们的构建工件,例如我们的 ABI 的 JSON 表示和合约字节码。

测试你的合约 (Testing your Contrac)

We will start by adding a Rust integration test harness using a Cargo generate template. If this is your first time going through this quickstart, you'll need to install the cargo generate command. In the future, you can skip this step as it will already be installed.

我们将从使用 Cargo 生成模板添加 Rust 集成测试工具开始。如果这是您第一次完成此快速入门,则需要安装 cargo generate 命令。以后,您可以跳过此步骤,因为它已经安装好了。

Navigate to your contract and then run the installation command:

导航到您的合约,然后运行安装命令:

$ cd counter-contract
changed directory into `counter-countract`
$ cargo install cargo-generate
 Updating crates.io index...
 installed package `cargo-generate v0.17.3`

Note: You can learn more about cargo generate by visiting its repository. 您可以通过访问存储库 了解有关 cargo generate 的更多信息。

Now, let's generate the default test harness with the following: 现在,让我们使用以下内容生成默认测试工具:

$ cargo generate --init fuellabs/sway templates/sway-test-rs --name counter-contract
⚠️   Favorite `fuellabs/sway` not found in config, using it as a git repository: https://github.com/fuellabs/sway
🤷   Project Name : counter-contract
🔧   Destination: /home/user/path/to/counter-contract ...
🔧   Generating template ...
[1/3]   Done: Cargo.toml
[2/3]   Done: tests/harness.rs
[3/3]   Done: tests
🔧   Moving generated files into: `/home/user/path/to/counter-contract`...
✨   Done! New project created /home/user/path/to/counter-contract

Let's have a look at the result: 让我们看看结果

$ tree .
.
├── Cargo.toml
├── Forc.lock
├── Forc.toml
├── out
│   └── debug
│       ├── counter-contract-abi.json
│       ├── counter-contract-contract-id
│       ├── counter-contract-storage_slots.json
│       └── counter-contract.bin
├── src
│   └── main.sw
└── tests
    └── harness.rs

We have two new files! 我们有两个新文件!

  • The Cargo.toml is the manifest for our new test harness and specifies the required dependencies including fuels the Fuel Rust SDK. Cargo.toml 是我们新测试工具的清单,并指定所需的依赖,包括fuels Fuel Rust SDK。

  • The tests/harness.rs contains some boilerplate test code to get us started, though doesn't call any contract methods just yet. tests/harness.rs 包含一些样板测试代码以方便我们开始,但还没有调用任何合约方法。

Now that we have our default test harness, let's add some useful tests to it.

现在我们有了默认的测试工具,让我们向它添加一些有用的测试。

At the bottom of test/harness.rs, define the body of can_get_contract_id(). Here is what your code should look like to verify that the value of the counter did get incremented:

test/harness.rs 的底部,定义 can_get_contract_id() 的主体。您的代码应该如下所示,进而验证计数器的值确实增加了:

File: tests/harness.rs 文件:tests/harness.rs

#[tokio::test]
async fn can_get_contract_id() {
    let (instance, _id) = get_contract_instance().await;

    // Increment the counter
    instance.methods().increment().call().await.unwrap();

    // Get the current value of the counter
    let result = instance.methods().count().call().await.unwrap();

    // Check that the current value of the counter is 1.
    // Recall that the initial value of the counter was 0.
    assert_eq!(result.value, 1);
}

Run cargo test in the terminal. If all goes well, the output should look as follows:

在终端中运行 cargo test。如果一切顺利,输出应如下所示:

$ cargo test
  ...
  running 1 test
  test can_get_contract_id ... ok
  test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.11s

部署合约 (Deploy the Contract)

It's now time to deploy the contract to the testnet. We will show how to do this using forc from the command line, but you can also do it using the Rust SDK or the TypeScript SDK.

现在是时候将合约部署到测试网了。我们会展示如何从命令行使用 forc 执行此操作,但您也可以使用 Rust SDKTypeScript SDK

In order to deploy a contract, you need to have a wallet to sign the transaction and coins to pay for gas. First, we'll create a wallet.

为了部署合约,您需要有一个钱包来签署交易和硬币来支付gas。首先,我们将创建一个钱包。

安装钱包 CLI (Install the Wallet CLI)

Follow these steps to set up a wallet and create an account.

按照这些步骤设置钱包和创建帐户

After typing in a password, be sure to save the mnemonic phrase that is output.

输入密码后,一定要保存输出的助记词。

With this, you'll get a fuel address that looks something like this: fuel1efz7lf36w9da9jekqzyuzqsfrqrlzwtt3j3clvemm6eru8fe9nvqj5kar8. Save this address as you'll need it to sign transactions when we deploy the contract.

有了这个,你会得到一个看起来像这样的Fuel地址:fuel1efz7lf36w9da9jekqzyuzqsfrqrlzwtt3j3clvemm6eru8fe9nvqj5kar8。保存此地址,因为在我们部署合约时您将用它来签署交易。

获取测试网代币 (Get Testnet Coins)

With your account address in hand, head to the testnet faucet to get some coins sent to your wallet.

使用您的帐户地址,前往 testnet 水龙头 将一些代币发送到您的钱包。

部署到测试网 (Deploy To Testnet)

Now that you have a wallet, you can deploy with forc deploy and passing in the testnet endpoint like this:

现在您有了一个钱包,您可以使用 forc deploy进行部署并像这样传入测试网端点:

forc deploy --node-url beta-3.fuel.network/graphql --gas-price 1 --random-salt

Note: We set the gas price to 1. Without this flag, the gas price is 0 by default and the transaction will fail. 注意:我们将gas price设置为1,如果没有这个flag,gas price默认为0,交易会失败。

The terminal will ask for the address of the wallet you want to sign this transaction with, paste in the address you saved earlier, it looks like this: fuel1efz7lf36w9da9jekqzyuzqsfrqrlzwtt3j3clvemm6eru8fe9nvqj5kar8

终端将询问您要签署此交易的钱包地址,粘贴您之前保存的地址,如下所示:fuel1efz7lf36w9da9jekqzyuzqsfrqrlzwtt3j3clvemm6eru8fe9nvqj5kar8

The terminal will output your Contract id like this:

终端将像这样输出您的Contract id

Contract id: 0xd09b469b0c31c05222b553021aa23c3b6a535db5092c22b84690dc88ca17deaa Be sure to save this as you will need it to build a frontend with the Typescript SDK later in this tutorial.

请务必保存它,因为您将需要它来在本教程后面使用 Typescript SDK 构建前端。

The terminal will output a Transaction id to sign and prompt you for a signature. Open a new terminal tab and view your accounts by running forc wallet accounts. If you followed these steps, you'll notice you only have one account, 0.

终端将输出一个 Transaction id to sign 并提示您签名。打开一个新的终端选项卡并通过运行forc wallet accounts 查看您的帐户。如果您按照这些步骤操作,您会发现您只有一个帐户“0”。

Grab the Transaction id to sign from your other terminal and sign with your account by running the following command:

从您的其他终端获取“要签名的交易 ID”,并通过运行以下命令使用您的帐户签名:

forc wallet sign --account `[the account index, without brackets]` tx-id `[Transaction id to sign, without brackets]`

Your command should look like this: 您的命令应该看起来像这样:

$ forc wallet sign --account 0 tx-id 16d7a8f9d15cfba1bd000d3f99cd4077dfa1fce2a6de83887afc3f739d6c84df
Please enter your password to decrypt initialized wallet's phrases:
Signature: 736dec3e92711da9f52bed7ad4e51e3ec1c9390f4b05caf10743229295ffd5c1c08a4ca477afa85909173af3feeda7c607af5109ef6eb72b6b40b3484db2332c

Enter your password when prompted, and you'll get back a signature. Save that signature, and return to your other terminal window, and paste that in where its prompting you to provide a signature for this transaction.

出现提示时输入您的密码,您将得到一个“签名”。保存该签名,然后返回到您的其他终端窗口,并将其粘贴到提示您“为此交易提供签名”的位置。

Finally, you will get back a TransactionId to confirm your contract was deployed. With this ID, you can head to the block explorer and view your contract.

最后,您将返回一个 TransactionId 来确认您的合约已部署。使用此 ID,您可以前往 block explorer 查看您的合约。

Note You should prefix your TransactionId with 0x to view it in the block explorer 注意 您应该在您的 TransactionId 前加上 0x 才能在区块浏览器中查看它

恭喜,你已经在 Fuel 上完成了你的第一个智能合约 ⛽ (Congrats, you have completed your first smart contract on Fuel ⛽)

Here is the repo for this project. If you run into any problems, a good first step is to compare your code to this repo and resolve any differences.

这是该项目的存储库。如果您遇到任何问题,最好的第一步是将您的代码与此存储库进行比较并解决任何差异。

Tweet us @fuel_network letting us know you just built a dapp on Fuel, you might get invited to a private group of builders, be invited to the next Fuel dinner, get alpha on the project, or something 👀.

您还可以发推给我们 @fuel_network ,让我们知道您刚刚在 Fuel 上构建了一个 dapp,您可能会被邀请加入一个私人开发者小组,被邀请参加下一次 Fuel 晚宴,获得 alpha 版项目之类的👀。

需要帮助? (Need Help?)

Get help from the team by posting your question in the Fuel Forum.

Fuel 论坛 中发布您的问题,获得团队的帮助。

Last updated