pallet_partner_chains_bridge/
lib.rs1#![cfg_attr(not(feature = "std"), no_std)]
3#![deny(missing_docs)]
4
5extern crate alloc;
6
7#[cfg(test)]
8mod tests;
9
10#[cfg(test)]
11mod mock;
12
13#[cfg(feature = "runtime-benchmarks")]
15pub mod benchmarking;
16
17pub mod weights;
19
20pub use pallet::*;
21use sp_partner_chains_bridge::BridgeTransferV1;
22
23pub trait TransferHandler<Recipient> {
30 fn handle_incoming_transfer(_transfer: BridgeTransferV1<Recipient>);
32}
33
34impl<Recipient> TransferHandler<Recipient> for () {
36 fn handle_incoming_transfer(_transfer: BridgeTransferV1<Recipient>) {}
37}
38
39#[frame_support::pallet(dev_mode)]
40pub mod pallet {
41 use super::*;
42 use frame_support::pallet_prelude::*;
43 use frame_system::{ensure_none, pallet_prelude::OriginFor};
44 use parity_scale_codec::MaxEncodedLen;
45 use sp_partner_chains_bridge::{BridgeDataCheckpoint, TokenBridgeTransfersV1};
46 use sp_partner_chains_bridge::{INHERENT_IDENTIFIER, InherentError, MainChainScripts};
47
48 pub const PALLET_VERSION: u32 = 1;
50
51 #[pallet::pallet]
52 pub struct Pallet<T>(_);
53
54 #[pallet::config]
55 pub trait Config: frame_system::Config {
56 type GovernanceOrigin: EnsureOrigin<Self::RuntimeOrigin>;
60
61 type Recipient: Member + Parameter + MaxEncodedLen;
63
64 type TransferHandler: TransferHandler<Self::Recipient>;
66
67 type MaxTransfersPerBlock: Get<u32>;
69
70 type WeightInfo: crate::weights::WeightInfo;
72
73 #[cfg(feature = "runtime-benchmarks")]
75 type BenchmarkHelper: benchmarking::BenchmarkHelper<Self>;
76 }
77
78 #[pallet::error]
80 pub enum Error<T> {}
81
82 #[pallet::storage]
83 pub type MainChainScriptsConfiguration<T: Config> =
84 StorageValue<_, MainChainScripts, OptionQuery>;
85
86 #[pallet::storage]
87 pub type DataCheckpoint<T: Config> = StorageValue<_, BridgeDataCheckpoint, OptionQuery>;
88
89 #[pallet::genesis_config]
91 pub struct GenesisConfig<T: Config> {
92 pub main_chain_scripts: Option<MainChainScripts>,
94 #[allow(missing_docs)]
95 pub _marker: PhantomData<T>,
96 }
97
98 impl<T: Config> Default for GenesisConfig<T> {
99 fn default() -> Self {
100 Self { main_chain_scripts: None, _marker: Default::default() }
101 }
102 }
103
104 #[pallet::genesis_build]
105 impl<T: Config> BuildGenesisConfig for GenesisConfig<T> {
106 fn build(&self) {
107 MainChainScriptsConfiguration::<T>::set(self.main_chain_scripts.clone());
108 }
109 }
110
111 #[pallet::call]
112 impl<T: Config> Pallet<T> {
113 #[pallet::call_index(0)]
115 #[pallet::weight(0)]
116 pub fn handle_transfers(
117 origin: OriginFor<T>,
118 transfers: BoundedVec<BridgeTransferV1<T::Recipient>, T::MaxTransfersPerBlock>,
119 data_checkpoint: BridgeDataCheckpoint,
120 ) -> DispatchResult {
121 ensure_none(origin)?;
122 for transfer in transfers {
123 T::TransferHandler::handle_incoming_transfer(transfer);
124 }
125 DataCheckpoint::<T>::put(data_checkpoint);
126 Ok(())
127 }
128
129 #[pallet::call_index(1)]
135 #[pallet::weight(0)]
136 pub fn set_main_chain_scripts(
137 origin: OriginFor<T>,
138 new_scripts: MainChainScripts,
139 data_checkpoint: BridgeDataCheckpoint,
140 ) -> DispatchResult {
141 T::GovernanceOrigin::ensure_origin(origin)?;
142 MainChainScriptsConfiguration::<T>::put(new_scripts);
143 DataCheckpoint::<T>::put(data_checkpoint);
144 Ok(())
145 }
146 }
147
148 #[pallet::inherent]
149 impl<T: Config> ProvideInherent for Pallet<T> {
150 type Call = Call<T>;
151 type Error = InherentError;
152 const INHERENT_IDENTIFIER: InherentIdentifier = INHERENT_IDENTIFIER;
153
154 fn create_inherent(data: &InherentData) -> Option<Self::Call> {
155 let data = Self::decode_inherent_data(data)?;
156 let transfers = data.transfers.try_into().expect(
157 "The number of transfers in the inherent data must be within configured bounds",
158 );
159 Some(Call::handle_transfers { transfers, data_checkpoint: data.data_checkpoint })
160 }
161
162 fn check_inherent(call: &Self::Call, data: &InherentData) -> Result<(), Self::Error> {
163 let Some(expected_call) = Self::create_inherent(data) else {
164 return Err(Self::Error::InherentNotExpected);
165 };
166
167 if *call != expected_call {
168 return Err(Self::Error::IncorrectInherent);
169 }
170
171 Ok(())
172 }
173
174 fn is_inherent(call: &Self::Call) -> bool {
175 matches!(call, Call::handle_transfers { .. })
176 }
177
178 fn is_inherent_required(data: &InherentData) -> Result<Option<Self::Error>, Self::Error> {
179 match Self::decode_inherent_data(data) {
180 None => Ok(None),
181 Some(_) => Ok(Some(Self::Error::InherentRequired)),
182 }
183 }
184 }
185
186 impl<T: Config> Pallet<T> {
187 fn decode_inherent_data(
188 data: &InherentData,
189 ) -> Option<TokenBridgeTransfersV1<T::Recipient>> {
190 data.get_data(&INHERENT_IDENTIFIER)
191 .expect("Bridge inherent data is not encoded correctly")
192 }
193 }
194
195 impl<T: Config> Pallet<T> {
196 pub fn get_pallet_version() -> u32 {
198 PALLET_VERSION
199 }
200
201 pub fn get_main_chain_scripts() -> Option<MainChainScripts> {
203 MainChainScriptsConfiguration::<T>::get()
204 }
205
206 pub fn get_max_transfers_per_block() -> u32 {
208 T::MaxTransfersPerBlock::get()
209 }
210
211 pub fn get_data_checkpoint() -> Option<BridgeDataCheckpoint> {
213 DataCheckpoint::<T>::get()
214 }
215 }
216}