4 个版本 (2 个重大变更)
0.3.1 | 2024年6月18日 |
---|---|
0.3.0 | 2024年4月30日 |
0.2.0 | 2024年1月18日 |
0.1.0 | 2024年1月10日 |
#23 在 #signer
773 每月下载量
165KB
3K SLoC
入门指南
创建新的 Rust 应用
第一步是创建一个二进制 rust 项目。
cargo new zilliqa-rs-demo
然后我们需要将 zilliqa-rs 和 tokio 添加到项目的依赖中
cargo add zilliqa-rs tokio
调用简单的 JSON-RPC API
使用 Docker 运行 isolated-server
这里我们使用 Docker 运行一个 isolated server,将其用作目标网络,但您可以使用任何您想要的 Zilliqa 网络。
docker run -d -p 5555:5555 --name iso-server zilliqa-isolated-server:latest
调用 GetBalance
首先,我们需要创建一个 provider。在 main 的第一行,我们创建了一个 HTTP provider。我们使用上一行运行的 isolated server 的 URL。这个网络的链 ID 是 222。然后我们可以调用 provider 的 get_balance
函数,传入我们想要获取余额的账户地址。
use std::error::Error;
use zilliqa_rs::middlewares::Middleware;
use zilliqa_rs::providers::{Http, Provider};
#[tokio::main]
async fn main() -> Result<(), Box<dyn Error>> {
let provider = Provider::<Http>::try_from("http://127.0.0.1:5555")?.with_chain_id(222);
let balance = provider
.get_balance("0x381f4008505e940ad7681ec3468a719060caf796")
.await;
println!("{balance:?}");
Ok(())
}
发送交易
带有 signers 的 provider
要开始发送交易,我们需要更改 provider。我们之前拥有的 provider 没有signer,那是因为我们不打算发送交易。但现在我们想要发送,所以我们需要为它提供一个 signers。
let wallet = "0xe53d1c3edaffc7a7bab5418eb836cf75819a82872b4a1a0f1c7fcf5c3e020b89"
.parse::<LocalWallet>()?;
let provider = Provider::<Http>::try_from("http://127.0.0.1:5555")?
.with_chain_id(222)
.with_signer(wallet.clone());
这里,我们从一个私钥和一个带有该 signers 的 provider 创建一个新的钱包。这个 provider 现在可以用来发送交易。
让我们将一些 ZIL 转移到随机地址。首先,我们创建一个随机钱包
let receiver = LocalWallet::create_random()?;
然后我们需要构建一个交易。 TransactionBuilder
用于构建交易
let tx = TransactionBuilder::default()
.to_address(receiver.address.clone())
.amount(parse_zil("2.0")?)
.gas_price(2000000000u128)
.gas_limit(50u64)
.build();
这里我们将转移 2.0 ZIL 到接收者。现在我们需要发送这个交易
provider
.send_transaction_without_confirm::<CreateTransactionResponse>(tx)
.await?;
现在,让我们检查余额
let balance = provider.get_balance(&receiver.address).await;
println!("{balance:?}");
cargo run
Ok(BalanceResponse { nonce: 138, balance: 899999994124734000000000 })
Ok(BalanceResponse { nonce: 0, balance: 2000000000000 })
使用 pay 函数
TransactionBuilder 有一个辅助函数 pay
,用于简化支付交易创建
let tx = TransactionBuilder::default().pay(amount, receiver.address.clone()).build();
处理合约
技术笔记
zilliqa-rs 的一大亮点是在构建时为您的 scilla 合同生成 Rust 代码。这意味着如果您合同中有一个类似 transfer
的转换,您可以像调用普通 Rust 函数一样调用它。如果它有一个地址参数,您必须向此函数传递地址。这意味着 Rust 的类型检查之美都可以在处理 scilla 合同时发挥作用。
从 scilla 合同生成 Rust 代码
我们想要部署一个名为 HelloWorld
的简单合同并调用其 setHello
转换。首先,我们需要在 src
旁边创建一个文件夹。让我们称它为 contracts
。然后我们将 HelloWorld.scilla 移动到这个文件夹。为了让 zilliqa-rs 知道 scilla 到 Rust 代码生成的合同路径,我们需要导出 CONTRACTS_PATH
环境变量。最简单的方法是创建 .cargo/config.toml
文件并更改它如下:
[env]
CONTRACTS_PATH = {value = "contracts", relative = true}
将 relative
设置为 true
是至关重要的。否则,您的 scilla 合同不会编译成 Rust。现在,如果您使用 cargo build
构建项目,HelloWorld.scilla 就会在幕后转换为 Rust。
生成的代码可能如下所示
impl<T: Middleware> HelloWorld<T> {
pub async fn deploy(client: Arc<T> , owner: ZilAddress) -> Result<Self, Error> {
}
pub fn address(&self) -> &ZilAddress {
}
pub fn set_hello(&self , msg: String) -> RefMut<'_, transition_call::TransitionCall<T>> {
}
pub fn get_hello(&self ) -> RefMut<'_, transition_call::TransitionCall<T>> {
}
pub async fn welcome_msg(&self) -> Result<String, Error> {
}
pub async fn owner(&self) -> Result<ZilAddress, Error> {
}
}
deploy
将合同部署到网络。由于 HelloWorld.scilla 合同接受一个地址owner
作为部署参数,因此deploy
函数也需要它。这意味着您必须提供有效地址才能部署它。address
函数返回已部署合同的地址。set_hello
对应于合同中的setHello
转换。同样,由于转换接受一个字符串参数,因此set_hello
函数也是如此。get_hello
对应于getHello
转换。- 合同有一个名为
welcome_msg
的字段,要获取此字段的值,应调用welcome_msg
函数。 - 合同有一个名为
owner
的不可变状态,我们在部署时传递了值。要获取所有者值,需要调用owner
合同部署
现在是部署合同的时候了
let contract = HelloWorld::deploy(provider.into(), wallet.address).await?;
println!("Contract address: {:?}", contract.address());
deploy
的第一个参数是提供者。其余的取决于合同及其具有多少不可变状态。在这里,HelloWorld.scilla 我们只有 owner
,所以我们只传递一个地址。它是类型安全的,这意味着您不能将整数或原始字符串传递给 deploy
函数作为 owner
。
运行代码
cargo run
Ok(BalanceResponse { nonce: 138, balance: 899999994124734000000000 })
Contract address: ZilAddress("0xC50C93831F6eAB4e4F011076dca6e887288cc872")
如果您喜欢部署压缩版本的合同,可以使用 deploy_compressed
而不是 deploy
。
获取合同状态
我们的合同有一个不可变状态 owner
和一个可变状态 welcome_msg
。我们可以通过调用相应的函数来获取这些状态。
println!("Contract owner: {:?}", contract.owner().await?);
println!("Welcome msg: {}", contract.welcome_msg().await?);
调用转换
我们的合同有一个 setHello
转换。调用这个转换并不比调用 Rust 函数困难。
contract.set_hello("Salaam".to_string()).call().await?;
请注意,这里我们需要调用 call
。这是因为您在调用 call
之前所做的所有操作都像是配置转换调用。例如,您可以在调用 call
函数之前设置想要传递给转换的 ZIL 数量。
contract.transfer(receiver).amount(parse_zil("0.1")).call().await?;
好的,现在如果您获取并打印 welcome_msg
,它应该有新的值
println!("Welcome msg: {}", contract.welcome_msg().await?);
最终的 main
use std::error::Error;
use zilliqa_rs::{
contract::HelloWorld,
core::CreateTransactionResponse,
middlewares::Middleware,
providers::{Http, Provider},
signers::LocalWallet,
transaction::TransactionBuilder,
core::parse_zil,
};
#[tokio::main]
async fn main() -> Result<(), Box<dyn Error>> {
// Create the signer.
let wallet = "0xe53d1c3edaffc7a7bab5418eb836cf75819a82872b4a1a0f1c7fcf5c3e020b89"
.parse::<LocalWallet>()?;
// Create the provider with a signer.
let provider = Provider::<Http>::try_from("http://127.0.0.1:5555")?
.with_chain_id(222)
.with_signer(wallet.clone());
// Call a JSON-RPC endpoint.
let balance = provider
.get_balance("0x381f4008505e940ad7681ec3468a719060caf796")
.await;
println!("{balance:?}");
// Send a transaction
let receiver = LocalWallet::create_random()?;
let tx = TransactionBuilder::default()
.to_address(receiver.address.clone())
.amount(parse_zil("2.0")?)
.gas_price(2000000000u128)
.gas_limit(50u64)
.build();
provider
.send_transaction_without_confirm::<CreateTransactionResponse>(tx)
.await?;
let balance = provider.get_balance(&receiver.address).await;
println!("{balance:?}");
// Deploy a contract
let contract = HelloWorld::deploy(provider.into(), wallet.address).await?;
println!("Contract address: {:?}", contract.address());
println!("Contract owner: {:?}", contract.owner().await?);
println!("Welcome msg: {}", contract.welcome_msg().await?);
contract.set_hello("Salaam".to_string()).call().await?;
println!("Welcome msg: {}", contract.welcome_msg().await?);
Ok(())
}
让我们运行代码
cargo run
Ok(BalanceResponse { nonce: 138, balance: 899999994124734000000000 })
Contract address: ZilAddress("0xB84De4A67E1640D9259c502AAb6751678B593185")
Contract owner: ZilAddress("0xd90f2e538CE0Df89c8273CAd3b63ec44a3c4ed82")
Welcome msg: Hello world!
Welcome msg: Salaam
依赖项
~18–31MB
~471K SLoC