Skip to content

Commit ada47a6

Browse files
committed
feat(WIP): Introduce BatchTransactions
Signed-off-by: gsstoykov <[email protected]>
1 parent 4ae9ad8 commit ada47a6

File tree

8 files changed

+515
-6
lines changed

8 files changed

+515
-6
lines changed

examples/batch_transaction.rs

Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
// SPDX-License-Identifier: Apache-2.0
2+
3+
use std::str::FromStr;
4+
5+
use hedera::{
6+
AccountBalanceQuery,
7+
AccountCreateTransaction,
8+
AccountId,
9+
BatchTransaction,
10+
Client,
11+
Hbar,
12+
PrivateKey,
13+
TransferTransaction,
14+
};
15+
16+
#[tokio::main]
17+
async fn main() -> hedera::Result<()> {
18+
// Create client for testnet (you can also use mainnet or previewnet)
19+
let client = Client::for_testnet();
20+
21+
// Set operator (the account that pays for transactions)
22+
let operator_key = PrivateKey::from_str_ed25519(
23+
"302e020100300506032b657004220420a869f4c6191b9c8c99933e7f6b6611711737e4b1a1a5a4cb5370e719a1f6df98"
24+
)?;
25+
let operator_account = AccountId::from_str("0.0.1001")?;
26+
client.set_operator(operator_account, operator_key);
27+
28+
println!("BatchTransaction Example");
29+
println!("========================");
30+
31+
// Step 1: Create a batch key
32+
// This key will be used to sign the batch transaction itself
33+
let batch_key = PrivateKey::generate_ed25519();
34+
println!("Generated batch key: {}", batch_key.public_key());
35+
36+
// Step 2: Create some accounts that will be involved in transfers
37+
let alice_key = PrivateKey::generate_ed25519();
38+
let alice = create_account(&client, alice_key.public_key(), Hbar::new(5)).await?;
39+
println!("Created Alice account: {}", alice);
40+
41+
let bob_key = PrivateKey::generate_ed25519();
42+
let bob = create_account(&client, bob_key.public_key(), Hbar::new(3)).await?;
43+
println!("Created Bob account: {}", bob);
44+
45+
// Step 3: Create individual transactions and prepare them for batching
46+
println!("\nPreparing batch transactions...");
47+
48+
// Create a transfer from Alice to the operator
49+
let mut alice_transfer = TransferTransaction::new();
50+
alice_transfer
51+
.hbar_transfer(alice, Hbar::new(-1)) // Alice sends 1 HBAR
52+
.hbar_transfer(operator_account, Hbar::new(1)); // Operator receives 1 HBAR
53+
54+
// Freeze the transaction and set batch key
55+
alice_transfer.freeze_with(&client)?;
56+
alice_transfer.set_batch_key(batch_key.public_key().into());
57+
alice_transfer.sign(alice_key.clone());
58+
59+
// Create a transfer from Bob to the operator
60+
let mut bob_transfer = TransferTransaction::new();
61+
bob_transfer
62+
.hbar_transfer(bob, Hbar::new(-2)) // Bob sends 2 HBAR
63+
.hbar_transfer(operator_account, Hbar::new(2)); // Operator receives 2 HBAR
64+
65+
// Freeze the transaction and set batch key
66+
bob_transfer.freeze_with(&client)?;
67+
bob_transfer.set_batch_key(batch_key.public_key().into());
68+
bob_transfer.sign(bob_key.clone());
69+
70+
// Step 4: Get balances before batch execution
71+
println!("\nBalances before batch execution:");
72+
print_balance(&client, "Alice", alice).await?;
73+
print_balance(&client, "Bob", bob).await?;
74+
print_balance(&client, "Operator", operator_account).await?;
75+
76+
// Step 5: Create and execute the batch transaction
77+
println!("\nExecuting batch transaction...");
78+
79+
let mut batch = BatchTransaction::new();
80+
batch.add_inner_transaction(alice_transfer.into())?;
81+
batch.add_inner_transaction(bob_transfer.into())?;
82+
batch.freeze_with(&client)?;
83+
batch.sign(batch_key);
84+
85+
// Execute the batch transaction
86+
let response = batch.execute(&client).await?;
87+
let receipt = response.get_receipt(&client).await?;
88+
89+
println!("Batch transaction executed successfully!");
90+
println!("Transaction ID: {}", response.transaction_id);
91+
println!("Status: {:?}", receipt.status);
92+
93+
// Step 6: Get balances after batch execution
94+
println!("\nBalances after batch execution:");
95+
print_balance(&client, "Alice", alice).await?;
96+
print_balance(&client, "Bob", bob).await?;
97+
print_balance(&client, "Operator", operator_account).await?;
98+
99+
// Step 7: Get inner transaction IDs
100+
println!("\nInner transaction IDs:");
101+
for (i, tx_id) in batch.get_inner_transaction_ids().iter().enumerate() {
102+
if let Some(id) = tx_id {
103+
println!("Transaction {}: {}", i + 1, id);
104+
}
105+
}
106+
107+
println!("\nBatchTransaction example completed successfully!");
108+
109+
Ok(())
110+
}
111+
112+
async fn create_account(
113+
client: &Client,
114+
public_key: hedera::PublicKey,
115+
initial_balance: Hbar,
116+
) -> hedera::Result<AccountId> {
117+
let response = AccountCreateTransaction::new()
118+
.set_key_without_alias(public_key)
119+
.initial_balance(initial_balance)
120+
.execute(client)
121+
.await?;
122+
123+
let receipt = response.get_receipt(client).await?;
124+
receipt.account_id.ok_or_else(|| hedera::Error::TimedOut(
125+
Box::new(hedera::Error::GrpcStatus(tonic::Status::not_found("account_id not found in receipt")))
126+
))
127+
}
128+
129+
async fn print_balance(client: &Client, name: &str, account_id: AccountId) -> hedera::Result<()> {
130+
let balance = AccountBalanceQuery::new()
131+
.account_id(account_id)
132+
.execute(client)
133+
.await?;
134+
println!("{}: {} HBAR", name, balance.hbars);
135+
Ok(())
136+
}

0 commit comments

Comments
 (0)