#![cfg_attr(not(feature = "std"), no_std)] use frame_support::{ pallet_prelude::*, storage::PrefixIterator, traits::{tokens::fungible::Inspect, EnsureOrigin}, }; use frame_system::pallet_prelude::*; use scale_info::TypeInfo; use sp_runtime::{ curve::PiecewiseLinear, traits::{ AtLeast32BitUnsigned, CheckedAdd, CheckedSub, Member, Saturating, UniqueSaturatedInto, }, DispatchResult, Perbill, }; use sp_std::{convert::TryInto, prelude::*}; use ghost_traits::networks::{ NetworkDataBasicHandler, NetworkDataInspectHandler, NetworkDataMutateHandler, }; use ghost_helpers::networks::{ MAX_ENDPOINT_LEN, MAX_GATEKEEPER_LEN, MAX_SELECTOR_LEN, NetworkData, NetworkType, NetworkCurve, NetworkInitiation, }; mod weights; pub use crate::weights::WeightInfo; pub use module::*; #[cfg(any(feature = "runtime-benchmarks", test))] mod benchmarking; #[cfg(all(feature = "std", test))] mod mock; #[cfg(all(feature = "std", test))] mod tests; pub type BalanceOf = <::Currency as Inspect<::AccountId>>::Balance; #[derive(Default, Encode, Decode, Clone, PartialEq, Eq, RuntimeDebug, TypeInfo)] pub struct NetworkImbalanceState { pub outgoing: Balance, pub incoming: Balance, pub curve_share: Balance, } pub struct BridgedInflationCurve(core::marker::PhantomData<(RewardCurve, T)>); impl pallet_staking::EraPayout for BridgedInflationCurve where Balance: Default + Copy + From> + AtLeast32BitUnsigned + num_traits::ops::wrapping::WrappingAdd + num_traits::ops::overflowing::OverflowingAdd + sp_std::ops::AddAssign + sp_std::ops::Not + sp_std::ops::Shl + sp_std::ops::Shr + sp_std::ops::BitAnd, RewardCurve: Get<&'static PiecewiseLinear<'static>>, T: Config, { fn era_payout( total_staked: Balance, total_issuance: Balance, _era_duration_in_millis: u64, ) -> (Balance, Balance) { let reward_curve = RewardCurve::get(); let state = NetworkImbalance::::take(); let accumulated_commission: Balance = state.curve_share.into(); let adjusted_issuance: Balance = total_issuance .saturating_add(state.outgoing.into()) .saturating_sub(state.incoming.into()); let estimated_reward = reward_curve.calculate_for_fraction_times_denominator( total_staked, adjusted_issuance, ); let payout: Balance = sp_runtime::helpers_128bit::multiply_by_rational_with_rounding( estimated_reward.unique_saturated_into(), accumulated_commission.unique_saturated_into(), adjusted_issuance.unique_saturated_into(), sp_runtime::Rounding::NearestPrefUp, ) .map(|result| result.unique_saturated_into()) .unwrap_or_default(); let rest_payout = accumulated_commission.saturating_sub(payout); (payout, rest_payout) } } #[frame_support::pallet] pub mod module { use super::*; const STORAGE_VERSION: StorageVersion = StorageVersion::new(1); #[pallet::config] pub trait Config: frame_system::Config { type RuntimeEvent: From> + IsType<::RuntimeEvent>; /// The type used for the internal balance storage. type Currency: Inspect; /// 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; #[pallet::constant] type MaxNetworks: Get; /// 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, /// Could not store networks into bounded vector. TooManyNetworks, /// Selector length should always be 4. InvalidSelectorLen, /// Index is out of possible range. IndexOutOfBounds, /// No more default endpoints available to store. TooManyEndpoints, /// Network type does not exist under specified curve. NetworkTypeDoesNotExist, } #[pallet::event] #[pallet::generate_deposit(pub(crate) fn deposit_event)] pub enum Event { NetworkRegistered { chain_id: T::NetworkId }, NetworkSelectorUpdated { chain_id: T::NetworkId }, NetworkEndpointUpdated { index: u32, chain_id: T::NetworkId }, NetworkEndpointRemoved { index: u32, chain_id: T::NetworkId }, NetworkEndpointAdded { chain_id: T::NetworkId }, NetworkFinalityDelayUpdated { chain_id: T::NetworkId, finality_delay: u64 }, NetworkRateLimitDelayUpdated { chain_id: T::NetworkId, rate_limit_delay: u64 }, NetworkBlockDeviationUpdated { chain_id: T::NetworkId, block_deviation: u64 }, NetworkTypeUpdated { chain_id: T::NetworkId, network_type: NetworkType }, NetworkCurveUpdated { chain_id: T::NetworkId, network_curve: NetworkCurve }, NetworkDecimalsUpdated { chain_id: T::NetworkId, decimals: u8 }, NetworkGatekeeperUpdated { chain_id: T::NetworkId }, NetworkIncomingShareUpdated { chain_id: T::NetworkId, incoming_share: u32 }, NetworkOutgoingShareUpdated { chain_id: T::NetworkId, outgoing_share: u32 }, NetworkAvgBlockSpeedUpdated { chain_id: T::NetworkId, avg_block_speed: u64 }, NetworkRemoved { chain_id: T::NetworkId }, } #[pallet::storage] #[pallet::getter(fn network_imbalance)] pub type NetworkImbalance = StorageValue< _, NetworkImbalanceState>, ValueQuery, >; #[pallet::storage] #[pallet::getter(fn network_indexes)] pub type NetworkIndexes = StorageValue<_, BoundedVec, ValueQuery>; #[pallet::storage] #[pallet::getter(fn network_curves)] pub type NetworkCurves = StorageMap< _, Twox64Concat, NetworkCurve, BoundedBTreeMap, ValueQuery, >; #[pallet::storage] #[pallet::getter(fn network_curves_vec)] pub type NetworkCurvesVec = StorageValue<_, BoundedVec, ValueQuery>; #[pallet::storage] #[pallet::getter(fn networks)] pub type Networks = StorageMap< _, Twox64Concat, T::NetworkId, NetworkData, OptionQuery, >; #[pallet::storage] #[pallet::getter(fn gatekeeper_amounts)] pub type GatekeeperAmounts = StorageMap<_, Twox64Concat, T::NetworkId, BalanceOf, ValueQuery>; #[pallet::genesis_config] pub struct GenesisConfig { pub networks: Vec>>, } impl Default for GenesisConfig { fn default() -> Self { Self { networks: sp_std::vec![] } } } #[pallet::genesis_build] impl BuildGenesisConfig for GenesisConfig { fn build(&self) { self.networks .iter() .for_each(|network| { Pallet::::do_register_network(network.id, network.data.clone()) .expect("Error registering network"); GatekeeperAmounts::::insert(network.id, network.amount); }); } } #[pallet::pallet] #[pallet::storage_version(STORAGE_VERSION)] #[pallet::without_storage_info] pub struct Pallet(PhantomData); #[pallet::call] impl Pallet { #[pallet::call_index(0)] #[pallet::weight(T::WeightInfo::register_network( network.gatekeeper.len() as u32, network.selector.len() as u32, network.default_endpoints .iter() .map(|endpoint| endpoint.len()) .max() .unwrap_or_default() 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_selector())] pub fn update_network_selector( origin: OriginFor, chain_id: T::NetworkId, selector: BoundedVec>, ) -> DispatchResult { T::UpdateOrigin::ensure_origin_or_root(origin)?; Self::do_update_nework_selector(chain_id, selector) } #[pallet::call_index(2)] #[pallet::weight(T::WeightInfo::update_network_endpoint( maybe_endpoint .as_ref() .map(|endpoint| endpoint.len()) .unwrap_or_default() as u32 ))] pub fn update_network_endpoint( origin: OriginFor, chain_id: T::NetworkId, maybe_index: Option, maybe_endpoint: Option>>, ) -> DispatchResult { T::UpdateOrigin::ensure_origin_or_root(origin)?; Self::do_update_network_endpoint(chain_id, maybe_index, maybe_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: u64, ) -> 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_rate_limit_delay())] pub fn update_network_rate_limit_delay( origin: OriginFor, chain_id: T::NetworkId, rate_limit_delay: u64, ) -> DispatchResult { T::UpdateOrigin::ensure_origin_or_root(origin)?; Self::do_update_network_rate_limit_delay(chain_id, rate_limit_delay) } #[pallet::call_index(5)] #[pallet::weight(T::WeightInfo::update_network_block_deviation())] pub fn update_network_block_deviation( origin: OriginFor, chain_id: T::NetworkId, block_deviation: u64, ) -> DispatchResult { T::UpdateOrigin::ensure_origin_or_root(origin)?; Self::do_update_network_block_deviation(chain_id, block_deviation) } #[pallet::call_index(6)] #[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(7)] #[pallet::weight(T::WeightInfo::update_network_curve())] pub fn update_network_curve( origin: OriginFor, chain_id: T::NetworkId, network_curve: NetworkCurve, ) -> DispatchResult { T::UpdateOrigin::ensure_origin_or_root(origin)?; Self::do_update_network_curve(chain_id, network_curve) } #[pallet::call_index(8)] #[pallet::weight(T::WeightInfo::update_network_gatekeeper())] pub fn update_network_gatekeeper( origin: OriginFor, chain_id: T::NetworkId, gatekeeper: BoundedVec>, ) -> DispatchResult { T::UpdateOrigin::ensure_origin_or_root(origin)?; Self::do_update_network_gatekeeper(chain_id, gatekeeper) } #[pallet::call_index(9)] #[pallet::weight(T::WeightInfo::update_incoming_network_share())] pub fn update_incoming_network_share( origin: OriginFor, chain_id: T::NetworkId, incoming_share: u32, ) -> DispatchResult { T::UpdateOrigin::ensure_origin_or_root(origin)?; Self::do_update_incoming_network_share(chain_id, incoming_share) } #[pallet::call_index(10)] #[pallet::weight(T::WeightInfo::update_outgoing_network_share())] pub fn update_outgoing_network_share( origin: OriginFor, chain_id: T::NetworkId, outgoing_share: u32, ) -> DispatchResult { T::UpdateOrigin::ensure_origin_or_root(origin)?; Self::do_update_outgoing_network_share(chain_id, outgoing_share) } #[pallet::call_index(11)] #[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) } #[pallet::call_index(12)] #[pallet::weight(T::WeightInfo::update_network_decimals())] pub fn update_network_decimals( origin: OriginFor, chain_id: T::NetworkId, decimals: u8, ) -> DispatchResult { T::UpdateOrigin::ensure_origin_or_root(origin)?; Self::do_update_network_decimals(chain_id, decimals) } } } impl Pallet { /// Register a new network. pub fn do_register_network( chain_id: T::NetworkId, network: NetworkData, ) -> DispatchResult { let network_curve = network.curve; let network_type = network.r#type; ensure!( !Networks::::contains_key(&chain_id), Error::::NetworkAlreadyRegistered, ); let mut modified_indexes = NetworkIndexes::::get(); modified_indexes.try_push(chain_id.clone()) .map_err(|_| Error::::TooManyNetworks)?; let mut modified_curves_map = NetworkCurves::::get(network_curve); if let Some(counter) = modified_curves_map.get_mut(&network_type) { *counter = counter.saturating_add(1); } else { modified_curves_map.try_insert(network_type, 1u32) .map_err(|_| Error::::TooManyNetworks)?; } let mut modified_curves_vec = NetworkCurvesVec::::get(); if !modified_curves_vec.contains(&network_curve) { modified_curves_vec.try_push(network_curve) .map_err(|_| Error::::TooManyNetworks)?; } Networks::::insert(&chain_id, network); NetworkIndexes::::put(modified_indexes); NetworkCurves::::insert(network_curve, modified_curves_map); NetworkCurvesVec::::put(modified_curves_vec); Self::deposit_event(Event::::NetworkRegistered { chain_id }); Ok(()) } /// Remove existent network. pub fn do_remove_network(chain_id: T::NetworkId) -> DispatchResult { let network = Networks::::get(&chain_id) .ok_or(Error::::NetworkDoesNotExist)?; let network_curve = network.curve; let network_type = network.r#type; let mut modified_curves_map = NetworkCurves::::get(network_curve); let counter = modified_curves_map .get_mut(&network_type) .ok_or(Error::::NetworkTypeDoesNotExist)?; *counter = counter.saturating_sub(1); let mut should_remove_curve_from_vec = false; if *counter == 0 { modified_curves_map.remove(&network_type); if modified_curves_map.is_empty() { should_remove_curve_from_vec = true; } } let mut modified_indexes = NetworkIndexes::::get(); modified_indexes.retain(|id| id != &chain_id); let mut modified_curves_vec = NetworkCurvesVec::::get(); if should_remove_curve_from_vec { modified_curves_vec.retain(|curve| curve != &network_curve); } Networks::::remove(&chain_id); NetworkIndexes::::put(modified_indexes); NetworkCurvesVec::::put(modified_curves_vec); if modified_curves_map.is_empty() { NetworkCurves::::remove(network_curve); } else { NetworkCurves::::insert(network_curve, modified_curves_map); } Self::deposit_event(Event::::NetworkRemoved { chain_id }); Ok(()) } /// Update existent network name. pub fn do_update_nework_selector( chain_id: T::NetworkId, selector: BoundedVec>, ) -> DispatchResult { Networks::::try_mutate(&chain_id, |maybe_network| -> DispatchResult { ensure!(selector.len() == 4, Error::::InvalidSelectorLen); let network = maybe_network.as_mut().ok_or(Error::::NetworkDoesNotExist)?; network.selector = selector; Ok(()) })?; Self::deposit_event(Event::::NetworkSelectorUpdated { chain_id }); Ok(()) } /// Update existent network default endpoint. pub fn do_update_network_endpoint( chain_id: T::NetworkId, maybe_index: Option, maybe_endpoint: Option>>, ) -> DispatchResult { Networks::::try_mutate(&chain_id, |maybe_network| -> DispatchResult { let network = maybe_network.as_mut().ok_or(Error::::NetworkDoesNotExist)?; match (maybe_index, maybe_endpoint) { (Some(index), Some(endpoint)) => { let idx = index as usize; ensure!(idx < network.default_endpoints.len(), Error::::IndexOutOfBounds); let _ = core::mem::replace(&mut network.default_endpoints[idx], endpoint); Self::deposit_event(Event::::NetworkEndpointUpdated { chain_id, index }); } (None, Some(endpoint)) => { network.default_endpoints.try_push(endpoint).map_err(|_| Error::::TooManyEndpoints)?; Self::deposit_event(Event::::NetworkEndpointAdded { chain_id }); } (Some(index), None) => { let idx = index as usize; ensure!(idx < network.default_endpoints.len(), Error::::IndexOutOfBounds); network.default_endpoints.remove(idx); Self::deposit_event(Event::::NetworkEndpointRemoved { chain_id, index }); } (None, None) => {} } Ok(()) }) } /// Update existent network default finality delay. pub fn do_update_network_finality_delay( chain_id: T::NetworkId, finality_delay: u64, ) -> 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 rate limit delay. pub fn do_update_network_rate_limit_delay( chain_id: T::NetworkId, rate_limit_delay: u64, ) -> DispatchResult { Networks::::try_mutate(&chain_id, |maybe_network| -> DispatchResult { ensure!(maybe_network.is_some(), Error::::NetworkDoesNotExist); let net = maybe_network.as_mut().unwrap(); net.rate_limit_delay = rate_limit_delay; *maybe_network = Some(net.clone()); Ok(()) })?; Self::deposit_event(Event::::NetworkRateLimitDelayUpdated { chain_id, rate_limit_delay, }); Ok(()) } /// Update existent network default block deviation between blocks. pub fn do_update_network_block_deviation( chain_id: T::NetworkId, block_deviation: u64, ) -> DispatchResult { Networks::::try_mutate(&chain_id, |maybe_network| -> DispatchResult { let network = maybe_network.as_mut().ok_or(Error::::NetworkDoesNotExist)?; network.block_deviation = block_deviation; Ok(()) })?; Self::deposit_event(Event::::NetworkBlockDeviationUpdated { chain_id, block_deviation, }); Ok(()) } /// Update existent network decimals. pub fn do_update_network_decimals( chain_id: T::NetworkId, decimals: u8, ) -> DispatchResult { Networks::::try_mutate(&chain_id, |maybe_network| -> DispatchResult { let network = maybe_network.as_mut().ok_or(Error::::NetworkDoesNotExist)?; network.decimals = decimals; Ok(()) })?; Self::deposit_event(Event::::NetworkDecimalsUpdated { chain_id, decimals, }); 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 { let network = maybe_network.as_mut().ok_or(Error::::NetworkDoesNotExist)?; network.r#type = network_type; Ok(()) })?; Self::deposit_event(Event::::NetworkTypeUpdated { chain_id, network_type, }); Ok(()) } /// Update underlying network curve. pub fn do_update_network_curve( chain_id: T::NetworkId, network_curve: NetworkCurve, ) -> DispatchResult { let mut network = Networks::::get(&chain_id) .ok_or(Error::::NetworkDoesNotExist)?; let prev_curve = network.curve; let network_type = network.r#type; if prev_curve == network_curve { return Ok(()); } let mut modified_prev_map = NetworkCurves::::get(prev_curve); let counter = modified_prev_map .get_mut(&network_type) .ok_or(Error::::NetworkTypeDoesNotExist)?; *counter = counter.saturating_sub(1); let mut should_remove_prev_from_vec = false; if *counter == 0 { modified_prev_map.remove(&network_type); if modified_prev_map.is_empty() { should_remove_prev_from_vec = true; } } let mut modified_curr_map = NetworkCurves::::get(network_curve); if let Some(counter) = modified_curr_map.get_mut(&network_type) { *counter = counter.saturating_add(1); } else { modified_curr_map.try_insert(network_type, 1u32) .map_err(|_| Error::::TooManyNetworks)?; } let mut modified_curves_vec = NetworkCurvesVec::::get(); if should_remove_prev_from_vec { modified_curves_vec.retain(|curve| curve != &prev_curve); } if !modified_curves_vec.contains(&network_curve) { modified_curves_vec.try_push(network_curve) .map_err(|_| Error::::TooManyNetworks)?; } network.curve = network_curve; Networks::::insert(&chain_id, network); NetworkCurves::::insert(network_curve, modified_curr_map); NetworkCurvesVec::::put(modified_curves_vec); if modified_prev_map.is_empty() { NetworkCurves::::remove(prev_curve); } else { NetworkCurves::::insert(prev_curve, modified_prev_map); } Self::deposit_event(Event::::NetworkCurveUpdated { chain_id, network_curve, }); Ok(()) } /// Update existent network gatekeeper. pub fn do_update_network_gatekeeper( chain_id: T::NetworkId, gatekeeper: BoundedVec>, ) -> DispatchResult { Networks::::try_mutate(&chain_id, |maybe_network| -> DispatchResult { let network = maybe_network.as_mut().ok_or(Error::::NetworkDoesNotExist)?; network.gatekeeper = gatekeeper; Ok(()) })?; Self::deposit_event(Event::::NetworkGatekeeperUpdated { chain_id }); Ok(()) } pub fn do_update_incoming_network_share( chain_id: T::NetworkId, incoming_share: 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_share = incoming_share; *maybe_network = Some(net.clone()); Ok(()) })?; Self::deposit_event(Event::::NetworkIncomingShareUpdated { chain_id, incoming_share, }); Ok(()) } pub fn do_update_outgoing_network_share( chain_id: T::NetworkId, outgoing_share: 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_share = outgoing_share; *maybe_network = Some(net.clone()); Ok(()) })?; Self::deposit_event(Event::::NetworkOutgoingShareUpdated { chain_id, outgoing_share, }); Ok(()) } } impl NetworkDataBasicHandler for Pallet { type NetworkId = T::NetworkId; type NetworkType = NetworkType; type NetworkCurve = NetworkCurve; } impl NetworkDataInspectHandler for Pallet { fn count() -> u32 { NetworkIndexes::::decode_len() .map(|len| len as u32) .unwrap_or_default() } fn contains_key(n: &Self::NetworkId) -> bool { Networks::::contains_key(n) } fn curve_exists(curve: &Self::NetworkCurve) -> bool { NetworkCurves::::contains_key(curve) } fn get(n: &Self::NetworkId) -> Option { Networks::::get(n) } fn network_for_block(block_number: impl Into) -> Option<(Self::NetworkId, NetworkData)> { let network_indexes = NetworkIndexes::::get(); block_number .into() .checked_rem(network_indexes.len()) .map(|id| { network_indexes.get(id).copied().and_then(|network_id| { Self::get(&network_id).map(|network_data| (network_id, network_data)) }) }) .flatten() } fn iter() -> PrefixIterator<(Self::NetworkId, NetworkData)> { Networks::::iter() } fn iter_indexes() -> impl Iterator { NetworkIndexes::::get().into_iter() } fn iter_curves() -> impl Iterator { NetworkCurvesVec::::get().into_iter() } fn iter_types_by_curve( curve: &Self::NetworkCurve ) -> impl Iterator { NetworkCurves::::get(curve) .into_iter() .map(|(network_type, _)| network_type) } } 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) } fn register_incoming( network_id: &T::NetworkId, amount: BalanceOf, ) -> Result, ()> { let incoming_share = Networks::::get(&network_id) .map(|network| network.incoming_share) .ok_or(())?; GatekeeperAmounts::::try_mutate(network_id, |gatekeeper_amount| -> Result<(), ()> { *gatekeeper_amount = gatekeeper_amount.checked_add(&amount).ok_or(())?; Ok(()) })?; let curve_share = Perbill::from_parts(incoming_share).mul_ceil(amount); let final_amount = amount.saturating_sub(curve_share); NetworkImbalance::::try_mutate(|imbalance_state| -> Result<(), ()> { imbalance_state.incoming = imbalance_state.incoming .checked_add(&final_amount) .ok_or(())?; imbalance_state.curve_share = imbalance_state.curve_share .checked_add(&curve_share) .ok_or(())?; Ok(()) })?; Ok(final_amount) } fn register_outgoing( network_id: &T::NetworkId, amount: BalanceOf ) -> Result, ()> { let outgoing_share = Networks::::get(&network_id) .map(|network| network.outgoing_share) .ok_or(())?; GatekeeperAmounts::::try_mutate(network_id, |gatekeeper_amount| -> Result<(), ()> { *gatekeeper_amount = gatekeeper_amount.checked_sub(&amount).ok_or(())?; Ok(()) })?; let curve_share = Perbill::from_parts(outgoing_share).mul_ceil(amount); let final_amount = amount.saturating_sub(curve_share); NetworkImbalance::::try_mutate(|imbalance_state| -> Result<(), ()> { imbalance_state.outgoing = imbalance_state.outgoing .checked_add(&final_amount) .ok_or(())?; imbalance_state.curve_share = imbalance_state.curve_share .checked_add(&curve_share) .ok_or(())?; Ok(()) })?; Ok(final_amount) } }