From db241e71e5b3ed75b43eb531d2ab00dd710a2c5a Mon Sep 17 00:00:00 2001
From: bgallois <benjamin@gallois.cc>
Date: Wed, 5 Feb 2025 11:43:42 +0100
Subject: [PATCH 1/3] revoke identity unlink account

---
 Cargo.lock                                    |  1 +
 pallets/duniter-account/Cargo.toml            |  3 +++
 pallets/duniter-account/src/benchmarking.rs   | 10 +++++++++
 pallets/duniter-account/src/lib.rs            | 19 ++++++++++++++++
 pallets/duniter-account/src/weights.rs        | 11 ++++++++++
 runtime/common/src/handlers.rs                | 18 ++++++++-------
 .../g1/src/weights/pallet_duniter_account.rs  | 22 +++++++++++++++----
 .../src/weights/pallet_duniter_account.rs     | 22 +++++++++++++++----
 runtime/gdev/tests/integration_tests.rs       | 17 ++++++++++++++
 .../src/weights/pallet_duniter_account.rs     | 22 +++++++++++++++----
 10 files changed, 125 insertions(+), 20 deletions(-)

diff --git a/Cargo.lock b/Cargo.lock
index be8a37afd..d420f9d4f 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -8878,6 +8878,7 @@ dependencies = [
 name = "pallet-duniter-account"
 version = "1.0.0"
 dependencies = [
+ "duniter-primitives",
  "frame-benchmarking",
  "frame-support",
  "frame-system",
diff --git a/pallets/duniter-account/Cargo.toml b/pallets/duniter-account/Cargo.toml
index ed9a58d17..f8b374914 100644
--- a/pallets/duniter-account/Cargo.toml
+++ b/pallets/duniter-account/Cargo.toml
@@ -23,6 +23,7 @@ runtime-benchmarks = [
 ]
 std = [
 	"codec/std",
+	"duniter-primitives/std",
 	"frame-benchmarking?/std",
 	"frame-support/std",
 	"frame-system/std",
@@ -39,6 +40,7 @@ std = [
 	"sp-runtime/std",
 ]
 try-runtime = [
+	"duniter-primitives/try-runtime",
 	"frame-support/try-runtime",
 	"frame-system/try-runtime",
 	"pallet-balances/try-runtime",
@@ -57,6 +59,7 @@ targets = ["x86_64-unknown-linux-gnu"]
 # local
 pallet-quota = { workspace = true }
 pallet-identity = { workspace = true }
+duniter-primitives = { workspace = true }
 codec = { workspace = true, features = ["derive"] }
 log = { workspace = true }
 pallet-balances = { workspace = true }
diff --git a/pallets/duniter-account/src/benchmarking.rs b/pallets/duniter-account/src/benchmarking.rs
index f92774262..fcd4e2fb2 100644
--- a/pallets/duniter-account/src/benchmarking.rs
+++ b/pallets/duniter-account/src/benchmarking.rs
@@ -34,4 +34,14 @@ mod benchmarks {
         #[extrinsic_call]
         _(RawOrigin::Signed(account));
     }
+
+    #[benchmark]
+    fn on_revoke_identity() {
+        let idty: IdtyIdOf<T> = 1u32.into();
+
+        #[block]
+        {
+            <Pallet<T> as pallet_identity::traits::OnRemoveIdty<T>>::on_revoked(&idty);
+        }
+    }
 }
diff --git a/pallets/duniter-account/src/lib.rs b/pallets/duniter-account/src/lib.rs
index 82fb57f09..727ea10e7 100644
--- a/pallets/duniter-account/src/lib.rs
+++ b/pallets/duniter-account/src/lib.rs
@@ -216,6 +216,25 @@ pub mod pallet {
     }
 }
 
+/// Implementing identity removal event handling for the pallet.
+impl<T: Config> pallet_identity::traits::OnRemoveIdty<T> for Pallet<T> {
+    fn on_removed(_idty_index: &IdtyIdOf<T>) -> Weight {
+        Weight::zero()
+    }
+
+    /// This implementation unlinks account associated with the identity.
+    fn on_revoked(idty_index: &IdtyIdOf<T>) -> Weight {
+        if let Some(account) = <pallet_identity::Pallet<T> as duniter_primitives::Idty<
+            IdtyIdOf<T>,
+            T::AccountId,
+        >>::owner_key(*idty_index)
+        {
+            Self::do_unlink_identity(account);
+        }
+        <T as pallet::Config>::WeightInfo::on_revoke_identity()
+    }
+}
+
 // implement account linker
 impl<T> pallet_identity::traits::LinkIdty<T::AccountId, IdtyIdOf<T>> for Pallet<T>
 where
diff --git a/pallets/duniter-account/src/weights.rs b/pallets/duniter-account/src/weights.rs
index 6f9544f5b..4b5c36fde 100644
--- a/pallets/duniter-account/src/weights.rs
+++ b/pallets/duniter-account/src/weights.rs
@@ -21,6 +21,7 @@ use frame_support::weights::{constants::RocksDbWeight, Weight};
 /// Weight functions needed for pallet_universal_dividend.
 pub trait WeightInfo {
     fn unlink_identity() -> Weight;
+    fn on_revoke_identity() -> Weight;
 }
 
 // Insecure weights implementation, use it for tests only!
@@ -36,4 +37,14 @@ impl WeightInfo for () {
             .saturating_add(Weight::from_parts(0, 3591))
             .saturating_add(RocksDbWeight::get().reads(1))
     }
+
+    fn on_revoke_identity() -> Weight {
+        // Proof Size summary in bytes:
+        //  Measured:  `0`
+        //  Estimated: `3591`
+        // Minimum execution time: 95_130_000 picoseconds.
+        Weight::from_parts(110_501_000, 0)
+            .saturating_add(Weight::from_parts(0, 3591))
+            .saturating_add(RocksDbWeight::get().reads(1))
+    }
 }
diff --git a/runtime/common/src/handlers.rs b/runtime/common/src/handlers.rs
index 078bb6d7c..91b791345 100644
--- a/runtime/common/src/handlers.rs
+++ b/runtime/common/src/handlers.rs
@@ -50,19 +50,21 @@ impl<Runtime: pallet_duniter_wot::Config + pallet_quota::Config>
 /// Runtime handler for OnRemoveIdty, calling all implementations of
 /// OnRemoveIdty and implementing logic at the runtime level.
 pub struct OnRemoveIdtyHandler<Runtime>(core::marker::PhantomData<Runtime>);
-impl<Runtime: pallet_duniter_wot::Config + pallet_quota::Config>
-    pallet_identity::traits::OnRemoveIdty<Runtime> for OnRemoveIdtyHandler<Runtime>
+impl<
+        Runtime: pallet_duniter_wot::Config + pallet_quota::Config + pallet_duniter_account::Config,
+    > pallet_identity::traits::OnRemoveIdty<Runtime> for OnRemoveIdtyHandler<Runtime>
 {
     fn on_removed(idty_index: &IdtyIndex) -> Weight {
-        let mut weight = pallet_duniter_wot::Pallet::<Runtime>::on_removed(idty_index);
-        weight += pallet_quota::Pallet::<Runtime>::on_removed(idty_index);
-        weight
+        pallet_duniter_wot::Pallet::<Runtime>::on_removed(idty_index)
+            .saturating_add(pallet_quota::Pallet::<Runtime>::on_removed(idty_index))
     }
 
     fn on_revoked(idty_index: &IdtyIndex) -> Weight {
-        let mut weight = pallet_duniter_wot::Pallet::<Runtime>::on_revoked(idty_index);
-        weight += pallet_quota::Pallet::<Runtime>::on_revoked(idty_index);
-        weight
+        pallet_duniter_wot::Pallet::<Runtime>::on_revoked(idty_index)
+            .saturating_add(pallet_duniter_account::Pallet::<Runtime>::on_revoked(
+                idty_index,
+            ))
+            .saturating_add(pallet_quota::Pallet::<Runtime>::on_revoked(idty_index))
     }
 }
 
diff --git a/runtime/g1/src/weights/pallet_duniter_account.rs b/runtime/g1/src/weights/pallet_duniter_account.rs
index 63e8003bb..7979b05fe 100644
--- a/runtime/g1/src/weights/pallet_duniter_account.rs
+++ b/runtime/g1/src/weights/pallet_duniter_account.rs
@@ -17,7 +17,7 @@
 //! Autogenerated weights for `pallet_duniter_account`
 //!
 //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0
-//! DATE: 2025-01-22, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]`
+//! DATE: 2025-02-05, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]`
 //! WORST CASE MAP SIZE: `1000000`
 //! HOSTNAME: `bgallois-ms7d43`, CPU: `12th Gen Intel(R) Core(TM) i3-12100F`
 //! WASM-EXECUTION: `Compiled`, CHAIN: `None`, DB CACHE: 1024
@@ -29,7 +29,7 @@
 // --genesis-builder=spec-genesis
 // --steps=50
 // --repeat=20
-// --pallet=*
+// --pallet=pallet_duniter-account
 // --extrinsic=*
 // --wasm-execution=compiled
 // --heap-pages=4096
@@ -53,10 +53,24 @@ impl<T: frame_system::Config> pallet_duniter_account::WeightInfo for WeightInfo<
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `3558`
-		// Minimum execution time: 4_566_000 picoseconds.
-		Weight::from_parts(4_728_000, 0)
+		// Minimum execution time: 4_528_000 picoseconds.
+		Weight::from_parts(4_834_000, 0)
 			.saturating_add(Weight::from_parts(0, 3558))
 			.saturating_add(T::DbWeight::get().reads(1))
 			.saturating_add(T::DbWeight::get().writes(1))
 	}
