From 0b8d6539cdd675260e9ca47008af7f0d6b36d4ec Mon Sep 17 00:00:00 2001 From: akildemir Date: Thu, 12 Sep 2024 13:02:42 +0300 Subject: [PATCH 1/3] add tests --- Cargo.lock | 3 + substrate/coins/pallet/Cargo.toml | 19 ++++- substrate/coins/pallet/src/lib.rs | 6 ++ substrate/coins/pallet/src/mock.rs | 70 ++++++++++++++++ substrate/coins/pallet/src/tests.rs | 126 ++++++++++++++++++++++++++++ 5 files changed, 222 insertions(+), 2 deletions(-) create mode 100644 substrate/coins/pallet/src/mock.rs create mode 100644 substrate/coins/pallet/src/tests.rs diff --git a/Cargo.lock b/Cargo.lock index ef72a56fd..ce7dda740 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -8063,10 +8063,13 @@ dependencies = [ "frame-system", "pallet-transaction-payment", "parity-scale-codec", + "rand_core", "scale-info", + "serai-abi", "serai-coins-primitives", "serai-primitives", "sp-core", + "sp-io", "sp-runtime", "sp-std", ] diff --git a/substrate/coins/pallet/Cargo.toml b/substrate/coins/pallet/Cargo.toml index 8c59fb3e6..237b429d1 100644 --- a/substrate/coins/pallet/Cargo.toml +++ b/substrate/coins/pallet/Cargo.toml @@ -34,6 +34,13 @@ pallet-transaction-payment = { git = "https://github.com/serai-dex/substrate", d serai-primitives = { path = "../../primitives", default-features = false, features = ["serde"] } coins-primitives = { package = "serai-coins-primitives", path = "../primitives", default-features = false } +[dev-dependencies] +sp-io = { git = "https://github.com/serai-dex/substrate", default-features = false } + +serai-abi = { path = "../../abi", default-features = false, features = ["serde"] } + +rand_core = "0.6" + [features] std = [ "frame-system/std", @@ -41,16 +48,24 @@ std = [ "sp-core/std", "sp-std/std", + "sp-io/std", "sp-runtime/std", + "serai-abi/std", + "serai-abi/serde", + "pallet-transaction-payment/std", "serai-primitives/std", "coins-primitives/std", ] -# TODO -try-runtime = [] +try-runtime = [ + "frame-system/try-runtime", + "frame-support/try-runtime", + + "sp-runtime/try-runtime", +] runtime-benchmarks = [ "frame-system/runtime-benchmarks", diff --git a/substrate/coins/pallet/src/lib.rs b/substrate/coins/pallet/src/lib.rs index a633ed070..06937b35f 100644 --- a/substrate/coins/pallet/src/lib.rs +++ b/substrate/coins/pallet/src/lib.rs @@ -1,5 +1,11 @@ #![cfg_attr(not(feature = "std"), no_std)] +#[cfg(test)] +mod mock; + +#[cfg(test)] +mod tests; + use serai_primitives::{Coin, SubstrateAmount, Balance}; pub trait AllowMint { diff --git a/substrate/coins/pallet/src/mock.rs b/substrate/coins/pallet/src/mock.rs new file mode 100644 index 000000000..bd4ebc55f --- /dev/null +++ b/substrate/coins/pallet/src/mock.rs @@ -0,0 +1,70 @@ +//! Test environment for Coins pallet. + +use super::*; + +use frame_support::{ + construct_runtime, + traits::{ConstU32, ConstU64}, +}; + +use sp_core::{H256, sr25519::Public}; +use sp_runtime::{ + traits::{BlakeTwo256, IdentityLookup}, + BuildStorage, +}; + +use crate as coins; + +type Block = frame_system::mocking::MockBlock; + +construct_runtime!( + pub enum Test + { + System: frame_system, + Coins: coins, + } +); + +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; + 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 Config for Test { + type RuntimeEvent = RuntimeEvent; + + type AllowMint = (); +} + +pub(crate) fn new_test_ext() -> sp_io::TestExternalities { + let mut t = frame_system::GenesisConfig::::default().build_storage().unwrap(); + + crate::GenesisConfig:: { accounts: vec![], _ignore: Default::default() } + .assimilate_storage(&mut t) + .unwrap(); + + let mut ext = sp_io::TestExternalities::new(t); + ext.execute_with(|| System::set_block_number(0)); + ext +} diff --git a/substrate/coins/pallet/src/tests.rs b/substrate/coins/pallet/src/tests.rs new file mode 100644 index 000000000..a50319ce5 --- /dev/null +++ b/substrate/coins/pallet/src/tests.rs @@ -0,0 +1,126 @@ +use crate::{mock::*, primitives::*}; + +use frame_system::RawOrigin; +use sp_core::Pair; + +use serai_primitives::*; + +pub type CoinsEvent = crate::Event; + +#[test] +fn mint() { + new_test_ext().execute_with(|| { + // minting u64::MAX should work + let coin = Coin::Serai; + let to = insecure_pair_from_name("random1").public(); + let balance = Balance { coin, amount: Amount(u64::MAX) }; + + Coins::mint(to, balance).unwrap(); + assert_eq!(Coins::balance(to, coin), balance.amount); + + // minting more should fail + assert!(Coins::mint(to, Balance { coin, amount: Amount(1) }).is_err()); + + // supply now should be equal to sum of the accounts balance sum + assert_eq!(Coins::supply(coin), balance.amount.0); + + // test events + let mint_events = System::events() + .iter() + .filter_map(|event| { + if let RuntimeEvent::Coins(e) = &event.event { + if matches!(e, CoinsEvent::Mint { .. }) { + Some(e.clone()) + } else { + None + } + } else { + None + } + }) + .collect::>(); + + assert_eq!(mint_events, vec![CoinsEvent::Mint { to, balance }]); + }) +} + +#[test] +fn burn_with_instruction() { + new_test_ext().execute_with(|| { + // mint some coin + let coin = Coin::Bitcoin; + let to = insecure_pair_from_name("random1").public(); + let balance = Balance { coin, amount: Amount(10 * 10u64.pow(coin.decimals())) }; + + Coins::mint(to, balance).unwrap(); + assert_eq!(Coins::balance(to, coin), balance.amount); + assert_eq!(Coins::supply(coin), balance.amount.0); + + // we shouldn't be able to burn more than what we have + let mut instruction = OutInstructionWithBalance { + instruction: OutInstruction { address: ExternalAddress::new(vec![]).unwrap(), data: None }, + balance: Balance { coin, amount: Amount(balance.amount.0 + 1) }, + }; + assert!( + Coins::burn_with_instruction(RawOrigin::Signed(to).into(), instruction.clone()).is_err() + ); + + // it should now work + instruction.balance.amount = balance.amount; + Coins::burn_with_instruction(RawOrigin::Signed(to).into(), instruction.clone()).unwrap(); + + // balance & supply now should be back to 0 + assert_eq!(Coins::balance(to, coin), Amount(0)); + assert_eq!(Coins::supply(coin), 0); + + let burn_events = System::events() + .iter() + .filter_map(|event| { + if let RuntimeEvent::Coins(e) = &event.event { + if matches!(e, CoinsEvent::BurnWithInstruction { .. }) { + Some(e.clone()) + } else { + None + } + } else { + None + } + }) + .collect::>(); + + assert_eq!(burn_events, vec![CoinsEvent::BurnWithInstruction { from: to, instruction }]); + }) +} + +#[test] +fn transfer() { + new_test_ext().execute_with(|| { + // mint some coin + let coin = Coin::Bitcoin; + let from = insecure_pair_from_name("random1").public(); + let balance = Balance { coin, amount: Amount(10 * 10u64.pow(coin.decimals())) }; + + Coins::mint(from, balance).unwrap(); + assert_eq!(Coins::balance(from, coin), balance.amount); + assert_eq!(Coins::supply(coin), balance.amount.0); + + // we can't send more than what we have + let to = insecure_pair_from_name("random2").public(); + assert!(Coins::transfer( + RawOrigin::Signed(from).into(), + to, + Balance { coin, amount: Amount(balance.amount.0 + 1) } + ) + .is_err()); + + // we can send it all + Coins::transfer(RawOrigin::Signed(from).into(), to, balance).unwrap(); + + // check the balances + assert_eq!(Coins::balance(from, coin), Amount(0)); + assert_eq!(Coins::balance(to, coin), balance.amount); + + // supply shouldn't change + assert_eq!(Coins::supply(coin), balance.amount.0); + }) +} From fdb5f82c0493214e65574a3a2c2d3ae67382f321 Mon Sep 17 00:00:00 2001 From: akildemir Date: Thu, 12 Sep 2024 13:04:52 +0300 Subject: [PATCH 2/3] remove unused crate --- Cargo.lock | 1 - substrate/coins/pallet/Cargo.toml | 2 -- 2 files changed, 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index ce7dda740..7547327f1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -8063,7 +8063,6 @@ dependencies = [ "frame-system", "pallet-transaction-payment", "parity-scale-codec", - "rand_core", "scale-info", "serai-abi", "serai-coins-primitives", diff --git a/substrate/coins/pallet/Cargo.toml b/substrate/coins/pallet/Cargo.toml index 237b429d1..04d81ab84 100644 --- a/substrate/coins/pallet/Cargo.toml +++ b/substrate/coins/pallet/Cargo.toml @@ -39,8 +39,6 @@ sp-io = { git = "https://github.com/serai-dex/substrate", default-features = fal serai-abi = { path = "../../abi", default-features = false, features = ["serde"] } -rand_core = "0.6" - [features] std = [ "frame-system/std", From d3517ce969fa7332c4568caffe7583c0bf3bb042 Mon Sep 17 00:00:00 2001 From: akildemir Date: Thu, 12 Sep 2024 13:07:24 +0300 Subject: [PATCH 3/3] remove serai_abi --- Cargo.lock | 1 - substrate/coins/pallet/Cargo.toml | 5 ----- 2 files changed, 6 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 7547327f1..94916cf20 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -8064,7 +8064,6 @@ dependencies = [ "pallet-transaction-payment", "parity-scale-codec", "scale-info", - "serai-abi", "serai-coins-primitives", "serai-primitives", "sp-core", diff --git a/substrate/coins/pallet/Cargo.toml b/substrate/coins/pallet/Cargo.toml index 04d81ab84..88ebfd32c 100644 --- a/substrate/coins/pallet/Cargo.toml +++ b/substrate/coins/pallet/Cargo.toml @@ -37,8 +37,6 @@ coins-primitives = { package = "serai-coins-primitives", path = "../primitives", [dev-dependencies] sp-io = { git = "https://github.com/serai-dex/substrate", default-features = false } -serai-abi = { path = "../../abi", default-features = false, features = ["serde"] } - [features] std = [ "frame-system/std", @@ -49,9 +47,6 @@ std = [ "sp-io/std", "sp-runtime/std", - "serai-abi/std", - "serai-abi/serde", - "pallet-transaction-payment/std", "serai-primitives/std",