Skip to content
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: 86 additions & 49 deletions pallets/rmrk-core/src/functions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,10 @@

use super::*;
use codec::{Codec, Decode, Encode};
use frame_support::traits::{tokens::Locker, Get};
use frame_support::{
pallet_prelude::*,
traits::{tokens::Locker, Get},
};

use sp_runtime::{
traits::{Saturating, TrailingZeroInput},
Expand All @@ -24,15 +27,11 @@ where
T: pallet_uniques::Config<CollectionId = CollectionId, ItemId = NftId>,
{
fn priority_set(
sender: T::AccountId,
_sender: T::AccountId,
collection_id: CollectionId,
nft_id: NftId,
priorities: BoundedVec<ResourceId, T::MaxPriorities>,
) -> DispatchResult {
let (root_owner, _) = Pallet::<T>::lookup_root_owner(collection_id, nft_id)?;
ensure!(sender == root_owner, Error::<T>::NoPermission);
// Check NFT lock status
ensure!(!Pallet::<T>::is_locked(collection_id, nft_id), pallet_uniques::Error::<T>::Locked);
let _multi_removal_results =
Priorities::<T>::clear_prefix((collection_id, nft_id), T::MaxPriorities::get(), None);
let mut priority_index = 0;
Expand Down Expand Up @@ -107,25 +106,18 @@ where
T: pallet_uniques::Config<CollectionId = CollectionId, ItemId = NftId>,
{
fn resource_add(
sender: T::AccountId,
_sender: T::AccountId,
collection_id: CollectionId,
nft_id: NftId,
resource: ResourceTypes<BoundedVec<u8, T::StringLimit>, BoundedVec<PartId, T::PartsLimit>>,
adding_on_mint: bool,
pending: bool,
resource_id: ResourceId,
) -> Result<ResourceId, DispatchError> {
ensure!(
Resources::<T>::get((collection_id, nft_id, resource_id)).is_none(),
Error::<T>::ResourceAlreadyExists
);

let collection = Self::collections(collection_id).ok_or(Error::<T>::CollectionUnknown)?;

ensure!(collection.issuer == sender, Error::<T>::NoPermission);
let (root_owner, _) = Pallet::<T>::lookup_root_owner(collection_id, nft_id)?;
// Check NFT lock status
ensure!(!Pallet::<T>::is_locked(collection_id, nft_id), pallet_uniques::Error::<T>::Locked);

match resource.clone() {
ResourceTypes::Basic(_r) => (),
ResourceTypes::Composable(r) => {
Expand All @@ -145,15 +137,6 @@ where
},
}

// Resource should be in a pending state if the rootowner of the resource is not the sender
// of the transaction, unless the resource is being added on mint. This prevents the
// situation where an NFT being minted *directly to* a non-owned NFT *with resources* will
// have those resources be *pending*. While the minted NFT itself will be pending, it is
// inefficent and unnecessary to have the resources also be pending. Otherwise, in such a
// case, the owner would have to accept not only the NFT but also all originally-added
// resources.
let pending = (root_owner != sender) && !adding_on_mint;

let res: ResourceInfo<BoundedVec<u8, T::StringLimit>, BoundedVec<PartId, T::PartsLimit>> =
ResourceInfo::<BoundedVec<u8, T::StringLimit>, BoundedVec<PartId, T::PartsLimit>> {
id: resource_id,
Expand All @@ -163,50 +146,50 @@ where
};
Resources::<T>::insert((collection_id, nft_id, resource_id), res);

Self::deposit_event(Event::ResourceAdded { nft_id, resource_id, collection_id });

Ok(resource_id)
}

fn accept(
sender: T::AccountId,
_sender: T::AccountId,
collection_id: CollectionId,
nft_id: NftId,
resource_id: ResourceId,
) -> DispatchResult {
let (root_owner, _) = Pallet::<T>::lookup_root_owner(collection_id, nft_id)?;
ensure!(root_owner == sender, Error::<T>::NoPermission);
// Check NFT lock status
ensure!(!Pallet::<T>::is_locked(collection_id, nft_id), pallet_uniques::Error::<T>::Locked);
ensure!(
Resources::<T>::get((collection_id, nft_id, resource_id)).is_some(),
Error::<T>::ResourceDoesntExist
);
Resources::<T>::try_mutate_exists(
(collection_id, nft_id, resource_id),
|resource| -> DispatchResult {
if let Some(res) = resource {
if let Some(res) = resource.into_mut() {
ensure!(res.pending, Error::<T>::ResourceNotPending);
res.pending = false;
}
Ok(())
},
)?;

Self::deposit_event(Event::ResourceAccepted { nft_id, resource_id });
Self::deposit_event(Event::ResourceAccepted { nft_id, resource_id, collection_id });

Ok(())
}

fn resource_remove(
sender: T::AccountId,
_sender: T::AccountId,
collection_id: CollectionId,
nft_id: NftId,
resource_id: ResourceId,
pending_resource: bool,
) -> DispatchResult {
let collection = Self::collections(collection_id).ok_or(Error::<T>::CollectionUnknown)?;
let (root_owner, _) = Pallet::<T>::lookup_root_owner(collection_id, nft_id)?;
ensure!(collection.issuer == sender, Error::<T>::NoPermission);
ensure!(
Resources::<T>::contains_key((collection_id, nft_id, resource_id)),
Error::<T>::ResourceDoesntExist
);

if root_owner == sender {
Resources::<T>::remove((collection_id, nft_id, resource_id));
} else {
if pending_resource {
Resources::<T>::try_mutate_exists(
(collection_id, nft_id, resource_id),
|resource| -> DispatchResult {
Expand All @@ -216,19 +199,21 @@ where
Ok(())
},
)?;
} else {
Resources::<T>::remove((collection_id, nft_id, resource_id));
}

Self::deposit_event(Event::ResourceRemoval { nft_id, resource_id, collection_id });

Ok(())
}

fn accept_removal(
sender: T::AccountId,
_sender: T::AccountId,
collection_id: CollectionId,
nft_id: NftId,
resource_id: ResourceId,
) -> DispatchResult {
let (root_owner, _) = Pallet::<T>::lookup_root_owner(collection_id, nft_id)?;
ensure!(root_owner == sender, Error::<T>::NoPermission);
ensure!(
Resources::<T>::contains_key((collection_id, nft_id, &resource_id)),
Error::<T>::ResourceDoesntExist
Expand All @@ -245,6 +230,8 @@ where
},
)?;

Self::deposit_event(Event::ResourceRemovalAccepted { nft_id, resource_id, collection_id });

Ok(())
}
}
Expand Down Expand Up @@ -290,10 +277,23 @@ where
Ok(collection_id)
}

fn collection_burn(_issuer: T::AccountId, collection_id: CollectionId) -> DispatchResult {
fn collection_burn(issuer: T::AccountId, collection_id: CollectionId) -> DispatchResult {
let collection = Self::collections(collection_id).ok_or(Error::<T>::CollectionUnknown)?;
ensure!(collection.nfts_count == 0, Error::<T>::CollectionNotEmpty);
// Get DestroyWitness for Uniques pallet
let witness = pallet_uniques::Pallet::<T>::get_destroy_witness(&collection_id)
.ok_or(Error::<T>::NoWitness)?;
ensure!(witness.items == 0u32, Error::<T>::CollectionNotEmpty);
// Remove from RMRK storage
Collections::<T>::remove(collection_id);

pallet_uniques::Pallet::<T>::do_destroy_collection(
collection_id,
witness,
issuer.clone().into(),
)?;

Self::deposit_event(Event::CollectionDestroyed { issuer, collection_id });
Ok(())
}

Expand All @@ -319,10 +319,12 @@ where
) -> Result<CollectionId, DispatchError> {
Collections::<T>::try_mutate_exists(collection_id, |collection| -> DispatchResult {
let collection = collection.as_mut().ok_or(Error::<T>::CollectionUnknown)?;
ensure!(collection.issuer == sender, Error::<T>::NoPermission);
collection.max = Some(collection.nfts_count);
Ok(())
})?;

Self::deposit_event(Event::CollectionLocked { issuer: sender, collection_id });

Ok(collection_id)
}
}
Expand Down Expand Up @@ -401,7 +403,7 @@ where
collection_id,
nft_id,
res.resource,
true,
false,
res.id,
)?;
}
Expand Down Expand Up @@ -488,7 +490,7 @@ where
collection_id,
nft_id,
res.resource,
true,
false,
res.id,
)?;
}
Expand All @@ -504,6 +506,7 @@ where
}

