Skip to content

Commit 101121e

Browse files
feat: add changes
Signed-off-by: Ivaylo Nikolov <[email protected]>
1 parent cfd9b7c commit 101121e

File tree

4 files changed

+526
-51
lines changed

4 files changed

+526
-51
lines changed

examples/account_hooks.rs

Lines changed: 168 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,168 @@
1+
// SPDX-License-Identifier: Apache-2.0
2+
3+
use clap::Parser;
4+
use hedera::{
5+
AccountCreateTransaction, AccountId, AccountUpdateTransaction, Client, ContractCreateTransaction, ContractId, EvmHookSpec, Hbar, HookCreationDetails, HookExtensionPoint, LambdaEvmHook, PrivateKey
6+
};
7+
8+
#[derive(Parser, Debug)]
9+
struct Args {
10+
#[clap(long, env, default_value = "0.0.2")]
11+
operator_account_id: AccountId,
12+
13+
#[clap(
14+
long,
15+
env,
16+
default_value = "302e020100300506032b65700422042091132178e72057a1d7528025956fe39b0b847f200ab59b2fdd367017f3087137"
17+
)]
18+
operator_key: PrivateKey,
19+
20+
#[clap(long, env, default_value = "testnet")]
21+
hedera_network: String,
22+
}
23+
24+
// Hook contract bytecode
25+
// For a real example, you'd read this from a file
26+
const HOOK_BYTECODE: &str = "6080604052348015600e575f5ffd5b506103da8061001c5f395ff3fe60806040526004361061001d575f3560e01c80630b6c5c0414610021575b5f5ffd5b61003b6004803603810190610036919061021c565b610051565b60405161004891906102ed565b60405180910390f35b5f61016d73ffffffffffffffffffffffffffffffffffffffff163073ffffffffffffffffffffffffffffffffffffffff16146100c2576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016100b990610386565b60405180910390fd5b60019050979650505050505050565b5f5ffd5b5f5ffd5b5f73ffffffffffffffffffffffffffffffffffffffff82169050919050565b5f610102826100d9565b9050919050565b610112816100f8565b811461011c575f5ffd5b50565b5f8135905061012d81610109565b92915050565b5f819050919050565b61014581610133565b811461014f575f5ffd5b50565b5f813590506101608161013c565b92915050565b5f5ffd5b5f5ffd5b5f5ffd5b5f5f83601f84011261018757610186610166565b5b8235905067ffffffffffffffff8111156101a4576101a361016a565b5b6020830191508360018202830111156101c0576101bf61016e565b5b9250929050565b5f5f83601f8401126101dc576101db610166565b5b8235905067ffffffffffffffff8111156101f9576101f861016a565b5b6020830191508360018202830111156102155761021461016e565b5b9250929050565b5f5f5f5f5f5f5f60a0888a031215610237576102366100d1565b5b5f6102448a828b0161011f565b97505060206102558a828b01610152565b96505060406102668a828b01610152565b955050606088013567ffffffffffffffff811115610287576102866100d5565b5b6102938a828b01610172565b9450945050608088013567ffffffffffffffff8111156102b6576102b56100d5565b5b6102c28a828b016101c7565b925092505092959891949750929550565b5f8115159050919050565b6102e7816102d3565b82525050565b5f6020820190506103005f8301846102de565b92915050565b5f82825260208201905092915050565b7f436f6e74726163742063616e206f6e6c792062652063616c6c656420617320615f8201527f20686f6f6b000000000000000000000000000000000000000000000000000000602082015250565b5f610370602583610306565b915061037b82610316565b604082019050919050565b5f6020820190508181035f83015261039d81610364565b905091905056fea2646970667358221220a8c76458204f8bb9a86f59ec2f0ccb7cbe8ae4dcb65700c4b6ee91a39404083a64736f6c634300081e0033";
27+
28+
async fn create_hook_contract(
29+
client: &Client,
30+
operator_key: &PrivateKey,
31+
) -> anyhow::Result<ContractId> {
32+
let bytecode = hex::decode(HOOK_BYTECODE)?;
33+
34+
let receipt = ContractCreateTransaction::new()
35+
.admin_key(operator_key.public_key())
36+
.gas(500_000)
37+
.bytecode(bytecode)
38+
.freeze_with(client)?
39+
.sign(operator_key.clone())
40+
.execute(client)
41+
.await?
42+
.get_receipt(client)
43+
.await?;
44+
45+
Ok(receipt.contract_id.unwrap())
46+
}
47+
48+
#[tokio::main]
49+
async fn main() -> anyhow::Result<()> {
50+
let _ = dotenvy::dotenv();
51+
52+
let args = Args::parse();
53+
54+
let client = Client::for_name(&args.hedera_network)?;
55+
client.set_operator(args.operator_account_id, args.operator_key.clone());
56+
57+
println!("Account Hooks Example Start!");
58+
59+
/*
60+
* Step 1: Create the hook contract.
61+
*/
62+
println!("Creating hook contract...");
63+
64+
let contract_id = create_hook_contract(&client, &args.operator_key).await?;
65+
println!("Hook contract created with ID: {contract_id}");
66+
67+
/*
68+
* Step 2: Demonstrate creating an account with hooks.
69+
*/
70+
println!("\n=== Creating Account with Hooks ===");
71+
println!("Creating account with lambda EVM hook...");
72+
73+
let account_key = PrivateKey::generate_ed25519();
74+
let account_public_key = account_key.public_key();
75+
76+
// Create a lambda EVM hook
77+
let spec = EvmHookSpec::new(Some(contract_id));
78+
let lambda_hook = LambdaEvmHook::new(spec, vec![]);
79+
80+
// Create hook creation details
81+
let admin_key = client.get_operator_public_key().unwrap();
82+
let mut hook_with_id_1002 = HookCreationDetails::new(
83+
HookExtensionPoint::AccountAllowanceHook,
84+
1002,
85+
Some(lambda_hook),
86+
);
87+
hook_with_id_1002.admin_key = Some(admin_key.into());
88+
89+
let account_receipt = AccountCreateTransaction::new()
90+
.set_key_without_alias(account_public_key)
91+
.initial_balance(Hbar::new(1))
92+
.add_hook(hook_with_id_1002)
93+
.freeze_with(&client)?
94+
.sign(args.operator_key.clone())
95+
.execute(&client)
96+
.await?
97+
.get_receipt(&client)
98+
.await?;
99+
100+
let account_id = account_receipt.account_id.unwrap();
101+
println!("account id = {account_id}");
102+
println!("Successfully created account with lambda hook!");
103+
104+
/*
105+
* Step 3: Demonstrate adding hooks to an existing account.
106+
*/
107+
println!("\n=== Adding Hooks to Existing Account ===");
108+
println!("Adding hooks to existing account...");
109+
110+
// Create basic lambda hooks with no storage updates
111+
let spec1 = EvmHookSpec::new(Some(contract_id));
112+
let basic_hook = LambdaEvmHook::new(spec1, vec![]);
113+
let mut hook_with_id_1 = HookCreationDetails::new(
114+
HookExtensionPoint::AccountAllowanceHook,
115+
1,
116+
Some(basic_hook),
117+
);
118+
hook_with_id_1.admin_key = Some(admin_key.into());
119+
120+
let spec2 = EvmHookSpec::new(Some(contract_id));
121+
let basic_hook2 = LambdaEvmHook::new(spec2, vec![]);
122+
let mut hook_with_id_2 = HookCreationDetails::new(
123+
HookExtensionPoint::AccountAllowanceHook,
124+
2,
125+
Some(basic_hook2),
126+
);
127+
hook_with_id_2.admin_key = Some(admin_key.into());
128+
129+
match AccountUpdateTransaction::new()
130+
.account_id(account_id)
131+
.add_hook(hook_with_id_1)
132+
.add_hook(hook_with_id_2)
133+
.freeze_with(&client)?
134+
.sign(account_key.clone())
135+
.execute(&client)
136+
.await?
137+
.get_receipt(&client)
138+
.await
139+
{
140+
Ok(_) => println!("Successfully added hooks to account!"),
141+
Err(error) => println!("Failed to execute hook transaction: {error}"),
142+
}
143+
144+
/*
145+
* Step 4: Demonstrate hook deletion.
146+
*/
147+
println!("\n=== Deleting Hooks from Account ===");
148+
println!("Deleting hooks from account...");
149+
150+
match AccountUpdateTransaction::new()
151+
.account_id(account_id)
152+
.delete_hook(1)
153+
.delete_hook(2)
154+
.freeze_with(&client)?
155+
.sign(account_key)
156+
.execute(&client)
157+
.await?
158+
.get_receipt(&client)
159+
.await
160+
{
161+
Ok(_) => println!("Successfully deleted hooks (IDs: 1, 2)"),
162+
Err(error) => println!("Failed to execute hook deletion: {error}"),
163+
}
164+
165+
println!("Account Hooks Example Complete!");
166+
167+
Ok(())
168+
}

