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

Refactor nft fractionalisation pallet #13008

Merged
merged 24 commits into from
Jan 27, 2023
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
14 changes: 11 additions & 3 deletions frame/assets/src/functions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -899,9 +899,7 @@ impl<T: Config<I>, I: 'static> Pallet<T, I> {
ensure!(metadata.as_ref().map_or(true, |m| !m.is_frozen), Error::<T, I>::NoPermission);

let old_deposit = metadata.take().map_or(Zero::zero(), |m| m.deposit);
let new_deposit = T::MetadataDepositPerByte::get()
.saturating_mul(((name.len() + symbol.len()) as u32).into())
.saturating_add(T::MetadataDepositBase::get());
let new_deposit = Self::calc_metadata_deposit(&name, &symbol);

if new_deposit > old_deposit {
T::Currency::reserve(from, new_deposit - old_deposit)?;
Expand All @@ -927,4 +925,14 @@ impl<T: Config<I>, I: 'static> Pallet<T, I> {
Ok(())
})
}

/// Calculate the metadata deposit for the provided data.
pub(super) fn calc_metadata_deposit(
name: &Vec<u8>,
symbol: &Vec<u8>,
) -> DepositBalanceOf<T, I> {
T::MetadataDepositPerByte::get()
.saturating_mul(((name.len() + symbol.len()) as u32).into())
.saturating_add(T::MetadataDepositBase::get())
}
}
13 changes: 13 additions & 0 deletions frame/assets/src/impl_fungibles.rs
Original file line number Diff line number Diff line change
Expand Up @@ -231,6 +231,19 @@ impl<T: Config<I>, I: 'static> fungibles::metadata::Mutate<<T as SystemConfig>::
}
}

impl<T: Config<I>, I: 'static>
fungibles::metadata::CalcMetadataDeposit<
<T::Currency as Currency<<T as SystemConfig>::AccountId>>::Balance,
> for Pallet<T, I>
{
fn calc(
name: &Vec<u8>,
symbol: &Vec<u8>,
) -> <T::Currency as Currency<<T as SystemConfig>::AccountId>>::Balance {
Self::calc_metadata_deposit(name, symbol)
}
}

