use clap::Parser;
use hedera::{
AccountBalanceQuery, AccountCreateTransaction, AccountId, BatchTransaction, Client, Hbar, PrivateKey, TransferTransaction
};
#[derive(Parser, Debug)]
struct Args {
#[clap(long, env)]
operator_account_id: AccountId,
#[clap(long, env)]
operator_key: PrivateKey,
}
#[tokio::main]
async fn main() -> anyhow::Result<()> {
let _ = dotenvy::dotenv();
let args = Args::parse();
let client = Client::for_testnet();
client.set_operator(args.operator_account_id, args.operator_key.clone());
println!("BatchTransaction Example");
println!("========================");
let batch_key = PrivateKey::generate_ed25519();
println!("Generated batch key: {}", batch_key.public_key());
let alice_key = PrivateKey::generate_ed25519();
let alice = create_account(&client, alice_key.public_key(), Hbar::new(5)).await?;
println!("Created Alice account: {}", alice);
let bob_key = PrivateKey::generate_ed25519();
let bob = create_account(&client, bob_key.public_key(), Hbar::new(3)).await?;
println!("Created Bob account: {}", bob);
println!("\nPreparing batch transactions...");
let mut alice_transfer = TransferTransaction::new();
alice_transfer
.hbar_transfer(alice, Hbar::new(-1)) .hbar_transfer(args.operator_account_id, Hbar::new(1));
client.set_operator(alice, alice_key.clone());
alice_transfer.set_batch_key(batch_key.public_key().into());
alice_transfer.batchify(&client, batch_key.public_key().into())?;
let mut bob_transfer = TransferTransaction::new();
bob_transfer
.hbar_transfer(bob, Hbar::new(-2)) .hbar_transfer(args.operator_account_id, Hbar::new(2));
client.set_operator(bob, bob_key.clone());
bob_transfer.set_batch_key(batch_key.public_key().into());
bob_transfer.batchify(&client, batch_key.public_key().into())?;
println!("\nBalances before batch execution:");
print_balance(&client, "Alice", alice).await?;
print_balance(&client, "Bob", bob).await?;
print_balance(&client, "Operator", args.operator_account_id).await?;
println!("\nExecuting batch transaction...");
client.set_operator(args.operator_account_id, args.operator_key.clone());
let mut batch = BatchTransaction::new();
batch.add_inner_transaction(alice_transfer.into())?;
batch.add_inner_transaction(bob_transfer.into())?;
batch.sign(batch_key);
let response = batch.execute(&client).await?;
let receipt = response.get_receipt(&client).await?;
println!("Batch transaction executed successfully!");
println!("Transaction ID: {}", response.transaction_id);
println!("Status: {:?}", receipt.status);
println!("\nBalances after batch execution:");
print_balance(&client, "Alice", alice).await?;
print_balance(&client, "Bob", bob).await?;
print_balance(&client, "Operator", args.operator_account_id).await?;
println!("\nInner transaction IDs:");
for (i, tx_id) in batch.get_inner_transaction_ids().iter().enumerate() {
if let Some(id) = tx_id {
println!("Transaction {}: {}", i + 1, id);
}
}
println!("\nBatchTransaction example completed successfully!");
Ok(())
}
async fn create_account(
client: &Client,
public_key: hedera::PublicKey,
initial_balance: Hbar,
) -> hedera::Result<AccountId> {
let response = AccountCreateTransaction::new()
.set_key_without_alias(public_key)
.initial_balance(initial_balance)
.execute(client)
.await?;
let receipt = response.get_receipt(client).await?;
receipt.account_id.ok_or_else(|| {
hedera::Error::TimedOut(Box::new(hedera::Error::GrpcStatus(
tonic::Status::not_found("account_id not found in receipt"),
)))
})
}
async fn print_balance(
client: &Client,
name: &str,
account_id: AccountId,
) -> hedera::Result<()> {
let balance = AccountBalanceQuery::new()
.account_id(account_id)
.execute(client)
.await?;
println!("{}: {} HBAR", name, balance.hbars);
Ok(())
}