From 04a43780693e46c9fe1cda95787ea1f719bf80f2 Mon Sep 17 00:00:00 2001
From: Dmitry Lavrenov <lawrenowdima@gmail.com>
Date: Fri, 29 Dec 2023 12:56:23 +0300
Subject: [PATCH] Draft addition of fungible related traits for currency type
 at pallet-pot

---
 crates/pallet-pot/src/lib.rs | 55 ++++++++++++++++++++++++++----------
 1 file changed, 40 insertions(+), 15 deletions(-)

diff --git a/crates/pallet-pot/src/lib.rs b/crates/pallet-pot/src/lib.rs
index a822c1fc1..ac09983ba 100644
--- a/crates/pallet-pot/src/lib.rs
+++ b/crates/pallet-pot/src/lib.rs
@@ -5,7 +5,10 @@
 
 #![cfg_attr(not(feature = "std"), no_std)]
 
-use frame_support::traits::{Imbalance, OnUnbalanced, StorageVersion};
+use frame_support::traits::{
+    fungible::{Balanced, Credit, Inspect, Mutate, Unbalanced},
+    Imbalance, OnUnbalanced, StorageVersion,
+};
 use frame_support::{pallet_prelude::*, traits::Currency, PalletId};
 use frame_system::pallet_prelude::*;
 use sp_runtime::traits::{AccountIdConversion, CheckedSub, MaybeDisplay, Saturating};
@@ -17,11 +20,14 @@ const STORAGE_VERSION: StorageVersion = StorageVersion::new(0);
 
 /// The balance of accessor for the currency.
 pub type BalanceOf<T, I = ()> =
-    <<T as Config<I>>::Currency as Currency<<T as Config<I>>::AccountId>>::Balance;
+    <<T as Config<I>>::FungibleAsset as Currency<<T as Config<I>>::AccountId>>::Balance;
 
 /// The negative implanace accessor.
 pub type NegativeImbalanceOf<T, I = ()> =
-    <<T as Config<I>>::Currency as Currency<<T as Config<I>>::AccountId>>::NegativeImbalance;
+    <<T as Config<I>>::FungibleAsset as Currency<<T as Config<I>>::AccountId>>::NegativeImbalance;
+
+/// The credit accessor.
+pub type CreditOf<T, I = ()> = Credit<<T as Config<I>>::AccountId, <T as Config<I>>::FungibleAsset>;
 
 /// The initial state of the pot, for use in genesis.
 #[cfg(feature = "std")]
@@ -63,8 +69,12 @@ pub mod pallet {
             + Ord
             + MaxEncodedLen;
 
-        /// The currency to operate with.
-        type Currency: Currency<<Self as Config<I>>::AccountId>;
+        /// The fungible asset to operate with.
+        type FungibleAsset: Currency<<Self as Config<I>>::AccountId>
+            + Inspect<<Self as Config<I>>::AccountId, Balance = BalanceOf<Self, I>>
+            + Balanced<<Self as Config<I>>::AccountId, Balance = BalanceOf<Self, I>>
+            + Unbalanced<<Self as Config<I>>::AccountId, Balance = BalanceOf<Self, I>>
+            + Mutate<<Self as Config<I>>::AccountId, Balance = BalanceOf<Self, I>>;
 
         /// The pot's pallet id, used for deriving its sovereign account ID.
         #[pallet::constant]
@@ -127,20 +137,20 @@ pub mod pallet {
                     // Just pass though.
                 }
                 InitialState::Initialized => {
-                    let current = T::Currency::free_balance(&account_id);
-                    let min = T::Currency::minimum_balance();
+                    let current = T::FungibleAsset::balance(&account_id);
+                    let min = <T::FungibleAsset as Inspect<_>>::minimum_balance();
                     assert!(
                         current >= min,
                         "the initial pot balance must be greater or equal than the existential balance"
                     );
                 }
                 InitialState::Balance { balance } => {
-                    let min = T::Currency::minimum_balance();
+                    let min = <T::FungibleAsset as Inspect<_>>::minimum_balance();
                     assert!(
                         balance >= min,
                         "the configured initial pot balance must be greater or equal than the existential balance"
                     );
-                    let _ = T::Currency::make_free_balance_be(&account_id, balance);
+                    let _ = T::FungibleAsset::set_balance(&account_id, balance);
                 }
             }
         }
@@ -159,9 +169,9 @@ impl<T: Config<I>, I: 'static> Pallet<T, I> {
     // The existential deposit (`minimum_balance`) is not part of
     // the pot so the pot account never gets killed.
     pub fn balance() -> BalanceOf<T, I> {
-        T::Currency::free_balance(&Self::account_id())
+        T::FungibleAsset::balance(&Self::account_id())
             // Must never be less than 0 but better be safe.
-            .saturating_sub(T::Currency::minimum_balance())
+            .saturating_sub(<T::FungibleAsset as Inspect<_>>::minimum_balance())
     }
 
     /// Update the inactive supply for this pot.
@@ -169,17 +179,17 @@ impl<T: Config<I>, I: 'static> Pallet<T, I> {
     /// This function uses the whole balance of the account, unlike [`Self::balance`],
     /// which subtracts the existential balance.
     fn update_inactive() -> Weight {
-        let balance = T::Currency::free_balance(&Self::account_id());
+        let balance = T::FungibleAsset::balance(&Self::account_id());
         let current = Inactive::<T, I>::get();
 
         let mut weight = T::DbWeight::get().reads(2);
 
         if balance != current {
             if let Some(delta) = balance.checked_sub(&current) {
-                T::Currency::deactivate(delta)
+                <T::FungibleAsset as Unbalanced<_>>::deactivate(delta)
             }
             if let Some(delta) = current.checked_sub(&balance) {
-                T::Currency::reactivate(delta)
+                <T::FungibleAsset as Unbalanced<_>>::reactivate(delta)
             }
             Inactive::<T, I>::put(balance);
 
@@ -195,10 +205,25 @@ impl<T: Config<I>, I: 'static> OnUnbalanced<NegativeImbalanceOf<T, I>> for Palle
         let numeric_amount = amount.peek();
 
         // Must resolve into existing but better to be safe.
-        T::Currency::resolve_creating(&Self::account_id(), amount);
+        T::FungibleAsset::resolve_creating(&Self::account_id(), amount);
 
         Self::deposit_event(Event::Deposit {
             value: numeric_amount,
         });
     }
 }
+
+pub struct OnUnbalancedOverCredit<T, I>(Pallet<T, I>);
+
+impl<T: Config<I>, I: 'static> OnUnbalanced<CreditOf<T, I>> for OnUnbalancedOverCredit<T, I> {
+    fn on_nonzero_unbalanced(amount: CreditOf<T, I>) {
+        let numeric_amount = amount.peek();
+
+        T::FungibleAsset::resolve(&Pallet::<T, I>::account_id(), amount);
+        T::FungibleAsset::done_deposit(&Pallet::<T, I>::account_id(), numeric_amount);
+
+        Pallet::<T, I>::deposit_event(Event::Deposit {
+            value: numeric_amount,
+        });
+    }
+}