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
124#[must_use]
126pub struct Dust<A, T: Unbalanced<A>>(pub T::AssetId, pub T::Balance);
127
128impl<A, T: Balanced<A>> Dust<A, T> {
129 pub fn into_credit(self) -> Credit<A, T> {
131 Credit::<A, T>::new(self.0, self.1)
132 }
133}
134
135pub trait Unbalanced<AccountId>: Inspect<AccountId> {
144 fn handle_raw_dust(asset: Self::AssetId, amount: Self::Balance) {
150 Self::handle_dust(Dust(
151 asset.clone(),
152 amount.min(Self::minimum_balance(asset).saturating_sub(One::one())),
153 ))
154 }
155
156 fn handle_dust(dust: Dust<AccountId, Self>);
159
160 fn write_balance(
172 asset: Self::AssetId,
173 who: &AccountId,
174 amount: Self::Balance,
175 ) -> Result<Option<Self::Balance>, DispatchError>;
176
177 fn set_total_issuance(asset: Self::AssetId, amount: Self::Balance);
179
180 fn decrease_balance(
191 asset: Self::AssetId,
192 who: &AccountId,
193 mut amount: Self::Balance,
194 precision: Precision,
195 preservation: Preservation,
196 force: Fortitude,
197 ) -> Result<Self::Balance, DispatchError> {
198 let old_balance = Self::balance(asset.clone(), who);
199 let reducible = Self::reducible_balance(asset.clone(), who, preservation, force);
200 match precision {
201 BestEffort => amount = amount.min(reducible),
202 Exact => ensure!(reducible >= amount, TokenError::FundsUnavailable),
203 }
204 let new_balance = old_balance.checked_sub(&amount).ok_or(TokenError::FundsUnavailable)?;
205 if let Some(dust) = Self::write_balance(asset.clone(), who, new_balance)? {
206 Self::handle_dust(Dust(asset, dust));
207 }
208 Ok(old_balance.saturating_sub(new_balance))
209 }
210
211 fn increase_balance(
218 asset: Self::AssetId,
219 who: &AccountId,
220 amount: Self::Balance,
221 precision: Precision,
222 ) -> Result<Self::Balance, DispatchError> {
223 let old_balance = Self::balance(asset.clone(), who);
224 let new_balance = if let BestEffort = precision {
225 old_balance.saturating_add(amount)
226 } else {
227 old_balance.checked_add(&amount).ok_or(ArithmeticError::Overflow)?
228 };
229 if new_balance < Self::minimum_balance(asset.clone()) {
230 if let BestEffort = precision {
232 Ok(Self::Balance::default())
233 } else {
234 Err(TokenError::BelowMinimum.into())
235 }
236 } else {
237 if new_balance == old_balance {
238 Ok(Self::Balance::default())
239 } else {
240 if let Some(dust) = Self::write_balance(asset.clone(), who, new_balance)? {
241 Self::handle_dust(Dust(asset, dust));
242 }
243 Ok(new_balance.saturating_sub(old_balance))
244 }
245 }
246 }
247
248 fn deactivate(_asset: Self::AssetId, _: Self::Balance) {}
250
251 fn reactivate(_asset: Self::AssetId, _: Self::Balance) {}
253}
254
255pub trait Mutate<AccountId>: Inspect<AccountId> + Unbalanced<AccountId>
257where
258 AccountId: Eq,
259{
260 fn mint_into(
263 asset: Self::AssetId,
264 who: &AccountId,
265 amount: Self::Balance,
266 ) -> Result<Self::Balance, DispatchError> {
267 Self::total_issuance(asset.clone())
268 .checked_add(&amount)
269 .ok_or(ArithmeticError::Overflow)?;
270 let actual = Self::increase_balance(asset.clone(), who, amount, Exact)?;
271 Self::set_total_issuance(
272 asset.clone(),
273 Self::total_issuance(asset.clone()).saturating_add(actual),
274 );
275 Self::done_mint_into(asset, who, amount);
276 Ok(actual)
277 }
278
279 fn burn_from(
283 asset: Self::AssetId,
284 who: &AccountId,
285 amount: Self::Balance,
286 preservation: Preservation,
287 precision: Precision,
288 force: Fortitude,
289 ) -> Result<Self::Balance, DispatchError> {
290 let actual = Self::reducible_balance(asset.clone(), who, preservation, force).min(amount);
291 ensure!(actual == amount || precision == BestEffort, TokenError::FundsUnavailable);
292 Self::total_issuance(asset.clone())
293 .checked_sub(&actual)
294 .ok_or(ArithmeticError::Overflow)?;
295 let actual =
296 Self::decrease_balance(asset.clone(), who, actual, BestEffort, preservation, force)?;
297 Self::set_total_issuance(
298 asset.clone(),
299 Self::total_issuance(asset.clone()).saturating_sub(actual),
300 );
301 Self::done_burn_from(asset, who, actual);
302 Ok(actual)
303 }
304
305 fn shelve(
316 asset: Self::AssetId,
317 who: &AccountId,
318 amount: Self::Balance,
319 ) -> Result<Self::Balance, DispatchError> {
320 let actual = Self::reducible_balance(asset.clone(), who, Expendable, Polite).min(amount);
321 ensure!(actual == amount, TokenError::FundsUnavailable);
322 Self::total_issuance(asset.clone())
323 .checked_sub(&actual)
324 .ok_or(ArithmeticError::Overflow)?;
325 let actual =
326 Self::decrease_balance(asset.clone(), who, actual, BestEffort, Expendable, Polite)?;
327 Self::set_total_issuance(
328 asset.clone(),
329 Self::total_issuance(asset.clone()).saturating_sub(actual),
330 );
331 Self::done_shelve(asset, who, actual);
332 Ok(actual)
333 }
334
335 fn restore(
346 asset: Self::AssetId,
347 who: &AccountId,
348 amount: Self::Balance,
349 ) -> Result<Self::Balance, DispatchError> {
350 Self::total_issuance(asset.clone())
351 .checked_add(&amount)
352 .ok_or(ArithmeticError::Overflow)?;
353 let actual = Self::increase_balance(asset.clone(), who, amount, Exact)?;
354 Self::set_total_issuance(
355 asset.clone(),
356 Self::total_issuance(asset.clone()).saturating_add(actual),
357 );
358 Self::done_restore(asset, who, amount);
359 Ok(actual)
360 }
361
362 fn transfer(
367 asset: Self::AssetId,
368 source: &AccountId,
369 dest: &AccountId,
370 amount: Self::Balance,
371 preservation: Preservation,
372 ) -> Result<Self::Balance, DispatchError> {
373 let _extra = Self::can_withdraw(asset.clone(), source, amount)
374 .into_result(preservation != Expendable)?;
375 Self::can_deposit(asset.clone(), dest, amount, Extant).into_result()?;
376 if source == dest {
377 return Ok(amount)
378 }
379
380 Self::decrease_balance(asset.clone(), source, amount, BestEffort, preservation, Polite)?;
381 let _ = Self::increase_balance(asset.clone(), dest, amount, BestEffort);
384 Self::done_transfer(asset, source, dest, amount);
385 Ok(amount)
386 }
387
388 fn set_balance(asset: Self::AssetId, who: &AccountId, amount: Self::Balance) -> Self::Balance {
394 let b = Self::balance(asset.clone(), who);
395 if b > amount {
396 Self::burn_from(asset, who, b - amount, Expendable, BestEffort, Force)
397 .map(|d| b.saturating_sub(d))
398 } else {
399 Self::mint_into(asset, who, amount - b).map(|d| b.saturating_add(d))
400 }
401 .unwrap_or(b)
402 }
403 fn done_mint_into(_asset: Self::AssetId, _who: &AccountId, _amount: Self::Balance) {}
404 fn done_burn_from(_asset: Self::AssetId, _who: &AccountId, _amount: Self::Balance) {}
405 fn done_shelve(_asset: Self::AssetId, _who: &AccountId, _amount: Self::Balance) {}
406 fn done_restore(_asset: Self::AssetId, _who: &AccountId, _amount: Self::Balance) {}
407 fn done_transfer(
408 _asset: Self::AssetId,
409 _source: &AccountId,
410 _dest: &AccountId,
411 _amount: Self::Balance,
412 ) {
413 }
414}
415
416pub struct IncreaseIssuance<AccountId, U>(PhantomData<(AccountId, U)>);
419impl<AccountId, U: Unbalanced<AccountId>> HandleImbalanceDrop<U::AssetId, U::Balance>
420 for IncreaseIssuance<AccountId, U>
421{
422 fn handle(asset: U::AssetId, amount: U::Balance) {
423 U::set_total_issuance(asset.clone(), U::total_issuance(asset).saturating_add(amount))
424 }
425}
426
427pub struct DecreaseIssuance<AccountId, U>(PhantomData<(AccountId, U)>);
430impl<AccountId, U: Unbalanced<AccountId>> HandleImbalanceDrop<U::AssetId, U::Balance>
431 for DecreaseIssuance<AccountId, U>
432{
433 fn handle(asset: U::AssetId, amount: U::Balance) {
434 U::set_total_issuance(asset.clone(), U::total_issuance(asset).saturating_sub(amount))
435 }
436}
437
438pub trait Balanced<AccountId>: Inspect<AccountId> + Unbalanced<AccountId> {
443 type OnDropDebt: HandleImbalanceDrop<Self::AssetId, Self::Balance>;
445 type OnDropCredit: HandleImbalanceDrop<Self::AssetId, Self::Balance>;
448
449 fn rescind(asset: Self::AssetId, amount: Self::Balance) -> Debt<AccountId, Self> {
455 let old = Self::total_issuance(asset.clone());
456 let new = old.saturating_sub(amount);
457 Self::set_total_issuance(asset.clone(), new);
458 let delta = old - new;
459 Self::done_rescind(asset.clone(), delta);
460 Imbalance::<Self::AssetId, Self::Balance, Self::OnDropDebt, Self::OnDropCredit>::new(
461 asset, delta,
462 )
463 }
464
465 fn issue(asset: Self::AssetId, amount: Self::Balance) -> Credit<AccountId, Self> {
472 let old = Self::total_issuance(asset.clone());
473 let new = old.saturating_add(amount);
474 Self::set_total_issuance(asset.clone(), new);
475 let delta = new - old;
476 Self::done_issue(asset.clone(), delta);
477 Imbalance::<Self::AssetId, Self::Balance, Self::OnDropCredit, Self::OnDropDebt>::new(
478 asset, delta,
479 )
480 }
481
482 fn pair(
491 asset: Self::AssetId,
492 amount: Self::Balance,
493 ) -> Result<(Debt<AccountId, Self>, Credit<AccountId, Self>), DispatchError> {
494 let issued = Self::issue(asset.clone(), amount);
495 let rescinded = Self::rescind(asset, amount);
496 if issued.peek() != rescinded.peek() || issued.peek() != amount {
499 Err("Failed to issue and rescind equal amounts".into())
501 } else {
502 Ok((rescinded, issued))
503 }
504 }
505
506 fn deposit(
516 asset: Self::AssetId,
517 who: &AccountId,
518 value: Self::Balance,
519 precision: Precision,
520 ) -> Result<Debt<AccountId, Self>, DispatchError> {
521 let increase = Self::increase_balance(asset.clone(), who, value, precision)?;
522 Self::done_deposit(asset.clone(), who, increase);
523 Ok(Imbalance::<Self::AssetId, Self::Balance, Self::OnDropDebt, Self::OnDropCredit>::new(
524 asset, increase,
525 ))
526 }
527
528 fn withdraw(
542 asset: Self::AssetId,
543 who: &AccountId,
544 value: Self::Balance,
545 precision: Precision,
546 preservation: Preservation,
547 force: Fortitude,
548 ) -> Result<Credit<AccountId, Self>, DispatchError> {
549 let decrease =
550 Self::decrease_balance(asset.clone(), who, value, precision, preservation, force)?;
551 Self::done_withdraw(asset.clone(), who, decrease);
552 Ok(Imbalance::<Self::AssetId, Self::Balance, Self::OnDropCredit, Self::OnDropDebt>::new(
553 asset, decrease,
554 ))
555 }
556
557 fn resolve(
564 who: &AccountId,
565 credit: Credit<AccountId, Self>,
566 ) -> Result<(), Credit<AccountId, Self>> {
567 let v = credit.peek();
568 let debt = match Self::deposit(credit.asset(), who, v, Exact) {
569 Err(_) => return Err(credit),
570 Ok(d) => d,
571 };
572 if let Ok(result) = credit.offset(debt) {
573 let result = result.try_drop();
574 debug_assert!(result.is_ok(), "ok deposit return must be equal to credit value; qed");
575 } else {
576 debug_assert!(false, "debt.asset is credit.asset; qed");
577 }
578 Ok(())
579 }
580
581 fn settle(
585 who: &AccountId,
586 debt: Debt<AccountId, Self>,
587 preservation: Preservation,
588 ) -> Result<Credit<AccountId, Self>, Debt<AccountId, Self>> {
589 let amount = debt.peek();
590 let asset = debt.asset();
591 let credit = match Self::withdraw(asset.clone(), who, amount, Exact, preservation, Polite) {
592 Err(_) => return Err(debt),
593 Ok(d) => d,
594 };
595 match credit.offset(debt) {
596 Ok(SameOrOther::None) => Ok(Credit::<AccountId, Self>::zero(asset)),
597 Ok(SameOrOther::Same(dust)) => Ok(dust),
598 Ok(SameOrOther::Other(rest)) => {
599 debug_assert!(false, "ok withdraw return must be at least debt value; qed");
600 Err(rest)
601 },
602 Err(_) => {
603 debug_assert!(false, "debt.asset is credit.asset; qed");
604 Ok(Credit::<AccountId, Self>::zero(asset))
605 },
606 }
607 }
608
609 fn done_rescind(_asset: Self::AssetId, _amount: Self::Balance) {}
610 fn done_issue(_asset: Self::AssetId, _amount: Self::Balance) {}
611 fn done_deposit(_asset: Self::AssetId, _who: &AccountId, _amount: Self::Balance) {}
612 fn done_withdraw(_asset: Self::AssetId, _who: &AccountId, _amount: Self::Balance) {}
613}
614
615#[cfg(feature = "std")]
617impl<AccountId> Inspect<AccountId> for () {
618 type AssetId = u32;
619 type Balance = u32;
620 fn total_issuance(_: Self::AssetId) -> Self::Balance {
621 0
622 }
623 fn minimum_balance(_: Self::AssetId) -> Self::Balance {
624 0
625 }
626 fn total_balance(_: Self::AssetId, _: &AccountId) -> Self::Balance {
627 0
628 }
629 fn balance(_: Self::AssetId, _: &AccountId) -> Self::Balance {
630 0
631 }
632 fn reducible_balance(
633 _: Self::AssetId,
634 _: &AccountId,
635 _: Preservation,
636 _: Fortitude,
637 ) -> Self::Balance {
638 0
639 }
640 fn can_deposit(
641 _: Self::AssetId,
642 _: &AccountId,
643 _: Self::Balance,
644 _: Provenance,
645 ) -> DepositConsequence {
646 DepositConsequence::Success
647 }
648 fn can_withdraw(
649 _: Self::AssetId,
650 _: &AccountId,
651 _: Self::Balance,
652 ) -> WithdrawConsequence<Self::Balance> {
653 WithdrawConsequence::Success
654 }
655 fn asset_exists(_: Self::AssetId) -> bool {
656 false
657 }
658}
659
660#[cfg(feature = "std")]
662impl<AccountId> Unbalanced<AccountId> for () {
663 fn handle_dust(_: Dust<AccountId, Self>) {}
664 fn write_balance(
665 _: Self::AssetId,
666 _: &AccountId,
667 _: Self::Balance,
668 ) -> Result<Option<Self::Balance>, DispatchError> {
669 Ok(None)
670 }
671 fn set_total_issuance(_: Self::AssetId, _: Self::Balance) {}
672}
673
674#[cfg(feature = "std")]
676impl<AccountId: Eq> Mutate<AccountId> for () {}