+	/// Storage: `Identity::Identities` (r:1 w:0)
+	/// Proof: `Identity::Identities` (`max_values`: None, `max_size`: None, mode: `Measured`)
+	/// Storage: `System::Account` (r:1 w:1)
+	/// Proof: `System::Account` (`max_values`: None, `max_size`: Some(93), added: 2568, mode: `MaxEncodedLen`)
+	fn on_revoke_identity() -> Weight {
+		// Proof Size summary in bytes:
+		//  Measured:  `384`
+		//  Estimated: `3849`
+		// Minimum execution time: 12_142_000 picoseconds.
+		Weight::from_parts(13_467_000, 0)
+			.saturating_add(Weight::from_parts(0, 3849))
+			.saturating_add(T::DbWeight::get().reads(2))
+			.saturating_add(T::DbWeight::get().writes(1))
+	}
 }
diff --git a/runtime/gdev/src/weights/pallet_duniter_account.rs b/runtime/gdev/src/weights/pallet_duniter_account.rs
index 3f4d9cd5c..99cd56094 100644
--- a/runtime/gdev/src/weights/pallet_duniter_account.rs
+++ b/runtime/gdev/src/weights/pallet_duniter_account.rs
@@ -17,7 +17,7 @@
 //! Autogenerated weights for `pallet_duniter_account`
 //!
 //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0
