Skip to content

Commit

Permalink
feat: asset management (#151)
Browse files Browse the repository at this point in the history
  • Loading branch information
Daanvdplas authored Aug 6, 2024
1 parent 60c744b commit 5b78e4c
Show file tree
Hide file tree
Showing 16 changed files with 1,477 additions and 993 deletions.
135 changes: 117 additions & 18 deletions pallets/api/src/fungibles/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,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 @@ -96,9 +99,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 @@ -115,10 +118,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 @@ -136,9 +139,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 @@ -186,9 +189,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 @@ -204,9 +207,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 @@ -234,6 +237,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 @@ -243,8 +341,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 @@ -263,6 +361,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

0 comments on commit 5b78e4c

Please sign in to comment.