frame_support/traits/tokens/fungible/conformance_tests/regular/
balanced.rs1use crate::traits::{
19 fungible::{Balanced, Inspect},
20 tokens::{imbalance::Imbalance as ImbalanceT, Fortitude, Precision, Preservation},
21};
22use core::fmt::Debug;
23use frame_support::traits::tokens::fungible::imbalance::{Credit, Debt};
24use sp_arithmetic::{traits::AtLeast8BitUnsigned, ArithmeticError};
25use sp_runtime::{traits::Bounded, TokenError};
26
27pub fn issue_and_resolve_credit<T, AccountId>()
30where
31 T: Balanced<AccountId>,
32 <T as Inspect<AccountId>>::Balance: AtLeast8BitUnsigned + Debug,
33 AccountId: AtLeast8BitUnsigned,
34{
35 let account = AccountId::from(0);
36 assert_eq!(T::total_issuance(), 0.into());
37 assert_eq!(T::balance(&account), 0.into());
38
39 let credit: Credit<AccountId, T> = T::issue(T::minimum_balance() - 1.into());
41 assert_eq!(T::total_issuance(), credit.peek());
43 match T::resolve(&account, credit) {
44 Ok(_) => panic!("Balanced::resolve should have failed"),
45 Err(c) => assert_eq!(c.peek(), T::minimum_balance() - 1.into()),
46 };
47 assert_eq!(T::total_issuance(), 0.into());
49 assert_eq!(T::balance(&account), 0.into());
50
51 let credit: Credit<AccountId, T> = T::issue(T::minimum_balance());
53 match T::resolve(&account, credit) {
54 Ok(()) => {},
55 Err(_) => panic!("resolve failed"),
56 };
57 assert_eq!(T::total_issuance(), T::minimum_balance());
58 assert_eq!(T::balance(&account), T::minimum_balance());
59
60 let total_issuance_before = T::total_issuance();
63 let balance_before = T::balance(&account);
64 let amount = T::minimum_balance() - 1.into();
65 let credit: Credit<AccountId, T> = T::issue(amount);
66 match T::resolve(&account, credit) {
67 Ok(()) => {},
68 Err(_) => panic!("resolve failed"),
69 };
70 assert_eq!(T::total_issuance(), total_issuance_before + amount);
71 assert_eq!(T::balance(&account), balance_before + amount);
72
73 let total_issuance_before = T::total_issuance();
77 let balance_before = T::balance(&account);
78 let _ = T::issue(5.into());
79 assert_eq!(T::total_issuance(), total_issuance_before);
80 assert_eq!(T::balance(&account), balance_before);
81}
82
83pub fn rescind_and_settle_debt<T, AccountId>()
86where
87 T: Balanced<AccountId>,
88 <T as Inspect<AccountId>>::Balance: AtLeast8BitUnsigned + Debug,
89 AccountId: AtLeast8BitUnsigned,
90{
91 let account = AccountId::from(0);
93 let initial_bal = T::minimum_balance() + 10.into();
94 let credit = T::issue(initial_bal);
95 match T::resolve(&account, credit) {
96 Ok(()) => {},
97 Err(_) => panic!("resolve failed"),
98 };
99 assert_eq!(T::total_issuance(), initial_bal);
100 assert_eq!(T::balance(&account), initial_bal);
101
102 let rescind_amount = 2.into();
104 let debt: Debt<AccountId, T> = T::rescind(rescind_amount);
105 assert_eq!(debt.peek(), rescind_amount);
106 match T::settle(&account, debt, Preservation::Expendable) {
107 Ok(c) => {
108 assert_eq!(c.peek(), 0.into());
111 },
112 Err(_) => panic!("settle failed"),
113 };
114 assert_eq!(T::total_issuance(), initial_bal - rescind_amount);
115 assert_eq!(T::balance(&account), initial_bal - rescind_amount);
116
117 let _ = T::rescind(T::minimum_balance());
121 assert_eq!(T::total_issuance(), initial_bal - rescind_amount);
122 assert_eq!(T::balance(&account), initial_bal - rescind_amount);
123
124 let balance_before = T::balance(&account);
126 let total_issuance_before = T::total_issuance();
127 let rescind_amount = balance_before - T::minimum_balance() + 1.into();
128 let debt: Debt<AccountId, T> = T::rescind(rescind_amount);
129 assert_eq!(debt.peek(), rescind_amount);
130 assert_eq!(T::total_issuance(), total_issuance_before - debt.peek().into());
132 match T::settle(&account, debt, Preservation::Preserve) {
133 Ok(_) => panic!("Balanced::settle should have failed"),
134 Err(d) => assert_eq!(d.peek(), rescind_amount),
135 };
136 assert_eq!(T::total_issuance(), total_issuance_before);
139 assert_eq!(T::balance(&account), balance_before);
140
141 let debt: Debt<AccountId, T> = T::rescind(rescind_amount);
143 match T::settle(&account, debt, Preservation::Expendable) {
144 Ok(c) => {
145 assert_eq!(c.peek(), 0.into());
147 },
148 Err(_) => panic!("settle failed"),
149 };
150 assert_eq!(T::total_issuance(), 0.into());
152 assert_eq!(T::balance(&account), 0.into());
153}
154
155pub fn deposit<T, AccountId>()
157where
158 T: Balanced<AccountId>,
159 <T as Inspect<AccountId>>::Balance: AtLeast8BitUnsigned + Debug,
160 AccountId: AtLeast8BitUnsigned,
161{
162 let account = AccountId::from(0);
164 let amount = T::minimum_balance() - 1.into();
165 match T::deposit(&account, amount, Precision::Exact) {
166 Ok(_) => panic!("Balanced::deposit should have failed"),
167 Err(e) => assert_eq!(e, TokenError::BelowMinimum.into()),
168 };
169 assert_eq!(T::total_issuance(), 0.into());
170 assert_eq!(T::balance(&account), 0.into());
171
172 let amount = T::minimum_balance();
174 match T::deposit(&account, amount, Precision::Exact) {
175 Ok(d) => assert_eq!(d.peek(), amount),
176 Err(_) => panic!("Balanced::deposit failed"),
177 };
178 assert_eq!(T::total_issuance(), amount);
179 assert_eq!(T::balance(&account), amount);
180
181 let amount = T::Balance::max_value();
183 let balance_before = T::balance(&account);
184 let total_issuance_before = T::total_issuance();
185 match T::deposit(&account, amount, Precision::Exact) {
186 Ok(_) => panic!("Balanced::deposit should have failed"),
187 Err(e) => assert_eq!(e, ArithmeticError::Overflow.into()),
188 };
189 assert_eq!(T::total_issuance(), total_issuance_before);
190 assert_eq!(T::balance(&account), balance_before);
191
192 match T::deposit(&account, amount, Precision::BestEffort) {
194 Ok(d) => assert_eq!(d.peek(), T::Balance::max_value() - balance_before),
195 Err(_) => panic!("Balanced::deposit failed"),
196 };
197 assert_eq!(T::total_issuance(), T::Balance::max_value());
198 assert_eq!(T::balance(&account), T::Balance::max_value());
199}
200
201pub fn withdraw<T, AccountId>()
203where
204 T: Balanced<AccountId>,
205 <T as Inspect<AccountId>>::Balance: AtLeast8BitUnsigned + Debug,
206 AccountId: AtLeast8BitUnsigned,
207{
208 let account = AccountId::from(0);
209
210 let initial_balance = T::minimum_balance() + 10.into();
212 match T::deposit(&account, initial_balance, Precision::Exact) {
213 Ok(_) => {},
214 Err(_) => panic!("Balanced::deposit failed"),
215 };
216 assert_eq!(T::total_issuance(), initial_balance);
217 assert_eq!(T::balance(&account), initial_balance);
218
219 let amount = 1.into();
221 match T::withdraw(
222 &account,
223 amount,
224 Precision::Exact,
225 Preservation::Expendable,
226 Fortitude::Polite,
227 ) {
228 Ok(c) => assert_eq!(c.peek(), amount),
229 Err(_) => panic!("withdraw failed"),
230 };
231 assert_eq!(T::total_issuance(), initial_balance - amount);
232 assert_eq!(T::balance(&account), initial_balance - amount);
233
234 let balance_before = T::balance(&account);
236 let amount = balance_before + 1.into();
237 match T::withdraw(
238 &account,
239 amount,
240 Precision::Exact,
241 Preservation::Expendable,
242 Fortitude::Polite,
243 ) {
244 Ok(_) => panic!("should have failed"),
245 Err(e) => assert_eq!(e, TokenError::FundsUnavailable.into()),
246 };
247 assert_eq!(T::total_issuance(), balance_before);
248 assert_eq!(T::balance(&account), balance_before);
249
250 let balance_before = T::balance(&account);
252 let amount = balance_before + 1.into();
253 match T::withdraw(
254 &account,
255 amount,
256 Precision::BestEffort,
257 Preservation::Expendable,
258 Fortitude::Polite,
259 ) {
260 Ok(c) => assert_eq!(c.peek(), balance_before),
261 Err(_) => panic!("withdraw failed"),
262 };
263 assert_eq!(T::total_issuance(), 0.into());
264 assert_eq!(T::balance(&account), 0.into());
265}
266
267pub fn pair<T, AccountId>()
269where
270 T: Balanced<AccountId>,
271 <T as Inspect<AccountId>>::Balance: AtLeast8BitUnsigned + Debug,
272 AccountId: AtLeast8BitUnsigned,
273{
274 T::set_total_issuance(50.into());
275
276 let (credit, debt) = T::pair(0.into()).unwrap();
278 assert_eq!(debt.peek(), 0.into());
279 assert_eq!(credit.peek(), 0.into());
280
281 let balance = 10.into();
283 let (credit, debt) = T::pair(balance).unwrap();
284 assert_eq!(credit.peek(), balance);
285 assert_eq!(debt.peek(), balance);
286
287 let max_value = T::Balance::max_value();
289 let distance_from_max_value = 5.into();
290 T::set_total_issuance(max_value - distance_from_max_value);
291 T::pair(distance_from_max_value + 5.into()).unwrap_err();
292}