-//! DATE: 2025-01-22, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]`
+//! DATE: 2025-02-05, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]`
 //! WORST CASE MAP SIZE: `1000000`
 //! HOSTNAME: `bgallois-ms7d43`, CPU: `12th Gen Intel(R) Core(TM) i3-12100F`
 //! WASM-EXECUTION: `Compiled`, CHAIN: `None`, DB CACHE: 1024
@@ -29,7 +29,7 @@
 // --genesis-builder=spec-genesis
 // --steps=50
 // --repeat=20
-// --pallet=*
+// --pallet=pallet_duniter-account
 // --extrinsic=*
 // --wasm-execution=compiled
 // --heap-pages=4096
@@ -53,10 +53,24 @@ impl<T: frame_system::Config> pallet_duniter_account::WeightInfo for WeightInfo<
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `3558`
-		// Minimum execution time: 4_307_000 picoseconds.
-		Weight::from_parts(4_532_000, 0)
+		// Minimum execution time: 4_500_000 picoseconds.
+		Weight::from_parts(4_694_000, 0)
 			.saturating_add(Weight::from_parts(0, 3558))
 			.saturating_add(T::DbWeight::get().reads(1))
 			.saturating_add(T::DbWeight::get().writes(1))
 	}
+	/// Storage: `Identity::Identities` (r:1 w:0)
+	/// Proof: `Identity::Identities` (`max_values`: None, `max_size`: None, mode: `Measured`)
+	/// Storage: `System::Account` (r:1 w:1)
+	/// Proof: `System::Account` (`max_values`: None, `max_size`: Some(93), added: 2568, mode: `MaxEncodedLen`)
+	fn on_revoke_identity() -> Weight {
+		// Proof Size summary in bytes:
+		//  Measured:  `384`
+		//  Estimated: `3849`
+		// Minimum execution time: 11_751_000 picoseconds.
+		Weight::from_parts(12_335_000, 0)
+			.saturating_add(Weight::from_parts(0, 3849))
+			.saturating_add(T::DbWeight::get().reads(2))
+			.saturating_add(T::DbWeight::get().writes(1))
+	}
 }
