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, Zero};
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(
203 asset: Self::AssetId,
204 who: &AccountId,
205 mut amount: Self::Balance,
206 precision: Precision,
207 preservation: Preservation,
208 force: Fortitude,
209 ) -> Result<Self::Balance, DispatchError> {
210 let old_balance = Self::balance(asset.clone(), who);
211 let reducible = Self::reducible_balance(asset.clone(), who, preservation, force);
212 match precision {
213 BestEffort => amount = amount.min(reducible),
214 Exact => ensure!(reducible >= amount, TokenError::FundsUnavailable),
215 }
216 let new_balance = old_balance.checked_sub(&amount).ok_or(TokenError::FundsUnavailable)?;
217 if let Some(dust) = Self::write_balance(asset.clone(), who, new_balance)? {
218 Self::handle_dust(Dust(asset, dust));
219 }
220 Ok(old_balance.saturating_sub(new_balance))
221 }
222
223 fn increase_balance(
230 asset: Self::AssetId,
231 who: &AccountId,
232 amount: Self::Balance,
233 precision: Precision,
234 ) -> Result<Self::Balance, DispatchError> {
235 let old_balance = Self::balance(asset.clone(), who);
236 let new_balance = if let BestEffort = precision {
237 old_balance.saturating_add(amount)
238 } else {
239 old_balance.checked_add(&amount).ok_or(ArithmeticError::Overflow)?
240 };
241 if new_balance < Self::minimum_balance(asset.clone()) {
242 if let BestEffort = precision {
244 Ok(Self::Balance::default())
245 } else {
246 Err(TokenError::BelowMinimum.into())
247 }
248 } else {
249 if new_balance == old_balance {
250 Ok(Self::Balance::default())
251 } else {
252 if let Some(dust) = Self::write_balance(asset.clone(), who, new_balance)? {
253 Self::handle_dust(Dust(asset, dust));
254 }
255 Ok(new_balance.saturating_sub(old_balance))
256 }
257 }
258 }
259
260 fn deactivate(_asset: Self::AssetId, _: Self::Balance) {}
262
263 fn reactivate(_asset: Self::AssetId, _: Self::Balance) {}
265}
266
267pub trait Mutate<AccountId>: Inspect<AccountId> + Unbalanced<AccountId>
269where
270 AccountId: Eq,
271{
272 fn mint_into(
275 asset: Self::AssetId,
276 who: &AccountId,
277 amount: Self::Balance,
278 ) -> Result<Self::Balance, DispatchError> {
279 Self::total_issuance(asset.clone())
280 .checked_add(&amount)
281 .ok_or(ArithmeticError::Overflow)?;
282 let actual = Self::increase_balance(asset.clone(), who, amount, Exact)?;
283 Self::set_total_issuance(
284 asset.clone(),
285 Self::total_issuance(asset.clone()).saturating_add(actual),
286 );
287 Self::done_mint_into(asset, who, amount);
288 Ok(actual)
289 }
290
291 fn burn_from(
295 asset: Self::AssetId,
296 who: &AccountId,
297 amount: Self::Balance,
298 preservation: Preservation,
299 precision: Precision,
300 force: Fortitude,
301 ) -> Result<Self::Balance, DispatchError> {
302 let actual = Self::reducible_balance(asset.clone(), who, preservation, force).min(amount);
303 ensure!(actual == amount || precision == BestEffort, TokenError::FundsUnavailable);
304 Self::total_issuance(asset.clone())
305 .checked_sub(&actual)
306 .ok_or(ArithmeticError::Overflow)?;
307 let actual =
308 Self::decrease_balance(asset.clone(), who, actual, BestEffort, preservation, force)?;
309 Self::set_total_issuance(
310 asset.clone(),
311 Self::total_issuance(asset.clone()).saturating_sub(actual),
312 );
313 Self::done_burn_from(asset, who, actual);
314 Ok(actual)
315 }
316
317 fn shelve(
328 asset: Self::AssetId,
329 who: &AccountId,
330 amount: Self::Balance,
331 ) -> Result<Self::Balance, DispatchError> {
332 let actual = Self::reducible_balance(asset.clone(), who, Expendable, Polite).min(amount);
333 ensure!(actual == amount, TokenError::FundsUnavailable);
334 Self::total_issuance(asset.clone())
335 .checked_sub(&actual)
336 .ok_or(ArithmeticError::Overflow)?;
337 let actual =
338 Self::decrease_balance(asset.clone(), who, actual, BestEffort, Expendable, Polite)?;
339 Self::set_total_issuance(
340 asset.clone(),
341 Self::total_issuance(asset.clone()).saturating_sub(actual),
342 );
343 Self::done_shelve(asset, who, actual);
344 Ok(actual)
345 }
346
347 fn restore(
358 asset: Self::AssetId,
359 who: &AccountId,
360 amount: Self::Balance,
361 ) -> Result<Self::Balance, DispatchError> {
362 Self::total_issuance(asset.clone())
363 .checked_add(&amount)
364 .ok_or(ArithmeticError::Overflow)?;
365 let actual = Self::increase_balance(asset.clone(), who, amount, Exact)?;
366 Self::set_total_issuance(
367 asset.clone(),
368 Self::total_issuance(asset.clone()).saturating_add(actual),
369 );
370 Self::done_restore(asset, who, amount);
371 Ok(actual)
372 }
373
374 fn transfer(
388 asset: Self::AssetId,
389 source: &AccountId,
390 dest: &AccountId,
391 amount: Self::Balance,
392 preservation: Preservation,
393 ) -> Result<Self::Balance, DispatchError> {
394 let _extra = Self::can_withdraw(asset.clone(), source, amount)
395 .into_result(preservation != Expendable)?;
396 Self::can_deposit(asset.clone(), dest, amount, Extant).into_result()?;
397 if source == dest || amount.is_zero() {
398 return Ok(amount);
399 }
400
401 let actual =
402 Self::decrease_balance(asset.clone(), source, amount, Exact, preservation, Polite)?;
403 Self::increase_balance(asset.clone(), dest, actual, Exact)?;
404 Self::done_transfer(asset, source, dest, actual);
405 Ok(actual)
406 }
407
408 fn set_balance(asset: Self::AssetId, who: &AccountId, amount: Self::Balance) -> Self::Balance {
414 let b = Self::balance(asset.clone(), who);
415 if b > amount {
416 Self::burn_from(asset, who, b - amount, Expendable, BestEffort, Force)
417 .map(|d| b.saturating_sub(d))
418 } else {
419 Self::mint_into(asset, who, amount - b).map(|d| b.saturating_add(d))
420 }
421 .unwrap_or(b)
422 }
423 fn done_mint_into(_asset: Self::AssetId, _who: &AccountId, _amount: Self::Balance) {}
424 fn done_burn_from(_asset: Self::AssetId, _who: &AccountId, _amount: Self::Balance) {}
425 fn done_shelve(_asset: Self::AssetId, _who: &AccountId, _amount: Self::Balance) {}
426 fn done_restore(_asset: Self::AssetId, _who: &AccountId, _amount: Self::Balance) {}
427 fn done_transfer(
428 _asset: Self::AssetId,
429 _source: &AccountId,
430 _dest: &AccountId,
431 _amount: Self::Balance,
432 ) {
433 }
434}
435
436pub struct IncreaseIssuance<AccountId, U>(PhantomData<(AccountId, U)>);
439impl<AccountId, U: Unbalanced<AccountId>> HandleImbalanceDrop<U::AssetId, U::Balance>
440 for IncreaseIssuance<AccountId, U>
441{
442 fn handle(asset: U::AssetId, amount: U::Balance) {
443 U::set_total_issuance(asset.clone(), U::total_issuance(asset).saturating_add(amount))
444 }
445}
446
447pub struct DecreaseIssuance<AccountId, U>(PhantomData<(AccountId, U)>);
450impl<AccountId, U: Unbalanced<AccountId>> HandleImbalanceDrop<U::AssetId, U::Balance>
451 for DecreaseIssuance<AccountId, U>
452{
453 fn handle(asset: U::AssetId, amount: U::Balance) {
454 U::set_total_issuance(asset.clone(), U::total_issuance(asset).saturating_sub(amount))
455 }
456}
457
458pub trait Balanced<AccountId>: Inspect<AccountId> + Unbalanced<AccountId> {
463 type OnDropDebt: HandleImbalanceDrop<Self::AssetId, Self::Balance>;
465 type OnDropCredit: HandleImbalanceDrop<Self::AssetId, Self::Balance>;
468
469 fn rescind(asset: Self::AssetId, amount: Self::Balance) -> Debt<AccountId, Self> {
475 let old = Self::total_issuance(asset.clone());
476 let new = old.saturating_sub(amount);
477 Self::set_total_issuance(asset.clone(), new);
478 let delta = old - new;
479 Self::done_rescind(asset.clone(), delta);
480 Imbalance::<Self::AssetId, Self::Balance, Self::OnDropDebt, Self::OnDropCredit>::new(
481 asset, delta,
482 )
483 }
484
485 fn issue(asset: Self::AssetId, amount: Self::Balance) -> Credit<AccountId, Self> {
492 let old = Self::total_issuance(asset.clone());
493 let new = old.saturating_add(amount);
494 Self::set_total_issuance(asset.clone(), new);
495 let delta = new - old;
496 Self::done_issue(asset.clone(), delta);
497 Imbalance::<Self::AssetId, Self::Balance, Self::OnDropCredit, Self::OnDropDebt>::new(
498 asset, delta,
499 )
500 }
501
502 fn pair(
511 asset: Self::AssetId,
512 amount: Self::Balance,
513 ) -> Result<(Debt<AccountId, Self>, Credit<AccountId, Self>), DispatchError> {
514 let issued = Self::issue(asset.clone(), amount);
515 let rescinded = Self::rescind(asset, amount);
516 if issued.peek() != rescinded.peek() || issued.peek() != amount {
519 Err("Failed to issue and rescind equal amounts".into())
521 } else {
522 Ok((rescinded, issued))
523 }
524 }
525
526 fn deposit(
536 asset: Self::AssetId,
537 who: &AccountId,
538 value: Self::Balance,
539 precision: Precision,
540 ) -> Result<Debt<AccountId, Self>, DispatchError> {
541 let increase = Self::increase_balance(asset.clone(), who, value, precision)?;
542 Self::done_deposit(asset.clone(), who, increase);
543 Ok(Imbalance::<Self::AssetId, Self::Balance, Self::OnDropDebt, Self::OnDropCredit>::new(
544 asset, increase,
545 ))
546 }
547
548 fn withdraw(
562 asset: Self::AssetId,
563 who: &AccountId,
564 value: Self::Balance,
565 precision: Precision,
566 preservation: Preservation,
567 force: Fortitude,
568 ) -> Result<Credit<AccountId, Self>, DispatchError> {
569 let decrease =
570 Self::decrease_balance(asset.clone(), who, value, precision, preservation, force)?;
571 Self::done_withdraw(asset.clone(), who, decrease);
572 Ok(Imbalance::<Self::AssetId, Self::Balance, Self::OnDropCredit, Self::OnDropDebt>::new(
573 asset, decrease,
574 ))
575 }
576
577 fn resolve(
584 who: &AccountId,
585 credit: Credit<AccountId, Self>,
586 ) -> Result<(), Credit<AccountId, Self>> {
587 let v = credit.peek();
588 let debt = match Self::deposit(credit.asset(), who, v, Exact) {
589 Err(_) => return Err(credit),
590 Ok(d) => d,
591 };
592 if let Ok(result) = credit.offset(debt) {
593 let result = result.try_drop();
594 debug_assert!(result.is_ok(), "ok deposit return must be equal to credit value; qed");
595 } else {
596 debug_assert!(false, "debt.asset is credit.asset; qed");
597 }
598 Ok(())
599 }
600
601 fn settle(
605 who: &AccountId,
606 debt: Debt<AccountId, Self>,
607 preservation: Preservation,
608 ) -> Result<Credit<AccountId, Self>, Debt<AccountId, Self>> {
609 let amount = debt.peek();
610 let asset = debt.asset();
611 let credit = match Self::withdraw(asset.clone(), who, amount, Exact, preservation, Polite) {
612 Err(_) => return Err(debt),
613 Ok(d) => d,
614 };
615 match credit.offset(debt) {
616 Ok(SameOrOther::None) => Ok(Credit::<AccountId, Self>::zero(asset)),
617 Ok(SameOrOther::Same(dust)) => Ok(dust),
618 Ok(SameOrOther::Other(rest)) => {
619 debug_assert!(false, "ok withdraw return must be at least debt value; qed");
620 Err(rest)
621 },
622 Err(_) => {
623 debug_assert!(false, "debt.asset is credit.asset; qed");
624 Ok(Credit::<AccountId, Self>::zero(asset))
625 },
626 }
627 }
628
629 fn done_rescind(_asset: Self::AssetId, _amount: Self::Balance) {}
630 fn done_issue(_asset: Self::AssetId, _amount: Self::Balance) {}
631 fn done_deposit(_asset: Self::AssetId, _who: &AccountId, _amount: Self::Balance) {}
632 fn done_withdraw(_asset: Self::AssetId, _who: &AccountId, _amount: Self::Balance) {}
633}
634
635#[cfg(feature = "std")]
637impl<AccountId> Inspect<AccountId> for () {
638 type AssetId = u32;
639 type Balance = u32;
640 fn total_issuance(_: Self::AssetId) -> Self::Balance {
641 0
642 }
643 fn minimum_balance(_: Self::AssetId) -> Self::Balance {
644 0
645 }
646 fn total_balance(_: Self::AssetId, _: &AccountId) -> Self::Balance {
647 0
648 }
649 fn balance(_: Self::AssetId, _: &AccountId) -> Self::Balance {
650 0
651 }
652 fn reducible_balance(
653 _: Self::AssetId,
654 _: &AccountId,
655 _: Preservation,
656 _: Fortitude,
657 ) -> Self::Balance {
658 0
659 }
660 fn can_deposit(
661 _: Self::AssetId,
662 _: &AccountId,
663 _: Self::Balance,
664 _: Provenance,
665 ) -> DepositConsequence {
666 DepositConsequence::Success
667 }
668 fn can_withdraw(
669 _: Self::AssetId,
670 _: &AccountId,
671 _: Self::Balance,
672 ) -> WithdrawConsequence<Self::Balance> {
673 WithdrawConsequence::Success
674 }
675 fn asset_exists(_: Self::AssetId) -> bool {
676 false
677 }
678}
679
680#[cfg(feature = "std")]
682impl<AccountId> Unbalanced<AccountId> for () {
683 fn handle_dust(_: Dust<AccountId, Self>) {}
684 fn write_balance(
685 _: Self::AssetId,
686 _: &AccountId,
687 _: Self::Balance,
688 ) -> Result<Option<Self::Balance>, DispatchError> {
689 Ok(None)
690 }
691 fn set_total_issuance(_: Self::AssetId, _: Self::Balance) {}
692}
693
694#[cfg(feature = "std")]
696impl<AccountId: Eq> Mutate<AccountId> for () {}