diff --git a/frame/assets/src/benchmarking.rs b/frame/assets/src/benchmarking.rs index 90b6f65b39890..986eedfb6a861 100644 --- a/frame/assets/src/benchmarking.rs +++ b/frame/assets/src/benchmarking.rs @@ -21,6 +21,7 @@ use super::*; use sp_runtime::traits::Bounded; use frame_system::RawOrigin as SystemOrigin; use frame_benchmarking::{benchmarks, account, whitelisted_caller}; +use frame_support::traits::Get; use crate::Module as Assets; @@ -79,7 +80,7 @@ benchmarks! { T::Currency::make_free_balance_be(&caller, BalanceOf::::max_value()); }: _(SystemOrigin::Signed(caller.clone()), Default::default(), caller_lookup, 1, 1u32.into()) verify { - assert_last_event::(RawEvent::Created(Default::default(), caller.clone(), caller).into()); + assert_last_event::(Event::Created(Default::default(), caller.clone(), caller).into()); } force_create { @@ -87,7 +88,7 @@ benchmarks! { let caller_lookup = T::Lookup::unlookup(caller.clone()); }: _(SystemOrigin::Root, Default::default(), caller_lookup, 1, 1u32.into()) verify { - assert_last_event::(RawEvent::ForceCreated(Default::default(), caller).into()); + assert_last_event::(Event::ForceCreated(Default::default(), caller).into()); } destroy { @@ -96,7 +97,7 @@ benchmarks! { add_zombies::(caller.clone(), z); }: _(SystemOrigin::Signed(caller), Default::default(), 10_000) verify { - assert_last_event::(RawEvent::Destroyed(Default::default()).into()); + assert_last_event::(Event::Destroyed(Default::default()).into()); } force_destroy { @@ -105,7 +106,7 @@ benchmarks! { add_zombies::(caller.clone(), z); }: _(SystemOrigin::Root, Default::default(), 10_000) verify { - assert_last_event::(RawEvent::Destroyed(Default::default()).into()); + assert_last_event::(Event::Destroyed(Default::default()).into()); } mint { @@ -113,7 +114,7 @@ benchmarks! { let amount = T::Balance::from(100u32); }: _(SystemOrigin::Signed(caller.clone()), Default::default(), caller_lookup, amount) verify { - assert_last_event::(RawEvent::Issued(Default::default(), caller, amount).into()); + assert_last_event::(Event::Issued(Default::default(), caller, amount).into()); } burn { @@ -121,7 +122,7 @@ benchmarks! { let (caller, caller_lookup) = create_default_minted_asset::(10, amount); }: _(SystemOrigin::Signed(caller.clone()), Default::default(), caller_lookup, amount) verify { - assert_last_event::(RawEvent::Burned(Default::default(), caller, amount).into()); + assert_last_event::(Event::Burned(Default::default(), caller, amount).into()); } transfer { @@ -131,7 +132,7 @@ benchmarks! { let target_lookup = T::Lookup::unlookup(target.clone()); }: _(SystemOrigin::Signed(caller.clone()), Default::default(), target_lookup, amount) verify { - assert_last_event::(RawEvent::Transferred(Default::default(), caller, target, amount).into()); + assert_last_event::(Event::Transferred(Default::default(), caller, target, amount).into()); } force_transfer { @@ -141,14 +142,16 @@ benchmarks! { let target_lookup = T::Lookup::unlookup(target.clone()); }: _(SystemOrigin::Signed(caller.clone()), Default::default(), caller_lookup, target_lookup, amount) verify { - assert_last_event::(RawEvent::ForceTransferred(Default::default(), caller, target, amount).into()); + assert_last_event::( + Event::ForceTransferred(Default::default(), caller, target, amount).into() + ); } freeze { let (caller, caller_lookup) = create_default_minted_asset::(10, 100u32.into()); }: _(SystemOrigin::Signed(caller.clone()), Default::default(), caller_lookup) verify { - assert_last_event::(RawEvent::Frozen(Default::default(), caller).into()); + assert_last_event::(Event::Frozen(Default::default(), caller).into()); } thaw { @@ -160,14 +163,14 @@ benchmarks! { )?; }: _(SystemOrigin::Signed(caller.clone()), Default::default(), caller_lookup) verify { - assert_last_event::(RawEvent::Thawed(Default::default(), caller).into()); + assert_last_event::(Event::Thawed(Default::default(), caller).into()); } freeze_asset { let (caller, caller_lookup) = create_default_minted_asset::(10, 100u32.into()); }: _(SystemOrigin::Signed(caller.clone()), Default::default()) verify { - assert_last_event::(RawEvent::AssetFrozen(Default::default()).into()); + assert_last_event::(Event::AssetFrozen(Default::default()).into()); } thaw_asset { @@ -178,7 +181,7 @@ benchmarks! { )?; }: _(SystemOrigin::Signed(caller.clone()), Default::default()) verify { - assert_last_event::(RawEvent::AssetThawed(Default::default()).into()); + assert_last_event::(Event::AssetThawed(Default::default()).into()); } transfer_ownership { @@ -187,7 +190,7 @@ benchmarks! { let target_lookup = T::Lookup::unlookup(target.clone()); }: _(SystemOrigin::Signed(caller), Default::default(), target_lookup) verify { - assert_last_event::(RawEvent::OwnerChanged(Default::default(), target).into()); + assert_last_event::(Event::OwnerChanged(Default::default(), target).into()); } set_team { @@ -197,7 +200,7 @@ benchmarks! { let target2 = T::Lookup::unlookup(account("target", 2, SEED)); }: _(SystemOrigin::Signed(caller), Default::default(), target0.clone(), target1.clone(), target2.clone()) verify { - assert_last_event::(RawEvent::TeamChanged( + assert_last_event::(Event::TeamChanged( Default::default(), account("target", 0, SEED), account("target", 1, SEED), @@ -211,7 +214,7 @@ benchmarks! { T::Currency::make_free_balance_be(&caller, BalanceOf::::max_value()); }: _(SystemOrigin::Signed(caller), Default::default(), max_zombies) verify { - assert_last_event::(RawEvent::MaxZombiesChanged(Default::default(), max_zombies).into()); + assert_last_event::(Event::MaxZombiesChanged(Default::default(), max_zombies).into()); } set_metadata { @@ -226,7 +229,7 @@ benchmarks! { T::Currency::make_free_balance_be(&caller, BalanceOf::::max_value()); }: _(SystemOrigin::Signed(caller), Default::default(), name.clone(), symbol.clone(), decimals) verify { - assert_last_event::(RawEvent::MetadataSet(Default::default(), name, symbol, decimals).into()); + assert_last_event::(Event::MetadataSet(Default::default(), name, symbol, decimals).into()); } } diff --git a/frame/assets/src/lib.rs b/frame/assets/src/lib.rs index 099361eceb95c..e5fa5f1fa5d1e 100644 --- a/frame/assets/src/lib.rs +++ b/frame/assets/src/lib.rs @@ -29,9 +29,9 @@ //! * Asset Freezing //! * Asset Destruction (Burning) //! -//! To use it in your runtime, you need to implement the assets [`Config`](./trait.Config.html). +//! To use it in your runtime, you need to implement the assets [`Config`]. //! -//! The supported dispatchable functions are documented in the [`Call`](./enum.Call.html) enum. +//! The supported dispatchable functions are documented in the [`Call`] enum. //! //! ### Terminology //! @@ -114,214 +114,81 @@ mod benchmarking; pub mod weights; use sp_std::{fmt::Debug, prelude::*}; -use sp_runtime::{RuntimeDebug, traits::{ - Member, AtLeast32BitUnsigned, Zero, StaticLookup, Saturating, CheckedSub, CheckedAdd -}}; +use sp_runtime::{ + RuntimeDebug, + traits::{ + AtLeast32BitUnsigned, Zero, StaticLookup, Saturating, CheckedSub, CheckedAdd, + } +}; use codec::{Encode, Decode, HasCompact}; -use frame_support::{Parameter, decl_module, decl_event, decl_storage, decl_error, ensure, - traits::{Currency, ReservableCurrency, EnsureOrigin, Get, BalanceStatus::Reserved}, - dispatch::{DispatchResult, DispatchError}, +use frame_support::{ + ensure, + traits::{Currency, ReservableCurrency, BalanceStatus::Reserved}, + dispatch::DispatchError, }; -use frame_system::ensure_signed; pub use weights::WeightInfo; -type BalanceOf = <::Currency as Currency<::AccountId>>::Balance; - -/// The module configuration trait. -pub trait Config: frame_system::Config { - /// The overarching event type. - type Event: From> + Into<::Event>; +pub use pallet::*; - /// The units in which we record balances. - type Balance: Member + Parameter + AtLeast32BitUnsigned + Default + Copy; - - /// The arithmetic type of asset identifier. - type AssetId: Member + Parameter + Default + Copy + HasCompact; +type BalanceOf = <::Currency as Currency<::AccountId>>::Balance; - /// The currency mechanism. - type Currency: ReservableCurrency; +#[frame_support::pallet] +pub mod pallet { + use frame_support::{ + dispatch::DispatchResultWithPostInfo, + pallet_prelude::*, + }; + use frame_system::pallet_prelude::*; + use super::*; - /// The origin which may forcibly create or destroy an asset. - type ForceOrigin: EnsureOrigin; + #[pallet::pallet] + #[pallet::generate_store(pub(super) trait Store)] + pub struct Pallet(PhantomData); - /// The basic amount of funds that must be reserved when creating a new asset class. - type AssetDepositBase: Get>; + #[pallet::config] + /// The module configuration trait. + pub trait Config: frame_system::Config { + /// The overarching event type. + type Event: From> + IsType<::Event>; - /// The additional funds that must be reserved for every zombie account that an asset class - /// supports. - type AssetDepositPerZombie: Get>; + /// The units in which we record balances. + type Balance: Member + Parameter + AtLeast32BitUnsigned + Default + Copy; - /// The maximum length of a name or symbol stored on-chain. - type StringLimit: Get; + /// The arithmetic type of asset identifier. + type AssetId: Member + Parameter + Default + Copy + HasCompact; - /// The basic amount of funds that must be reserved when adding metadata to your asset. - type MetadataDepositBase: Get>; + /// The currency mechanism. + type Currency: ReservableCurrency; - /// The additional funds that must be reserved for the number of bytes you store in your - /// metadata. - type MetadataDepositPerByte: Get>; + /// The origin which may forcibly create or destroy an asset. + type ForceOrigin: EnsureOrigin; - /// Weight information for extrinsics in this pallet. - type WeightInfo: WeightInfo; -} + /// The basic amount of funds that must be reserved when creating a new asset class. + type AssetDepositBase: Get>; -#[derive(Clone, Encode, Decode, Eq, PartialEq, RuntimeDebug)] -pub struct AssetDetails< - Balance: Encode + Decode + Clone + Debug + Eq + PartialEq, - AccountId: Encode + Decode + Clone + Debug + Eq + PartialEq, - DepositBalance: Encode + Decode + Clone + Debug + Eq + PartialEq, -> { - /// Can change `owner`, `issuer`, `freezer` and `admin` accounts. - owner: AccountId, - /// Can mint tokens. - issuer: AccountId, - /// Can thaw tokens, force transfers and burn tokens from any account. - admin: AccountId, - /// Can freeze tokens. - freezer: AccountId, - /// The total supply across all accounts. - supply: Balance, - /// The balance deposited for this asset. - /// - /// This pays for the data stored here together with any virtual accounts. - deposit: DepositBalance, - /// The number of balance-holding accounts that this asset may have, excluding those that were - /// created when they had a system-level ED. - max_zombies: u32, - /// The ED for virtual accounts. - min_balance: Balance, - /// The current number of zombie accounts. - zombies: u32, - /// The total number of accounts. - accounts: u32, - /// Whether the asset is frozen for permissionless transfers. - is_frozen: bool, -} + /// The additional funds that must be reserved for every zombie account that an asset class + /// supports. + type AssetDepositPerZombie: Get>; -#[derive(Clone, Encode, Decode, Eq, PartialEq, RuntimeDebug, Default)] -pub struct AssetBalance< - Balance: Encode + Decode + Clone + Debug + Eq + PartialEq, -> { - /// The balance. - balance: Balance, - /// Whether the account is frozen. - is_frozen: bool, - /// Whether the account is a zombie. If not, then it has a reference. - is_zombie: bool, -} + /// The maximum length of a name or symbol stored on-chain. + type StringLimit: Get; -#[derive(Clone, Encode, Decode, Eq, PartialEq, RuntimeDebug, Default)] -pub struct AssetMetadata { - /// The balance deposited for this metadata. - /// - /// This pays for the data stored in this struct. - deposit: DepositBalance, - /// The user friendly name of this asset. Limited in length by `StringLimit`. - name: Vec, - /// The ticker symbol for this asset. Limited in length by `StringLimit`. - symbol: Vec, - /// The number of decimals this asset uses to represent one unit. - decimals: u8, -} + /// The basic amount of funds that must be reserved when adding metadata to your asset. + type MetadataDepositBase: Get>; -decl_storage! { - trait Store for Module as Assets { - /// Details of an asset. - Asset: map hasher(blake2_128_concat) T::AssetId => Option, - >>; - - /// The number of units of assets held by any given account. - Account: double_map - hasher(blake2_128_concat) T::AssetId, - hasher(blake2_128_concat) T::AccountId - => AssetBalance; - - /// Metadata of an asset. - Metadata: map hasher(blake2_128_concat) T::AssetId => AssetMetadata>; - } -} + /// The additional funds that must be reserved for the number of bytes you store in your + /// metadata. + type MetadataDepositPerByte: Get>; -decl_event! { - pub enum Event where - ::AccountId, - ::Balance, - ::AssetId, - { - /// Some asset class was created. \[asset_id, creator, owner\] - Created(AssetId, AccountId, AccountId), - /// Some assets were issued. \[asset_id, owner, total_supply\] - Issued(AssetId, AccountId, Balance), - /// Some assets were transferred. \[asset_id, from, to, amount\] - Transferred(AssetId, AccountId, AccountId, Balance), - /// Some assets were destroyed. \[asset_id, owner, balance\] - Burned(AssetId, AccountId, Balance), - /// The management team changed \[asset_id, issuer, admin, freezer\] - TeamChanged(AssetId, AccountId, AccountId, AccountId), - /// The owner changed \[asset_id, owner\] - OwnerChanged(AssetId, AccountId), - /// Some assets was transferred by an admin. \[asset_id, from, to, amount\] - ForceTransferred(AssetId, AccountId, AccountId, Balance), - /// Some account `who` was frozen. \[asset_id, who\] - Frozen(AssetId, AccountId), - /// Some account `who` was thawed. \[asset_id, who\] - Thawed(AssetId, AccountId), - /// Some asset `asset_id` was frozen. \[asset_id\] - AssetFrozen(AssetId), - /// Some asset `asset_id` was thawed. \[asset_id\] - AssetThawed(AssetId), - /// An asset class was destroyed. - Destroyed(AssetId), - /// Some asset class was force-created. \[asset_id, owner\] - ForceCreated(AssetId, AccountId), - /// The maximum amount of zombies allowed has changed. \[asset_id, max_zombies\] - MaxZombiesChanged(AssetId, u32), - /// New metadata has been set for an asset. \[asset_id, name, symbol, decimals\] - MetadataSet(AssetId, Vec, Vec, u8), + /// Weight information for extrinsics in this pallet. + type WeightInfo: WeightInfo; } -} -decl_error! { - pub enum Error for Module { - /// Transfer amount should be non-zero. - AmountZero, - /// Account balance must be greater than or equal to the transfer amount. - BalanceLow, - /// Balance should be non-zero. - BalanceZero, - /// The signing account has no permission to do the operation. - NoPermission, - /// The given asset ID is unknown. - Unknown, - /// The origin account is frozen. - Frozen, - /// The asset ID is already taken. - InUse, - /// Too many zombie accounts in use. - TooManyZombies, - /// Attempt to destroy an asset class when non-zombie, reference-bearing accounts exist. - RefsLeft, - /// Invalid witness data given. - BadWitness, - /// Minimum balance should be non-zero. - MinBalanceZero, - /// A mint operation lead to an overflow. - Overflow, - /// Some internal state is broken. - BadState, - /// Invalid metadata given. - BadMetadata, - } -} - -decl_module! { - pub struct Module for enum Call where origin: T::Origin { - type Error = Error; - - fn deposit_event() = default; + #[pallet::hooks] + impl Hooks> for Pallet {} + #[pallet::call] + impl Pallet { /// Issue a new class of fungible assets from a public origin. /// /// This new asset class has no assets initially. @@ -345,13 +212,14 @@ decl_module! { /// Emits `Created` event when successful. /// /// Weight: `O(1)` - #[weight = T::WeightInfo::create()] - fn create(origin, - #[compact] id: T::AssetId, + #[pallet::weight(T::WeightInfo::create())] + pub(super) fn create( + origin: OriginFor, + #[pallet::compact] id: T::AssetId, admin: ::Source, max_zombies: u32, min_balance: T::Balance, - ) { + ) -> DispatchResultWithPostInfo { let owner = ensure_signed(origin)?; let admin = T::Lookup::lookup(admin)?; @@ -376,7 +244,8 @@ decl_module! { accounts: Zero::zero(), is_frozen: false, }); - Self::deposit_event(RawEvent::Created(id, owner, admin)); + Self::deposit_event(Event::Created(id, owner, admin)); + Ok(().into()) } /// Issue a new class of fungible assets from a privileged origin. @@ -400,13 +269,14 @@ decl_module! { /// Emits `ForceCreated` event when successful. /// /// Weight: `O(1)` - #[weight = T::WeightInfo::force_create()] - fn force_create(origin, - #[compact] id: T::AssetId, + #[pallet::weight(T::WeightInfo::force_create())] + pub(super) fn force_create( + origin: OriginFor, + #[pallet::compact] id: T::AssetId, owner: ::Source, - #[compact] max_zombies: u32, - #[compact] min_balance: T::Balance, - ) { + #[pallet::compact] max_zombies: u32, + #[pallet::compact] min_balance: T::Balance, + ) -> DispatchResultWithPostInfo { T::ForceOrigin::ensure_origin(origin)?; let owner = T::Lookup::lookup(owner)?; @@ -426,7 +296,8 @@ decl_module! { accounts: Zero::zero(), is_frozen: false, }); - Self::deposit_event(RawEvent::ForceCreated(id, owner)); + Self::deposit_event(Event::ForceCreated(id, owner)); + Ok(().into()) } /// Destroy a class of fungible assets owned by the sender. @@ -439,11 +310,12 @@ decl_module! { /// Emits `Destroyed` event when successful. /// /// Weight: `O(z)` where `z` is the number of zombie accounts. - #[weight = T::WeightInfo::destroy(*zombies_witness)] - fn destroy(origin, - #[compact] id: T::AssetId, - #[compact] zombies_witness: u32, - ) -> DispatchResult { + #[pallet::weight(T::WeightInfo::destroy(*zombies_witness))] + pub(super) fn destroy( + origin: OriginFor, + #[pallet::compact] id: T::AssetId, + #[pallet::compact] zombies_witness: u32, + ) -> DispatchResultWithPostInfo { let origin = ensure_signed(origin)?; Asset::::try_mutate_exists(id, |maybe_details| { @@ -457,8 +329,8 @@ decl_module! { *maybe_details = None; Account::::remove_prefix(&id); - Self::deposit_event(RawEvent::Destroyed(id)); - Ok(()) + Self::deposit_event(Event::Destroyed(id)); + Ok(().into()) }) } @@ -472,11 +344,12 @@ decl_module! { /// Emits `Destroyed` event when successful. /// /// Weight: `O(1)` - #[weight = T::WeightInfo::force_destroy(*zombies_witness)] - fn force_destroy(origin, - #[compact] id: T::AssetId, - #[compact] zombies_witness: u32, - ) -> DispatchResult { + #[pallet::weight(T::WeightInfo::force_destroy(*zombies_witness))] + pub(super) fn force_destroy( + origin: OriginFor, + #[pallet::compact] id: T::AssetId, + #[pallet::compact] zombies_witness: u32, + ) -> DispatchResultWithPostInfo { T::ForceOrigin::ensure_origin(origin)?; Asset::::try_mutate_exists(id, |maybe_details| { @@ -489,8 +362,8 @@ decl_module! { *maybe_details = None; Account::::remove_prefix(&id); - Self::deposit_event(RawEvent::Destroyed(id)); - Ok(()) + Self::deposit_event(Event::Destroyed(id)); + Ok(().into()) }) } @@ -506,12 +379,13 @@ decl_module! { /// /// Weight: `O(1)` /// Modes: Pre-existing balance of `beneficiary`; Account pre-existence of `beneficiary`. - #[weight = T::WeightInfo::mint()] - fn mint(origin, - #[compact] id: T::AssetId, + #[pallet::weight(T::WeightInfo::mint())] + pub(super) fn mint( + origin: OriginFor, + #[pallet::compact] id: T::AssetId, beneficiary: ::Source, - #[compact] amount: T::Balance - ) -> DispatchResult { + #[pallet::compact] amount: T::Balance + ) -> DispatchResultWithPostInfo { let origin = ensure_signed(origin)?; let beneficiary = T::Lookup::lookup(beneficiary)?; @@ -521,17 +395,17 @@ decl_module! { ensure!(&origin == &details.issuer, Error::::NoPermission); details.supply = details.supply.checked_add(&amount).ok_or(Error::::Overflow)?; - Account::::try_mutate(id, &beneficiary, |t| -> DispatchResult { + Account::::try_mutate(id, &beneficiary, |t| -> DispatchResultWithPostInfo { let new_balance = t.balance.saturating_add(amount); ensure!(new_balance >= details.min_balance, Error::::BalanceLow); if t.balance.is_zero() { t.is_zombie = Self::new_account(&beneficiary, details)?; } t.balance = new_balance; - Ok(()) + Ok(().into()) })?; - Self::deposit_event(RawEvent::Issued(id, beneficiary, amount)); - Ok(()) + Self::deposit_event(Event::Issued(id, beneficiary, amount)); + Ok(().into()) }) } @@ -550,12 +424,13 @@ decl_module! { /// /// Weight: `O(1)` /// Modes: Post-existence of `who`; Pre & post Zombie-status of `who`. - #[weight = T::WeightInfo::burn()] - fn burn(origin, - #[compact] id: T::AssetId, + #[pallet::weight(T::WeightInfo::burn())] + pub(super) fn burn( + origin: OriginFor, + #[pallet::compact] id: T::AssetId, who: ::Source, - #[compact] amount: T::Balance - ) -> DispatchResult { + #[pallet::compact] amount: T::Balance + ) -> DispatchResultWithPostInfo { let origin = ensure_signed(origin)?; let who = T::Lookup::lookup(who)?; @@ -583,8 +458,8 @@ decl_module! { d.supply = d.supply.saturating_sub(burned); - Self::deposit_event(RawEvent::Burned(id, who, burned)); - Ok(()) + Self::deposit_event(Event::Burned(id, who, burned)); + Ok(().into()) }) } @@ -606,12 +481,13 @@ decl_module! { /// Weight: `O(1)` /// Modes: Pre-existence of `target`; Post-existence of sender; Prior & post zombie-status /// of sender; Account pre-existence of `target`. - #[weight = T::WeightInfo::transfer()] - fn transfer(origin, - #[compact] id: T::AssetId, + #[pallet::weight(T::WeightInfo::transfer())] + pub(super) fn transfer( + origin: OriginFor, + #[pallet::compact] id: T::AssetId, target: ::Source, - #[compact] amount: T::Balance - ) -> DispatchResult { + #[pallet::compact] amount: T::Balance + ) -> DispatchResultWithPostInfo { let origin = ensure_signed(origin)?; ensure!(!amount.is_zero(), Error::::AmountZero); @@ -626,7 +502,7 @@ decl_module! { ensure!(!details.is_frozen, Error::::Frozen); if dest == origin { - return Ok(()) + return Ok(().into()) } let mut amount = amount; @@ -635,14 +511,14 @@ decl_module! { origin_account.balance = Zero::zero(); } - Account::::try_mutate(id, &dest, |a| -> DispatchResult { + Account::::try_mutate(id, &dest, |a| -> DispatchResultWithPostInfo { let new_balance = a.balance.saturating_add(amount); ensure!(new_balance >= details.min_balance, Error::::BalanceLow); if a.balance.is_zero() { a.is_zombie = Self::new_account(&dest, details)?; } a.balance = new_balance; - Ok(()) + Ok(().into()) })?; match origin_account.balance.is_zero() { @@ -656,8 +532,8 @@ decl_module! { } } - Self::deposit_event(RawEvent::Transferred(id, origin, dest, amount)); - Ok(()) + Self::deposit_event(Event::Transferred(id, origin, dest, amount)); + Ok(().into()) }) } @@ -680,13 +556,14 @@ decl_module! { /// Weight: `O(1)` /// Modes: Pre-existence of `dest`; Post-existence of `source`; Prior & post zombie-status /// of `source`; Account pre-existence of `dest`. - #[weight = T::WeightInfo::force_transfer()] - fn force_transfer(origin, - #[compact] id: T::AssetId, + #[pallet::weight(T::WeightInfo::force_transfer())] + pub(super) fn force_transfer( + origin: OriginFor, + #[pallet::compact] id: T::AssetId, source: ::Source, dest: ::Source, - #[compact] amount: T::Balance, - ) -> DispatchResult { + #[pallet::compact] amount: T::Balance, + ) -> DispatchResultWithPostInfo { let origin = ensure_signed(origin)?; let source = T::Lookup::lookup(source)?; @@ -696,7 +573,7 @@ decl_module! { let dest = T::Lookup::lookup(dest)?; if dest == source { - return Ok(()) + return Ok(().into()) } Asset::::try_mutate(id, |maybe_details| { @@ -709,14 +586,14 @@ decl_module! { source_account.balance = Zero::zero(); } - Account::::try_mutate(id, &dest, |a| -> DispatchResult { + Account::::try_mutate(id, &dest, |a| -> DispatchResultWithPostInfo { let new_balance = a.balance.saturating_add(amount); ensure!(new_balance >= details.min_balance, Error::::BalanceLow); if a.balance.is_zero() { a.is_zombie = Self::new_account(&dest, details)?; } a.balance = new_balance; - Ok(()) + Ok(().into()) })?; match source_account.balance.is_zero() { @@ -730,8 +607,8 @@ decl_module! { } } - Self::deposit_event(RawEvent::ForceTransferred(id, source, dest, amount)); - Ok(()) + Self::deposit_event(Event::ForceTransferred(id, source, dest, amount)); + Ok(().into()) }) } @@ -745,8 +622,12 @@ decl_module! { /// Emits `Frozen`. /// /// Weight: `O(1)` - #[weight = T::WeightInfo::freeze()] - fn freeze(origin, #[compact] id: T::AssetId, who: ::Source) { + #[pallet::weight(T::WeightInfo::freeze())] + pub(super) fn freeze( + origin: OriginFor, + #[pallet::compact] id: T::AssetId, + who: ::Source + ) -> DispatchResultWithPostInfo { let origin = ensure_signed(origin)?; let d = Asset::::get(id).ok_or(Error::::Unknown)?; @@ -757,6 +638,7 @@ decl_module! { Account::::mutate(id, &who, |a| a.is_frozen = true); Self::deposit_event(Event::::Frozen(id, who)); + Ok(().into()) } /// Allow unprivileged transfers from an account again. @@ -769,8 +651,13 @@ decl_module! { /// Emits `Thawed`. /// /// Weight: `O(1)` - #[weight = T::WeightInfo::thaw()] - fn thaw(origin, #[compact] id: T::AssetId, who: ::Source) { + #[pallet::weight(T::WeightInfo::thaw())] + pub(super) fn thaw( + origin: OriginFor, + #[pallet::compact] + id: T::AssetId, + who: ::Source + ) -> DispatchResultWithPostInfo { let origin = ensure_signed(origin)?; let details = Asset::::get(id).ok_or(Error::::Unknown)?; @@ -781,6 +668,7 @@ decl_module! { Account::::mutate(id, &who, |a| a.is_frozen = false); Self::deposit_event(Event::::Thawed(id, who)); + Ok(().into()) } /// Disallow further unprivileged transfers for the asset class. @@ -792,8 +680,11 @@ decl_module! { /// Emits `Frozen`. /// /// Weight: `O(1)` - #[weight = T::WeightInfo::freeze_asset()] - fn freeze_asset(origin, #[compact] id: T::AssetId) -> DispatchResult { + #[pallet::weight(T::WeightInfo::freeze_asset())] + pub(super) fn freeze_asset( + origin: OriginFor, + #[pallet::compact] id: T::AssetId + ) -> DispatchResultWithPostInfo { let origin = ensure_signed(origin)?; Asset::::try_mutate(id, |maybe_details| { @@ -803,7 +694,7 @@ decl_module! { d.is_frozen = true; Self::deposit_event(Event::::AssetFrozen(id)); - Ok(()) + Ok(().into()) }) } @@ -816,8 +707,11 @@ decl_module! { /// Emits `Thawed`. /// /// Weight: `O(1)` - #[weight = T::WeightInfo::thaw_asset()] - fn thaw_asset(origin, #[compact] id: T::AssetId) -> DispatchResult { + #[pallet::weight(T::WeightInfo::thaw_asset())] + pub(super) fn thaw_asset( + origin: OriginFor, + #[pallet::compact] id: T::AssetId + ) -> DispatchResultWithPostInfo { let origin = ensure_signed(origin)?; Asset::::try_mutate(id, |maybe_details| { @@ -827,7 +721,7 @@ decl_module! { d.is_frozen = false; Self::deposit_event(Event::::AssetThawed(id)); - Ok(()) + Ok(().into()) }) } @@ -841,26 +735,27 @@ decl_module! { /// Emits `OwnerChanged`. /// /// Weight: `O(1)` - #[weight = T::WeightInfo::transfer_ownership()] - fn transfer_ownership(origin, - #[compact] id: T::AssetId, + #[pallet::weight(T::WeightInfo::transfer_ownership())] + pub(super) fn transfer_ownership( + origin: OriginFor, + #[pallet::compact] id: T::AssetId, owner: ::Source, - ) -> DispatchResult { + ) -> DispatchResultWithPostInfo { let origin = ensure_signed(origin)?; let owner = T::Lookup::lookup(owner)?; Asset::::try_mutate(id, |maybe_details| { let details = maybe_details.as_mut().ok_or(Error::::Unknown)?; ensure!(&origin == &details.owner, Error::::NoPermission); - if details.owner == owner { return Ok(()) } + if details.owner == owner { return Ok(().into()) } // Move the deposit to the new owner. T::Currency::repatriate_reserved(&details.owner, &owner, details.deposit, Reserved)?; details.owner = owner.clone(); - Self::deposit_event(RawEvent::OwnerChanged(id, owner)); - Ok(()) + Self::deposit_event(Event::OwnerChanged(id, owner)); + Ok(().into()) }) } @@ -876,13 +771,14 @@ decl_module! { /// Emits `TeamChanged`. /// /// Weight: `O(1)` - #[weight = T::WeightInfo::set_team()] - fn set_team(origin, - #[compact] id: T::AssetId, + #[pallet::weight(T::WeightInfo::set_team())] + pub(super) fn set_team( + origin: OriginFor, + #[pallet::compact] id: T::AssetId, issuer: ::Source, admin: ::Source, freezer: ::Source, - ) -> DispatchResult { + ) -> DispatchResultWithPostInfo { let origin = ensure_signed(origin)?; let issuer = T::Lookup::lookup(issuer)?; let admin = T::Lookup::lookup(admin)?; @@ -896,8 +792,8 @@ decl_module! { details.admin = admin.clone(); details.freezer = freezer.clone(); - Self::deposit_event(RawEvent::TeamChanged(id, issuer, admin, freezer)); - Ok(()) + Self::deposit_event(Event::TeamChanged(id, issuer, admin, freezer)); + Ok(().into()) }) } @@ -915,11 +811,12 @@ decl_module! { /// Emits `MaxZombiesChanged`. /// /// Weight: `O(1)` - #[weight = T::WeightInfo::set_max_zombies()] - fn set_max_zombies(origin, - #[compact] id: T::AssetId, - #[compact] max_zombies: u32, - ) -> DispatchResult { + #[pallet::weight(T::WeightInfo::set_max_zombies())] + pub(super) fn set_max_zombies( + origin: OriginFor, + #[pallet::compact] id: T::AssetId, + #[pallet::compact] max_zombies: u32, + ) -> DispatchResultWithPostInfo { let origin = ensure_signed(origin)?; Asset::::try_mutate(id, |maybe_details| { @@ -939,8 +836,8 @@ decl_module! { details.max_zombies = max_zombies; - Self::deposit_event(RawEvent::MaxZombiesChanged(id, max_zombies)); - Ok(()) + Self::deposit_event(Event::MaxZombiesChanged(id, max_zombies)); + Ok(().into()) }) } @@ -964,13 +861,14 @@ decl_module! { /// Emits `MaxZombiesChanged`. /// /// Weight: `O(1)` - #[weight = T::WeightInfo::set_metadata(name.len() as u32, symbol.len() as u32)] - fn set_metadata(origin, - #[compact] id: T::AssetId, + #[pallet::weight(T::WeightInfo::set_metadata(name.len() as u32, symbol.len() as u32))] + pub(super) fn set_metadata( + origin: OriginFor, + #[pallet::compact] id: T::AssetId, name: Vec, symbol: Vec, decimals: u8, - ) -> DispatchResult { + ) -> DispatchResultWithPostInfo { let origin = ensure_signed(origin)?; ensure!(name.len() <= T::StringLimit::get() as usize, Error::::BadMetadata); @@ -1009,15 +907,175 @@ decl_module! { }) } - Self::deposit_event(RawEvent::MetadataSet(id, name, symbol, decimals)); - Ok(()) + Self::deposit_event(Event::MetadataSet(id, name, symbol, decimals)); + Ok(().into()) }) } + + } + + #[pallet::event] + #[pallet::generate_deposit(pub(super) fn deposit_event)] + #[pallet::metadata(T::AccountId = "AccountId", T::Balance = "Balance", T::AssetId = "AssetId")] + pub enum Event { + /// Some asset class was created. \[asset_id, creator, owner\] + Created(T::AssetId, T::AccountId, T::AccountId), + /// Some assets were issued. \[asset_id, owner, total_supply\] + Issued(T::AssetId, T::AccountId, T::Balance), + /// Some assets were transferred. \[asset_id, from, to, amount\] + Transferred(T::AssetId, T::AccountId, T::AccountId, T::Balance), + /// Some assets were destroyed. \[asset_id, owner, balance\] + Burned(T::AssetId, T::AccountId, T::Balance), + /// The management team changed \[asset_id, issuer, admin, freezer\] + TeamChanged(T::AssetId, T::AccountId, T::AccountId, T::AccountId), + /// The owner changed \[asset_id, owner\] + OwnerChanged(T::AssetId, T::AccountId), + /// Some assets was transferred by an admin. \[asset_id, from, to, amount\] + ForceTransferred(T::AssetId, T::AccountId, T::AccountId, T::Balance), + /// Some account `who` was frozen. \[asset_id, who\] + Frozen(T::AssetId, T::AccountId), + /// Some account `who` was thawed. \[asset_id, who\] + Thawed(T::AssetId, T::AccountId), + /// Some asset `asset_id` was frozen. \[asset_id\] + AssetFrozen(T::AssetId), + /// Some asset `asset_id` was thawed. \[asset_id\] + AssetThawed(T::AssetId), + /// An asset class was destroyed. + Destroyed(T::AssetId), + /// Some asset class was force-created. \[asset_id, owner\] + ForceCreated(T::AssetId, T::AccountId), + /// The maximum amount of zombies allowed has changed. \[asset_id, max_zombies\] + MaxZombiesChanged(T::AssetId, u32), + /// New metadata has been set for an asset. \[asset_id, name, symbol, decimals\] + MetadataSet(T::AssetId, Vec, Vec, u8), + } + + #[deprecated(note = "use `Event` instead")] + pub type RawEvent = Event; + + #[pallet::error] + pub enum Error { + /// Transfer amount should be non-zero. + AmountZero, + /// Account balance must be greater than or equal to the transfer amount. + BalanceLow, + /// Balance should be non-zero. + BalanceZero, + /// The signing account has no permission to do the operation. + NoPermission, + /// The given asset ID is unknown. + Unknown, + /// The origin account is frozen. + Frozen, + /// The asset ID is already taken. + InUse, + /// Too many zombie accounts in use. + TooManyZombies, + /// Attempt to destroy an asset class when non-zombie, reference-bearing accounts exist. + RefsLeft, + /// Invalid witness data given. + BadWitness, + /// Minimum balance should be non-zero. + MinBalanceZero, + /// A mint operation lead to an overflow. + Overflow, + /// Some internal state is broken. + BadState, + /// Invalid metadata given. + BadMetadata, } + + #[pallet::storage] + /// Details of an asset. + pub(super) type Asset = StorageMap< + _, + Blake2_128Concat, + T::AssetId, + AssetDetails> + >; + #[pallet::storage] + /// The number of units of assets held by any given account. + pub(super) type Account = StorageDoubleMap< + _, + Blake2_128Concat, + T::AssetId, + Blake2_128Concat, + T::AccountId, + AssetBalance, + ValueQuery + >; + #[pallet::storage] + /// Metadata of an asset. + pub(super) type Metadata = StorageMap< + _, + Blake2_128Concat, + T::AssetId, + AssetMetadata>, + ValueQuery + >; +} + +#[derive(Clone, Encode, Decode, Eq, PartialEq, RuntimeDebug)] +pub struct AssetDetails< + Balance: Encode + Decode + Clone + Debug + Eq + PartialEq, + AccountId: Encode + Decode + Clone + Debug + Eq + PartialEq, + DepositBalance: Encode + Decode + Clone + Debug + Eq + PartialEq, +> { + /// Can change `owner`, `issuer`, `freezer` and `admin` accounts. + owner: AccountId, + /// Can mint tokens. + issuer: AccountId, + /// Can thaw tokens, force transfers and burn tokens from any account. + admin: AccountId, + /// Can freeze tokens. + freezer: AccountId, + /// The total supply across all accounts. + supply: Balance, + /// The balance deposited for this asset. + /// + /// This pays for the data stored here together with any virtual accounts. + deposit: DepositBalance, + /// The number of balance-holding accounts that this asset may have, excluding those that were + /// created when they had a system-level ED. + max_zombies: u32, + /// The ED for virtual accounts. + min_balance: Balance, + /// The current number of zombie accounts. + zombies: u32, + /// The total number of accounts. + accounts: u32, + /// Whether the asset is frozen for permissionless transfers. + is_frozen: bool, +} + +#[derive(Clone, Encode, Decode, Eq, PartialEq, RuntimeDebug, Default)] +pub struct AssetBalance< + Balance: Encode + Decode + Clone + Debug + Eq + PartialEq, +> { + /// The balance. + balance: Balance, + /// Whether the account is frozen. + is_frozen: bool, + /// Whether the account is a zombie. If not, then it has a reference. + is_zombie: bool, +} + +#[derive(Clone, Encode, Decode, Eq, PartialEq, RuntimeDebug, Default)] +pub struct AssetMetadata { + /// The balance deposited for this metadata. + /// + /// This pays for the data stored in this struct. + deposit: DepositBalance, + /// The user friendly name of this asset. Limited in length by `StringLimit`. + name: Vec, + /// The ticker symbol for this asset. Limited in length by `StringLimit`. + symbol: Vec, + /// The number of decimals this asset uses to represent one unit. + decimals: u8, } // The main implementation block for the module. -impl Module { +impl Pallet { // Public immutables /// Get the asset `id` balance of `who`. diff --git a/frame/support/src/lib.rs b/frame/support/src/lib.rs index 08852a7f3c1fe..951e12c9c7d4a 100644 --- a/frame/support/src/lib.rs +++ b/frame/support/src/lib.rs @@ -1874,11 +1874,15 @@ pub mod pallet_prelude { /// /// ## Upgrade guidelines: /// -/// 1. export metadata of the pallet for later checks -/// 2. generate the template upgrade for the pallet provided by decl_storage with environment -/// variable `PRINT_PALLET_UPGRADE`: `PRINT_PALLET_UPGRADE=1 cargo check -p my_pallet` -/// This template can be used as information it contains all information for storages, genesis -/// config and genesis build. +/// 1. Export the metadata of the pallet for later checks +/// - run your node with the pallet active +/// - query the metadata using the `state_getMetadata` RPC and curl, or use +/// `subsee -p > meta.json` +/// 2. generate the template upgrade for the pallet provided by decl_storage +/// with environment variable `PRINT_PALLET_UPGRADE`: +/// `PRINT_PALLET_UPGRADE=1 cargo check -p my_pallet` This template can be +/// used as information it contains all information for storages, genesis +/// config and genesis build. /// 3. reorganize pallet to have trait `Config`, `decl_*` macros, `ValidateUnsigned`, /// `ProvideInherent`, `Origin` all together in one file. Suggested order: /// * Config, @@ -1925,7 +1929,7 @@ pub mod pallet_prelude { /// impl Pallet { /// } /// ``` -/// and write inside all the call in decl_module with a few changes in the signature: +/// and write inside all the calls in decl_module with a few changes in the signature: /// - origin must now be written completely, e.g. `origin: OriginFor` /// - result type must be `DispatchResultWithPostInfo`, you need to write it and also you might /// need to put `Ok(().into())` at the end or the function.