Skip to content

Commit 7e791e0

Browse files
feat: contract and account hooks transactions
Signed-off-by: Ivaylo Nikolov <[email protected]>
1 parent 47b590e commit 7e791e0

File tree

11 files changed

+1553
-0
lines changed

11 files changed

+1553
-0
lines changed

src/account/account_create_transaction.rs

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,10 @@ use hedera_proto::services::crypto_service_client::CryptoServiceClient;
55
use time::Duration;
66
use tonic::transport::Channel;
77

8+
use crate::hooks::{
9+
HookCreationDetails,
10+
LambdaEvmHook,
11+
};
812
use crate::ledger_id::RefLedgerId;
913
use crate::protobuf::{
1014
FromProtobuf,
@@ -76,6 +80,9 @@ pub struct AccountCreateTransactionData {
7680

7781
/// If true, the account declines receiving a staking reward. The default value is false.
7882
decline_staking_reward: bool,
83+
84+
/// Hooks to add immediately after creating this account.
85+
hooks: Vec<HookCreationDetails>,
7986
}
8087

8188
impl Default for AccountCreateTransactionData {
@@ -91,6 +98,7 @@ impl Default for AccountCreateTransactionData {
9198
alias: None,
9299
staked_id: None,
93100
decline_staking_reward: false,
101+
hooks: Vec::new(),
94102
}
95103
}
96104
}
@@ -293,6 +301,29 @@ impl AccountCreateTransaction {
293301
self.data_mut().decline_staking_reward = decline;
294302
self
295303
}
304+
305+
pub fn add_hook(&mut self, hook: HookCreationDetails) -> &mut Self {
306+
self.data_mut().hooks.push(hook);
307+
self
308+
}
309+
310+
pub fn add_lambda_evm_hook(&mut self, hook: LambdaEvmHook) -> &mut Self {
311+
// Helper to add a Lambda EVM hook with default extension point and hook ID
312+
use crate::hooks::HookExtensionPoint;
313+
let details =
314+
HookCreationDetails::new(HookExtensionPoint::AccountAllowanceHook, 1, Some(hook));
315+
self.data_mut().hooks.push(details);
316+
self
317+
}
318+
319+
pub fn set_hooks(&mut self, hooks: Vec<HookCreationDetails>) -> &mut Self {
320+
self.data_mut().hooks = hooks;
321+
self
322+
}
323+
324+
pub fn get_hooks(&self) -> &[HookCreationDetails] {
325+
&self.data().hooks
326+
}
296327
}
297328

298329
impl TransactionData for AccountCreateTransactionData {}
@@ -353,6 +384,11 @@ impl FromProtobuf<services::CryptoCreateTransactionBody> for AccountCreateTransa
353384
alias,
354385
staked_id: Option::from_protobuf(pb.staked_id)?,
355386
decline_staking_reward: pb.decline_reward,
387+
hooks: pb
388+
.hook_creation_details
389+
.into_iter()
390+
.map(HookCreationDetails::from_protobuf)
391+
.collect::<Result<Vec<_>, _>>()?,
356392
})
357393
}
358394
}
@@ -391,6 +427,7 @@ impl ToProtobuf for AccountCreateTransactionData {
391427
alias: self.alias.map_or(vec![], |it| it.to_bytes().to_vec()),
392428
decline_reward: self.decline_staking_reward,
393429
staked_id,
430+
hook_creation_details: self.hooks.iter().map(|h| h.to_protobuf()).collect(),
394431
}
395432
}
396433
}
@@ -417,8 +454,13 @@ mod tests {
417454
AccountCreateTransaction,
418455
AccountId,
419456
AnyTransaction,
457+
ContractId,
420458
EvmAddress,
459+
EvmHookSpec,
421460
Hbar,
461+
HookCreationDetails,
462+
HookExtensionPoint,
463+
LambdaEvmHook,
422464
PublicKey,
423465
};
424466

