Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: asset management #151

Merged
Merged
Show file tree
Hide file tree
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
135 changes: 117 additions & 18 deletions pallets/api/src/fungibles/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,9 @@ pub mod pallet {
/// Token decimals for a given asset ID.
#[codec(index = 10)]
TokenDecimals(AssetIdOf<T>),
/// Check if token exists for a given asset ID.
#[codec(index = 18)]
AssetExists(AssetIdOf<T>),
}

/// Configure the pallet by specifying the parameters and types on which it depends.
Expand All @@ -95,9 +98,9 @@ pub mod pallet {
/// `data` in unspecified format.
///
/// # Parameters
/// * `id` - The ID of the asset.
/// * `to` - The recipient account.
/// * `value` - The number of tokens to transfer.
/// - `id` - The ID of the asset.
/// - `to` - The recipient account.
/// - `value` - The number of tokens to transfer.
#[pallet::call_index(3)]
#[pallet::weight(AssetsWeightInfoOf::<T>::transfer_keep_alive())]
pub fn transfer(
Expand All @@ -114,10 +117,10 @@ pub mod pallet {
/// account `to`, with additional `data` in unspecified format.
///
/// # Parameters
/// * `id` - The ID of the asset.
/// * `owner` - The account from which the asset balance will be withdrawn.
/// * `to` - The recipient account.
/// * `value` - The number of tokens to transfer.
/// - `id` - The ID of the asset.
/// - `owner` - The account from which the asset balance will be withdrawn.
/// - `to` - The recipient account.
/// - `value` - The number of tokens to transfer.
#[pallet::call_index(4)]
#[pallet::weight(AssetsWeightInfoOf::<T>::transfer_approved())]
pub fn transfer_from(
Expand All @@ -135,9 +138,9 @@ pub mod pallet {
/// Approves an account to spend a specified number of tokens on behalf of the caller.
///
/// # Parameters
/// * `id` - The ID of the asset.
/// * `spender` - The account that is allowed to spend the tokens.
/// * `value` - The number of tokens to approve.
/// - `id` - The ID of the asset.
/// - `spender` - The account that is allowed to spend the tokens.
/// - `value` - The number of tokens to approve.
#[pallet::call_index(5)]
#[pallet::weight(<T as Config>::WeightInfo::approve(1, 1))]
pub fn approve(
Expand Down Expand Up @@ -183,9 +186,9 @@ pub mod pallet {
/// Increases the allowance of a spender.
///
/// # Parameters
/// * `id` - The ID of the asset.
/// * `spender` - The account that is allowed to spend the tokens.
/// * `value` - The number of tokens to increase the allowance by.
/// - `id` - The ID of the asset.
/// - `spender` - The account that is allowed to spend the tokens.
/// - `value` - The number of tokens to increase the allowance by.
#[pallet::call_index(6)]
#[pallet::weight(AssetsWeightInfoOf::<T>::approve_transfer())]
pub fn increase_allowance(
Expand All @@ -201,9 +204,9 @@ pub mod pallet {
/// Decreases the allowance of a spender.
///
/// # Parameters
/// * `id` - The ID of the asset.
/// * `spender` - The account that is allowed to spend the tokens.
/// * `value` - The number of tokens to decrease the allowance by.
/// - `id` - The ID of the asset.
/// - `spender` - The account that is allowed to spend the tokens.
/// - `value` - The number of tokens to decrease the allowance by.
#[pallet::call_index(7)]
#[pallet::weight(<T as Config>::WeightInfo::approve(1, 1))]
pub fn decrease_allowance(
Expand Down Expand Up @@ -231,6 +234,101 @@ pub mod pallet {
AssetsOf::<T>::approve_transfer(origin, id, spender, new_allowance)?;
Ok(().into())
}

/// Create a new token with a given asset ID.
///
/// # Parameters
/// - `id` - The ID of the asset.
/// - `admin` - The account that will administer the asset.
/// - `min_balance` - The minimum balance required for accounts holding this asset.
#[pallet::call_index(11)]
#[pallet::weight(AssetsWeightInfoOf::<T>::create())]
pub fn create(
origin: OriginFor<T>,
id: AssetIdOf<T>,
admin: AccountIdOf<T>,
min_balance: BalanceOf<T>,
) -> DispatchResult {
let admin = T::Lookup::unlookup(admin);
AssetsOf::<T>::create(origin, id.into(), admin, min_balance)
}

/// Start the process of destroying a token with a given asset ID.
///
/// # Parameters
/// - `id` - The ID of the asset.
#[pallet::call_index(12)]
#[pallet::weight(AssetsWeightInfoOf::<T>::start_destroy())]
pub fn start_destroy(origin: OriginFor<T>, id: AssetIdOf<T>) -> DispatchResult {
AssetsOf::<T>::start_destroy(origin, id.into())
}

/// Set the metadata for a token with a given asset ID.
///
/// # Parameters
/// - `id`: The identifier of the asset to update.
/// - `name`: The user friendly name of this asset. Limited in length by
/// `pallet_assets::Config::StringLimit`.
/// - `symbol`: The exchange symbol for this asset. Limited in length by
/// `pallet_assets::Config::StringLimit`.
/// - `decimals`: The number of decimals this asset uses to represent one unit.
#[pallet::call_index(16)]
#[pallet::weight(AssetsWeightInfoOf::<T>::set_metadata(name.len() as u32, symbol.len() as u32))]
pub fn set_metadata(
origin: OriginFor<T>,
id: AssetIdOf<T>,
name: Vec<u8>,
symbol: Vec<u8>,
decimals: u8,
) -> DispatchResult {
AssetsOf::<T>::set_metadata(origin, id.into(), name, symbol, decimals)
}

/// Clear the metadata for a token with a given asset ID.
///
/// # Parameters
/// - `id` - The ID of the asset.
#[pallet::call_index(17)]
#[pallet::weight(AssetsWeightInfoOf::<T>::clear_metadata())]
pub fn clear_metadata(origin: OriginFor<T>, id: AssetIdOf<T>) -> DispatchResult {
AssetsOf::<T>::clear_metadata(origin, id.into())
}

/// Creates `amount` tokens and assigns them to `account`, increasing the total supply.
///
/// # Parameters
/// - `id` - The ID of the asset.
/// - `owner` - The account to be credited with the created tokens.
/// - `value` - The number of tokens to mint.
#[pallet::call_index(19)]
#[pallet::weight(AssetsWeightInfoOf::<T>::mint())]
pub fn mint(
origin: OriginFor<T>,
id: AssetIdOf<T>,
account: AccountIdOf<T>,
amount: BalanceOf<T>,
) -> DispatchResult {
let account = T::Lookup::unlookup(account);
AssetsOf::<T>::mint(origin, id.into(), account, amount)
}

/// Destroys `amount` tokens from `account`, reducing the total supply.
///
/// # Parameters
/// - `id` - The ID of the asset.
/// - `owner` - The account from which the tokens will be destroyed.
/// - `value` - The number of tokens to destroy.
#[pallet::call_index(20)]
#[pallet::weight(AssetsWeightInfoOf::<T>::burn())]
pub fn burn(
origin: OriginFor<T>,
id: AssetIdOf<T>,
account: AccountIdOf<T>,
amount: BalanceOf<T>,
) -> DispatchResult {
let account = T::Lookup::unlookup(account);
AssetsOf::<T>::burn(origin, id.into(), account, amount)
}
}

impl<T: Config> Pallet<T> {
Expand All @@ -240,8 +338,8 @@ pub mod pallet {
/// encoded result.
///
/// # Parameter
/// * `value` - An instance of `Read<T>`, which specifies the type of state query and
/// the associated parameters.
/// - `value` - An instance of `Read<T>`, which specifies the type of state query and
/// the associated parameters.
pub fn read_state(value: Read<T>) -> Vec<u8> {
use Read::*;

Expand All @@ -260,6 +358,7 @@ pub mod pallet {
TokenDecimals(id) => {
<AssetsOf<T> as MetadataInspect<AccountIdOf<T>>>::decimals(id).encode()
},
AssetExists(id) => AssetsOf::<T>::asset_exists(id).encode(),
}
}

Expand Down
93 changes: 89 additions & 4 deletions pallets/api/src/fungibles/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@ use crate::{fungibles::Read::*, mock::*};
use codec::Encode;
use frame_support::{
assert_ok,
traits::fungibles::{approvals::Inspect, metadata::Inspect as MetadataInspect},
traits::fungibles::{
approvals::Inspect as ApprovalInspect, metadata::Inspect as MetadataInspect, Inspect,
},
};

const ASSET: u32 = 42;
Expand Down Expand Up @@ -94,6 +96,81 @@ fn decrease_allowance_works() {
});
}

#[test]
fn create_works() {
new_test_ext().execute_with(|| {
assert!(!Assets::asset_exists(ASSET));
assert_ok!(Fungibles::create(signed(ALICE), ASSET, ALICE, 100));
assert!(Assets::asset_exists(ASSET));
});
}

#[test]
fn start_destroy_works() {
new_test_ext().execute_with(|| {
create_asset(ALICE, ASSET);
assert_ok!(Fungibles::start_destroy(signed(ALICE), ASSET));
});
}

#[test]
fn set_metadata_works() {
new_test_ext().execute_with(|| {
let name = vec![42];
let symbol = vec![42];
let decimals = 42;
create_asset(ALICE, ASSET);
assert_ok!(Fungibles::set_metadata(
signed(ALICE),
ASSET,
name.clone(),
symbol.clone(),
decimals
));
assert_eq!(Assets::name(ASSET), name);
assert_eq!(Assets::symbol(ASSET), symbol);
assert_eq!(Assets::decimals(ASSET), decimals);
});
}

#[test]
fn clear_metadata_works() {
new_test_ext().execute_with(|| {
let name = vec![42];
let symbol = vec![42];
let decimals = 42;
create_asset_and_set_metadata(ALICE, ASSET, name, symbol, decimals);
assert_ok!(Fungibles::clear_metadata(signed(ALICE), ASSET));
assert_eq!(Assets::name(ASSET), Vec::<u8>::new());
assert_eq!(Assets::symbol(ASSET), Vec::<u8>::new());
assert_eq!(Assets::decimals(ASSET), 0u8);
});
}

#[test]
fn mint_works() {
new_test_ext().execute_with(|| {
let amount: Balance = 100 * UNIT;
create_asset(ALICE, ASSET);
let balance_before_mint = Assets::balance(ASSET, &BOB);
assert_ok!(Fungibles::mint(signed(ALICE), ASSET, BOB, amount));
let balance_after_mint = Assets::balance(ASSET, &BOB);
assert_eq!(balance_after_mint, balance_before_mint + amount);
});
}

#[test]
fn burn_works() {
new_test_ext().execute_with(|| {
let amount: Balance = 100 * UNIT;
create_asset_and_mint_to(ALICE, ASSET, BOB, amount);
let balance_before_burn = Assets::balance(ASSET, &BOB);
assert_ok!(Fungibles::burn(signed(ALICE), ASSET, BOB, amount));
let balance_after_burn = Assets::balance(ASSET, &BOB);
assert_eq!(balance_after_burn, balance_before_burn - amount);
});
}

#[test]
fn total_supply_works() {
new_test_ext().execute_with(|| {
Expand Down Expand Up @@ -137,20 +214,28 @@ fn token_metadata_works() {
});
}

#[test]
fn asset_exists_works() {
new_test_ext().execute_with(|| {
create_asset(ALICE, ASSET);
assert_eq!(Assets::asset_exists(ASSET).encode(), Fungibles::read_state(AssetExists(ASSET)));
});
}

fn signed(account: AccountId) -> RuntimeOrigin {
RuntimeOrigin::signed(account)
}

fn create_asset(owner: AccountId, asset_id: AssetId, min_balance: Balance) {
assert_ok!(Assets::create(signed(owner), asset_id, owner, min_balance));
fn create_asset(owner: AccountId, asset_id: AssetId) {
assert_ok!(Assets::create(signed(owner), asset_id, owner, 1));
}

fn mint_asset(owner: AccountId, asset_id: AssetId, to: AccountId, value: Balance) {
assert_ok!(Assets::mint(signed(owner), asset_id, to, value));
}

fn create_asset_and_mint_to(owner: AccountId, asset_id: AssetId, to: AccountId, value: Balance) {
create_asset(owner, asset_id, 1);
create_asset(owner, asset_id);
mint_asset(owner, asset_id, to, value)
}

Expand Down
3 changes: 2 additions & 1 deletion pop-api/examples/balance-transfer/lib.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// DEPRECATED
#![cfg_attr(not(feature = "std"), no_std, no_main)]

use pop_api::balances::*;
Expand Down Expand Up @@ -131,4 +132,4 @@ mod balance_transfer {
Ok(())
}
}
}
}
Loading
Loading