diff --git a/frame/assets/src/benchmarking.rs b/frame/assets/src/benchmarking.rs index 047ede2ce6964..a2483650715a2 100644 --- a/frame/assets/src/benchmarking.rs +++ b/frame/assets/src/benchmarking.rs @@ -482,5 +482,74 @@ benchmarks_instance_pallet! { assert_last_event::(Event::AssetMinBalanceChanged { asset_id: asset_id.into(), new_min_balance: 50u32.into() }.into()); } + touch { + let (asset_id, asset_owner, asset_owner_lookup) = create_default_asset::(false); + let new_account: T::AccountId = account("newaccount", 1, SEED); + T::Currency::make_free_balance_be(&new_account, DepositBalanceOf::::max_value()); + assert_ne!(asset_owner, new_account); + assert!(!Account::::contains_key(asset_id.into(), &new_account)); + }: _(SystemOrigin::Signed(new_account.clone()), asset_id) + verify { + assert!(Account::::contains_key(asset_id.into(), &new_account)); + } + + touch_other { + let (asset_id, asset_owner, asset_owner_lookup) = create_default_asset::(false); + let new_account: T::AccountId = account("newaccount", 1, SEED); + let new_account_lookup = T::Lookup::unlookup(new_account.clone()); + T::Currency::make_free_balance_be(&asset_owner, DepositBalanceOf::::max_value()); + assert_ne!(asset_owner, new_account); + assert!(!Account::::contains_key(asset_id.into(), &new_account)); + }: _(SystemOrigin::Signed(asset_owner.clone()), asset_id, new_account_lookup) + verify { + assert!(Account::::contains_key(asset_id.into(), &new_account)); + } + + refund { + let (asset_id, asset_owner, asset_owner_lookup) = create_default_asset::(false); + let new_account: T::AccountId = account("newaccount", 1, SEED); + T::Currency::make_free_balance_be(&new_account, DepositBalanceOf::::max_value()); + assert_ne!(asset_owner, new_account); + assert!(Assets::::touch( + SystemOrigin::Signed(new_account.clone()).into(), + asset_id + ).is_ok()); + // `touch` should reserve some balance of the caller... + assert!(!T::Currency::reserved_balance(&new_account).is_zero()); + // ...and also create an `Account` entry. + assert!(Account::::contains_key(asset_id.into(), &new_account)); + }: _(SystemOrigin::Signed(new_account.clone()), asset_id, true) + verify { + // `refund`ing should of course repatriate the reserve + assert!(T::Currency::reserved_balance(&new_account).is_zero()); + } + + refund_other { + let (asset_id, asset_owner, asset_owner_lookup) = create_default_asset::(false); + let new_account: T::AccountId = account("newaccount", 1, SEED); + let new_account_lookup = T::Lookup::unlookup(new_account.clone()); + T::Currency::make_free_balance_be(&asset_owner, DepositBalanceOf::::max_value()); + assert_ne!(asset_owner, new_account); + assert!(Assets::::touch_other( + SystemOrigin::Signed(asset_owner.clone()).into(), + asset_id, + new_account_lookup.clone() + ).is_ok()); + // `touch_other` should reserve balance of the freezer + assert!(!T::Currency::reserved_balance(&asset_owner).is_zero()); + assert!(Account::::contains_key(asset_id.into(), &new_account)); + }: _(SystemOrigin::Signed(asset_owner.clone()), asset_id, new_account_lookup.clone()) + verify { + // this should repatriate the reserved balance of the freezer + assert!(T::Currency::reserved_balance(&asset_owner).is_zero()); + } + + block { + let (asset_id, caller, caller_lookup) = create_default_minted_asset::(true, 100u32.into()); + }: _(SystemOrigin::Signed(caller.clone()), asset_id, caller_lookup) + verify { + assert_last_event::(Event::Blocked { asset_id: asset_id.into(), who: caller }.into()); + } + impl_benchmark_test_suite!(Assets, crate::mock::new_test_ext(), crate::mock::Test) } diff --git a/frame/assets/src/functions.rs b/frame/assets/src/functions.rs index 1e10e0066e851..d7c5bbe95e9fe 100644 --- a/frame/assets/src/functions.rs +++ b/frame/assets/src/functions.rs @@ -66,11 +66,15 @@ impl, I: 'static> Pallet { pub(super) fn new_account( who: &T::AccountId, d: &mut AssetDetails>, - maybe_deposit: Option>, - ) -> Result>, DispatchError> { + maybe_deposit: Option<(&T::AccountId, DepositBalanceOf)>, + ) -> Result, DispatchError> { let accounts = d.accounts.checked_add(1).ok_or(ArithmeticError::Overflow)?; - let reason = if let Some(deposit) = maybe_deposit { - ExistenceReason::DepositHeld(deposit) + let reason = if let Some((depositor, deposit)) = maybe_deposit { + if depositor == who { + ExistenceReason::DepositHeld(deposit) + } else { + ExistenceReason::DepositFrom(depositor.clone(), deposit) + } } else if d.is_sufficient { frame_system::Pallet::::inc_sufficients(who); d.sufficients += 1; @@ -93,18 +97,19 @@ impl, I: 'static> Pallet { pub(super) fn dead_account( who: &T::AccountId, d: &mut AssetDetails>, - reason: &ExistenceReason>, + reason: &ExistenceReasonOf, force: bool, ) -> DeadConsequence { + use ExistenceReason::*; match *reason { - ExistenceReason::Consumer => frame_system::Pallet::::dec_consumers(who), - ExistenceReason::Sufficient => { + Consumer => frame_system::Pallet::::dec_consumers(who), + Sufficient => { d.sufficients = d.sufficients.saturating_sub(1); frame_system::Pallet::::dec_sufficients(who); }, - ExistenceReason::DepositRefunded => {}, - ExistenceReason::DepositHeld(_) if !force => return Keep, - ExistenceReason::DepositHeld(_) => {}, + DepositRefunded => {}, + DepositHeld(_) | DepositFrom(..) if !force => return Keep, + DepositHeld(_) | DepositFrom(..) => {}, } d.accounts = d.accounts.saturating_sub(1); Remove @@ -130,8 +135,11 @@ impl, I: 'static> Pallet { if increase_supply && details.supply.checked_add(&amount).is_none() { return DepositConsequence::Overflow } - if let Some(balance) = Self::maybe_balance(id, who) { - if balance.checked_add(&amount).is_none() { + if let Some(account) = Account::::get(id, who) { + if account.status.is_blocked() { + return DepositConsequence::Blocked + } + if account.balance.checked_add(&amount).is_none() { return DepositConsequence::Overflow } } else { @@ -174,7 +182,7 @@ impl, I: 'static> Pallet { Some(a) => a, None => return BalanceLow, }; - if account.is_frozen { + if account.status.is_frozen() { return Frozen } if let Some(rest) = account.balance.checked_sub(&amount) { @@ -215,7 +223,7 @@ impl, I: 'static> Pallet { ensure!(details.status == AssetStatus::Live, Error::::AssetNotLive); let account = Account::::get(id, who).ok_or(Error::::NoAccount)?; - ensure!(!account.is_frozen, Error::::Frozen); + ensure!(!account.status.is_frozen(), Error::::Frozen); let amount = if let Some(frozen) = T::Freezer::frozen_balance(id, who) { // Frozen balance: account CANNOT be deleted @@ -302,43 +310,63 @@ impl, I: 'static> Pallet { Ok((credit, maybe_burn)) } - /// Creates a account for `who` to hold asset `id` with a zero balance and takes a deposit. - pub(super) fn do_touch(id: T::AssetId, who: T::AccountId) -> DispatchResult { + /// Creates an account for `who` to hold asset `id` with a zero balance and takes a deposit. + /// + /// When `check_depositor` is set to true, the depositor must be either the asset's Admin or + /// Freezer, otherwise the depositor can be any account. + pub(super) fn do_touch( + id: T::AssetId, + who: T::AccountId, + depositor: T::AccountId, + check_depositor: bool, + ) -> DispatchResult { ensure!(!Account::::contains_key(id, &who), Error::::AlreadyExists); let deposit = T::AssetAccountDeposit::get(); let mut details = Asset::::get(&id).ok_or(Error::::Unknown)?; ensure!(details.status == AssetStatus::Live, Error::::AssetNotLive); - let reason = Self::new_account(&who, &mut details, Some(deposit))?; - T::Currency::reserve(&who, deposit)?; + ensure!( + !check_depositor || &depositor == &details.admin || &depositor == &details.freezer, + Error::::NoPermission + ); + let reason = Self::new_account(&who, &mut details, Some((&depositor, deposit)))?; + T::Currency::reserve(&depositor, deposit)?; Asset::::insert(&id, details); Account::::insert( id, &who, AssetAccountOf:: { balance: Zero::zero(), - is_frozen: false, + status: AccountStatus::Liquid, reason, extra: T::Extra::default(), }, ); + Self::deposit_event(Event::Touched { asset_id: id, who, depositor }); Ok(()) } - /// Returns a deposit, destroying an asset-account. + /// Returns a deposit or a consumer reference, destroying an asset-account. + /// Non-zero balance accounts refunded and destroyed only if `allow_burn` is true. pub(super) fn do_refund(id: T::AssetId, who: T::AccountId, allow_burn: bool) -> DispatchResult { + use AssetStatus::*; + use ExistenceReason::*; let mut account = Account::::get(id, &who).ok_or(Error::::NoDeposit)?; - let deposit = account.reason.take_deposit().ok_or(Error::::NoDeposit)?; + ensure!(matches!(account.reason, Consumer | DepositHeld(..)), Error::::NoDeposit); let mut details = Asset::::get(&id).ok_or(Error::::Unknown)?; - ensure!(details.status == AssetStatus::Live, Error::::AssetNotLive); + ensure!(matches!(details.status, Live | Frozen), Error::::IncorrectStatus); ensure!(account.balance.is_zero() || allow_burn, Error::::WouldBurn); - ensure!(!account.is_frozen, Error::::Frozen); - T::Currency::unreserve(&who, deposit); + if let Some(deposit) = account.reason.take_deposit() { + T::Currency::unreserve(&who, deposit); + } if let Remove = Self::dead_account(&who, &mut details, &account.reason, false) { Account::::remove(id, &who); } else { debug_assert!(false, "refund did not result in dead account?!"); + // deposit may have been refunded, need to update `Account` + Account::::insert(id, &who, account); + return Ok(()) } Asset::::insert(&id, details); // Executing a hook here is safe, since it is not in a `mutate`. @@ -346,6 +374,37 @@ impl, I: 'static> Pallet { Ok(()) } + /// Returns a `DepositFrom` of an account only if balance is zero. + pub(super) fn do_refund_other( + id: T::AssetId, + who: &T::AccountId, + caller: &T::AccountId, + ) -> DispatchResult { + let mut account = Account::::get(id, &who).ok_or(Error::::NoDeposit)?; + let (depositor, deposit) = + account.reason.take_deposit_from().ok_or(Error::::NoDeposit)?; + let mut details = Asset::::get(&id).ok_or(Error::::Unknown)?; + ensure!(details.status == AssetStatus::Live, Error::::AssetNotLive); + ensure!(!account.status.is_frozen(), Error::::Frozen); + ensure!(caller == &depositor || caller == &details.admin, Error::::NoPermission); + ensure!(account.balance.is_zero(), Error::::WouldBurn); + + T::Currency::unreserve(&depositor, deposit); + + if let Remove = Self::dead_account(&who, &mut details, &account.reason, false) { + Account::::remove(id, &who); + } else { + debug_assert!(false, "refund did not result in dead account?!"); + // deposit may have been refunded, need to update `Account` + Account::::insert(id, &who, account); + return Ok(()) + } + Asset::::insert(&id, details); + // Executing a hook here is safe, since it is not in a `mutate`. + T::Freezer::died(id, &who); + return Ok(()) + } + /// Increases the asset `id` balance of `beneficiary` by `amount`. /// /// This alters the registered supply of the asset and emits an event. @@ -408,7 +467,7 @@ impl, I: 'static> Pallet { *maybe_account = Some(AssetAccountOf:: { balance: amount, reason: Self::new_account(beneficiary, details, None)?, - is_frozen: false, + status: AccountStatus::Liquid, extra: T::Extra::default(), }); }, @@ -602,7 +661,7 @@ impl, I: 'static> Pallet { maybe_account @ None => { *maybe_account = Some(AssetAccountOf:: { balance: credit, - is_frozen: false, + status: AccountStatus::Liquid, reason: Self::new_account(dest, details, None)?, extra: T::Extra::default(), }); diff --git a/frame/assets/src/lib.rs b/frame/assets/src/lib.rs index d32b407e67f6e..e6b59bba53836 100644 --- a/frame/assets/src/lib.rs +++ b/frame/assets/src/lib.rs @@ -82,6 +82,10 @@ //! * `approve_transfer`: Create or increase an delegated transfer. //! * `cancel_approval`: Rescind a previous approval. //! * `transfer_approved`: Transfer third-party's assets to another account. +//! * `touch`: Create an asset account for non-provider assets. Caller must place a deposit. +//! * `refund`: Return the deposit (if any) of the caller's asset account or a consumer reference +//! (if any) of the caller's account. +//! * `refund_other`: Return the deposit (if any) of a specified asset account. //! //! ### Permissioned Functions //! @@ -98,12 +102,16 @@ //! * `burn`: Decreases the asset balance of an account; called by the asset class's Admin. //! * `force_transfer`: Transfers between arbitrary accounts; called by the asset class's Admin. //! * `freeze`: Disallows further `transfer`s from an account; called by the asset class's Freezer. -//! * `thaw`: Allows further `transfer`s from an account; called by the asset class's Admin. +//! * `thaw`: Allows further `transfer`s to and from an account; called by the asset class's Admin. //! * `transfer_ownership`: Changes an asset class's Owner; called by the asset class's Owner. //! * `set_team`: Changes an asset class's Admin, Freezer and Issuer; called by the asset class's //! Owner. //! * `set_metadata`: Set the metadata of an asset class; called by the asset class's Owner. //! * `clear_metadata`: Remove the metadata of an asset class; called by the asset class's Owner. +//! * `touch_other`: Create an asset account for specified account. Caller must place a deposit; +//! called by the asset class's Freezer or Admin. +//! * `block`: Disallows further `transfer`s to and from an account; called by the asset class's +//! Freezer. //! //! Please refer to the [`Call`] enum and its associated variants for documentation on each //! function. @@ -194,7 +202,7 @@ impl AssetsCallback for () {} #[frame_support::pallet] pub mod pallet { use super::*; - use frame_support::pallet_prelude::*; + use frame_support::{pallet_prelude::*, traits::AccountTouch}; use frame_system::pallet_prelude::*; /// The current storage version. @@ -519,6 +527,10 @@ pub mod pallet { AssetStatusChanged { asset_id: T::AssetId }, /// The min_balance of an asset has been updated by the asset owner. AssetMinBalanceChanged { asset_id: T::AssetId, new_min_balance: T::Balance }, + /// Some account `who` was created with a deposit from `depositor`. + Touched { asset_id: T::AssetId, who: T::AccountId, depositor: T::AccountId }, + /// Some account `who` was blocked. + Blocked { asset_id: T::AssetId, who: T::AccountId }, } #[pallet::error] @@ -911,7 +923,9 @@ pub mod pallet { Self::do_transfer(id, &source, &dest, amount, Some(origin), f).map(|_| ()) } - /// Disallow further unprivileged transfers from an account. + /// Disallow further unprivileged transfers of an asset `id` from an account `who`. `who` + /// must already exist as an entry in `Account`s of the asset. If you want to freeze an + /// account that does not have an entry, use `touch_other` first. /// /// Origin must be Signed and the sender should be the Freezer of the asset `id`. /// @@ -939,7 +953,8 @@ pub mod pallet { let who = T::Lookup::lookup(who)?; Account::::try_mutate(id, &who, |maybe_account| -> DispatchResult { - maybe_account.as_mut().ok_or(Error::::NoAccount)?.is_frozen = true; + maybe_account.as_mut().ok_or(Error::::NoAccount)?.status = + AccountStatus::Frozen; Ok(()) })?; @@ -947,7 +962,7 @@ pub mod pallet { Ok(()) } - /// Allow unprivileged transfers from an account again. + /// Allow unprivileged transfers to and from an account again. /// /// Origin must be Signed and the sender should be the Admin of the asset `id`. /// @@ -975,7 +990,8 @@ pub mod pallet { let who = T::Lookup::lookup(who)?; Account::::try_mutate(id, &who, |maybe_account| -> DispatchResult { - maybe_account.as_mut().ok_or(Error::::NoAccount)?.is_frozen = false; + maybe_account.as_mut().ok_or(Error::::NoAccount)?.status = + AccountStatus::Liquid; Ok(()) })?; @@ -1471,22 +1487,25 @@ pub mod pallet { /// /// Emits `Touched` event when successful. #[pallet::call_index(26)] - #[pallet::weight(T::WeightInfo::mint())] + #[pallet::weight(T::WeightInfo::touch())] pub fn touch(origin: OriginFor, id: T::AssetIdParameter) -> DispatchResult { + let who = ensure_signed(origin)?; let id: T::AssetId = id.into(); - Self::do_touch(id, ensure_signed(origin)?) + Self::do_touch(id, who.clone(), who, false) } - /// Return the deposit (if any) of an asset account. + /// Return the deposit (if any) of an asset account or a consumer reference (if any) of an + /// account. /// /// The origin must be Signed. /// - /// - `id`: The identifier of the asset for the account to be created. + /// - `id`: The identifier of the asset for which the caller would like the deposit + /// refunded. /// - `allow_burn`: If `true` then assets may be destroyed in order to complete the refund. /// /// Emits `Refunded` event when successful. #[pallet::call_index(27)] - #[pallet::weight(T::WeightInfo::mint())] + #[pallet::weight(T::WeightInfo::refund())] pub fn refund( origin: OriginFor, id: T::AssetIdParameter, @@ -1541,6 +1560,104 @@ pub mod pallet { }); Ok(()) } + + /// Create an asset account for `who`. + /// + /// A deposit will be taken from the signer account. + /// + /// - `origin`: Must be Signed by `Freezer` or `Admin` of the asset `id`; the signer account + /// must have sufficient funds for a deposit to be taken. + /// - `id`: The identifier of the asset for the account to be created. + /// - `who`: The account to be created. + /// + /// Emits `Touched` event when successful. + #[pallet::call_index(29)] + #[pallet::weight(T::WeightInfo::touch_other())] + pub fn touch_other( + origin: OriginFor, + id: T::AssetIdParameter, + who: AccountIdLookupOf, + ) -> DispatchResult { + let origin = ensure_signed(origin)?; + let who = T::Lookup::lookup(who)?; + let id: T::AssetId = id.into(); + Self::do_touch(id, who, origin, true) + } + + /// Return the deposit (if any) of a target asset account. Useful if you are the depositor. + /// + /// The origin must be Signed and either the account owner, depositor, or asset `Admin`. In + /// order to burn a non-zero balance of the asset, the caller must be the account and should + /// use `refund`. + /// + /// - `id`: The identifier of the asset for the account holding a deposit. + /// - `who`: The account to refund. + /// + /// Emits `Refunded` event when successful. + #[pallet::call_index(30)] + #[pallet::weight(T::WeightInfo::refund_other())] + pub fn refund_other( + origin: OriginFor, + id: T::AssetIdParameter, + who: AccountIdLookupOf, + ) -> DispatchResult { + let origin = ensure_signed(origin)?; + let who = T::Lookup::lookup(who)?; + let id: T::AssetId = id.into(); + Self::do_refund_other(id, &who, &origin) + } + + /// Disallow further unprivileged transfers of an asset `id` to and from an account `who`. + /// + /// Origin must be Signed and the sender should be the Freezer of the asset `id`. + /// + /// - `id`: The identifier of the account's asset. + /// - `who`: The account to be unblocked. + /// + /// Emits `Blocked`. + /// + /// Weight: `O(1)` + #[pallet::call_index(31)] + pub fn block( + origin: OriginFor, + id: T::AssetIdParameter, + who: AccountIdLookupOf, + ) -> DispatchResult { + let origin = ensure_signed(origin)?; + let id: T::AssetId = id.into(); + + let d = Asset::::get(id).ok_or(Error::::Unknown)?; + ensure!( + d.status == AssetStatus::Live || d.status == AssetStatus::Frozen, + Error::::AssetNotLive + ); + ensure!(origin == d.freezer, Error::::NoPermission); + let who = T::Lookup::lookup(who)?; + + Account::::try_mutate(id, &who, |maybe_account| -> DispatchResult { + maybe_account.as_mut().ok_or(Error::::NoAccount)?.status = + AccountStatus::Blocked; + Ok(()) + })?; + + Self::deposit_event(Event::::Blocked { asset_id: id, who }); + Ok(()) + } + } + + /// Implements [AccountTouch] trait. + /// Note that a depositor can be any account, without any specific privilege. + /// This implementation is supposed to be used only for creation of system accounts. + impl, I: 'static> AccountTouch for Pallet { + type Balance = DepositBalanceOf; + + fn deposit_required() -> Self::Balance { + T::AssetAccountDeposit::get() + } + + fn touch(asset: T::AssetId, who: T::AccountId, depositor: T::AccountId) -> DispatchResult { + Self::do_touch(asset, who, depositor, false) + } } } diff --git a/frame/assets/src/migration.rs b/frame/assets/src/migration.rs index 71da8823e92ef..90400ef5bd1dc 100644 --- a/frame/assets/src/migration.rs +++ b/frame/assets/src/migration.rs @@ -122,7 +122,10 @@ pub mod v1 { ); Asset::::iter().for_each(|(_id, asset)| { - assert!(asset.status == AssetStatus::Live || asset.status == AssetStatus::Frozen, "assets should only be live or frozen. None should be in destroying status, or undefined state") + assert!( + asset.status == AssetStatus::Live || asset.status == AssetStatus::Frozen, + "assets should only be live or frozen. None should be in destroying status, or undefined state" + ) }); Ok(()) } diff --git a/frame/assets/src/tests.rs b/frame/assets/src/tests.rs index 88ba92d0685a9..009d0180f36bc 100644 --- a/frame/assets/src/tests.rs +++ b/frame/assets/src/tests.rs @@ -34,6 +34,12 @@ fn asset_ids() -> Vec { s } +/// returns tuple of asset's account and sufficient counts +fn asset_account_counts(asset_id: u32) -> (u32, u32) { + let asset = Asset::::get(asset_id).unwrap(); + (asset.accounts, asset.sufficients) +} + #[test] fn transfer_should_never_burn() { new_test_ext().execute_with(|| { @@ -154,9 +160,11 @@ fn refunding_asset_deposit_without_burn_should_work() { assert_eq!(Assets::balance(0, 2), 100); assert_eq!(Assets::balance(0, 1), 0); assert_eq!(Balances::reserved_balance(&1), 10); + assert_eq!(asset_account_counts(0), (2, 0)); assert_ok!(Assets::refund(RuntimeOrigin::signed(1), 0, false)); assert_eq!(Balances::reserved_balance(&1), 0); assert_eq!(Assets::balance(1, 0), 0); + assert_eq!(asset_account_counts(0), (1, 0)); }); } @@ -176,6 +184,99 @@ fn refunding_calls_died_hook() { }); } +#[test] +fn refunding_with_sufficient_existence_reason_should_fail() { + new_test_ext().execute_with(|| { + // create sufficient asset + assert_ok!(Assets::force_create(RuntimeOrigin::root(), 0, 1, true, 1)); + assert_ok!(Assets::mint(RuntimeOrigin::signed(1), 0, 1, 100)); + // create an asset account with sufficient existence reason + // by transferring some sufficient assets + assert_ok!(Assets::transfer(RuntimeOrigin::signed(1), 0, 2, 50)); + assert_eq!(Assets::balance(0, 1), 50); + assert_eq!(Assets::balance(0, 2), 50); + assert_eq!(asset_account_counts(0), (2, 2)); + // fails to refund + assert_noop!(Assets::refund(RuntimeOrigin::signed(2), 0, true), Error::::NoDeposit); + }); +} + +#[test] +fn refunding_with_deposit_from_should_fail() { + new_test_ext().execute_with(|| { + assert_ok!(Assets::force_create(RuntimeOrigin::root(), 0, 1, false, 1)); + Balances::make_free_balance_be(&1, 100); + // create asset account `2` with deposit from `1` + assert_ok!(Assets::touch_other(RuntimeOrigin::signed(1), 0, 2)); + assert_eq!(Balances::reserved_balance(&1), 10); + // fails to refund + assert_noop!(Assets::refund(RuntimeOrigin::signed(2), 0, true), Error::::NoDeposit); + assert!(Account::::contains_key(0, &2)); + }); +} + +#[test] +fn refunding_frozen_with_consumer_ref_works() { + new_test_ext().execute_with(|| { + // 1 will be an admin + // 2 will be a frozen account + Balances::make_free_balance_be(&1, 100); + Balances::make_free_balance_be(&2, 100); + // create non-sufficient asset + assert_ok!(Assets::force_create(RuntimeOrigin::root(), 0, 1, false, 1)); + assert_ok!(Assets::mint(RuntimeOrigin::signed(1), 0, 1, 100)); + assert_eq!(System::consumers(&2), 0); + // create asset account `2` with a consumer reference by transferring + // non-sufficient funds into + assert_ok!(Assets::transfer(RuntimeOrigin::signed(1), 0, 2, 50)); + assert_eq!(System::consumers(&2), 1); + assert_eq!(Assets::balance(0, 1), 50); + assert_eq!(Assets::balance(0, 2), 50); + assert_eq!(asset_account_counts(0), (2, 0)); + // freeze asset account `2` and asset `0` + assert_ok!(Assets::freeze(RuntimeOrigin::signed(1), 0, 2)); + assert_ok!(Assets::freeze_asset(RuntimeOrigin::signed(1), 0)); + // refund works + assert_ok!(Assets::refund(RuntimeOrigin::signed(2), 0, true)); + assert!(!Account::::contains_key(0, &2)); + assert_eq!(System::consumers(&2), 0); + assert_eq!(asset_account_counts(0), (1, 0)); + }); +} + +#[test] +fn refunding_frozen_with_deposit_works() { + new_test_ext().execute_with(|| { + // 1 will be an asset admin + // 2 will be a frozen account + Balances::make_free_balance_be(&1, 100); + Balances::make_free_balance_be(&2, 100); + assert_ok!(Assets::force_create(RuntimeOrigin::root(), 0, 1, false, 1)); + assert_ok!(Assets::mint(RuntimeOrigin::signed(1), 0, 1, 100)); + assert_eq!(System::consumers(&2), 0); + assert_ok!(Assets::touch(RuntimeOrigin::signed(2), 0)); + // reserve deposit holds one consumer ref + assert_eq!(System::consumers(&2), 1); + assert_eq!(Balances::reserved_balance(&2), 10); + assert!(Account::::contains_key(0, &2)); + // transfer some assets to `2` + assert_ok!(Assets::transfer(RuntimeOrigin::signed(1), 0, 2, 50)); + assert_eq!(System::consumers(&2), 1); + assert_eq!(Assets::balance(0, 1), 50); + assert_eq!(Assets::balance(0, 2), 50); + assert_eq!(asset_account_counts(0), (2, 0)); + // ensure refundable even if asset account and asset is frozen + assert_ok!(Assets::freeze(RuntimeOrigin::signed(1), 0, 2)); + assert_ok!(Assets::freeze_asset(RuntimeOrigin::signed(1), 0)); + // success + assert_ok!(Assets::refund(RuntimeOrigin::signed(2), 0, true)); + assert!(!Account::::contains_key(0, &2)); + assert_eq!(Balances::reserved_balance(&2), 0); + assert_eq!(System::consumers(&2), 0); + assert_eq!(asset_account_counts(0), (1, 0)); + }); +} + #[test] fn approval_lifecycle_works() { new_test_ext().execute_with(|| { @@ -637,6 +738,37 @@ fn approve_transfer_frozen_asset_should_not_work() { }); } +#[test] +fn transferring_from_blocked_account_should_not_work() { + new_test_ext().execute_with(|| { + assert_ok!(Assets::force_create(RuntimeOrigin::root(), 0, 1, true, 1)); + assert_ok!(Assets::mint(RuntimeOrigin::signed(1), 0, 1, 100)); + assert_eq!(Assets::balance(0, 1), 100); + assert_ok!(Assets::block(RuntimeOrigin::signed(1), 0, 1)); + // behaves as frozen when transferring from blocked + assert_noop!(Assets::transfer(RuntimeOrigin::signed(1), 0, 2, 50), Error::::Frozen); + assert_ok!(Assets::thaw(RuntimeOrigin::signed(1), 0, 1)); + assert_ok!(Assets::transfer(RuntimeOrigin::signed(1), 0, 2, 50)); + assert_ok!(Assets::transfer(RuntimeOrigin::signed(2), 0, 1, 50)); + }); +} + +#[test] +fn transferring_to_blocked_account_should_not_work() { + new_test_ext().execute_with(|| { + assert_ok!(Assets::force_create(RuntimeOrigin::root(), 0, 1, true, 1)); + assert_ok!(Assets::mint(RuntimeOrigin::signed(1), 0, 1, 100)); + assert_ok!(Assets::mint(RuntimeOrigin::signed(1), 0, 2, 100)); + assert_eq!(Assets::balance(0, 1), 100); + assert_eq!(Assets::balance(0, 2), 100); + assert_ok!(Assets::block(RuntimeOrigin::signed(1), 0, 1)); + assert_noop!(Assets::transfer(RuntimeOrigin::signed(2), 0, 1, 50), TokenError::Blocked); + assert_ok!(Assets::thaw(RuntimeOrigin::signed(1), 0, 1)); + assert_ok!(Assets::transfer(RuntimeOrigin::signed(2), 0, 1, 50)); + assert_ok!(Assets::transfer(RuntimeOrigin::signed(1), 0, 2, 50)); + }); +} + #[test] fn origin_guards_should_work() { new_test_ext().execute_with(|| { @@ -719,7 +851,7 @@ fn set_team_should_work() { } #[test] -fn transferring_to_frozen_account_should_work() { +fn transferring_from_frozen_account_should_not_work() { new_test_ext().execute_with(|| { assert_ok!(Assets::force_create(RuntimeOrigin::root(), 0, 1, true, 1)); assert_ok!(Assets::mint(RuntimeOrigin::signed(1), 0, 1, 100)); @@ -727,11 +859,226 @@ fn transferring_to_frozen_account_should_work() { assert_eq!(Assets::balance(0, 1), 100); assert_eq!(Assets::balance(0, 2), 100); assert_ok!(Assets::freeze(RuntimeOrigin::signed(1), 0, 2)); + // can transfer to `2` assert_ok!(Assets::transfer(RuntimeOrigin::signed(1), 0, 2, 50)); + // cannot transfer from `2` + assert_noop!(Assets::transfer(RuntimeOrigin::signed(2), 0, 1, 25), Error::::Frozen); + assert_eq!(Assets::balance(0, 1), 50); assert_eq!(Assets::balance(0, 2), 150); }); } +#[test] +fn touching_and_freezing_account_with_zero_asset_balance_should_work() { + new_test_ext().execute_with(|| { + // need some deposit for the touch + Balances::make_free_balance_be(&2, 100); + assert_ok!(Assets::force_create(RuntimeOrigin::root(), 0, 1, true, 1)); + assert_ok!(Assets::mint(RuntimeOrigin::signed(1), 0, 1, 100)); + assert_eq!(Assets::balance(0, 1), 100); + assert_eq!(Assets::balance(0, 2), 0); + // cannot freeze an account that doesn't have an `Assets` entry + assert_noop!(Assets::freeze(RuntimeOrigin::signed(1), 0, 2), Error::::NoAccount); + assert_ok!(Assets::touch(RuntimeOrigin::signed(2), 0)); + // now it can be frozen + assert_ok!(Assets::freeze(RuntimeOrigin::signed(1), 0, 2)); + // can transfer to `2` even though its frozen + assert_ok!(Assets::transfer(RuntimeOrigin::signed(1), 0, 2, 50)); + // cannot transfer from `2` + assert_noop!(Assets::transfer(RuntimeOrigin::signed(2), 0, 1, 25), Error::::Frozen); + assert_eq!(Assets::balance(0, 1), 50); + assert_eq!(Assets::balance(0, 2), 50); + }); +} + +#[test] +fn touch_other_works() { + new_test_ext().execute_with(|| { + // 1 will be admin + // 2 will be freezer + // 4 will be an account attempting to execute `touch_other` + Balances::make_free_balance_be(&1, 100); + Balances::make_free_balance_be(&2, 100); + Balances::make_free_balance_be(&4, 100); + assert_ok!(Assets::force_create(RuntimeOrigin::root(), 0, 1, false, 1)); + assert_ok!(Assets::set_team(RuntimeOrigin::signed(1), 0, 1, 1, 2)); + assert_ok!(Assets::mint(RuntimeOrigin::signed(1), 0, 1, 100)); + assert_eq!(Assets::balance(0, 1), 100); + // account `3` does not exist + assert!(!Account::::contains_key(0, &3)); + // creation of asset account `3` by account `4` fails + assert_noop!( + Assets::touch_other(RuntimeOrigin::signed(4), 0, 3), + Error::::NoPermission + ); + // creation of asset account `3` by admin `1` works + assert!(!Account::::contains_key(0, &3)); + assert_ok!(Assets::touch_other(RuntimeOrigin::signed(1), 0, 3)); + assert!(Account::::contains_key(0, &3)); + // creation of asset account `4` by freezer `2` works + assert!(!Account::::contains_key(0, &4)); + assert_ok!(Assets::touch_other(RuntimeOrigin::signed(2), 0, 4)); + assert!(Account::::contains_key(0, &4)); + }); +} + +#[test] +fn touch_other_and_freeze_works() { + new_test_ext().execute_with(|| { + Balances::make_free_balance_be(&1, 100); + assert_ok!(Assets::force_create(RuntimeOrigin::root(), 0, 1, true, 1)); + assert_ok!(Assets::mint(RuntimeOrigin::signed(1), 0, 1, 100)); + assert_eq!(Assets::balance(0, 1), 100); + // account `2` does not exist + assert!(!Account::::contains_key(0, &2)); + // create account `2` with touch_other + assert_ok!(Assets::touch_other(RuntimeOrigin::signed(1), 0, 2)); + assert!(Account::::contains_key(0, &2)); + // now it can be frozen + assert_ok!(Assets::freeze(RuntimeOrigin::signed(1), 0, 2)); + // can transfer to `2` even though its frozen + assert_ok!(Assets::transfer(RuntimeOrigin::signed(1), 0, 2, 50)); + // cannot transfer from `2` + assert_noop!(Assets::transfer(RuntimeOrigin::signed(2), 0, 1, 25), Error::::Frozen); + assert_eq!(Assets::balance(0, 1), 50); + assert_eq!(Assets::balance(0, 2), 50); + }); +} + +#[test] +fn account_with_deposit_not_destroyed() { + new_test_ext().execute_with(|| { + // 1 will be the asset admin + // 2 will exist without balance but with deposit + Balances::make_free_balance_be(&1, 100); + Balances::make_free_balance_be(&2, 100); + assert_ok!(Assets::force_create(RuntimeOrigin::root(), 0, 1, false, 1)); + assert_ok!(Assets::mint(RuntimeOrigin::signed(1), 0, 1, 100)); + assert_eq!(Assets::balance(0, 1), 100); + assert_eq!(Assets::balance(0, 2), 0); + // case 1; account `2` not destroyed with a holder's deposit + assert_ok!(Assets::touch(RuntimeOrigin::signed(2), 0)); + assert_eq!(Balances::reserved_balance(&2), 10); + assert!(Account::::contains_key(0, &2)); + assert_ok!(Assets::transfer(RuntimeOrigin::signed(1), 0, 2, 50)); + assert_ok!(Assets::transfer(RuntimeOrigin::signed(2), 0, 1, 50)); + assert_eq!(Assets::balance(0, 2), 0); + assert!(Account::::contains_key(0, &2)); + + // destroy account `2` + assert_ok!(Assets::refund(RuntimeOrigin::signed(2), 0, false)); + assert!(!Account::::contains_key(0, &2)); + + // case 2; account `2` not destroyed with a deposit from `1` + assert_ok!(Assets::touch_other(RuntimeOrigin::signed(1), 0, 2)); + assert_eq!(Balances::reserved_balance(&1), 10); + assert_ok!(Assets::transfer(RuntimeOrigin::signed(1), 0, 2, 50)); + assert_ok!(Assets::transfer(RuntimeOrigin::signed(2), 0, 1, 50)); + assert!(Account::::contains_key(0, &2)); + }); +} + +#[test] +fn refund_other_should_fails() { + new_test_ext().execute_with(|| { + // 1 will be the asset admin + // 2 will be the asset freezer + // 3 will be created with deposit of 2 + Balances::make_free_balance_be(&1, 100); + Balances::make_free_balance_be(&2, 100); + Balances::make_free_balance_be(&3, 0); + assert_ok!(Assets::force_create(RuntimeOrigin::root(), 0, 1, true, 1)); + assert_ok!(Assets::set_team(RuntimeOrigin::signed(1), 0, 1, 1, 2)); + assert!(!Account::::contains_key(0, &3)); + + // create asset account `3` with a deposit from freezer `2` + assert_ok!(Assets::touch_other(RuntimeOrigin::signed(2), 0, 3)); + assert_eq!(Balances::reserved_balance(&2), 10); + + // fail case; non-existing asset account `10` + assert_noop!( + Assets::refund_other(RuntimeOrigin::signed(2), 0, 10), + Error::::NoDeposit + ); + // fail case; non-existing asset `3` + assert_noop!( + Assets::refund_other(RuntimeOrigin::signed(2), 1, 3), + Error::::NoDeposit + ); + // fail case; no `DepositFrom` for asset account `1` + assert_noop!( + Assets::refund_other(RuntimeOrigin::signed(2), 0, 1), + Error::::NoDeposit + ); + // fail case; asset `0` is frozen + assert_ok!(Assets::freeze_asset(RuntimeOrigin::signed(2), 0)); + assert_noop!( + Assets::refund_other(RuntimeOrigin::signed(2), 0, 3), + Error::::AssetNotLive + ); + assert_ok!(Assets::thaw_asset(RuntimeOrigin::signed(1), 0)); + // fail case; asset `1` is being destroyed + assert_ok!(Assets::force_create(RuntimeOrigin::root(), 10, 1, true, 1)); + assert_ok!(Assets::touch_other(RuntimeOrigin::signed(1), 10, 3)); + assert_ok!(Assets::start_destroy(RuntimeOrigin::signed(1), 10)); + assert_noop!( + Assets::refund_other(RuntimeOrigin::signed(2), 10, 3), + Error::::AssetNotLive + ); + assert_ok!(Assets::destroy_accounts(RuntimeOrigin::signed(1), 10)); + assert_ok!(Assets::finish_destroy(RuntimeOrigin::signed(1), 10)); + // fail case; account is frozen + assert_ok!(Assets::freeze(RuntimeOrigin::signed(2), 0, 3)); + assert_noop!(Assets::refund_other(RuntimeOrigin::signed(2), 0, 3), Error::::Frozen); + assert_ok!(Assets::thaw(RuntimeOrigin::signed(1), 0, 3)); + // fail case; not a freezer or an admin + assert_noop!( + Assets::refund_other(RuntimeOrigin::signed(4), 0, 3), + Error::::NoPermission + ); + // fail case; would burn + assert_ok!(Assets::mint(RuntimeOrigin::signed(1), 0, 3, 100)); + assert_noop!( + Assets::refund_other(RuntimeOrigin::signed(1), 0, 3), + Error::::WouldBurn + ); + assert_ok!(Assets::burn(RuntimeOrigin::signed(1), 0, 3, 100)); + }) +} + +#[test] +fn refund_other_works() { + new_test_ext().execute_with(|| { + // 1 will be the asset admin + // 2 will be the asset freezer + // 3 will be created with deposit of 2 + Balances::make_free_balance_be(&1, 100); + Balances::make_free_balance_be(&2, 100); + assert_ok!(Assets::force_create(RuntimeOrigin::root(), 0, 1, true, 1)); + assert_ok!(Assets::set_team(RuntimeOrigin::signed(1), 0, 1, 1, 2)); + assert!(!Account::::contains_key(0, &3)); + assert_eq!(asset_account_counts(0), (0, 0)); + + // success case; freezer is depositor + assert_ok!(Assets::touch_other(RuntimeOrigin::signed(2), 0, 3)); + assert_eq!(Balances::reserved_balance(&2), 10); + assert_eq!(asset_account_counts(0), (1, 0)); + assert_ok!(Assets::refund_other(RuntimeOrigin::signed(2), 0, 3)); + assert_eq!(Balances::reserved_balance(&2), 0); + assert!(!Account::::contains_key(0, &3)); + assert_eq!(asset_account_counts(0), (0, 0)); + + // success case; admin is depositor + assert_ok!(Assets::touch_other(RuntimeOrigin::signed(1), 0, 3)); + assert_eq!(Balances::reserved_balance(&1), 10); + assert_eq!(asset_account_counts(0), (1, 0)); + assert_ok!(Assets::refund_other(RuntimeOrigin::signed(1), 0, 3)); + assert_eq!(Balances::reserved_balance(&1), 0); + assert!(!Account::::contains_key(0, &3)); + assert_eq!(asset_account_counts(0), (0, 0)); + }) +} + #[test] fn transferring_amount_more_than_available_balance_should_not_work() { new_test_ext().execute_with(|| { diff --git a/frame/assets/src/types.rs b/frame/assets/src/types.rs index c83e764f4a68d..559afccb946c5 100644 --- a/frame/assets/src/types.rs +++ b/frame/assets/src/types.rs @@ -26,8 +26,14 @@ use sp_runtime::{traits::Convert, FixedPointNumber, FixedPointOperand, FixedU128 pub(super) type DepositBalanceOf = <>::Currency as Currency<::AccountId>>::Balance; -pub(super) type AssetAccountOf = - AssetAccount<>::Balance, DepositBalanceOf, >::Extra>; +pub(super) type AssetAccountOf = AssetAccount< + >::Balance, + DepositBalanceOf, + >::Extra, + ::AccountId, +>; +pub(super) type ExistenceReasonOf = + ExistenceReason, ::AccountId>; /// AssetStatus holds the current state of the asset. It could either be Live and available for use, /// or in a Destroying state. @@ -83,23 +89,35 @@ pub struct Approval { #[test] fn ensure_bool_decodes_to_consumer_or_sufficient() { - assert_eq!(false.encode(), ExistenceReason::<()>::Consumer.encode()); - assert_eq!(true.encode(), ExistenceReason::<()>::Sufficient.encode()); + assert_eq!(false.encode(), ExistenceReason::<(), ()>::Consumer.encode()); + assert_eq!(true.encode(), ExistenceReason::<(), ()>::Sufficient.encode()); } +/// The reason for an account's existence within an asset class. #[derive(Clone, Encode, Decode, Eq, PartialEq, RuntimeDebug, MaxEncodedLen, TypeInfo)] -pub enum ExistenceReason { +pub enum ExistenceReason { + /// A consumer reference was used to create this account. #[codec(index = 0)] Consumer, + /// The asset class is `sufficient` for account existence. #[codec(index = 1)] Sufficient, + /// The account holder has placed a deposit to exist within an asset class. #[codec(index = 2)] DepositHeld(Balance), + /// A deposit was placed for this account to exist, but it has been refunded. #[codec(index = 3)] DepositRefunded, + /// Some other `AccountId` has placed a deposit to make this account exist. + /// An account with such a reason might not be referenced in `system`. + #[codec(index = 4)] + DepositFrom(AccountId, Balance), } -impl ExistenceReason { +impl ExistenceReason +where + AccountId: Clone, +{ pub(crate) fn take_deposit(&mut self) -> Option { if !matches!(self, ExistenceReason::DepositHeld(_)) { return None @@ -112,16 +130,56 @@ impl ExistenceReason { None } } + + pub(crate) fn take_deposit_from(&mut self) -> Option<(AccountId, Balance)> { + if !matches!(self, ExistenceReason::DepositFrom(..)) { + return None + } + if let ExistenceReason::DepositFrom(depositor, deposit) = + sp_std::mem::replace(self, ExistenceReason::DepositRefunded) + { + Some((depositor, deposit)) + } else { + None + } + } } +#[test] +fn ensure_bool_decodes_to_liquid_or_frozen() { + assert_eq!(false.encode(), AccountStatus::Liquid.encode()); + assert_eq!(true.encode(), AccountStatus::Frozen.encode()); +} + +/// The status of an asset account. #[derive(Clone, Encode, Decode, Eq, PartialEq, RuntimeDebug, MaxEncodedLen, TypeInfo)] -pub struct AssetAccount { +pub enum AccountStatus { + /// Asset account can receive and transfer the assets. + Liquid, + /// Asset account cannot transfer the assets. + Frozen, + /// Asset account cannot receive and transfer the assets. + Blocked, +} +impl AccountStatus { + /// Returns `true` if frozen or blocked. + pub(crate) fn is_frozen(&self) -> bool { + matches!(self, AccountStatus::Frozen | AccountStatus::Blocked) + } + /// Returns `true` if blocked. + pub(crate) fn is_blocked(&self) -> bool { + matches!(self, AccountStatus::Blocked) + } +} + +#[derive(Clone, Encode, Decode, Eq, PartialEq, RuntimeDebug, MaxEncodedLen, TypeInfo)] +pub struct AssetAccount { /// The balance. pub(super) balance: Balance, - /// Whether the account is frozen. - pub(super) is_frozen: bool, + /// The status of the account. + pub(super) status: AccountStatus, /// The reason for the existence of the account. - pub(super) reason: ExistenceReason, + pub(super) reason: ExistenceReason, /// Additional "sidecar" data, in case some other pallet wants to use this storage item. pub(super) extra: Extra, } diff --git a/frame/assets/src/weights.rs b/frame/assets/src/weights.rs index 4cc90e25f43fa..76ac585ff41f8 100644 --- a/frame/assets/src/weights.rs +++ b/frame/assets/src/weights.rs @@ -18,33 +18,35 @@ //! Autogenerated weights for pallet_assets //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-04-06, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-05-01, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `bm2`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` +//! HOSTNAME: `bm3`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: -// ./target/production/substrate +// target/production/substrate // benchmark // pallet -// --chain=dev // --steps=50 // --repeat=20 -// --pallet=pallet_assets // --extrinsic=* // --execution=wasm // --wasm-execution=compiled // --heap-pages=4096 -// --output=./frame/assets/src/weights.rs +// --json-file=/var/lib/gitlab-runner/builds/zyw4fam_/0/parity/mirrors/substrate/.git/.artifacts/bench.json +// --pallet=pallet_assets +// --chain=dev // --header=./HEADER-APACHE2 +// --output=./frame/assets/src/weights.rs // --template=./.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] #![allow(unused_imports)] +#![allow(missing_docs)] use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; -use sp_std::marker::PhantomData; +use core::marker::PhantomData; /// Weight functions needed for pallet_assets. pub trait WeightInfo { @@ -75,6 +77,11 @@ pub trait WeightInfo { fn cancel_approval() -> Weight; fn force_cancel_approval() -> Weight; fn set_min_balance() -> Weight; + fn touch() -> Weight; + fn touch_other() -> Weight; + fn refund() -> Weight; + fn refund_other() -> Weight; + fn block() -> Weight; } /// Weights for pallet_assets using the Substrate node and recommended hardware. @@ -88,8 +95,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `293` // Estimated: `3675` - // Minimum execution time: 33_678_000 picoseconds. - Weight::from_parts(34_320_000, 3675) + // Minimum execution time: 31_668_000 picoseconds. + Weight::from_parts(32_079_000, 3675) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -99,8 +106,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `153` // Estimated: `3675` - // Minimum execution time: 15_521_000 picoseconds. - Weight::from_parts(16_035_000, 3675) + // Minimum execution time: 14_885_000 picoseconds. + Weight::from_parts(15_358_000, 3675) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -110,31 +117,31 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `385` // Estimated: `3675` - // Minimum execution time: 15_921_000 picoseconds. - Weight::from_parts(16_153_000, 3675) + // Minimum execution time: 15_295_000 picoseconds. + Weight::from_parts(15_639_000, 3675) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } /// Storage: Assets Asset (r:1 w:1) /// Proof: Assets Asset (max_values: None, max_size: Some(210), added: 2685, mode: MaxEncodedLen) /// Storage: Assets Account (r:1001 w:1000) - /// Proof: Assets Account (max_values: None, max_size: Some(102), added: 2577, mode: MaxEncodedLen) + /// Proof: Assets Account (max_values: None, max_size: Some(134), added: 2609, mode: MaxEncodedLen) /// Storage: System Account (r:1000 w:1000) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) /// The range of component `c` is `[0, 1000]`. fn destroy_accounts(c: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0 + c * (208 ±0)` - // Estimated: `3675 + c * (2603 ±0)` - // Minimum execution time: 21_242_000 picoseconds. - Weight::from_parts(21_532_000, 3675) - // Standard Error: 6_449 - .saturating_add(Weight::from_parts(13_150_845, 0).saturating_mul(c.into())) + // Estimated: `3675 + c * (2609 ±0)` + // Minimum execution time: 19_916_000 picoseconds. + Weight::from_parts(20_220_000, 3675) + // Standard Error: 7_298 + .saturating_add(Weight::from_parts(12_553_976, 0).saturating_mul(c.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().reads((2_u64).saturating_mul(c.into()))) .saturating_add(T::DbWeight::get().writes(1_u64)) .saturating_add(T::DbWeight::get().writes((2_u64).saturating_mul(c.into()))) - .saturating_add(Weight::from_parts(0, 2603).saturating_mul(c.into())) + .saturating_add(Weight::from_parts(0, 2609).saturating_mul(c.into())) } /// Storage: Assets Asset (r:1 w:1) /// Proof: Assets Asset (max_values: None, max_size: Some(210), added: 2685, mode: MaxEncodedLen) @@ -145,10 +152,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `522 + a * (86 ±0)` // Estimated: `3675 + a * (2623 ±0)` - // Minimum execution time: 21_604_000 picoseconds. - Weight::from_parts(21_881_000, 3675) - // Standard Error: 4_225 - .saturating_add(Weight::from_parts(15_968_205, 0).saturating_mul(a.into())) + // Minimum execution time: 20_322_000 picoseconds. + Weight::from_parts(20_744_000, 3675) + // Standard Error: 12_314 + .saturating_add(Weight::from_parts(14_767_353, 0).saturating_mul(a.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(a.into()))) .saturating_add(T::DbWeight::get().writes(1_u64)) @@ -163,105 +170,105 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `351` // Estimated: `3675` - // Minimum execution time: 16_465_000 picoseconds. - Weight::from_parts(16_775_000, 3675) + // Minimum execution time: 15_668_000 picoseconds. + Weight::from_parts(16_016_000, 3675) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } /// Storage: Assets Asset (r:1 w:1) /// Proof: Assets Asset (max_values: None, max_size: Some(210), added: 2685, mode: MaxEncodedLen) /// Storage: Assets Account (r:1 w:1) - /// Proof: Assets Account (max_values: None, max_size: Some(102), added: 2577, mode: MaxEncodedLen) + /// Proof: Assets Account (max_values: None, max_size: Some(134), added: 2609, mode: MaxEncodedLen) fn mint() -> Weight { // Proof Size summary in bytes: // Measured: `351` // Estimated: `3675` - // Minimum execution time: 30_709_000 picoseconds. - Weight::from_parts(31_159_000, 3675) + // Minimum execution time: 28_227_000 picoseconds. + Weight::from_parts(28_769_000, 3675) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } /// Storage: Assets Asset (r:1 w:1) /// Proof: Assets Asset (max_values: None, max_size: Some(210), added: 2685, mode: MaxEncodedLen) /// Storage: Assets Account (r:1 w:1) - /// Proof: Assets Account (max_values: None, max_size: Some(102), added: 2577, mode: MaxEncodedLen) + /// Proof: Assets Account (max_values: None, max_size: Some(134), added: 2609, mode: MaxEncodedLen) fn burn() -> Weight { // Proof Size summary in bytes: // Measured: `459` // Estimated: `3675` - // Minimum execution time: 36_944_000 picoseconds. - Weight::from_parts(38_166_000, 3675) + // Minimum execution time: 34_672_000 picoseconds. + Weight::from_parts(34_902_000, 3675) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } /// Storage: Assets Asset (r:1 w:1) /// Proof: Assets Asset (max_values: None, max_size: Some(210), added: 2685, mode: MaxEncodedLen) /// Storage: Assets Account (r:2 w:2) - /// Proof: Assets Account (max_values: None, max_size: Some(102), added: 2577, mode: MaxEncodedLen) + /// Proof: Assets Account (max_values: None, max_size: Some(134), added: 2609, mode: MaxEncodedLen) /// Storage: System Account (r:1 w:1) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn transfer() -> Weight { // Proof Size summary in bytes: // Measured: `498` - // Estimated: `6144` - // Minimum execution time: 52_497_000 picoseconds. - Weight::from_parts(53_147_000, 6144) + // Estimated: `6208` + // Minimum execution time: 49_003_000 picoseconds. + Weight::from_parts(49_345_000, 6208) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } /// Storage: Assets Asset (r:1 w:1) /// Proof: Assets Asset (max_values: None, max_size: Some(210), added: 2685, mode: MaxEncodedLen) /// Storage: Assets Account (r:2 w:2) - /// Proof: Assets Account (max_values: None, max_size: Some(102), added: 2577, mode: MaxEncodedLen) + /// Proof: Assets Account (max_values: None, max_size: Some(134), added: 2609, mode: MaxEncodedLen) /// Storage: System Account (r:1 w:1) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn transfer_keep_alive() -> Weight { // Proof Size summary in bytes: // Measured: `498` - // Estimated: `6144` - // Minimum execution time: 46_203_000 picoseconds. - Weight::from_parts(46_853_000, 6144) + // Estimated: `6208` + // Minimum execution time: 43_429_000 picoseconds. + Weight::from_parts(43_936_000, 6208) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } /// Storage: Assets Asset (r:1 w:1) /// Proof: Assets Asset (max_values: None, max_size: Some(210), added: 2685, mode: MaxEncodedLen) /// Storage: Assets Account (r:2 w:2) - /// Proof: Assets Account (max_values: None, max_size: Some(102), added: 2577, mode: MaxEncodedLen) + /// Proof: Assets Account (max_values: None, max_size: Some(134), added: 2609, mode: MaxEncodedLen) /// Storage: System Account (r:1 w:1) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn force_transfer() -> Weight { // Proof Size summary in bytes: // Measured: `498` - // Estimated: `6144` - // Minimum execution time: 52_911_000 picoseconds. - Weight::from_parts(55_511_000, 6144) + // Estimated: `6208` + // Minimum execution time: 49_177_000 picoseconds. + Weight::from_parts(49_548_000, 6208) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } /// Storage: Assets Asset (r:1 w:0) /// Proof: Assets Asset (max_values: None, max_size: Some(210), added: 2685, mode: MaxEncodedLen) /// Storage: Assets Account (r:1 w:1) - /// Proof: Assets Account (max_values: None, max_size: Some(102), added: 2577, mode: MaxEncodedLen) + /// Proof: Assets Account (max_values: None, max_size: Some(134), added: 2609, mode: MaxEncodedLen) fn freeze() -> Weight { // Proof Size summary in bytes: // Measured: `459` // Estimated: `3675` - // Minimum execution time: 20_308_000 picoseconds. - Weight::from_parts(20_524_000, 3675) + // Minimum execution time: 19_323_000 picoseconds. + Weight::from_parts(19_945_000, 3675) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } /// Storage: Assets Asset (r:1 w:0) /// Proof: Assets Asset (max_values: None, max_size: Some(210), added: 2685, mode: MaxEncodedLen) /// Storage: Assets Account (r:1 w:1) - /// Proof: Assets Account (max_values: None, max_size: Some(102), added: 2577, mode: MaxEncodedLen) + /// Proof: Assets Account (max_values: None, max_size: Some(134), added: 2609, mode: MaxEncodedLen) fn thaw() -> Weight { // Proof Size summary in bytes: // Measured: `459` // Estimated: `3675` - // Minimum execution time: 20_735_000 picoseconds. - Weight::from_parts(21_026_000, 3675) + // Minimum execution time: 19_543_000 picoseconds. + Weight::from_parts(19_747_000, 3675) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -271,8 +278,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `385` // Estimated: `3675` - // Minimum execution time: 16_148_000 picoseconds. - Weight::from_parts(16_404_000, 3675) + // Minimum execution time: 15_623_000 picoseconds. + Weight::from_parts(15_833_000, 3675) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -282,8 +289,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `385` // Estimated: `3675` - // Minimum execution time: 16_075_000 picoseconds. - Weight::from_parts(16_542_000, 3675) + // Minimum execution time: 15_396_000 picoseconds. + Weight::from_parts(15_704_000, 3675) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -295,8 +302,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `351` // Estimated: `3675` - // Minimum execution time: 17_866_000 picoseconds. - Weight::from_parts(18_129_000, 3675) + // Minimum execution time: 17_205_000 picoseconds. + Weight::from_parts(17_546_000, 3675) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -306,8 +313,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `351` // Estimated: `3675` - // Minimum execution time: 16_637_000 picoseconds. - Weight::from_parts(16_918_000, 3675) + // Minimum execution time: 16_049_000 picoseconds. + Weight::from_parts(16_317_000, 3675) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -317,14 +324,16 @@ impl WeightInfo for SubstrateWeight { /// Proof: Assets Metadata (max_values: None, max_size: Some(140), added: 2615, mode: MaxEncodedLen) /// The range of component `n` is `[0, 50]`. /// The range of component `s` is `[0, 50]`. - fn set_metadata(_n: u32, s: u32, ) -> Weight { + fn set_metadata(n: u32, s: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `351` // Estimated: `3675` - // Minimum execution time: 33_304_000 picoseconds. - Weight::from_parts(34_764_544, 3675) - // Standard Error: 634 - .saturating_add(Weight::from_parts(4_733, 0).saturating_mul(s.into())) + // Minimum execution time: 31_574_000 picoseconds. + Weight::from_parts(32_447_787, 3675) + // Standard Error: 904 + .saturating_add(Weight::from_parts(653, 0).saturating_mul(n.into())) + // Standard Error: 904 + .saturating_add(Weight::from_parts(271, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -336,8 +345,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `515` // Estimated: `3675` - // Minimum execution time: 33_640_000 picoseconds. - Weight::from_parts(34_100_000, 3675) + // Minimum execution time: 31_865_000 picoseconds. + Weight::from_parts(32_160_000, 3675) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -351,12 +360,12 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `190` // Estimated: `3675` - // Minimum execution time: 16_549_000 picoseconds. - Weight::from_parts(17_337_982, 3675) - // Standard Error: 586 - .saturating_add(Weight::from_parts(4_584, 0).saturating_mul(n.into())) - // Standard Error: 586 - .saturating_add(Weight::from_parts(4_288, 0).saturating_mul(s.into())) + // Minimum execution time: 16_203_000 picoseconds. + Weight::from_parts(16_432_499, 3675) + // Standard Error: 1_563 + .saturating_add(Weight::from_parts(5_818, 0).saturating_mul(n.into())) + // Standard Error: 1_563 + .saturating_add(Weight::from_parts(9_660, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -368,8 +377,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `515` // Estimated: `3675` - // Minimum execution time: 34_183_000 picoseconds. - Weight::from_parts(34_577_000, 3675) + // Minimum execution time: 33_443_000 picoseconds. + Weight::from_parts(56_533_000, 3675) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -379,8 +388,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `351` // Estimated: `3675` - // Minimum execution time: 15_505_000 picoseconds. - Weight::from_parts(15_784_000, 3675) + // Minimum execution time: 20_636_000 picoseconds. + Weight::from_parts(23_960_000, 3675) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -392,8 +401,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `385` // Estimated: `3675` - // Minimum execution time: 38_762_000 picoseconds. - Weight::from_parts(39_138_000, 3675) + // Minimum execution time: 35_987_000 picoseconds. + Weight::from_parts(36_429_000, 3675) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -402,15 +411,15 @@ impl WeightInfo for SubstrateWeight { /// Storage: Assets Approvals (r:1 w:1) /// Proof: Assets Approvals (max_values: None, max_size: Some(148), added: 2623, mode: MaxEncodedLen) /// Storage: Assets Account (r:2 w:2) - /// Proof: Assets Account (max_values: None, max_size: Some(102), added: 2577, mode: MaxEncodedLen) + /// Proof: Assets Account (max_values: None, max_size: Some(134), added: 2609, mode: MaxEncodedLen) /// Storage: System Account (r:1 w:1) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn transfer_approved() -> Weight { // Proof Size summary in bytes: // Measured: `668` - // Estimated: `6144` - // Minimum execution time: 73_396_000 picoseconds. - Weight::from_parts(73_986_000, 6144) + // Estimated: `6208` + // Minimum execution time: 68_059_000 picoseconds. + Weight::from_parts(69_845_000, 6208) .saturating_add(T::DbWeight::get().reads(5_u64)) .saturating_add(T::DbWeight::get().writes(5_u64)) } @@ -422,8 +431,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `555` // Estimated: `3675` - // Minimum execution time: 39_707_000 picoseconds. - Weight::from_parts(40_222_000, 3675) + // Minimum execution time: 38_066_000 picoseconds. + Weight::from_parts(38_450_000, 3675) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -435,8 +444,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `555` // Estimated: `3675` - // Minimum execution time: 40_357_000 picoseconds. - Weight::from_parts(40_731_000, 3675) + // Minimum execution time: 38_500_000 picoseconds. + Weight::from_parts(38_953_000, 3675) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -446,11 +455,80 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `351` // Estimated: `3675` - // Minimum execution time: 16_937_000 picoseconds. - Weight::from_parts(17_219_000, 3675) + // Minimum execution time: 16_268_000 picoseconds. + Weight::from_parts(16_764_000, 3675) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } + /// Storage: Assets Account (r:1 w:1) + /// Proof: Assets Account (max_values: None, max_size: Some(134), added: 2609, mode: MaxEncodedLen) + /// Storage: Assets Asset (r:1 w:1) + /// Proof: Assets Asset (max_values: None, max_size: Some(210), added: 2685, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + fn touch() -> Weight { + // Proof Size summary in bytes: + // Measured: `453` + // Estimated: `3675` + // Minimum execution time: 37_468_000 picoseconds. + Weight::from_parts(37_957_000, 3675) + .saturating_add(T::DbWeight::get().reads(3_u64)) + .saturating_add(T::DbWeight::get().writes(3_u64)) + } + /// Storage: Assets Account (r:1 w:1) + /// Proof: Assets Account (max_values: None, max_size: Some(134), added: 2609, mode: MaxEncodedLen) + /// Storage: Assets Asset (r:1 w:1) + /// Proof: Assets Asset (max_values: None, max_size: Some(210), added: 2685, mode: MaxEncodedLen) + fn touch_other() -> Weight { + // Proof Size summary in bytes: + // Measured: `351` + // Estimated: `3675` + // Minimum execution time: 383_408_000 picoseconds. + Weight::from_parts(392_036_000, 3675) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(2)) + } + /// Storage: Assets Account (r:1 w:1) + /// Proof: Assets Account (max_values: None, max_size: Some(134), added: 2609, mode: MaxEncodedLen) + /// Storage: Assets Asset (r:1 w:1) + /// Proof: Assets Asset (max_values: None, max_size: Some(210), added: 2685, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + fn refund() -> Weight { + // Proof Size summary in bytes: + // Measured: `579` + // Estimated: `3675` + // Minimum execution time: 34_066_000 picoseconds. + Weight::from_parts(34_347_000, 3675) + .saturating_add(T::DbWeight::get().reads(3_u64)) + .saturating_add(T::DbWeight::get().writes(3_u64)) + } + /// Storage: Assets Account (r:1 w:1) + /// Proof: Assets Account (max_values: None, max_size: Some(134), added: 2609, mode: MaxEncodedLen) + /// Storage: Assets Asset (r:1 w:1) + /// Proof: Assets Asset (max_values: None, max_size: Some(210), added: 2685, mode: MaxEncodedLen) + fn refund_other() -> Weight { + // Proof Size summary in bytes: + // Measured: `510` + // Estimated: `3675` + // Minimum execution time: 32_060_000 picoseconds. + Weight::from_parts(32_519_000, 3675) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) + } + /// Storage: Assets Asset (r:1 w:0) + /// Proof: Assets Asset (max_values: None, max_size: Some(210), added: 2685, mode: MaxEncodedLen) + /// Storage: Assets Account (r:1 w:1) + /// Proof: Assets Account (max_values: None, max_size: Some(134), added: 2609, mode: MaxEncodedLen) + fn block() -> Weight { + // Proof Size summary in bytes: + // Measured: `459` + // Estimated: `3675` + // Minimum execution time: 115_000_000 picoseconds. + Weight::from_parts(163_000_000, 3675) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } } // For backwards compatibility and tests @@ -463,8 +541,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `293` // Estimated: `3675` - // Minimum execution time: 33_678_000 picoseconds. - Weight::from_parts(34_320_000, 3675) + // Minimum execution time: 31_668_000 picoseconds. + Weight::from_parts(32_079_000, 3675) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -474,8 +552,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `153` // Estimated: `3675` - // Minimum execution time: 15_521_000 picoseconds. - Weight::from_parts(16_035_000, 3675) + // Minimum execution time: 14_885_000 picoseconds. + Weight::from_parts(15_358_000, 3675) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -485,31 +563,31 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `385` // Estimated: `3675` - // Minimum execution time: 15_921_000 picoseconds. - Weight::from_parts(16_153_000, 3675) + // Minimum execution time: 15_295_000 picoseconds. + Weight::from_parts(15_639_000, 3675) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } /// Storage: Assets Asset (r:1 w:1) /// Proof: Assets Asset (max_values: None, max_size: Some(210), added: 2685, mode: MaxEncodedLen) /// Storage: Assets Account (r:1001 w:1000) - /// Proof: Assets Account (max_values: None, max_size: Some(102), added: 2577, mode: MaxEncodedLen) + /// Proof: Assets Account (max_values: None, max_size: Some(134), added: 2609, mode: MaxEncodedLen) /// Storage: System Account (r:1000 w:1000) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) /// The range of component `c` is `[0, 1000]`. fn destroy_accounts(c: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0 + c * (208 ±0)` - // Estimated: `3675 + c * (2603 ±0)` - // Minimum execution time: 21_242_000 picoseconds. - Weight::from_parts(21_532_000, 3675) - // Standard Error: 6_449 - .saturating_add(Weight::from_parts(13_150_845, 0).saturating_mul(c.into())) + // Estimated: `3675 + c * (2609 ±0)` + // Minimum execution time: 19_916_000 picoseconds. + Weight::from_parts(20_220_000, 3675) + // Standard Error: 7_298 + .saturating_add(Weight::from_parts(12_553_976, 0).saturating_mul(c.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().reads((2_u64).saturating_mul(c.into()))) .saturating_add(RocksDbWeight::get().writes(1_u64)) .saturating_add(RocksDbWeight::get().writes((2_u64).saturating_mul(c.into()))) - .saturating_add(Weight::from_parts(0, 2603).saturating_mul(c.into())) + .saturating_add(Weight::from_parts(0, 2609).saturating_mul(c.into())) } /// Storage: Assets Asset (r:1 w:1) /// Proof: Assets Asset (max_values: None, max_size: Some(210), added: 2685, mode: MaxEncodedLen) @@ -520,10 +598,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `522 + a * (86 ±0)` // Estimated: `3675 + a * (2623 ±0)` - // Minimum execution time: 21_604_000 picoseconds. - Weight::from_parts(21_881_000, 3675) - // Standard Error: 4_225 - .saturating_add(Weight::from_parts(15_968_205, 0).saturating_mul(a.into())) + // Minimum execution time: 20_322_000 picoseconds. + Weight::from_parts(20_744_000, 3675) + // Standard Error: 12_314 + .saturating_add(Weight::from_parts(14_767_353, 0).saturating_mul(a.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(a.into()))) .saturating_add(RocksDbWeight::get().writes(1_u64)) @@ -538,105 +616,105 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `351` // Estimated: `3675` - // Minimum execution time: 16_465_000 picoseconds. - Weight::from_parts(16_775_000, 3675) + // Minimum execution time: 15_668_000 picoseconds. + Weight::from_parts(16_016_000, 3675) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } /// Storage: Assets Asset (r:1 w:1) /// Proof: Assets Asset (max_values: None, max_size: Some(210), added: 2685, mode: MaxEncodedLen) /// Storage: Assets Account (r:1 w:1) - /// Proof: Assets Account (max_values: None, max_size: Some(102), added: 2577, mode: MaxEncodedLen) + /// Proof: Assets Account (max_values: None, max_size: Some(134), added: 2609, mode: MaxEncodedLen) fn mint() -> Weight { // Proof Size summary in bytes: // Measured: `351` // Estimated: `3675` - // Minimum execution time: 30_709_000 picoseconds. - Weight::from_parts(31_159_000, 3675) + // Minimum execution time: 28_227_000 picoseconds. + Weight::from_parts(28_769_000, 3675) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } /// Storage: Assets Asset (r:1 w:1) /// Proof: Assets Asset (max_values: None, max_size: Some(210), added: 2685, mode: MaxEncodedLen) /// Storage: Assets Account (r:1 w:1) - /// Proof: Assets Account (max_values: None, max_size: Some(102), added: 2577, mode: MaxEncodedLen) + /// Proof: Assets Account (max_values: None, max_size: Some(134), added: 2609, mode: MaxEncodedLen) fn burn() -> Weight { // Proof Size summary in bytes: // Measured: `459` // Estimated: `3675` - // Minimum execution time: 36_944_000 picoseconds. - Weight::from_parts(38_166_000, 3675) + // Minimum execution time: 34_672_000 picoseconds. + Weight::from_parts(34_902_000, 3675) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } /// Storage: Assets Asset (r:1 w:1) /// Proof: Assets Asset (max_values: None, max_size: Some(210), added: 2685, mode: MaxEncodedLen) /// Storage: Assets Account (r:2 w:2) - /// Proof: Assets Account (max_values: None, max_size: Some(102), added: 2577, mode: MaxEncodedLen) + /// Proof: Assets Account (max_values: None, max_size: Some(134), added: 2609, mode: MaxEncodedLen) /// Storage: System Account (r:1 w:1) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn transfer() -> Weight { // Proof Size summary in bytes: // Measured: `498` - // Estimated: `6144` - // Minimum execution time: 52_497_000 picoseconds. - Weight::from_parts(53_147_000, 6144) + // Estimated: `6208` + // Minimum execution time: 49_003_000 picoseconds. + Weight::from_parts(49_345_000, 6208) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } /// Storage: Assets Asset (r:1 w:1) /// Proof: Assets Asset (max_values: None, max_size: Some(210), added: 2685, mode: MaxEncodedLen) /// Storage: Assets Account (r:2 w:2) - /// Proof: Assets Account (max_values: None, max_size: Some(102), added: 2577, mode: MaxEncodedLen) + /// Proof: Assets Account (max_values: None, max_size: Some(134), added: 2609, mode: MaxEncodedLen) /// Storage: System Account (r:1 w:1) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn transfer_keep_alive() -> Weight { // Proof Size summary in bytes: // Measured: `498` - // Estimated: `6144` - // Minimum execution time: 46_203_000 picoseconds. - Weight::from_parts(46_853_000, 6144) + // Estimated: `6208` + // Minimum execution time: 43_429_000 picoseconds. + Weight::from_parts(43_936_000, 6208) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } /// Storage: Assets Asset (r:1 w:1) /// Proof: Assets Asset (max_values: None, max_size: Some(210), added: 2685, mode: MaxEncodedLen) /// Storage: Assets Account (r:2 w:2) - /// Proof: Assets Account (max_values: None, max_size: Some(102), added: 2577, mode: MaxEncodedLen) + /// Proof: Assets Account (max_values: None, max_size: Some(134), added: 2609, mode: MaxEncodedLen) /// Storage: System Account (r:1 w:1) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn force_transfer() -> Weight { // Proof Size summary in bytes: // Measured: `498` - // Estimated: `6144` - // Minimum execution time: 52_911_000 picoseconds. - Weight::from_parts(55_511_000, 6144) + // Estimated: `6208` + // Minimum execution time: 49_177_000 picoseconds. + Weight::from_parts(49_548_000, 6208) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } /// Storage: Assets Asset (r:1 w:0) /// Proof: Assets Asset (max_values: None, max_size: Some(210), added: 2685, mode: MaxEncodedLen) /// Storage: Assets Account (r:1 w:1) - /// Proof: Assets Account (max_values: None, max_size: Some(102), added: 2577, mode: MaxEncodedLen) + /// Proof: Assets Account (max_values: None, max_size: Some(134), added: 2609, mode: MaxEncodedLen) fn freeze() -> Weight { // Proof Size summary in bytes: // Measured: `459` // Estimated: `3675` - // Minimum execution time: 20_308_000 picoseconds. - Weight::from_parts(20_524_000, 3675) + // Minimum execution time: 19_323_000 picoseconds. + Weight::from_parts(19_945_000, 3675) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } /// Storage: Assets Asset (r:1 w:0) /// Proof: Assets Asset (max_values: None, max_size: Some(210), added: 2685, mode: MaxEncodedLen) /// Storage: Assets Account (r:1 w:1) - /// Proof: Assets Account (max_values: None, max_size: Some(102), added: 2577, mode: MaxEncodedLen) + /// Proof: Assets Account (max_values: None, max_size: Some(134), added: 2609, mode: MaxEncodedLen) fn thaw() -> Weight { // Proof Size summary in bytes: // Measured: `459` // Estimated: `3675` - // Minimum execution time: 20_735_000 picoseconds. - Weight::from_parts(21_026_000, 3675) + // Minimum execution time: 19_543_000 picoseconds. + Weight::from_parts(19_747_000, 3675) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -646,8 +724,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `385` // Estimated: `3675` - // Minimum execution time: 16_148_000 picoseconds. - Weight::from_parts(16_404_000, 3675) + // Minimum execution time: 15_623_000 picoseconds. + Weight::from_parts(15_833_000, 3675) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -657,8 +735,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `385` // Estimated: `3675` - // Minimum execution time: 16_075_000 picoseconds. - Weight::from_parts(16_542_000, 3675) + // Minimum execution time: 15_396_000 picoseconds. + Weight::from_parts(15_704_000, 3675) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -670,8 +748,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `351` // Estimated: `3675` - // Minimum execution time: 17_866_000 picoseconds. - Weight::from_parts(18_129_000, 3675) + // Minimum execution time: 17_205_000 picoseconds. + Weight::from_parts(17_546_000, 3675) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -681,8 +759,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `351` // Estimated: `3675` - // Minimum execution time: 16_637_000 picoseconds. - Weight::from_parts(16_918_000, 3675) + // Minimum execution time: 16_049_000 picoseconds. + Weight::from_parts(16_317_000, 3675) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -692,14 +770,16 @@ impl WeightInfo for () { /// Proof: Assets Metadata (max_values: None, max_size: Some(140), added: 2615, mode: MaxEncodedLen) /// The range of component `n` is `[0, 50]`. /// The range of component `s` is `[0, 50]`. - fn set_metadata(_n: u32, s: u32, ) -> Weight { + fn set_metadata(n: u32, s: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `351` // Estimated: `3675` - // Minimum execution time: 33_304_000 picoseconds. - Weight::from_parts(34_764_544, 3675) - // Standard Error: 634 - .saturating_add(Weight::from_parts(4_733, 0).saturating_mul(s.into())) + // Minimum execution time: 31_574_000 picoseconds. + Weight::from_parts(32_447_787, 3675) + // Standard Error: 904 + .saturating_add(Weight::from_parts(653, 0).saturating_mul(n.into())) + // Standard Error: 904 + .saturating_add(Weight::from_parts(271, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -711,8 +791,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `515` // Estimated: `3675` - // Minimum execution time: 33_640_000 picoseconds. - Weight::from_parts(34_100_000, 3675) + // Minimum execution time: 31_865_000 picoseconds. + Weight::from_parts(32_160_000, 3675) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -726,12 +806,12 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `190` // Estimated: `3675` - // Minimum execution time: 16_549_000 picoseconds. - Weight::from_parts(17_337_982, 3675) - // Standard Error: 586 - .saturating_add(Weight::from_parts(4_584, 0).saturating_mul(n.into())) - // Standard Error: 586 - .saturating_add(Weight::from_parts(4_288, 0).saturating_mul(s.into())) + // Minimum execution time: 16_203_000 picoseconds. + Weight::from_parts(16_432_499, 3675) + // Standard Error: 1_563 + .saturating_add(Weight::from_parts(5_818, 0).saturating_mul(n.into())) + // Standard Error: 1_563 + .saturating_add(Weight::from_parts(9_660, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -743,8 +823,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `515` // Estimated: `3675` - // Minimum execution time: 34_183_000 picoseconds. - Weight::from_parts(34_577_000, 3675) + // Minimum execution time: 33_443_000 picoseconds. + Weight::from_parts(56_533_000, 3675) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -754,8 +834,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `351` // Estimated: `3675` - // Minimum execution time: 15_505_000 picoseconds. - Weight::from_parts(15_784_000, 3675) + // Minimum execution time: 20_636_000 picoseconds. + Weight::from_parts(23_960_000, 3675) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -767,8 +847,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `385` // Estimated: `3675` - // Minimum execution time: 38_762_000 picoseconds. - Weight::from_parts(39_138_000, 3675) + // Minimum execution time: 35_987_000 picoseconds. + Weight::from_parts(36_429_000, 3675) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -777,15 +857,15 @@ impl WeightInfo for () { /// Storage: Assets Approvals (r:1 w:1) /// Proof: Assets Approvals (max_values: None, max_size: Some(148), added: 2623, mode: MaxEncodedLen) /// Storage: Assets Account (r:2 w:2) - /// Proof: Assets Account (max_values: None, max_size: Some(102), added: 2577, mode: MaxEncodedLen) + /// Proof: Assets Account (max_values: None, max_size: Some(134), added: 2609, mode: MaxEncodedLen) /// Storage: System Account (r:1 w:1) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn transfer_approved() -> Weight { // Proof Size summary in bytes: // Measured: `668` - // Estimated: `6144` - // Minimum execution time: 73_396_000 picoseconds. - Weight::from_parts(73_986_000, 6144) + // Estimated: `6208` + // Minimum execution time: 68_059_000 picoseconds. + Weight::from_parts(69_845_000, 6208) .saturating_add(RocksDbWeight::get().reads(5_u64)) .saturating_add(RocksDbWeight::get().writes(5_u64)) } @@ -797,8 +877,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `555` // Estimated: `3675` - // Minimum execution time: 39_707_000 picoseconds. - Weight::from_parts(40_222_000, 3675) + // Minimum execution time: 38_066_000 picoseconds. + Weight::from_parts(38_450_000, 3675) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -810,8 +890,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `555` // Estimated: `3675` - // Minimum execution time: 40_357_000 picoseconds. - Weight::from_parts(40_731_000, 3675) + // Minimum execution time: 38_500_000 picoseconds. + Weight::from_parts(38_953_000, 3675) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -821,9 +901,78 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `351` // Estimated: `3675` - // Minimum execution time: 16_937_000 picoseconds. - Weight::from_parts(17_219_000, 3675) + // Minimum execution time: 16_268_000 picoseconds. + Weight::from_parts(16_764_000, 3675) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } + /// Storage: Assets Account (r:1 w:1) + /// Proof: Assets Account (max_values: None, max_size: Some(134), added: 2609, mode: MaxEncodedLen) + /// Storage: Assets Asset (r:1 w:1) + /// Proof: Assets Asset (max_values: None, max_size: Some(210), added: 2685, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + fn touch() -> Weight { + // Proof Size summary in bytes: + // Measured: `453` + // Estimated: `3675` + // Minimum execution time: 37_468_000 picoseconds. + Weight::from_parts(37_957_000, 3675) + .saturating_add(RocksDbWeight::get().reads(3_u64)) + .saturating_add(RocksDbWeight::get().writes(3_u64)) + } + /// Storage: Assets Account (r:1 w:1) + /// Proof: Assets Account (max_values: None, max_size: Some(134), added: 2609, mode: MaxEncodedLen) + /// Storage: Assets Asset (r:1 w:1) + /// Proof: Assets Asset (max_values: None, max_size: Some(210), added: 2685, mode: MaxEncodedLen) + fn touch_other() -> Weight { + // Proof Size summary in bytes: + // Measured: `351` + // Estimated: `3675` + // Minimum execution time: 383_408_000 picoseconds. + Weight::from_parts(392_036_000, 3675) + .saturating_add(RocksDbWeight::get().reads(2)) + .saturating_add(RocksDbWeight::get().writes(2)) + } + /// Storage: Assets Account (r:1 w:1) + /// Proof: Assets Account (max_values: None, max_size: Some(134), added: 2609, mode: MaxEncodedLen) + /// Storage: Assets Asset (r:1 w:1) + /// Proof: Assets Asset (max_values: None, max_size: Some(210), added: 2685, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + fn refund() -> Weight { + // Proof Size summary in bytes: + // Measured: `579` + // Estimated: `3675` + // Minimum execution time: 34_066_000 picoseconds. + Weight::from_parts(34_347_000, 3675) + .saturating_add(RocksDbWeight::get().reads(3_u64)) + .saturating_add(RocksDbWeight::get().writes(3_u64)) + } + /// Storage: Assets Account (r:1 w:1) + /// Proof: Assets Account (max_values: None, max_size: Some(134), added: 2609, mode: MaxEncodedLen) + /// Storage: Assets Asset (r:1 w:1) + /// Proof: Assets Asset (max_values: None, max_size: Some(210), added: 2685, mode: MaxEncodedLen) + fn refund_other() -> Weight { + // Proof Size summary in bytes: + // Measured: `510` + // Estimated: `3675` + // Minimum execution time: 32_060_000 picoseconds. + Weight::from_parts(32_519_000, 3675) + .saturating_add(RocksDbWeight::get().reads(2_u64)) + .saturating_add(RocksDbWeight::get().writes(2_u64)) + } + /// Storage: Assets Asset (r:1 w:0) + /// Proof: Assets Asset (max_values: None, max_size: Some(210), added: 2685, mode: MaxEncodedLen) + /// Storage: Assets Account (r:1 w:1) + /// Proof: Assets Account (max_values: None, max_size: Some(134), added: 2609, mode: MaxEncodedLen) + fn block() -> Weight { + // Proof Size summary in bytes: + // Measured: `459` + // Estimated: `3675` + // Minimum execution time: 115_000_000 picoseconds. + Weight::from_parts(163_000_000, 3675) + .saturating_add(RocksDbWeight::get().reads(2_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) + } } diff --git a/frame/support/src/traits.rs b/frame/support/src/traits.rs index b2e6a6138c163..8d0f8aa88dc5e 100644 --- a/frame/support/src/traits.rs +++ b/frame/support/src/traits.rs @@ -55,8 +55,8 @@ pub use filter::{ClearFilterGuard, FilterStack, FilterStackGuard, InstanceFilter mod misc; pub use misc::{ defensive_prelude::{self, *}, - Backing, ConstBool, ConstI128, ConstI16, ConstI32, ConstI64, ConstI8, ConstU128, ConstU16, - ConstU32, ConstU64, ConstU8, DefensiveMax, DefensiveMin, DefensiveSaturating, + AccountTouch, Backing, ConstBool, ConstI128, ConstI16, ConstI32, ConstI64, ConstI8, ConstU128, + ConstU16, ConstU32, ConstU64, ConstU8, DefensiveMax, DefensiveMin, DefensiveSaturating, DefensiveTruncateFrom, EnsureInherentsAreFirst, EqualPrivilegeOnly, EstimateCallFee, ExecuteBlock, ExtrinsicCall, Get, GetBacking, GetDefault, HandleLifetime, IsSubType, IsType, Len, OffchainWorker, OnKilledAccount, OnNewAccount, PrivilegeCmp, SameOrOther, Time, diff --git a/frame/support/src/traits/misc.rs b/frame/support/src/traits/misc.rs index a320b85eac557..e21fcfbb24179 100644 --- a/frame/support/src/traits/misc.rs +++ b/frame/support/src/traits/misc.rs @@ -17,7 +17,7 @@ //! Smaller traits used in FRAME which don't need their own file. -use crate::dispatch::Parameter; +use crate::dispatch::{DispatchResult, Parameter}; use codec::{CompactLen, Decode, DecodeLimit, Encode, EncodeLike, Input, MaxEncodedLen}; use impl_trait_for_tuples::impl_for_tuples; use scale_info::{build::Fields, meta_type, Path, Type, TypeInfo, TypeParameter}; @@ -1154,6 +1154,19 @@ impl PreimageRecipient for () { fn unnote_preimage(_: &Hash) {} } +/// Trait for creating an asset account with a deposit taken from a designated depositor specified +/// by the client. +pub trait AccountTouch { + /// The type for currency units of the deposit. + type Balance; + + /// The deposit amount of a native currency required for creating an asset account. + fn deposit_required() -> Self::Balance; + + /// Create an account for `who` of the `asset` with a deposit taken from the `depositor`. + fn touch(asset: AssetId, who: AccountId, depositor: AccountId) -> DispatchResult; +} + #[cfg(test)] mod test { use super::*; diff --git a/frame/support/src/traits/tokens/misc.rs b/frame/support/src/traits/tokens/misc.rs index 75aef0e04ea65..0ba900e95f9b8 100644 --- a/frame/support/src/traits/tokens/misc.rs +++ b/frame/support/src/traits/tokens/misc.rs @@ -141,6 +141,8 @@ pub enum DepositConsequence { Overflow, /// Account continued in existence. Success, + /// Account cannot receive the assets. + Blocked, } impl DepositConsequence { @@ -152,6 +154,7 @@ impl DepositConsequence { CannotCreate => TokenError::CannotCreate.into(), UnknownAsset => TokenError::UnknownAsset.into(), Overflow => ArithmeticError::Overflow.into(), + Blocked => TokenError::Blocked.into(), Success => return Ok(()), }) } diff --git a/primitives/runtime/src/lib.rs b/primitives/runtime/src/lib.rs index e30146918a4a9..13ef157dff19e 100644 --- a/primitives/runtime/src/lib.rs +++ b/primitives/runtime/src/lib.rs @@ -626,6 +626,8 @@ pub enum TokenError { CannotCreateHold, /// Withdrawal would cause unwanted loss of account. NotExpendable, + /// Account cannot receive the assets. + Blocked, } impl From for &'static str { @@ -641,6 +643,7 @@ impl From for &'static str { TokenError::CannotCreateHold => "Account cannot be created for recording amount on hold", TokenError::NotExpendable => "Account that is desired to remain would die", + TokenError::Blocked => "Account cannot receive the assets", } } }