要安装 Fuel 工具链,你可以使用 fuelup-init
脚本。
这将安装 forc
、forc-client
、forc-fmt
、forc-lsp
、forc-wallet
以及 fuel-core
到 ~/.fuelup/bin
。
curl https://install.fuel.network | sh
如果您正在使用 VSCode,我们建议安装 Sway 扩展 。
fuelup
? 如果您已经安装了 fuelup
,请运行以下命令,确保您的工具链是最新的。
fuelup self update
fuelup update
fuelup default latest
我们将构建一个简单的计数器合约,其中包含两个函数:一个用于递增计数器,一个用于返回计数器的值。
首先创建一个新的空文件夹。我们将其命名为 fuel-project
。
mkdir fuel-project
进入您的 fuel-project
文件夹:
cd fuel-project
然后使用 forc
创建一个合约项目:
forc new counter-contract
您将看到以下输出:
To compile, use `forc build`, and to run tests use `forc test`
----
Read the Docs:
- Sway Book: https://docs.fueldev.xyz/docs/sway
- Forc Book: https://docs.fueldev.xyz/docs/forc
- Rust SDK Book: https://docs.fueldev.xyz/docs/fuels-rs
- TypeScript SDK: https://docs.fueldev.xyz/docs/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
这是 forc
初始化的项目:
tree counter-contract
counter-contract
├── Forc.toml
└── src
└── main.sw
1 directory, 2 files
forc.toml
是 清单文件(类似于 Cargo 的 Cargo.toml
或 Node 的 package.json
),用于定义项目元数据,例如项目名称和依赖项。
在代码编辑器中打开您的项目,并删除 src/main.sw
中除第一行之外的所有内容。
每个 Sway 文件都必须以声明文件包含的程序类型开始;在这里,我们声明了这个文件是一个合约。您可以在 Sway 书 中了解更多关于 Sway 程序类型的信息。
contract;
接下来,我们将定义一个存储值。
在我们的案例中,我们有一个名为 counter
的单一计数器,类型为 u64
(64 位无符号整数),并将其初始化为 0。
storage {
counter: u64 = 0,
}
ABI 意为应用二进制接口。 ABI 定义了合约的接口。 合约必须定义或导入 ABI 声明。
将 ABI 定义在单独的库中并导入到合约中被认为是最佳实践。 这样做可以让调用合约的人更轻松地导入和使用 ABI。
为简单起见,我们将直接在合约文件中定义 ABI。
abi Counter {
#[storage(read, write)]
fn increment();
#[storage(read)]
fn count() -> u64;
}
在您的 ABI 定义下面,您将编写 ABI 中定义的函数的实现。
impl Counter for Contract {
#[storage(read)]
fn count() -> u64 {
storage.counter.read()
}
#[storage(read, write)]
fn increment() {
let incremented = storage.counter.read() + 1;
storage.counter.write(incremented);
}
}
storage.counter.read()
是一个隐式返回,等同于return storage.counter.read();
。
到目前为止,您的代码应该是这样的:
文件:./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.read()
}
#[storage(read, write)]
fn increment() {
let incremented = storage.counter.read() + 1;
storage.counter.write(incremented);
}
}
导航到您的合约文件夹:
cd counter-contract
然后运行以下命令来构建您的合约:
forc build
Compiled library "core".
Compiled library "std".
Compiled contract "counter-contract".
Bytecode size: 84 bytes.
让我们在构建后查看 counter-contract
文件夹的内容:
tree .
.
├── Forc.lock
├── Forc.toml
├── out
│ └── debug
│ ├── counter-contract-abi.json
│ ├── counter-contract-storage_slots.json
│ └── counter-contract.bin
└── src
└── main.sw
3 directories, 6 files
我们现在有一个 out
目录,其中包含我们的构建结果,如我们 ABI 的 JSON 表示和合约字节码。
不想使用 Rust 进行测试?跳过此部分,转到 部署合约 。
我们将从使用 Cargo 生成模板添加一个 Rust 集成测试套件开始。
如果您尚未安装 Rust
,可以通过运行以下命令来安装它:
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
接下来,如果您尚未安装它,请安装 cargo generate
:
cargo install cargo-generate --locked
现在,让我们使用以下命令生成默认的测试套件:
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.git
🔧 Destination: /home/user/path/to/counter-contract ...
🔧 project-name: counter-contract ...
🔧 Generating template ...
🔧 Moving generated files into: `/home/user/path/to/counter-contract`...
✨ Done! New project created /home/user/path/to/counter-contract
让我们看一下结果:
tree .
.
├── Cargo.toml
├── Forc.lock
├── Forc.toml
├── out
│ └── debug
│ ├── counter-contract-abi.json
│ ├── counter-contract-storage_slots.json
│ └── counter-contract.bin
├── src
│ └── main.sw
└── tests
└── harness.rs
4 directories, 8 files
我们有两个新文件!
Cargo.toml
是我们新测试套件的清单,指定了所需的依赖项,包括 fuels
(Fuel Rust SDK)。 tests/harness.rs
包含一些样板测试代码,让我们开始,尽管目前还没有调用任何合约方法。 打开您的 Cargo.toml
文件并检查在 dev-dependencies
下使用的 fuels
的版本。如果尚未安装,请将版本更改为 0.62.0
:
[dev-dependencies]
fuels = { version = "0.62.0", features = ["fuel-core-lib"] }
tokio = { version = "1.12", features = ["rt", "macros"] }
现在我们有了默认的测试套件,让我们向其中添加一个有用的测试。
在 test/harness.rs
文件的最底部,下面 can_get_contract_id()
测试之后,添加以下 test_increment
测试函数以验证计数器的值是否得到了增加:
#[tokio::test]
async fn test_increment() {
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);
}
以下是您的文件应该是什么样子:
文件:./counter-contract/tests/harness.rs
use fuels::{prelude::*, types::ContractId};
// Load abi from json
abigen!(Contract(
name = "MyContract",
abi = "out/debug/counter-contract-abi.json"
));
async fn get_contract_instance() -> (MyContract<WalletUnlocked>, ContractId) {
// Launch a local network and deploy the contract
let mut wallets = launch_custom_provider_and_get_wallets(
WalletsConfig::new(
Some(1), /* Single wallet */
Some(1), /* Single coin (UTXO) */
Some(1_000_000_000), /* Amount per coin */
),
None,
None,
)
.await
.unwrap();
let wallet = wallets.pop().unwrap();
let id = Contract::load_from(
"./out/debug/counter-contract.bin",
LoadConfiguration::default(),
)
.unwrap()
.deploy(&wallet, TxPolicies::default())
.await
.unwrap();
let instance = MyContract::new(id.clone(), wallet);
(instance, id.into())
}
#[tokio::test]
async fn can_get_contract_id() {
let (_instance, _id) = get_contract_instance().await;
// Now you have an instance of your contract you can use to test each function
}
#[tokio::test]
async fn test_increment() {
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);
}
在终端中运行 cargo test
:
cargo test
如果一切顺利,输出应如下所示:
...
running 2 tests
test can_get_contract_id ... ok
test test_increment ... ok
test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.25s
现在是时候部署了。我们将展示如何使用命令行中的 forc
进行部署,但您也可以使用 Rust SDK 或 TypeScript SDK 进行部署。
为了部署合约,您需要拥有一个钱包来签署交易并支付 Gas 费用。Fuelup
将指导您完成此过程。
forc-wallet
插件随默认分发的工具链一起打包安装,因此如果你按照上述说明操作,应该已经安装了它。
要使用 forc-wallet
初始化一个新钱包,可以运行以下命令:
forc wallet new
输入密码后,务必保存输出的助记词。
接下来,创建一个新的钱包账户:
forc wallet account new
这样,你将获得一个类似于这样的 Fuel 地址:fuel1efz7lf36w9da9jekqzyuzqsfrqrlzwtt3j3clvemm6eru8fe9nvqj5kar8
。
如果你需要列出你的账户,可以运行以下命令:
forc wallet accounts
您可以使用 faucet 获取测试资金。
现在,您可以使用 forc deploy
命令将合约部署到最新的测试网。
forc deploy --testnet
终端将要求您输入钱包的密码:
Please provide the password of your encrypted wallet vault at "~/.fuel/wallets/.wallet":
解锁钱包后,终端将显示账户列表:
Account 0 -- fuel18caanqmumttfnm8qp0eq7u9yluydxtqmzuaqtzdjlsww5t2jmg9skutn8n:
Asset ID Amount
0000000000000000000000000000000000000000000000000000000000000000 499999940
在列表下方,您将看到此提示:
Please provide the index of account to use for signing:
然后,您将输入首选账户的编号,并在提示时按 Y
以接受交易。
最后,您将获得部署合约的网络端点、Contract ID
和交易签名的区块。
保存 Contract ID
,因为您稍后需要用到它来连接前端。
Contract counter-contract Deployed!
Network: https://testnet.fuel.network
Contract ID: 0x8342d413de2a678245d9ee39f020795800c7e6a4ac5ff7daae275f533dc05e08
Deployed in block 0x4ea52b6652836c499e44b7e42f7c22d1ed1f03cf90a1d94cd0113b9023dfa636
这是该项目的仓库 。如果您遇到任何问题,一个很好的第一步是将您的代码与该仓库进行比较,并解决任何差异。
在 Twitter 上给我们发推 @fuel_network ,让我们知道您刚在 Fuel 上构建了一个 dapp,您可能会被邀请加入建设者的私人群组,被邀请参加下一次 Fuel 晚宴,获得项目的 Alpha 版本,或者其他什么事情 👀。
通过在 Fuel 论坛 上发布您的问题来获取团队的帮助。