#waves #blockchain #async #cryptography

waves-rust

一个用于与 Waves 区块链交互的 Rust 库。支持节点交互、离线交易签名以及创建地址和密钥。

7 个版本

0.2.5 2023 年 12 月 11 日
0.2.4 2023 年 2 月 17 日
0.2.3 2022 年 12 月 26 日
0.2.2 2022 年 11 月 28 日
0.1.0 2022 年 9 月 19 日

#1671 in 魔法豆

每月下载量 38

MIT 许可证

450KB
11K SLoC

waves-rust

一个用于与 Waves 区块链交互的 Rust 库。

支持节点交互、离线交易签名以及创建地址和密钥。

在项目中使用 waves-rust

使用以下代码将 waves-rust 添加为项目的依赖项。

要求
  • edition "2021"
  • rust-version "1.56" 或更高版本
  • tokio 运行时以与节点 REST-API 交互
Cargo
[dependencies]
waves-rust = "0.2.2"
tokio = { version = "1.12.0", features = ["full"] }

入门

从随机词组创建一个私钥('T' 为测试网)的账户

use waves_rust::model::{ChainId, PrivateKey};
use waves_rust::util::Crypto;

let seed_phrase = Crypto::get_random_seed_phrase(12);
let private_key = PrivateKey::from_seed(&seed_phrase, 0).unwrap();
let public_key = private_key.public_key();
let address = public_key.address(ChainId::TESTNET.byte()).unwrap();

创建一个节点并学习一些关于区块链的知识

use waves_rust::api::{Node, Profile};
use waves_rust::model::Address;

#[tokio::main]
async fn get_node_info() {
    let node = Node::from_profile(Profile::TESTNET);
    println!("Current height is {}", node.get_height().await.unwrap());
    println!("My balance is {}", node.get_balance(&address).await.unwrap());
    println!("With 100 confirmations: {}", node.get_balance_with_confirmations(&address, 100).await.unwrap());
}

给朋友发送一些钱

use waves_rust::api::{Node, Profile};
use waves_rust::model::{Address, Amount, Base58String, ChainId, PrivateKey, Transaction, TransactionData, TransferTransaction};
use waves_rust::util::get_current_epoch_millis;

let buddy = Address::from_string("3N2yqTEKArWS3ySs2f6t8fpXdjX6cpPuhG8").unwrap();

let transaction_data = TransactionData::Transfer(TransferTransaction::new(
    buddy,
    Amount::new(1_00_000_000, None), // None is WAVES asset
    Base58String::from_string("thisisattachment").unwrap(),
));

let timestamp = get_current_epoch_millis();
let signed_tx = Transaction::new(
    transaction_data,
    Amount::new(100000, None),
    timestamp,
    private_key.public_key(),
    3,
    ChainId::TESTNET.byte(),
)
.sign(&private_key)
.unwrap();

node.broadcast(&signed_tx).await.unwrap();

在账户上设置一个脚本。请小心处理这里的脚本,因为它可能会永远锁定账户!

use waves_rust::api::{Node, Profile};
use waves_rust::model::{Address, Amount, ChainId, PrivateKey, SetScriptTransaction, Transaction, TransactionData};
use waves_rust::util::get_current_epoch_millis;

let script =
"{-# CONTENT_TYPE EXPRESSION #-} sigVerify(tx.bodyBytes, tx.proofs[0], tx.senderPublicKey)";

let compiled_script = node.compile_script(script, true).await.unwrap();
let transaction_data =
TransactionData::SetScript(SetScriptTransaction::new(compiled_script.script()));

let timestamp = get_current_epoch_millis();
let signed_tx = Transaction::new(
    transaction_data,
    Amount::new(100000, None),
    timestamp,
    private_key.public_key(),
    3,
    ChainId::TESTNET.byte(),
)
.sign(&private_key)
.unwrap();

node.broadcast(&signed_tx).await.unwrap();

读取交易信息

来自 REST API 的相同交易

use waves_rust::api::{Node, Profile};
use waves_rust::model::{Address, ByteString, ChainId, Id, TransactionDataInfo};

