diff --git a/Cargo.lock b/Cargo.lock index 665a4b78d9..d3192f1319 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4061,6 +4061,7 @@ dependencies = [ "orml-tokens", "orml-traits", "pallet-balances", + "pallet-proxy", "pallet-transaction-payment-rpc-runtime-api", "parity-scale-codec", "serde", diff --git a/modules/accounts/Cargo.toml b/modules/accounts/Cargo.toml index da1b72860c..b519a6773f 100644 --- a/modules/accounts/Cargo.toml +++ b/modules/accounts/Cargo.toml @@ -13,6 +13,7 @@ frame-system = { version = "2.0.0", default-features = false } sp-std = { version = "2.0.0", default-features = false } sp-io= { version = "2.0.0", default-features = false } pallet-balances = { version = "2.0.0", default-features = false } +pallet-proxy = { version = "2.0.0", default-features = false } pallet-transaction-payment-rpc-runtime-api = { version = "2.0.0", default-features = false } orml-tokens = { path = "../../orml/tokens", default-features = false } orml-currencies = { path = "../../orml/currencies", default-features = false } @@ -39,6 +40,7 @@ std = [ "orml-tokens/std", "orml-currencies/std", "pallet-balances/std", + "pallet-proxy/std", "pallet-transaction-payment-rpc-runtime-api/std", "primitives/std", "support/std", diff --git a/modules/accounts/src/lib.rs b/modules/accounts/src/lib.rs index 6e1ff5c20a..b6ac94c5fb 100644 --- a/modules/accounts/src/lib.rs +++ b/modules/accounts/src/lib.rs @@ -13,8 +13,8 @@ use frame_support::{ dispatch::{DispatchResult, Dispatchable}, ensure, traits::{ - Currency, ExistenceRequirement, Get, Happened, Imbalance, IsSubType, OnKilledAccount, OnUnbalanced, StoredMap, - WithdrawReasons, + Currency, ExistenceRequirement, Get, Happened, Imbalance, IsSubType, OnKilledAccount, OnUnbalanced, + ReservableCurrency, StoredMap, WithdrawReasons, }, transactional, weights::{ @@ -199,7 +199,7 @@ where } } -pub trait Trait: system::Trait + orml_currencies::Trait { +pub trait Trait: system::Trait + orml_currencies::Trait + pallet_proxy::Trait { /// All non-native currency ids in Acala. type AllNonNativeCurrencyIds: Get>; @@ -320,6 +320,11 @@ decl_module! { let who = ensure_signed(origin)?; let recipient = recipient.unwrap_or_else(Self::treasury_account_id); + // remove proxy first + // use `remove_proxies` instead after https://github.com/paritytech/substrate/issues/7557 is available + let (_, proxy_deposit) = pallet_proxy::Proxies::::take(&who); + ::Currency::unreserve(&who, proxy_deposit); + Self::do_merge_account_check(&who)?; ::MultiCurrency::merge_account(&who, &recipient)?; @@ -578,7 +583,7 @@ where where T: Send + Sync, PalletBalanceOf: Send + Sync, - T::Call: Dispatchable, + ::Call: Dispatchable, { // NOTE: we can actually make it understand `ChargeTransactionPayment`, but // would be some hassle for sure. We have to make it aware of the index of @@ -622,9 +627,13 @@ where /// inclusion_fee = base_fee + len_fee + [targeted_fee_adjustment * weight_fee]; /// final_fee = inclusion_fee + tip; /// ``` - pub fn compute_fee(len: u32, info: &DispatchInfoOf, tip: PalletBalanceOf) -> PalletBalanceOf + pub fn compute_fee( + len: u32, + info: &DispatchInfoOf<::Call>, + tip: PalletBalanceOf, + ) -> PalletBalanceOf where - T::Call: Dispatchable, + ::Call: Dispatchable, { Self::compute_fee_raw(len, info.weight, tip, info.pays_fee) } @@ -635,12 +644,12 @@ where /// dispatch corrected weight is used for the weight fee calculation. pub fn compute_actual_fee( len: u32, - info: &DispatchInfoOf, - post_info: &PostDispatchInfoOf, + info: &DispatchInfoOf<::Call>, + post_info: &PostDispatchInfoOf<::Call>, tip: PalletBalanceOf, ) -> PalletBalanceOf where - T::Call: Dispatchable, + ::Call: Dispatchable, { Self::compute_fee_raw(len, post_info.calc_actual_weight(info), tip, post_info.pays_fee(info)) } @@ -711,7 +720,8 @@ impl sp_std::fmt::Debug for ChargeTransactionPayment impl ChargeTransactionPayment where - T::Call: Dispatchable + IsSubType>, + ::Call: + Dispatchable + IsSubType>, PalletBalanceOf: Send + Sync + FixedPointOperand, { /// utility constructor. Used only in client/factory code. @@ -722,8 +732,8 @@ where fn withdraw_fee( &self, who: &T::AccountId, - _call: &T::Call, - info: &DispatchInfoOf, + _call: &::Call, + info: &DispatchInfoOf<::Call>, len: usize, ) -> Result<(PalletBalanceOf, Option>), TransactionValidityError> { // pay any fees. @@ -796,7 +806,11 @@ where /// `(1/1)`, its priority is `fee * min(1, 4) = fee * 1`. This means /// that the transaction which consumes more resources (either length or /// weight) with the same `fee` ends up having lower priority. - fn get_priority(len: usize, info: &DispatchInfoOf, final_fee: PalletBalanceOf) -> TransactionPriority { + fn get_priority( + len: usize, + info: &DispatchInfoOf<::Call>, + final_fee: PalletBalanceOf, + ) -> TransactionPriority { let weight_saturation = T::MaximumBlockWeight::get() / info.weight.max(1); let len_saturation = T::MaximumBlockLength::get() as u64 / (len as u64).max(1); let coefficient: PalletBalanceOf = weight_saturation @@ -811,11 +825,12 @@ where impl SignedExtension for ChargeTransactionPayment where PalletBalanceOf: Send + Sync + From + FixedPointOperand, - T::Call: Dispatchable + IsSubType>, + ::Call: + Dispatchable + IsSubType>, { const IDENTIFIER: &'static str = "ChargeTransactionPayment"; type AccountId = T::AccountId; - type Call = T::Call; + type Call = ::Call; type AdditionalSigned = (); type Pre = ( PalletBalanceOf, diff --git a/modules/accounts/src/mock.rs b/modules/accounts/src/mock.rs index 9ac5d22a10..db2e72eaba 100644 --- a/modules/accounts/src/mock.rs +++ b/modules/accounts/src/mock.rs @@ -10,7 +10,11 @@ use frame_support::{ use primitives::{Amount, TokenSymbol, TradingPair}; use smallvec::smallvec; use sp_core::H256; -use sp_runtime::{testing::Header, traits::IdentityLookup, FixedPointNumber, Perbill}; +use sp_runtime::{ + testing::Header, + traits::{BlakeTwo256, IdentityLookup}, + FixedPointNumber, Perbill, +}; use sp_std::cell::RefCell; use support::Ratio; @@ -36,6 +40,7 @@ impl_outer_dispatch! { orml_currencies::Currencies, pallet_balances::PalletBalances, frame_system::System, + pallet_proxy::Proxy, } } @@ -44,6 +49,7 @@ impl_outer_event! { frame_system, orml_tokens, pallet_balances, + pallet_proxy, orml_currencies, dex, } @@ -152,6 +158,31 @@ impl dex::Trait for Runtime { } pub type DEXModule = dex::Module; +parameter_types! { + pub const ProxyDepositBase: u64 = 1; + pub const ProxyDepositFactor: u64 = 1; + pub const MaxProxies: u16 = 4; + pub const MaxPending: u32 = 2; + pub const AnnouncementDepositBase: u64 = 1; + pub const AnnouncementDepositFactor: u64 = 1; +} + +impl pallet_proxy::Trait for Runtime { + type Event = TestEvent; + type Call = Call; + type Currency = PalletBalances; + type ProxyType = (); + type ProxyDepositBase = ProxyDepositBase; + type ProxyDepositFactor = ProxyDepositFactor; + type MaxProxies = MaxProxies; + type WeightInfo = (); + type CallHasher = BlakeTwo256; + type MaxPending = MaxPending; + type AnnouncementDepositBase = AnnouncementDepositBase; + type AnnouncementDepositFactor = AnnouncementDepositFactor; +} +pub type Proxy = pallet_proxy::Module; + parameter_types! { pub AllNonNativeCurrencyIds: Vec = vec![AUSD, BTC]; pub const NewAccountDeposit: Balance = 100; diff --git a/modules/accounts/src/tests.rs b/modules/accounts/src/tests.rs index 3db897ac9e..b7e40795cd 100644 --- a/modules/accounts/src/tests.rs +++ b/modules/accounts/src/tests.rs @@ -8,8 +8,8 @@ use frame_support::{ weights::{DispatchClass, DispatchInfo, Pays}, }; use mock::{ - Accounts, Call, Currencies, DEXModule, ExtBuilder, MaximumBlockWeight, NewAccountDeposit, Origin, Runtime, System, - ACA, ALICE, AUSD, BOB, BTC, CAROL, + Accounts, Call, Currencies, DEXModule, ExtBuilder, MaximumBlockWeight, NewAccountDeposit, Origin, Proxy, Runtime, + System, ACA, ALICE, AUSD, BOB, BTC, CAROL, }; use orml_traits::MultiCurrency; use sp_runtime::testing::TestXt; @@ -229,6 +229,36 @@ fn close_account_failed_when_still_has_active_reserved() { }); } +#[test] +fn close_account_will_remove_proxies() { + ExtBuilder::default().build().execute_with(|| { + assert_ok!(>::transfer(ACA, &ALICE, &BOB, 500)); + assert_eq!(Accounts::is_explicit(&BOB), true); + assert_eq!(>::free_balance(ACA, &BOB), 400); + assert_eq!( + >::reserved_balance(ACA, &BOB), + 100 + ); + + assert_ok!(Proxy::add_proxy_delegate(&BOB, ALICE, Default::default(), Zero::zero())); + assert_eq!(Proxy::proxies(BOB).1, 2); + assert_eq!(>::free_balance(ACA, &BOB), 398); + assert_eq!( + >::reserved_balance(ACA, &BOB), + 102 + ); + + assert_ok!(Accounts::close_account(Origin::signed(BOB), None)); + assert_eq!(Accounts::is_explicit(&BOB), false); + assert_eq!(Proxy::proxies(BOB).1, 0); + assert_eq!(>::free_balance(ACA, &BOB), 0); + assert_eq!( + >::reserved_balance(ACA, &BOB), + 0 + ); + }); +} + #[test] fn close_account_and_does_not_specific_receiver() { ExtBuilder::default().build().execute_with(|| { diff --git a/modules/nft/benchmarking/src/lib.rs b/modules/nft/benchmarking/src/lib.rs index b5c65bd8bd..5de6241e6a 100644 --- a/modules/nft/benchmarking/src/lib.rs +++ b/modules/nft/benchmarking/src/lib.rs @@ -8,8 +8,9 @@ use sp_std::prelude::*; use sp_std::vec; use frame_benchmarking::{account, benchmarks}; +use frame_support::traits::Get; use frame_system::RawOrigin; -use sp_runtime::traits::UniqueSaturatedInto; +use sp_runtime::traits::{AccountIdConversion, UniqueSaturatedInto}; use module_nft::*; use orml_traits::BasicCurrencyExtended; @@ -47,8 +48,10 @@ benchmarks! { let base_currency_amount = dollar(1000); ::NativeCurrency::update_balance(&caller, base_currency_amount.unique_saturated_into())?; + let module_account: T::AccountId = T::ModuleId::get().into_sub_account(orml_nft::Module::::next_class_id()); module_nft::Module::::create_class(RawOrigin::Signed(caller.clone()).into(), vec![1], Properties(ClassProperty::Transferable | ClassProperty::Burnable))?; - }: _(RawOrigin::Signed(caller), to, 0u32.into(), vec![1], i) + ::NativeCurrency::update_balance(&module_account, base_currency_amount.unique_saturated_into())?; + }: _(RawOrigin::Signed(module_account), to, 0u32.into(), vec![1], i) // transfer NFT token to another account transfer { @@ -58,8 +61,10 @@ benchmarks! { let base_currency_amount = dollar(1000); ::NativeCurrency::update_balance(&caller, base_currency_amount.unique_saturated_into())?; + let module_account: T::AccountId = T::ModuleId::get().into_sub_account(orml_nft::Module::::next_class_id()); module_nft::Module::::create_class(RawOrigin::Signed(caller.clone()).into(), vec![1], Properties(ClassProperty::Transferable | ClassProperty::Burnable))?; - module_nft::Module::::mint(RawOrigin::Signed(caller.clone()).into(), to.clone(), 0u32.into(), vec![1], 1)?; + ::NativeCurrency::update_balance(&module_account, base_currency_amount.unique_saturated_into())?; + module_nft::Module::::mint(RawOrigin::Signed(module_account.clone()).into(), to.clone(), 0u32.into(), vec![1], 1)?; }: _(RawOrigin::Signed(to), caller, (0u32.into(), 0u32.into())) // burn NFT token @@ -70,8 +75,10 @@ benchmarks! { let base_currency_amount = dollar(1000); ::NativeCurrency::update_balance(&caller, base_currency_amount.unique_saturated_into())?; + let module_account: T::AccountId = T::ModuleId::get().into_sub_account(orml_nft::Module::::next_class_id()); module_nft::Module::::create_class(RawOrigin::Signed(caller.clone()).into(), vec![1], Properties(ClassProperty::Transferable | ClassProperty::Burnable))?; - module_nft::Module::::mint(RawOrigin::Signed(caller).into(), to.clone(), 0u32.into(), vec![1], 1)?; + ::NativeCurrency::update_balance(&module_account, base_currency_amount.unique_saturated_into())?; + module_nft::Module::::mint(RawOrigin::Signed(module_account.clone()).into(), to.clone(), 0u32.into(), vec![1], 1)?; }: _(RawOrigin::Signed(to), (0u32.into(), 0u32.into())) // destroy NFT class @@ -82,8 +89,9 @@ benchmarks! { let base_currency_amount = dollar(1000); ::NativeCurrency::update_balance(&caller, base_currency_amount.unique_saturated_into())?; + let module_account: T::AccountId = T::ModuleId::get().into_sub_account(orml_nft::Module::::next_class_id()); module_nft::Module::::create_class(RawOrigin::Signed(caller.clone()).into(), vec![1], Properties(ClassProperty::Transferable | ClassProperty::Burnable))?; - }: _(RawOrigin::Signed(caller), 0u32.into(), to) + }: _(RawOrigin::Signed(module_account), 0u32.into(), to) } #[cfg(test)] diff --git a/modules/nft/src/lib.rs b/modules/nft/src/lib.rs index fe1a5c7b99..3326d6007c 100644 --- a/modules/nft/src/lib.rs +++ b/modules/nft/src/lib.rs @@ -4,7 +4,11 @@ use codec::{Decode, Encode}; use enumflags2::BitFlags; use frame_support::{ - decl_error, decl_event, decl_module, ensure, traits::Get, transactional, weights::Weight, IterableStorageDoubleMap, + decl_error, decl_event, decl_module, ensure, + traits::{Currency, ExistenceRequirement::KeepAlive, Get}, + transactional, + weights::Weight, + IterableStorageDoubleMap, }; use frame_system::ensure_signed; use orml_traits::{BasicCurrency, BasicReservableCurrency, NFT}; @@ -166,17 +170,22 @@ decl_module! { let next_id = orml_nft::Module::::next_class_id(); let owner: T::AccountId = T::ModuleId::get().into_sub_account(next_id); let deposit = T::CreateClassDeposit::get(); + + // TODO: not sure whether to also transfer `NewAccountDeposit` for new account, + // it depends https://github.com/paritytech/substrate/issues/7563 ::Currency::transfer(&who, &owner, deposit)?; - // `owner` must be a new account, so the free balance will reserve `NewAccountDeposit`. - // use `free_balance(owner)` instead of `deposit` + // Currently, use `free_balance(owner)` instead of `deposit`. ::Currency::reserve(&owner, ::Currency::free_balance(&owner))?; - // Depends on https://github.com/paritytech/substrate/issues/7139 - // For now, use origin as owner and skip the proxy part - // pallet_proxy::Module::add_proxy(owner, origin, Default::default(), 0) + + // owner add proxy delegate to origin + let proxy_deposit = >::deposit(1u32); + ::Currency::transfer(&who, &owner, proxy_deposit, KeepAlive)?; + >::add_proxy_delegate(&owner, who, Default::default(), Zero::zero())?; + let data = ClassData { deposit, properties }; - orml_nft::Module::::create_class(&who, metadata, data)?; + orml_nft::Module::::create_class(&owner, metadata, data)?; - Self::deposit_event(RawEvent::CreatedClass(who, next_id)); + Self::deposit_event(RawEvent::CreatedClass(owner, next_id)); } /// Mint NFT token @@ -205,10 +214,8 @@ decl_module! { let class_info = orml_nft::Module::::classes(class_id).ok_or(Error::::ClassIdNotFound)?; ensure!(who == class_info.owner, Error::::NoPermission); let deposit = T::CreateTokenDeposit::get(); - let owner: T::AccountId = T::ModuleId::get().into_sub_account(class_id); let total_deposit = deposit * (quantity as u128); - ::Currency::transfer(&who, &owner, total_deposit)?; - ::Currency::reserve(&owner, total_deposit)?; + ::Currency::reserve(&class_info.owner, total_deposit)?; let data = TokenData { deposit }; for _ in 0..quantity { @@ -308,8 +315,6 @@ decl_module! { ::Currency::unreserve(&owner, data.deposit); ::Currency::transfer(&owner, &dest, data.deposit)?; - // Skip two steps until pallet_proxy is accessable - // pallet_proxy::Module::remove_proxies(owner) // transfer all free from origin to dest orml_nft::Module::::destroy_class(&who, class_id)?; diff --git a/modules/nft/src/mock.rs b/modules/nft/src/mock.rs index 95da137eee..2c3a129932 100644 --- a/modules/nft/src/mock.rs +++ b/modules/nft/src/mock.rs @@ -155,9 +155,9 @@ impl pallet_proxy::Trait for Runtime { } type System = frame_system::Module; -type Balances = pallet_balances::Module; +pub type Balances = pallet_balances::Module; type Utility = pallet_utility::Module; -type Proxy = pallet_proxy::Module; +pub type Proxy = pallet_proxy::Module; pub type NativeCurrency = orml_currencies::BasicCurrencyAdapter; diff --git a/modules/nft/src/tests.rs b/modules/nft/src/tests.rs index 5c3a5bb241..8cfeba9538 100644 --- a/modules/nft/src/tests.rs +++ b/modules/nft/src/tests.rs @@ -6,8 +6,8 @@ use super::*; use frame_support::StorageMap; use frame_support::{assert_noop, assert_ok}; use mock::{ - last_event, AccountId, ExtBuilder, NFTModule, Origin, Runtime, TestEvent, ALICE, BOB, CLASS_ID, CLASS_ID_NOT_EXIST, - TOKEN_ID, TOKEN_ID_NOT_EXIST, + last_event, AccountId, Balances, ExtBuilder, NFTModule, Origin, Proxy, Runtime, TestEvent, ALICE, BOB, CLASS_ID, + CLASS_ID_NOT_EXIST, TOKEN_ID, TOKEN_ID_NOT_EXIST, }; fn free_balance(who: &AccountId) -> Balance { @@ -30,12 +30,12 @@ fn create_class_should_work() { vec![1], Default::default() )); - let event = TestEvent::nft(RawEvent::CreatedClass(ALICE, CLASS_ID)); + let event = TestEvent::nft(RawEvent::CreatedClass(class_id_account(), CLASS_ID)); assert_eq!(last_event(), event); assert_eq!( reserved_balance(&class_id_account()), - ::CreateClassDeposit::get() + ::CreateClassDeposit::get() + Proxy::deposit(1u32) ); }); } @@ -62,16 +62,29 @@ fn mint_should_work() { vec![1], Properties(ClassProperty::Transferable | ClassProperty::Burnable) )); - let event = TestEvent::nft(RawEvent::CreatedClass(ALICE, CLASS_ID)); + let event = TestEvent::nft(RawEvent::CreatedClass(class_id_account(), CLASS_ID)); assert_eq!(last_event(), event); - assert_ok!(NFTModule::mint(Origin::signed(ALICE), BOB, CLASS_ID, vec![1], 2)); - let event = TestEvent::nft(RawEvent::MintedToken(ALICE, BOB, CLASS_ID, 2)); + assert_eq!( + Balances::deposit_into_existing(&class_id_account(), 2 * ::CreateTokenDeposit::get()) + .is_ok(), + true + ); + assert_ok!(NFTModule::mint( + Origin::signed(class_id_account()), + BOB, + CLASS_ID, + vec![1], + 2 + )); + let event = TestEvent::nft(RawEvent::MintedToken(class_id_account(), BOB, CLASS_ID, 2)); assert_eq!(last_event(), event); assert_eq!( reserved_balance(&class_id_account()), - ::CreateClassDeposit::get() + 2 * ::CreateTokenDeposit::get() + ::CreateClassDeposit::get() + + 2 * ::CreateTokenDeposit::get() + + Proxy::deposit(1u32) ); }); } @@ -102,8 +115,13 @@ fn mint_should_fail() { orml_nft::NextTokenId::::mutate(CLASS_ID, |id| { *id = ::TokenId::max_value() }); + assert_eq!( + Balances::deposit_into_existing(&class_id_account(), 2 * ::CreateTokenDeposit::get()) + .is_ok(), + true + ); assert_noop!( - NFTModule::mint(Origin::signed(ALICE), BOB, CLASS_ID, vec![1], 2), + NFTModule::mint(Origin::signed(class_id_account()), BOB, CLASS_ID, vec![1], 2), orml_nft::Error::::NoAvailableTokenId ); }); @@ -117,7 +135,18 @@ fn transfer_should_work() { vec![1], Properties(ClassProperty::Transferable | ClassProperty::Burnable) )); - assert_ok!(NFTModule::mint(Origin::signed(ALICE), BOB, CLASS_ID, vec![1], 2)); + assert_eq!( + Balances::deposit_into_existing(&class_id_account(), 2 * ::CreateTokenDeposit::get()) + .is_ok(), + true + ); + assert_ok!(NFTModule::mint( + Origin::signed(class_id_account()), + BOB, + CLASS_ID, + vec![1], + 2 + )); assert_ok!(NFTModule::transfer(Origin::signed(BOB), ALICE, (CLASS_ID, TOKEN_ID))); let event = TestEvent::nft(RawEvent::TransferedToken(BOB, ALICE, CLASS_ID, TOKEN_ID)); @@ -137,7 +166,18 @@ fn transfer_should_fail() { vec![1], Properties(ClassProperty::Transferable | ClassProperty::Burnable) )); - assert_ok!(NFTModule::mint(Origin::signed(ALICE), BOB, CLASS_ID, vec![1], 1)); + assert_eq!( + Balances::deposit_into_existing(&class_id_account(), 1 * ::CreateTokenDeposit::get()) + .is_ok(), + true + ); + assert_ok!(NFTModule::mint( + Origin::signed(class_id_account()), + BOB, + CLASS_ID, + vec![1], + 1 + )); assert_noop!( NFTModule::transfer(Origin::signed(BOB), ALICE, (CLASS_ID_NOT_EXIST, TOKEN_ID)), Error::::ClassIdNotFound @@ -158,7 +198,18 @@ fn transfer_should_fail() { vec![1], Default::default() )); - assert_ok!(NFTModule::mint(Origin::signed(ALICE), BOB, CLASS_ID, vec![1], 1)); + assert_eq!( + Balances::deposit_into_existing(&class_id_account(), 1 * ::CreateTokenDeposit::get()) + .is_ok(), + true + ); + assert_ok!(NFTModule::mint( + Origin::signed(class_id_account()), + BOB, + CLASS_ID, + vec![1], + 1 + )); assert_noop!( NFTModule::transfer(Origin::signed(BOB), ALICE, (CLASS_ID, TOKEN_ID)), Error::::NonTransferable @@ -174,14 +225,25 @@ fn burn_should_work() { vec![1], Properties(ClassProperty::Transferable | ClassProperty::Burnable) )); - assert_ok!(NFTModule::mint(Origin::signed(ALICE), BOB, CLASS_ID, vec![1], 1)); + assert_eq!( + Balances::deposit_into_existing(&class_id_account(), 1 * ::CreateTokenDeposit::get()) + .is_ok(), + true + ); + assert_ok!(NFTModule::mint( + Origin::signed(class_id_account()), + BOB, + CLASS_ID, + vec![1], + 1 + )); assert_ok!(NFTModule::burn(Origin::signed(BOB), (CLASS_ID, TOKEN_ID))); let event = TestEvent::nft(RawEvent::BurnedToken(BOB, CLASS_ID, TOKEN_ID)); assert_eq!(last_event(), event); assert_eq!( reserved_balance(&class_id_account()), - ::CreateClassDeposit::get() + ::CreateClassDeposit::get() + Proxy::deposit(1u32) ); }); } @@ -194,7 +256,18 @@ fn burn_should_fail() { vec![1], Properties(ClassProperty::Transferable | ClassProperty::Burnable) )); - assert_ok!(NFTModule::mint(Origin::signed(ALICE), BOB, CLASS_ID, vec![1], 1)); + assert_eq!( + Balances::deposit_into_existing(&class_id_account(), 1 * ::CreateTokenDeposit::get()) + .is_ok(), + true + ); + assert_ok!(NFTModule::mint( + Origin::signed(class_id_account()), + BOB, + CLASS_ID, + vec![1], + 1 + )); assert_noop!( NFTModule::burn(Origin::signed(BOB), (CLASS_ID, TOKEN_ID_NOT_EXIST)), Error::::TokenIdNotFound @@ -220,7 +293,18 @@ fn burn_should_fail() { vec![1], Default::default() )); - assert_ok!(NFTModule::mint(Origin::signed(ALICE), BOB, CLASS_ID, vec![1], 1)); + assert_eq!( + Balances::deposit_into_existing(&class_id_account(), 1 * ::CreateTokenDeposit::get()) + .is_ok(), + true + ); + assert_ok!(NFTModule::mint( + Origin::signed(class_id_account()), + BOB, + CLASS_ID, + vec![1], + 1 + )); assert_noop!( NFTModule::burn(Origin::signed(BOB), (CLASS_ID, TOKEN_ID)), Error::::NonBurnable @@ -236,14 +320,29 @@ fn destroy_class_should_work() { vec![1], Properties(ClassProperty::Transferable | ClassProperty::Burnable) )); - assert_ok!(NFTModule::mint(Origin::signed(ALICE), BOB, CLASS_ID, vec![1], 1)); + assert_eq!( + Balances::deposit_into_existing(&class_id_account(), 1 * ::CreateTokenDeposit::get()) + .is_ok(), + true + ); // + 100 + assert_ok!(NFTModule::mint( + Origin::signed(class_id_account()), + BOB, + CLASS_ID, + vec![1], + 1 + )); assert_ok!(NFTModule::burn(Origin::signed(BOB), (CLASS_ID, TOKEN_ID))); - assert_ok!(NFTModule::destroy_class(Origin::signed(ALICE), CLASS_ID, BOB)); - let event = TestEvent::nft(RawEvent::DestroyedClass(ALICE, CLASS_ID, BOB)); + assert_ok!(NFTModule::destroy_class( + Origin::signed(class_id_account()), + CLASS_ID, + BOB + )); + let event = TestEvent::nft(RawEvent::DestroyedClass(class_id_account(), CLASS_ID, BOB)); assert_eq!(last_event(), event); - assert_eq!(reserved_balance(&class_id_account()), 0); - assert_eq!(free_balance(&ALICE), 99700); + assert_eq!(reserved_balance(&class_id_account()), 2); + assert_eq!(free_balance(&ALICE), 99700 + 100 - 2); assert_eq!(free_balance(&BOB), 300); }); } @@ -256,9 +355,20 @@ fn destroy_class_should_fail() { vec![1], Properties(ClassProperty::Transferable | ClassProperty::Burnable) )); - assert_ok!(NFTModule::mint(Origin::signed(ALICE), BOB, CLASS_ID, vec![1], 1)); + assert_eq!( + Balances::deposit_into_existing(&class_id_account(), 1 * ::CreateTokenDeposit::get()) + .is_ok(), + true + ); + assert_ok!(NFTModule::mint( + Origin::signed(class_id_account()), + BOB, + CLASS_ID, + vec![1], + 1 + )); assert_noop!( - NFTModule::destroy_class(Origin::signed(ALICE), CLASS_ID_NOT_EXIST, BOB), + NFTModule::destroy_class(Origin::signed(class_id_account()), CLASS_ID_NOT_EXIST, BOB), Error::::ClassIdNotFound ); @@ -268,11 +378,15 @@ fn destroy_class_should_fail() { ); assert_noop!( - NFTModule::destroy_class(Origin::signed(ALICE), CLASS_ID, BOB), + NFTModule::destroy_class(Origin::signed(class_id_account()), CLASS_ID, BOB), Error::::CannotDestroyClass ); assert_ok!(NFTModule::burn(Origin::signed(BOB), (CLASS_ID, TOKEN_ID))); - assert_ok!(NFTModule::destroy_class(Origin::signed(ALICE), CLASS_ID, BOB)); + assert_ok!(NFTModule::destroy_class( + Origin::signed(class_id_account()), + CLASS_ID, + BOB + )); }); } diff --git a/runtime/mandala/tests/integration_test.rs b/runtime/mandala/tests/integration_test.rs index 53db4237b8..0be1ed42c3 100644 --- a/runtime/mandala/tests/integration_test.rs +++ b/runtime/mandala/tests/integration_test.rs @@ -3,13 +3,13 @@ use codec::Encode; use frame_support::{ assert_noop, assert_ok, - traits::{schedule::DispatchTime, OnFinalize, OnInitialize, OriginTrait}, + traits::{schedule::DispatchTime, Currency, OnFinalize, OnInitialize, OriginTrait}, }; use frame_system::RawOrigin; use mandala_runtime::{ get_all_module_accounts, AccountId, Accounts, AuthoritysOriginId, Balance, Balances, BlockNumber, Call, CreateClassDeposit, CreateTokenDeposit, CurrencyId, DSWFModuleId, Event, EvmAccounts, GetNativeCurrencyId, - NewAccountDeposit, Origin, OriginCaller, Perbill, Runtime, SevenDays, TokenSymbol, NFT, + NewAccountDeposit, NftModuleId, Origin, OriginCaller, Perbill, Proxy, Runtime, SevenDays, TokenSymbol, NFT, }; use module_cdp_engine::LiquidationStrategy; use module_support::{CDPTreasury, DEXManager, Price, Rate, Ratio, RiskManager}; @@ -1131,8 +1131,13 @@ fn test_nft_module() { vec![1], module_nft::Properties(module_nft::ClassProperty::Transferable | module_nft::ClassProperty::Burnable) )); + assert_eq!( + Balances::deposit_into_existing(&NftModuleId::get().into_sub_account(0), 1 * CreateTokenDeposit::get()) + .is_ok(), + true + ); assert_ok!(NFT::mint( - origin_of(AccountId::from(ALICE)), + origin_of(NftModuleId::get().into_sub_account(0)), AccountId::from(BOB), 0, vec![1], @@ -1141,7 +1146,7 @@ fn test_nft_module() { assert_ok!(NFT::burn(origin_of(AccountId::from(BOB)), (0, 0))); assert_eq!(Balances::free_balance(AccountId::from(BOB)), CreateTokenDeposit::get()); assert_ok!(NFT::destroy_class( - origin_of(AccountId::from(ALICE)), + origin_of(NftModuleId::get().into_sub_account(0)), 0, AccountId::from(BOB) )); @@ -1152,7 +1157,7 @@ fn test_nft_module() { assert_eq!(Balances::reserved_balance(AccountId::from(BOB)), 0); assert_eq!( Balances::free_balance(AccountId::from(ALICE)), - amount(1000) - (CreateClassDeposit::get() + CreateTokenDeposit::get()) + amount(1000) - (CreateClassDeposit::get() + Proxy::deposit(1u32)) ); }); }