Skip to main content

hiero_sdk/hooks/
hook_store_transaction.rs

1use hiero_sdk_proto::services;
2use hiero_sdk_proto::services::smart_contract_service_client::SmartContractServiceClient;
3use tonic::transport::Channel;
4
5use crate::hooks::{
6    EvmHookStorageUpdate,
7    HookId,
8};
9use crate::ledger_id::RefLedgerId;
10use crate::protobuf::ToProtobuf;
11use crate::transaction::{
12    ChunkInfo,
13    ToTransactionDataProtobuf,
14    Transaction,
15    TransactionData,
16    TransactionExecute,
17};
18use crate::{
19    BoxGrpcFuture,
20    ValidateChecksums,
21};
22
23/// A transaction to store lambda data in hook storage.
24pub type HookStoreTransaction = Transaction<HookStoreTransactionData>;
25
26#[derive(Debug, Clone, PartialEq, Eq)]
27pub struct HookStoreTransactionData {
28    /// The hook ID to store data for.
29    hook_id: Option<HookId>,
30    /// The storage updates to apply.
31    storage_updates: Vec<EvmHookStorageUpdate>,
32}
33
34impl Default for HookStoreTransactionData {
35    fn default() -> Self {
36        Self { hook_id: None, storage_updates: Vec::new() }
37    }
38}
39
40impl HookStoreTransaction {
41    /// Set the hook ID.
42    pub fn set_hook_id(&mut self, hook_id: HookId) -> &mut Self {
43        self.data_mut().hook_id = Some(hook_id);
44        self
45    }
46
47    /// Set the storage updates.
48    pub fn set_storage_updates(&mut self, storage_updates: Vec<EvmHookStorageUpdate>) -> &mut Self {
49        self.data_mut().storage_updates = storage_updates;
50        self
51    }
52
53    /// Add a storage update.
54    pub fn add_storage_update(&mut self, storage_update: EvmHookStorageUpdate) -> &mut Self {
55        self.data_mut().storage_updates.push(storage_update);
56        self
57    }
58
59    /// Get the hook ID.
60    pub fn get_hook_id(&self) -> Option<&HookId> {
61        self.data().hook_id.as_ref()
62    }
63
64    /// Get the storage updates.
65    pub fn get_storage_updates(&self) -> &[EvmHookStorageUpdate] {
66        &self.data().storage_updates
67    }
68}
69
70impl HookStoreTransactionData {
71    /// Create a new `HookStoreTransactionData`.
72    pub fn new() -> Self {
73        Self::default()
74    }
75}
76
77impl TransactionData for HookStoreTransactionData {
78    // 2 habrs are the default max transaction fee for most transaction acrooss the SDK
79    fn default_max_transaction_fee(&self) -> crate::Hbar {
80        crate::Hbar::new(2)
81    }
82}
83
84impl ValidateChecksums for HookStoreTransactionData {
85    fn validate_checksums(&self, ledger_id: &RefLedgerId) -> Result<(), crate::Error> {
86        if let Some(hook_id) = &self.hook_id {
87            hook_id.entity_id.validate_checksums(ledger_id)?;
88        }
89        Ok(())
90    }
91}
92
93impl TransactionExecute for HookStoreTransactionData {
94    fn execute(
95        &self,
96        channel: Channel,
97        request: services::Transaction,
98    ) -> BoxGrpcFuture<'_, services::TransactionResponse> {
99        Box::pin(async { SmartContractServiceClient::new(channel).hook_store(request).await })
100    }
101}
102
103impl ToTransactionDataProtobuf for HookStoreTransactionData {
104    fn to_transaction_data_protobuf(
105        &self,
106        chunk_info: &ChunkInfo,
107    ) -> services::transaction_body::Data {
108        let _ = chunk_info.assert_single_transaction();
109        services::transaction_body::Data::HookStore(self.to_protobuf())
110    }
111}
112
113impl crate::protobuf::ToProtobuf for HookStoreTransactionData {
114    type Protobuf = services::HookStoreTransactionBody;
115
116    fn to_protobuf(&self) -> Self::Protobuf {
117        services::HookStoreTransactionBody {
118            hook_id: self.hook_id.as_ref().map(|id| id.to_protobuf()),
119            storage_updates: self
120                .storage_updates
121                .iter()
122                .map(|update| update.to_protobuf())
123                .collect(),
124        }
125    }
126}
127
128impl crate::protobuf::FromProtobuf<services::HookStoreTransactionBody>
129    for HookStoreTransactionData
130{
131    fn from_protobuf(pb: services::HookStoreTransactionBody) -> crate::Result<Self> {
132        let hook_id = pb.hook_id.map(HookId::from_protobuf).transpose()?;
133
134        let storage_updates = pb
135            .storage_updates
136            .into_iter()
137            .map(EvmHookStorageUpdate::from_protobuf)
138            .collect::<Result<Vec<_>, _>>()?;
139
140        Ok(Self { hook_id, storage_updates })
141    }
142}
143
144impl From<HookStoreTransactionData> for crate::transaction::AnyTransactionData {
145    fn from(transaction: HookStoreTransactionData) -> Self {
146        Self::HookStore(transaction)
147    }
148}
149
150#[cfg(test)]
151mod tests {
152    use super::*;
153    use crate::hooks::{
154        EvmHookStorageSlot,
155        EvmHookStorageUpdate,
156        HookId,
157    };
158
159    #[test]
160    fn test_hook_store_transaction_creation() {
161        let hook_id = HookId::new(None, 123);
162        let storage_slot = EvmHookStorageSlot::new(vec![1, 2, 3], vec![4, 5, 6]);
163        let storage_update = EvmHookStorageUpdate::StorageSlot(storage_slot);
164
165        let mut transaction = HookStoreTransaction::new();
166        transaction.set_hook_id(hook_id.clone()).add_storage_update(storage_update);
167
168        assert_eq!(transaction.get_hook_id(), Some(&hook_id));
169        assert_eq!(transaction.get_storage_updates().len(), 1);
170    }
171
172    #[test]
173    fn test_hook_store_transaction_default() {
174        let transaction = HookStoreTransaction::new();
175        assert_eq!(transaction.get_hook_id(), None);
176        assert_eq!(transaction.get_storage_updates().len(), 0);
177    }
178}