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 #149

Closed
wants to merge 40 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
360bb2a
feat: pop api fungibles pallet
Daanvdplas Jul 19, 2024
e097f80
refactor: comments
Daanvdplas Jul 20, 2024
c8d8b2a
refactor: rebase main, refactor extension with enums
evilrobot-01 Jul 20, 2024
c88387d
refactor
Daanvdplas Jul 21, 2024
224390a
refactor 2
Daanvdplas Jul 22, 2024
43ae445
feat: add fungibles pallet functions
Daanvdplas Jul 22, 2024
bbe01a1
tests: remove transfer_from (transfer copy) and add approve
Daanvdplas Jul 22, 2024
68264da
refactor: primitives
Daanvdplas Jul 22, 2024
2481773
fix: pallet api error + missing docs
Daanvdplas Jul 22, 2024
c10a8d4
fix: integration test after removal fungibles feature primitives
Daanvdplas Jul 22, 2024
a8c4bb5
chore: benchmark approve
Daanvdplas Jul 23, 2024
4419bad
refactor: pallet
Daanvdplas Jul 24, 2024
792fa07
refactor: integration-tests
Daanvdplas Jul 24, 2024
96da2f0
refactor: ink api library
Daanvdplas Jul 24, 2024
cb54a57
refactor: devnet runtime
Daanvdplas Jul 24, 2024
9ec2744
chore: benchmark fungibles approve
Daanvdplas Jul 24, 2024
f0fff97
test: ensure Lookup configuration
Daanvdplas Jul 24, 2024
4a476b0
fix: approve benchmark + weights
Daanvdplas Jul 24, 2024
f3cc83a
refactor: primitives
Daanvdplas Jul 25, 2024
bd85489
refactor: bits and pieces
Daanvdplas Jul 25, 2024
0e49f63
fix: test devnet
Daanvdplas Jul 25, 2024
8f6139c
refactor: apply final comments
Daanvdplas Jul 25, 2024
948e144
chore: benchmark approve
Daanvdplas Jul 23, 2024
88577e4
refactor: read state
Daanvdplas Jul 23, 2024
809e192
refactor: add state query filter
Daanvdplas Jul 23, 2024
ac9714c
fix: test UnknownCall
Daanvdplas Jul 23, 2024
77711ec
refactor: read state functions
Daanvdplas Jul 25, 2024
b50830c
refactor: enums
Daanvdplas Jul 25, 2024
2a8800c
refactor: style docs and using constants for errors in chain extension
Daanvdplas Jul 26, 2024
b93f009
refactor: api integration tests
Daanvdplas Jul 26, 2024
b639e8b
refactor: IT better error handling
Daanvdplas Jul 26, 2024
074b8cf
merge daan/api
Daanvdplas Jul 28, 2024
f72b15a
feat: create & set_metadata
Daanvdplas Jul 30, 2024
7739392
feat: rest of asset management
Daanvdplas Jul 30, 2024
d4f7f99
style: pub function docs
Daanvdplas Jul 30, 2024
6f4da18
fix: remove unnecessary api functions
Daanvdplas Jul 30, 2024
5aec185
merge daan/api
Daanvdplas Jul 31, 2024
602b8bf
merge refactor: integration tests error handling
Daanvdplas Jul 31, 2024
51c38cc
refactor: match statement
Daanvdplas Jul 31, 2024
406063c
Merge branch 'daan/fix-read_state_error_handling' into daan/feat-asse…
Daanvdplas Jul 31, 2024
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
103 changes: 80 additions & 23 deletions pallets/api/src/fungibles/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -95,9 +95,9 @@
/// `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 +114,10 @@
/// 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 +135,9 @@
/// 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 All @@ -153,39 +153,39 @@
let id: AssetIdParameterOf<T> = id.into();

// If the new value is equal to the current allowance, do nothing.
let return_weight = if value == current_allowance {
Self::weight_approve(0, 0)
}
// If the new value is greater than the current allowance, approve the difference
// because `approve_transfer` works additively (see `pallet-assets`).
else if value > current_allowance {
AssetsOf::<T>::approve_transfer(
origin,
id,
spender,
value.saturating_sub(current_allowance),
)
.map_err(|e| e.with_weight(Self::weight_approve(1, 0)))?;
Self::weight_approve(1, 0)
} else {
// If the new value is less than the current allowance, cancel the approval and set the new value
AssetsOf::<T>::cancel_approval(origin.clone(), id.clone(), spender.clone())
.map_err(|e| e.with_weight(Self::weight_approve(0, 1)))?;
if value.is_zero() {
return Ok(Some(Self::weight_approve(0, 1)).into());
}
AssetsOf::<T>::approve_transfer(origin, id, spender, value)?;
Self::weight_approve(1, 1)
};