@@ -560,6 +602,7 @@ mod tests {
560602
20,
561603
23,
562604
],
605+
hook_creation_details: [],
563606
staked_id: Some(
564607
StakedAccountId(
565608
AccountId {
@@ -683,6 +726,7 @@ mod tests {
683726
20,
684727
23,
685728
],
729+
hook_creation_details: [],
686730
staked_id: Some(
687731
StakedNodeId(
688732
4,
@@ -710,6 +754,13 @@ mod tests {
710754
#[test]
711755
fn from_proto_body() {
712756
#[allow(deprecated)]
757+
let contract_id = ContractId::new(0, 0, 1);
758+
let hooks = vec![HookCreationDetails::new(
759+
HookExtensionPoint::AccountAllowanceHook,
760+
0,
761+
Some(LambdaEvmHook::new(EvmHookSpec::new(Some(contract_id)), vec![])),
762+
)];
763+
713764
let tx = services::CryptoCreateTransactionBody {
714765
key: Some(key().to_protobuf()),
715766
initial_balance: INITIAL_BALANCE.to_tinybars() as u64,
@@ -728,6 +779,7 @@ mod tests {
728779
staked_id: Some(services::crypto_create_transaction_body::StakedId::StakedAccountId(
729780
STAKED_ACCOUNT_ID.to_protobuf(),
730781
)),
782+
hook_creation_details: hooks.iter().map(|h| h.to_protobuf()).collect(),
731783
};
732784

733785
let tx = AccountCreateTransactionData::from_protobuf(tx).unwrap();

src/account/account_update_transaction.rs

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ use time::{
88
};
99
use tonic::transport::Channel;
1010

11+
use crate::hooks::HookCreationDetails;
1112
use crate::ledger_id::RefLedgerId;
1213
use crate::protobuf::{
1314
FromProtobuf,
@@ -89,6 +90,10 @@ pub struct AccountUpdateTransactionData {
8990

9091
/// If true, the account declines receiving a staking reward. The default value is false.
9192
decline_staking_reward: Option<bool>,
93+
94+
/// Hooks to add immediately after updating this account.
95+
hooks: Vec<HookCreationDetails>,
96+
hook_ids_to_delete: Vec<i64>,
9297
}
9398

9499
impl AccountUpdateTransaction {
@@ -271,6 +276,42 @@ impl AccountUpdateTransaction {
271276
self.data_mut().decline_staking_reward = Some(decline);
272277
self
273278
}
279+
280+
/// Returns the hooks to be created.
281+
#[must_use]
282+
pub fn get_hooks_to_create(&self) -> &[HookCreationDetails] {
283+
&self.data().hooks
284+
}
285+
286+
/// Adds a hook to be created.
287+
pub fn add_hook(&mut self, hook: HookCreationDetails) -> &mut Self {
288+
self.data_mut().hooks.push(hook);
289+
self
290+
}
291+
292+
/// Sets the hooks to be created.
293+
pub fn set_hooks(&mut self, hooks: Vec<HookCreationDetails>) -> &mut Self {
294+
self.data_mut().hooks = hooks;
295+
self
296+
}
297+
298+
/// Returns the hook IDs to be deleted.
299+
#[must_use]
300+
pub fn get_hooks_to_delete(&self) -> &[i64] {
301+
&self.data().hook_ids_to_delete
302+
}
303+
304+
/// Adds a hook ID to be deleted.
305+
pub fn delete_hook(&mut self, hook_id: i64) -> &mut Self {
306+
self.data_mut().hook_ids_to_delete.push(hook_id);
307+
self
308+
}
309+
310+
/// Sets the hook IDs to be deleted.
311+
pub fn delete_hooks(&mut self, hook_ids: Vec<i64>) -> &mut Self {
312+
self.data_mut().hook_ids_to_delete = hook_ids;
313+
self
314+
}
274315
}
275316

276317
impl TransactionData for AccountUpdateTransactionData {}
@@ -339,6 +380,12 @@ impl FromProtobuf<services::CryptoUpdateTransactionBody> for AccountUpdateTransa
339380
max_automatic_token_associations: pb.max_automatic_token_associations,
340381
staked_id: Option::from_protobuf(pb.staked_id)?,
341382
decline_staking_reward: pb.decline_reward,
383+
hooks: pb
384+
.hook_creation_details
385+
.into_iter()
386+
.map(HookCreationDetails::from_protobuf)
387+
.collect::<Result<Vec<_>, _>>()?,
388+
hook_ids_to_delete: pb.hook_ids_to_delete,
342389
})
343390
}
344391
}
@@ -382,6 +429,8 @@ impl ToProtobuf for AccountUpdateTransactionData {
382429
receive_record_threshold_field: None,
383430
receiver_sig_required_field: receiver_signature_required,
384431
staked_id,
432+
hook_creation_details: self.hooks.iter().map(|hook| hook.to_protobuf()).collect(),
433+
hook_ids_to_delete: self.hook_ids_to_delete.clone(),
385434
}
386435
}
387436
}
@@ -410,6 +459,11 @@ mod tests {
410459
AccountId,
411460
AccountUpdateTransaction,
412461
AnyTransaction,
462+
ContractId,
463+
EvmHookSpec,
464+
HookCreationDetails,
465+
HookExtensionPoint,
466+
LambdaEvmHook,
413467
PublicKey,
414468
};
415469

@@ -563,6 +617,8 @@ mod tests {
563617
100,
564618
),
565619
decline_reward: None,
620+
hook_ids_to_delete: [],
621+
hook_creation_details: [],
566622
send_record_threshold_field: None,
567623
receive_record_threshold_field: None,
568624
receiver_sig_required_field: Some(
@@ -696,6 +752,8 @@ mod tests {
696752
100,
697753
),
698754
decline_reward: None,
755+
hook_ids_to_delete: [],
756+
hook_creation_details: [],
699757
send_record_threshold_field: None,
700758
receive_record_threshold_field: None,
701759
receiver_sig_required_field: Some(
@@ -730,6 +788,14 @@ mod tests {
730788
#[test]
731789
fn from_proto_body() {
732790
#[allow(deprecated)]
791+
let contract_id = ContractId::new(0, 0, 1);
792+
let hooks = vec![HookCreationDetails::new(
793+
HookExtensionPoint::AccountAllowanceHook,
794+
0,
795+
Some(LambdaEvmHook::new(EvmHookSpec::new(Some(contract_id)), vec![])),
796+
)];
797+
let hook_ids_to_delete = vec![1, 2, 3];
798+
733799
let tx = services::CryptoUpdateTransactionBody {
734800
account_id_to_update: Some(ACCOUNT_ID.to_protobuf()),
735801
key: Some(key().to_protobuf()),
@@ -746,6 +812,8 @@ mod tests {
746812
)),
747813
proxy_fraction: 0,
748814
expiration_time: Some(EXPIRATION_TIME.to_protobuf()),
815+
hook_creation_details: hooks.iter().map(|h| h.to_protobuf()).collect(),
816+
hook_ids_to_delete,
749817
};
750818

751819
let tx = AccountUpdateTransactionData::from_protobuf(tx).unwrap();

src/contract/contract_create_transaction.rs

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ use hedera_proto::services::smart_contract_service_client::SmartContractServiceC
55
use time::Duration;
66
use tonic::transport::Channel;
77

8+
use crate::hooks::HookCreationDetails;
89
use crate::ledger_id::RefLedgerId;
910
use crate::protobuf::FromProtobuf;
1011
use crate::staked_id::StakedId;
@@ -57,6 +58,9 @@ pub struct ContractCreateTransactionData {
5758
staked_id: Option<StakedId>,
5859

5960
decline_staking_reward: bool,
61+
62+
/// Hooks to add immediately after creating this contract.
63+
hooks: Vec<HookCreationDetails>,
6064
}
6165

6266
impl Default for ContractCreateTransactionData {
@@ -74,6 +78,7 @@ impl Default for ContractCreateTransactionData {
7478
auto_renew_account_id: None,
7579
staked_id: None,
7680
decline_staking_reward: false,
81+
hooks: Vec::new(),
7782
}
7883
}
7984
}
@@ -240,6 +245,24 @@ impl ContractCreateTransaction {
240245
self.data_mut().decline_staking_reward = decline;
241246
self
242247
}
248+
249+
/// Returns the hooks to be created.
250+
#[must_use]
251+
pub fn get_hooks_to_create(&self) -> &[HookCreationDetails] {
252+
&self.data().hooks
253+
}
254+
255+
/// Adds a hook to be created.
256+
pub fn add_hook(&mut self, hook: HookCreationDetails) -> &mut Self {
257+
self.data_mut().hooks.push(hook);
258+
self
259+
}
260+
261+
/// Sets the hooks to be created.
262+
pub fn set_hooks(&mut self, hooks: Vec<HookCreationDetails>) -> &mut Self {
263+
self.data_mut().hooks = hooks;
264+
self
265+
}
243266
}
244267

245268
impl TransactionData for ContractCreateTransactionData {
@@ -313,6 +336,11 @@ impl FromProtobuf<services::ContractCreateTransactionBody> for ContractCreateTra
313336
auto_renew_account_id: Option::from_protobuf(pb.auto_renew_account_id)?,
314337
staked_id: Option::from_protobuf(pb.staked_id)?,
315338
decline_staking_reward: pb.decline_reward,
339+
hooks: pb
340+
.hook_creation_details
341+
.into_iter()
342+
.map(HookCreationDetails::from_protobuf)
343+
.collect::<Result<Vec<_>, _>>()?,
316344
})
317345
}
318346
}
@@ -372,6 +400,7 @@ impl ToProtobuf for ContractCreateTransactionData {
372400
decline_reward: self.decline_staking_reward,
373401
initcode_source,
374402
staked_id,
403+
hook_creation_details: self.hooks.iter().map(|hook| hook.to_protobuf()).collect(),
375404
}
376405
}
377406
}
@@ -397,8 +426,13 @@ mod tests {
397426
AccountId,
398427
AnyTransaction,
399428
ContractCreateTransaction,
429+
ContractId,
430+
EvmHookSpec,
400431
FileId,
401432
Hbar,
433+
HookCreationDetails,
434+
HookExtensionPoint,
435+
LambdaEvmHook,
402436
PublicKey,
403437
};
404438

