mirror of
https://github.com/serai-dex/serai.git
synced 2025-12-08 12:19:24 +00:00
Restore AllowMint to serai-validator-sets-pallet and reorganize TODOs
This commit is contained in:
@@ -1,6 +1,9 @@
|
|||||||
use borsh::{BorshSerialize, BorshDeserialize};
|
use borsh::{BorshSerialize, BorshDeserialize};
|
||||||
|
|
||||||
use serai_primitives::network_id::ExternalNetworkId;
|
use serai_primitives::{
|
||||||
|
network_id::ExternalNetworkId,
|
||||||
|
balance::{Amount, ExternalBalance},
|
||||||
|
};
|
||||||
|
|
||||||
/// An event from economic security.
|
/// An event from economic security.
|
||||||
#[derive(Clone, PartialEq, Eq, Debug, BorshSerialize, BorshDeserialize)]
|
#[derive(Clone, PartialEq, Eq, Debug, BorshSerialize, BorshDeserialize)]
|
||||||
@@ -14,7 +17,10 @@ pub enum Event {
|
|||||||
|
|
||||||
/// A trait representing access to the information on economic security.
|
/// A trait representing access to the information on economic security.
|
||||||
pub trait EconomicSecurity {
|
pub trait EconomicSecurity {
|
||||||
/// If am external network has _ever_ achieved economic security.
|
/// If an external network has _ever_ achieved economic security.
|
||||||
#[must_use]
|
#[must_use]
|
||||||
fn achieved_economic_security(network: ExternalNetworkId) -> bool;
|
fn achieved_economic_security(network: ExternalNetworkId) -> bool;
|
||||||
|
|
||||||
|
/// The security oracle's valuation of this balance in SRI.
|
||||||
|
fn sri_value(balance: ExternalBalance) -> Amount;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -46,7 +46,8 @@ mod pallet {
|
|||||||
};
|
};
|
||||||
|
|
||||||
use serai_core_pallet::Pallet as Core;
|
use serai_core_pallet::Pallet as Core;
|
||||||
use serai_coins_pallet::Pallet as Coins;
|
use serai_coins_pallet::AllowMint;
|
||||||
|
type Coins<T> = serai_coins_pallet::Pallet<T, serai_coins_pallet::CoinsInstance>;
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
@@ -274,88 +275,28 @@ mod pallet {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* TODO
|
/// The required amount of stake for a balance.
|
||||||
/// Decreases a validator's allocation to a set.
|
fn stake_requirement(balance: ExternalBalance) -> AmountRepr {
|
||||||
///
|
let value = T::EconomicSecurity::sri_value(balance).0;
|
||||||
/// Errors if the capacity provided by this allocation is in use.
|
// As 67% can misbehave, 67% of stake must be sufficient to secure this
|
||||||
///
|
let requirement = value.saturating_mul(3) / 2;
|
||||||
/// Errors if a partial decrease of allocation which puts the remaining allocation below the
|
// We add an additional margin of 20%
|
||||||
/// minimum requirement.
|
let margin = requirement / 5;
|
||||||
///
|
requirement.saturating_add(margin)
|
||||||
/// The capacity prior provided by the allocation is immediately removed, in order to ensure it
|
|
||||||
/// doesn't become used (preventing deallocation).
|
|
||||||
///
|
|
||||||
/// Returns if the amount is immediately eligible for deallocation.
|
|
||||||
fn decrease_allocation(
|
|
||||||
network: NetworkId,
|
|
||||||
account: T::AccountId,
|
|
||||||
amount: Amount,
|
|
||||||
) -> Result<bool, DispatchError> {
|
|
||||||
// Check it's safe to decrease this set's stake by this amount
|
|
||||||
if let NetworkId::External(n) = network {
|
|
||||||
let new_total_staked = Self::total_allocated_stake(NetworkId::from(n))
|
|
||||||
.unwrap()
|
|
||||||
.0
|
|
||||||
.checked_sub(amount.0)
|
|
||||||
.ok_or(Error::<T>::NotEnoughAllocated)?;
|
|
||||||
let required_stake = Self::required_stake_for_network(n);
|
|
||||||
if new_total_staked < required_stake {
|
|
||||||
Err(Error::<T>::DeallocationWouldRemoveEconomicSecurity)?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let decreased_key_shares =
|
|
||||||
(old_allocation / allocation_per_key_share) > (new_allocation / allocation_per_key_share);
|
|
||||||
|
|
||||||
// If this decreases the validator's key shares, error if the new set is unable to handle
|
|
||||||
// byzantine faults
|
|
||||||
let mut was_bft = None;
|
|
||||||
if decreased_key_shares {
|
|
||||||
was_bft = Some(Self::is_bft(network));
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(was_bft) = was_bft {
|
|
||||||
if was_bft && (!Self::is_bft(network)) {
|
|
||||||
Err(Error::<T>::DeallocationWouldRemoveFaultTolerance)?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Sessions::<T>::decrease_allocation(network, account, amount)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the required stake in terms SRI for a given `Balance`.
|
/// The required amount of stake for a network.
|
||||||
pub fn required_stake(balance: &ExternalBalance) -> SubstrateAmount {
|
fn network_stake_requirement(network: ExternalNetworkId) -> AmountRepr {
|
||||||
use dex_pallet::HigherPrecisionBalance;
|
let mut requirement = AmountRepr::zero();
|
||||||
|
|
||||||
// This is inclusive to an increase in accuracy
|
|
||||||
let sri_per_coin = Dex::<T>::security_oracle_value(balance.coin).unwrap_or(Amount(0));
|
|
||||||
|
|
||||||
// See dex-pallet for the reasoning on these
|
|
||||||
let coin_decimals = balance.coin.decimals().max(5);
|
|
||||||
let accuracy_increase = HigherPrecisionBalance::from(SubstrateAmount::pow(10, coin_decimals));
|
|
||||||
|
|
||||||
let total_coin_value = u64::try_from(
|
|
||||||
HigherPrecisionBalance::from(balance.amount.0) *
|
|
||||||
HigherPrecisionBalance::from(sri_per_coin.0) /
|
|
||||||
accuracy_increase,
|
|
||||||
)
|
|
||||||
.unwrap_or(u64::MAX);
|
|
||||||
|
|
||||||
// required stake formula (COIN_VALUE * 1.5) + margin(20%)
|
|
||||||
let required_stake = total_coin_value.saturating_mul(3).saturating_div(2);
|
|
||||||
required_stake.saturating_add(total_coin_value.saturating_div(5))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns the current total required stake for a given `network`.
|
|
||||||
pub fn required_stake_for_network(network: ExternalNetworkId) -> SubstrateAmount {
|
|
||||||
let mut total_required = 0;
|
|
||||||
for coin in network.coins() {
|
for coin in network.coins() {
|
||||||
let supply = Coins::<T>::supply(Coin::from(coin));
|
let supply = Coins::<T>::supply(Coin::from(coin));
|
||||||
total_required += Self::required_stake(&ExternalBalance { coin, amount: Amount(supply) });
|
requirement = requirement
|
||||||
|
.saturating_add(Self::stake_requirement(ExternalBalance { coin, amount: supply }));
|
||||||
}
|
}
|
||||||
total_required
|
requirement
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* TODO
|
||||||
pub fn distribute_block_rewards(
|
pub fn distribute_block_rewards(
|
||||||
network: NetworkId,
|
network: NetworkId,
|
||||||
account: T::AccountId,
|
account: T::AccountId,
|
||||||
@@ -532,11 +473,7 @@ mod pallet {
|
|||||||
#[pallet::weight((0, DispatchClass::Normal))] // TODO
|
#[pallet::weight((0, DispatchClass::Normal))] // TODO
|
||||||
pub fn allocate(origin: OriginFor<T>, network: NetworkId, amount: Amount) -> DispatchResult {
|
pub fn allocate(origin: OriginFor<T>, network: NetworkId, amount: Amount) -> DispatchResult {
|
||||||
let validator = ensure_signed(origin)?;
|
let validator = ensure_signed(origin)?;
|
||||||
Coins::<T, serai_coins_pallet::CoinsInstance>::transfer_fn(
|
Coins::<T>::transfer_fn(validator, Self::account(), Balance { coin: Coin::Serai, amount })?;
|
||||||
validator,
|
|
||||||
Self::account(),
|
|
||||||
Balance { coin: Coin::Serai, amount },
|
|
||||||
)?;
|
|
||||||
Abstractions::<T>::increase_allocation(network, validator, amount, false)
|
Abstractions::<T>::increase_allocation(network, validator, amount, false)
|
||||||
.map_err(Error::<T>::AllocationError)?;
|
.map_err(Error::<T>::AllocationError)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
@@ -558,11 +495,7 @@ mod pallet {
|
|||||||
});
|
});
|
||||||
|
|
||||||
if matches!(timeline, DeallocationTimeline::Immediate) {
|
if matches!(timeline, DeallocationTimeline::Immediate) {
|
||||||
Coins::<T, serai_coins_pallet::CoinsInstance>::transfer_fn(
|
Coins::<T>::transfer_fn(Self::account(), validator, Balance { coin: Coin::Serai, amount })?;
|
||||||
Self::account(),
|
|
||||||
validator,
|
|
||||||
Balance { coin: Coin::Serai, amount },
|
|
||||||
)?;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
@@ -584,11 +517,7 @@ mod pallet {
|
|||||||
deallocation: ValidatorSet { network, session },
|
deallocation: ValidatorSet { network, session },
|
||||||
});
|
});
|
||||||
|
|
||||||
Coins::<T, serai_coins_pallet::CoinsInstance>::transfer_fn(
|
Coins::<T>::transfer_fn(Self::account(), validator, Balance { coin: Coin::Serai, amount })?;
|
||||||
Self::account(),
|
|
||||||
validator,
|
|
||||||
Balance { coin: Coin::Serai, amount },
|
|
||||||
)?;
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -693,20 +622,20 @@ mod pallet {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* TODO
|
/*
|
||||||
|
TODO: Add an intent. While we shouldn't allow `Transfer`, `AddLiquidity` when we're within a
|
||||||
|
certain range of the limit, we should still allow swaps.
|
||||||
|
*/
|
||||||
impl<T: Config> AllowMint for Pallet<T> {
|
impl<T: Config> AllowMint for Pallet<T> {
|
||||||
fn is_allowed(balance: &ExternalBalance) -> bool {
|
fn is_allowed(balance: &ExternalBalance) -> bool {
|
||||||
// get the required stake
|
let current_requirement = Self::network_stake_requirement(balance.coin.network());
|
||||||
let current_required = Self::required_stake_for_network(balance.coin.network());
|
let new_requirement = current_requirement.saturating_add(Self::stake_requirement(*balance));
|
||||||
let new_required = current_required + Self::required_stake(balance);
|
|
||||||
|
|
||||||
// get the total stake for the network & compare.
|
|
||||||
let staked =
|
let staked =
|
||||||
Self::total_allocated_stake(NetworkId::from(balance.coin.network())).unwrap_or(Amount(0));
|
Abstractions::<T>::stake_for_current_validator_set(balance.coin.network().into())
|
||||||
staked.0 >= new_required
|
.unwrap_or(Amount(0));
|
||||||
|
staked.0 >= new_requirement
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
pub use pallet::*;
|
pub use pallet::*;
|
||||||
|
|
||||||
|
|||||||
@@ -494,6 +494,9 @@ impl<Storage: SessionsStorage> Sessions for Storage {
|
|||||||
validator: Public,
|
validator: Public,
|
||||||
amount: Amount,
|
amount: Amount,
|
||||||
) -> Result<DeallocationTimeline, DeallocationError> {
|
) -> Result<DeallocationTimeline, DeallocationError> {
|
||||||
|
// TODO: Check if this would introduce a single point of failure
|
||||||
|
// TODO: Check if this would violate economic security
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Decrease the allocation.
|
Decrease the allocation.
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user