frame_support/traits/tokens/fungible/
item_of.rs

1// This file is part of Substrate.
2
3// Copyright (C) Parity Technologies (UK) Ltd.
4// SPDX-License-Identifier: Apache-2.0
5
6// Licensed under the Apache License, Version 2.0 (the "License");
7// you may not use this file except in compliance with the License.
8// You may obtain a copy of the License at
9//
10// 	http://www.apache.org/licenses/LICENSE-2.0
11//
12// Unless required by applicable law or agreed to in writing, software
13// distributed under the License is distributed on an "AS IS" BASIS,
14// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15// See the License for the specific language governing permissions and
16// limitations under the License.
17
18//! Adapter to use `fungibles::*` implementations as `fungible::*`.
19//!
20//! This allows for a `fungibles` asset, e.g. from the `pallet_assets` pallet, to be used when a
21//! `fungible` asset is expected.
22//!
23//! See the [`crate::traits::fungible`] doc for more information about fungible traits.
24
25use super::*;
26use crate::traits::{
27	fungible::imbalance,
28	tokens::{
29		fungibles, DepositConsequence, Fortitude, Precision, Preservation, Provenance, Restriction,
30		WithdrawConsequence,
31	},
32};
33use sp_core::Get;
34use sp_runtime::{DispatchError, DispatchResult};
35
36/// Convert a `fungibles` trait implementation into a `fungible` trait implementation by identifying
37/// a single item.
38pub struct ItemOf<
39	F: fungibles::Inspect<AccountId>,
40	A: Get<<F as fungibles::Inspect<AccountId>>::AssetId>,
41	AccountId,
42>(core::marker::PhantomData<(F, A, AccountId)>);
43
44impl<
45		F: fungibles::Inspect<AccountId>,
46		A: Get<<F as fungibles::Inspect<AccountId>>::AssetId>,
47		AccountId,
48	> Inspect<AccountId> for ItemOf<F, A, AccountId>
49{
50	type Balance = <F as fungibles::Inspect<AccountId>>::Balance;
51	fn total_issuance() -> Self::Balance {
52		<F as fungibles::Inspect<AccountId>>::total_issuance(A::get())
53	}
54	fn active_issuance() -> Self::Balance {
55		<F as fungibles::Inspect<AccountId>>::active_issuance(A::get())
56	}
57	fn minimum_balance() -> Self::Balance {
58		<F as fungibles::Inspect<AccountId>>::minimum_balance(A::get())
59	}
60	fn balance(who: &AccountId) -> Self::Balance {
61		<F as fungibles::Inspect<AccountId>>::balance(A::get(), who)
62	}
63	fn total_balance(who: &AccountId) -> Self::Balance {
64		<F as fungibles::Inspect<AccountId>>::total_balance(A::get(), who)
65	}
66	fn reducible_balance(
67		who: &AccountId,
68		preservation: Preservation,
69		force: Fortitude,
70	) -> Self::Balance {
71		<F as fungibles::Inspect<AccountId>>::reducible_balance(A::get(), who, preservation, force)
72	}
73	fn can_deposit(
74		who: &AccountId,
75		amount: Self::Balance,
76		provenance: Provenance,
77	) -> DepositConsequence {
78		<F as fungibles::Inspect<AccountId>>::can_deposit(A::get(), who, amount, provenance)
79	}
80	fn can_withdraw(who: &AccountId, amount: Self::Balance) -> WithdrawConsequence<Self::Balance> {
81		<F as fungibles::Inspect<AccountId>>::can_withdraw(A::get(), who, amount)
82	}
83}
84
85impl<
86		F: fungibles::InspectHold<AccountId>,
87		A: Get<<F as fungibles::Inspect<AccountId>>::AssetId>,
88		AccountId,
89	> InspectHold<AccountId> for ItemOf<F, A, AccountId>
90{
91	type Reason = F::Reason;
92
93	fn reducible_total_balance_on_hold(who: &AccountId, force: Fortitude) -> Self::Balance {
94		<F as fungibles::InspectHold<AccountId>>::reducible_total_balance_on_hold(
95			A::get(),
96			who,
97			force,
98		)
99	}
100	fn hold_available(reason: &Self::Reason, who: &AccountId) -> bool {
101		<F as fungibles::InspectHold<AccountId>>::hold_available(A::get(), reason, who)
102	}
103	fn total_balance_on_hold(who: &AccountId) -> Self::Balance {
104		<F as fungibles::InspectHold<AccountId>>::total_balance_on_hold(A::get(), who)
105	}
106	fn balance_on_hold(reason: &Self::Reason, who: &AccountId) -> Self::Balance {
107		<F as fungibles::InspectHold<AccountId>>::balance_on_hold(A::get(), reason, who)
108	}
109	fn can_hold(reason: &Self::Reason, who: &AccountId, amount: Self::Balance) -> bool {
110		<F as fungibles::InspectHold<AccountId>>::can_hold(A::get(), reason, who, amount)
111	}
112}
113
114impl<
115		F: fungibles::InspectFreeze<AccountId>,
116		A: Get<<F as fungibles::Inspect<AccountId>>::AssetId>,
117		AccountId,
118	> InspectFreeze<AccountId> for ItemOf<F, A, AccountId>
119{
120	type Id = F::Id;
121	fn balance_frozen(id: &Self::Id, who: &AccountId) -> Self::Balance {
122		<F as fungibles::InspectFreeze<AccountId>>::balance_frozen(A::get(), id, who)
123	}
124	fn balance_freezable(who: &AccountId) -> Self::Balance {
125		<F as fungibles::InspectFreeze<AccountId>>::balance_freezable(A::get(), who)
126	}
127	fn can_freeze(id: &Self::Id, who: &AccountId) -> bool {
128		<F as fungibles::InspectFreeze<AccountId>>::can_freeze(A::get(), id, who)
129	}
130}
131
132impl<
133		F: fungibles::Unbalanced<AccountId>,
134		A: Get<<F as fungibles::Inspect<AccountId>>::AssetId>,
135		AccountId,
136	> Unbalanced<AccountId> for ItemOf<F, A, AccountId>
137{
138	fn handle_dust(dust: regular::Dust<AccountId, Self>)
139	where
140		Self: Sized,
141	{
142		<F as fungibles::Unbalanced<AccountId>>::handle_dust(fungibles::Dust(A::get(), dust.0))
143	}
144	fn write_balance(
145		who: &AccountId,
146		amount: Self::Balance,
147	) -> Result<Option<Self::Balance>, DispatchError> {
148		<F as fungibles::Unbalanced<AccountId>>::write_balance(A::get(), who, amount)
149	}
150	fn set_total_issuance(amount: Self::Balance) -> () {
151		<F as fungibles::Unbalanced<AccountId>>::set_total_issuance(A::get(), amount)
152	}
153	fn decrease_balance(
154		who: &AccountId,
155		amount: Self::Balance,
156		precision: Precision,
157		preservation: Preservation,
158		force: Fortitude,
159	) -> Result<Self::Balance, DispatchError> {
160		<F as fungibles::Unbalanced<AccountId>>::decrease_balance(
161			A::get(),
162			who,
163			amount,
164			precision,
165			preservation,
166			force,
167		)
168	}
169	fn increase_balance(
170		who: &AccountId,
171		amount: Self::Balance,
172		precision: Precision,
173	) -> Result<Self::Balance, DispatchError> {
174		<F as fungibles::Unbalanced<AccountId>>::increase_balance(A::get(), who, amount, precision)
175	}
176}
177
178impl<
179		F: fungibles::UnbalancedHold<AccountId>,
180		A: Get<<F as fungibles::Inspect<AccountId>>::AssetId>,
181		AccountId,
182	> UnbalancedHold<AccountId> for ItemOf<F, A, AccountId>
183{
184	fn set_balance_on_hold(
185		reason: &Self::Reason,
186		who: &AccountId,
187		amount: Self::Balance,
188	) -> DispatchResult {
189		<F as fungibles::UnbalancedHold<AccountId>>::set_balance_on_hold(
190			A::get(),
191			reason,
192			who,
193			amount,
194		)
195	}
196	fn decrease_balance_on_hold(
197		reason: &Self::Reason,
198		who: &AccountId,
199		amount: Self::Balance,
200		precision: Precision,
201	) -> Result<Self::Balance, DispatchError> {
202		<F as fungibles::UnbalancedHold<AccountId>>::decrease_balance_on_hold(
203			A::get(),
204			reason,
205			who,
206			amount,
207			precision,
208		)
209	}
210	fn increase_balance_on_hold(
211		reason: &Self::Reason,
212		who: &AccountId,
213		amount: Self::Balance,
214		precision: Precision,
215	) -> Result<Self::Balance, DispatchError> {
216		<F as fungibles::UnbalancedHold<AccountId>>::increase_balance_on_hold(
217			A::get(),
218			reason,
219			who,
220			amount,
221			precision,
222		)
223	}
224}
225
226impl<
227		F: fungibles::Mutate<AccountId>,
228		A: Get<<F as fungibles::Inspect<AccountId>>::AssetId>,
229		AccountId: Eq,
230	> Mutate<AccountId> for ItemOf<F, A, AccountId>
231{
232	fn mint_into(who: &AccountId, amount: Self::Balance) -> Result<Self::Balance, DispatchError> {
233		<F as fungibles::Mutate<AccountId>>::mint_into(A::get(), who, amount)
234	}
235	fn burn_from(
236		who: &AccountId,
237		amount: Self::Balance,
238		preservation: Preservation,
239		precision: Precision,
240		force: Fortitude,
241	) -> Result<Self::Balance, DispatchError> {
242		<F as fungibles::Mutate<AccountId>>::burn_from(
243			A::get(),
244			who,
245			amount,
246			preservation,
247			precision,
248			force,
249		)
250	}
251	fn shelve(who: &AccountId, amount: Self::Balance) -> Result<Self::Balance, DispatchError> {
252		<F as fungibles::Mutate<AccountId>>::shelve(A::get(), who, amount)
253	}
254	fn restore(who: &AccountId, amount: Self::Balance) -> Result<Self::Balance, DispatchError> {
255		<F as fungibles::Mutate<AccountId>>::restore(A::get(), who, amount)
256	}
257	fn transfer(
258		source: &AccountId,
259		dest: &AccountId,
260		amount: Self::Balance,
261		preservation: Preservation,
262	) -> Result<Self::Balance, DispatchError> {
263		<F as fungibles::Mutate<AccountId>>::transfer(A::get(), source, dest, amount, preservation)
264	}
265
266	fn set_balance(who: &AccountId, amount: Self::Balance) -> Self::Balance {
267		<F as fungibles::Mutate<AccountId>>::set_balance(A::get(), who, amount)
268	}
269}
270
271impl<
272		F: fungibles::MutateHold<AccountId>,
273		A: Get<<F as fungibles::Inspect<AccountId>>::AssetId>,
274		AccountId,
275	> MutateHold<AccountId> for ItemOf<F, A, AccountId>
276{
277	fn hold(reason: &Self::Reason, who: &AccountId, amount: Self::Balance) -> DispatchResult {
278		<F as fungibles::MutateHold<AccountId>>::hold(A::get(), reason, who, amount)
279	}
280	fn release(
281		reason: &Self::Reason,
282		who: &AccountId,
283		amount: Self::Balance,
284		precision: Precision,
285	) -> Result<Self::Balance, DispatchError> {
286		<F as fungibles::MutateHold<AccountId>>::release(A::get(), reason, who, amount, precision)
287	}
288	fn burn_held(
289		reason: &Self::Reason,
290		who: &AccountId,
291		amount: Self::Balance,
292		precision: Precision,
293		force: Fortitude,
294	) -> Result<Self::Balance, DispatchError> {
295		<F as fungibles::MutateHold<AccountId>>::burn_held(
296			A::get(),
297			reason,
298			who,
299			amount,
300			precision,
301			force,
302		)
303	}
304	fn transfer_on_hold(
305		reason: &Self::Reason,
306		source: &AccountId,
307		dest: &AccountId,
308		amount: Self::Balance,
309		precision: Precision,
310		mode: Restriction,
311		force: Fortitude,
312	) -> Result<Self::Balance, DispatchError> {
313		<F as fungibles::MutateHold<AccountId>>::transfer_on_hold(
314			A::get(),
315			reason,
316			source,
317			dest,
318			amount,
319			precision,
320			mode,
321			force,
322		)
323	}
324	fn transfer_and_hold(
325		reason: &Self::Reason,
326		source: &AccountId,
327		dest: &AccountId,
328		amount: Self::Balance,
329		precision: Precision,
330		preservation: Preservation,
331		force: Fortitude,
332	) -> Result<Self::Balance, DispatchError> {
333		<F as fungibles::MutateHold<AccountId>>::transfer_and_hold(
334			A::get(),
335			reason,
336			source,
337			dest,
338			amount,
339			precision,
340			preservation,
341			force,
342		)
343	}
344}
345
346impl<
347		F: fungibles::MutateFreeze<AccountId>,
348		A: Get<<F as fungibles::Inspect<AccountId>>::AssetId>,
349		AccountId,
350	> MutateFreeze<AccountId> for ItemOf<F, A, AccountId>
351{
352	fn set_freeze(id: &Self::Id, who: &AccountId, amount: Self::Balance) -> DispatchResult {
353		<F as fungibles::MutateFreeze<AccountId>>::set_freeze(A::get(), id, who, amount)
354	}
355	fn extend_freeze(id: &Self::Id, who: &AccountId, amount: Self::Balance) -> DispatchResult {
356		<F as fungibles::MutateFreeze<AccountId>>::extend_freeze(A::get(), id, who, amount)
357	}
358	fn thaw(id: &Self::Id, who: &AccountId) -> DispatchResult {
359		<F as fungibles::MutateFreeze<AccountId>>::thaw(A::get(), id, who)
360	}
361}
362
363pub struct ConvertImbalanceDropHandler<AccountId, Balance, AssetIdType, AssetId, Handler>(
364	core::marker::PhantomData<(AccountId, Balance, AssetIdType, AssetId, Handler)>,
365);
366
367impl<
368		AccountId,
369		Balance,
370		AssetIdType,
371		AssetId: Get<AssetIdType>,
372		Handler: crate::traits::fungibles::HandleImbalanceDrop<AssetIdType, Balance>,
373	> HandleImbalanceDrop<Balance>
374	for ConvertImbalanceDropHandler<AccountId, Balance, AssetIdType, AssetId, Handler>
375{
376	fn handle(amount: Balance) {
377		Handler::handle(AssetId::get(), amount)
378	}
379}
380
381impl<
382		F: fungibles::Inspect<AccountId>
383			+ fungibles::Unbalanced<AccountId>
384			+ fungibles::Balanced<AccountId>,
385		A: Get<<F as fungibles::Inspect<AccountId>>::AssetId>,
386		AccountId,
387	> Balanced<AccountId> for ItemOf<F, A, AccountId>
388{
389	type OnDropDebt =
390		ConvertImbalanceDropHandler<AccountId, Self::Balance, F::AssetId, A, F::OnDropDebt>;
391	type OnDropCredit =
392		ConvertImbalanceDropHandler<AccountId, Self::Balance, F::AssetId, A, F::OnDropCredit>;
393	fn deposit(
394		who: &AccountId,
395		value: Self::Balance,
396		precision: Precision,
397	) -> Result<Debt<AccountId, Self>, DispatchError> {
398		<F as fungibles::Balanced<AccountId>>::deposit(A::get(), who, value, precision)
399			.map(imbalance::from_fungibles)
400	}
401	fn issue(amount: Self::Balance) -> Credit<AccountId, Self> {
402		let credit = <F as fungibles::Balanced<AccountId>>::issue(A::get(), amount);
403		imbalance::from_fungibles(credit)
404	}
405	fn pair(
406		amount: Self::Balance,
407	) -> Result<(Debt<AccountId, Self>, Credit<AccountId, Self>), DispatchError> {
408		let (a, b) = <F as fungibles::Balanced<AccountId>>::pair(A::get(), amount)?;
409		Ok((imbalance::from_fungibles(a), imbalance::from_fungibles(b)))
410	}
411	fn rescind(amount: Self::Balance) -> Debt<AccountId, Self> {
412		let debt = <F as fungibles::Balanced<AccountId>>::rescind(A::get(), amount);
413		imbalance::from_fungibles(debt)
414	}
415	fn resolve(
416		who: &AccountId,
417		credit: Credit<AccountId, Self>,
418	) -> Result<(), Credit<AccountId, Self>> {
419		let credit = fungibles::imbalance::from_fungible(credit, A::get());
420		<F as fungibles::Balanced<AccountId>>::resolve(who, credit)
421			.map_err(imbalance::from_fungibles)
422	}
423	fn settle(
424		who: &AccountId,
425		debt: Debt<AccountId, Self>,
426		preservation: Preservation,
427	) -> Result<Credit<AccountId, Self>, Debt<AccountId, Self>> {
428		let debt = fungibles::imbalance::from_fungible(debt, A::get());
429		<F as fungibles::Balanced<AccountId>>::settle(who, debt, preservation).map_or_else(
430			|d| Err(imbalance::from_fungibles(d)),
431			|c| Ok(imbalance::from_fungibles(c)),
432		)
433	}
434	fn withdraw(
435		who: &AccountId,
436		value: Self::Balance,
437		precision: Precision,
438		preservation: Preservation,
439		force: Fortitude,
440	) -> Result<Credit<AccountId, Self>, DispatchError> {
441		<F as fungibles::Balanced<AccountId>>::withdraw(
442			A::get(),
443			who,
444			value,
445			precision,
446			preservation,
447			force,
448		)
449		.map(imbalance::from_fungibles)
450	}
451}
452
453impl<
454		F: fungibles::BalancedHold<AccountId>,
455		A: Get<<F as fungibles::Inspect<AccountId>>::AssetId>,
456		AccountId,
457	> BalancedHold<AccountId> for ItemOf<F, A, AccountId>
458{
459	fn slash(
460		reason: &Self::Reason,
461		who: &AccountId,
462		amount: Self::Balance,
463	) -> (Credit<AccountId, Self>, Self::Balance) {
464		let (credit, amount) =
465			<F as fungibles::BalancedHold<AccountId>>::slash(A::get(), reason, who, amount);
466		(imbalance::from_fungibles(credit), amount)
467	}
468}
469
470#[test]
471fn test() {}