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}