diff --git a/runtime/gdev/tests/integration_tests.rs b/runtime/gdev/tests/integration_tests.rs
index 911d2be7e..34d3150df 100644
--- a/runtime/gdev/tests/integration_tests.rs
+++ b/runtime/gdev/tests/integration_tests.rs
@@ -669,6 +669,23 @@ fn test_membership_renewal() {
         });
 }
 
+// test that identity is unlinked when identity is revoked
+#[test]
+fn test_revoke_identity_should_unlink() {
+    ExtBuilder::new(1, 3, 4).build().execute_with(|| {
+        run_to_block(1);
+
+        // revoke identity
+        Identity::do_revoke_identity(1, pallet_identity::RevocationReason::Root);
+
+        assert_eq!(
+            frame_system::Pallet::<Runtime>::get(&AccountKeyring::Alice.to_account_id())
+                .linked_idty,
+            None
+        );
+    })
+}
+
 // test that UD are auto claimed when identity is revoked
 #[test]
 fn test_revoke_identity_after_one_ud() {
diff --git a/runtime/gtest/src/weights/pallet_duniter_account.rs b/runtime/gtest/src/weights/pallet_duniter_account.rs
index 9731c3b38..d1e5585ea 100644
--- a/runtime/gtest/src/weights/pallet_duniter_account.rs
+++ b/runtime/gtest/src/weights/pallet_duniter_account.rs
@@ -17,7 +17,7 @@
 //! Autogenerated weights for `pallet_duniter_account`
 //!
 //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0
-//! DATE: 2025-01-22, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]`
+//! DATE: 2025-02-05, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]`
 //! WORST CASE MAP SIZE: `1000000`
 //! HOSTNAME: `bgallois-ms7d43`, CPU: `12th Gen Intel(R) Core(TM) i3-12100F`
 //! WASM-EXECUTION: `Compiled`, CHAIN: `None`, DB CACHE: 1024
@@ -29,7 +29,7 @@
 // --genesis-builder=spec-genesis
 // --steps=50
 // --repeat=20
-// --pallet=*
+// --pallet=pallet_duniter-account
 // --extrinsic=*
 // --wasm-execution=compiled
 // --heap-pages=4096
@@ -53,10 +53,24 @@ impl<T: frame_system::Config> pallet_duniter_account::WeightInfo for WeightInfo<
 		// Proof Size summary in bytes:
 		//  Measured:  `0`
 		//  Estimated: `3558`
-		// Minimum execution time: 4_257_000 picoseconds.
-		Weight::from_parts(4_495_000, 0)
+		// Minimum execution time: 4_425_000 picoseconds.
+		Weight::from_parts(4_688_000, 0)
 			.saturating_add(Weight::from_parts(0, 3558))
 			.saturating_add(T::DbWeight::get().reads(1))
 			.saturating_add(T::DbWeight::get().writes(1))
 	}
+	/// Storage: `Identity::Identities` (r:1 w:0)
+	/// Proof: `Identity::Identities` (`max_values`: None, `max_size`: None, mode: `Measured`)
+	/// Storage: `System::Account` (r:1 w:1)
+	/// Proof: `System::Account` (`max_values`: None, `max_size`: Some(93), added: 2568, mode: `MaxEncodedLen`)
+	fn on_revoke_identity() -> Weight {
+		// Proof Size summary in bytes:
+		//  Measured:  `384`
+		//  Estimated: `3849`
+		// Minimum execution time: 11_832_000 picoseconds.
+		Weight::from_parts(12_747_000, 0)
+			.saturating_add(Weight::from_parts(0, 3849))
+			.saturating_add(T::DbWeight::get().reads(2))
+			.saturating_add(T::DbWeight::get().writes(1))
+	}
 }
-- 
GitLab


From c1cee127021f6c85f47a24e8b89bfacde83bbaa7 Mon Sep 17 00:00:00 2001
From: bgallois <benjamin@gallois.cc>
Date: Thu, 6 Feb 2025 13:57:16 +0100
Subject: [PATCH 2/3] allocate quota for membership instead of identity fix
 https://git.duniter.org/nodes/rust/duniter-v2s/-/issues/247

---
 Cargo.lock                                    |  1 +
 .../cucumber-features/distance_fail.feature   | 12 ++++----
 .../identity_creation.feature                 |  8 ++++--
 pallets/quota/Cargo.toml                      |  5 +++-
 pallets/quota/src/lib.rs                      | 28 +++++++++----------
 runtime/common/src/handlers.rs                | 28 +++++++++----------
 6 files changed, 45 insertions(+), 37 deletions(-)

