diff --git a/Cargo.lock b/Cargo.lock index 8e9237671..e25f0d973 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -8202,6 +8202,7 @@ dependencies = [ "scale-info", "serai-coins-primitives", "serai-primitives", + "sp-core", "sp-runtime", "sp-std", ] @@ -8595,7 +8596,6 @@ dependencies = [ "serai-coins-pallet", "serai-primitives", "serai-validator-sets-pallet", - "serai-validator-sets-primitives", "sp-runtime", "sp-std", ] diff --git a/deny.toml b/deny.toml index f00f97320..701a0e1d4 100644 --- a/deny.toml +++ b/deny.toml @@ -54,13 +54,13 @@ exceptions = [ { allow = ["AGPL-3.0"], name = "tributary-chain" }, { allow = ["AGPL-3.0"], name = "serai-coordinator" }, + { allow = ["AGPL-3.0"], name = "serai-coins-pallet" }, + { allow = ["AGPL-3.0"], name = "serai-in-instructions-pallet" }, { allow = ["AGPL-3.0"], name = "serai-validator-sets-pallet" }, { allow = ["AGPL-3.0"], name = "serai-staking-pallet" }, - - { allow = ["AGPL-3.0"], name = "serai-coins-pallet" }, { allow = ["AGPL-3.0"], name = "serai-runtime" }, { allow = ["AGPL-3.0"], name = "serai-node" }, diff --git a/substrate/coins/pallet/Cargo.toml b/substrate/coins/pallet/Cargo.toml index a30421067..2ee8ecac6 100644 --- a/substrate/coins/pallet/Cargo.toml +++ b/substrate/coins/pallet/Cargo.toml @@ -18,8 +18,9 @@ scale-info = { version = "2", default-features = false, features = ["derive"] } frame-system = { git = "https://github.com/serai-dex/substrate", default-features = false } frame-support = { git = "https://github.com/serai-dex/substrate", default-features = false } -sp-runtime = { 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-runtime = { git = "https://github.com/serai-dex/substrate", default-features = false } pallet-transaction-payment = { git = "https://github.com/serai-dex/substrate", default-features = false } @@ -31,6 +32,7 @@ std = [ "frame-system/std", "frame-support/std", + "sp-std/std", "sp-runtime/std", "pallet-transaction-payment/std", diff --git a/substrate/coins/pallet/src/lib.rs b/substrate/coins/pallet/src/lib.rs index b22474427..c672159f7 100644 --- a/substrate/coins/pallet/src/lib.rs +++ b/substrate/coins/pallet/src/lib.rs @@ -2,14 +2,15 @@ #[frame_support::pallet] pub mod pallet { - use frame_support::pallet_prelude::{*, ValueQuery, OptionQuery}; - use frame_system::pallet_prelude::*; - + use sp_std::vec::Vec; + use sp_core::sr25519::Public; use sp_runtime::{ traits::{DispatchInfoOf, PostDispatchInfoOf}, transaction_validity::{TransactionValidityError, InvalidTransaction}, }; - use sp_std::vec::Vec; + + use frame_system::pallet_prelude::*; + use frame_support::pallet_prelude::*; use pallet_transaction_payment::{Config as TpConfig, OnChargeTransaction}; @@ -18,19 +19,20 @@ pub mod pallet { use primitives::*; #[pallet::config] - pub trait Config: frame_system::Config + TpConfig { + pub trait Config: frame_system::Config + TpConfig { type RuntimeEvent: From> + IsType<::RuntimeEvent>; } #[pallet::genesis_config] #[derive(Clone, PartialEq, Eq, Debug, Encode, Decode)] pub struct GenesisConfig { - pub accounts: Vec<(T::AccountId, Balance)>, + _config: PhantomData, + pub accounts: Vec<(Public, Balance)>, } impl Default for GenesisConfig { fn default() -> Self { - GenesisConfig { accounts: Default::default() } + GenesisConfig { _config: PhantomData, accounts: Default::default() } } } @@ -44,27 +46,28 @@ pub mod pallet { #[pallet::event] #[pallet::generate_deposit(fn deposit_event)] pub enum Event { - Mint { address: SeraiAddress, balance: Balance }, - Burn { address: SeraiAddress, instruction: OutInstructionWithBalance }, - SriBurn { address: SeraiAddress, amount: Amount }, - Transfer { from: SeraiAddress, to: SeraiAddress, balance: Balance }, + Mint { to: Public, balance: Balance }, + Burn { from: Public, instruction: OutInstructionWithBalance }, + SriBurn { from: Public, amount: Amount }, + Transfer { from: Public, to: Public, balance: Balance }, } #[pallet::pallet] pub struct Pallet(PhantomData); /// The amount of coins each account has. - // We use Identity type for the second key due to it being a non-manipulatable fixed-space ID. + // Identity is used as the second key's hasher due to it being a non-manipulatable fixed-space + // ID. #[pallet::storage] #[pallet::getter(fn balances)] pub type Balances = StorageDoubleMap< _, Blake2_128Concat, - T::AccountId, + Public, Identity, Coin, SubstrateAmount, - OptionQuery, + ValueQuery, >; /// The total supply of each coin. @@ -83,7 +86,7 @@ pub mod pallet { // initialize the genesis accounts for (account, balance) in self.accounts.iter() { - Pallet::::mint(account, *balance).unwrap(); + Pallet::::mint(*account, *balance).unwrap(); } } } @@ -93,55 +96,57 @@ pub mod pallet { fn on_initialize(_: BlockNumberFor) -> Weight { // burn the fees collected previous block let coin = Coin::Serai; - let amount = Self::balance(&FEE_ACCOUNT.into(), coin); - // we can unwrap, we are not burning more then what we have. - Self::burn_internal(&FEE_ACCOUNT.into(), Balance { coin, amount }, None).unwrap(); + let amount = Self::balance(FEE_ACCOUNT.into(), coin); + // we can unwrap, we are not burning more then what we have + // If this errors, it'll halt the runtime however (due to being called at the start of every + // block), requiring extra care when reviewing + Self::burn_sri(FEE_ACCOUNT.into(), amount).unwrap(); Weight::zero() // TODO } } impl Pallet { /// Returns the balance of a given account for `coin`. - pub fn balance(of: &T::AccountId, coin: Coin) -> Amount { - Amount(Self::balances(of, coin).unwrap_or(0)) + pub fn balance(of: Public, coin: Coin) -> Amount { + Amount(Self::balances(of, coin)) } - fn decrease_balance_internal(at: &T::AccountId, balance: Balance) -> Result<(), Error> { + fn decrease_balance_internal(from: Public, balance: Balance) -> Result<(), Error> { let coin = &balance.coin; // sub amount from account - let new_amount = Self::balances(at, coin) - .unwrap_or(0) + let new_amount = Self::balances(from, coin) .checked_sub(balance.amount.0) .ok_or(Error::::NotEnoughCoins)?; // save if new_amount == 0 { - Balances::::remove(at, coin); + Balances::::remove(from, coin); } else { - Balances::::set(at, coin, Some(new_amount)); + Balances::::set(from, coin, new_amount); } Ok(()) } - fn increase_balance_internal(at: &T::AccountId, balance: Balance) -> Result<(), Error> { + fn increase_balance_internal(to: Public, balance: Balance) -> Result<(), Error> { let coin = &balance.coin; // sub amount from account - let new_amount = Self::balances(at, coin) - .unwrap_or(0) + let new_amount = Self::balances(to, coin) .checked_add(balance.amount.0) .ok_or(Error::::AmountOverflowed)?; // save - Balances::::set(at, coin, Some(new_amount)); + Balances::::set(to, coin, new_amount); Ok(()) } - /// Mints amount at the given account, errors if amount overflows. - pub fn mint(at: &T::AccountId, balance: Balance) -> Result<(), Error> { + /// Mint `balance` to the given account. + /// + /// Errors if any amount overflows. + pub fn mint(to: Public, balance: Balance) -> Result<(), Error> { // update the balance - Self::increase_balance_internal(at, balance)?; + Self::increase_balance_internal(to, balance)?; // update the supply let new_supply = Self::supply(balance.coin) @@ -149,63 +154,63 @@ pub mod pallet { .ok_or(Error::::AmountOverflowed)?; Supply::::set(balance.coin, new_supply); - Self::deposit_event(Event::Mint { address: SeraiAddress(at.0), balance }); + Self::deposit_event(Event::Mint { to, balance }); Ok(()) } - /// Burns amount at the given account, errors if not enough funds to burn. - pub fn burn_internal( - at: &T::AccountId, + // Burn `balance` from the specified account. + fn burn_internal( + from: Public, balance: Balance, - instruction: Option, ) -> Result<(), Error> { - // don't waste time if amount 0. + // don't waste time if amount == 0 if balance.amount.0 == 0 { return Ok(()); } // update the balance - Self::decrease_balance_internal(at, balance)?; + Self::decrease_balance_internal(from, balance)?; // update the supply let new_supply = Self::supply(balance.coin) .checked_sub(balance.amount.0) - .ok_or(Error::::AmountOverflowed)?; + .unwrap(); Supply::::set(balance.coin, new_supply); - if balance.coin == Coin::Serai { - Self::deposit_event(Event::SriBurn { address: SeraiAddress(at.0), amount: balance.amount }); - } else { - let out_instruction = - OutInstructionWithBalance { instruction: instruction.unwrap(), balance }; - Self::deposit_event(Event::Burn { - address: SeraiAddress(at.0), - instruction: out_instruction, - }); + Ok(()) + } + + pub fn burn_sri( + from: Public, + amount: Amount, + ) -> Result<(), Error> { + Self::burn_internal(from, Balance { coin: Coin::Serai, amount })?; + Self::deposit_event(Event::SriBurn { from, amount }); + Ok(()) + } + + pub fn burn_non_sri( + from: Public, + instruction: OutInstructionWithBalance, + ) -> Result<(), Error> { + if instruction.balance.coin == Coin::Serai { + Err(Error::::SriBurnNotAllowed)?; } + Self::burn_internal(from, instruction.balance)?; + Self::deposit_event(Event::Burn { from, instruction }); Ok(()) } - /// Transfers coins from `from` to `to`. + /// Transfer `balance` from `from` to `to`. pub fn transfer_internal( - from: &T::AccountId, - to: &T::AccountId, + from: Public, + to: Public, balance: Balance, ) -> Result<(), Error> { - // don't waste time if amount 0. - if balance.amount.0 == 0 { - return Ok(()); - } - // update balances of accounts Self::decrease_balance_internal(from, balance)?; Self::increase_balance_internal(to, balance)?; - - Self::deposit_event(Event::Transfer { - from: SeraiAddress(from.0), - to: SeraiAddress(to.0), - balance, - }); + Self::deposit_event(Event::Transfer { from, to, balance }); Ok(()) } } @@ -214,9 +219,9 @@ pub mod pallet { impl Pallet { #[pallet::call_index(0)] #[pallet::weight((0, DispatchClass::Normal))] // TODO - pub fn transfer(origin: OriginFor, to: SeraiAddress, balance: Balance) -> DispatchResult { + pub fn transfer(origin: OriginFor, to: Public, balance: Balance) -> DispatchResult { let from = ensure_signed(origin)?; - Self::transfer_internal(&from, &to.into(), balance)?; + Self::transfer_internal(from, to, balance)?; Ok(()) } @@ -224,12 +229,7 @@ pub mod pallet { #[pallet::weight((0, DispatchClass::Normal))] // TODO pub fn burn(origin: OriginFor, instruction: OutInstructionWithBalance) -> DispatchResult { let from = ensure_signed(origin)?; - - if instruction.balance.coin == Coin::Serai { - Err(Error::::SriBurnNotAllowed)?; - } - - Self::burn_internal(&from, instruction.balance, Some(instruction.instruction))?; + Self::burn_non_sri(from, instruction)?; Ok(()) } } @@ -239,7 +239,7 @@ pub mod pallet { type LiquidityInfo = Option; fn withdraw_fee( - who: &T::AccountId, + who: &Public, _call: &T::RuntimeCall, _dispatch_info: &DispatchInfoOf, fee: Self::Balance, @@ -250,14 +250,14 @@ pub mod pallet { } let balance = Balance { coin: Coin::Serai, amount: Amount(fee) }; - match Self::transfer_internal(who, &FEE_ACCOUNT.into(), balance) { - Err(_) => Err(InvalidTransaction::Payment.into()), + match Self::transfer_internal(*who, FEE_ACCOUNT.into(), balance) { + Err(_) => Err(InvalidTransaction::Payment)?, Ok(()) => Ok(Some(fee)), } } fn correct_and_deposit_fee( - who: &T::AccountId, + who: &Public, _dispatch_info: &DispatchInfoOf, _post_info: &PostDispatchInfoOf, corrected_fee: Self::Balance, @@ -267,7 +267,7 @@ pub mod pallet { if let Some(paid) = already_withdrawn { let refund_amount = paid.saturating_sub(corrected_fee); let balance = Balance { coin: Coin::Serai, amount: Amount(refund_amount) }; - Self::transfer_internal(&FEE_ACCOUNT.into(), who, balance) + Self::transfer_internal(FEE_ACCOUNT.into(), *who, balance) .map_err(|_| TransactionValidityError::Invalid(InvalidTransaction::Payment))?; } Ok(()) diff --git a/substrate/primitives/src/networks.rs b/substrate/primitives/src/networks.rs index 8b19d60f9..608217b89 100644 --- a/substrate/primitives/src/networks.rs +++ b/substrate/primitives/src/networks.rs @@ -71,10 +71,31 @@ impl Coin { } } - pub fn precision(&self) -> u32 { + pub fn name(&self) -> &'static str { + match self { + Coin::Serai => "Serai", + Coin::Bitcoin => "Bitcoin", + Coin::Ether => "Ether", + Coin::Dai => "Dai Stablecoin", + Coin::Monero => "Monero", + } + } + + pub fn symbol(&self) -> &'static str { + match self { + Coin::Serai => "SRI", + Coin::Bitcoin => "BTC", + Coin::Ether => "ETH", + Coin::Dai => "DAI", + Coin::Monero => "XMR", + } + } + + pub fn decimals(&self) -> u32 { match self { Coin::Serai => 8, Coin::Bitcoin => 8, + // Ether and DAI have 18 decimals, yet we only track 8 in order to fit them within u64s Coin::Ether => 8, Coin::Dai => 8, Coin::Monero => 12, diff --git a/substrate/runtime/Cargo.toml b/substrate/runtime/Cargo.toml index 78474a9a1..9fd44ff10 100644 --- a/substrate/runtime/Cargo.toml +++ b/substrate/runtime/Cargo.toml @@ -122,8 +122,8 @@ runtime-benchmarks = [ "pallet-timestamp/runtime-benchmarks", - "pallet-babe/runtime-benchmarks", - "pallet-grandpa/runtime-benchmarks", + "pallet-babe/runtime-benchmarks", + "pallet-grandpa/runtime-benchmarks", ] default = ["std"] diff --git a/substrate/staking/pallet/Cargo.toml b/substrate/staking/pallet/Cargo.toml index 93b7aacdc..16b24cf86 100644 --- a/substrate/staking/pallet/Cargo.toml +++ b/substrate/staking/pallet/Cargo.toml @@ -15,19 +15,19 @@ rustdoc-args = ["--cfg", "docsrs"] parity-scale-codec = { version = "3", default-features = false, features = ["derive"] } scale-info = { version = "2", default-features = false, features = ["derive"] } -sp-runtime = { git = "https://github.com/serai-dex/substrate", default-features = false } sp-std = { git = "https://github.com/serai-dex/substrate", default-features = false } +sp-runtime = { git = "https://github.com/serai-dex/substrate", default-features = false } frame-system = { git = "https://github.com/serai-dex/substrate", default-features = false } frame-support = { git = "https://github.com/serai-dex/substrate", default-features = false } -validator-sets-pallet = { package = "serai-validator-sets-pallet", path = "../../validator-sets/pallet", default-features = false } -pallet-session = { git = "https://github.com/serai-dex/substrate", default-features = false } +serai-primitives = { path = "../../primitives", default-features = false } coins-pallet = { package = "serai-coins-pallet", path = "../../coins/pallet", default-features = false } -serai-primitives = { path = "../../primitives", default-features = false } -serai-validator-sets-primitives = { path = "../../validator-sets/primitives", default-features = false } +validator-sets-pallet = { package = "serai-validator-sets-pallet", path = "../../validator-sets/pallet", default-features = false } + +pallet-session = { git = "https://github.com/serai-dex/substrate", default-features = false } [features] std = [ @@ -35,10 +35,14 @@ std = [ "frame-support/std", "sp-std/std", - + "sp-runtime/std", + + "serai-primitives/std", + "coins-pallet/std", "validator-sets-pallet/std", + "pallet-session/std", ] diff --git a/substrate/staking/pallet/src/lib.rs b/substrate/staking/pallet/src/lib.rs index e0b7c8f2e..4b01820f8 100644 --- a/substrate/staking/pallet/src/lib.rs +++ b/substrate/staking/pallet/src/lib.rs @@ -10,14 +10,14 @@ pub mod pallet { use serai_primitives::*; + use coins_pallet::{Config as CoinsConfig, Pallet as Coins}; + use validator_sets_pallet::{ primitives::{Session, ValidatorSet}, Config as VsConfig, Pallet as VsPallet, }; use pallet_session::{Config as SessionConfig, SessionManager}; - use coins_pallet::{Config as CoinsConfig, Pallet as Coins}; - #[pallet::error] pub enum Error { StakeUnavilable,