Skip to content

Commit 6ea8793

Browse files
authored
Merge pull request #512 from hashgraph/sr/final-examples
2 parents 7a13c53 + b49ddc3 commit 6ea8793

21 files changed

+988
-50
lines changed

Cargo.lock

Lines changed: 29 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@ clap = { version = "4.0.0", features = ["derive", "env"] }
8484
dotenvy = "0.15.5"
8585
expect-test = "1.4.0"
8686
hex-literal = "0.4.0"
87+
miniserde = "0.1.30"
8788
parking_lot = "0.12.0"
8889

8990
[dev-dependencies.tokio]

examples/contract/mod.rs

Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
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 hedera::{
22+
AccountId, Client, ContractCreateFlow, ContractExecuteTransaction, ContractFunctionParameters,
23+
ContractFunctionResult, ContractId, Hbar, PrivateKey, TransactionId,
24+
};
25+
26+
#[derive(Default)]
27+
pub struct ContractStep {
28+
pub result_inspector: Option<fn(&ContractFunctionResult)>,
29+
pub parameters: Option<Box<dyn Fn() -> ContractFunctionParameters>>,
30+
pub payable_amount: Option<Hbar>,
31+
pub signers: Vec<PrivateKey>,
32+
pub fee_payer: Option<AccountId>,
33+
}
34+
35+
pub struct ContractHelper {
36+
contract_id: ContractId,
37+
steps: Vec<ContractStep>,
38+
}
39+
40+
impl ContractHelper {
41+
pub fn new(contract_id: ContractId, steps: Vec<ContractStep>) -> Self {
42+
Self { contract_id, steps }
43+
}
44+
45+
pub async fn execute(&self, client: &Client) -> hedera::Result<()> {
46+
for (index, step) in self.steps.iter().enumerate() {
47+
println!("Attempting to execute step {index}");
48+
49+
let mut tx = ContractExecuteTransaction::new();
50+
51+
tx.contract_id(self.contract_id).gas(10_000_000);
52+
53+
if let Some(payable_amount) = step.payable_amount {
54+
tx.payable_amount(payable_amount);
55+
}
56+
57+
let function_name = format!("step{index}");
58+
let params = step.parameters.as_deref().map(|it| it());
59+
60+
match params {
61+
Some(params) => tx.function_with_parameters(&function_name, &params),
62+
None => tx.function(&function_name),
63+
};
64+
65+
if let Some(fee_payer) = step.fee_payer {
66+
tx.transaction_id(TransactionId::generate(fee_payer));
67+
}
68+
69+
tx.freeze_with(client)?;
70+
71+
for signer in &step.signers {
72+
tx.sign(signer.clone());
73+
}
74+
75+
let record = tx
76+
.execute(client)
77+
.await?
78+
.valdiate_status(false)
79+
.get_record(client)
80+
.await?;
81+
82+
if let Err(e) = record.receipt.validate_status(true) {
83+
eprintln!("Error occurred during step{index}: {e}");
84+
eprintln!("Transaction record: {record:?}");
85+
break;
86+
}
87+
88+
let function_result = record.contract_function_result.unwrap();
89+
println!("gas used: {}", function_result.gas_used);
90+
91+
if let Some(inspector) = step.result_inspector {
92+
inspector(&function_result)
93+
}
94+
95+
println!(
96+
"step {index} completed, and returned valid result. (TransactionId `{}`",
97+
record.transaction_id
98+
);
99+
}
100+
101+
Ok(())
102+
}
103+
}
104+
105+
pub async fn create_contract(
106+
client: &Client,
107+
bytecode: &str,
108+
constructor_parameters: ContractFunctionParameters,
109+
) -> hedera::Result<ContractId> {
110+
let contract_id = ContractCreateFlow::new()
111+
.bytecode_hex(bytecode)?
112+
.max_chunks(30)
113+
.gas(8_000_000)
114+
.constructor_parameters(constructor_parameters.to_bytes(None))
115+
.execute(client)
116+
.await?
117+
.get_receipt(client)
118+
.await?
119+
.contract_id
120+
.unwrap();
121+
122+
Ok(contract_id)
123+
}
Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
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+
AccountBalanceQuery, AccountCreateTransaction, AccountId, Client, Hbar, Key, KeyList, PrivateKey, 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+
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);
47+
48+
// Generate three Ed25519::new private, public key pairs.
49+
// You do not need the private keys to create the Threshold Key List,
50+
// you only need the public keys, and if you're doing things correctly,
51+
// you probably shouldn't have these private keys.
52+
let private_keys = [
53+
PrivateKey::generate_ed25519(),
54+
PrivateKey::generate_ed25519(),
55+
PrivateKey::generate_ed25519(),
56+
];
57+
58+
println!("public keys:");
59+
for public_key in private_keys.iter().map(PrivateKey::public_key) {
60+
println!("{public_key}");
61+
}
62+
63+
// require 2 of the 3 keys we generated to sign on anything modifying this account
64+
let transaction_key = KeyList {
65+
keys: private_keys
66+
.iter()
67+
.map(PrivateKey::public_key)
68+
.map(Key::from)
69+
.collect(),
70+
threshold: Some(2),
71+
};
72+
73+
let transaction_response = AccountCreateTransaction::new()
74+
.key(transaction_key)
75+
.initial_balance(Hbar::new(10))
76+
.execute(&client)
77+
.await?;
78+
79+
// This will wait for the receipt to become available
80+
let receipt = transaction_response.get_receipt(&client).await?;
81+
82+
let new_account_id = receipt.account_id.unwrap();
83+
84+
println!("account = {new_account_id}");
85+
86+
let transfer_transaction_response = TransferTransaction::new()
87+
.hbar_transfer(new_account_id, Hbar::new(10).negated())
88+
.hbar_transfer(AccountId::from(3), Hbar::new(10))
89+
// we sign with 2 of the 3 keys
90+
.sign(private_keys[0].clone())
91+
.sign(private_keys[1].clone())
92+
.execute(&client)
93+
.await?;
94+
95+
// (important!) wait for the transfer to go to consensus
96+
transfer_transaction_response.get_receipt(&client).await?;
97+
98+
let balance_after = AccountBalanceQuery::new()
99+
.account_id(new_account_id)
100+
.execute(&client)
101+
.await?
102+
.hbars;
103+
104+
println!("account balance after transfer: {balance_after}");
105+
106+
Ok(())
107+
}

