From 431ff35b6b9b372b9b7b9912e416bcf98755849d Mon Sep 17 00:00:00 2001
From: Benjamin Gallois <business@gallois.cc>
Date: Wed, 6 Mar 2024 11:54:32 +0100
Subject: [PATCH] Fix #196 forbid empty linked account
 (nodes/rust/duniter-v2s!253)

* test refund behavior on reaped account

* Revert "complete the test with refund check"

This reverts commit edb681382905a388445f399e44d5e5184de73181.

* complete the test with refund check

* add test empty linked account
---
 runtime/gdev/tests/balance_tests.rs | 46 ++++++++++++++++++++++++++++
 runtime/gdev/tests/xt_tests.rs      | 47 +++++++++++++++++++++++++++++
 2 files changed, 93 insertions(+)

diff --git a/runtime/gdev/tests/balance_tests.rs b/runtime/gdev/tests/balance_tests.rs
index de2ac25c8..85c3b0ae3 100644
--- a/runtime/gdev/tests/balance_tests.rs
+++ b/runtime/gdev/tests/balance_tests.rs
@@ -19,9 +19,12 @@
 mod common;
 
 use common::*;
+use frame_support::traits::StoredMap;
 use frame_support::{assert_noop, assert_ok};
 use gdev_runtime::*;
+use sp_core::Encode;
 use sp_keyring::AccountKeyring;
+use sp_runtime::MultiAddress;
 
 /// test currency transfer
 /// (does not take fees into account because it's only calls, not extrinsics)
@@ -115,3 +118,46 @@ fn test_transfer_funds_unavailable() {
             );
         })
 }
+
+/// test balance transfer all with linked account not member
+#[test]
+fn test_transfer_all_linked_no_member() {
+    ExtBuilder::new(1, 3, 4)
+        .with_initial_balances(vec![(AccountKeyring::Alice.to_account_id(), 5_000)])
+        .build()
+        .execute_with(|| {
+            run_to_block(1);
+
+            let genesis_hash = System::block_hash(0);
+            let alice = AccountKeyring::Alice.to_account_id();
+            let ferdie = AccountKeyring::Ferdie.to_account_id();
+            let payload = (b"link", genesis_hash, 1u32, ferdie.clone()).encode();
+            let signature = AccountKeyring::Ferdie.sign(&payload);
+
+            assert_ok!(Balances::transfer_allow_death(
+                frame_system::RawOrigin::Signed(alice.clone()).into(),
+                MultiAddress::Id(ferdie.clone()),
+                1_000
+            ));
+            // Ferdie's account can be linked to Alice identity
+            assert_ok!(Identity::link_account(
+                frame_system::RawOrigin::Signed(alice).into(),
+                ferdie.clone(),
+                signature.into()
+            ));
+            assert_eq!(
+                frame_system::Pallet::<Runtime>::get(&ferdie).linked_idty,
+                Some(1)
+            );
+            assert_ok!(Balances::transfer_all(
+                frame_system::RawOrigin::Signed(ferdie.clone()).into(),
+                AccountKeyring::Bob.to_account_id().into(),
+                false
+            ),);
+            assert_eq!(Balances::free_balance(ferdie.clone()), 0);
+            // During reaping the account is unlinked
+            assert!(frame_system::Pallet::<Runtime>::get(&ferdie)
+                .linked_idty
+                .is_none());
+        })
+}
diff --git a/runtime/gdev/tests/xt_tests.rs b/runtime/gdev/tests/xt_tests.rs
index ab48fdaf7..bfa840a54 100644
--- a/runtime/gdev/tests/xt_tests.rs
+++ b/runtime/gdev/tests/xt_tests.rs
@@ -22,6 +22,7 @@ mod common;
 use common::*;
 use frame_support::assert_ok;
 use frame_support::traits::OnIdle;
+use frame_support::traits::StoredMap;
 use gdev_runtime::*;
 use sp_core::Encode;
 use sp_core::Pair;
@@ -191,3 +192,49 @@ fn test_no_refund() {
             assert_eq!(Balances::free_balance(Treasury::account_id()), 100 + 3);
         })
 }
+
+/// test refund on_idle when linked account is reaped
+#[test]
+fn test_refund_reaped_linked_account() {
+    ExtBuilder::new(1, 3, 4)
+        .with_initial_balances(vec![
+            (AccountKeyring::Alice.to_account_id(), 10_000),
+            (AccountKeyring::Ferdie.to_account_id(), 10_000),
+        ])
+        .build()
+        .execute_with(|| {
+            let genesis_hash = System::block_hash(0);
+            let alice = AccountKeyring::Alice.to_account_id();
+            let ferdie = AccountKeyring::Ferdie.to_account_id();
+            let payload = (b"link", genesis_hash, 1u32, ferdie.clone()).encode();
+            let signature = AccountKeyring::Ferdie.sign(&payload);
+
+            // Ferdie's account can be linked to Alice identity
+            assert_ok!(Identity::link_account(
+                frame_system::RawOrigin::Signed(alice.clone()).into(),
+                ferdie.clone(),
+                signature.into()
+            ));
+            assert_eq!(
+                frame_system::Pallet::<Runtime>::get(&ferdie).linked_idty,
+                Some(1)
+            );
+
+            // transfer_all call to extrinsic
+            let call = RuntimeCall::Balances(BalancesCall::transfer_all {
+                dest: AccountKeyring::Alice.to_account_id().into(),
+                keep_alive: false,
+            });
+            let xt = get_unchecked_extrinsic(call, 4u64, 8u64, AccountKeyring::Ferdie, 0u64);
+            assert_ok!(Executive::apply_extrinsic(xt));
+
+            assert_eq!(Balances::free_balance(ferdie.clone()), 0);
+            // During reaping the account is unlinked
+            assert!(frame_system::Pallet::<Runtime>::get(&ferdie)
+                .linked_idty
+                .is_none());
+
+            // since the account is reaped, it is not linked anymore and no refund is added to queue
+            assert!(pallet_quota::RefundQueue::<Runtime>::get().is_empty());
+        })
+}
-- 
GitLab