Check warning on line 179 in pallets/api/src/fungibles/mod.rs

View workflow job for this annotation

GitHub Actions / clippy

`if` chain can be rewritten with `match`

warning: `if` chain can be rewritten with `match` --> pallets/api/src/fungibles/mod.rs:156:24 | 156 | let return_weight = if value == current_allowance { | _________________________________^ 157 | | Self::weight_approve(0, 0) 158 | | } 159 | | // If the new value is greater than the current allowance, approve the difference ... | 178 | | Self::weight_approve(1, 1) 179 | | }; | |_____________^ | = help: consider rewriting the `if` chain to use `cmp` and `match` = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#comparison_chain = note: `#[warn(clippy::comparison_chain)]` on by default
Ok(Some(return_weight).into())
}

/// 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 +201,9 @@
/// 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 All @@ -214,25 +214,82 @@
) -> DispatchResultWithPostInfo {
let who = ensure_signed(origin.clone())
.map_err(|e| e.with_weight(Self::weight_approve(0, 0)))?;
let mut current_allowance = AssetsOf::<T>::allowance(id.clone(), &who, &spender);
let current_allowance = AssetsOf::<T>::allowance(id.clone(), &who, &spender);
let spender = T::Lookup::unlookup(spender);
let id: AssetIdParameterOf<T> = id.into();

if value.is_zero() {
return Ok(Some(Self::weight_approve(0, 0)).into());
}

current_allowance.saturating_reduce(value);
// Cancel the aproval and set the new value if `current_allowance` is more than zero.
AssetsOf::<T>::cancel_approval(origin.clone(), id.clone(), spender.clone())
.map_err(|e| e.with_weight(Self::weight_approve(0, 1)))?;

if current_allowance.is_zero() {
let new_allowance = current_allowance.saturating_sub(value);
if new_allowance.is_zero() {
return Ok(Some(Self::weight_approve(0, 1)).into());
}
AssetsOf::<T>::approve_transfer(origin, id, spender, current_allowance)?;
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())
}
}

impl<T: Config> Pallet<T> {
Expand All @@ -242,7 +299,7 @@
/// encoded result.
///
/// # Parameter
/// * `value` - An instance of `Read<T>`, which specifies the type of state query and
/// - `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 Down
91 changes: 72 additions & 19 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 @@ -38,24 +40,6 @@ fn transfer_from_works() {
});
}

#[test]
fn decrease_allowance_works() {
new_test_ext().execute_with(|| {
let amount: Balance = 100 * UNIT;
create_asset_mint_and_approve(ALICE, ASSET, ALICE, amount, BOB, amount);
assert_eq!(Assets::allowance(ASSET, &ALICE, &BOB), amount);
// Owner balance is not changed if decreased by zero.
assert_ok!(Fungibles::decrease_allowance(signed(ALICE), ASSET, BOB, 0));
assert_eq!(Assets::allowance(ASSET, &ALICE, &BOB), amount);
// Decrease allowance successfully.
assert_ok!(Fungibles::decrease_allowance(signed(ALICE), ASSET, BOB, amount / 2 - 1 * UNIT));
assert_eq!(Assets::allowance(ASSET, &ALICE, &BOB), amount / 2 + 1 * UNIT);
// Saturating if current allowance is decreased more than the owner balance.
assert_ok!(Fungibles::decrease_allowance(signed(ALICE), ASSET, BOB, amount));
assert_eq!(Assets::allowance(ASSET, &ALICE, &BOB), 0);
});
}

// Non-additive, sets new value.
#[test]
fn approve_works() {
Expand Down Expand Up @@ -94,6 +78,75 @@ fn increase_allowance_works() {
});
}