examples/contract_hooks.rs

Lines changed: 156 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,156 @@
1+
// SPDX-License-Identifier: Apache-2.0
2+
3+
mod resources;
4+
5+
use clap::Parser;
6+
use hedera::{
7+
AccountId, Client, ContractCreateTransaction, ContractId, ContractUpdateTransaction, EvmHookSpec, HookCreationDetails, HookExtensionPoint, LambdaEvmHook, PrivateKey
8+
};
9+
10+
#[derive(Parser, Debug)]
11+
struct Args {
12+
#[clap(long, env, default_value = "0.0.2")]
13+
operator_account_id: AccountId,
14+
15+
#[clap(
16+
long,
17+
env,
18+
default_value = "302e020100300506032b65700422042091132178e72057a1d7528025956fe39b0b847f200ab59b2fdd367017f3087137"
19+
)]
20+
operator_key: PrivateKey,
21+
22+
#[clap(long, env, default_value = "testnet")]
23+
hedera_network: String,
24+
}
25+
26+
// Hook contract bytecode
27+
// For a real example, you'd read this from a file
28+
const HOOK_BYTECODE: &str = "6080604052348015600e575f5ffd5b506103da8061001c5f395ff3fe60806040526004361061001d575f3560e01c80630b6c5c0414610021575b5f5ffd5b61003b6004803603810190610036919061021c565b610051565b60405161004891906102ed565b60405180910390f35b5f61016d73ffffffffffffffffffffffffffffffffffffffff163073ffffffffffffffffffffffffffffffffffffffff16146100c2576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016100b990610386565b60405180910390fd5b60019050979650505050505050565b5f5ffd5b5f5ffd5b5f73ffffffffffffffffffffffffffffffffffffffff82169050919050565b5f610102826100d9565b9050919050565b610112816100f8565b811461011c575f5ffd5b50565b5f8135905061012d81610109565b92915050565b5f819050919050565b61014581610133565b811461014f575f5ffd5b50565b5f813590506101608161013c565b92915050565b5f5ffd5b5f5ffd5b5f5ffd5b5f5f83601f84011261018757610186610166565b5b8235905067ffffffffffffffff8111156101a4576101a361016a565b5b6020830191508360018202830111156101c0576101bf61016e565b5b9250929050565b5f5f83601f8401126101dc576101db610166565b5b8235905067ffffffffffffffff8111156101f9576101f861016a565b5b6020830191508360018202830111156102155761021461016e565b5b9250929050565b5f5f5f5f5f5f5f60a0888a031215610237576102366100d1565b5b5f6102448a828b0161011f565b97505060206102558a828b01610152565b96505060406102668a828b01610152565b955050606088013567ffffffffffffffff811115610287576102866100d5565b5b6102938a828b01610172565b9450945050608088013567ffffffffffffffff8111156102b6576102b56100d5565b5b6102c28a828b016101c7565b925092505092959891949750929550565b5f8115159050919050565b6102e7816102d3565b82525050565b5f6020820190506103005f8301846102de565b92915050565b5f82825260208201905092915050565b7f436f6e74726163742063616e206f6e6c792062652063616c6c656420617320615f8201527f20686f6f6b000000000000000000000000000000000000000000000000000000602082015250565b5f610370602583610306565b915061037b82610316565b604082019050919050565b5f6020820190508181035f83015261039d81610364565b905091905056fea2646970667358221220a8c76458204f8bb9a86f59ec2f0ccb7cbe8ae4dcb65700c4b6ee91a39404083a64736f6c634300081e0033";
29+
30+
async fn create_hook_contract(
31+
client: &Client,
32+
operator_key: &PrivateKey,
33+
) -> anyhow::Result<ContractId> {
34+
let bytecode = hex::decode(HOOK_BYTECODE)?;
35+
36+
let receipt = ContractCreateTransaction::new()
37+
.admin_key(operator_key.public_key())
38+
.gas(500_000)
39+
.bytecode(bytecode)
40+
.freeze_with(client)?
41+
.sign(operator_key.clone())
42+
.execute(client)
43+
.await?
44+
.get_receipt(client)
45+
.await?;
46+
47+
Ok(receipt.contract_id.unwrap())
48+
}
49+
50+
#[tokio::main]
51+
async fn main() -> anyhow::Result<()> {
52+
let _ = dotenvy::dotenv();
53+
54+
let args = Args::parse();
55+
56+
let client = Client::for_name(&args.hedera_network)?;
57+
client.set_operator(args.operator_account_id, args.operator_key.clone());
58+
59+
println!("Contract Hooks Example Start!");
60+
61+
/*
62+
* Step 1: Create the hook contract.
63+
*/
64+
println!("Creating hook contract...");
65+
66+
let hook_contract_id = create_hook_contract(&client, &args.operator_key).await?;
67+
println!("Hook contract created with ID: {hook_contract_id}");
68+
69+
/*
70+
* Step 2: Demonstrate creating a contract with hooks.
71+
*/
72+
println!("\n=== Creating Contract with Hooks ===");
73+
println!("Creating contract with lambda EVM hook...");
74+
75+
let simple_contract_bytecode = hex::decode(resources::simple_bytecode())?;
76+
77+
// Build a basic lambda EVM hook (no admin key, no storage updates)
78+
let spec = EvmHookSpec::new(Some(hook_contract_id));
79+
let lambda_hook = LambdaEvmHook::new(spec, vec![]);
80+
let hook_with_id_1 = HookCreationDetails::new(
81+
HookExtensionPoint::AccountAllowanceHook,
82+
1,
83+
Some(lambda_hook),
84+
);
85+
86+
let contract_receipt = ContractCreateTransaction::new()
87+
.admin_key(args.operator_key.public_key())
88+
.gas(400_000)
89+
.bytecode(simple_contract_bytecode)
90+
.add_hook(hook_with_id_1)
91+
.freeze_with(&client)?
92+
.sign(args.operator_key.clone())
93+
.execute(&client)
94+
.await?
95+
.get_receipt(&client)
96+
.await?;
97+
98+
let contract_with_hooks_id = contract_receipt.contract_id.unwrap();
99+
println!("Created contract with ID: {contract_with_hooks_id}");
100+
println!("Successfully created contract with basic lambda hook!");
101+
102+
/*
103+
* Step 3: Demonstrate adding hooks to an existing contract.
104+
*/
105+
println!("\n=== Adding Hooks to Existing Contract ===");
106+
println!("Adding hooks to existing contract...");
107+
108+
let admin_key = client.get_operator_public_key().unwrap();
109+
let spec3 = EvmHookSpec::new(Some(hook_contract_id));
110+
let basic_hook = LambdaEvmHook::new(spec3, vec![]);
111+
let mut hook_with_id_3 = HookCreationDetails::new(
112+
HookExtensionPoint::AccountAllowanceHook,
113+
3,
114+
Some(basic_hook),
115+
);
116+
hook_with_id_3.admin_key = Some(admin_key.into());
117+
118+
match ContractUpdateTransaction::new()
119+
.contract_id(contract_with_hooks_id)
120+
.add_hook(hook_with_id_3)
121+
.freeze_with(&client)?
122+
.sign(args.operator_key.clone())
123+
.execute(&client)
124+
.await?
125+
.get_receipt(&client)
126+
.await
127+
{
128+
Ok(_) => println!("Successfully added hooks to contract!"),
129+
Err(error) => println!("Failed to execute hook transaction: {error}"),
130+
}
131+
132+
/*
133+
* Step 4: Demonstrate hook deletion.
134+
*/
135+
println!("\n=== Deleting Hooks from Contract ===");
136+
println!("Deleting hooks from contract...");
137+
138+
match ContractUpdateTransaction::new()
139+
.contract_id(contract_with_hooks_id)
140+
.delete_hook(1) // Delete hook created during contract creation
141+
.delete_hook(3) // Delete hook added via contract update
142+
.freeze_with(&client)?
143+
.sign(args.operator_key)
144+
.execute(&client)
145+
.await?
146+
.get_receipt(&client)
147+
.await
148+
{
149+
Ok(_) => println!("Successfully deleted hooks with IDs: 1 and 3"),
150+
Err(error) => println!("Failed to execute hook deletion: {error}"),
151+
}
152+
153+
println!("Contract Hooks Example Complete!");
154+
155+
Ok(())
156+
}

0 commit comments

Comments
 (0)