diff --git a/Cargo.lock b/Cargo.lock
index d420f9d4f..b8f42cc06 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -9547,6 +9547,7 @@ dependencies = [
  "scale-info",
  "sp-core",
  "sp-io",
+ "sp-membership",
  "sp-runtime",
 ]
 
diff --git a/end2end-tests/cucumber-features/distance_fail.feature b/end2end-tests/cucumber-features/distance_fail.feature
index 1abb9df53..e465b715a 100644
--- a/end2end-tests/cucumber-features/distance_fail.feature
+++ b/end2end-tests/cucumber-features/distance_fail.feature
@@ -31,12 +31,14 @@ Feature: Distance fail
     When bob certifies ferdie
     Then ferdie should be certified by bob
     Then ferdie should have 0 ÄžD reserved
-    Then ferdie should have 1449 cÄžD
+    # 700 + 750 - 2(one transaction fee, not a member yet)
+    Then ferdie should have 1448 cÄžD
     When ferdie requests distance evaluation
     Then ferdie should have 10 ÄžD reserved
-    Then ferdie should have 449 cÄžD
+    # 1448 - 1000 - 2(one transaction fee, not a member yet)
+    Then ferdie should have 446 cÄžD
     When 7 blocks later
-    Then treasury should contain 102 cÄžD
+    Then treasury should contain 105 cÄžD
     When alice runs distance oracle
     When 7 blocks later
     Then ferdie should be certified by alice
@@ -45,6 +47,6 @@ Feature: Distance fail
     Then ferdie identity should be unvalidated
     # Ferdie got his reserve slashed
     Then ferdie should have 0 ÄžD reserved
-    Then ferdie should have 449 cÄžD
+    Then ferdie should have 446 cÄžD
     # Slashed amount is transfered to treasury
-    Then treasury should contain 1102 cÄžD
+    Then treasury should contain 1105 cÄžD
diff --git a/end2end-tests/cucumber-features/identity_creation.feature b/end2end-tests/cucumber-features/identity_creation.feature
index 97ae14b02..3bb8fee16 100644
--- a/end2end-tests/cucumber-features/identity_creation.feature
+++ b/end2end-tests/cucumber-features/identity_creation.feature
@@ -24,13 +24,15 @@ Feature: Identity creation
     Then dave should be certified by bob
     Then dave should be certified by charlie
     Then dave should have 0 ÄžD reserved
-    Then dave should have 1449 cÄžD
+    # 700 + 750 - 2(one transaction fee, not a member yet)
+    Then dave should have 1448 cÄžD
     When dave requests distance evaluation
     Then dave should have 10 ÄžD reserved
-    Then dave should have 449 cÄžD
+    # 1448 - 1000 - 2(one transaction fee, not a member yet)
+    Then dave should have 446 cÄžD
     When 7 blocks later
     When alice runs distance oracle
     When 7 blocks later
     Then dave identity should be member
     Then dave should have 0 ÄžD reserved