fn nft_burn(
owner: T::AccountId,
collection_id: CollectionId,
nft_id: NftId,
max_recursions: u32,
Expand All @@ -530,7 +533,7 @@ where
for ((child_collection_id, child_nft_id), _) in
Children::<T>::drain_prefix((collection_id, nft_id))
{
Self::nft_burn(child_collection_id, child_nft_id, max_recursions - 1)?;
Self::nft_burn(owner.clone(), child_collection_id, child_nft_id, max_recursions - 1)?;
}

// decrement nfts counter
Expand All @@ -540,6 +543,11 @@ where
Ok(())
})?;

// Call pallet uniques to ensure NFT is burned
pallet_uniques::Pallet::<T>::do_burn(collection_id, nft_id, |_, _| Ok(()))?;

Self::deposit_event(Event::NFTBurned { owner, nft_id, collection_id });

Ok((collection_id, nft_id))
}

Expand Down Expand Up @@ -599,7 +607,7 @@ where
},
};

sending_nft.owner = new_owner;
sending_nft.owner = new_owner.clone();
// Nfts::<T>::insert(collection_id, nft_id, sending_nft);

if approval_required {
Expand Down Expand Up @@ -630,6 +638,21 @@ where
Pallet::<T>::add_child(new_owner_cid_nid, (collection_id, nft_id));
}