impl<T: Config<I>, I: 'static> fungibles::approvals::Inspect<<T as SystemConfig>::AccountId>
for Pallet<T, I>
{
Expand Down
51 changes: 39 additions & 12 deletions frame/nft-fractionalization/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,17 +40,21 @@ pub mod pallet {
use super::*;
use frame_support::pallet_prelude::*;
use frame_system::pallet_prelude::*;
use sp_runtime::traits::One;
use sp_runtime::traits::{One, Zero};
use std::fmt::Display;

use frame_support::{
dispatch::DispatchResult,
sp_runtime::traits::{AccountIdConversion, AtLeast32BitUnsigned, StaticLookup},
traits::{
fungibles::{metadata::Mutate as MutateMetadata, Create, Destroy, Inspect, Mutate},
fungibles::{
metadata::{CalcMetadataDeposit, Mutate as MutateMetadata},
Create, Destroy, Inspect, Mutate,
},
tokens::nonfungibles_v2::{
Inspect as NonFungiblesInspect, LockableNonfungible, Transfer,
},
Currency,
Currency, ExistenceRequirement,
},
PalletId,
};
Expand All @@ -73,11 +77,11 @@ pub mod pallet {
/// The currency mechanism, used for paying for deposits.
type Currency: Currency<Self::AccountId>;

/// Identifier for the collection of nft.
type NftCollectionId: Member + Parameter + MaxEncodedLen + Copy;
/// Identifier for the collection of NFT.
type NftCollectionId: Member + Parameter + MaxEncodedLen + Copy + Display;

/// The type used to identify an nft within a collection.
type NftId: Member + Parameter + MaxEncodedLen + Copy;
/// The type used to identify an NFT within a collection.
type NftId: Member + Parameter + MaxEncodedLen + Copy + Display;

/// The type used to describe the amount of fractions converted into assets.
type AssetBalance: AtLeast32BitUnsigned
Expand All @@ -104,16 +108,17 @@ pub mod pallet {
+ Create<Self::AccountId>
+ Destroy<Self::AccountId>
+ Mutate<Self::AccountId>
+ MutateMetadata<Self::AccountId>;
+ MutateMetadata<Self::AccountId>
+ CalcMetadataDeposit<<Self::Currency as Currency<Self::AccountId>>::Balance>;

/// Registry for minted nfts.
/// Registry for minted NFTs.
type Nfts: NonFungiblesInspect<
Self::AccountId,
ItemId = Self::NftId,
CollectionId = Self::NftCollectionId,
> + Transfer<Self::AccountId>;

/// Locker trait to enable Nft Locking.
/// Locker trait to enable NFT's locking.
type NftLocker: LockableNonfungible<Self::NftCollectionId, Self::NftId>;

/// The pallet's id, used for deriving its sovereign account ID.
Expand Down Expand Up @@ -185,10 +190,10 @@ pub mod pallet {
ensure!(nft_owner == who, Error::<T>::NoPermission);

let pallet_account = Self::get_pallet_account();

Self::do_lock_nft(nft_collection_id, nft_id)?;
Self::do_create_asset(asset_id, pallet_account)?;
Self::do_create_asset(asset_id, pallet_account.clone())?;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should do_create_asset be taking a reference to pallet_account rather than ownership?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

then we would need to deref it inside because of T::Assets::create()

Self::do_mint_asset(asset_id, &beneficiary, fractions)?;
Self::do_set_metadata(asset_id, &who, &pallet_account, &nft_collection_id, &nft_id)?;

NftToAsset::<T>::insert(
(nft_collection_id, nft_id),
Expand Down Expand Up @@ -285,5 +290,27 @@ pub mod pallet {
T::Assets::burn_from(asset_id, account, amount)?;
T::Assets::start_destroy(asset_id, None)
jsidorenko marked this conversation as resolved.
Show resolved Hide resolved
}

/// Set the metadata for the newly created asset.
fn do_set_metadata(
asset_id: AssetIdOf<T>,
depositor: &T::AccountId,
pallet_account: &T::AccountId,
nft_collection_id: &T::NftCollectionId,
nft_id: &T::NftId,
) -> DispatchResult {
let symbol = "FRAC";
let name = format!("Frac {nft_collection_id}-{nft_id}");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't know if you want to pad these ids so that its always the same cost?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it would be less readable on the UI if we pad them

let deposit = T::Assets::calc(&name.clone().into(), &symbol.into());
if deposit != Zero::zero() {
T::Currency::transfer(
&depositor,
&pallet_account,
deposit,
ExistenceRequirement::KeepAlive,
)?;
}
T::Assets::set(asset_id, &pallet_account, name.into(), symbol.into(), 0)
}
}
}
6 changes: 3 additions & 3 deletions frame/nft-fractionalization/src/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -167,8 +167,8 @@ parameter_types! {
pub const NftFractionsPalletId: PalletId = PalletId(*b"fraction");
}

pub struct TestLockableNonfungible;
impl LockableNonfungible<CollectionId, ItemId> for TestLockableNonfungible {
pub struct MockLockableNonfungible;
impl LockableNonfungible<CollectionId, ItemId> for MockLockableNonfungible {
fn lock(collection: &CollectionId, item: &ItemId) -> DispatchResult {
<Nfts as Mutate<AccountId, ItemConfig>>::set_attribute(
collection,
Expand All @@ -192,7 +192,7 @@ impl Config for Test {
type Assets = Assets;
type Nfts = Nfts;
type PalletId = NftFractionsPalletId;
type NftLocker = TestLockableNonfungible;
type NftLocker = MockLockableNonfungible;
type WeightInfo = ();
}

Expand Down
7 changes: 6 additions & 1 deletion frame/nft-fractionalization/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,10 @@
use crate::{mock::*, *};
use frame_support::{
assert_noop, assert_ok,
traits::{fungibles::InspectEnumerable, Currency},
traits::{
fungibles::{metadata::Inspect, InspectEnumerable},
Currency,
},
};
use pallet_nfts::CollectionConfig;
use sp_runtime::{DispatchError, ModuleError};
Expand Down Expand Up @@ -73,6 +76,8 @@ fn fractionalize_should_work() {
));
assert_eq!(assets(), vec![asset_id]);
assert_eq!(Assets::balance(asset_id, 2), fractions);
assert_eq!(String::from_utf8(Assets::name(0)).unwrap(), "Frac 0-0");
assert_eq!(String::from_utf8(Assets::symbol(0)).unwrap(), "FRAC");
assert_eq!(Nfts::owner(nft_collection_id, nft_id), Some(1));
assert_noop!(
Nfts::transfer(RuntimeOrigin::signed(1), nft_collection_id, nft_id, 2),
Expand Down
5 changes: 5 additions & 0 deletions frame/support/src/traits/tokens/fungibles/metadata.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,3 +39,8 @@ pub trait Mutate<AccountId>: Inspect<AccountId> {
decimals: u8,
) -> DispatchResult;
}

pub trait CalcMetadataDeposit<DepositBalance> {
// Returns the required deposit amount for a given metadata.
fn calc(name: &Vec<u8>, symbol: &Vec<u8>) -> DepositBalance;
}