let node = Node::from_profile(Profile::STAGENET);

let id = Id::from_string("CWuFY42te67sLmc5gwt4NxwHmFjVfJdHkKuLyshTwEct").unwrap();
let tx_info = node.get_transaction_info(&id).await.unwrap();

println!("type: {:?}", tx_info.tx_type());
println!("id: {:?}", tx_info.id());
println!("fee: {:?}", tx_info.fee().value());
println!("feeAssetId: {:?}", tx_info.fee().asset_id());
println!("timestamp: {:?}", tx_info.timestamp());
println!("version: {:?}", tx_info.version());
println!("chainId: {:?}", tx_info.chain_id());
println!("sender: {:?}",tx_info.public_key().address(ChainId::STAGENET.byte()).unwrap().encoded());
println!("senderPublicKey: {:?}", tx_info.public_key().encoded());
println!("height: {:?}", tx_info.height());
println!("applicationStatus: {:?}", tx_info.status());

let eth_tx = match tx_info.data() {
    TransactionDataInfo::Ethereum(eth_tx) => eth_tx,
    _ => panic!("expected ethereum transaction"),
};

println!("bytes: {}", eth_tx.bytes().encoded());
println!("{:?}", eth_tx.payload());

广播交易

创建账户(有关账户创建的更多信息,请参阅入门部分)

use waves_rust::model::PrivateKey;
use waves_rust::util::Crypto;

let bob = PrivateKey::from_seed(&Crypto::get_random_seed_phrase(12), 0).unwrap();
let alice = PrivateKey::from_seed(&Crypto::get_random_seed_phrase(12), 0).unwrap();

广播兑换交易

use waves_rust::api::{Node, Profile};
use waves_rust::model::{Amount, AssetId, ChainId, ExchangeTransaction, Order, OrderType, PriceMode, PrivateKey, Transaction, TransactionData};
use waves_rust::util::{get_current_epoch_millis, Crypto};

let price = Amount::new(1000, None);
let amount = Amount::new(
    100,
    Some(AssetId::from_string("8bt2MZjuUCJPmfucPfaZPTXqrxmoCHCC8gVnbjZ7bhH6").unwrap()),
);

let matcher_fee = 300000;

let buy = Order::v4(
    ChainId::TESTNET.byte(),
    get_current_epoch_millis(),
    alice.public_key(),
    Amount::new(300000, None),
    OrderType::Buy,
    amount.clone(),
    price.clone(),
    bob.public_key(),
    Order::default_expiration(get_current_epoch_millis()),
    PriceMode::AssetDecimals,
)
.sign(&alice)
.unwrap();

let sell = Order::v3(
    ChainId::TESTNET.byte(),
    get_current_epoch_millis(),
    bob.public_key(),
    Amount::new(300000, None),
    OrderType::Sell,
    amount.clone(),
    price.clone(),
    bob.public_key(),
    Order::default_expiration(get_current_epoch_millis()),
)
.sign(&bob)
.unwrap();

let transaction_data = TransactionData::Exchange(ExchangeTransaction::new(
    buy.clone(),
    sell.clone(),
    amount.value(),
    price.value(),
    matcher_fee,
    matcher_fee,
));

let timestamp = get_current_epoch_millis();
let signed_tx = Transaction::new(
    transaction_data,
    Amount::new(300000, None),
    timestamp,
    bob.public_key(),
    4,
    ChainId::TESTNET.byte(),
)
.sign(&bob)
.unwrap();

let tx_info = node.broadcast(&signed_tx).await.unwrap();

与 dApp 一起工作

创建账户(有关账户创建的更多信息,请参阅入门部分)

use waves_rust::model::PrivateKey;
use waves_rust::util::Crypto;

let bob = PrivateKey::from_seed(&Crypto::get_random_seed_phrase(12), 0);
let alice = PrivateKey::from_seed(&Crypto::get_random_seed_phrase(12), 0);

广播发行交易