pallet_uniques::Pallet::<T>::do_transfer(
collection_id,
nft_id,
new_owner_account.clone(),
|_class_details, _details| Ok(()),
)?;

Self::deposit_event(Event::NFTSent {
sender,
recipient: new_owner,
collection_id,
nft_id,
approval_required,
});

Ok((new_owner_account, approval_required))
}

Expand All @@ -649,7 +672,7 @@ where
Nfts::<T>::get(collection_id, nft_id).ok_or(Error::<T>::NoAvailableNftId)?;

// Prepare acceptance
let new_owner_account = match new_owner {
let new_owner_account = match new_owner.clone() {
AccountIdOrCollectionNftTuple::AccountId(id) => id,
AccountIdOrCollectionNftTuple::CollectionAndNftTuple(cid, nid) => {
// Check if NFT target exists
Expand Down Expand Up @@ -682,6 +705,20 @@ where
Ok(())
})?;

pallet_uniques::Pallet::<T>::do_transfer(
collection_id,
nft_id,
new_owner_account.clone(),
|_class_details, _details| Ok(()),
)?;

Self::deposit_event(Event::NFTAccepted {
sender,
recipient: new_owner,
collection_id,
nft_id,
});

Ok((new_owner_account, collection_id, nft_id))
}

Expand Down Expand Up @@ -720,7 +757,7 @@ where
let _rejecting_nft =
Nfts::<T>::get(collection_id, nft_id).ok_or(Error::<T>::NoAvailableNftId)?;

Self::nft_burn(collection_id, nft_id, max_recursions)?;
Self::nft_burn(sender.clone(), collection_id, nft_id, max_recursions)?;

Ok((sender, collection_id, nft_id))
}
Expand Down
Loading