Rust StarkNet账户管理库starknet-accounts的使用,实现StarkNet区块链账户创建、签名和交易功能
Rust StarkNet账户管理库starknet-accounts的使用,实现StarkNet区块链账户创建、签名和交易功能
安装
在项目目录中运行以下Cargo命令:
cargo add starknet-accounts
或者在Cargo.toml中添加:
starknet-accounts = "0.15.0"
完整示例代码
以下是一个使用starknet-accounts库实现StarkNet账户创建、签名和交易的完整示例:
use starknet_accounts::{
Account, AccountFactory, OpenZeppelinAccountFactory, SingleOwnerAccount
};
use starknet_core::types::{
FieldElement, InvokeTransactionResult, TransactionRequest
};
use starknet_providers::{Provider, SequencerGatewayProvider};
use starknet_signers::{LocalWallet, SigningKey};
#[tokio::main]
async fn main() {
// 1. 初始化Provider连接StarkNet测试网
let provider = SequencerGatewayProvider::starknet_alpha_goerli();
// 2. 生成随机私钥
let signing_key = SigningKey::from_random();
let private_key = signing_key.secret_scalar();
// 3. 创建账户工厂
let factory = OpenZeppelinAccountFactory::new(
FieldElement::from_hex_be("0x123...").unwrap(), // 类哈希
FieldElement::from_hex_be("0x456...").unwrap(), // 盐
provider.clone()
).await.unwrap();
// 4. 部署新账户
let account = factory.deploy(private_key).await.unwrap();
println!("New account deployed: {:#x}", account.address());
// 5. 准备交易
let transaction = TransactionRequest::new(
FieldElement::from_hex_be("0x789...").unwrap(), // 合约地址
"transfer".to_string(), // 函数名
vec![
FieldElement::from_hex_be("0xabc...").unwrap(), // 接收方地址
FieldElement::from(100u64) // 转账金额
]
);
// 6. 签名并发送交易
let result: InvokeTransactionResult = account.execute(vec![transaction]).await.unwrap();
println!("Transaction hash: {:#x}", result.transaction_hash);
}
代码说明
- Provider初始化:连接StarkNet测试网
- 密钥生成:使用
SigningKey
生成随机私钥 - 账户工厂:使用OpenZeppelin账户模板创建工厂
- 账户部署:部署新账户到StarkNet网络
- 交易构建:创建转账交易请求
- 交易执行:账户签名并发送交易
注意事项
- 需要替换示例中的类哈希、盐和合约地址等参数
- 实际使用中需要处理错误和交易状态
- 部署账户需要支付gas费用
1 回复
Rust StarkNet账户管理库starknet-accounts使用指南
starknet-accounts
是一个用于StarkNet区块链账户管理的Rust库,提供了账户创建、签名和交易发送等功能。
主要功能
- 创建和管理StarkNet账户
- 对交易进行签名
- 发送交易到StarkNet网络
- 支持不同类型的账户实现
安装
在Cargo.toml
中添加依赖:
[dependencies]
starknet-accounts = "0.3"
starknet = "0.3"
tokio = { version = "1.0", features = ["full"] }
基本使用方法
1. 创建本地账户
use starknet::core::types::FieldElement;
use starknet::core::utils::get_contract_address;
use starknet_accounts::{LocalWallet, SingleOwnerAccount};
use starknet_providers::jsonrpc::HttpTransport;
use starknet_providers::JsonRpcClient;
#[tokio::main]
async fn main() {
// 初始化provider
let provider = JsonRpcClient::new(HttpTransport::new(
"https://starknet-goerli.infura.io/v3/YOUR_INFURA_KEY".parse().unwrap(),
));
// 创建私钥
let private_key = FieldElement::from_hex_be("YOUR_PRIVATE_KEY").unwrap();
// 创建账户地址
let address = get_contract_address(
FieldElement::from_hex_be("0x123").unwrap(), // salt
FieldElement::from_hex_be("0x456").unwrap(), // class hash
&[private_key],
FieldElement::from_hex_be("0x0").unwrap(), // constructor calldata
);
// 创建本地钱包
let signer = LocalWallet::from(private_key);
// 创建账户
let account = SingleOwnerAccount::new(
provider,
signer,
address,
FieldElement::from_hex_be("0x534e5f474f45524c49").unwrap(), // chain_id (SN_GOERLI)
);
}
2. 发送交易
use starknet::core::types::{FunctionCall, InvokeTransactionRequest};
use starknet::macros::selector;
#[tokio::main]
async fn main() {
// ... 前面的账户创建代码
// 准备调用数据
let call = FunctionCall {
contract_address: FieldElement::from_hex_be("0xCONTRACT_ADDRESS").unwrap(),
entry_point_selector: selector!("transfer"),
calldata: vec![
FieldElement::from_hex_be("0xRECIPIENT").unwrap(),
FieldElement::from_hex_be("1000000000000000000").unwrap(), // 1 ETH
FieldElement::ZERO,
],
};
// 创建调用交易请求
let tx_request = InvokeTransactionRequest {
sender_address: address,
calldata: call.calldata,
signature: vec![],
max_fee: FieldElement::from_hex_be("1000000000000000").unwrap(),
nonce: FieldElement::ZERO,
};
// 执行交易
let result = account.execute(vec![call]).send().await.unwrap();
println!("Transaction hash: {:#x}", result.transaction_hash);
}
3. 查询账户信息
#[tokio::main]
async fn main() {
// ... 前面的账户创建代码
// 查询nonce
let nonce = account.get_nonce().await.unwrap();
println!("Current nonce: {}", nonce);
// 查询余额
let balance = provider
.call(
FunctionCall {
contract_address: FieldElement::from_hex_be("0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7").unwrap(), // ETH合约地址
entry_point_selector: selector!("balanceOf"),
calldata: vec![address],
},
None,
)
.await
.unwrap();
println!("ETH balance: {}", balance[0]);
}
高级功能
1. 使用多重签名账户
use starknet_accounts::MultiSigAccount;
#[tokio::main]
async fn main() {
// 创建多个签名者
let signer1 = LocalWallet::from(FieldElement::from_hex_be("PRIVATE_KEY1").unwrap());
let signer2 = LocalWallet::from(FieldElement::from_hex_be("PRIVATE_KEY2").unwrap());
// 创建多重签名账户
let account = MultiSigAccount::new(
provider,
vec![signer1, signer2],
address,
FieldElement::from_hex_be("0x534e5f474f45524c49").unwrap(), // chain_id
2, // 需要的签名数
);
}
2. 使用硬件钱包签名
use starknet_accounts::LedgerWallet;
#[tokio::main]
async fn main() {
// 创建Ledger钱包
let signer = LedgerWallet::new("path/to/ledger").unwrap();
// 创建账户
let account = SingleOwnerAccount::new(
provider,
signer,
address,
FieldElement::from_hex_be("0x534e5f474f45524c49").unwrap(),
);
}
注意事项
- 妥善保管私钥,不要硬编码在代码中
- 生产环境使用环境变量或安全的密钥管理系统
- 发送交易前确保账户有足够的ETH支付gas费用
- 注意处理nonce,避免重复使用
完整示例
以下是一个完整的StarkNet账户管理示例,包含创建账户、查询余额和发送交易:
use starknet::core::types::{FieldElement, FunctionCall, InvokeTransactionRequest};
use starknet::core::utils::get_contract_address;
use starknet::macros::selector;
use starknet_accounts::{LocalWallet, SingleOwnerAccount};
use starknet_providers::jsonrpc::HttpTransport;
use starknet_providers::JsonRpcClient;
#[tokio::main]
async fn main() {
// 1. 初始化provider
let provider = JsonRpcClient::new(HttpTransport::new(
"https://starknet-goerli.infura.io/v3/YOUR_INFURA_KEY".parse().unwrap(),
));
// 2. 创建账户
let private_key = FieldElement::from_hex_be("YOUR_PRIVATE_KEY").unwrap();
let address = get_contract_address(
FieldElement::from_hex_be("0x123").unwrap(),
FieldElement::from_hex_be("0x456").unwrap(),
&[private_key],
FieldElement::from_hex_be("0x0").unwrap(),
);
let signer = LocalWallet::from(private_key);
let account = SingleOwnerAccount::new(
provider.clone(),
signer,
address,
FieldElement::from_hex_be("0x534e5f474f45524c49").unwrap(),
);
// 3. 查询余额
let balance = provider
.call(
FunctionCall {
contract_address: FieldElement::from_hex_be("0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7").unwrap(),
entry_point_selector: selector!("balanceOf"),
calldata: vec![address],
},
None,
)
.await
.unwrap();
println!("Current ETH balance: {}", balance[0]);
// 4. 发送交易
let call = FunctionCall {
contract_address: FieldElement::from_hex_be("0xCONTRACT_ADDRESS").unwrap(),
entry_point_selector: selector!("transfer"),
calldata: vec![
FieldElement::from_hex_be("0xRECIPIENT").unwrap(),
FieldElement::from_hex_be("1000000000000000000").unwrap(),
FieldElement::ZERO,
],
};
let result = account.execute(vec![call]).send().await.unwrap();
println!("Transaction hash: {:#x}", result.transaction_hash);
}