1use core::marker::PhantomData;
19
20use crate::{
21 asset_strategies::{Attribute, WithItemConfig},
22 Item as ItemStorage, *,
23};
24use frame_support::{
25 dispatch::DispatchResult,
26 ensure,
27 traits::tokens::asset_ops::{
28 common_strategies::{
29 Bytes, CanUpdate, ChangeOwnerFrom, CheckOrigin, CheckState, ConfigValue, IfOwnedBy,
30 NoParams, Owner, PredefinedId, WithConfig,
31 },
32 AssetDefinition, Create, Inspect, Restore, Stash, Update,
33 },
34 BoundedSlice,
35};
36use frame_system::ensure_signed;
37use sp_runtime::DispatchError;
38
39pub struct Item<PalletInstance>(PhantomData<PalletInstance>);
40
41impl<T: Config<I>, I: 'static> AssetDefinition for Item<Pallet<T, I>> {
42 type Id = (T::CollectionId, T::ItemId);
43}
44
45impl<T: Config<I>, I: 'static> Inspect<Owner<T::AccountId>> for Item<Pallet<T, I>> {
46 fn inspect(
47 (collection, item): &Self::Id,
48 _ownership: Owner<T::AccountId>,
49 ) -> Result<T::AccountId, DispatchError> {
50 ItemStorage::<T, I>::get(collection, item)
51 .map(|a| a.owner)
52 .ok_or(Error::<T, I>::UnknownItem.into())
53 }
54}
55
56impl<T: Config<I>, I: 'static> Inspect<Bytes> for Item<Pallet<T, I>> {
57 fn inspect((collection, item): &Self::Id, _bytes: Bytes) -> Result<Vec<u8>, DispatchError> {
58 ItemMetadataOf::<T, I>::get(collection, item)
59 .map(|m| m.data.into())
60 .ok_or(Error::<T, I>::NoMetadata.into())
61 }
62}
63
64impl<'a, T: Config<I>, I: 'static> Inspect<Bytes<Attribute<'a>>> for Item<Pallet<T, I>> {
65 fn inspect(
66 (collection, item): &Self::Id,
67 strategy: Bytes<Attribute>,
68 ) -> Result<Vec<u8>, DispatchError> {
69 let Bytes(Attribute(attribute)) = strategy;
70
71 let attribute =
72 BoundedSlice::try_from(attribute).map_err(|_| Error::<T, I>::WrongAttribute)?;
73 crate::Attribute::<T, I>::get((collection, Some(item), attribute))
74 .map(|a| a.0.into())
75 .ok_or(Error::<T, I>::AttributeNotFound.into())
76 }
77}
78
79impl<T: Config<I>, I: 'static> Inspect<CanUpdate<Owner<T::AccountId>>> for Item<Pallet<T, I>> {
80 fn inspect(
81 (collection, item): &Self::Id,
82 _can_update: CanUpdate<Owner<T::AccountId>>,
83 ) -> Result<bool, DispatchError> {
84 match (Collection::<T, I>::get(collection), ItemStorage::<T, I>::get(collection, item)) {
85 (Some(cd), Some(id)) => Ok(!cd.is_frozen && !id.is_frozen),
86 _ => Err(Error::<T, I>::UnknownItem.into()),
87 }
88 }
89}
90
91impl<T: Config<I>, I: 'static> Create<WithItemConfig<T, I>> for Item<Pallet<T, I>> {
92 fn create(
93 strategy: WithItemConfig<T, I>,
94 ) -> Result<(T::CollectionId, T::ItemId), DispatchError> {
95 let WithConfig { config: ConfigValue::<_>(owner), extra: id_assignment } = strategy;
96 let (collection, item) = id_assignment.params;
97
98 <Pallet<T, I>>::do_mint(collection.clone(), item, owner, |_| Ok(()))?;
99
100 Ok((collection, item))
101 }
102}
103
104impl<T: Config<I>, I: 'static> Create<CheckOrigin<T::RuntimeOrigin, WithItemConfig<T, I>>>
105 for Item<Pallet<T, I>>
106{
107 fn create(
108 strategy: CheckOrigin<T::RuntimeOrigin, WithItemConfig<T, I>>,
109 ) -> Result<(T::CollectionId, T::ItemId), DispatchError> {
110 let CheckOrigin(
111 origin,
112 WithConfig { config: ConfigValue::<_>(owner), extra: id_assignment },
113 ) = strategy;
114 let (collection, item) = id_assignment.params;
115
116 let signer = ensure_signed(origin)?;
117
118 <Pallet<T, I>>::do_mint(collection.clone(), item, owner, |collection_details| {
119 ensure!(collection_details.issuer == signer, Error::<T, I>::NoPermission);
120 Ok(())
121 })?;
122
123 Ok((collection, item))
124 }
125}
126
127impl<T: Config<I>, I: 'static> Update<Owner<T::AccountId>> for Item<Pallet<T, I>> {
128 fn update(
129 (collection, item): &Self::Id,
130 _strategy: Owner<T::AccountId>,
131 dest: &T::AccountId,
132 ) -> DispatchResult {
133 <Pallet<T, I>>::do_transfer(collection.clone(), *item, dest.clone(), |_, _| Ok(()))
134 }
135}
136
137impl<T: Config<I>, I: 'static> Update<CheckOrigin<T::RuntimeOrigin, Owner<T::AccountId>>>
138 for Item<Pallet<T, I>>
139{
140 fn update(
141 (collection, item): &Self::Id,
142 strategy: CheckOrigin<T::RuntimeOrigin, Owner<T::AccountId>>,
143 dest: &T::AccountId,
144 ) -> DispatchResult {
145 let CheckOrigin(origin, ..) = strategy;
146
147 let signer = ensure_signed(origin)?;
148
149 <Pallet<T, I>>::do_transfer(
150 collection.clone(),
151 *item,
152 dest.clone(),
153 |collection_details, details| {
154 if details.owner != signer && collection_details.admin != signer {
155 let approved = details.approved.take().map_or(false, |i| i == signer);
156 ensure!(approved, Error::<T, I>::NoPermission);
157 }
158 Ok(())
159 },
160 )
161 }
162}
163
164impl<T: Config<I>, I: 'static> Update<ChangeOwnerFrom<T::AccountId>> for Item<Pallet<T, I>> {
165 fn update(
166 (collection, item): &Self::Id,
167 strategy: ChangeOwnerFrom<T::AccountId>,
168 dest: &T::AccountId,
169 ) -> DispatchResult {
170 let CheckState(from, ..) = strategy;
171
172 <Pallet<T, I>>::do_transfer(collection.clone(), *item, dest.clone(), |_, details| {
173 ensure!(details.owner == from, Error::<T, I>::WrongOwner);
174 Ok(())
175 })
176 }
177}
178
179impl<T: Config<I>, I: 'static> Stash<NoParams> for Item<Pallet<T, I>> {
180 fn stash((collection, item): &Self::Id, _strategy: NoParams) -> DispatchResult {
181 <Pallet<T, I>>::do_burn(collection.clone(), *item, |_, _| Ok(()))
182 }
183}
184
185impl<T: Config<I>, I: 'static> Stash<CheckOrigin<T::RuntimeOrigin>> for Item<Pallet<T, I>> {
186 fn stash(
187 (collection, item): &Self::Id,
188 strategy: CheckOrigin<T::RuntimeOrigin>,
189 ) -> DispatchResult {
190 let CheckOrigin(origin, ..) = strategy;
191
192 let signer = ensure_signed(origin)?;
193
194 <Pallet<T, I>>::do_burn(collection.clone(), *item, |collection_details, details| {
195 let is_permitted = collection_details.admin == signer || details.owner == signer;
196 ensure!(is_permitted, Error::<T, I>::NoPermission);
197 Ok(())
198 })
199 }
200}
201
202impl<T: Config<I>, I: 'static> Stash<IfOwnedBy<T::AccountId>> for Item<Pallet<T, I>> {
203 fn stash((collection, item): &Self::Id, strategy: IfOwnedBy<T::AccountId>) -> DispatchResult {
204 let CheckState(who, ..) = strategy;
205
206 <Pallet<T, I>>::do_burn(collection.clone(), *item, |_, d| {
207 ensure!(d.owner == who, Error::<T, I>::NoPermission);
208 Ok(())
209 })
210 }
211}
212
213impl<T: Config<I>, I: 'static> Restore<WithConfig<ConfigValue<Owner<T::AccountId>>>>
219 for Item<Pallet<T, I>>
220{
221 fn restore(
222 (collection, item): &Self::Id,
223 strategy: WithConfig<ConfigValue<Owner<T::AccountId>>>,
224 ) -> DispatchResult {
225 Self::create(WithConfig::new(
226 strategy.config,
227 PredefinedId::from((collection.clone(), *item)),
228 ))?;
229
230 Ok(())
231 }
232}