examples/create_simple_contract.rs

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
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+
mod resources;
22+
23+
use clap::Parser;
24+
use hedera::{
25+
AccountId, Client, ContractCallQuery, ContractCreateTransaction, ContractDeleteTransaction, ContractFunctionParameters, FileCreateTransaction, PrivateKey
26+
};
27+
28+
#[derive(Parser, Debug)]
29+
struct Args {
30+
#[clap(long, env)]
31+
operator_account_id: AccountId,
32+
33+
#[clap(long, env)]
34+
operator_key: PrivateKey,
35+
36+
#[clap(long, env, default_value = "testnet")]
37+
hedera_network: String,
38+
}
39+
40+
#[tokio::main]
41+
async fn main() -> anyhow::Result<()> {
42+
let _ = dotenvy::dotenv();
43+
44+
let args = Args::parse();
45+
46+
let client = Client::for_name(&args.hedera_network)?;
47+
48+
client.set_operator(args.operator_account_id, args.operator_key.clone());
49+
50+
let bytecode = resources::simple_bytecode();
51+
52+
// create the contract's bytecode file
53+
let file_transaction_response = FileCreateTransaction::new()
54+
// Use the same key as the operator to "own" this file
55+
.keys([args.operator_key.public_key()])
56+
.contents(bytecode)
57+
.execute(&client)
58+
.await?;
59+
60+
let file_receipt = file_transaction_response.get_receipt(&client).await?;
61+
let new_file_id = file_receipt.file_id.unwrap();
62+
63+
println!("contract bytecode file: {new_file_id}");
64+
65+
let contract_transaction_response = ContractCreateTransaction::new()
66+
.bytecode_file_id(new_file_id)
67+
.gas(500000)
68+
.admin_key(args.operator_key.public_key())
69+
.constructor_parameters(
70+
ContractFunctionParameters::new()
71+
.add_string("hello from hedera!")
72+
.to_bytes(None),
73+
)
74+
.execute(&client)
75+
.await?;
76+
77+
let contract_receipt = contract_transaction_response.get_receipt(&client).await?;
78+
let new_contract_id = contract_receipt.contract_id.unwrap();
79+
80+
println!("new contract ID: {new_contract_id}");
81+
82+
let contract_call_result = ContractCallQuery::new()
83+
.contract_id(new_contract_id)
84+
.gas(500000)
85+
.function("greet")
86+
.execute(&client)
87+
.await?;
88+
89+
if let Some(err) = contract_call_result.error_message {
90+
anyhow::bail!("error calling contract: {err}");
91+
}
92+
93+
let message = contract_call_result.get_str(0);
94+
println!("contract returned message: {message:?}");
95+
96+
// now delete the contract
97+
let _contract_delete_result = ContractDeleteTransaction::new()
98+
.contract_id(new_contract_id)
99+
.transfer_account_id(args.operator_account_id)
100+
.execute(&client)
101+
.await?
102+
.get_receipt(&client)
103+
.await?;
104+
105+
println!("Contract successfully deleted");
106+
107+
Ok(())
108+
}

0 commit comments

Comments
 (0)