#![cfg_attr(not(feature = "std"), no_std)] #![allow(clippy::large_enum_variant)] #![allow(clippy::too_many_arguments)] use frame_support::{ pallet_prelude::*, storage::PrefixIterator, traits::EnsureOrigin, }; use frame_system::pallet_prelude::*; use scale_info::TypeInfo; use sp_runtime::{ traits::{AtLeast32BitUnsigned, Member}, DispatchResult, }; use sp_std::prelude::*; pub use ghost_traits::networks::{ NetworkDataBasicHandler, NetworkDataInspectHandler, NetworkDataMutateHandler, }; mod weights; pub use module::*; pub use crate::weights::WeightInfo; #[cfg(any(feature = "runtime-benchmarks", test))] mod benchmarking; #[cfg(all(feature = "std", test))] mod mock; #[cfg(all(feature = "std", test))] mod tests; #[derive(Encode, Decode, Clone, PartialEq, Eq, RuntimeDebug, TypeInfo)] pub enum NetworkType { Evm = 0, Utxo = 1, Undefined = 2, } impl Default for NetworkType { fn default() -> Self { NetworkType::Evm } } #[derive(Encode, Decode, Clone, PartialEq, Eq, RuntimeDebug, TypeInfo)] pub struct NetworkData { pub chain_name: Vec, pub default_endpoint: Vec, pub gatekeeper: Vec, pub topic_name: Vec, pub finality_delay: Option, pub release_delay: Option, pub network_type: NetworkType, pub incoming_fee: u32, pub outgoing_fee: u32, } #[frame_support::pallet] pub mod module { use super::*; #[pallet::config] pub trait Config: frame_system::Config { type RuntimeEvent: From> + IsType<::RuntimeEvent>; /// The type used as a unique network id. type NetworkId: Parameter + Member + Parameter + AtLeast32BitUnsigned + Default + Copy + Ord + TypeInfo + MaybeSerializeDeserialize + MaxEncodedLen; /// The origin required to register new network. type RegisterOrigin: EnsureOrigin; /// The origin required to update network information. type UpdateOrigin: EnsureOrigin; /// The origin required to remove network. type RemoveOrigin: EnsureOrigin; /// Weight information for extrinsics in this module. type WeightInfo: WeightInfo; } #[pallet::error] pub enum Error { /// Network already registered. NetworkAlreadyRegistered, /// Network does not exist. NetworkDoesNotExist, /// Gatekeeper address length not 42 or prefix `0x` missed. WrongGatekeeperAddress, /// Topic name length not 66 or prefix `0x` missed. WrongTopicName, } #[pallet::event] #[pallet::generate_deposit(pub(crate) fn deposit_event)] pub enum Event { NetworkRegistered { chain_id: T::NetworkId, network: NetworkData }, NetworkNameUpdated { chain_id: T::NetworkId, chain_name: Vec }, NetworkEndpointUpdated { chain_id: T::NetworkId, default_endpoint: Vec }, NetworkFinalityDelayUpdated { chain_id: T::NetworkId, finality_delay: Option }, NetworkReleaseDelayUpdated { chain_id: T::NetworkId, release_delay: Option }, NetworkTypeUpdated { chain_id: T::NetworkId, network_type: NetworkType }, NetworkGatekeeperUpdated { chain_id: T::NetworkId, gatekeeper: Vec }, NetworkTopicNameUpdated { chain_id: T::NetworkId, topic_name: Vec }, NetworkIncomingFeeUpdated { chain_id: T::NetworkId, incoming_fee: u32 }, NetworkOutgoingFeeUpdated { chain_id: T::NetworkId, outgoing_fee: u32 }, NetworkRemoved { chain_id: T::NetworkId }, } #[pallet::storage] #[pallet::getter(fn networks)] pub type Networks = StorageMap<_, Twox64Concat, T::NetworkId, NetworkData, OptionQuery>; #[pallet::genesis_config] pub struct GenesisConfig { pub networks: Vec<(T::NetworkId, Vec)>, } impl Default for GenesisConfig { fn default() -> Self { Self { networks: vec![] } } } #[pallet::genesis_build] impl BuildGenesisConfig for GenesisConfig { fn build(&self) { if !self.networks.is_empty() { self.networks.iter().for_each(|(chain_id, network_metadata)| { let network = NetworkData::decode(&mut &network_metadata[..]) .expect("Error decoding NetworkData"); Pallet::::do_register_network(chain_id.clone(), network) .expect("Error registering network"); }); } } } #[pallet::pallet] #[pallet::without_storage_info] pub struct Pallet(PhantomData); #[pallet::hooks] impl Hooks> for Pallet {} #[pallet::call] impl Pallet { #[pallet::call_index(0)] #[pallet::weight(T::WeightInfo::register_network( network.chain_name.len() as u32, network.default_endpoint.len() as u32, ))] pub fn register_network( origin: OriginFor, chain_id: T::NetworkId, network: NetworkData, ) -> DispatchResult { T::RegisterOrigin::ensure_origin_or_root(origin)?; Self::do_register_network(chain_id, network) } #[pallet::call_index(1)] #[pallet::weight(T::WeightInfo::update_network_name( chain_name.len() as u32, ))] pub fn update_network_name( origin: OriginFor, chain_id: T::NetworkId, chain_name: Vec, ) -> DispatchResult { T::UpdateOrigin::ensure_origin_or_root(origin)?; Self::do_update_network_name( chain_id, chain_name, ) } #[pallet::call_index(2)] #[pallet::weight(T::WeightInfo::update_network_endpoint( default_endpoint.len() as u32 ))] pub fn update_network_endpoint( origin: OriginFor, chain_id: T::NetworkId, default_endpoint: Vec, ) -> DispatchResult { T::UpdateOrigin::ensure_origin_or_root(origin)?; Self::do_update_network_endpoint( chain_id, default_endpoint, ) } #[pallet::call_index(3)] #[pallet::weight(T::WeightInfo::update_network_finality_delay())] pub fn update_network_finality_delay( origin: OriginFor, chain_id: T::NetworkId, finality_delay: Option, ) -> DispatchResult { T::UpdateOrigin::ensure_origin_or_root(origin)?; Self::do_update_network_finality_delay( chain_id, finality_delay, ) } #[pallet::call_index(4)] #[pallet::weight(T::WeightInfo::update_network_release_delay())] pub fn update_network_release_delay( origin: OriginFor, chain_id: T::NetworkId, release_delay: Option, ) -> DispatchResult { T::UpdateOrigin::ensure_origin_or_root(origin)?; Self::do_update_network_release_delay( chain_id, release_delay, ) } #[pallet::call_index(5)] #[pallet::weight(T::WeightInfo::update_network_type())] pub fn update_network_type( origin: OriginFor, chain_id: T::NetworkId, network_type: NetworkType, ) -> DispatchResult { T::UpdateOrigin::ensure_origin_or_root(origin)?; Self::do_update_network_type( chain_id, network_type, ) } #[pallet::call_index(6)] #[pallet::weight(T::WeightInfo::update_network_gatekeeper())] pub fn update_network_gatekeeper( origin: OriginFor, chain_id: T::NetworkId, gatekeeper: Vec, ) -> DispatchResult { T::UpdateOrigin::ensure_origin_or_root(origin)?; Self::do_update_network_gatekeeper( chain_id, gatekeeper, ) } #[pallet::call_index(7)] #[pallet::weight(T::WeightInfo::update_network_topic_name())] pub fn update_network_topic_name( origin: OriginFor, chain_id: T::NetworkId, topic_name: Vec, ) -> DispatchResult { T::UpdateOrigin::ensure_origin_or_root(origin)?; Self::do_update_network_topic_name( chain_id, topic_name, ) } #[pallet::call_index(8)] #[pallet::weight(T::WeightInfo::update_incoming_network_fee())] pub fn update_incoming_network_fee( origin: OriginFor, chain_id: T::NetworkId, incoming_fee: u32, ) -> DispatchResult { T::UpdateOrigin::ensure_origin_or_root(origin)?; Self::do_update_incoming_network_fee( chain_id, incoming_fee, ) } #[pallet::call_index(9)] #[pallet::weight(T::WeightInfo::update_outgoing_network_fee())] pub fn update_outgoing_network_fee( origin: OriginFor, chain_id: T::NetworkId, outgoing_fee: u32, ) -> DispatchResult { T::UpdateOrigin::ensure_origin_or_root(origin)?; Self::do_update_outgoing_network_fee( chain_id, outgoing_fee, ) } #[pallet::call_index(10)] #[pallet::weight(T::WeightInfo::remove_network())] pub fn remove_network( origin: OriginFor, chain_id: T::NetworkId, ) -> DispatchResult { T::RemoveOrigin::ensure_origin_or_root(origin)?; Self::do_remove_network(chain_id) } } } impl Pallet { /// Register a new network. pub fn do_register_network( chain_id: T::NetworkId, network: NetworkData, ) -> DispatchResult { Networks::::try_mutate(&chain_id, |maybe_network| -> DispatchResult { ensure!(maybe_network.is_none(), Error::::NetworkAlreadyRegistered); *maybe_network = Some(network.clone()); Ok(()) })?; Self::deposit_event(Event::::NetworkRegistered { chain_id, network }); Ok(()) } /// Remove existent network. pub fn do_remove_network(chain_id: T::NetworkId) -> DispatchResult { Networks::::try_mutate(&chain_id, |maybe_network| -> DispatchResult { ensure!(maybe_network.is_some(), Error::::NetworkDoesNotExist); *maybe_network = None; Ok(()) })?; Self::deposit_event(Event::::NetworkRemoved { chain_id }); Ok(()) } /// Update existent network name. pub fn do_update_network_name( chain_id: T::NetworkId, chain_name: Vec, ) -> DispatchResult { Networks::::try_mutate(&chain_id, |maybe_network| -> DispatchResult { ensure!(maybe_network.is_some(), Error::::NetworkDoesNotExist); let net = maybe_network.as_mut().unwrap(); net.chain_name = chain_name.clone(); *maybe_network = Some(net.clone()); Ok(()) })?; Self::deposit_event(Event::::NetworkNameUpdated { chain_id, chain_name, }); Ok(()) } /// Update existent network default endpoint. pub fn do_update_network_endpoint( chain_id: T::NetworkId, default_endpoint: Vec, ) -> DispatchResult { Networks::::try_mutate(&chain_id, |maybe_network| -> DispatchResult { ensure!(maybe_network.is_some(), Error::::NetworkDoesNotExist); let net = maybe_network.as_mut().unwrap(); net.default_endpoint = default_endpoint.clone(); *maybe_network = Some(net.clone()); Ok(()) })?; Self::deposit_event(Event::::NetworkEndpointUpdated { chain_id, default_endpoint, }); Ok(()) } /// Update existent network default endpoint. pub fn do_update_network_finality_delay( chain_id: T::NetworkId, finality_delay: Option, ) -> DispatchResult { Networks::::try_mutate(&chain_id, |maybe_network| -> DispatchResult { ensure!(maybe_network.is_some(), Error::::NetworkDoesNotExist); let net = maybe_network.as_mut().unwrap(); net.finality_delay = finality_delay; *maybe_network = Some(net.clone()); Ok(()) })?; Self::deposit_event(Event::::NetworkFinalityDelayUpdated { chain_id, finality_delay, }); Ok(()) } /// Update existent network default endpoint. pub fn do_update_network_release_delay( chain_id: T::NetworkId, release_delay: Option, ) -> DispatchResult { Networks::::try_mutate(&chain_id, |maybe_network| -> DispatchResult { ensure!(maybe_network.is_some(), Error::::NetworkDoesNotExist); let net = maybe_network.as_mut().unwrap(); net.release_delay = release_delay; *maybe_network = Some(net.clone()); Ok(()) })?; Self::deposit_event(Event::::NetworkReleaseDelayUpdated { chain_id, release_delay, }); Ok(()) } /// Update existent network type. pub fn do_update_network_type( chain_id: T::NetworkId, network_type: NetworkType, ) -> DispatchResult { Networks::::try_mutate(&chain_id, |maybe_network| -> DispatchResult { ensure!(maybe_network.is_some(), Error::::NetworkDoesNotExist); let net = maybe_network.as_mut().unwrap(); net.network_type = network_type.clone(); *maybe_network = Some(net.clone()); Ok(()) })?; Self::deposit_event(Event::::NetworkTypeUpdated { chain_id, network_type, }); Ok(()) } /// Update existent network gatekeeper. pub fn do_update_network_gatekeeper( chain_id: T::NetworkId, gatekeeper: Vec, ) -> DispatchResult { ensure!(gatekeeper.len() == 42 && gatekeeper[0] == 48 && gatekeeper[1] == 120, Error::::WrongGatekeeperAddress); Networks::::try_mutate(&chain_id, |maybe_network| -> DispatchResult { ensure!(maybe_network.is_some(), Error::::NetworkDoesNotExist); let net = maybe_network.as_mut().unwrap(); net.gatekeeper = gatekeeper.clone(); *maybe_network = Some(net.clone()); Ok(()) })?; Self::deposit_event(Event::::NetworkGatekeeperUpdated { chain_id, gatekeeper, }); Ok(()) } /// Update existent network gatekeeper's topic name. pub fn do_update_network_topic_name( chain_id: T::NetworkId, topic_name: Vec, ) -> DispatchResult { ensure!(topic_name.len() == 66 && topic_name[0] == 48 && topic_name[1] == 120, Error::::WrongTopicName); Networks::::try_mutate(&chain_id, |maybe_network| -> DispatchResult { ensure!(maybe_network.is_some(), Error::::NetworkDoesNotExist); let net = maybe_network.as_mut().unwrap(); net.topic_name = topic_name.clone(); *maybe_network = Some(net.clone()); Ok(()) })?; Self::deposit_event(Event::::NetworkTopicNameUpdated { chain_id, topic_name, }); Ok(()) } pub fn do_update_incoming_network_fee( chain_id: T::NetworkId, incoming_fee: u32, ) -> DispatchResult { Networks::::try_mutate(&chain_id, |maybe_network| -> DispatchResult { ensure!(maybe_network.is_some(), Error::::NetworkDoesNotExist); let net = maybe_network.as_mut().unwrap(); net.incoming_fee = incoming_fee.clone(); *maybe_network = Some(net.clone()); Ok(()) })?; Self::deposit_event(Event::::NetworkIncomingFeeUpdated { chain_id, incoming_fee, }); Ok(()) } pub fn do_update_outgoing_network_fee( chain_id: T::NetworkId, outgoing_fee: u32, ) -> DispatchResult { Networks::::try_mutate(&chain_id, |maybe_network| -> DispatchResult { ensure!(maybe_network.is_some(), Error::::NetworkDoesNotExist); let net = maybe_network.as_mut().unwrap(); net.outgoing_fee = outgoing_fee.clone(); *maybe_network = Some(net.clone()); Ok(()) })?; Self::deposit_event(Event::::NetworkOutgoingFeeUpdated { chain_id, outgoing_fee, }); Ok(()) } } impl NetworkDataBasicHandler for Pallet { type NetworkId = T::NetworkId; } impl NetworkDataInspectHandler for Pallet { fn get(n: &Self::NetworkId) -> Option { Networks::::get(n) } fn iter() -> PrefixIterator<(Self::NetworkId, NetworkData)> { Networks::::iter() } } impl NetworkDataMutateHandler for Pallet { fn register(chain_id: Self::NetworkId, network: NetworkData) -> DispatchResult { Self::do_register_network(chain_id, network) } fn remove(chain_id: Self::NetworkId) -> DispatchResult { Self::do_remove_network(chain_id) } }