pallet_hookpoints/
functions.rs

1// Copyright (C) Deep Ink Ventures GmbH
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15//! This module provides various utility functions to manage and operate on hook points within the system.
16//! These functions range from retrieving a registered callback for a given owner, executing a hook point,
17//! installing an ink! contract, to creating a new hook point.
18//!
19//! The primary purpose of this module is to act as a bridge between the core logic of the hook points
20//! and the external components like the ink! contracts. By offering a clear API with well-defined
21//! functions, it simplifies the interaction and management of hook points, making it easier for developers
22//! to integrate and extend functionalities.
23
24use codec::Decode;
25use frame_support::BoundedVec;
26use super::*;
27use frame_support::pallet_prelude::{DispatchError, Get};
28use pallet_contracts::{CollectEvents, DebugInfo, Determinism, Pallet as Contracts};
29use pallet_contracts_primitives::Code;
30use crate::builder::{ContractDeployment, HookPoint};
31
32impl<T: Config> Pallet<T> {
33    /// Retrieves the callback registered by a given owner for a specific callback name.
34    ///
35    /// This function first checks for a specific callback registered by the owner and, if not found,
36    /// falls back to the global callback registered by the owner.
37    ///
38    /// # Arguments
39    ///
40    /// * `owner` - The account id of the owner of the registered callback.
41    /// * `callback_name` - The name of the callback to be fetched.
42    pub fn get_callback(owner: &T::AccountId, callback_name: Vec<u8>) -> Option<T::AccountId> {
43        let call: BoundedVec<_, _> = callback_name.try_into().unwrap();
44        Pallet::<T>::specific_callbacks(owner, call)
45            .or_else(|| Pallet::<T>::callbacks(owner))
46    }
47
48    /// Executes the logic associated with a given hook point.
49    ///
50    /// This function is responsible for invoking the callback logic registered for a hook point.
51    ///
52    /// # Arguments
53    ///
54    /// * `hook_point` - A struct containing details about the hook point to be executed.
55    pub fn execute<R>(hook_point: HookPoint<T::AccountId>) -> Result<R, DispatchError>
56        where R: Decode
57    {
58        let callback = Pallet::<T>::get_callback(&hook_point.owner, hook_point.callback);
59        let contract = callback.ok_or(DispatchError::Other("no contract"))?;
60        let data = Contracts::<T>::bare_call(
61            hook_point.signer,
62            contract,
63            0_u32.into(),
64            T::BlockWeights::get().max_block,
65            Some(0_u32.into()),
66            hook_point.data,
67            DebugInfo::Skip,
68            CollectEvents::Skip,
69            Determinism::Enforced,
70        ).result?.data;
71        <Result<R, DispatchError>>::decode(&mut &data[..])
72            .map_err(|_| DispatchError::Other("decoding error"))
73            .unwrap()
74    }
75
76    /// Deploys an ink! contract into the runtime.
77    ///
78    /// This function handles the instantiation of an ink! contract, making it available for interaction.
79    ///
80    /// # Arguments
81    ///
82    /// * `contract_deployment`: An instance of the `ContractDeployment` struct containing all the necessary details for deployment.
83    pub fn install(contract_deployment: ContractDeployment<T::AccountId>) -> Result<T::AccountId, DispatchError> {
84        let ContractDeployment {
85            creator,
86            code,
87            init_args,
88            salt,
89            ..
90        } = contract_deployment;
91
92
93        let contract_instantiate_result = Contracts::<T>::bare_instantiate(
94            creator,
95            0_u32.into(),
96            T::BlockWeights::get().max_block,
97            Some(100_u32.into()),
98            Code::Upload(code),
99            init_args,
100            salt,
101            pallet_contracts::DebugInfo::Skip,
102            pallet_contracts::CollectEvents::Skip,
103        );
104        Ok(contract_instantiate_result.result?.account_id)
105    }
106
107    /// Initializes and returns a new hook point.
108    ///
109    /// This function creates a new hook point, which can be further customized and then executed.
110    ///
111    /// # Arguments
112    ///
113    /// * `callback` - The fully qualified name of the callback to be associated with the hook point.
114    /// * `owner` - The account id of the owner of the hook point.
115    /// * `origin` - The account id initiating the creation of the hook point.
116    pub fn create(callback: &str, owner: T::AccountId, origin: T::AccountId) -> HookPoint<T::AccountId> {
117        HookPoint::<T::AccountId>::new(callback, owner, origin)
118    }
119
120    /// Prepares the details for a new contract deployment.
121    ///
122    /// This function assists in creating a `ContractDeployment` instance by setting up the necessary data,
123    /// such as the selector derived from the given constructor. The created instance can then be further customized
124    /// with initial arguments using the `add_init_arg` method.
125    ///
126    /// # Arguments
127    ///
128    /// * `constructor` - A string representing the constructor identifier.
129    /// * `creator` - The account ID of the entity deploying the contract.
130    /// * `code` - The compiled wasm code of the ink! contract.
131    /// * `salt` - A unique salt to ensure the resulting contract address is unique.
132    ///
133    /// # Returns
134    ///
135    /// A new `ContractDeployment` instance.
136    pub fn prepare_deployment(constructor: &str, creator: T::AccountId, code: Vec<u8>, salt: Vec<u8>) -> ContractDeployment<T::AccountId> {
137        ContractDeployment::<T::AccountId>::new(constructor, creator, code, salt)
138    }
139}