referrerpolicy=no-referrer-when-downgrade

pallet_assets_freezer/
impls.rs

1// This file is part of Substrate.
2
3// Copyright (C) Parity Technologies (UK) Ltd.
4// SPDX-License-Identifier: MIT-0
5
6// Permission is hereby granted, free of charge, to any person obtaining a copy of
7// this software and associated documentation files (the "Software"), to deal in
8// the Software without restriction, including without limitation the rights to
9// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
10// of the Software, and to permit persons to whom the Software is furnished to do
11// so, subject to the following conditions:
12
13// The above copyright notice and this permission notice shall be included in all
14// copies or substantial portions of the Software.
15
16// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22// SOFTWARE.
23
24use super::*;
25use frame::prelude::storage::StorageDoubleMap;
26use pallet_assets::FrozenBalance;
27
28// Implements [`FrozenBalance`] from [`pallet-assets`], so it can understand how much of an
29// account balance is frozen, and is able to signal to this pallet when to clear the state of an
30// account.
31impl<T: Config<I>, I: 'static> FrozenBalance<T::AssetId, T::AccountId, T::Balance>
32	for Pallet<T, I>
33{
34	fn frozen_balance(asset: T::AssetId, who: &T::AccountId) -> Option<T::Balance> {
35		FrozenBalances::<T, I>::get(asset, who)
36	}
37
38	fn died(asset: T::AssetId, who: &T::AccountId) {
39		defensive_assert!(
40			Freezes::<T, I>::get(asset.clone(), who).is_empty(),
41			"The list of Freezes should be empty before allowing an account to die"
42		);
43		defensive_assert!(
44			FrozenBalances::<T, I>::get(asset.clone(), who).is_none(),
45			"There should not be a frozen balance before allowing to die"
46		);
47
48		FrozenBalances::<T, I>::remove(asset.clone(), who);
49		Freezes::<T, I>::remove(asset, who);
50	}
51
52	fn contains_freezes(asset: T::AssetId) -> bool {
53		Freezes::<T, I>::contains_prefix(asset)
54	}
55}
56
57// Implement [`fungibles::Inspect`](frame_support::traits::fungibles::Inspect) as it is bound by
58// [`fungibles::InspectFreeze`](frame_support::traits::fungibles::InspectFreeze) and
59// [`fungibles::MutateFreeze`](frame_support::traits::fungibles::MutateFreeze). To do so, we'll
60// re-export all of `pallet-assets` implementation of the same trait.
61impl<T: Config<I>, I: 'static> Inspect<T::AccountId> for Pallet<T, I> {
62	type AssetId = T::AssetId;
63	type Balance = T::Balance;
64
65	fn total_issuance(asset: Self::AssetId) -> Self::Balance {
66		pallet_assets::Pallet::<T, I>::total_issuance(asset)
67	}
68
69	fn minimum_balance(asset: Self::AssetId) -> Self::Balance {
70		pallet_assets::Pallet::<T, I>::minimum_balance(asset)
71	}
72
73	fn total_balance(asset: Self::AssetId, who: &T::AccountId) -> Self::Balance {
74		pallet_assets::Pallet::<T, I>::total_balance(asset, who)
75	}
76
77	fn balance(asset: Self::AssetId, who: &T::AccountId) -> Self::Balance {
78		pallet_assets::Pallet::<T, I>::balance(asset, who)
79	}
80
81	fn reducible_balance(
82		asset: Self::AssetId,
83		who: &T::AccountId,
84		preservation: Preservation,
85		force: Fortitude,
86	) -> Self::Balance {
87		pallet_assets::Pallet::<T, I>::reducible_balance(asset, who, preservation, force)
88	}
89
90	fn can_deposit(
91		asset: Self::AssetId,
92		who: &T::AccountId,
93		amount: Self::Balance,
94		provenance: Provenance,
95	) -> DepositConsequence {
96		pallet_assets::Pallet::<T, I>::can_deposit(asset, who, amount, provenance)
97	}
98
99	fn can_withdraw(
100		asset: Self::AssetId,
101		who: &T::AccountId,
102		amount: Self::Balance,
103	) -> WithdrawConsequence<Self::Balance> {
104		pallet_assets::Pallet::<T, I>::can_withdraw(asset, who, amount)
105	}
106
107	fn asset_exists(asset: Self::AssetId) -> bool {
108		pallet_assets::Pallet::<T, I>::asset_exists(asset)
109	}
110}
111
112impl<T: Config<I>, I: 'static> InspectFreeze<T::AccountId> for Pallet<T, I> {
113	type Id = T::RuntimeFreezeReason;
114
115	fn balance_frozen(asset: Self::AssetId, id: &Self::Id, who: &T::AccountId) -> Self::Balance {
116		let freezes = Freezes::<T, I>::get(asset, who);
117		freezes.into_iter().find(|l| &l.id == id).map_or(Zero::zero(), |l| l.amount)
118	}
119
120	fn can_freeze(asset: Self::AssetId, id: &Self::Id, who: &T::AccountId) -> bool {
121		let freezes = Freezes::<T, I>::get(asset, who);
122		!freezes.is_full() || freezes.into_iter().any(|i| i.id == *id)
123	}
124}
125
126impl<T: Config<I>, I: 'static> MutateFreeze<T::AccountId> for Pallet<T, I> {
127	fn set_freeze(
128		asset: Self::AssetId,
129		id: &Self::Id,
130		who: &T::AccountId,
131		amount: Self::Balance,
132	) -> DispatchResult {
133		if amount.is_zero() {
134			return Self::thaw(asset, id, who);
135		}
136		let mut freezes = Freezes::<T, I>::get(asset.clone(), who);
137		if let Some(i) = freezes.iter_mut().find(|i| &i.id == id) {
138			i.amount = amount;
139		} else {
140			freezes
141				.try_push(IdAmount { id: *id, amount })
142				.map_err(|_| Error::<T, I>::TooManyFreezes)?;
143		}
144		Self::update_freezes(asset, who, freezes.as_bounded_slice())
145	}
146
147	fn extend_freeze(
148		asset: Self::AssetId,
149		id: &Self::Id,
150		who: &T::AccountId,
151		amount: Self::Balance,
152	) -> DispatchResult {
153		if amount.is_zero() {
154			return Ok(());
155		}
156		let mut freezes = Freezes::<T, I>::get(asset.clone(), who);
157		if let Some(i) = freezes.iter_mut().find(|x| &x.id == id) {
158			i.amount = i.amount.max(amount);
159		} else {
160			freezes
161				.try_push(IdAmount { id: *id, amount })
162				.map_err(|_| Error::<T, I>::TooManyFreezes)?;
163		}
164		Self::update_freezes(asset, who, freezes.as_bounded_slice())
165	}
166
167	fn thaw(asset: Self::AssetId, id: &Self::Id, who: &T::AccountId) -> DispatchResult {
168		let mut freezes = Freezes::<T, I>::get(asset.clone(), who);
169		freezes.retain(|f| &f.id != id);
170		Self::update_freezes(asset, who, freezes.as_bounded_slice())
171	}
172}