-    Then dave should have 1449 cÄžD
+    Then dave should have 1446 cÄžD
diff --git a/pallets/quota/Cargo.toml b/pallets/quota/Cargo.toml
index 9df99355f..d23f77648 100644
--- a/pallets/quota/Cargo.toml
+++ b/pallets/quota/Cargo.toml
@@ -16,6 +16,7 @@ runtime-benchmarks = [
 	"frame-system/runtime-benchmarks",
 	"pallet-balances/runtime-benchmarks",
 	"pallet-identity/runtime-benchmarks",
+	"sp-membership/runtime-benchmarks",
 	"sp-runtime/runtime-benchmarks",
 ]
 try-runtime = [
@@ -23,8 +24,8 @@ try-runtime = [
 	"frame-system/try-runtime",
 	"pallet-balances/runtime-benchmarks",
 	"pallet-balances/try-runtime",
-	"pallet-identity/runtime-benchmarks",
 	"pallet-identity/try-runtime",
+	"sp-membership/try-runtime",
 	"sp-runtime/try-runtime",
 ]
 std = [
@@ -34,6 +35,7 @@ std = [
 	"frame-system/std",
 	"pallet-balances/std",
 	"pallet-identity/std",
+	"sp-membership/std",
 	"scale-info/std",
 	"sp-core/std",
 	"sp-io/std",
@@ -50,6 +52,7 @@ frame-support = { workspace = true }
 frame-system = { workspace = true }
 pallet-balances = { workspace = true }
 pallet-identity = { workspace = true }
+sp-membership = { workspace = true }
 scale-info = { workspace = true, features = ["derive"] }
 sp-core = { workspace = true }
 sp-runtime = { workspace = true }
diff --git a/pallets/quota/src/lib.rs b/pallets/quota/src/lib.rs
index 9ea7aa210..25782264e 100644
--- a/pallets/quota/src/lib.rs
+++ b/pallets/quota/src/lib.rs
@@ -360,17 +360,20 @@ impl<T: Config> RefundFee<T> for Pallet<T> {
 
 /// Checks if an identity is eligible for a refund.
 ///
-/// This function returns `true` for all identities, regardless of their status.
-/// If the identity has no quotas or has been deleted, the refund request is still queued,
-/// but when handled, no refund will be issued (and `NoQuotaForIdty` may be raised).
-fn is_eligible_for_refund<T: pallet_identity::Config>(_identity: IdtyId<T>) -> bool {
-    true
+/// This function returns `true` only if the identity exists and has a status of `Member`.
+/// If the identity does not exist or has a different status, it returns `false`, and the refund request will not be processed.
+///
+fn is_eligible_for_refund<T: pallet_identity::Config>(idty_index: IdtyId<T>) -> bool {
+    pallet_identity::Identities::<T>::get(idty_index).map_or_else(
+        || false,
+        |id| id.status == pallet_identity::IdtyStatus::Member,
+    )
 }
 
-/// Implementing the on new identity event handler for the pallet.
-impl<T: Config> pallet_identity::traits::OnNewIdty<T> for Pallet<T> {
+/// Implementing the on new membership event handler for the pallet.
+impl<T: Config> sp_membership::traits::OnNewMembership<IdtyId<T>> for Pallet<T> {
     /// This implementation initializes the identity quota for the newly created identity.
-    fn on_created(idty_index: &IdtyId<T>, _creator: &T::IdtyIndex) {
+    fn on_created(idty_index: &IdtyId<T>) {
         IdtyQuota::<T>::insert(
             idty_index,
             Quota {
@@ -379,10 +382,12 @@ impl<T: Config> pallet_identity::traits::OnNewIdty<T> for Pallet<T> {
             },
         );
     }
+
+    fn on_renewed(_idty_index: &IdtyId<T>) {}
 }
 
 /// Implementing the on remove identity event handler for the pallet.
-impl<T: Config> pallet_identity::traits::OnRemoveIdty<T> for Pallet<T> {
+impl<T: Config> sp_membership::traits::OnRemoveMembership<IdtyId<T>> for Pallet<T> {
     /// This implementation removes the identity quota associated with the removed identity.
     fn on_removed(idty_id: &IdtyId<T>) -> Weight {
         let mut weight = Weight::zero();
@@ -394,9 +399,4 @@ impl<T: Config> pallet_identity::traits::OnRemoveIdty<T> for Pallet<T> {
         add_db_reads_writes(1, 1);
         weight
     }
-
-    /// This implementation removes the identity quota associated with the removed identity.
-    fn on_revoked(idty_id: &IdtyId<T>) -> Weight {
-        Self::on_removed(idty_id)
-    }
 }
diff --git a/runtime/common/src/handlers.rs b/runtime/common/src/handlers.rs
index 91b791345..3fdd7b2d3 100644
--- a/runtime/common/src/handlers.rs
+++ b/runtime/common/src/handlers.rs
@@ -38,33 +38,28 @@ where
 /// Runtime handler for OnNewIdty, calling all implementations of
 /// OnNewIdty and implementing logic at the runtime level.
 pub struct OnNewIdtyHandler<Runtime>(core::marker::PhantomData<Runtime>);
-impl<Runtime: pallet_duniter_wot::Config + pallet_quota::Config>
-    pallet_identity::traits::OnNewIdty<Runtime> for OnNewIdtyHandler<Runtime>
+impl<Runtime: pallet_duniter_wot::Config> pallet_identity::traits::OnNewIdty<Runtime>
+    for OnNewIdtyHandler<Runtime>
 {
     fn on_created(idty_index: &IdtyIndex, creator: &IdtyIndex) {
         pallet_duniter_wot::Pallet::<Runtime>::on_created(idty_index, creator);
-        pallet_quota::Pallet::<Runtime>::on_created(idty_index, creator);
     }
 }
 
 /// Runtime handler for OnRemoveIdty, calling all implementations of
 /// OnRemoveIdty and implementing logic at the runtime level.
 pub struct OnRemoveIdtyHandler<Runtime>(core::marker::PhantomData<Runtime>);
-impl<
-        Runtime: pallet_duniter_wot::Config + pallet_quota::Config + pallet_duniter_account::Config,
-    > pallet_identity::traits::OnRemoveIdty<Runtime> for OnRemoveIdtyHandler<Runtime>
+impl<Runtime: pallet_duniter_wot::Config + pallet_duniter_account::Config>
+    pallet_identity::traits::OnRemoveIdty<Runtime> for OnRemoveIdtyHandler<Runtime>
 {
     fn on_removed(idty_index: &IdtyIndex) -> Weight {
         pallet_duniter_wot::Pallet::<Runtime>::on_removed(idty_index)
-            .saturating_add(pallet_quota::Pallet::<Runtime>::on_removed(idty_index))
     }
 
     fn on_revoked(idty_index: &IdtyIndex) -> Weight {
-        pallet_duniter_wot::Pallet::<Runtime>::on_revoked(idty_index)
-            .saturating_add(pallet_duniter_account::Pallet::<Runtime>::on_revoked(
-                idty_index,
-            ))
-            .saturating_add(pallet_quota::Pallet::<Runtime>::on_revoked(idty_index))
+        pallet_duniter_wot::Pallet::<Runtime>::on_revoked(idty_index).saturating_add(
+            pallet_duniter_account::Pallet::<Runtime>::on_revoked(idty_index),
+        )
     }
 }
 
@@ -75,13 +70,16 @@ impl<
         Runtime: frame_system::Config<AccountId = AccountId>
             + pallet_identity::Config<IdtyData = IdtyData, IdtyIndex = IdtyIndex>
             + pallet_duniter_wot::Config
-            + pallet_universal_dividend::Config,
+            + pallet_universal_dividend::Config
+            + pallet_quota::Config,
     > sp_membership::traits::OnNewMembership<IdtyIndex> for OnNewMembershipHandler<Runtime>
 {
     fn on_created(idty_index: &IdtyIndex) {
         // duniter-wot related actions
         pallet_duniter_wot::Pallet::<Runtime>::on_created(idty_index);
 
+        pallet_quota::Pallet::<Runtime>::on_created(idty_index);
+
         // When main membership is acquired, it starts getting right to UD.
         pallet_identity::Identities::<Runtime>::mutate_exists(idty_index, |idty_val_opt| {
             if let Some(ref mut idty_val) = idty_val_opt {
@@ -107,6 +105,7 @@ impl<
             + pallet_identity::Config<IdtyData = IdtyData, IdtyIndex = IdtyIndex>
             + pallet_smith_members::Config<IdtyIndex = IdtyIndex>
             + pallet_duniter_wot::Config
+            + pallet_quota::Config
             + pallet_universal_dividend::Config,
     > sp_membership::traits::OnRemoveMembership<IdtyIndex> for OnRemoveMembershipHandler<Runtime>
 {
@@ -127,7 +126,8 @@ impl<
                 }
             }
         });
-        weight += Runtime::DbWeight::get().reads_writes(1, 1);
+        weight.saturating_add(pallet_quota::Pallet::<Runtime>::on_removed(idty_index));
+        weight.saturating_add(Runtime::DbWeight::get().reads_writes(1, 1));
 
         // When membership is removed, also remove from smith member.
         weight.saturating_add(
-- 
GitLab


From b72c7dd7fec5f9ee8d8f88ee98fd8074dcfda51b Mon Sep 17 00:00:00 2001
From: bgallois <benjamin@gallois.cc>
Date: Thu, 6 Feb 2025 15:39:38 +0100
Subject: [PATCH 3/3] test refund by status

---
 runtime/gdev/tests/xt_tests.rs | 97 ++++++++++++++++++++++++++++++++++
 1 file changed, 97 insertions(+)

diff --git a/runtime/gdev/tests/xt_tests.rs b/runtime/gdev/tests/xt_tests.rs
index 6fcc2060c..efac8a18f 100644
--- a/runtime/gdev/tests/xt_tests.rs
+++ b/runtime/gdev/tests/xt_tests.rs
@@ -207,3 +207,100 @@ fn test_refund_reaped_linked_account() {
             assert!(pallet_quota::RefundQueue::<Runtime>::get().is_empty());
         })
 }
+
+/// test no refund on_idle when account is not a member
+#[test]
+fn test_no_member_no_refund() {
+    ExtBuilder::new(1, 3, 4)
+        .with_initial_balances(vec![
+            (AccountKeyring::Alice.to_account_id(), 10_000),
+            (AccountKeyring::Bob.to_account_id(), 10_000),
+        ])
+        .build()
+        .execute_with(|| {
+            // Revoked identities are not eligible for a refund
+            let revocation_payload = pallet_identity::RevocationPayload {
+                idty_index: 2u32,
+                genesis_hash: System::block_hash(0),
+            };
+            let signature = AccountKeyring::Bob.sign(
+                &(
+                    pallet_identity::REVOCATION_PAYLOAD_PREFIX,
+                    revocation_payload,
+                )
+                    .encode(),
+            );
+            assert_ok!(Identity::revoke_identity(
+                RuntimeOrigin::signed(AccountKeyring::Bob.to_account_id()),
+                2,
+                AccountKeyring::Bob.to_account_id(),
+                signature.into()
+            ));
+            assert_eq!(
+                pallet_identity::Identities::<Runtime>::get(&2)
+                    .unwrap()
+                    .status,
+                pallet_identity::IdtyStatus::Revoked
+            );
+            let call = RuntimeCall::Balances(BalancesCall::transfer_allow_death {
+                dest: AccountKeyring::Ferdie.to_account_id().into(),
+                value: 500,
+            });
+            let xt = get_unchecked_extrinsic(call, 4u64, 8u64, AccountKeyring::Bob, 0u64, 0);
+            assert_ok!(Executive::apply_extrinsic(xt));
+            assert!(pallet_quota::RefundQueue::<Runtime>::get().is_empty());
+
+            // Unconfirmed identities are not eligible for a refund
+            assert_ok!(Identity::create_identity(
+                RuntimeOrigin::signed(AccountKeyring::Alice.to_account_id()),
+                AccountKeyring::Ferdie.to_account_id(),
+            ));
+            assert_eq!(
+                pallet_identity::Identities::<Runtime>::get(&5)
+                    .unwrap()
+                    .status,
+                pallet_identity::IdtyStatus::Unconfirmed
+            );
+            let call = RuntimeCall::Balances(BalancesCall::transfer_allow_death {
+                dest: AccountKeyring::Alice.to_account_id().into(),
+                value: 500,
+            });
+            let xt =
+                get_unchecked_extrinsic(call.clone(), 4u64, 8u64, AccountKeyring::Ferdie, 0u64, 0);
+            assert_ok!(Executive::apply_extrinsic(xt));
+            assert!(pallet_quota::RefundQueue::<Runtime>::get().is_empty());
+
+            // Unvalidated identities are not eligible for a refund
+            assert_ok!(Identity::confirm_identity(
+                RuntimeOrigin::signed(AccountKeyring::Ferdie.to_account_id()),
+                "ferdie".into(),
+            ));
+            assert_eq!(
+                pallet_identity::Identities::<Runtime>::get(&5)
+                    .unwrap()
+                    .status,
+                pallet_identity::IdtyStatus::Unvalidated
+            );
+            let xt =
+                get_unchecked_extrinsic(call.clone(), 4u64, 8u64, AccountKeyring::Ferdie, 0u64, 1);
+            assert_ok!(Executive::apply_extrinsic(xt));
+            assert!(pallet_quota::RefundQueue::<Runtime>::get().is_empty());
+
+            // NotMember identities are not eligible for a refund
+            pallet_identity::Pallet::<Runtime>::membership_removed(1);
+            assert_eq!(
+                pallet_identity::Identities::<Runtime>::get(&1)
+                    .unwrap()
+                    .status,
+                pallet_identity::IdtyStatus::NotMember
+            );
+            let call = RuntimeCall::Balances(BalancesCall::transfer_allow_death {
+                dest: AccountKeyring::Bob.to_account_id().into(),
+                value: 500,
+            });
+            let xt =
+                get_unchecked_extrinsic(call.clone(), 4u64, 8u64, AccountKeyring::Alice, 0u64, 0);
+            assert_ok!(Executive::apply_extrinsic(xt));
+            assert!(pallet_quota::RefundQueue::<Runtime>::get().is_empty());
+        })
+}
-- 
GitLab