1use core::marker::PhantomData;
23
24use crate::{
25 ensure,
26 traits::{
27 tokens::{
28 misc::{
29 Balance, DepositConsequence,
30 Fortitude::{self, Force, Polite},
31 Precision::{self, BestEffort, Exact},
32 Preservation::{self, Expendable},
33 Provenance::{self, Extant},
34 WithdrawConsequence,
35 },
36 AssetId,
37 },
38 SameOrOther, TryDrop,
39 },
40};
41use sp_arithmetic::traits::{CheckedAdd, CheckedSub, One};
42use sp_runtime::{traits::Saturating, ArithmeticError, DispatchError, TokenError};
43
44use super::{Credit, Debt, HandleImbalanceDrop, Imbalance};
45
46pub trait Inspect<AccountId>: Sized {
48 type AssetId: AssetId;
50
51 type Balance: Balance;
53
54 fn total_issuance(asset: Self::AssetId) -> Self::Balance;
56
57 fn active_issuance(asset: Self::AssetId) -> Self::Balance {
60 Self::total_issuance(asset)
61 }
62
63 fn minimum_balance(asset: Self::AssetId) -> Self::Balance;
65
66 fn total_balance(asset: Self::AssetId, who: &AccountId) -> Self::Balance;
78
79 fn balance(asset: Self::AssetId, who: &AccountId) -> Self::Balance;
85
86 fn reducible_balance(
93 asset: Self::AssetId,
94 who: &AccountId,
95 preservation: Preservation,
96 force: Fortitude,
97 ) -> Self::Balance;
98
99 fn can_deposit(
106 asset: Self::AssetId,
107 who: &AccountId,
108 amount: Self::Balance,
109 provenance: Provenance,
110 ) -> DepositConsequence;
111
112 fn can_withdraw(
115 asset: Self::AssetId,
116 who: &AccountId,
117 amount: Self::Balance,
118 ) -> WithdrawConsequence<Self::Balance>;
119
120 fn asset_exists(asset: Self::AssetId) -> bool;
122
123 fn is_sufficient(_asset: Self::AssetId) -> bool {
127 false
128 }
129}
130
131#[must_use]
133pub struct Dust<A, T: Unbalanced<A>>(pub T::AssetId, pub T::Balance);
134
135impl<A, T: Balanced<A>> Dust<A, T> {
136 pub fn into_credit(self) -> Credit<A, T> {
138 Credit::<A, T>::new(self.0, self.1)
139 }
140}
141
142pub trait Unbalanced<AccountId>: Inspect<AccountId> {
151 fn handle_raw_dust(asset: Self::AssetId, amount: Self::Balance) {
157 Self::handle_dust(Dust(
158 asset.clone(),
159 amount.min(Self::minimum_balance(asset).saturating_sub(One::one())),
160 ))
161 }
162
163 fn handle_dust(dust: Dust<AccountId, Self>);
166
167 fn write_balance(
179 asset: Self::AssetId,
180 who: &AccountId,
181 amount: Self::Balance,
182 ) -> Result<Option<Self::Balance>, DispatchError>;
183
184 fn set_total_issuance(asset: Self::AssetId, amount: Self::Balance);
186
187 fn decrease_balance(
198 asset: Self::AssetId,
199 who: &AccountId,
200 mut amount: Self::Balance,
201 precision: Precision,
202 preservation: Preservation,
203 force: Fortitude,
204 ) -> Result<Self::Balance, DispatchError> {
205 let old_balance = Self::balance(asset.clone(), who);
206 let reducible = Self::reducible_balance(asset.clone(), who, preservation, force);
207 match precision {
208 BestEffort => amount = amount.min(reducible),
209 Exact => ensure!(reducible >= amount, TokenError::FundsUnavailable),
210 }
211 let new_balance = old_balance.checked_sub(&amount).ok_or(TokenError::FundsUnavailable)?;
212 if let Some(dust) = Self::write_balance(asset.clone(), who, new_balance)? {
213 Self::handle_dust(Dust(asset, dust));
214 }
215 Ok(old_balance.saturating_sub(new_balance))
216 }
217
218 fn increase_balance(
225 asset: Self::AssetId,
226 who: &AccountId,
227 amount: Self::Balance,
228 precision: Precision,
229 ) -> Result<Self::Balance, DispatchError> {
230 let old_balance = Self::balance(asset.clone(), who);
231 let new_balance = if let BestEffort = precision {
232 old_balance.saturating_add(amount)
233 } else {
234 old_balance.checked_add(&amount).ok_or(ArithmeticError::Overflow)?
235 };
236 if new_balance < Self::minimum_balance(asset.clone()) {
237 if let BestEffort = precision {
239 Ok(Self::Balance::default())
240 } else {
241 Err(TokenError::BelowMinimum.into())
242 }
243 } else {
244 if new_balance == old_balance {
245 Ok(Self::Balance::default())
246 } else {
247 if let Some(dust) = Self::write_balance(asset.clone(), who, new_balance)? {
248 Self::handle_dust(Dust(asset, dust));
249 }
250 Ok(new_balance.saturating_sub(old_balance))
251 }
252 }
253 }
254
255 fn deactivate(_asset: Self::AssetId, _: Self::Balance) {}
257
258 fn reactivate(_asset: Self::AssetId, _: Self::Balance) {}
260}
261
262pub trait Mutate<AccountId>: Inspect<AccountId> + Unbalanced<AccountId>
264where
265 AccountId: Eq,
266{
267 fn mint_into(
270 asset: Self::AssetId,
271 who: &AccountId,
272 amount: Self::Balance,
273 ) -> Result<Self::Balance, DispatchError> {
274 Self::total_issuance(asset.clone())
275 .checked_add(&amount)
276 .ok_or(ArithmeticError::Overflow)?;
277 let actual = Self::increase_balance(asset.clone(), who, amount, Exact)?;
278 Self::set_total_issuance(
279 asset.clone(),
280 Self::total_issuance(asset.clone()).saturating_add(actual),
281 );
282 Self::done_mint_into(asset, who, amount);
283 Ok(actual)
284 }
285
286 fn burn_from(
290 asset: Self::AssetId,
291 who: &AccountId,
292 amount: Self::Balance,
293 preservation: Preservation,
294 precision: Precision,
295 force: Fortitude,
296 ) -> Result<Self::Balance, DispatchError> {
297 let actual = Self::reducible_balance(asset.clone(), who, preservation, force).min(amount);
298 ensure!(actual == amount || precision == BestEffort, TokenError::FundsUnavailable);
299 Self::total_issuance(asset.clone())
300 .checked_sub(&actual)
301 .ok_or(ArithmeticError::Overflow)?;
302 let actual =
303 Self::decrease_balance(asset.clone(), who, actual, BestEffort, preservation, force)?;
304 Self::set_total_issuance(
305 asset.clone(),
306 Self::total_issuance(asset.clone()).saturating_sub(actual),
307 );
308 Self::done_burn_from(asset, who, actual);
309 Ok(actual)
310 }
311
312 fn shelve(
323 asset: Self::AssetId,
324 who: &AccountId,
325 amount: Self::Balance,
326 ) -> Result<Self::Balance, DispatchError> {
327 let actual = Self::reducible_balance(asset.clone(), who, Expendable, Polite).min(amount);
328 ensure!(actual == amount, TokenError::FundsUnavailable);
329 Self::total_issuance(asset.clone())
330 .checked_sub(&actual)
331 .ok_or(ArithmeticError::Overflow)?;
332 let actual =
333 Self::decrease_balance(asset.clone(), who, actual, BestEffort, Expendable, Polite)?;
334 Self::set_total_issuance(
335 asset.clone(),
336 Self::total_issuance(asset.clone()).saturating_sub(actual),
337 );
338 Self::done_shelve(asset, who, actual);
339 Ok(actual)
340 }
341
342 fn restore(
353 asset: Self::AssetId,
354 who: &AccountId,
355 amount: Self::Balance,
356 ) -> Result<Self::Balance, DispatchError> {
357 Self::total_issuance(asset.clone())
358 .checked_add(&amount)
359 .ok_or(ArithmeticError::Overflow)?;
360 let actual = Self::increase_balance(asset.clone(), who, amount, Exact)?;
361 Self::set_total_issuance(
362 asset.clone(),
363 Self::total_issuance(asset.clone()).saturating_add(actual),
364 );
365 Self::done_restore(asset, who, amount);
366 Ok(actual)
367 }
368
369 fn transfer(
374 asset: Self::AssetId,
375 source: &AccountId,
376 dest: &AccountId,
377 amount: Self::Balance,
378 preservation: Preservation,
379 ) -> Result<Self::Balance, DispatchError> {
380 let _extra = Self::can_withdraw(asset.clone(), source, amount)
381 .into_result(preservation != Expendable)?;
382 Self::can_deposit(asset.clone(), dest, amount, Extant).into_result()?;
383 if source == dest {
384 return Ok(amount);
385 }
386
387 Self::decrease_balance(asset.clone(), source, amount, BestEffort, preservation, Polite)?;
388 let _ = Self::increase_balance(asset.clone(), dest, amount, BestEffort);
391 Self::done_transfer(asset, source, dest, amount);
392 Ok(amount)
393 }
394
395 fn set_balance(asset: Self::AssetId, who: &AccountId, amount: Self::Balance) -> Self::Balance {
401 let b = Self::balance(asset.clone(), who);
402 if b > amount {
403 Self::burn_from(asset, who, b - amount, Expendable, BestEffort, Force)
404 .map(|d| b.saturating_sub(d))
405 } else {
406 Self::mint_into(asset, who, amount - b).map(|d| b.saturating_add(d))
407 }
408 .unwrap_or(b)
409 }
410 fn done_mint_into(_asset: Self::AssetId, _who: &AccountId, _amount: Self::Balance) {}
411 fn done_burn_from(_asset: Self::AssetId, _who: &AccountId, _amount: Self::Balance) {}
412 fn done_shelve(_asset: Self::AssetId, _who: &AccountId, _amount: Self::Balance) {}
413 fn done_restore(_asset: Self::AssetId, _who: &AccountId, _amount: Self::Balance) {}
414 fn done_transfer(
415 _asset: Self::AssetId,
416 _source: &AccountId,
417 _dest: &AccountId,
418 _amount: Self::Balance,
419 ) {
420 }
421}
422
423pub struct IncreaseIssuance<AccountId, U>(PhantomData<(AccountId, U)>);
426impl<AccountId, U: Unbalanced<AccountId>> HandleImbalanceDrop<U::AssetId, U::Balance>
427 for IncreaseIssuance<AccountId, U>
428{
429 fn handle(asset: U::AssetId, amount: U::Balance) {
430 U::set_total_issuance(asset.clone(), U::total_issuance(asset).saturating_add(amount))
431 }
432}
433
434pub struct DecreaseIssuance<AccountId, U>(PhantomData<(AccountId, U)>);
437impl<AccountId, U: Unbalanced<AccountId>> HandleImbalanceDrop<U::AssetId, U::Balance>
438 for DecreaseIssuance<AccountId, U>
439{
440 fn handle(asset: U::AssetId, amount: U::Balance) {
441 U::set_total_issuance(asset.clone(), U::total_issuance(asset).saturating_sub(amount))
442 }
443}
444
445pub trait Balanced<AccountId>: Inspect<AccountId> + Unbalanced<AccountId> {
450 type OnDropDebt: HandleImbalanceDrop<Self::AssetId, Self::Balance>;
452 type OnDropCredit: HandleImbalanceDrop<Self::AssetId, Self::Balance>;
455
456 fn rescind(asset: Self::AssetId, amount: Self::Balance) -> Debt<AccountId, Self> {
462 let old = Self::total_issuance(asset.clone());
463 let new = old.saturating_sub(amount);
464 Self::set_total_issuance(asset.clone(), new);
465 let delta = old - new;
466 Self::done_rescind(asset.clone(), delta);
467 Imbalance::<Self::AssetId, Self::Balance, Self::OnDropDebt, Self::OnDropCredit>::new(
468 asset, delta,
469 )
470 }
471
472 fn issue(asset: Self::AssetId, amount: Self::Balance) -> Credit<AccountId, Self> {
479 let old = Self::total_issuance(asset.clone());
480 let new = old.saturating_add(amount);
481 Self::set_total_issuance(asset.clone(), new);
482 let delta = new - old;
483 Self::done_issue(asset.clone(), delta);
484 Imbalance::<Self::AssetId, Self::Balance, Self::OnDropCredit, Self::OnDropDebt>::new(
485 asset, delta,
486 )
487 }
488
489 fn pair(
498 asset: Self::AssetId,
499 amount: Self::Balance,
500 ) -> Result<(Debt<AccountId, Self>, Credit<AccountId, Self>), DispatchError> {
501 let issued = Self::issue(asset.clone(), amount);
502 let rescinded = Self::rescind(asset, amount);
503 if issued.peek() != rescinded.peek() || issued.peek() != amount {
506 Err("Failed to issue and rescind equal amounts".into())
508 } else {
509 Ok((rescinded, issued))
510 }
511 }
512
513 fn deposit(
523 asset: Self::AssetId,
524 who: &AccountId,
525 value: Self::Balance,
526 precision: Precision,
527 ) -> Result<Debt<AccountId, Self>, DispatchError> {
528 let increase = Self::increase_balance(asset.clone(), who, value, precision)?;
529 Self::done_deposit(asset.clone(), who, increase);
530 Ok(Imbalance::<Self::AssetId, Self::Balance, Self::OnDropDebt, Self::OnDropCredit>::new(
531 asset, increase,
532 ))
533 }
534
535 fn withdraw(
549 asset: Self::AssetId,
550 who: &AccountId,
551 value: Self::Balance,
552 precision: Precision,
553 preservation: Preservation,
554 force: Fortitude,
555 ) -> Result<Credit<AccountId, Self>, DispatchError> {
556 let decrease =
557 Self::decrease_balance(asset.clone(), who, value, precision, preservation, force)?;
558 Self::done_withdraw(asset.clone(), who, decrease);
559 Ok(Imbalance::<Self::AssetId, Self::Balance, Self::OnDropCredit, Self::OnDropDebt>::new(
560 asset, decrease,
561 ))
562 }
563
564 fn resolve(
571 who: &AccountId,
572 credit: Credit<AccountId, Self>,
573 ) -> Result<(), Credit<AccountId, Self>> {
574 let v = credit.peek();
575 let debt = match Self::deposit(credit.asset(), who, v, Exact) {
576 Err(_) => return Err(credit),
577 Ok(d) => d,
578 };
579 if let Ok(result) = credit.offset(debt) {
580 let result = result.try_drop();
581 debug_assert!(result.is_ok(), "ok deposit return must be equal to credit value; qed");
582 } else {
583 debug_assert!(false, "debt.asset is credit.asset; qed");
584 }
585 Ok(())
586 }
587
588 fn settle(
592 who: &AccountId,
593 debt: Debt<AccountId, Self>,
594 preservation: Preservation,
595 ) -> Result<Credit<AccountId, Self>, Debt<AccountId, Self>> {
596 let amount = debt.peek();
597 let asset = debt.asset();
598 let credit = match Self::withdraw(asset.clone(), who, amount, Exact, preservation, Polite) {
599 Err(_) => return Err(debt),
600 Ok(d) => d,
601 };
602 match credit.offset(debt) {
603 Ok(SameOrOther::None) => Ok(Credit::<AccountId, Self>::zero(asset)),
604 Ok(SameOrOther::Same(dust)) => Ok(dust),
605 Ok(SameOrOther::Other(rest)) => {
606 debug_assert!(false, "ok withdraw return must be at least debt value; qed");
607 Err(rest)
608 },
609 Err(_) => {
610 debug_assert!(false, "debt.asset is credit.asset; qed");
611 Ok(Credit::<AccountId, Self>::zero(asset))
612 },
613 }
614 }
615
616 fn done_rescind(_asset: Self::AssetId, _amount: Self::Balance) {}
617 fn done_issue(_asset: Self::AssetId, _amount: Self::Balance) {}
618 fn done_deposit(_asset: Self::AssetId, _who: &AccountId, _amount: Self::Balance) {}
619 fn done_withdraw(_asset: Self::AssetId, _who: &AccountId, _amount: Self::Balance) {}
620}
621
622#[cfg(feature = "std")]
624impl<AccountId> Inspect<AccountId> for () {
625 type AssetId = u32;
626 type Balance = u32;
627 fn total_issuance(_: Self::AssetId) -> Self::Balance {
628 0
629 }
630 fn minimum_balance(_: Self::AssetId) -> Self::Balance {
631 0
632 }
633 fn total_balance(_: Self::AssetId, _: &AccountId) -> Self::Balance {
634 0
635 }
636 fn balance(_: Self::AssetId, _: &AccountId) -> Self::Balance {
637 0
638 }
639 fn reducible_balance(
640 _: Self::AssetId,
641 _: &AccountId,
642 _: Preservation,
643 _: Fortitude,
644 ) -> Self::Balance {
645 0
646 }
647 fn can_deposit(
648 _: Self::AssetId,
649 _: &AccountId,
650 _: Self::Balance,
651 _: Provenance,
652 ) -> DepositConsequence {
653 DepositConsequence::Success
654 }
655 fn can_withdraw(
656 _: Self::AssetId,
657 _: &AccountId,
658 _: Self::Balance,
659 ) -> WithdrawConsequence<Self::Balance> {
660 WithdrawConsequence::Success
661 }
662 fn asset_exists(_: Self::AssetId) -> bool {
663 false
664 }
665}
666
667#[cfg(feature = "std")]
669impl<AccountId> Unbalanced<AccountId> for () {
670 fn handle_dust(_: Dust<AccountId, Self>) {}
671 fn write_balance(
672 _: Self::AssetId,
673 _: &AccountId,
674 _: Self::Balance,
675 ) -> Result<Option<Self::Balance>, DispatchError> {
676 Ok(None)
677 }
678 fn set_total_issuance(_: Self::AssetId, _: Self::Balance) {}
679}
680
681#[cfg(feature = "std")]
683impl<AccountId: Eq> Mutate<AccountId> for () {}