Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add in instructions pallet tests #608

Merged
merged 3 commits into from
Jan 30, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

17 changes: 13 additions & 4 deletions substrate/emissions/pallet/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ pub mod pallet {
use frame_system::{pallet_prelude::*, RawOrigin};
use frame_support::{pallet_prelude::*, sp_runtime::SaturatedConversion};

use sp_std::{vec, vec::Vec, ops::Mul, collections::btree_map::BTreeMap};
use sp_std::{vec, vec::Vec, collections::btree_map::BTreeMap};

use coins_pallet::{Config as CoinsConfig, Pallet as Coins};
use dex_pallet::{Config as DexConfig, Pallet as Dex};
Expand Down Expand Up @@ -59,6 +59,7 @@ pub mod pallet {
NetworkHasEconomicSecurity,
NoValueForCoin,
InsufficientAllocation,
AmountOverflow,
}

#[pallet::event]
Expand Down Expand Up @@ -412,9 +413,17 @@ pub mod pallet {
let last_block = <frame_system::Pallet<T>>::block_number() - 1u32.into();
let value = Dex::<T>::spot_price_for_block(last_block, balance.coin)
.ok_or(Error::<T>::NoValueForCoin)?;
// TODO: may panic? It might be best for this math ops to return the result as is instead of
// doing an unwrap so that it can be properly dealt with.
let sri_amount = balance.amount.mul(value);

let sri_amount = Amount(
u64::try_from(
u128::from(balance.amount.0)
.checked_mul(u128::from(value.0))
.ok_or(Error::<T>::AmountOverflow)?
.checked_div(u128::from(10u64.pow(balance.coin.decimals())))
.ok_or(Error::<T>::AmountOverflow)?,
)
.map_err(|_| Error::<T>::AmountOverflow)?,
);

// Mint
Coins::<T>::mint(to, Balance { coin: Coin::Serai, amount: sri_amount })?;
Expand Down
2 changes: 2 additions & 0 deletions substrate/genesis-liquidity/pallet/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ pub mod pallet {

/// Keeps shares and the amount of coins per account.
#[pallet::storage]
#[pallet::getter(fn liquidity)]
pub(crate) type Liquidity<T: Config> = StorageDoubleMap<
_,
Identity,
Expand All @@ -76,6 +77,7 @@ pub mod pallet {

/// Keeps the total shares and the total amount of coins per coin.
#[pallet::storage]
#[pallet::getter(fn supply)]
pub(crate) type Supply<T: Config> =
StorageMap<_, Identity, ExternalCoin, LiquidityAmount, OptionQuery>;

Expand Down
25 changes: 22 additions & 3 deletions substrate/in-instructions/pallet/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,14 @@ validator-sets-pallet = { package = "serai-validator-sets-pallet", path = "../..
genesis-liquidity-pallet = { package = "serai-genesis-liquidity-pallet", path = "../../genesis-liquidity/pallet", default-features = false }
emissions-pallet = { package = "serai-emissions-pallet", path = "../../emissions/pallet", default-features = false }


[dev-dependencies]
pallet-babe = { git = "https://github.com/serai-dex/substrate", default-features = false }
pallet-grandpa = { git = "https://github.com/serai-dex/substrate", default-features = false }
pallet-timestamp = { git = "https://github.com/serai-dex/substrate", default-features = false }

economic-security-pallet = { package = "serai-economic-security-pallet", path = "../../economic-security/pallet", default-features = false }

[features]
std = [
"scale/std",
Expand All @@ -62,8 +70,19 @@ std = [
"validator-sets-pallet/std",
"genesis-liquidity-pallet/std",
"emissions-pallet/std",

"economic-security-pallet/std",

"pallet-babe/std",
"pallet-grandpa/std",
"pallet-timestamp/std",
]
default = ["std"]

# TODO
try-runtime = []
try-runtime = [
"frame-system/try-runtime",
"frame-support/try-runtime",

"sp-runtime/try-runtime",
]

default = ["std"]
6 changes: 6 additions & 0 deletions substrate/in-instructions/pallet/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,12 @@ use serai_primitives::*;
pub use in_instructions_primitives as primitives;
use primitives::*;

#[cfg(test)]
mod mock;

#[cfg(test)]
mod tests;

// TODO: Investigate why Substrate generates these
#[allow(
unreachable_patterns,
Expand Down
201 changes: 201 additions & 0 deletions substrate/in-instructions/pallet/src/mock.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,201 @@
//! Test environment for InInstructions pallet.

use super::*;

use std::collections::HashMap;

use frame_support::{
construct_runtime,
traits::{ConstU16, ConstU32, ConstU64},
};

use sp_core::{H256, Pair, sr25519::Public};
use sp_runtime::{
traits::{BlakeTwo256, IdentityLookup},
BuildStorage,
};

use validator_sets::{primitives::MAX_KEY_SHARES_PER_SET, MembershipProof};

pub use crate as in_instructions;
pub use coins_pallet as coins;
pub use validator_sets_pallet as validator_sets;
pub use genesis_liquidity_pallet as genesis_liquidity;
pub use emissions_pallet as emissions;
pub use dex_pallet as dex;
pub use pallet_babe as babe;
pub use pallet_grandpa as grandpa;
pub use pallet_timestamp as timestamp;
pub use economic_security_pallet as economic_security;

type Block = frame_system::mocking::MockBlock<Test>;
// Maximum number of authorities per session.
pub type MaxAuthorities = ConstU32<{ MAX_KEY_SHARES_PER_SET }>;

pub const MEDIAN_PRICE_WINDOW_LENGTH: u16 = 10;

construct_runtime!(
pub enum Test
{
System: frame_system,
Timestamp: timestamp,
Coins: coins,
LiquidityTokens: coins::<Instance1>::{Pallet, Call, Storage, Event<T>},
Emissions: emissions,
ValidatorSets: validator_sets,
GenesisLiquidity: genesis_liquidity,
EconomicSecurity: economic_security,
Dex: dex,
Babe: babe,
Grandpa: grandpa,
InInstructions: in_instructions,
}
);

impl frame_system::Config for Test {
type BaseCallFilter = frame_support::traits::Everything;
type BlockWeights = ();
type BlockLength = ();
type RuntimeOrigin = RuntimeOrigin;
type RuntimeCall = RuntimeCall;
type Nonce = u64;
type Hash = H256;
type Hashing = BlakeTwo256;
type AccountId = Public;
type Lookup = IdentityLookup<Self::AccountId>;
type Block = Block;
type RuntimeEvent = RuntimeEvent;
type BlockHashCount = ConstU64<250>;
type DbWeight = ();
type Version = ();
type PalletInfo = PalletInfo;
type AccountData = ();
type OnNewAccount = ();
type OnKilledAccount = ();
type SystemWeightInfo = ();
type SS58Prefix = ();
type OnSetCode = ();
type MaxConsumers = ConstU32<16>;
}

impl timestamp::Config for Test {
type Moment = u64;
type OnTimestampSet = Babe;
type MinimumPeriod = ConstU64<{ (TARGET_BLOCK_TIME * 1000) / 2 }>;
type WeightInfo = ();
}

impl babe::Config for Test {
type EpochDuration = ConstU64<{ FAST_EPOCH_DURATION }>;

type ExpectedBlockTime = ConstU64<{ TARGET_BLOCK_TIME * 1000 }>;
type EpochChangeTrigger = babe::ExternalTrigger;
type DisabledValidators = ValidatorSets;

type WeightInfo = ();
type MaxAuthorities = MaxAuthorities;

type KeyOwnerProof = MembershipProof<Self>;
type EquivocationReportSystem = ();
}

impl grandpa::Config for Test {
type RuntimeEvent = RuntimeEvent;

type WeightInfo = ();
type MaxAuthorities = MaxAuthorities;

type MaxSetIdSessionEntries = ConstU64<0>;
type KeyOwnerProof = MembershipProof<Self>;
type EquivocationReportSystem = ();
}

impl coins::Config for Test {
type RuntimeEvent = RuntimeEvent;
type AllowMint = ValidatorSets;
}

impl coins::Config<coins::Instance1> for Test {
type RuntimeEvent = RuntimeEvent;
type AllowMint = ();
}

impl dex::Config for Test {
type RuntimeEvent = RuntimeEvent;

type LPFee = ConstU32<3>; // 0.3%
type MintMinLiquidity = ConstU64<10000>;

type MaxSwapPathLength = ConstU32<3>; // coin1 -> SRI -> coin2

type MedianPriceWindowLength = ConstU16<{ MEDIAN_PRICE_WINDOW_LENGTH }>;

type WeightInfo = dex::weights::SubstrateWeight<Test>;
}

impl validator_sets::Config for Test {
type RuntimeEvent = RuntimeEvent;
type ShouldEndSession = Babe;
}

impl genesis_liquidity::Config for Test {
type RuntimeEvent = RuntimeEvent;
}

impl emissions::Config for Test {
type RuntimeEvent = RuntimeEvent;
}

impl economic_security::Config for Test {
type RuntimeEvent = RuntimeEvent;
}

impl Config for Test {
type RuntimeEvent = RuntimeEvent;
}

// Amounts for single key share per network
pub fn key_shares() -> HashMap<NetworkId, Amount> {
HashMap::from([
(NetworkId::Serai, Amount(50_000 * 10_u64.pow(8))),
(NetworkId::External(ExternalNetworkId::Bitcoin), Amount(1_000_000 * 10_u64.pow(8))),
(NetworkId::External(ExternalNetworkId::Ethereum), Amount(1_000_000 * 10_u64.pow(8))),
(NetworkId::External(ExternalNetworkId::Monero), Amount(100_000 * 10_u64.pow(8))),
])
}

pub(crate) fn new_test_ext() -> sp_io::TestExternalities {
let mut t = frame_system::GenesisConfig::<Test>::default().build_storage().unwrap();
let networks: Vec<(NetworkId, Amount)> = key_shares().into_iter().collect::<Vec<_>>();

let accounts: Vec<Public> = vec![
insecure_pair_from_name("Alice").public(),
insecure_pair_from_name("Bob").public(),
insecure_pair_from_name("Charlie").public(),
insecure_pair_from_name("Dave").public(),
insecure_pair_from_name("Eve").public(),
insecure_pair_from_name("Ferdie").public(),
];
let validators = accounts.clone();

coins::GenesisConfig::<Test> {
accounts: accounts
.into_iter()
.map(|a| (a, Balance { coin: Coin::Serai, amount: Amount(1 << 60) }))
.collect(),
_ignore: Default::default(),
}
.assimilate_storage(&mut t)
.unwrap();

validator_sets::GenesisConfig::<Test> {
networks: networks.clone(),
participants: validators.clone(),
}
.assimilate_storage(&mut t)
.unwrap();

let mut ext = sp_io::TestExternalities::new(t);
ext.execute_with(|| System::set_block_number(0));
ext
}
Loading
Loading