Skip to content

Commit 1cca4ce

Browse files
authored
Merge pull request #28 from rmrk-team/rework/rmrk-as-trait
reworks some nft operations into trait
2 parents c963e52 + 1c2dc49 commit 1cca4ce

File tree

7 files changed

+421
-462
lines changed

7 files changed

+421
-462
lines changed

pallets/rmrk-core/src/functions.rs

Lines changed: 218 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,191 @@
11
use super::*;
22

3+
impl<T: Config> Collection<StringLimitOf<T>, T::AccountId> for Pallet<T> {
4+
fn issuer(collection_id: CollectionId) -> Option<T::AccountId> {
5+
None
6+
}
7+
fn collection_create(
8+
issuer: T::AccountId,
9+
metadata: StringLimitOf<T>,
10+
max: u32,
11+
symbol: StringLimitOf<T>,
12+
) -> Result<CollectionId, DispatchError> {
13+
let collection = CollectionInfo { issuer: issuer.clone(), metadata, max, symbol };
14+
let collection_id =
15+
<CollectionIndex<T>>::try_mutate(|n| -> Result<CollectionId, DispatchError> {
16+
let id = *n;
17+
ensure!(id != CollectionId::max_value(), Error::<T>::NoAvailableCollectionId);
18+
*n += 1;
19+
Ok(id)
20+
})?;
21+
Collections::<T>::insert(collection_id, collection);
22+
Ok(collection_id)
23+
}
24+
25+
fn collection_burn(issuer: T::AccountId, collection_id: CollectionId) -> DispatchResult {
26+
ensure!(
27+
NFTs::<T>::iter_prefix_values(collection_id).count() == 0,
28+
Error::<T>::CollectionNotEmpty
29+
);
30+
Collections::<T>::remove(collection_id);
31+
Ok(())
32+
}
33+
34+
fn collection_change_issuer(
35+
collection_id: CollectionId,
36+
new_issuer: T::AccountId,
37+
) -> Result<(T::AccountId, CollectionId), DispatchError> {
38+
ensure!(Collections::<T>::contains_key(collection_id), Error::<T>::NoAvailableCollectionId);
39+
40+
Collections::<T>::try_mutate_exists(collection_id, |collection| -> DispatchResult {
41+
if let Some(col) = collection {
42+
col.issuer = new_issuer.clone();
43+
}
44+
Ok(())
45+
})?;
46+
47+
Ok((new_issuer, collection_id))
48+
}
49+
50+
fn collection_lock(collection_id: CollectionId) -> Result<CollectionId, DispatchError> {
51+
Collections::<T>::try_mutate_exists(collection_id, |collection| -> DispatchResult {
52+
let collection = collection.as_mut().ok_or(Error::<T>::CollectionUnknown)?;
53+
let currently_minted = NFTs::<T>::iter_prefix_values(collection_id).count();
54+
collection.max = currently_minted.try_into().unwrap();
55+
Ok(())
56+
})?;
57+
Ok(collection_id)
58+
}
59+
}
60+
61+
impl<T: Config> Nft<T::AccountId, StringLimitOf<T>> for Pallet<T> {
62+
type MaxRecursions = T::MaxRecursions;
63+
64+
fn nft_mint(
65+
sender: T::AccountId,
66+
owner: T::AccountId,
67+
collection_id: CollectionId,
68+
recipient: Option<T::AccountId>,
69+
royalty: Option<Permill>,
70+
metadata: StringLimitOf<T>,
71+
) -> sp_std::result::Result<(CollectionId, NftId), DispatchError> {
72+
let nft_id = Self::get_next_nft_id(collection_id)?;
73+
74+
let collection = Self::collections(collection_id).ok_or(Error::<T>::CollectionUnknown)?;
75+
76+
let nfts_minted = NFTs::<T>::iter_prefix_values(collection_id).count();
77+
let max: u32 = collection.max.try_into().unwrap();
78+
79+
ensure!(
80+
nfts_minted < max.try_into().unwrap() || max == 0,
81+
Error::<T>::CollectionFullOrLocked
82+
);
83+
84+
let recipient = recipient.unwrap_or(owner.clone());
85+
let royalty = royalty.unwrap_or(Permill::default());
86+
87+
let rootowner = owner.clone();
88+
let owner_as_maybe_account = AccountIdOrCollectionNftTuple::AccountId(owner.clone());
89+
90+
let nft =
91+
NftInfo { owner: owner_as_maybe_account, rootowner, recipient, royalty, metadata };
92+
93+
NFTs::<T>::insert(collection_id, nft_id, nft);
94+
NftsByOwner::<T>::append(owner, (collection_id, nft_id));
95+
96+
Ok((collection_id, nft_id))
97+
}
98+
99+
fn nft_burn(
100+
collection_id: CollectionId,
101+
nft_id: NftId,
102+
max_recursions: u32,
103+
) -> sp_std::result::Result<(CollectionId, NftId), DispatchError> {
104+
ensure!(max_recursions > 0, Error::<T>::TooManyRecursions);
105+
NFTs::<T>::remove(collection_id, nft_id);
106+
if let Some(kids) = Children::<T>::take(collection_id, nft_id) {
107+
for (child_collection_id, child_nft_id) in kids {
108+
Self::nft_burn(
109+
child_collection_id,
110+
child_nft_id,
111+
max_recursions - 1,
112+
)?;
113+
}
114+
}
115+
Ok((collection_id, nft_id))
116+
}
117+
118+
fn nft_send(
119+
sender: T::AccountId,
120+
collection_id: CollectionId,
121+
nft_id: NftId,
122+
new_owner: AccountIdOrCollectionNftTuple<T::AccountId>,
123+
max_recursions: u32,
124+
) -> sp_std::result::Result<(CollectionId, NftId), DispatchError> {
125+
let mut sending_nft =
126+
NFTs::<T>::get(collection_id, nft_id).ok_or(Error::<T>::NoAvailableNftId)?;
127+
ensure!(&sending_nft.rootowner == &sender, Error::<T>::NoPermission);
128+
129+
match new_owner.clone() {
130+
AccountIdOrCollectionNftTuple::AccountId(account_id) => {
131+
// Remove previous parental relationship
132+
if let AccountIdOrCollectionNftTuple::CollectionAndNftTuple(cid, nid) =
133+
sending_nft.owner
134+
{
135+
if let Some(mut kids) = Children::<T>::take(cid, nid) {
136+
kids.retain(|&kid| kid != (collection_id, nft_id));
137+
Children::<T>::insert(cid, nid, kids);
138+
}
139+
}
140+
sending_nft.rootowner = account_id.clone();
141+
},
142+
AccountIdOrCollectionNftTuple::CollectionAndNftTuple(cid, nid) => {
143+
let recipient_nft = NFTs::<T>::get(cid, nid).ok_or(Error::<T>::NoAvailableNftId)?;
144+
// Check if sending NFT is already a child of recipient NFT
145+
ensure!(
146+
!Pallet::<T>::is_x_descendent_of_y(cid, nid, collection_id, nft_id),
147+
Error::<T>::CannotSendToDescendent
148+
);
149+
150+
// Remove parent if exists: first we only care if the owner is a non-AccountId)
151+
if let AccountIdOrCollectionNftTuple::CollectionAndNftTuple(cid, nid) =
152+
sending_nft.owner
153+
{
154+
// second we only care if the parent has children (it should)
155+
if let Some(mut kids) = Children::<T>::take(cid, nid) {
156+
// third we only "retain" the other children
157+
kids.retain(|&kid| kid != (collection_id, nft_id));
158+
Children::<T>::insert(cid, nid, kids);
159+
}
160+
}
161+
if sending_nft.rootowner != recipient_nft.rootowner {
162+
// sending_nft.rootowner = recipient_nft.rootowner
163+
sending_nft.rootowner = recipient_nft.rootowner.clone();
164+
165+
Pallet::<T>::recursive_update_rootowner(
166+
collection_id,
167+
nft_id,
168+
recipient_nft.rootowner,
169+
max_recursions,
170+
)?;
171+
}
172+
match Children::<T>::take(cid, nid) {
173+
None => Children::<T>::insert(cid, nid, vec![(collection_id, nft_id)]),
174+
Some(mut kids) => {
175+
kids.push((collection_id, nft_id));
176+
Children::<T>::insert(cid, nid, kids);
177+
},
178+
}
179+
},
180+
};
181+
sending_nft.owner = new_owner.clone();
182+
183+
NFTs::<T>::insert(collection_id, nft_id, sending_nft);
184+
185+
Ok((collection_id, nft_id))
186+
}
187+
}
188+
3189
impl<T: Config> Pallet<T> {
4190
pub fn is_x_descendent_of_y(
5191
child_collection_id: CollectionId,
@@ -61,10 +247,40 @@ impl<T: Config> Pallet<T> {
61247
ensure!(max_recursions > 0, Error::<T>::TooManyRecursions);
62248
NFTs::<T>::remove(collection_id, nft_id);
63249
if let Some(kids) = Children::<T>::take(collection_id, nft_id) {
64-
for child in kids {
65-
Pallet::<T>::recursive_burn(child.0, child.1, max_recursions - 1)?;
250+
for (child_collection_id, child_nft_id) in kids {
251+
Pallet::<T>::recursive_burn(child_collection_id, child_nft_id, max_recursions - 1)?;
66252
}
67253
}
68254
Ok(())
69255
}
256+
257+
pub fn to_bounded_string(name: Vec<u8>) -> Result<BoundedVec<u8, T::StringLimit>, Error<T>> {
258+
name.try_into().map_err(|_| Error::<T>::TooLong)
259+
}
260+
261+
pub fn to_optional_bounded_string(
262+
name: Option<Vec<u8>>,
263+
) -> Result<Option<BoundedVec<u8, T::StringLimit>>, Error<T>> {
264+
Ok(match name {
265+
Some(n) => Some(Self::to_bounded_string(n)?),
266+
None => None,
267+
})
268+
}
269+
270+
pub fn get_next_nft_id(collection_id: CollectionId) -> Result<NftId, Error<T>> {
271+
NextNftId::<T>::try_mutate(collection_id, |id| {
272+
let current_id = *id;
273+
*id = id.checked_add(1).ok_or(Error::<T>::NoAvailableNftId)?;
274+
Ok(current_id)
275+
})
276+
}
277+
278+
pub fn get_next_resource_id() -> Result<ResourceId, Error<T>> {
279+
NextResourceId::<T>::try_mutate(|id| {
280+
let current_id = *id;
281+
*id = id.checked_add(1).ok_or(Error::<T>::NoAvailableCollectionId)?;
282+
Ok(current_id)
283+
})
284+
}
285+
70286
}

0 commit comments

Comments
 (0)