implement setting initial values for coins

This commit is contained in:
akildemir
2024-04-20 10:53:25 +03:00
parent 7041dbeb0b
commit 826f9986e4
8 changed files with 155 additions and 9 deletions

11
Cargo.lock generated
View File

@@ -7329,6 +7329,7 @@ dependencies = [
"parity-scale-codec",
"scale-info",
"serai-coins-primitives",
"serai-genesis-liquidity-primitives",
"serai-in-instructions-primitives",
"serai-primitives",
"serai-signals-primitives",
@@ -7527,6 +7528,9 @@ dependencies = [
"serai-dex-pallet",
"serai-genesis-liquidity-primitives",
"serai-primitives",
"serai-validator-sets-primitives",
"sp-application-crypto",
"sp-core",
"sp-std",
]
@@ -7534,7 +7538,14 @@ dependencies = [
name = "serai-genesis-liquidity-primitives"
version = "0.1.0"
dependencies = [
"borsh",
"parity-scale-codec",
"scale-info",
"serai-primitives",
"serai-validator-sets-primitives",
"serde",
"sp-std",
"zeroize",
]
[[package]]

View File

@@ -31,6 +31,7 @@ sp-consensus-grandpa = { git = "https://github.com/serai-dex/substrate" }
serai-primitives = { path = "../primitives", version = "0.1" }
serai-coins-primitives = { path = "../coins/primitives", version = "0.1" }
serai-validator-sets-primitives = { path = "../validator-sets/primitives", version = "0.1" }
serai-genesis-liquidity-primitives = { path = "../genesis-liquidity/primitives", version = "0.1" }
serai-in-instructions-primitives = { path = "../in-instructions/primitives", version = "0.1" }
serai-signals-primitives = { path = "../signals/primitives", version = "0.1" }
@@ -42,6 +43,7 @@ borsh = [
"serai-primitives/borsh",
"serai-coins-primitives/borsh",
"serai-validator-sets-primitives/borsh",
"serai-genesis-liquidity-primitives/borsh",
"serai-in-instructions-primitives/borsh",
"serai-signals-primitives/borsh",
]
@@ -50,6 +52,7 @@ serde = [
"serai-primitives/serde",
"serai-coins-primitives/serde",
"serai-validator-sets-primitives/serde",
"serai-genesis-liquidity-primitives/serde",
"serai-in-instructions-primitives/serde",
"serai-signals-primitives/serde",
]

View File

@@ -1,10 +1,12 @@
use serai_primitives::*;
use serai_genesis_liquidity_primitives::*;
#[derive(Clone, PartialEq, Eq, Debug, scale::Encode, scale::Decode, scale_info::TypeInfo)]
#[cfg_attr(feature = "borsh", derive(borsh::BorshSerialize, borsh::BorshDeserialize))]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum Call {
remove_coin_liquidity { balance: Balance },
set_initial_price { prices: Prices },
}
#[derive(Clone, PartialEq, Eq, Debug, scale::Encode, scale::Decode, scale_info::TypeInfo)]

View File

@@ -27,12 +27,15 @@ frame-system = { git = "https://github.com/serai-dex/substrate", default-feature
frame-support = { git = "https://github.com/serai-dex/substrate", default-features = false }
sp-std = { git = "https://github.com/serai-dex/substrate", default-features = false }
sp-core = { git = "https://github.com/serai-dex/substrate", default-features = false }
sp-application-crypto = { git = "https://github.com/serai-dex/substrate", default-features = false }
dex-pallet = { package = "serai-dex-pallet", path = "../../dex/pallet", default-features = false }
coins-pallet = { package = "serai-coins-pallet", path = "../../coins/pallet", default-features = false }
serai-primitives = { path = "../../primitives", default-features = false }
genesis-liquidity-primitives = { package = "serai-genesis-liquidity-primitives", path = "../primitives", default-features = false }
validator-sets-primitives = { package = "serai-validator-sets-primitives", path = "../../validator-sets/primitives", default-features = false }
[features]
std = [
@@ -43,12 +46,15 @@ std = [
"frame-support/std",
"sp-std/std",
"sp-core/std",
"sp-application-crypto/std",
"coins-pallet/std",
"dex-pallet/std",
"serai-primitives/std",
"genesis-liquidity-primitives/std",
"validator-sets-primitives/std",
]
default = ["std"]
default = ["std"]

View File

@@ -5,14 +5,20 @@
pub mod pallet {
use super::*;
use frame_system::{pallet_prelude::*, RawOrigin};
use frame_support::{pallet_prelude::*, sp_runtime::SaturatedConversion};
use frame_support::{
pallet_prelude::*,
sp_runtime::{self, SaturatedConversion},
};
use sp_std::{vec, collections::btree_map::BTreeMap};
use sp_std::{vec, vec::Vec, collections::btree_map::BTreeMap};
use sp_core::sr25519::Signature;
use sp_application_crypto::RuntimePublic;
use dex_pallet::{Pallet as Dex, Config as DexConfig};
use coins_pallet::{Config as CoinsConfig, Pallet as Coins, AllowMint};
use serai_primitives::*;
use validator_sets_primitives::{ValidatorSet, Session, musig_key};
pub use genesis_liquidity_primitives as primitives;
use primitives::*;
@@ -26,6 +32,19 @@ pub mod pallet {
type RuntimeEvent: From<Event<Self>> + IsType<<Self as frame_system::Config>::RuntimeEvent>;
}
#[pallet::genesis_config]
#[derive(Clone, PartialEq, Eq, Debug, Encode, Decode)]
pub struct GenesisConfig<T: Config> {
/// List of participants to place in the initial validator sets.
pub participants: Vec<T::AccountId>,
}
impl<T: Config> Default for GenesisConfig<T> {
fn default() -> Self {
GenesisConfig { participants: Default::default() }
}
}
#[pallet::error]
pub enum Error<T> {
GenesisPeriodEnded,
@@ -58,6 +77,20 @@ pub mod pallet {
pub(crate) type EconomicSecurityReached<T: Config> =
StorageMap<_, Identity, NetworkId, BlockNumberFor<T>, ValueQuery>;
#[pallet::storage]
pub(crate) type Participants<T: Config> =
StorageMap<_, Identity, NetworkId, BoundedVec<PublicKey, ConstU32<150>>, ValueQuery>;
#[pallet::storage]
pub(crate) type Oracle<T: Config> = StorageMap<_, Identity, Coin, u64, ValueQuery>;
#[pallet::genesis_build]
impl<T: Config> BuildGenesisConfig for GenesisConfig<T> {
fn build(&self) {
Participants::<T>::set(NetworkId::Serai, self.participants.clone().try_into().unwrap());
}
}
#[pallet::hooks]
impl<T: Config> Hooks<BlockNumberFor<T>> for Pallet<T> {
fn on_finalize(n: BlockNumberFor<T>) {
@@ -75,9 +108,14 @@ pub mod pallet {
let mut pool_values = BTreeMap::new();
let mut total_value: u64 = 0;
for coin in COINS {
// TODO: following line is just a place holder till we get the actual coin value
// in terms of btc.
let value = Dex::<T>::security_oracle_value(coin).unwrap_or(Amount(0)).0;
if coin == Coin::Serai {
continue;
}
// initial coin value in terms of btc
let value = Oracle::<T>::get(coin);
// get the pool & individual address values
account_values.insert(coin, vec![]);
let mut pool_amount: u64 = 0;
for (account, amount) in Liquidity::<T>::iter_prefix(coin) {
@@ -265,6 +303,50 @@ pub mod pallet {
Self::deposit_event(Event::GenesisLiquidityRemoved { by: account.into(), balance });
Ok(())
}
/// A call to submit the initial coi values.
#[pallet::call_index(1)]
#[pallet::weight((0, DispatchClass::Operational))] // TODO
pub fn set_initial_price(
origin: OriginFor<T>,
prices: Prices,
_signature: Signature,
) -> DispatchResult {
ensure_none(origin)?;
// set the prices
Oracle::<T>::set(Coin::Bitcoin, prices.bitcoin);
Oracle::<T>::set(Coin::Monero, prices.monero);
Oracle::<T>::set(Coin::Ether, prices.ethereum);
Oracle::<T>::set(Coin::Dai, prices.dai);
Ok(())
}
}
#[pallet::validate_unsigned]
impl<T: Config> ValidateUnsigned for Pallet<T> {
type Call = Call<T>;
fn validate_unsigned(_: TransactionSource, call: &Self::Call) -> TransactionValidity {
match call {
Call::set_initial_price { ref prices, ref signature } => {
let set = ValidatorSet { network: NetworkId::Serai, session: Session(0) };
let signers = Participants::<T>::get(NetworkId::Serai);
if !musig_key(set, &signers).verify(&set_initial_price_message(&set, prices), signature) {
Err(InvalidTransaction::BadProof)?;
}
ValidTransaction::with_tag_prefix("GenesisLiquidity")
.and_provides((0, set))
.longevity(u64::MAX)
.propagate(true)
.build()
}
Call::remove_coin_liquidity { .. } => Err(InvalidTransaction::Call)?,
Call::__Ignore(_, _) => unreachable!(),
}
}
}
}

View File

@@ -16,10 +16,19 @@ rustdoc-args = ["--cfg", "docsrs"]
workspace = true
[dependencies]
zeroize = { version = "^1.5", features = ["derive"], optional = true }
borsh = { version = "1", default-features = false, features = ["derive", "de_strict_order"], optional = true }
serde = { version = "1", default-features = false, features = ["derive", "alloc"], optional = true }
scale = { package = "parity-scale-codec", version = "3", default-features = false, features = ["derive"] }
scale-info = { version = "2", default-features = false, features = ["derive"] }
sp-std = { git = "https://github.com/serai-dex/substrate", default-features = false }
serai-primitives = { path = "../../primitives", default-features = false }
validator-sets-primitives = { package = "serai-validator-sets-primitives", path = "../../validator-sets/primitives", default-features = false }
[features]
std = [
"serai-primitives/std",
]
std = ["serai-primitives/std", "validator-sets-primitives/std", "sp-std/std"]
default = ["std"]

View File

@@ -2,7 +2,21 @@
#![cfg_attr(docsrs, feature(doc_auto_cfg))]
#![cfg_attr(not(feature = "std"), no_std)]
#[cfg(feature = "std")]
use zeroize::Zeroize;
#[cfg(feature = "borsh")]
use borsh::{BorshSerialize, BorshDeserialize};
#[cfg(feature = "serde")]
use serde::{Serialize, Deserialize};
use sp_std::vec::Vec;
use scale::{Encode, Decode, MaxEncodedLen};
use scale_info::TypeInfo;
use serai_primitives::*;
use validator_sets_primitives::ValidatorSet;
// amount of blocks in 30 days for 6s per block.
pub const BLOCKS_PER_MONTH: u32 = 10 * 60 * 24 * 30;
@@ -15,3 +29,19 @@ pub const GENESIS_SRI: u64 = 100_000_000 * 10_u64.pow(8);
// This is the account to hold and manage the genesis liquidity.
pub const GENESIS_LIQUIDITY_ACCOUNT: SeraiAddress = system_address(b"Genesis-liquidity-account");
#[derive(Clone, PartialEq, Eq, Debug, Encode, Decode, MaxEncodedLen, TypeInfo)]
#[cfg_attr(feature = "std", derive(Zeroize))]
#[cfg_attr(feature = "borsh", derive(BorshSerialize, BorshDeserialize))]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct Prices {
pub bitcoin: u64,
pub monero: u64,
pub ethereum: u64,
pub dai: u64,
}
/// The message for the set_initial_price signature.
pub fn set_initial_price_message(set: &ValidatorSet, prices: &Prices) -> Vec<u8> {
(b"GenesisLiquidity-set_initial_price", set, prices).encode()
}

View File

@@ -8,6 +8,7 @@ use sc_service::ChainType;
use serai_runtime::{
primitives::*, WASM_BINARY, BABE_GENESIS_EPOCH_CONFIG, RuntimeGenesisConfig, SystemConfig,
CoinsConfig, DexConfig, ValidatorSetsConfig, SignalsConfig, BabeConfig, GrandpaConfig,
GenesisLiquidityConfig,
};
pub type ChainSpec = sc_service::GenericChainSpec<RuntimeGenesisConfig>;
@@ -60,6 +61,7 @@ fn devnet_genesis(
.collect(),
participants: validators.clone(),
},
genesis_liquidity: GenesisLiquidityConfig { participants: validators.clone() },
signals: SignalsConfig::default(),
babe: BabeConfig {
authorities: validators.iter().map(|validator| ((*validator).into(), 1)).collect(),
@@ -111,6 +113,7 @@ fn testnet_genesis(wasm_binary: &[u8], validators: Vec<&'static str>) -> Runtime
.collect(),
participants: validators.clone(),
},
genesis_liquidity: GenesisLiquidityConfig { participants: validators.clone() },
signals: SignalsConfig::default(),
babe: BabeConfig {
authorities: validators.iter().map(|validator| ((*validator).into(), 1)).collect(),