1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
#![cfg_attr(not(feature = "std"), no_std)]

#[allow(
  unreachable_patterns,
  clippy::cast_possible_truncation,
  clippy::no_effect_underscore_binding,
  clippy::empty_docs
)]
#[frame_support::pallet]
pub mod pallet {
  use frame_system::pallet_prelude::*;
  use frame_support::pallet_prelude::*;

  use dex_pallet::{Config as DexConfig, Pallet as Dex};
  use coins_pallet::{Config as CoinsConfig, AllowMint};

  use serai_primitives::*;

  #[pallet::config]
  pub trait Config: frame_system::Config + CoinsConfig + DexConfig {
    type RuntimeEvent: From<Event<Self>> + IsType<<Self as frame_system::Config>::RuntimeEvent>;
  }

  #[pallet::event]
  #[pallet::generate_deposit(fn deposit_event)]
  pub enum Event<T: Config> {
    EconomicSecurityReached { network: ExternalNetworkId },
  }

  #[pallet::pallet]
  pub struct Pallet<T>(PhantomData<T>);

  #[pallet::storage]
  #[pallet::getter(fn economic_security_block)]
  pub(crate) type EconomicSecurityBlock<T: Config> =
    StorageMap<_, Identity, ExternalNetworkId, BlockNumberFor<T>, OptionQuery>;

  #[pallet::hooks]
  impl<T: Config> Hooks<BlockNumberFor<T>> for Pallet<T> {
    fn on_initialize(n: BlockNumberFor<T>) -> Weight {
      // we accept we reached economic security once we can mint smallest amount of a network's coin
      for coin in EXTERNAL_COINS {
        let existing = EconomicSecurityBlock::<T>::get(coin.network());
        // TODO: we don't need to check for oracle value if is_allowed returns false when there is
        // no coin value
        if existing.is_none() &&
          Dex::<T>::security_oracle_value(coin).is_some() &&
          <T as CoinsConfig>::AllowMint::is_allowed(&ExternalBalance { coin, amount: Amount(1) })
        {
          EconomicSecurityBlock::<T>::set(coin.network(), Some(n));
          Self::deposit_event(Event::EconomicSecurityReached { network: coin.network() });
        }
      }

      Weight::zero() // TODO
    }
  }
}

pub use pallet::*;