Skip to content
This repository has been archived by the owner on Nov 15, 2023. It is now read-only.

fix some discrepancies in generic-asset #4221

Merged
merged 8 commits into from
Jan 15, 2020
Merged
132 changes: 72 additions & 60 deletions frame/generic-asset/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -95,9 +95,10 @@
//! This will emit the `Transferred` event.
//! - `reserve`: Moves an amount from free balance to reserved balance.
//! - `unreserve`: Move up to an amount from reserved balance to free balance. This function cannot fail.
//! - `mint_free`: Mint to an account's free balance.
//! - `burn_free`: Burn an account's free balance.
//! - `slash`: Deduct up to an amount from the combined balance of `who`, preferring to deduct from the
//! free balance. This function cannot fail.
//! - `reward`: Add up to an amount to the free balance of an account.
//! - `slash_reserved`: Deduct up to an amount from reserved balance of an account. This function cannot fail.
//! - `repatriate_reserved`: Move up to an amount from reserved balance of an account to free balance of another
//! account.
Expand All @@ -109,7 +110,7 @@
//!
//! The following examples show how to use the Generic Asset module in your custom module.
//!
//! ### Examples from the PRML
//! ### Examples from the frame module
//!
//! The Fees module uses the `Currency` trait to handle fee charge/refund, and its types inherit from `Currency`:
//!
Expand Down Expand Up @@ -162,7 +163,7 @@ use sp_runtime::traits::{
use sp_std::prelude::*;
use sp_std::{cmp, result, fmt::Debug};
use frame_support::{
decl_event, decl_module, decl_storage, ensure, dispatch, decl_error,
decl_event, decl_module, decl_storage, ensure, decl_error,
traits::{
Currency, ExistenceRequirement, Imbalance, LockIdentifier, LockableCurrency, ReservableCurrency,
SignedImbalance, UpdateBalanceOutcome, WithdrawReason, WithdrawReasons, TryDrop,
Expand Down Expand Up @@ -359,7 +360,7 @@ decl_module! {
fn deposit_event() = default;

/// Create a new kind of asset.
fn create(origin, options: AssetOptions<T::Balance, T::AccountId>) -> dispatch::DispatchResult {
fn create(origin, options: AssetOptions<T::Balance, T::AccountId>) -> DispatchResult {
let origin = ensure_signed(origin)?;
let id = Self::next_asset_id();

Expand Down Expand Up @@ -392,7 +393,7 @@ decl_module! {
origin,
#[compact] asset_id: T::AssetId,
new_permission: PermissionLatest<T::AccountId>
) -> dispatch::DispatchResult {
) -> DispatchResult {
let origin = ensure_signed(origin)?;

let permissions: PermissionVersions<T::AccountId> = new_permission.into();
Expand All @@ -410,56 +411,20 @@ decl_module! {

/// Mints an asset, increases its total issuance.
/// The origin must have `mint` permissions.
fn mint(origin, #[compact] asset_id: T::AssetId, to: T::AccountId, amount: T::Balance)
-> dispatch::DispatchResult
{
let origin = ensure_signed(origin)?;
if Self::check_permission(&asset_id, &origin, &PermissionType::Mint) {
let original_free_balance = Self::free_balance(&asset_id, &to);
let current_total_issuance = <TotalIssuance<T>>::get(asset_id);
let new_total_issuance = current_total_issuance.checked_add(&amount)
.ok_or(Error::<T>::TotalMintingOverflow)?;
let value = original_free_balance.checked_add(&amount)
.ok_or(Error::<T>::FreeMintingOverflow)?;

<TotalIssuance<T>>::insert(asset_id, new_total_issuance);
Self::set_free_balance(&asset_id, &to, value);

Self::deposit_event(RawEvent::Minted(asset_id, to, amount));

Ok(())
} else {
Err(Error::<T>::NoMintPermission)?
}
fn mint(origin, #[compact] asset_id: T::AssetId, to: T::AccountId, amount: T::Balance) -> DispatchResult {
let who = ensure_signed(origin)?;
Self::mint_free(&asset_id, &who, &to, &amount)?;
Self::deposit_event(RawEvent::Minted(asset_id, to, amount));
Ok(())
}

/// Burns an asset, decreases its total issuance.
///
/// The `origin` must have `burn` permissions.
fn burn(origin, #[compact] asset_id: T::AssetId, to: T::AccountId, amount: T::Balance)
-> dispatch::DispatchResult
{
let origin = ensure_signed(origin)?;

if Self::check_permission(&asset_id, &origin, &PermissionType::Burn) {
let original_free_balance = Self::free_balance(&asset_id, &to);

let current_total_issuance = <TotalIssuance<T>>::get(asset_id);
let new_total_issuance = current_total_issuance.checked_sub(&amount)
.ok_or(Error::<T>::TotalBurningUnderflow)?;
let value = original_free_balance.checked_sub(&amount)
.ok_or(Error::<T>::FreeBurningUnderflow)?;

<TotalIssuance<T>>::insert(asset_id, new_total_issuance);

Self::set_free_balance(&asset_id, &to, value);

Self::deposit_event(RawEvent::Burned(asset_id, to, amount));

Ok(())
} else {
Err(Error::<T>::NoBurnPermission)?
}
fn burn(origin, #[compact] asset_id: T::AssetId, to: T::AccountId, amount: T::Balance) -> DispatchResult {
let who = ensure_signed(origin)?;
Self::burn_free(&asset_id, &who, &to, &amount)?;
Self::deposit_event(RawEvent::Burned(asset_id, to, amount));
Ok(())
}

/// Can be used to create reserved tokens.
Expand All @@ -468,7 +433,7 @@ decl_module! {
origin,
asset_id: T::AssetId,
options: AssetOptions<T::Balance, T::AccountId>
) -> dispatch::DispatchResult {
) -> DispatchResult {
ensure_root(origin)?;
Self::create_asset(Some(asset_id), None, options)
}
Expand Down Expand Up @@ -565,6 +530,53 @@ impl<T: Trait> Module<T> {
<ReservedBalance<T>>::get(asset_id, who)
}

/// Mint to an account's free balance, without event
pub fn mint_free(
asset_id: &T::AssetId,
who: &T::AccountId,
to: &T::AccountId,
amount: &T::Balance,
) -> DispatchResult {
if Self::check_permission(asset_id, who, &PermissionType::Mint) {
let original_free_balance = Self::free_balance(&asset_id, &to);
let current_total_issuance = <TotalIssuance<T>>::get(asset_id);
let new_total_issuance = current_total_issuance.checked_add(&amount)
.ok_or(Error::<T>::TotalMintingOverflow)?;
let value = original_free_balance.checked_add(&amount)
.ok_or(Error::<T>::FreeMintingOverflow)?;

<TotalIssuance<T>>::insert(asset_id, new_total_issuance);
Self::set_free_balance(&asset_id, &to, value);
Ok(())
} else {
Err(Error::<T>::NoMintPermission)?
}
}

/// Burn an account's free balance, without event
pub fn burn_free(
asset_id: &T::AssetId,
who: &T::AccountId,
to: &T::AccountId,
amount: &T::Balance,
) -> DispatchResult {
if Self::check_permission(asset_id, who, &PermissionType::Burn) {
let original_free_balance = Self::free_balance(asset_id, to);

let current_total_issuance = <TotalIssuance<T>>::get(asset_id);
let new_total_issuance = current_total_issuance.checked_sub(amount)
.ok_or(Error::<T>::TotalBurningUnderflow)?;
let value = original_free_balance.checked_sub(amount)
.ok_or(Error::<T>::FreeBurningUnderflow)?;

<TotalIssuance<T>>::insert(asset_id, new_total_issuance);
Self::set_free_balance(asset_id, to, value);
Ok(())
} else {
Err(Error::<T>::NoBurnPermission)?
}
}

/// Creates an asset.
///
/// # Arguments
Expand All @@ -577,7 +589,7 @@ impl<T: Trait> Module<T> {
asset_id: Option<T::AssetId>,
from_account: Option<T::AccountId>,
options: AssetOptions<T::Balance, T::AccountId>,
) -> dispatch::DispatchResult {
) -> DispatchResult {
let asset_id = if let Some(asset_id) = asset_id {
ensure!(!<TotalIssuance<T>>::exists(&asset_id), Error::<T>::IdAlreadyTaken);
ensure!(asset_id < Self::next_asset_id(), Error::<T>::IdUnavailable);
Expand Down Expand Up @@ -610,7 +622,7 @@ impl<T: Trait> Module<T> {
from: &T::AccountId,
to: &T::AccountId,
amount: T::Balance
) -> dispatch::DispatchResult {
) -> DispatchResult {
let new_balance = Self::free_balance(asset_id, from)
.checked_sub(&amount)
.ok_or(Error::<T>::InsufficientBalance)?;
Expand All @@ -631,7 +643,7 @@ impl<T: Trait> Module<T> {
from: &T::AccountId,
to: &T::AccountId,
amount: T::Balance,
) -> dispatch::DispatchResult {
) -> DispatchResult {
Self::make_transfer(asset_id, from, to, amount)?;

if from != to {
Expand All @@ -646,7 +658,7 @@ impl<T: Trait> Module<T> {
/// If the free balance is lower than `amount`, then no funds will be moved and an `Err` will
/// be returned. This is different behavior than `unreserve`.
pub fn reserve(asset_id: &T::AssetId, who: &T::AccountId, amount: T::Balance)
-> dispatch::DispatchResult
-> DispatchResult
{
// Do we need to consider that this is an atomic transaction?
let original_reserve_balance = Self::reserved_balance(asset_id, who);
Expand Down Expand Up @@ -683,7 +695,7 @@ impl<T: Trait> Module<T> {
/// then `Some(remaining)` will be returned. Full completion is given by `None`.
/// NOTE: LOW-LEVEL: This will not attempt to maintain total issuance. It is expected that
/// the caller will do this.
fn slash(asset_id: &T::AssetId, who: &T::AccountId, amount: T::Balance) -> Option<T::Balance> {
pub fn slash(asset_id: &T::AssetId, who: &T::AccountId, amount: T::Balance) -> Option<T::Balance> {
let free_balance = Self::free_balance(asset_id, who);
let free_slash = sp_std::cmp::min(free_balance, amount);
let new_free_balance = free_balance - free_slash;
Expand All @@ -701,7 +713,7 @@ impl<T: Trait> Module<T> {
/// is less than `amount`, then a non-zero second item will be returned.
/// NOTE: LOW-LEVEL: This will not attempt to maintain total issuance. It is expected that
/// the caller will do this.
fn slash_reserved(asset_id: &T::AssetId, who: &T::AccountId, amount: T::Balance) -> Option<T::Balance> {
pub fn slash_reserved(asset_id: &T::AssetId, who: &T::AccountId, amount: T::Balance) -> Option<T::Balance> {
let original_reserve_balance = Self::reserved_balance(asset_id, who);
let slash = sp_std::cmp::min(original_reserve_balance, amount);
let new_reserve_balance = original_reserve_balance - slash;
Expand All @@ -720,7 +732,7 @@ impl<T: Trait> Module<T> {
/// the `remaining` would be returned, else `Zero::zero()`.
/// NOTE: LOW-LEVEL: This will not attempt to maintain total issuance. It is expected that
/// the caller will do this.
fn repatriate_reserved(
pub fn repatriate_reserved(
asset_id: &T::AssetId,
who: &T::AccountId,
beneficiary: &T::AccountId,
Expand Down Expand Up @@ -785,7 +797,7 @@ impl<T: Trait> Module<T> {
_amount: T::Balance,
reasons: WithdrawReasons,
new_balance: T::Balance,
) -> dispatch::DispatchResult {
) -> DispatchResult {
if asset_id != &Self::staking_asset_id() {
return Ok(());
}
Expand Down