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 ! ( "\n Preparing 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 ! ( "\n Balances 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 ! ( "\n Executing 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 ! ( "\n Balances 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 ! ( "\n Inner 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 ! ( "\n BatchTransaction 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