use waves_rust::api::{Node, Profile};
use waves_rust::model::{Amount, ChainId, IssueTransaction, PrivateKey, Transaction, TransactionData};
use waves_rust::util::{Crypto, get_current_epoch_millis};

let transaction_data = TransactionData::Issue(IssueTransaction::new(
        "Asset".to_owned(),
        "this is test asset".to_owned(),
        1000,
        2,
        false,
        None,
));

let timestamp = get_current_epoch_millis();
let signed_tx = Transaction::new(
    transaction_data,
    Amount::new(100400000, None),
    timestamp,
    alice.public_key(),
    3,
    ChainId::TESTNET.byte(),
)
.sign(&alice)
.unwrap();

node.broadcast(&signed_tx).await.unwrap();

编译和广播 RIDE 脚本

use waves_rust::api::{Node, Profile};
use waves_rust::model::{Amount, ChainId, PrivateKey, SetScriptTransaction, Transaction, TransactionData};
use waves_rust::util::{get_current_epoch_millis, Crypto};

let script = r#"
        {-# STDLIB_VERSION 5 #-}
        {-# CONTENT_TYPE DAPP #-}
        {-# SCRIPT_TYPE ACCOUNT #-}
        
        @Callable(inv)
        func call(bv: ByteVector, b: Boolean, int: Int, str: String, list: List[Int]) = {
             let asset = Issue("Asset", "", 1, 0, true)
             let assetId = asset.calculateAssetId()
             let lease = Lease(inv.caller, 7)
             let leaseId = lease.calculateLeaseId()
             [
                BinaryEntry("bin", assetId),
                BooleanEntry("bool", true),
                IntegerEntry("int", 100500),
                StringEntry("assetId", assetId.toBase58String()),
                StringEntry("leaseId", leaseId.toBase58String()),
                StringEntry("del", ""),
                DeleteEntry("del"),
                asset,
                SponsorFee(assetId, 1),
                Reissue(assetId, 4, false),
                Burn(assetId, 3),
                ScriptTransfer(inv.caller, 2, assetId),
                lease,
                LeaseCancel(lease.calculateLeaseId())
             ]
        }
"#;

let compiled_script = node.compile_script(script, true).await.unwrap();

let transaction_data = TransactionData::SetScript(SetScriptTransaction::new(compiled_script.script()));

let timestamp = get_current_epoch_millis();
let signed_tx = Transaction::new(
    transaction_data,
    Amount::new(500000, None),
    timestamp,
    alice.public_key(),
    3,
    ChainId::TESTNET.byte(),
)
.sign(&alice)
.unwrap();

node.broadcast(&signed_tx).await.unwrap();

调用 dApp

use waves_rust::api::{Node, Profile};
use waves_rust::model::{Address, Amount, Base64String, ByteString, ChainId, Function, InvokeScriptTransaction, PrivateKey, Transaction, TransactionData};
use waves_rust::model::Arg::{Binary, Boolean, Integer, List, String};
use waves_rust::util::{get_current_epoch_millis, Crypto};

let alice_address =
Address::from_public_key(ChainId::TESTNET.byte(), &alice.public_key()).unwrap();
let transaction_data = TransactionData::InvokeScript(InvokeScriptTransaction::new(
    alice_address.clone(),
    Function::new(
        "call".to_owned(),
        vec![
            Binary(Base64String::from_bytes(vec![1, 2, 3])),
            Boolean(true),
            Integer(100500),
            String(alice_address.encoded()),
            List(vec![Integer(100500)]),
        ],
    ),
    vec![
        Amount::new(1, None),
        Amount::new(2, None),
        Amount::new(3, None),
        Amount::new(4, None),
    ],
));

let timestamp = get_current_epoch_millis();
let signed_tx = Transaction::new(
    transaction_data,
    Amount::new(100500000, None),
    timestamp,
    bob.public_key(),
    3,
    ChainId::TESTNET.byte(),
)
.sign(&bob)
.unwrap();

node.broadcast(&signed_tx).await.unwrap();

依赖项

~13–33MB
~503K SLoC