@@ -539,6 +573,7 @@ mod tests {
539573
},
540574
),
541575
decline_reward: false,
576+
hook_creation_details: [],
542577
initcode_source: Some(
543578
FileId(
544579
FileId {
@@ -665,6 +700,7 @@ mod tests {
665700
},
666701
),
667702
decline_reward: false,
703+
hook_creation_details: [],
668704
initcode_source: Some(
669705
Initcode(
670706
[
@@ -702,6 +738,13 @@ mod tests {
702738
#[test]
703739
fn from_proto_body() {
704740
#[allow(deprecated)]
741+
let contract_id = ContractId::new(0, 0, 1);
742+
let hooks = vec![HookCreationDetails::new(
743+
HookExtensionPoint::AccountAllowanceHook,
744+
0,
745+
Some(LambdaEvmHook::new(EvmHookSpec::new(Some(contract_id)), vec![])),
746+
)];
747+
705748
let tx = services::ContractCreateTransactionBody {
706749
admin_key: Some(admin_key().to_protobuf()),
707750
initial_balance: INITIAL_BALANCE.to_tinybars(),
@@ -724,6 +767,7 @@ mod tests {
724767
BYTECODE_FILE_ID.to_protobuf(),
725768
),
726769
),
770+
hook_creation_details: hooks.iter().map(|h| h.to_protobuf()).collect(),
727771
};
728772
let tx = ContractCreateTransactionData::from_protobuf(tx).unwrap();
729773

0 commit comments

Comments
 (0)