diff --git a/frame/assets/src/benchmarking.rs b/frame/assets/src/benchmarking.rs index 047ede2ce6964..d23ba667f8f05 100644 --- a/frame/assets/src/benchmarking.rs +++ b/frame/assets/src/benchmarking.rs @@ -49,7 +49,7 @@ fn create_default_asset, I: 'static>( assert!(Assets::::force_create( root, asset_id, - caller_lookup.clone(), + Some(caller_lookup.clone()), is_sufficient, 1u32.into(), ) @@ -144,18 +144,18 @@ benchmarks_instance_pallet! { let caller = T::CreateOrigin::ensure_origin(origin, &asset_id.into()).unwrap(); let caller_lookup = T::Lookup::unlookup(caller.clone()); T::Currency::make_free_balance_be(&caller, DepositBalanceOf::::max_value()); - }: _(SystemOrigin::Signed(caller.clone()), asset_id, caller_lookup, 1u32.into()) + }: _(SystemOrigin::Signed(caller.clone()), asset_id, Some(caller_lookup), 1u32.into()) verify { - assert_last_event::(Event::Created { asset_id: asset_id.into(), creator: caller.clone(), owner: caller }.into()); + assert_last_event::(Event::Created { asset_id: asset_id.into(), creator: caller.clone(), owner: caller.clone(), admin: Some(caller) }.into()); } force_create { let asset_id = default_asset_id::(); let caller: T::AccountId = whitelisted_caller(); let caller_lookup = T::Lookup::unlookup(caller.clone()); - }: _(SystemOrigin::Root, asset_id, caller_lookup, true, 1u32.into()) + }: _(SystemOrigin::Root, asset_id, Some(caller_lookup), true, 1u32.into()) verify { - assert_last_event::(Event::ForceCreated { asset_id: asset_id.into(), owner: caller }.into()); + assert_last_event::(Event::ForceCreated { asset_id: asset_id.into(), owner: Some(caller) }.into()); } start_destroy { @@ -311,9 +311,10 @@ benchmarks_instance_pallet! { let (asset_id, caller, _) = create_default_asset::(true); let target: T::AccountId = account("target", 0, SEED); let target_lookup = T::Lookup::unlookup(target.clone()); - }: _(SystemOrigin::Signed(caller), asset_id, target_lookup) + T::Currency::make_free_balance_be(&target, DepositBalanceOf::::max_value()); + }: _(SystemOrigin::Signed(caller), asset_id, Some(target_lookup)) verify { - assert_last_event::(Event::OwnerChanged { asset_id: asset_id.into(), owner: target }.into()); + assert_last_event::(Event::OwnerChanged { asset_id: asset_id.into(), owner: Some(target) }.into()); } set_team { @@ -321,13 +322,13 @@ benchmarks_instance_pallet! { let target0 = T::Lookup::unlookup(account("target", 0, SEED)); let target1 = T::Lookup::unlookup(account("target", 1, SEED)); let target2 = T::Lookup::unlookup(account("target", 2, SEED)); - }: _(SystemOrigin::Signed(caller), asset_id, target0, target1, target2) + }: _(SystemOrigin::Signed(caller), asset_id, Some(target0), Some(target1), Some(target2)) verify { assert_last_event::(Event::TeamChanged { asset_id: asset_id.into(), - issuer: account("target", 0, SEED), - admin: account("target", 1, SEED), - freezer: account("target", 2, SEED), + issuer: Some(account("target", 0, SEED)), + admin: Some(account("target", 1, SEED)), + freezer: Some(account("target", 2, SEED)), }.into()); } @@ -403,10 +404,10 @@ benchmarks_instance_pallet! { T::ForceOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?; let call = Call::::force_asset_status { id: asset_id, - owner: caller_lookup.clone(), - issuer: caller_lookup.clone(), - admin: caller_lookup.clone(), - freezer: caller_lookup, + owner: Some(caller_lookup.clone()), + issuer: Some(caller_lookup.clone()), + admin: Some(caller_lookup.clone()), + freezer: Some(caller_lookup), min_balance: 100u32.into(), is_sufficient: true, is_frozen: false, diff --git a/frame/assets/src/functions.rs b/frame/assets/src/functions.rs index 1e10e0066e851..b3bb6b46ccf20 100644 --- a/frame/assets/src/functions.rs +++ b/frame/assets/src/functions.rs @@ -358,8 +358,8 @@ impl, I: 'static> Pallet { maybe_check_issuer: Option, ) -> DispatchResult { Self::increase_balance(id, beneficiary, amount, |details| -> DispatchResult { - if let Some(check_issuer) = maybe_check_issuer { - ensure!(check_issuer == details.issuer, Error::::NoPermission); + if maybe_check_issuer.is_some() { + ensure!(maybe_check_issuer == details.issuer, Error::::NoPermission); } debug_assert!(details.supply.checked_add(&amount).is_some(), "checked in prep; qed"); @@ -442,8 +442,8 @@ impl, I: 'static> Pallet { let actual = Self::decrease_balance(id, target, amount, f, |actual, details| { // Check admin rights. - if let Some(check_admin) = maybe_check_admin { - ensure!(check_admin == details.admin, Error::::NoPermission); + if maybe_check_admin.is_some() { + ensure!(maybe_check_admin == details.admin, Error::::NoPermission); } debug_assert!(details.supply >= actual, "checked in prep; qed"); @@ -567,8 +567,8 @@ impl, I: 'static> Pallet { let details = maybe_details.as_mut().ok_or(Error::::Unknown)?; // Check admin rights. - if let Some(need_admin) = maybe_need_admin { - ensure!(need_admin == details.admin, Error::::NoPermission); + if maybe_need_admin.is_some() { + ensure!(maybe_need_admin == details.admin, Error::::NoPermission); } // Skip if source == dest @@ -644,7 +644,7 @@ impl, I: 'static> Pallet { /// considered dust and cleaned up. pub(super) fn do_force_create( id: T::AssetId, - owner: T::AccountId, + owner: Option, is_sufficient: bool, min_balance: T::Balance, ) -> DispatchResult { @@ -681,8 +681,8 @@ impl, I: 'static> Pallet { ) -> DispatchResult { Asset::::try_mutate_exists(id, |maybe_details| -> Result<(), DispatchError> { let mut details = maybe_details.as_mut().ok_or(Error::::Unknown)?; - if let Some(check_owner) = maybe_check_owner { - ensure!(details.owner == check_owner, Error::::NoPermission); + if maybe_check_owner.is_some() { + ensure!(maybe_check_owner == details.owner, Error::::NoPermission); } details.status = AssetStatus::Destroying; @@ -776,10 +776,11 @@ impl, I: 'static> Pallet { ensure!(T::CallbackHandle::destroyed(&id).is_ok(), Error::::CallbackFailed); let metadata = Metadata::::take(&id); - T::Currency::unreserve( - &details.owner, - details.deposit.saturating_add(metadata.deposit), - ); + + if let Some(owner) = details.owner { + T::Currency::unreserve(&owner, details.deposit.saturating_add(metadata.deposit)); + } + Self::deposit_event(Event::Destroyed { asset_id: id }); Ok(()) @@ -897,7 +898,7 @@ impl, I: 'static> Pallet { let d = Asset::::get(id).ok_or(Error::::Unknown)?; ensure!(d.status == AssetStatus::Live, Error::::AssetNotLive); - ensure!(from == &d.owner, Error::::NoPermission); + ensure!(Some(from) == d.owner.as_ref(), Error::::NoPermission); Metadata::::try_mutate_exists(id, |metadata| { ensure!(metadata.as_ref().map_or(true, |m| !m.is_frozen), Error::::NoPermission); diff --git a/frame/assets/src/impl_fungibles.rs b/frame/assets/src/impl_fungibles.rs index 7bec884f4c56b..eadc4a56411f2 100644 --- a/frame/assets/src/impl_fungibles.rs +++ b/frame/assets/src/impl_fungibles.rs @@ -139,7 +139,7 @@ impl, I: 'static> fungibles::Unbalanced for Pallet, I: 'static> fungibles::Create for Pallet { fn create( id: T::AssetId, - admin: T::AccountId, + admin: Option, is_sufficient: bool, min_balance: Self::Balance, ) -> DispatchResult { @@ -238,19 +238,19 @@ impl, I: 'static> fungibles::roles::Inspect<::Ac for Pallet { fn owner(asset: T::AssetId) -> Option<::AccountId> { - Asset::::get(asset).map(|x| x.owner) + Asset::::get(asset).and_then(|x| x.owner) } fn issuer(asset: T::AssetId) -> Option<::AccountId> { - Asset::::get(asset).map(|x| x.issuer) + Asset::::get(asset).and_then(|x| x.issuer) } fn admin(asset: T::AssetId) -> Option<::AccountId> { - Asset::::get(asset).map(|x| x.admin) + Asset::::get(asset).and_then(|x| x.admin) } fn freezer(asset: T::AssetId) -> Option<::AccountId> { - Asset::::get(asset).map(|x| x.freezer) + Asset::::get(asset).and_then(|x| x.freezer) } } diff --git a/frame/assets/src/lib.rs b/frame/assets/src/lib.rs index d32b407e67f6e..dbd8491fc6460 100644 --- a/frame/assets/src/lib.rs +++ b/frame/assets/src/lib.rs @@ -163,7 +163,6 @@ use frame_support::{ storage::KeyPrefixIterator, traits::{ tokens::{fungibles, DepositConsequence, WithdrawConsequence}, - BalanceStatus::Reserved, Currency, EnsureOriginWithArg, ReservableCurrency, StoredMap, }, }; @@ -173,12 +172,11 @@ pub use pallet::*; pub use weights::WeightInfo; type AccountIdLookupOf = <::Lookup as StaticLookup>::Source; -const LOG_TARGET: &str = "runtime::assets"; -/// Trait with callbacks that are executed after successfull asset creation or destruction. +/// Trait with callbacks that are executed after successful asset creation or destruction. pub trait AssetsCallback { /// Indicates that asset with `id` was successfully created by the `owner` - fn created(_id: &AssetId, _owner: &AccountId) -> Result<(), ()> { + fn created(_id: &AssetId, _owner: &Option) -> Result<(), ()> { Ok(()) } @@ -387,10 +385,10 @@ pub mod pallet { Asset::::insert( id, AssetDetails { - owner: owner.clone(), - issuer: owner.clone(), - admin: owner.clone(), - freezer: owner.clone(), + owner: Some(owner.clone()), + issuer: Some(owner.clone()), + admin: Some(owner.clone()), + freezer: Some(owner.clone()), supply: Zero::zero(), deposit: Zero::zero(), min_balance: *min_balance, @@ -444,7 +442,12 @@ pub mod pallet { #[pallet::generate_deposit(pub(super) fn deposit_event)] pub enum Event, I: 'static = ()> { /// Some asset class was created. - Created { asset_id: T::AssetId, creator: T::AccountId, owner: T::AccountId }, + Created { + asset_id: T::AssetId, + creator: T::AccountId, + owner: T::AccountId, + admin: Option, + }, /// Some assets were issued. Issued { asset_id: T::AssetId, owner: T::AccountId, amount: T::Balance }, /// Some assets were transferred. @@ -459,12 +462,12 @@ pub mod pallet { /// The management team changed. TeamChanged { asset_id: T::AssetId, - issuer: T::AccountId, - admin: T::AccountId, - freezer: T::AccountId, + issuer: Option, + admin: Option, + freezer: Option, }, /// The owner changed. - OwnerChanged { asset_id: T::AssetId, owner: T::AccountId }, + OwnerChanged { asset_id: T::AssetId, owner: Option }, /// Some account `who` was frozen. Frozen { asset_id: T::AssetId, who: T::AccountId }, /// Some account `who` was thawed. @@ -486,7 +489,7 @@ pub mod pallet { /// An asset class was destroyed. Destroyed { asset_id: T::AssetId }, /// Some asset class was force-created. - ForceCreated { asset_id: T::AssetId, owner: T::AccountId }, + ForceCreated { asset_id: T::AssetId, owner: Option }, /// New metadata has been set for an asset. MetadataSet { asset_id: T::AssetId, @@ -593,12 +596,12 @@ pub mod pallet { pub fn create( origin: OriginFor, id: T::AssetIdParameter, - admin: AccountIdLookupOf, + admin: Option>, min_balance: T::Balance, ) -> DispatchResult { let id: T::AssetId = id.into(); let owner = T::CreateOrigin::ensure_origin(origin, &id)?; - let admin = T::Lookup::lookup(admin)?; + let admin = admin.map(T::Lookup::lookup).transpose()?; ensure!(!Asset::::contains_key(id), Error::::InUse); ensure!(!min_balance.is_zero(), Error::::MinBalanceZero); @@ -609,7 +612,7 @@ pub mod pallet { Asset::::insert( id, AssetDetails { - owner: owner.clone(), + owner: Some(owner.clone()), issuer: admin.clone(), admin: admin.clone(), freezer: admin.clone(), @@ -623,11 +626,15 @@ pub mod pallet { status: AssetStatus::Live, }, ); - ensure!(T::CallbackHandle::created(&id, &owner).is_ok(), Error::::CallbackFailed); + ensure!( + T::CallbackHandle::created(&id, &Some(owner.clone())).is_ok(), + Error::::CallbackFailed + ); Self::deposit_event(Event::Created { asset_id: id, creator: owner.clone(), - owner: admin, + owner, + admin, }); Ok(()) @@ -656,12 +663,12 @@ pub mod pallet { pub fn force_create( origin: OriginFor, id: T::AssetIdParameter, - owner: AccountIdLookupOf, + owner: Option>, is_sufficient: bool, #[pallet::compact] min_balance: T::Balance, ) -> DispatchResult { T::ForceOrigin::ensure_origin(origin)?; - let owner = T::Lookup::lookup(owner)?; + let owner = owner.map(T::Lookup::lookup).transpose()?; let id: T::AssetId = id.into(); Self::do_force_create(id, owner, is_sufficient, min_balance) } @@ -771,10 +778,10 @@ pub mod pallet { beneficiary: AccountIdLookupOf, #[pallet::compact] amount: T::Balance, ) -> DispatchResult { - let origin = ensure_signed(origin)?; + let origin = ensure_signed_or_root(origin)?; let beneficiary = T::Lookup::lookup(beneficiary)?; let id: T::AssetId = id.into(); - Self::do_mint(id, &beneficiary, amount, Some(origin))?; + Self::do_mint(id, &beneficiary, amount, origin)?; Ok(()) } @@ -800,12 +807,12 @@ pub mod pallet { who: AccountIdLookupOf, #[pallet::compact] amount: T::Balance, ) -> DispatchResult { - let origin = ensure_signed(origin)?; + let origin = ensure_signed_or_root(origin)?; let who = T::Lookup::lookup(who)?; let id: T::AssetId = id.into(); let f = DebitFlags { keep_alive: false, best_effort: true }; - let _ = Self::do_burn(id, &who, amount, Some(origin), f)?; + let _ = Self::do_burn(id, &who, amount, origin, f)?; Ok(()) } @@ -902,13 +909,13 @@ pub mod pallet { dest: AccountIdLookupOf, #[pallet::compact] amount: T::Balance, ) -> DispatchResult { - let origin = ensure_signed(origin)?; + let origin = ensure_signed_or_root(origin)?; let source = T::Lookup::lookup(source)?; let dest = T::Lookup::lookup(dest)?; let id: T::AssetId = id.into(); let f = TransferFlags { keep_alive: false, best_effort: false, burn_dust: false }; - Self::do_transfer(id, &source, &dest, amount, Some(origin), f).map(|_| ()) + Self::do_transfer(id, &source, &dest, amount, origin, f).map(|_| ()) } /// Disallow further unprivileged transfers from an account. @@ -927,7 +934,7 @@ pub mod pallet { id: T::AssetIdParameter, who: AccountIdLookupOf, ) -> DispatchResult { - let origin = ensure_signed(origin)?; + let origin = ensure_signed_or_root(origin)?; let id: T::AssetId = id.into(); let d = Asset::::get(id).ok_or(Error::::Unknown)?; @@ -936,6 +943,7 @@ pub mod pallet { Error::::AssetNotLive ); ensure!(origin == d.freezer, Error::::NoPermission); + let who = T::Lookup::lookup(who)?; Account::::try_mutate(id, &who, |maybe_account| -> DispatchResult { @@ -963,7 +971,7 @@ pub mod pallet { id: T::AssetIdParameter, who: AccountIdLookupOf, ) -> DispatchResult { - let origin = ensure_signed(origin)?; + let origin = ensure_signed_or_root(origin)?; let id: T::AssetId = id.into(); let details = Asset::::get(id).ok_or(Error::::Unknown)?; @@ -994,13 +1002,13 @@ pub mod pallet { /// Weight: `O(1)` #[pallet::call_index(13)] pub fn freeze_asset(origin: OriginFor, id: T::AssetIdParameter) -> DispatchResult { - let origin = ensure_signed(origin)?; + let origin = ensure_signed_or_root(origin)?; let id: T::AssetId = id.into(); Asset::::try_mutate(id, |maybe_details| { let d = maybe_details.as_mut().ok_or(Error::::Unknown)?; ensure!(d.status == AssetStatus::Live, Error::::AssetNotLive); - ensure!(origin == d.freezer, Error::::NoPermission); + ensure!(origin == d.freezer.clone(), Error::::NoPermission); d.status = AssetStatus::Frozen; @@ -1020,12 +1028,12 @@ pub mod pallet { /// Weight: `O(1)` #[pallet::call_index(14)] pub fn thaw_asset(origin: OriginFor, id: T::AssetIdParameter) -> DispatchResult { - let origin = ensure_signed(origin)?; + let origin = ensure_signed_or_root(origin)?; let id: T::AssetId = id.into(); Asset::::try_mutate(id, |maybe_details| { let d = maybe_details.as_mut().ok_or(Error::::Unknown)?; - ensure!(origin == d.admin, Error::::NoPermission); + ensure!(origin == d.admin.clone(), Error::::NoPermission); ensure!(d.status == AssetStatus::Frozen, Error::::NotFrozen); d.status = AssetStatus::Live; @@ -1049,25 +1057,33 @@ pub mod pallet { pub fn transfer_ownership( origin: OriginFor, id: T::AssetIdParameter, - owner: AccountIdLookupOf, + owner: Option>, ) -> DispatchResult { - let origin = ensure_signed(origin)?; - let owner = T::Lookup::lookup(owner)?; + let origin = ensure_signed_or_root(origin)?; + let owner = owner.map(T::Lookup::lookup).transpose()?; let id: T::AssetId = id.into(); Asset::::try_mutate(id, |maybe_details| { let details = maybe_details.as_mut().ok_or(Error::::Unknown)?; ensure!(details.status == AssetStatus::Live, Error::::LiveAsset); - ensure!(origin == details.owner, Error::::NoPermission); - if details.owner == owner { + ensure!(origin == details.owner.clone(), Error::::NoPermission); + + if details.owner == owner.clone() { return Ok(()) } - let metadata_deposit = Metadata::::get(id).deposit; - let deposit = details.deposit + metadata_deposit; - // Move the deposit to the new owner. - T::Currency::repatriate_reserved(&details.owner, &owner, deposit, Reserved)?; + if let Some(details_owner) = &details.owner { + let metadata_deposit = Metadata::::get(id).deposit; + let old_deposit = details.deposit + metadata_deposit; + + T::Currency::unreserve(&details_owner, old_deposit); + + if let Some(account) = owner.clone() { + let new_deposit = T::AssetDeposit::get() + metadata_deposit; + T::Currency::reserve(&account, new_deposit)?; + } + } details.owner = owner.clone(); @@ -1092,24 +1108,30 @@ pub mod pallet { pub fn set_team( origin: OriginFor, id: T::AssetIdParameter, - issuer: AccountIdLookupOf, - admin: AccountIdLookupOf, - freezer: AccountIdLookupOf, + issuer: Option>, + admin: Option>, + freezer: Option>, ) -> DispatchResult { - let origin = ensure_signed(origin)?; - let issuer = T::Lookup::lookup(issuer)?; - let admin = T::Lookup::lookup(admin)?; - let freezer = T::Lookup::lookup(freezer)?; + let origin = ensure_signed_or_root(origin)?; + let issuer = issuer.map(T::Lookup::lookup).transpose()?; + let admin = admin.map(T::Lookup::lookup).transpose()?; + let freezer = freezer.map(T::Lookup::lookup).transpose()?; let id: T::AssetId = id.into(); Asset::::try_mutate(id, |maybe_details| { let details = maybe_details.as_mut().ok_or(Error::::Unknown)?; ensure!(details.status == AssetStatus::Live, Error::::AssetNotLive); - ensure!(origin == details.owner, Error::::NoPermission); + ensure!(origin == details.owner.clone(), Error::::NoPermission); - details.issuer = issuer.clone(); - details.admin = admin.clone(); - details.freezer = freezer.clone(); + if details.issuer.is_some() { + details.issuer = issuer.clone(); + } + if details.admin.is_some() { + details.admin = admin.clone(); + } + if details.freezer.is_some() { + details.freezer = freezer.clone(); + } Self::deposit_event(Event::TeamChanged { asset_id: id, issuer, admin, freezer }); Ok(()) @@ -1164,11 +1186,15 @@ pub mod pallet { let d = Asset::::get(id).ok_or(Error::::Unknown)?; ensure!(d.status == AssetStatus::Live, Error::::AssetNotLive); - ensure!(origin == d.owner, Error::::NoPermission); + ensure!(Some(origin) == d.owner.clone(), Error::::NoPermission); Metadata::::try_mutate_exists(id, |metadata| { let deposit = metadata.take().ok_or(Error::::Unknown)?.deposit; - T::Currency::unreserve(&d.owner, deposit); + + if let Some(owner) = d.owner { + T::Currency::unreserve(&owner, deposit); + } + Self::deposit_event(Event::MetadataCleared { asset_id: id }); Ok(()) }) @@ -1251,7 +1277,9 @@ pub mod pallet { let d = Asset::::get(id).ok_or(Error::::Unknown)?; Metadata::::try_mutate_exists(id, |metadata| { let deposit = metadata.take().ok_or(Error::::Unknown)?.deposit; - T::Currency::unreserve(&d.owner, deposit); + if let Some(owner) = &d.owner { + T::Currency::unreserve(owner, deposit); + } Self::deposit_event(Event::MetadataCleared { asset_id: id }); Ok(()) }) @@ -1283,10 +1311,10 @@ pub mod pallet { pub fn force_asset_status( origin: OriginFor, id: T::AssetIdParameter, - owner: AccountIdLookupOf, - issuer: AccountIdLookupOf, - admin: AccountIdLookupOf, - freezer: AccountIdLookupOf, + owner: Option>, + issuer: Option>, + admin: Option>, + freezer: Option>, #[pallet::compact] min_balance: T::Balance, is_sufficient: bool, is_frozen: bool, @@ -1297,10 +1325,28 @@ pub mod pallet { Asset::::try_mutate(id, |maybe_asset| { let mut asset = maybe_asset.take().ok_or(Error::::Unknown)?; ensure!(asset.status != AssetStatus::Destroying, Error::::AssetNotLive); - asset.owner = T::Lookup::lookup(owner)?; - asset.issuer = T::Lookup::lookup(issuer)?; - asset.admin = T::Lookup::lookup(admin)?; - asset.freezer = T::Lookup::lookup(freezer)?; + + let prev_owner = asset.owner; + let new_owner = owner.map(T::Lookup::lookup).transpose()?; + + // move the deposit + if prev_owner != new_owner { + let metadata_deposit = Metadata::::get(id).deposit; + + if let Some(account) = prev_owner { + let old_deposit = asset.deposit + metadata_deposit; + T::Currency::unreserve(&account, old_deposit); + } + if let Some(account) = new_owner.clone() { + let new_deposit = T::AssetDeposit::get() + metadata_deposit; + T::Currency::reserve(&account, new_deposit)?; + } + } + + asset.owner = new_owner; + asset.issuer = issuer.map(T::Lookup::lookup).transpose()?; + asset.admin = admin.map(T::Lookup::lookup).transpose()?; + asset.freezer = freezer.map(T::Lookup::lookup).transpose()?; asset.min_balance = min_balance; asset.is_sufficient = is_sufficient; if is_frozen { @@ -1411,7 +1457,7 @@ pub mod pallet { .map(|_| ()) .or_else(|origin| -> DispatchResult { let origin = ensure_signed(origin)?; - ensure!(origin == d.admin, Error::::NoPermission); + ensure!(Some(origin) == d.admin, Error::::NoPermission); Ok(()) })?; @@ -1514,7 +1560,7 @@ pub mod pallet { id: T::AssetIdParameter, min_balance: T::Balance, ) -> DispatchResult { - let origin = ensure_signed(origin)?; + let origin = ensure_signed_or_root(origin)?; let id: T::AssetId = id.into(); let mut details = Asset::::get(id).ok_or(Error::::Unknown)?; diff --git a/frame/assets/src/migration.rs b/frame/assets/src/migration.rs index 71da8823e92ef..2dc4db8439fc6 100644 --- a/frame/assets/src/migration.rs +++ b/frame/assets/src/migration.rs @@ -19,12 +19,12 @@ use super::*; use frame_support::{log, traits::OnRuntimeUpgrade}; pub mod v1 { - use frame_support::{pallet_prelude::*, weights::Weight}; + use frame_support::pallet_prelude::*; use super::*; #[derive(Decode)] - pub struct OldAssetDetails { + pub struct AssetDetailsV0 { pub owner: AccountId, pub issuer: AccountId, pub admin: AccountId, @@ -39,15 +39,37 @@ pub mod v1 { pub is_frozen: bool, } - impl OldAssetDetails { - fn migrate_to_v1(self) -> AssetDetails { + #[derive(Decode)] + pub struct AssetDetailsV1 { + pub owner: AccountId, + pub issuer: AccountId, + pub admin: AccountId, + pub freezer: AccountId, + pub supply: Balance, + pub deposit: DepositBalance, + pub min_balance: Balance, + pub is_sufficient: bool, + pub accounts: u32, + pub sufficients: u32, + pub approvals: u32, + pub status: AssetStatus, + } +} + +pub mod v2 { + use super::*; + use crate::migration::v1::{AssetDetailsV0, AssetDetailsV1}; + use frame_support::{pallet_prelude::*, weights::Weight}; + + impl AssetDetailsV0 { + fn migrate_from_v0_to_v2(self) -> AssetDetails { let status = if self.is_frozen { AssetStatus::Frozen } else { AssetStatus::Live }; AssetDetails { - owner: self.owner, - issuer: self.issuer, - admin: self.admin, - freezer: self.freezer, + owner: Some(self.owner), + issuer: Some(self.issuer), + admin: Some(self.admin), + freezer: Some(self.freezer), supply: self.supply, deposit: self.deposit, min_balance: self.min_balance, @@ -60,33 +82,57 @@ pub mod v1 { } } - pub struct MigrateToV1(sp_std::marker::PhantomData); - impl OnRuntimeUpgrade for MigrateToV1 { + impl AssetDetailsV1 { + fn migrate_from_v1_to_v2(self) -> AssetDetails { + AssetDetails { + owner: Some(self.owner), + issuer: Some(self.issuer), + admin: Some(self.admin), + freezer: Some(self.freezer), + supply: self.supply, + deposit: self.deposit, + min_balance: self.min_balance, + is_sufficient: self.is_sufficient, + accounts: self.accounts, + sufficients: self.sufficients, + approvals: self.approvals, + status: self.status, + } + } + } + + pub struct MigrateToV2(sp_std::marker::PhantomData); + impl OnRuntimeUpgrade for MigrateToV2 { fn on_runtime_upgrade() -> Weight { let current_version = Pallet::::current_storage_version(); let onchain_version = Pallet::::on_chain_storage_version(); + if onchain_version == 0 && current_version == 1 { let mut translated = 0u64; Asset::::translate::< - OldAssetDetails>, + AssetDetailsV0>, + _, + >(|_key, old_value| { + translated.saturating_inc(); + Some(old_value.migrate_from_v0_to_v2()) + }); + current_version.put::>(); + log::info!(target: "runtime::assets", "Upgraded {} pools, storage to version {:?}", translated, current_version); + T::DbWeight::get().reads_writes(translated + 1, translated + 1) + } else if onchain_version == 1 && current_version == 2 { + let mut translated = 0u64; + Asset::::translate::< + AssetDetailsV1>, _, >(|_key, old_value| { translated.saturating_inc(); - Some(old_value.migrate_to_v1()) + Some(old_value.migrate_from_v1_to_v2()) }); current_version.put::>(); - log::info!( - target: LOG_TARGET, - "Upgraded {} pools, storage to version {:?}", - translated, - current_version - ); + log::info!(target: "runtime::assets", "Upgraded {} asset classes, storage to version {:?}", translated, current_version); T::DbWeight::get().reads_writes(translated + 1, translated + 1) } else { - log::info!( - target: LOG_TARGET, - "Migration did not execute. This probably should be removed" - ); + log::info!(target: "runtime::assets", "Migration did not execute. This probably should be removed"); T::DbWeight::get().reads(1) } } @@ -121,9 +167,6 @@ pub mod v1 { "after migration, the current_version and onchain_version should be the same" ); - 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") - }); Ok(()) } } diff --git a/frame/assets/src/mock.rs b/frame/assets/src/mock.rs index 3926d2fa8b010..442d58051d5f4 100644 --- a/frame/assets/src/mock.rs +++ b/frame/assets/src/mock.rs @@ -95,7 +95,7 @@ impl pallet_balances::Config for Test { pub struct AssetsCallbackHandle; impl AssetsCallback for AssetsCallbackHandle { - fn created(_id: &AssetId, _owner: &AccountId) -> Result<(), ()> { + fn created(_id: &AssetId, _owner: &Option) -> Result<(), ()> { if Self::should_err() { Err(()) } else { diff --git a/frame/assets/src/tests.rs b/frame/assets/src/tests.rs index 88ba92d0685a9..0e5646be5d612 100644 --- a/frame/assets/src/tests.rs +++ b/frame/assets/src/tests.rs @@ -37,7 +37,7 @@ fn asset_ids() -> Vec { #[test] fn transfer_should_never_burn() { new_test_ext().execute_with(|| { - assert_ok!(Assets::force_create(RuntimeOrigin::root(), 0, 1, false, 1)); + assert_ok!(Assets::force_create(RuntimeOrigin::root(), 0, Some(1), false, 1)); Balances::make_free_balance_be(&1, 100); Balances::make_free_balance_be(&2, 100); @@ -56,8 +56,8 @@ fn transfer_should_never_burn() { #[test] fn basic_minting_should_work() { new_test_ext().execute_with(|| { - assert_ok!(Assets::force_create(RuntimeOrigin::root(), 0, 1, true, 1)); - assert_ok!(Assets::force_create(RuntimeOrigin::root(), 1, 1, true, 1)); + assert_ok!(Assets::force_create(RuntimeOrigin::root(), 0, Some(1), true, 1)); + assert_ok!(Assets::force_create(RuntimeOrigin::root(), 1, Some(1), true, 1)); assert_ok!(Assets::mint(RuntimeOrigin::signed(1), 0, 1, 100)); assert_eq!(Assets::balance(0, 1), 100); assert_ok!(Assets::mint(RuntimeOrigin::signed(1), 0, 2, 100)); @@ -71,9 +71,9 @@ fn basic_minting_should_work() { #[test] fn minting_too_many_insufficient_assets_fails() { new_test_ext().execute_with(|| { - assert_ok!(Assets::force_create(RuntimeOrigin::root(), 0, 1, false, 1)); - assert_ok!(Assets::force_create(RuntimeOrigin::root(), 1, 1, false, 1)); - assert_ok!(Assets::force_create(RuntimeOrigin::root(), 2, 1, false, 1)); + assert_ok!(Assets::force_create(RuntimeOrigin::root(), 0, Some(1), false, 1)); + assert_ok!(Assets::force_create(RuntimeOrigin::root(), 1, Some(1), false, 1)); + assert_ok!(Assets::force_create(RuntimeOrigin::root(), 2, Some(1), false, 1)); Balances::make_free_balance_be(&1, 100); assert_ok!(Assets::mint(RuntimeOrigin::signed(1), 0, 1, 100)); assert_ok!(Assets::mint(RuntimeOrigin::signed(1), 1, 1, 100)); @@ -89,9 +89,9 @@ fn minting_too_many_insufficient_assets_fails() { #[test] fn minting_insufficient_asset_with_deposit_should_work_when_consumers_exhausted() { new_test_ext().execute_with(|| { - assert_ok!(Assets::force_create(RuntimeOrigin::root(), 0, 1, false, 1)); - assert_ok!(Assets::force_create(RuntimeOrigin::root(), 1, 1, false, 1)); - assert_ok!(Assets::force_create(RuntimeOrigin::root(), 2, 1, false, 1)); + assert_ok!(Assets::force_create(RuntimeOrigin::root(), 0, Some(1), false, 1)); + assert_ok!(Assets::force_create(RuntimeOrigin::root(), 1, Some(1), false, 1)); + assert_ok!(Assets::force_create(RuntimeOrigin::root(), 2, Some(1), false, 1)); Balances::make_free_balance_be(&1, 100); assert_ok!(Assets::mint(RuntimeOrigin::signed(1), 0, 1, 100)); assert_ok!(Assets::mint(RuntimeOrigin::signed(1), 1, 1, 100)); @@ -107,7 +107,7 @@ fn minting_insufficient_asset_with_deposit_should_work_when_consumers_exhausted( #[test] fn minting_insufficient_assets_with_deposit_without_consumer_should_work() { new_test_ext().execute_with(|| { - assert_ok!(Assets::force_create(RuntimeOrigin::root(), 0, 1, false, 1)); + assert_ok!(Assets::force_create(RuntimeOrigin::root(), 0, Some(1), false, 1)); assert_noop!(Assets::mint(RuntimeOrigin::signed(1), 0, 1, 100), TokenError::CannotCreate); Balances::make_free_balance_be(&1, 100); assert_ok!(Assets::touch(RuntimeOrigin::signed(1), 0)); @@ -120,7 +120,7 @@ fn minting_insufficient_assets_with_deposit_without_consumer_should_work() { #[test] fn refunding_asset_deposit_with_burn_should_work() { new_test_ext().execute_with(|| { - assert_ok!(Assets::force_create(RuntimeOrigin::root(), 0, 1, false, 1)); + assert_ok!(Assets::force_create(RuntimeOrigin::root(), 0, Some(1), false, 1)); Balances::make_free_balance_be(&1, 100); assert_ok!(Assets::touch(RuntimeOrigin::signed(1), 0)); assert_ok!(Assets::mint(RuntimeOrigin::signed(1), 0, 1, 100)); @@ -133,7 +133,7 @@ fn refunding_asset_deposit_with_burn_should_work() { #[test] fn refunding_asset_deposit_with_burn_disallowed_should_fail() { new_test_ext().execute_with(|| { - assert_ok!(Assets::force_create(RuntimeOrigin::root(), 0, 1, false, 1)); + assert_ok!(Assets::force_create(RuntimeOrigin::root(), 0, Some(1), false, 1)); Balances::make_free_balance_be(&1, 100); assert_ok!(Assets::touch(RuntimeOrigin::signed(1), 0)); assert_ok!(Assets::mint(RuntimeOrigin::signed(1), 0, 1, 100)); @@ -144,7 +144,7 @@ fn refunding_asset_deposit_with_burn_disallowed_should_fail() { #[test] fn refunding_asset_deposit_without_burn_should_work() { new_test_ext().execute_with(|| { - assert_ok!(Assets::force_create(RuntimeOrigin::root(), 0, 1, false, 1)); + assert_ok!(Assets::force_create(RuntimeOrigin::root(), 0, Some(1), false, 1)); assert_noop!(Assets::mint(RuntimeOrigin::signed(1), 0, 1, 100), TokenError::CannotCreate); Balances::make_free_balance_be(&1, 100); assert_ok!(Assets::touch(RuntimeOrigin::signed(1), 0)); @@ -164,7 +164,7 @@ fn refunding_asset_deposit_without_burn_should_work() { #[test] fn refunding_calls_died_hook() { new_test_ext().execute_with(|| { - assert_ok!(Assets::force_create(RuntimeOrigin::root(), 0, 1, false, 1)); + assert_ok!(Assets::force_create(RuntimeOrigin::root(), 0, Some(1), false, 1)); Balances::make_free_balance_be(&1, 100); assert_ok!(Assets::touch(RuntimeOrigin::signed(1), 0)); assert_ok!(Assets::mint(RuntimeOrigin::signed(1), 0, 1, 100)); @@ -185,7 +185,7 @@ fn approval_lifecycle_works() { Error::::Unknown ); // so we create it :) - assert_ok!(Assets::force_create(RuntimeOrigin::root(), 0, 1, true, 1)); + assert_ok!(Assets::force_create(RuntimeOrigin::root(), 0, Some(1), true, 1)); assert_ok!(Assets::mint(RuntimeOrigin::signed(1), 0, 1, 100)); Balances::make_free_balance_be(&1, 2); assert_ok!(Assets::approve_transfer(RuntimeOrigin::signed(1), 0, 2, 50)); @@ -211,7 +211,7 @@ fn transfer_approved_all_funds() { Error::::Unknown ); // so we create it :) - assert_ok!(Assets::force_create(RuntimeOrigin::root(), 0, 1, true, 1)); + assert_ok!(Assets::force_create(RuntimeOrigin::root(), 0, Some(1), true, 1)); assert_ok!(Assets::mint(RuntimeOrigin::signed(1), 0, 1, 100)); Balances::make_free_balance_be(&1, 2); assert_ok!(Assets::approve_transfer(RuntimeOrigin::signed(1), 0, 2, 50)); @@ -230,7 +230,7 @@ fn transfer_approved_all_funds() { #[test] fn approval_deposits_work() { new_test_ext().execute_with(|| { - assert_ok!(Assets::force_create(RuntimeOrigin::root(), 0, 1, true, 1)); + assert_ok!(Assets::force_create(RuntimeOrigin::root(), 0, Some(1), true, 1)); assert_ok!(Assets::mint(RuntimeOrigin::signed(1), 0, 1, 100)); let e = BalancesError::::InsufficientBalance; assert_noop!(Assets::approve_transfer(RuntimeOrigin::signed(1), 0, 2, 50), e); @@ -251,7 +251,7 @@ fn approval_deposits_work() { #[test] fn cannot_transfer_more_than_approved() { new_test_ext().execute_with(|| { - assert_ok!(Assets::force_create(RuntimeOrigin::root(), 0, 1, true, 1)); + assert_ok!(Assets::force_create(RuntimeOrigin::root(), 0, Some(1), true, 1)); assert_ok!(Assets::mint(RuntimeOrigin::signed(1), 0, 1, 100)); Balances::make_free_balance_be(&1, 2); assert_ok!(Assets::approve_transfer(RuntimeOrigin::signed(1), 0, 2, 50)); @@ -263,7 +263,7 @@ fn cannot_transfer_more_than_approved() { #[test] fn cannot_transfer_more_than_exists() { new_test_ext().execute_with(|| { - assert_ok!(Assets::force_create(RuntimeOrigin::root(), 0, 1, true, 1)); + assert_ok!(Assets::force_create(RuntimeOrigin::root(), 0, Some(1), true, 1)); assert_ok!(Assets::mint(RuntimeOrigin::signed(1), 0, 1, 100)); Balances::make_free_balance_be(&1, 2); assert_ok!(Assets::approve_transfer(RuntimeOrigin::signed(1), 0, 2, 101)); @@ -275,7 +275,7 @@ fn cannot_transfer_more_than_exists() { #[test] fn cancel_approval_works() { new_test_ext().execute_with(|| { - assert_ok!(Assets::force_create(RuntimeOrigin::root(), 0, 1, true, 1)); + assert_ok!(Assets::force_create(RuntimeOrigin::root(), 0, Some(1), true, 1)); assert_ok!(Assets::mint(RuntimeOrigin::signed(1), 0, 1, 100)); Balances::make_free_balance_be(&1, 2); assert_ok!(Assets::approve_transfer(RuntimeOrigin::signed(1), 0, 2, 50)); @@ -305,7 +305,7 @@ fn cancel_approval_works() { #[test] fn force_cancel_approval_works() { new_test_ext().execute_with(|| { - assert_ok!(Assets::force_create(RuntimeOrigin::root(), 0, 1, true, 1)); + assert_ok!(Assets::force_create(RuntimeOrigin::root(), 0, Some(1), true, 1)); assert_ok!(Assets::mint(RuntimeOrigin::signed(1), 0, 1, 100)); Balances::make_free_balance_be(&1, 2); assert_ok!(Assets::approve_transfer(RuntimeOrigin::signed(1), 0, 2, 50)); @@ -338,7 +338,7 @@ fn force_cancel_approval_works() { fn lifecycle_should_work() { new_test_ext().execute_with(|| { Balances::make_free_balance_be(&1, 100); - assert_ok!(Assets::create(RuntimeOrigin::signed(1), 0, 1, 1)); + assert_ok!(Assets::create(RuntimeOrigin::signed(1), 0, Some(1), 1)); assert_eq!(Balances::reserved_balance(&1), 1); assert!(Asset::::contains_key(0)); @@ -364,7 +364,7 @@ fn lifecycle_should_work() { assert!(!Metadata::::contains_key(0)); assert_eq!(Account::::iter_prefix(0).count(), 0); - assert_ok!(Assets::create(RuntimeOrigin::signed(1), 0, 1, 1)); + assert_ok!(Assets::create(RuntimeOrigin::signed(1), 0, Some(1), 1)); assert_eq!(Balances::reserved_balance(&1), 1); assert!(Asset::::contains_key(0)); @@ -394,7 +394,7 @@ fn lifecycle_should_work() { fn destroy_should_refund_approvals() { 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::force_create(RuntimeOrigin::root(), 0, Some(1), true, 1)); assert_ok!(Assets::mint(RuntimeOrigin::signed(1), 0, 10, 100)); assert_ok!(Assets::approve_transfer(RuntimeOrigin::signed(1), 0, 2, 50)); assert_ok!(Assets::approve_transfer(RuntimeOrigin::signed(1), 0, 3, 50)); @@ -420,7 +420,7 @@ fn destroy_should_refund_approvals() { #[test] fn partial_destroy_should_work() { new_test_ext().execute_with(|| { - assert_ok!(Assets::force_create(RuntimeOrigin::root(), 0, 1, true, 1)); + assert_ok!(Assets::force_create(RuntimeOrigin::root(), 0, Some(1), true, 1)); assert_ok!(Assets::mint(RuntimeOrigin::signed(1), 0, 1, 10)); assert_ok!(Assets::mint(RuntimeOrigin::signed(1), 0, 2, 10)); assert_ok!(Assets::mint(RuntimeOrigin::signed(1), 0, 3, 10)); @@ -472,7 +472,7 @@ fn partial_destroy_should_work() { #[test] fn non_providing_should_work() { new_test_ext().execute_with(|| { - assert_ok!(Assets::force_create(RuntimeOrigin::root(), 0, 1, false, 1)); + assert_ok!(Assets::force_create(RuntimeOrigin::root(), 0, Some(1), false, 1)); Balances::make_free_balance_be(&0, 100); assert_ok!(Assets::mint(RuntimeOrigin::signed(1), 0, 0, 100)); @@ -501,7 +501,7 @@ fn non_providing_should_work() { #[test] fn min_balance_should_work() { new_test_ext().execute_with(|| { - assert_ok!(Assets::force_create(RuntimeOrigin::root(), 0, 1, true, 10)); + assert_ok!(Assets::force_create(RuntimeOrigin::root(), 0, Some(1), true, 10)); assert_ok!(Assets::mint(RuntimeOrigin::signed(1), 0, 1, 100)); assert_eq!(Asset::::get(0).unwrap().accounts, 1); @@ -546,7 +546,7 @@ fn min_balance_should_work() { #[test] fn querying_total_supply_should_work() { new_test_ext().execute_with(|| { - assert_ok!(Assets::force_create(RuntimeOrigin::root(), 0, 1, true, 1)); + assert_ok!(Assets::force_create(RuntimeOrigin::root(), 0, Some(1), true, 1)); assert_ok!(Assets::mint(RuntimeOrigin::signed(1), 0, 1, 100)); assert_eq!(Assets::balance(0, 1), 100); assert_ok!(Assets::transfer(RuntimeOrigin::signed(1), 0, 2, 50)); @@ -564,7 +564,7 @@ fn querying_total_supply_should_work() { #[test] fn transferring_amount_below_available_balance_should_work() { new_test_ext().execute_with(|| { - assert_ok!(Assets::force_create(RuntimeOrigin::root(), 0, 1, true, 1)); + assert_ok!(Assets::force_create(RuntimeOrigin::root(), 0, Some(1), true, 1)); assert_ok!(Assets::mint(RuntimeOrigin::signed(1), 0, 1, 100)); assert_eq!(Assets::balance(0, 1), 100); assert_ok!(Assets::transfer(RuntimeOrigin::signed(1), 0, 2, 50)); @@ -576,7 +576,7 @@ fn transferring_amount_below_available_balance_should_work() { #[test] fn transferring_enough_to_kill_source_when_keep_alive_should_fail() { new_test_ext().execute_with(|| { - assert_ok!(Assets::force_create(RuntimeOrigin::root(), 0, 1, true, 10)); + assert_ok!(Assets::force_create(RuntimeOrigin::root(), 0, Some(1), true, 10)); assert_ok!(Assets::mint(RuntimeOrigin::signed(1), 0, 1, 100)); assert_eq!(Assets::balance(0, 1), 100); assert_noop!( @@ -594,7 +594,7 @@ fn transferring_enough_to_kill_source_when_keep_alive_should_fail() { #[test] fn transferring_frozen_user_should_not_work() { new_test_ext().execute_with(|| { - assert_ok!(Assets::force_create(RuntimeOrigin::root(), 0, 1, true, 1)); + assert_ok!(Assets::force_create(RuntimeOrigin::root(), 0, Some(1), true, 1)); assert_ok!(Assets::mint(RuntimeOrigin::signed(1), 0, 1, 100)); assert_eq!(Assets::balance(0, 1), 100); assert_ok!(Assets::freeze(RuntimeOrigin::signed(1), 0, 1)); @@ -607,7 +607,7 @@ fn transferring_frozen_user_should_not_work() { #[test] fn transferring_frozen_asset_should_not_work() { new_test_ext().execute_with(|| { - assert_ok!(Assets::force_create(RuntimeOrigin::root(), 0, 1, true, 1)); + assert_ok!(Assets::force_create(RuntimeOrigin::root(), 0, Some(1), true, 1)); assert_ok!(Assets::mint(RuntimeOrigin::signed(1), 0, 1, 100)); assert_eq!(Assets::balance(0, 1), 100); assert_ok!(Assets::freeze_asset(RuntimeOrigin::signed(1), 0)); @@ -624,7 +624,7 @@ fn transferring_frozen_asset_should_not_work() { fn approve_transfer_frozen_asset_should_not_work() { 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::force_create(RuntimeOrigin::root(), 0, Some(1), true, 1)); assert_ok!(Assets::mint(RuntimeOrigin::signed(1), 0, 1, 100)); assert_eq!(Assets::balance(0, 1), 100); assert_ok!(Assets::freeze_asset(RuntimeOrigin::signed(1), 0)); @@ -640,14 +640,14 @@ fn approve_transfer_frozen_asset_should_not_work() { #[test] fn origin_guards_should_work() { new_test_ext().execute_with(|| { - assert_ok!(Assets::force_create(RuntimeOrigin::root(), 0, 1, true, 1)); + assert_ok!(Assets::force_create(RuntimeOrigin::root(), 0, Some(1), true, 1)); assert_ok!(Assets::mint(RuntimeOrigin::signed(1), 0, 1, 100)); assert_noop!( - Assets::transfer_ownership(RuntimeOrigin::signed(2), 0, 2), + Assets::transfer_ownership(RuntimeOrigin::signed(2), 0, Some(2)), Error::::NoPermission ); assert_noop!( - Assets::set_team(RuntimeOrigin::signed(2), 0, 2, 2, 2), + Assets::set_team(RuntimeOrigin::signed(2), 0, Some(2), Some(2), Some(2)), Error::::NoPermission ); assert_noop!(Assets::freeze(RuntimeOrigin::signed(2), 0, 1), Error::::NoPermission); @@ -676,17 +676,17 @@ fn transfer_owner_should_work() { new_test_ext().execute_with(|| { Balances::make_free_balance_be(&1, 100); Balances::make_free_balance_be(&2, 100); - assert_ok!(Assets::create(RuntimeOrigin::signed(1), 0, 1, 1)); + assert_ok!(Assets::create(RuntimeOrigin::signed(1), 0, Some(1), 1)); assert_eq!(asset_ids(), vec![0, 999]); assert_eq!(Balances::reserved_balance(&1), 1); - assert_ok!(Assets::transfer_ownership(RuntimeOrigin::signed(1), 0, 2)); + assert_ok!(Assets::transfer_ownership(RuntimeOrigin::signed(1), 0, Some(2))); assert_eq!(Balances::reserved_balance(&2), 1); assert_eq!(Balances::reserved_balance(&1), 0); assert_noop!( - Assets::transfer_ownership(RuntimeOrigin::signed(1), 0, 1), + Assets::transfer_ownership(RuntimeOrigin::signed(1), 0, Some(1)), Error::::NoPermission ); @@ -698,7 +698,7 @@ fn transfer_owner_should_work() { vec![0u8; 10], 12 )); - assert_ok!(Assets::transfer_ownership(RuntimeOrigin::signed(2), 0, 1)); + assert_ok!(Assets::transfer_ownership(RuntimeOrigin::signed(2), 0, Some(1))); assert_eq!(Balances::reserved_balance(&1), 22); assert_eq!(Balances::reserved_balance(&2), 0); }); @@ -707,8 +707,8 @@ fn transfer_owner_should_work() { #[test] fn set_team_should_work() { new_test_ext().execute_with(|| { - assert_ok!(Assets::force_create(RuntimeOrigin::root(), 0, 1, true, 1)); - assert_ok!(Assets::set_team(RuntimeOrigin::signed(1), 0, 2, 3, 4)); + assert_ok!(Assets::force_create(RuntimeOrigin::root(), 0, Some(1), true, 1)); + assert_ok!(Assets::set_team(RuntimeOrigin::signed(1), 0, Some(2), Some(3), Some(4))); assert_ok!(Assets::mint(RuntimeOrigin::signed(2), 0, 2, 100)); assert_ok!(Assets::freeze(RuntimeOrigin::signed(4), 0, 2)); @@ -721,7 +721,7 @@ fn set_team_should_work() { #[test] fn transferring_to_frozen_account_should_work() { new_test_ext().execute_with(|| { - assert_ok!(Assets::force_create(RuntimeOrigin::root(), 0, 1, true, 1)); + assert_ok!(Assets::force_create(RuntimeOrigin::root(), 0, Some(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); @@ -735,7 +735,7 @@ fn transferring_to_frozen_account_should_work() { #[test] fn transferring_amount_more_than_available_balance_should_not_work() { new_test_ext().execute_with(|| { - assert_ok!(Assets::force_create(RuntimeOrigin::root(), 0, 1, true, 1)); + assert_ok!(Assets::force_create(RuntimeOrigin::root(), 0, Some(1), true, 1)); assert_ok!(Assets::mint(RuntimeOrigin::signed(1), 0, 1, 100)); assert_eq!(Assets::balance(0, 1), 100); assert_ok!(Assets::transfer(RuntimeOrigin::signed(1), 0, 2, 50)); @@ -757,7 +757,7 @@ fn transferring_amount_more_than_available_balance_should_not_work() { #[test] fn transferring_less_than_one_unit_is_fine() { new_test_ext().execute_with(|| { - assert_ok!(Assets::force_create(RuntimeOrigin::root(), 0, 1, true, 1)); + assert_ok!(Assets::force_create(RuntimeOrigin::root(), 0, Some(1), true, 1)); assert_ok!(Assets::mint(RuntimeOrigin::signed(1), 0, 1, 100)); assert_eq!(Assets::balance(0, 1), 100); assert_ok!(Assets::transfer(RuntimeOrigin::signed(1), 0, 2, 0)); @@ -769,7 +769,7 @@ fn transferring_less_than_one_unit_is_fine() { #[test] fn transferring_more_units_than_total_supply_should_not_work() { new_test_ext().execute_with(|| { - assert_ok!(Assets::force_create(RuntimeOrigin::root(), 0, 1, true, 1)); + assert_ok!(Assets::force_create(RuntimeOrigin::root(), 0, Some(1), true, 1)); assert_ok!(Assets::mint(RuntimeOrigin::signed(1), 0, 1, 100)); assert_eq!(Assets::balance(0, 1), 100); assert_noop!( @@ -782,7 +782,7 @@ fn transferring_more_units_than_total_supply_should_not_work() { #[test] fn burning_asset_balance_with_positive_balance_should_work() { new_test_ext().execute_with(|| { - assert_ok!(Assets::force_create(RuntimeOrigin::root(), 0, 1, true, 1)); + assert_ok!(Assets::force_create(RuntimeOrigin::root(), 0, Some(1), true, 1)); assert_ok!(Assets::mint(RuntimeOrigin::signed(1), 0, 1, 100)); assert_eq!(Assets::balance(0, 1), 100); assert_ok!(Assets::burn(RuntimeOrigin::signed(1), 0, 1, u64::MAX)); @@ -793,7 +793,7 @@ fn burning_asset_balance_with_positive_balance_should_work() { #[test] fn burning_asset_balance_with_zero_balance_does_nothing() { new_test_ext().execute_with(|| { - assert_ok!(Assets::force_create(RuntimeOrigin::root(), 0, 1, true, 1)); + assert_ok!(Assets::force_create(RuntimeOrigin::root(), 0, Some(1), true, 1)); assert_ok!(Assets::mint(RuntimeOrigin::signed(1), 0, 1, 100)); assert_eq!(Assets::balance(0, 2), 0); assert_noop!( @@ -813,7 +813,7 @@ fn set_metadata_should_work() { Assets::set_metadata(RuntimeOrigin::signed(1), 0, vec![0u8; 10], vec![0u8; 10], 12), Error::::Unknown, ); - assert_ok!(Assets::force_create(RuntimeOrigin::root(), 0, 1, true, 1)); + assert_ok!(Assets::force_create(RuntimeOrigin::root(), 0, Some(1), true, 1)); // Cannot add metadata to unowned asset assert_noop!( Assets::set_metadata(RuntimeOrigin::signed(2), 0, vec![0u8; 10], vec![0u8; 10], 12), @@ -881,7 +881,7 @@ fn set_metadata_should_work() { #[test] fn destroy_accounts_calls_died_hooks() { new_test_ext().execute_with(|| { - assert_ok!(Assets::force_create(RuntimeOrigin::root(), 0, 1, true, 50)); + assert_ok!(Assets::force_create(RuntimeOrigin::root(), 0, Some(1), true, 50)); // Create account 1 and 2. assert_ok!(Assets::mint(RuntimeOrigin::signed(1), 0, 1, 100)); assert_ok!(Assets::mint(RuntimeOrigin::signed(1), 0, 2, 100)); @@ -899,7 +899,7 @@ fn destroy_accounts_calls_died_hooks() { #[test] fn finish_destroy_asset_destroys_asset() { new_test_ext().execute_with(|| { - assert_ok!(Assets::force_create(RuntimeOrigin::root(), 0, 1, true, 50)); + assert_ok!(Assets::force_create(RuntimeOrigin::root(), 0, Some(1), true, 50)); // Destroy the accounts. assert_ok!(Assets::freeze_asset(RuntimeOrigin::signed(1), 0)); assert_ok!(Assets::start_destroy(RuntimeOrigin::signed(1), 0)); @@ -913,7 +913,7 @@ fn finish_destroy_asset_destroys_asset() { #[test] fn freezer_should_work() { new_test_ext().execute_with(|| { - assert_ok!(Assets::force_create(RuntimeOrigin::root(), 0, 1, true, 10)); + assert_ok!(Assets::force_create(RuntimeOrigin::root(), 0, Some(1), true, 10)); assert_ok!(Assets::mint(RuntimeOrigin::signed(1), 0, 1, 100)); assert_eq!(Assets::balance(0, 1), 100); @@ -955,7 +955,7 @@ fn imbalances_should_work() { use frame_support::traits::tokens::fungibles::Balanced; new_test_ext().execute_with(|| { - assert_ok!(Assets::force_create(RuntimeOrigin::root(), 0, 1, true, 1)); + assert_ok!(Assets::force_create(RuntimeOrigin::root(), 0, Some(1), true, 1)); let imb = Assets::issue(0, 100); assert_eq!(Assets::total_supply(0), 100); @@ -978,7 +978,7 @@ fn imbalances_should_work() { fn force_metadata_should_work() { new_test_ext().execute_with(|| { // force set metadata works - assert_ok!(Assets::force_create(RuntimeOrigin::root(), 0, 1, true, 1)); + assert_ok!(Assets::force_create(RuntimeOrigin::root(), 0, Some(1), true, 1)); assert_ok!(Assets::force_set_metadata( RuntimeOrigin::root(), 0, @@ -1057,7 +1057,7 @@ fn force_asset_status_should_work() { new_test_ext().execute_with(|| { Balances::make_free_balance_be(&1, 10); Balances::make_free_balance_be(&2, 10); - assert_ok!(Assets::create(RuntimeOrigin::signed(1), 0, 1, 30)); + assert_ok!(Assets::create(RuntimeOrigin::signed(1), 0, Some(1), 30)); assert_ok!(Assets::mint(RuntimeOrigin::signed(1), 0, 1, 50)); assert_ok!(Assets::mint(RuntimeOrigin::signed(1), 0, 2, 150)); @@ -1065,10 +1065,10 @@ fn force_asset_status_should_work() { assert_ok!(Assets::force_asset_status( RuntimeOrigin::root(), 0, - 1, - 1, - 1, - 1, + Some(1), + Some(1), + Some(1), + Some(1), 100, true, false @@ -1091,7 +1091,17 @@ fn force_asset_status_should_work() { // force asset status will not execute for non-existent class assert_noop!( - Assets::force_asset_status(RuntimeOrigin::root(), 1, 1, 1, 1, 1, 90, true, false), + Assets::force_asset_status( + RuntimeOrigin::root(), + 1, + Some(1), + Some(1), + Some(1), + Some(1), + 90, + true, + false + ), Error::::Unknown ); @@ -1099,10 +1109,10 @@ fn force_asset_status_should_work() { assert_ok!(Assets::force_asset_status( RuntimeOrigin::root(), 0, - 1, - 1, - 1, - 1, + Some(1), + Some(1), + Some(1), + Some(1), 110, true, false @@ -1119,7 +1129,7 @@ fn set_min_balance_should_work() { new_test_ext().execute_with(|| { let id = 42; Balances::make_free_balance_be(&1, 10); - assert_ok!(Assets::create(RuntimeOrigin::signed(1), id, 1, 30)); + assert_ok!(Assets::create(RuntimeOrigin::signed(1), id, Some(1), 30)); assert_ok!(Assets::mint(RuntimeOrigin::signed(1), id, 1, 100)); // Won't execute because there is an asset holder. @@ -1132,10 +1142,10 @@ fn set_min_balance_should_work() { assert_ok!(Assets::force_asset_status( RuntimeOrigin::root(), id, - 1, - 1, - 1, - 1, + Some(1), + Some(1), + Some(1), + Some(1), 30, true, false @@ -1152,10 +1162,10 @@ fn set_min_balance_should_work() { assert_ok!(Assets::force_asset_status( RuntimeOrigin::root(), id, - 1, - 1, - 1, - 1, + Some(1), + Some(1), + Some(1), + Some(1), 60, false, false @@ -1179,9 +1189,9 @@ fn balance_conversion_should_work() { use frame_support::traits::tokens::ConversionToAssetBalance; let id = 42; - assert_ok!(Assets::force_create(RuntimeOrigin::root(), id, 1, true, 10)); + assert_ok!(Assets::force_create(RuntimeOrigin::root(), id, Some(1), true, 10)); let not_sufficient = 23; - assert_ok!(Assets::force_create(RuntimeOrigin::root(), not_sufficient, 1, false, 10)); + assert_ok!(Assets::force_create(RuntimeOrigin::root(), not_sufficient, Some(1), false, 10)); assert_eq!(asset_ids(), vec![23, 42, 999]); assert_eq!( BalanceToAssetBalance::::to_asset_balance(100, 1234), @@ -1216,7 +1226,7 @@ fn assets_from_genesis_should_exist() { fn querying_name_symbol_and_decimals_should_work() { new_test_ext().execute_with(|| { use frame_support::traits::tokens::fungibles::metadata::Inspect; - assert_ok!(Assets::force_create(RuntimeOrigin::root(), 0, 1, true, 1)); + assert_ok!(Assets::force_create(RuntimeOrigin::root(), 0, Some(1), true, 1)); assert_ok!(Assets::force_set_metadata( RuntimeOrigin::root(), 0, @@ -1235,7 +1245,7 @@ fn querying_name_symbol_and_decimals_should_work() { fn querying_allowance_should_work() { new_test_ext().execute_with(|| { use frame_support::traits::tokens::fungibles::approvals::{Inspect, Mutate}; - assert_ok!(Assets::force_create(RuntimeOrigin::root(), 0, 1, true, 1)); + assert_ok!(Assets::force_create(RuntimeOrigin::root(), 0, Some(1), true, 1)); assert_ok!(Assets::mint(RuntimeOrigin::signed(1), 0, 1, 100)); Balances::make_free_balance_be(&1, 2); assert_ok!(Assets::approve(0, &1, &2, 50)); @@ -1250,7 +1260,7 @@ fn querying_allowance_should_work() { fn transfer_large_asset() { new_test_ext().execute_with(|| { let amount = u64::pow(2, 63) + 2; - assert_ok!(Assets::force_create(RuntimeOrigin::root(), 0, 1, true, 1)); + assert_ok!(Assets::force_create(RuntimeOrigin::root(), 0, Some(1), true, 1)); assert_ok!(Assets::mint(RuntimeOrigin::signed(1), 0, 1, amount)); assert_ok!(Assets::transfer(RuntimeOrigin::signed(1), 0, 2, amount - 1)); }) @@ -1260,16 +1270,16 @@ fn transfer_large_asset() { fn querying_roles_should_work() { new_test_ext().execute_with(|| { use frame_support::traits::tokens::fungibles::roles::Inspect; - assert_ok!(Assets::force_create(RuntimeOrigin::root(), 0, 1, true, 1)); + assert_ok!(Assets::force_create(RuntimeOrigin::root(), 0, Some(1), true, 1)); assert_ok!(Assets::set_team( RuntimeOrigin::signed(1), 0, // Issuer - 2, + Some(2), // Admin - 3, + Some(3), // Freezer - 4, + Some(4), )); assert_eq!(Assets::owner(0), Some(1)); assert_eq!(Assets::issuer(0), Some(2)); @@ -1285,7 +1295,7 @@ fn normal_asset_create_and_destroy_callbacks_should_work() { assert!(storage::get(AssetsCallbackHandle::DESTROYED.as_bytes()).is_none()); Balances::make_free_balance_be(&1, 100); - assert_ok!(Assets::create(RuntimeOrigin::signed(1), 0, 1, 1)); + assert_ok!(Assets::create(RuntimeOrigin::signed(1), 0, Some(1), 1)); assert!(storage::get(AssetsCallbackHandle::CREATED.as_bytes()).is_some()); assert!(storage::get(AssetsCallbackHandle::DESTROYED.as_bytes()).is_none()); @@ -1304,7 +1314,7 @@ fn normal_asset_create_and_destroy_callbacks_should_work() { fn root_asset_create_should_work() { new_test_ext().execute_with(|| { assert!(storage::get(AssetsCallbackHandle::CREATED.as_bytes()).is_none()); - assert_ok!(Assets::force_create(RuntimeOrigin::root(), 0, 1, true, 1)); + assert_ok!(Assets::force_create(RuntimeOrigin::root(), 0, Some(1), true, 1)); assert!(storage::get(AssetsCallbackHandle::CREATED.as_bytes()).is_some()); assert!(storage::get(AssetsCallbackHandle::DESTROYED.as_bytes()).is_none()); }); @@ -1317,13 +1327,13 @@ fn asset_create_and_destroy_is_reverted_if_callback_fails() { AssetsCallbackHandle::set_return_error(); Balances::make_free_balance_be(&1, 100); assert_noop!( - Assets::create(RuntimeOrigin::signed(1), 0, 1, 1), + Assets::create(RuntimeOrigin::signed(1), 0, Some(1), 1), Error::::CallbackFailed ); // Callback succeeds, so asset creation succeeds AssetsCallbackHandle::set_return_ok(); - assert_ok!(Assets::create(RuntimeOrigin::signed(1), 0, 1, 1)); + assert_ok!(Assets::create(RuntimeOrigin::signed(1), 0, Some(1), 1)); // Asset destroy should fail due to callback failure AssetsCallbackHandle::set_return_error(); @@ -1346,7 +1356,7 @@ fn multiple_transfer_alls_work_ok() { Balances::force_set_balance(RuntimeOrigin::root(), 1, 100).unwrap(); // Emulate a sufficient, in reality this could be reached by transferring a sufficient // asset to the account - assert_ok!(Assets::force_create(RuntimeOrigin::root(), 0, 1, true, 1)); + assert_ok!(Assets::force_create(RuntimeOrigin::root(), 0, Some(1), true, 1)); assert_ok!(Assets::mint(RuntimeOrigin::signed(1), 0, 1, 100)); // Spend the same balance multiple times assert_ok!(Balances::transfer_all(RuntimeOrigin::signed(1), 1337, false)); @@ -1359,7 +1369,8 @@ fn multiple_transfer_alls_work_ok() { #[test] fn weights_sane() { - let info = crate::Call::::create { id: 10, admin: 4, min_balance: 3 }.get_dispatch_info(); + let info = + crate::Call::::create { id: 10, admin: Some(4), min_balance: 3 }.get_dispatch_info(); assert_eq!(<() as crate::WeightInfo>::create(), info.weight); let info = crate::Call::::finish_destroy { id: 10 }.get_dispatch_info(); diff --git a/frame/assets/src/types.rs b/frame/assets/src/types.rs index c83e764f4a68d..14fcb3f6184d9 100644 --- a/frame/assets/src/types.rs +++ b/frame/assets/src/types.rs @@ -32,7 +32,7 @@ pub(super) type AssetAccountOf = /// AssetStatus holds the current state of the asset. It could either be Live and available for use, /// or in a Destroying state. #[derive(Clone, Encode, Decode, Eq, PartialEq, RuntimeDebug, MaxEncodedLen, TypeInfo)] -pub(super) enum AssetStatus { +pub enum AssetStatus { /// The asset is active and able to be used. Live, /// Whether the asset is frozen for non-admin transfers. @@ -45,13 +45,13 @@ pub(super) enum AssetStatus { #[derive(Clone, Encode, Decode, Eq, PartialEq, RuntimeDebug, MaxEncodedLen, TypeInfo)] pub struct AssetDetails { /// Can change `owner`, `issuer`, `freezer` and `admin` accounts. - pub(super) owner: AccountId, + pub(super) owner: Option, /// Can mint tokens. - pub(super) issuer: AccountId, + pub(super) issuer: Option, /// Can thaw tokens, force transfers and burn tokens from any account. - pub(super) admin: AccountId, + pub(super) admin: Option, /// Can freeze tokens. - pub(super) freezer: AccountId, + pub(super) freezer: Option, /// The total supply across all accounts. pub(super) supply: Balance, /// The balance deposited for this asset. This pays for the data stored here. diff --git a/frame/support/src/traits/tokens/fungibles/lifetime.rs b/frame/support/src/traits/tokens/fungibles/lifetime.rs index 9e2c306f6f38a..652f68f9dd9e8 100644 --- a/frame/support/src/traits/tokens/fungibles/lifetime.rs +++ b/frame/support/src/traits/tokens/fungibles/lifetime.rs @@ -26,7 +26,7 @@ pub trait Create: Inspect { /// Create a new fungible asset. fn create( id: Self::AssetId, - admin: AccountId, + admin: Option, is_sufficient: bool, min_balance: Self::Balance, ) -> DispatchResult; diff --git a/frame/transaction-payment/asset-tx-payment/src/tests.rs b/frame/transaction-payment/asset-tx-payment/src/tests.rs index 2fee9c849f4b4..40a9df44e5474 100644 --- a/frame/transaction-payment/asset-tx-payment/src/tests.rs +++ b/frame/transaction-payment/asset-tx-payment/src/tests.rs @@ -163,8 +163,8 @@ fn transaction_payment_in_asset_possible() { assert_ok!(Assets::force_create( RuntimeOrigin::root(), asset_id.into(), - 42, /* owner */ - true, /* is_sufficient */ + Some(42), /* owner */ + true, /* is_sufficient */ min_balance )); @@ -216,8 +216,8 @@ fn transaction_payment_without_fee() { assert_ok!(Assets::force_create( RuntimeOrigin::root(), asset_id.into(), - 42, /* owner */ - true, /* is_sufficient */ + Some(42), /* owner */ + true, /* is_sufficient */ min_balance )); @@ -269,8 +269,8 @@ fn asset_transaction_payment_with_tip_and_refund() { assert_ok!(Assets::force_create( RuntimeOrigin::root(), asset_id.into(), - 42, /* owner */ - true, /* is_sufficient */ + Some(42), /* owner */ + true, /* is_sufficient */ min_balance )); @@ -321,8 +321,8 @@ fn payment_from_account_with_only_assets() { assert_ok!(Assets::force_create( RuntimeOrigin::root(), asset_id.into(), - 42, /* owner */ - true, /* is_sufficient */ + Some(42), /* owner */ + true, /* is_sufficient */ min_balance )); @@ -380,8 +380,8 @@ fn payment_only_with_existing_sufficient_asset() { assert_ok!(Assets::force_create( RuntimeOrigin::root(), asset_id.into(), - 42, /* owner */ - false, /* is_sufficient */ + Some(42), /* owner */ + false, /* is_sufficient */ min_balance )); // pre_dispatch fails for non-sufficient asset @@ -405,8 +405,8 @@ fn converted_fee_is_never_zero_if_input_fee_is_not() { assert_ok!(Assets::force_create( RuntimeOrigin::root(), asset_id.into(), - 42, /* owner */ - true, /* is_sufficient */ + Some(42), /* owner */ + true, /* is_sufficient */ min_balance )); @@ -470,8 +470,8 @@ fn post_dispatch_fee_is_zero_if_pre_dispatch_fee_is_zero() { assert_ok!(Assets::force_create( RuntimeOrigin::root(), asset_id.into(), - 42, /* owner */ - true, /* is_sufficient */ + Some(42), /* owner */ + true, /* is_sufficient */ min_balance )); @@ -527,8 +527,8 @@ fn post_dispatch_fee_is_zero_if_unsigned_pre_dispatch_fee_is_zero() { assert_ok!(Assets::force_create( RuntimeOrigin::root(), asset_id.into(), - 42, /* owner */ - true, /* is_sufficient */ + Some(42), /* owner */ + true, /* is_sufficient */ min_balance ));