Skip to content
This repository was archived by the owner on Nov 15, 2023. It is now read-only.
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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