#[test]
fn decrease_allowance_works() {
new_test_ext().execute_with(|| {
let amount: Balance = 100 * UNIT;
create_asset_mint_and_approve(ALICE, ASSET, ALICE, amount, BOB, amount);
assert_eq!(Assets::allowance(ASSET, &ALICE, &BOB), amount);
// Owner balance is not changed if decreased by zero.
assert_ok!(Fungibles::decrease_allowance(signed(ALICE), ASSET, BOB, 0));
assert_eq!(Assets::allowance(ASSET, &ALICE, &BOB), amount);
// Decrease allowance successfully.
assert_ok!(Fungibles::decrease_allowance(signed(ALICE), ASSET, BOB, amount / 2 - 1 * UNIT));
assert_eq!(Assets::allowance(ASSET, &ALICE, &BOB), amount / 2 + 1 * UNIT);
// Saturating if current allowance is decreased more than the owner balance.
assert_ok!(Fungibles::decrease_allowance(signed(ALICE), ASSET, BOB, amount));
assert_eq!(Assets::allowance(ASSET, &ALICE, &BOB), 0);
});
}

#[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, 100);
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, 100);
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 total_supply_works() {
new_test_ext().execute_with(|| {
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(())
}
}
}
}
49 changes: 25 additions & 24 deletions pop-api/examples/nfts/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::nfts::*;
Expand Down Expand Up @@ -33,27 +34,29 @@ mod nfts {
}

#[ink(message)]
pub fn create_nft_collection( &self ) -> Result<(), ContractError>{
pub fn create_nft_collection(&self) -> Result<(), ContractError> {
ink::env::debug_println!("Nfts::create_nft_collection: collection creation started.");
let admin = Self::env().caller();
let item_settings = ItemSettings(BitFlags::from(ItemSetting::Transferable));

let mint_settings = MintSettings {
mint_type: MintType::Issuer,
price: Some(0),
start_block: Some(0),
end_block: Some(0),
default_item_settings: item_settings,
};

let config = CollectionConfig {
settings: CollectionSettings(BitFlags::from(CollectionSetting::TransferableItems)),
max_supply: None,
mint_settings,
};
pop_api::nfts::create(admin, config)?;
ink::env::debug_println!("Nfts::create_nft_collection: collection created successfully.");
Ok(())
let admin = Self::env().caller();
let item_settings = ItemSettings(BitFlags::from(ItemSetting::Transferable));

let mint_settings = MintSettings {
mint_type: MintType::Issuer,
price: Some(0),
start_block: Some(0),
end_block: Some(0),
default_item_settings: item_settings,
};

let config = CollectionConfig {
settings: CollectionSettings(BitFlags::from(CollectionSetting::TransferableItems)),
max_supply: None,
mint_settings,
};
pop_api::nfts::create(admin, config)?;
ink::env::debug_println!(
"Nfts::create_nft_collection: collection created successfully."
);
Ok(())
}

#[ink(message)]
Expand Down Expand Up @@ -82,9 +85,7 @@ mod nfts {
// check owner
match owner(collection_id, item_id)? {
Some(owner) if owner == receiver => {
ink::env::debug_println!(
"Nfts::mint success: minted item belongs to receiver"
);
ink::env::debug_println!("Nfts::mint success: minted item belongs to receiver");
},
_ => {
return Err(ContractError::NotOwner);
Expand Down Expand Up @@ -113,4 +114,4 @@ mod nfts {
Nfts::new();
}
}
}
}
14 changes: 4 additions & 10 deletions pop-api/examples/place-spot-order/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)]

#[ink::contract(env = pop_api::Environment)]
Expand All @@ -15,11 +16,7 @@ mod spot_order {
}

#[ink(message)]
pub fn place_spot_order(
&mut self,
max_amount: Balance,
para_id: u32,
) {
pub fn place_spot_order(&mut self, max_amount: Balance, para_id: u32) {
ink::env::debug_println!(
"SpotOrder::place_spot_order: max_amount {:?} para_id: {:?} ",
max_amount,
Expand All @@ -28,10 +25,7 @@ mod spot_order {

#[allow(unused_variables)]
let res = pop_api::cross_chain::coretime::place_spot_order(max_amount, para_id);
ink::env::debug_println!(
"SpotOrder::place_spot_order: res {:?} ",
res,
);
ink::env::debug_println!("SpotOrder::place_spot_order: res {:?} ", res,);

ink::env::debug_println!("SpotOrder::place_spot_order end");
}
Expand All @@ -46,4 +40,4 @@ mod spot_order {
SpotOrder::new();
}
}
}
}
Loading
Loading