886 lines
31 KiB
Rust
886 lines
31 KiB
Rust
#![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<T> =
|
|
<<T as Config>::Currency as Inspect<<T as frame_system::Config>::AccountId>>::Balance;
|
|
|
|
#[derive(Default, Encode, Decode, Clone, PartialEq, Eq, RuntimeDebug, TypeInfo)]
|
|
pub struct NetworkImbalanceState<Balance> {
|
|
pub outgoing: Balance,
|
|
pub incoming: Balance,
|
|
pub curve_share: Balance,
|
|
}
|
|
|
|
pub struct BridgedInflationCurve<RewardCurve, T>(core::marker::PhantomData<(RewardCurve, T)>);
|
|
impl<Balance, RewardCurve, T> pallet_staking::EraPayout<Balance>
|
|
for BridgedInflationCurve<RewardCurve, T>
|
|
where
|
|
Balance: Default
|
|
+ Copy
|
|
+ From<BalanceOf<T>>
|
|
+ AtLeast32BitUnsigned
|
|
+ num_traits::ops::wrapping::WrappingAdd
|
|
+ num_traits::ops::overflowing::OverflowingAdd
|
|
+ sp_std::ops::AddAssign
|
|
+ sp_std::ops::Not<Output = Balance>
|
|
+ sp_std::ops::Shl<Output = Balance>
|
|
+ sp_std::ops::Shr<Output = Balance>
|
|
+ sp_std::ops::BitAnd<Balance, Output = Balance>,
|
|
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::<T>::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<Event<Self>> + IsType<<Self as frame_system::Config>::RuntimeEvent>;
|
|
|
|
/// The type used for the internal balance storage.
|
|
type Currency: Inspect<Self::AccountId>;
|
|
|
|
/// 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<Self::RuntimeOrigin>;
|
|
/// The origin required to update network information.
|
|
type UpdateOrigin: EnsureOrigin<Self::RuntimeOrigin>;
|
|
/// The origin required to remove network.
|
|
type RemoveOrigin: EnsureOrigin<Self::RuntimeOrigin>;
|
|
|
|
#[pallet::constant]
|
|
type MaxNetworks: Get<u32>;
|
|
|
|
/// Weight information for extrinsics in this module.
|
|
type WeightInfo: WeightInfo;
|
|
}
|
|
|
|
#[pallet::error]
|
|
pub enum Error<T> {
|
|
/// 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<T: Config> {
|
|
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<T: Config> = StorageValue<
|
|
_,
|
|
NetworkImbalanceState<BalanceOf<T>>,
|
|
ValueQuery,
|
|
>;
|
|
|
|
#[pallet::storage]
|
|
#[pallet::getter(fn network_indexes)]
|
|
pub type NetworkIndexes<T: Config> =
|
|
StorageValue<_, BoundedVec<T::NetworkId, T::MaxNetworks>, ValueQuery>;
|
|
|
|
#[pallet::storage]
|
|
#[pallet::getter(fn network_curves)]
|
|
pub type NetworkCurves<T: Config> = StorageMap<
|
|
_,
|
|
Twox64Concat, NetworkCurve,
|
|
BoundedBTreeMap<NetworkType, u32, T::MaxNetworks>,
|
|
ValueQuery,
|
|
>;
|
|
|
|
#[pallet::storage]
|
|
#[pallet::getter(fn network_curves_vec)]
|
|
pub type NetworkCurvesVec<T: Config> =
|
|
StorageValue<_, BoundedVec<NetworkCurve, T::MaxNetworks>, ValueQuery>;
|
|
|
|
#[pallet::storage]
|
|
#[pallet::getter(fn networks)]
|
|
pub type Networks<T: Config> = StorageMap<
|
|
_,
|
|
Twox64Concat, T::NetworkId,
|
|
NetworkData,
|
|
OptionQuery,
|
|
>;
|
|
|
|
#[pallet::storage]
|
|
#[pallet::getter(fn gatekeeper_amounts)]
|
|
pub type GatekeeperAmounts<T: Config> =
|
|
StorageMap<_, Twox64Concat, T::NetworkId, BalanceOf<T>, ValueQuery>;
|
|
|
|
#[pallet::genesis_config]
|
|
pub struct GenesisConfig<T: Config> {
|
|
pub networks: Vec<NetworkInitiation<T::NetworkId, BalanceOf<T>>>,
|
|
}
|
|
|
|
impl<T: Config> Default for GenesisConfig<T> {
|
|
fn default() -> Self {
|
|
Self { networks: sp_std::vec![] }
|
|
}
|
|
}
|
|
|
|
#[pallet::genesis_build]
|
|
impl<T: Config> BuildGenesisConfig for GenesisConfig<T> {
|
|
fn build(&self) {
|
|
self.networks
|
|
.iter()
|
|
.for_each(|network| {
|
|
Pallet::<T>::do_register_network(network.id, network.data.clone())
|
|
.expect("Error registering network");
|
|
GatekeeperAmounts::<T>::insert(network.id, network.amount);
|
|
});
|
|
|
|
}
|
|
}
|
|
|
|
#[pallet::pallet]
|
|
#[pallet::storage_version(STORAGE_VERSION)]
|
|
#[pallet::without_storage_info]
|
|
pub struct Pallet<T>(PhantomData<T>);
|
|
|
|
#[pallet::call]
|
|
impl<T: Config> Pallet<T> {
|
|
#[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<T>,
|
|
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<T>,
|
|
chain_id: T::NetworkId,
|
|
selector: BoundedVec<u8, ConstU32<MAX_SELECTOR_LEN>>,
|
|
) -> 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<T>,
|
|
chain_id: T::NetworkId,
|
|
maybe_index: Option<u32>,
|
|
maybe_endpoint: Option<BoundedVec<u8, ConstU32<MAX_ENDPOINT_LEN>>>,
|
|
) -> 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<T>,
|
|
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<T>,
|
|
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<T>,
|
|
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<T>,
|
|
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<T>,
|
|
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<T>,
|
|
chain_id: T::NetworkId,
|
|
gatekeeper: BoundedVec<u8, ConstU32<MAX_GATEKEEPER_LEN>>,
|
|
) -> 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<T>,
|
|
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<T>,
|
|
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<T>, 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<T>,
|
|
chain_id: T::NetworkId,
|
|
decimals: u8,
|
|
) -> DispatchResult {
|
|
T::UpdateOrigin::ensure_origin_or_root(origin)?;
|
|
Self::do_update_network_decimals(chain_id, decimals)
|
|
}
|
|
}
|
|
}
|
|
|
|
impl<T: Config> Pallet<T> {
|
|
/// 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::<T>::contains_key(&chain_id),
|
|
Error::<T>::NetworkAlreadyRegistered,
|
|
);
|
|
|
|
let mut modified_indexes = NetworkIndexes::<T>::get();
|
|
modified_indexes.try_push(chain_id.clone())
|
|
.map_err(|_| Error::<T>::TooManyNetworks)?;
|
|
|
|
let mut modified_curves_map = NetworkCurves::<T>::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::<T>::TooManyNetworks)?;
|
|
}
|
|
|
|
let mut modified_curves_vec = NetworkCurvesVec::<T>::get();
|
|
if !modified_curves_vec.contains(&network_curve) {
|
|
modified_curves_vec.try_push(network_curve)
|
|
.map_err(|_| Error::<T>::TooManyNetworks)?;
|
|
}
|
|
|
|
Networks::<T>::insert(&chain_id, network);
|
|
NetworkIndexes::<T>::put(modified_indexes);
|
|
NetworkCurves::<T>::insert(network_curve, modified_curves_map);
|
|
NetworkCurvesVec::<T>::put(modified_curves_vec);
|
|
|
|
Self::deposit_event(Event::<T>::NetworkRegistered { chain_id });
|
|
Ok(())
|
|
}
|
|
|
|
/// Remove existent network.
|
|
pub fn do_remove_network(chain_id: T::NetworkId) -> DispatchResult {
|
|
let network = Networks::<T>::get(&chain_id)
|
|
.ok_or(Error::<T>::NetworkDoesNotExist)?;
|
|
|
|
let network_curve = network.curve;
|
|
let network_type = network.r#type;
|
|
|
|
let mut modified_curves_map = NetworkCurves::<T>::get(network_curve);
|
|
|
|
let counter = modified_curves_map
|
|
.get_mut(&network_type)
|
|
.ok_or(Error::<T>::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::<T>::get();
|
|
modified_indexes.retain(|id| id != &chain_id);
|
|
|
|
let mut modified_curves_vec = NetworkCurvesVec::<T>::get();
|
|
if should_remove_curve_from_vec {
|
|
modified_curves_vec.retain(|curve| curve != &network_curve);
|
|
}
|
|
|
|
Networks::<T>::remove(&chain_id);
|
|
NetworkIndexes::<T>::put(modified_indexes);
|
|
NetworkCurvesVec::<T>::put(modified_curves_vec);
|
|
|
|
if modified_curves_map.is_empty() {
|
|
NetworkCurves::<T>::remove(network_curve);
|
|
} else {
|
|
NetworkCurves::<T>::insert(network_curve, modified_curves_map);
|
|
}
|
|
|
|
Self::deposit_event(Event::<T>::NetworkRemoved { chain_id });
|
|
Ok(())
|
|
}
|
|
|
|
/// Update existent network name.
|
|
pub fn do_update_nework_selector(
|
|
chain_id: T::NetworkId,
|
|
selector: BoundedVec<u8, ConstU32<MAX_SELECTOR_LEN>>,
|
|
) -> DispatchResult {
|
|
Networks::<T>::try_mutate(&chain_id, |maybe_network| -> DispatchResult {
|
|
ensure!(selector.len() == 4, Error::<T>::InvalidSelectorLen);
|
|
let network = maybe_network.as_mut().ok_or(Error::<T>::NetworkDoesNotExist)?;
|
|
network.selector = selector;
|
|
Ok(())
|
|
})?;
|
|
|
|
Self::deposit_event(Event::<T>::NetworkSelectorUpdated { chain_id });
|
|
|
|
Ok(())
|
|
}
|
|
|
|
/// Update existent network default endpoint.
|
|
pub fn do_update_network_endpoint(
|
|
chain_id: T::NetworkId,
|
|
maybe_index: Option<u32>,
|
|
maybe_endpoint: Option<BoundedVec<u8, ConstU32<MAX_ENDPOINT_LEN>>>,
|
|
) -> DispatchResult {
|
|
Networks::<T>::try_mutate(&chain_id, |maybe_network| -> DispatchResult {
|
|
let network = maybe_network.as_mut().ok_or(Error::<T>::NetworkDoesNotExist)?;
|
|
match (maybe_index, maybe_endpoint) {
|
|
(Some(index), Some(endpoint)) => {
|
|
let idx = index as usize;
|
|
ensure!(idx < network.default_endpoints.len(), Error::<T>::IndexOutOfBounds);
|
|
let _ = core::mem::replace(&mut network.default_endpoints[idx], endpoint);
|
|
Self::deposit_event(Event::<T>::NetworkEndpointUpdated { chain_id, index });
|
|
}
|
|
(None, Some(endpoint)) => {
|
|
network.default_endpoints.try_push(endpoint).map_err(|_| Error::<T>::TooManyEndpoints)?;
|
|
Self::deposit_event(Event::<T>::NetworkEndpointAdded { chain_id });
|
|
}
|
|
(Some(index), None) => {
|
|
let idx = index as usize;
|
|
ensure!(idx < network.default_endpoints.len(), Error::<T>::IndexOutOfBounds);
|
|
network.default_endpoints.remove(idx);
|
|
Self::deposit_event(Event::<T>::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::<T>::try_mutate(&chain_id, |maybe_network| -> DispatchResult {
|
|
ensure!(maybe_network.is_some(), Error::<T>::NetworkDoesNotExist);
|
|
let net = maybe_network.as_mut().unwrap();
|
|
net.finality_delay = finality_delay;
|
|
*maybe_network = Some(net.clone());
|
|
Ok(())
|
|
})?;
|
|
Self::deposit_event(Event::<T>::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::<T>::try_mutate(&chain_id, |maybe_network| -> DispatchResult {
|
|
ensure!(maybe_network.is_some(), Error::<T>::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::<T>::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::<T>::try_mutate(&chain_id, |maybe_network| -> DispatchResult {
|
|
let network = maybe_network.as_mut().ok_or(Error::<T>::NetworkDoesNotExist)?;
|
|
network.block_deviation = block_deviation;
|
|
Ok(())
|
|
})?;
|
|
|
|
Self::deposit_event(Event::<T>::NetworkBlockDeviationUpdated {
|
|
chain_id,
|
|
block_deviation,
|
|
});
|
|
|
|
Ok(())
|
|
}
|
|
|
|
/// Update existent network decimals.
|
|
pub fn do_update_network_decimals(
|
|
chain_id: T::NetworkId,
|
|
decimals: u8,
|
|
) -> DispatchResult {
|
|
Networks::<T>::try_mutate(&chain_id, |maybe_network| -> DispatchResult {
|
|
let network = maybe_network.as_mut().ok_or(Error::<T>::NetworkDoesNotExist)?;
|
|
network.decimals = decimals;
|
|
Ok(())
|
|
})?;
|
|
Self::deposit_event(Event::<T>::NetworkDecimalsUpdated {
|
|
chain_id,
|
|
decimals,
|
|
});
|
|
Ok(())
|
|
}
|
|
|
|
/// Update existent network type.
|
|
pub fn do_update_network_type(
|
|
chain_id: T::NetworkId,
|
|
network_type: NetworkType,
|
|
) -> DispatchResult {
|
|
Networks::<T>::try_mutate(&chain_id, |maybe_network| -> DispatchResult {
|
|
let network = maybe_network.as_mut().ok_or(Error::<T>::NetworkDoesNotExist)?;
|
|
network.r#type = network_type;
|
|
Ok(())
|
|
})?;
|
|
Self::deposit_event(Event::<T>::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::<T>::get(&chain_id)
|
|
.ok_or(Error::<T>::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::<T>::get(prev_curve);
|
|
let counter = modified_prev_map
|
|
.get_mut(&network_type)
|
|
.ok_or(Error::<T>::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::<T>::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::<T>::TooManyNetworks)?;
|
|
}
|
|
|
|
let mut modified_curves_vec = NetworkCurvesVec::<T>::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::<T>::TooManyNetworks)?;
|
|
}
|
|
|
|
network.curve = network_curve;
|
|
|
|
Networks::<T>::insert(&chain_id, network);
|
|
NetworkCurves::<T>::insert(network_curve, modified_curr_map);
|
|
NetworkCurvesVec::<T>::put(modified_curves_vec);
|
|
|
|
if modified_prev_map.is_empty() {
|
|
NetworkCurves::<T>::remove(prev_curve);
|
|
} else {
|
|
NetworkCurves::<T>::insert(prev_curve, modified_prev_map);
|
|
}
|
|
|
|
Self::deposit_event(Event::<T>::NetworkCurveUpdated {
|
|
chain_id,
|
|
network_curve,
|
|
});
|
|
|
|
Ok(())
|
|
}
|
|
|
|
/// Update existent network gatekeeper.
|
|
pub fn do_update_network_gatekeeper(
|
|
chain_id: T::NetworkId,
|
|
gatekeeper: BoundedVec<u8, ConstU32<MAX_GATEKEEPER_LEN>>,
|
|
) -> DispatchResult {
|
|
Networks::<T>::try_mutate(&chain_id, |maybe_network| -> DispatchResult {
|
|
let network = maybe_network.as_mut().ok_or(Error::<T>::NetworkDoesNotExist)?;
|
|
network.gatekeeper = gatekeeper;
|
|
Ok(())
|
|
})?;
|
|
Self::deposit_event(Event::<T>::NetworkGatekeeperUpdated { chain_id });
|
|
Ok(())
|
|
}
|
|
|
|
pub fn do_update_incoming_network_share(
|
|
chain_id: T::NetworkId,
|
|
incoming_share: u32,
|
|
) -> DispatchResult {
|
|
Networks::<T>::try_mutate(&chain_id, |maybe_network| -> DispatchResult {
|
|
ensure!(maybe_network.is_some(), Error::<T>::NetworkDoesNotExist);
|
|
let net = maybe_network.as_mut().unwrap();
|
|
net.incoming_share = incoming_share;
|
|
*maybe_network = Some(net.clone());
|
|
Ok(())
|
|
})?;
|
|
Self::deposit_event(Event::<T>::NetworkIncomingShareUpdated {
|
|
chain_id,
|
|
incoming_share,
|
|
});
|
|
Ok(())
|
|
}
|
|
|
|
pub fn do_update_outgoing_network_share(
|
|
chain_id: T::NetworkId,
|
|
outgoing_share: u32,
|
|
) -> DispatchResult {
|
|
Networks::<T>::try_mutate(&chain_id, |maybe_network| -> DispatchResult {
|
|
ensure!(maybe_network.is_some(), Error::<T>::NetworkDoesNotExist);
|
|
let net = maybe_network.as_mut().unwrap();
|
|
net.outgoing_share = outgoing_share;
|
|
*maybe_network = Some(net.clone());
|
|
Ok(())
|
|
})?;
|
|
Self::deposit_event(Event::<T>::NetworkOutgoingShareUpdated {
|
|
chain_id,
|
|
outgoing_share,
|
|
});
|
|
Ok(())
|
|
}
|
|
}
|
|
|
|
impl<T: Config> NetworkDataBasicHandler for Pallet<T> {
|
|
type NetworkId = T::NetworkId;
|
|
type NetworkType = NetworkType;
|
|
type NetworkCurve = NetworkCurve;
|
|
}
|
|
|
|
impl<T: Config> NetworkDataInspectHandler<NetworkData> for Pallet<T> {
|
|
fn count() -> u32 {
|
|
NetworkIndexes::<T>::decode_len()
|
|
.map(|len| len as u32)
|
|
.unwrap_or_default()
|
|
}
|
|
|
|
fn contains_key(n: &Self::NetworkId) -> bool {
|
|
Networks::<T>::contains_key(n)
|
|
}
|
|
|
|
fn curve_exists(curve: &Self::NetworkCurve) -> bool {
|
|
NetworkCurves::<T>::contains_key(curve)
|
|
}
|
|
|
|
fn get(n: &Self::NetworkId) -> Option<NetworkData> {
|
|
Networks::<T>::get(n)
|
|
}
|
|
|
|
fn network_for_block(block_number: impl Into<usize>) -> Option<(Self::NetworkId, NetworkData)> {
|
|
let network_indexes = NetworkIndexes::<T>::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::<T>::iter()
|
|
}
|
|
|
|
fn iter_indexes() -> impl Iterator<Item = Self::NetworkId> {
|
|
NetworkIndexes::<T>::get().into_iter()
|
|
}
|
|
|
|
fn iter_curves() -> impl Iterator<Item = Self::NetworkCurve> {
|
|
NetworkCurvesVec::<T>::get().into_iter()
|
|
}
|
|
|
|
fn iter_types_by_curve(
|
|
curve: &Self::NetworkCurve
|
|
) -> impl Iterator<Item = Self::NetworkType> {
|
|
NetworkCurves::<T>::get(curve)
|
|
.into_iter()
|
|
.map(|(network_type, _)| network_type)
|
|
}
|
|
}
|
|
|
|
impl<T: Config> NetworkDataMutateHandler<NetworkData, BalanceOf<T>> for Pallet<T> {
|
|
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<T>,
|
|
) -> Result<BalanceOf<T>, ()> {
|
|
let incoming_share = Networks::<T>::get(&network_id)
|
|
.map(|network| network.incoming_share)
|
|
.ok_or(())?;
|
|
|
|
GatekeeperAmounts::<T>::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::<T>::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<T>
|
|
) -> Result<BalanceOf<T>, ()> {
|
|
let outgoing_share = Networks::<T>::get(&network_id)
|
|
.map(|network| network.outgoing_share)
|
|
.ok_or(())?;
|
|
|
|
GatekeeperAmounts::<T>::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::<T>::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)
|
|
}
|
|
}
|