Skip to content

Commit 1a959b9

Browse files
authored
Merge pull request #506 from hashgraph/sr/examples
2 parents 37aad36 + 7f036a9 commit 1a959b9

16 files changed

+1133
-22
lines changed

examples/schedule.rs

Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
/*
2+
* ‌
3+
* Hedera Rust SDK
4+
* ​
5+
* Copyright (C) 2022 - 2023 Hedera Hashgraph, LLC
6+
* ​
7+
* Licensed under the Apache License, Version 2.0 (the "License");
8+
* you may not use this file except in compliance with the License.
9+
* You may obtain a copy of the License at
10+
*
11+
* http://www.apache.org/licenses/LICENSE-2.0
12+
*
13+
* Unless required by applicable law or agreed to in writing, software
14+
* distributed under the License is distributed on an "AS IS" BASIS,
15+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16+
* See the License for the specific language governing permissions and
17+
* limitations under the License.
18+
* ‍
19+
*/
20+
21+
use clap::Parser;
22+
use hedera::{
23+
AccountCreateTransaction, AccountId, Client, Hbar, KeyList, PrivateKey, ScheduleInfoQuery, ScheduleSignTransaction, TransferTransaction
24+
};
25+
use time::OffsetDateTime;
26+
27+
#[derive(Parser, Debug)]
28+
struct Args {
29+
#[clap(long, env)]
30+
operator_account_id: AccountId,
31+
32+
#[clap(long, env)]
33+
operator_key: PrivateKey,
34+
35+
#[clap(long, env, default_value = "testnet")]
36+
hedera_network: String,
37+
}
38+
39+
#[tokio::main]
40+
async fn main() -> anyhow::Result<()> {
41+
let _ = dotenvy::dotenv();
42+
let args = Args::parse();
43+
44+
let client = Client::for_name(&args.hedera_network)?;
45+
46+
client.set_operator(args.operator_account_id, args.operator_key.clone());
47+
48+
// Generate a Ed25519 private, public key pair
49+
let key1 = PrivateKey::generate_ed25519();
50+
let key2 = PrivateKey::generate_ed25519();
51+
52+
println!("private key 1 = {key1}");
53+
println!("public key 1 = {}", key1.public_key());
54+
println!("private key 2 = {key2}");
55+
println!("public key 2 = {}", key2.public_key());
56+
57+
let new_account_id = AccountCreateTransaction::new()
58+
.key(KeyList::from([key1.public_key(), key2.public_key()]))
59+
.initial_balance(Hbar::from_tinybars(1000))
60+
.execute(&client)
61+
.await?
62+
.get_receipt(&client)
63+
.await?
64+
.account_id
65+
.unwrap();
66+
67+
println!("new account ID: {new_account_id}");
68+
69+
let mut tx = TransferTransaction::new();
70+
71+
tx.hbar_transfer(new_account_id, -Hbar::new(1))
72+
.hbar_transfer(args.operator_account_id, Hbar::new(1));
73+
74+
let response = tx
75+
.schedule()
76+
.expiration_time(OffsetDateTime::now_utc() + time::Duration::days(1))
77+
.wait_for_expiry(true)
78+
.execute(&client)
79+
.await?;
80+
81+
println!("scheduled transaction ID = {}", response.transaction_id);
82+
83+
let schedule_id = response.get_receipt(&client).await?.schedule_id.unwrap();
84+
println!("schedule ID = {schedule_id}");
85+
86+
let record = response.get_record(&client).await?;
87+
println!("record = {record:?}");
88+
89+
ScheduleSignTransaction::new()
90+
.schedule_id(schedule_id)
91+
.freeze_with(&client)?
92+
.sign(key1)
93+
.execute(&client)
94+
.await?
95+
.get_receipt(&client)
96+
.await?;
97+
98+
let info = ScheduleInfoQuery::new()
99+
.schedule_id(schedule_id)
100+
.execute(&client)
101+
.await?;
102+
103+
println!("schedule info = {info:?}");
104+
105+
ScheduleSignTransaction::new()
106+
.schedule_id(schedule_id)
107+
.freeze_with(&client)?
108+
.sign(key2)
109+
.execute(&client)
110+
.await?
111+
.get_receipt(&client)
112+
.await?;
113+
114+
let transaction_id = response.transaction_id;
115+
116+
println!("The following link should query the mirror node for the scheduled transaction:");
117+
118+
println!(
119+
"https://{}.mirrornode.hedera.com/api/v1/transactions/{}",
120+
args.hedera_network,
121+
format_args!(
122+
"{}-{}-{}",
123+
transaction_id.account_id,
124+
transaction_id.valid_start.unix_timestamp(),
125+
transaction_id.valid_start.nanosecond()
126+
)
127+
);
128+
129+
Ok(())
130+
}
Lines changed: 208 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,208 @@
1+
/*
2+
* ‌
3+
* Hedera Rust SDK
4+
* ​
5+
* Copyright (C) 2022 - 2023 Hedera Hashgraph, LLC
6+
* ​
7+
* Licensed under the Apache License, Version 2.0 (the "License");
8+
* you may not use this file except in compliance with the License.
9+
* You may obtain a copy of the License at
10+
*
11+
* http://www.apache.org/licenses/LICENSE-2.0
12+
*
13+
* Unless required by applicable law or agreed to in writing, software
14+
* distributed under the License is distributed on an "AS IS" BASIS,
15+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16+
* See the License for the specific language governing permissions and
17+
* limitations under the License.
18+
* ‍
19+
*/
20+
21+
use clap::Parser;
22+
use hedera::{
23+
AccountCreateTransaction, AccountDeleteTransaction, AccountId, Client, Hbar, Key, KeyList, PrivateKey, ScheduleCreateTransaction, ScheduleId, ScheduleInfoQuery, ScheduleSignTransaction, Status, TransactionReceiptQuery, TransferTransaction
24+
};
25+
26+
#[derive(Parser, Debug)]
27+
struct Args {
28+
#[clap(long, env)]
29+
operator_account_id: AccountId,
30+
31+
#[clap(long, env)]
32+
operator_key: PrivateKey,
33+
34+
#[clap(long, env, default_value = "testnet")]
35+
hedera_network: String,
36+
}
37+
38+
#[tokio::main]
39+
async fn main() -> anyhow::Result<()> {
40+
let _ = dotenvy::dotenv();
41+
let args = Args::parse();
42+
43+
let client = Client::for_name(&args.hedera_network)?;
44+
45+
client.set_operator(args.operator_account_id, args.operator_key.clone());
46+
47+
println!("threshold key example");
48+
println!("keys:");
49+
50+
let mut private_keys = Vec::with_capacity(3);
51+
let mut public_keys = Vec::with_capacity(3);
52+
let mut clients = Vec::with_capacity(3);
53+
let mut accounts = Vec::with_capacity(3);
54+
55+
for i in 0..3 {
56+
let private_key = PrivateKey::generate_ed25519();
57+
let public_key = private_key.public_key();
58+
59+
println!("key #{i}");
60+
println!("private key: {private_key}");
61+
println!("public key: {public_key}");
62+
63+
let receipt = AccountCreateTransaction::new()
64+
.key(public_key.clone())
65+
.initial_balance(Hbar::new(1))
66+
.execute(&client)
67+
.await?
68+
.get_receipt(&client)
69+
.await?;
70+
71+
let account_id = receipt.account_id.unwrap();
72+
73+
let client = Client::for_name(&args.hedera_network)?;
74+
75+
client.set_operator(account_id, private_key.clone());
76+
77+
private_keys.push(private_key);
78+
public_keys.push(public_key);
79+
clients.push(client);
80+
accounts.push(account_id);
81+
println!("account = {account_id}");
82+
}
83+
84+
let key_list = KeyList {
85+
keys: public_keys.iter().cloned().map(Key::from).collect(),
86+
threshold: Some(2),
87+
};
88+
89+
// We are using all of these keys, so the scheduled transaction doesn't automatically go through
90+
// It works perfectly fine with just one key
91+
// The key that must sign each transfer out of the account. If receiverSigRequired is true, then
92+
// it must also sign any transfer into the account.
93+
let threshold_account = AccountCreateTransaction::new()
94+
.key(key_list.clone())
95+
.initial_balance(Hbar::new(10))
96+
.execute(&client)
97+
.await?
98+
.get_receipt(&client)
99+
.await?
100+
.account_id
101+
.unwrap();
102+
103+
println!("threshold account = {threshold_account}");
104+
105+
let mut schedule_id: Option<ScheduleId> = None;
106+
107+
for (loop_client, operator_id) in clients.iter().zip(&accounts) {
108+
// Each loopClient creates an identical transaction, sending 1 hbar to each of the created accounts,
109+
// sent from the threshold Account
110+
let mut tx = TransferTransaction::new();
111+
for account in &accounts {
112+
tx.hbar_transfer(*account, Hbar::new(1));
113+
}
114+
115+
tx.hbar_transfer(threshold_account, -Hbar::new(3));
116+
117+
let mut scheduled_tx = ScheduleCreateTransaction::new();
118+
119+
scheduled_tx.scheduled_transaction(tx);
120+
121+
scheduled_tx.payer_account_id(threshold_account);
122+
123+
let response = scheduled_tx.execute(&loop_client).await?;
124+
125+
let loop_receipt = TransactionReceiptQuery::new()
126+
.transaction_id(response.transaction_id)
127+
.node_account_ids([response.node_account_id])
128+
.execute(&loop_client)
129+
.await?;
130+
131+
println!(
132+
"operator [{operator_id}]: schedule_id = {:?}",
133+
loop_receipt.schedule_id
134+
);
135+
136+
// Save the schedule ID, so that it can be asserted for each loopClient submission
137+
let schedule_id = &*schedule_id.get_or_insert_with(|| loop_receipt.schedule_id.unwrap());
138+
139+
if Some(schedule_id) != loop_receipt.schedule_id.as_ref() {
140+
println!(
141+
"invalid generated schedule id, expected {schedule_id}, got {:?}",
142+
loop_receipt.schedule_id
143+
);
144+
}
145+
146+
// If the status return by the receipt is related to already created, execute a schedule sign transaction
147+
if loop_receipt.status == Status::IdenticalScheduleAlreadyCreated {
148+
let sign_response = ScheduleSignTransaction::new()
149+
.schedule_id(*schedule_id)
150+
.node_account_ids([response.node_account_id])
151+
.execute(&loop_client)
152+
.await?;
153+
154+
let sign_receipt = TransactionReceiptQuery::new()
155+
.transaction_id(sign_response.transaction_id)
156+
.execute(&client)
157+
.await?;
158+
159+
if !matches!(
160+
sign_receipt.status,
161+
Status::Success | Status::ScheduleAlreadyExecuted
162+
) {
163+
println!(
164+
"Bad status while getting receipt of schedule sign with operator {operator_id}: {:?}"
165+
, sign_receipt.status,
166+
);
167+
return Ok(());
168+
}
169+
}
170+
}
171+
172+
println!(
173+
"{:?}",
174+
ScheduleInfoQuery::new()
175+
.schedule_id(schedule_id.unwrap())
176+
.execute(&client)
177+
.await?
178+
);
179+
180+
let mut threshold_delete_tx = AccountDeleteTransaction::new();
181+
182+
threshold_delete_tx
183+
.account_id(threshold_account)
184+
.transfer_account_id(args.operator_account_id)
185+
.freeze_with(&client)?;
186+
187+
for (key, account) in private_keys.into_iter().zip(accounts) {
188+
threshold_delete_tx.sign(key.clone());
189+
190+
AccountDeleteTransaction::new()
191+
.account_id(account)
192+
.transfer_account_id(args.operator_account_id)
193+
.freeze_with(&client)?
194+
.sign(key)
195+
.execute(&client)
196+
.await?
197+
.get_receipt(&client)
198+
.await?;
199+
}
200+
201+
threshold_delete_tx
202+
.execute(&client)
203+
.await?
204+
.get_receipt(&client)
205+
.await?;
206+
207+
Ok(())
208+
}

0 commit comments

Comments
 (0)