diff --git a/Cargo.lock b/Cargo.lock index e4c5166fbe..d14c76bb20 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -11117,6 +11117,7 @@ dependencies = [ "pallet-restricted-tokens", "pallet-rewards", "pallet-session", + "pallet-sudo", "pallet-timestamp", "pallet-transaction-payment", "pallet-treasury", diff --git a/runtime/integration-tests/Cargo.toml b/runtime/integration-tests/Cargo.toml index cbe7df6145..3cf3662520 100644 --- a/runtime/integration-tests/Cargo.toml +++ b/runtime/integration-tests/Cargo.toml @@ -30,7 +30,7 @@ pallet-uniques = { git = "https://github.com/paritytech/substrate", default-feat pallet-timestamp = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.38" } pallet-treasury = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.38" } pallet-authorship = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.38" } - +pallet-sudo = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.38" } ## Substrate-Primitives sp-api = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.38" } diff --git a/runtime/integration-tests/src/generic/cases/loans.rs b/runtime/integration-tests/src/generic/cases/loans.rs new file mode 100644 index 0000000000..fe6fda9407 --- /dev/null +++ b/runtime/integration-tests/src/generic/cases/loans.rs @@ -0,0 +1,47 @@ +use cfg_primitives::{AccountId, Balance, CollectionId, ItemId, PoolId, CFG}; +use frame_support::traits::Get; +use orml_traits::GetByKey; + +use crate::{ + generic::{ + environment::{Blocks, Env}, + envs::runtime_env::RuntimeEnv, + runtime::Runtime, + utils::{ + self, + genesis::{self, Genesis, MUSD_CURRENCY_ID}, + }, + }, + utils::accounts::Keyring, +}; + +const POOL_ADMIN: Keyring = Keyring::Admin; +const INVESTOR: Keyring = Keyring::Alice; +const BORROWER: Keyring = Keyring::Bob; + +const FOR_FEES: Balance = 1 * CFG; + +const POOL_A: PoolId = 23; +const NFT_A: (CollectionId, ItemId) = (1, ItemId(10)); + +fn borrow() { + let mut env = RuntimeEnv::::from_storage( + Genesis::::default() + .add(genesis::balances(T::ExistentialDeposit::get() + FOR_FEES)) + .add(genesis::tokens(vec![( + MUSD_CURRENCY_ID, + T::ExistentialDeposits::get(&MUSD_CURRENCY_ID), + )])) + .add(genesis::assets(vec![MUSD_CURRENCY_ID])) + .storage(), + ); + + env.state_mut(|| { + utils::give_balance_to::(POOL_ADMIN.id(), T::PoolDeposit::get()); + utils::give_nft_to::(BORROWER.id(), NFT_A); + }); + + env.state(|| { + //pallet_uniques::Pallet:::: + }); +} diff --git a/runtime/integration-tests/src/generic/environment.rs b/runtime/integration-tests/src/generic/environment.rs index d9b98daae1..0ff0d9dbc7 100644 --- a/runtime/integration-tests/src/generic/environment.rs +++ b/runtime/integration-tests/src/generic/environment.rs @@ -36,11 +36,11 @@ pub trait Env { fn submit_now( &mut self, who: Keyring, - call: impl Into, + call: impl Into, ) -> Result; /// Submit an extrinsic mutating the state when the block is finalized - fn submit_later(&mut self, who: Keyring, call: impl Into) -> DispatchResult; + fn submit_later(&mut self, who: Keyring, call: impl Into) -> DispatchResult; /// Pass any number of blocks fn pass(&mut self, blocks: Blocks) { @@ -123,7 +123,7 @@ pub mod utils { /// To create and submit an extrinsic, see `submit()` pub fn create_extrinsic( who: Keyring, - call: impl Into, + call: impl Into, nonce: Index, ) -> ::Extrinsic { let runtime_call = call.into(); diff --git a/runtime/integration-tests/src/generic/envs/fudge_env.rs b/runtime/integration-tests/src/generic/envs/fudge_env.rs index 59570f2c9c..9aa395102a 100644 --- a/runtime/integration-tests/src/generic/envs/fudge_env.rs +++ b/runtime/integration-tests/src/generic/envs/fudge_env.rs @@ -44,12 +44,12 @@ impl Env for FudgeEnv { fn submit_now( &mut self, _who: Keyring, - _call: impl Into, + _call: impl Into, ) -> Result { unimplemented!("FudgeEnv does not support submit_now() try submit_later()") } - fn submit_later(&mut self, who: Keyring, call: impl Into) -> DispatchResult { + fn submit_later(&mut self, who: Keyring, call: impl Into) -> DispatchResult { let nonce = *self.nonce_storage.entry(who).or_default(); let extrinsic = self.state(|| utils::create_extrinsic::(who, call, nonce)); diff --git a/runtime/integration-tests/src/generic/envs/runtime_env.rs b/runtime/integration-tests/src/generic/envs/runtime_env.rs index 5ce87bde24..26c372a501 100644 --- a/runtime/integration-tests/src/generic/envs/runtime_env.rs +++ b/runtime/integration-tests/src/generic/envs/runtime_env.rs @@ -26,7 +26,7 @@ use crate::{ /// without the usage of a client. pub struct RuntimeEnv { ext: Rc>, - pending_extrinsics: Vec<(Keyring, T::RuntimeCall)>, + pending_extrinsics: Vec<(Keyring, T::RuntimeCallExt)>, _config: PhantomData, } @@ -53,7 +53,7 @@ impl Env for RuntimeEnv { fn submit_now( &mut self, who: Keyring, - call: impl Into, + call: impl Into, ) -> Result { let extrinsic = self.state(|| { let nonce = frame_system::Pallet::::account(who.to_account_id()).nonce; @@ -74,7 +74,7 @@ impl Env for RuntimeEnv { Ok(fee) } - fn submit_later(&mut self, who: Keyring, call: impl Into) -> DispatchResult { + fn submit_later(&mut self, who: Keyring, call: impl Into) -> DispatchResult { self.pending_extrinsics.push((who, call.into())); Ok(()) } @@ -145,7 +145,7 @@ impl RuntimeEnv { } } - fn cumulus_inherent(i: BlockNumber) -> T::RuntimeCall { + fn cumulus_inherent(i: BlockNumber) -> T::RuntimeCallExt { let mut inherent_data = InherentData::default(); let sproof_builder = RelayStateSproofBuilder::default(); @@ -176,7 +176,7 @@ impl RuntimeEnv { .into() } - fn timestamp_inherent(timestamp: u64) -> T::RuntimeCall { + fn timestamp_inherent(timestamp: u64) -> T::RuntimeCallExt { let mut inherent_data = InherentData::default(); let timestamp_inherent = Timestamp::new(timestamp); diff --git a/runtime/integration-tests/src/generic/mod.rs b/runtime/integration-tests/src/generic/mod.rs index 2c98116c24..1960349310 100644 --- a/runtime/integration-tests/src/generic/mod.rs +++ b/runtime/integration-tests/src/generic/mod.rs @@ -9,13 +9,12 @@ pub mod envs { pub mod runtime_env; } pub mod runtime; -pub mod utils { - pub mod genesis; -} +pub mod utils; // Test cases mod cases { mod example; + mod loans; } use runtime::{Runtime, RuntimeKind}; diff --git a/runtime/integration-tests/src/generic/utils/genesis.rs b/runtime/integration-tests/src/generic/utils/genesis.rs index f6b64d3ecf..8842d3e9d8 100644 --- a/runtime/integration-tests/src/generic/utils/genesis.rs +++ b/runtime/integration-tests/src/generic/utils/genesis.rs @@ -1,15 +1,29 @@ +use std::{collections::BTreeMap, marker::PhantomData}; + +use cfg_primitives::Balance; +use cfg_types::tokens::{AssetMetadata, CurrencyId, CustomMetadata}; +use codec::Encode; use frame_support::traits::GenesisBuild; use sp_runtime::Storage; -use crate::generic::runtime::Runtime; +use crate::{generic::runtime::Runtime, utils::accounts::default_accounts}; -#[derive(Default)] -pub struct Genesis { +pub struct Genesis { storage: Storage, + _config: PhantomData, +} + +impl Default for Genesis { + fn default() -> Self { + Self { + storage: Default::default(), + _config: Default::default(), + } + } } -impl Genesis { - pub fn add(mut self, builder: impl GenesisBuild) -> Genesis { +impl Genesis { + pub fn add(mut self, builder: impl GenesisBuild) -> Self { builder.assimilate_storage(&mut self.storage).unwrap(); self } @@ -18,3 +32,80 @@ impl Genesis { self.storage } } + +pub fn balances(balance: Balance) -> impl GenesisBuild { + pallet_balances::GenesisConfig:: { + balances: default_accounts() + .into_iter() + .map(|keyring| (keyring.id(), balance)) + .collect(), + } +} + +pub fn tokens(values: Vec<(CurrencyId, Balance)>) -> impl GenesisBuild { + orml_tokens::GenesisConfig:: { + balances: default_accounts() + .into_iter() + .map(|keyring| { + values + .clone() + .into_iter() + .map(|(curency_id, balance)| (keyring.id(), curency_id, balance)) + .collect::>() + }) + .flatten() + .collect(), + } +} + +pub const MUSD_DECIMALS: u32 = 6; +pub const MUSD_UNIT: Balance = 10u128.pow(MUSD_DECIMALS); +pub const MUSD_CURRENCY_ID: CurrencyId = CurrencyId::ForeignAsset(1); + +pub const AUSD_DECIMALS: u32 = 12; +pub const AUSD_UNIT: Balance = 10u128.pow(AUSD_DECIMALS); +pub const AUSD_CURRENCY_ID: CurrencyId = CurrencyId::ForeignAsset(2); + +pub fn assets(currency_ids: Vec) -> impl GenesisBuild { + let assets = BTreeMap::from([ + ( + MUSD_CURRENCY_ID, + AssetMetadata { + decimals: MUSD_DECIMALS, + name: "Mock USD".as_bytes().to_vec(), + symbol: "MUSD".as_bytes().to_vec(), + existential_deposit: 0, + location: None, + additional: CustomMetadata { + pool_currency: true, + ..Default::default() + }, + } + .encode(), + ), + ( + AUSD_CURRENCY_ID, + AssetMetadata { + decimals: 12, + name: "Acala Dollar".as_bytes().to_vec(), + symbol: "AUSD".as_bytes().to_vec(), + existential_deposit: 0, + location: None, + additional: CustomMetadata { + pool_currency: true, + ..Default::default() + }, + } + .encode(), + ), + // Add new currencies here + ]); + + orml_asset_registry::GenesisConfig:: { + assets: currency_ids + .into_iter() + .map(|id| (id, assets.get(&id).unwrap().clone())) + .collect(), + last_asset_id: Default::default(), // It seems deprecated + } +} diff --git a/runtime/integration-tests/src/generic/utils/mod.rs b/runtime/integration-tests/src/generic/utils/mod.rs new file mode 100644 index 0000000000..1e8ad5e31b --- /dev/null +++ b/runtime/integration-tests/src/generic/utils/mod.rs @@ -0,0 +1,84 @@ +// Divide this utilties into files when they grow + +use cfg_primitives::{Balance, CollectionId, ItemId, Moment, PoolId, TrancheId}; +use cfg_types::{ + permissions::{PermissionScope, PoolRole, Role}, + tokens::CurrencyId, +}; +use frame_system::RawOrigin; +use sp_runtime::{traits::StaticLookup, AccountId32}; +pub mod genesis; + +use crate::generic::runtime::Runtime; + +pub fn give_nft_to( + dest: AccountId32, + (collection_id, item_id): (CollectionId, ItemId), +) { + pallet_uniques::Pallet::::force_create( + RawOrigin::Root.into(), + collection_id, + T::Lookup::unlookup(dest.clone()), + true, + ) + .unwrap(); + + pallet_uniques::Pallet::::mint( + RawOrigin::Signed(dest.clone()).into(), + collection_id, + item_id, + T::Lookup::unlookup(dest), + ) + .unwrap() +} + +pub fn give_balance_to(dest: AccountId32, amount: Balance) { + let data = pallet_balances::Account::::get(dest.clone()); + pallet_balances::Pallet::::set_balance( + RawOrigin::Root.into(), + T::Lookup::unlookup(dest), + data.free + amount, + data.reserved, + ) + .unwrap(); +} + +pub fn give_token_to(dest: AccountId32, currency_id: CurrencyId, amount: Balance) { + let data = orml_tokens::Accounts::::get(dest.clone(), currency_id); + orml_tokens::Pallet::::set_balance( + RawOrigin::Root.into(), + T::Lookup::unlookup(dest), + currency_id, + data.free + amount, + data.reserved, + ) + .unwrap(); +} + +pub fn give_investor_role( + investor: AccountId32, + pool_id: PoolId, + tranche_id: TrancheId, +) { + let role = Role::PoolRole(PoolRole::TrancheInvestor(tranche_id, Moment::MAX)); + pallet_permissions::Pallet::::add( + RawOrigin::Root.into(), + role, + investor, + PermissionScope::Pool(pool_id), + role, + ) + .unwrap(); +} + +pub fn give_borrower_role(borrower: AccountId32, pool_id: PoolId) { + let role = Role::PoolRole(PoolRole::Borrower); + pallet_permissions::Pallet::::add( + RawOrigin::Root.into(), + role, + borrower, + PermissionScope::Pool(pool_id), + role, + ) + .unwrap(); +} diff --git a/runtime/integration-tests/src/utils/accounts.rs b/runtime/integration-tests/src/utils/accounts.rs index ae61b304d6..d4cc842c72 100644 --- a/runtime/integration-tests/src/utils/accounts.rs +++ b/runtime/integration-tests/src/utils/accounts.rs @@ -154,6 +154,11 @@ impl Keyring { self.public().0.into() } + /// Shorter alias for `to_account_id()` + pub fn id(self) -> AccountId32 { + self.to_account_id() + } + pub fn sign(self, msg: &[u8]) -> Signature { Pair::from(self).sign(msg) }