1use crate::*;
24use frame_support::{
25 pallet_prelude::*,
26 traits::{Currency, ExistenceRequirement::KeepAlive},
27};
28
29impl<T: Config<I>, I: 'static> Pallet<T, I> {
30 pub(crate) fn do_create_swap(
50 caller: T::AccountId,
51 offered_collection_id: T::CollectionId,
52 offered_item_id: T::ItemId,
53 desired_collection_id: T::CollectionId,
54 maybe_desired_item_id: Option<T::ItemId>,
55 maybe_price: Option<PriceWithDirection<ItemPrice<T, I>>>,
56 duration: BlockNumberFor<T, I>,
57 ) -> DispatchResult {
58 ensure!(
59 Self::is_pallet_feature_enabled(PalletFeature::Swaps),
60 Error::<T, I>::MethodDisabled
61 );
62 ensure!(duration <= T::MaxDeadlineDuration::get(), Error::<T, I>::WrongDuration);
63
64 let item = Item::<T, I>::get(&offered_collection_id, &offered_item_id)
65 .ok_or(Error::<T, I>::UnknownItem)?;
66 ensure!(item.owner == caller, Error::<T, I>::NoPermission);
67
68 match maybe_desired_item_id {
69 Some(desired_item_id) => ensure!(
70 Item::<T, I>::contains_key(&desired_collection_id, &desired_item_id),
71 Error::<T, I>::UnknownItem
72 ),
73 None => ensure!(
74 Collection::<T, I>::contains_key(&desired_collection_id),
75 Error::<T, I>::UnknownCollection
76 ),
77 };
78
79 let now = T::BlockNumberProvider::current_block_number();
80 let deadline = duration.saturating_add(now);
81
82 PendingSwapOf::<T, I>::insert(
83 &offered_collection_id,
84 &offered_item_id,
85 PendingSwap {
86 desired_collection: desired_collection_id,
87 desired_item: maybe_desired_item_id,
88 price: maybe_price.clone(),
89 deadline,
90 },
91 );
92
93 Self::deposit_event(Event::SwapCreated {
94 offered_collection: offered_collection_id,
95 offered_item: offered_item_id,
96 desired_collection: desired_collection_id,
97 desired_item: maybe_desired_item_id,
98 price: maybe_price,
99 deadline,
100 });
101
102 Ok(())
103 }
104 pub(crate) fn do_cancel_swap(
115 caller: T::AccountId,
116 offered_collection_id: T::CollectionId,
117 offered_item_id: T::ItemId,
118 ) -> DispatchResult {
119 let swap = PendingSwapOf::<T, I>::get(&offered_collection_id, &offered_item_id)
120 .ok_or(Error::<T, I>::UnknownSwap)?;
121
122 let now = T::BlockNumberProvider::current_block_number();
123 if swap.deadline > now {
124 let item = Item::<T, I>::get(&offered_collection_id, &offered_item_id)
125 .ok_or(Error::<T, I>::UnknownItem)?;
126 ensure!(item.owner == caller, Error::<T, I>::NoPermission);
127 }
128
129 PendingSwapOf::<T, I>::remove(&offered_collection_id, &offered_item_id);
130
131 Self::deposit_event(Event::SwapCancelled {
132 offered_collection: offered_collection_id,
133 offered_item: offered_item_id,
134 desired_collection: swap.desired_collection,
135 desired_item: swap.desired_item,
136 price: swap.price,
137 deadline: swap.deadline,
138 });
139
140 Ok(())
141 }
142
143 pub(crate) fn do_claim_swap(
161 caller: T::AccountId,
162 send_collection_id: T::CollectionId,
163 send_item_id: T::ItemId,
164 receive_collection_id: T::CollectionId,
165 receive_item_id: T::ItemId,
166 witness_price: Option<PriceWithDirection<ItemPrice<T, I>>>,
167 ) -> DispatchResult {
168 ensure!(
169 Self::is_pallet_feature_enabled(PalletFeature::Swaps),
170 Error::<T, I>::MethodDisabled
171 );
172
173 let send_item = Item::<T, I>::get(&send_collection_id, &send_item_id)
174 .ok_or(Error::<T, I>::UnknownItem)?;
175 let receive_item = Item::<T, I>::get(&receive_collection_id, &receive_item_id)
176 .ok_or(Error::<T, I>::UnknownItem)?;
177 let swap = PendingSwapOf::<T, I>::get(&receive_collection_id, &receive_item_id)
178 .ok_or(Error::<T, I>::UnknownSwap)?;
179
180 ensure!(send_item.owner == caller, Error::<T, I>::NoPermission);
181 ensure!(
182 swap.desired_collection == send_collection_id && swap.price == witness_price,
183 Error::<T, I>::UnknownSwap
184 );
185
186 if let Some(desired_item) = swap.desired_item {
187 ensure!(desired_item == send_item_id, Error::<T, I>::UnknownSwap);
188 }
189
190 let now = T::BlockNumberProvider::current_block_number();
191 ensure!(now <= swap.deadline, Error::<T, I>::DeadlineExpired);
192
193 if let Some(ref price) = swap.price {
194 match price.direction {
195 PriceDirection::Send => T::Currency::transfer(
196 &receive_item.owner,
197 &send_item.owner,
198 price.amount,
199 KeepAlive,
200 )?,
201 PriceDirection::Receive => T::Currency::transfer(
202 &send_item.owner,
203 &receive_item.owner,
204 price.amount,
205 KeepAlive,
206 )?,
207 };
208 }
209
210 Self::do_transfer(send_collection_id, send_item_id, receive_item.owner.clone(), |_, _| {
212 Ok(())
213 })?;
214 Self::do_transfer(
215 receive_collection_id,
216 receive_item_id,
217 send_item.owner.clone(),
218 |_, _| Ok(()),
219 )?;
220
221 Self::deposit_event(Event::SwapClaimed {
222 sent_collection: send_collection_id,
223 sent_item: send_item_id,
224 sent_item_owner: send_item.owner,
225 received_collection: receive_collection_id,
226 received_item: receive_item_id,
227 received_item_owner: receive_item.owner,
228 price: swap.price,
229 deadline: swap.deadline,
230 });
231
232 Ok(())
233 }
234}