From 70b4bf60df80213f4ef4a7dbef888f7457c263c7 Mon Sep 17 00:00:00 2001
From: Michal Lustyk <MichalLustykNeti>
Date: Mon, 2 Oct 2023 15:50:19 +0200
Subject: [PATCH 1/2] BLOCKCHAIN-176 Added proposal fee and updated tests

BLOCKCHAIN-176 Added proposal fee and updated tests

BLOCKCHAIN-176 Added proposal fee and tests

BLOCKCHAIN-176 Added proposal fee and updated tests

Update bin/node/runtime/src/lib.rs

Co-authored-by: kacperzuk-neti <117277751+kacperzuk-neti@users.noreply.github.com>

BLOCKCHAIN-176 added test that ensure proposal creation fee is valid

BLOCKCHAIN-176 added check of total account balance

BLOCKCHAIN-176 added check of total account balance
---
 bin/node/runtime/src/lib.rs                   |  4 ++
 frame/democracy/src/lib.rs                    | 11 ++++-
 frame/democracy/src/tests.rs                  |  2 +
 frame/democracy/src/tests/delegation.rs       | 26 +++++-----
 frame/democracy/src/tests/public_proposals.rs | 47 ++++++++++++-------
 frame/democracy/src/tests/voting.rs           |  5 +-
 6 files changed, 62 insertions(+), 33 deletions(-)

diff --git a/bin/node/runtime/src/lib.rs b/bin/node/runtime/src/lib.rs
index c62c871eba..9af3d6db0e 100644
--- a/bin/node/runtime/src/lib.rs
+++ b/bin/node/runtime/src/lib.rs
@@ -806,6 +806,7 @@ parameter_types! {
 	pub const MinimumDeposit: Balance = 10 * GRAINS_IN_LLM;
 	pub const CooloffPeriod: BlockNumber = 7 * DAYS;
 	pub const MaxProposals: u32 = 100;
+	pub const ProposalFeeAmount: Balance = 100 * DOLLARS;
 }
 
 impl pallet_democracy::Config for Runtime {
@@ -870,6 +871,9 @@ impl pallet_democracy::Config for Runtime {
 	type MaxDeposits = ConstU32<100>;
 	type MaxBlacklisted = ConstU32<100>;
 	type DelegateeFilter = ContainsMember<Runtime, CouncilCollective>;
+
+	type ProposalFee = Treasury;
+	type ProposalFeeAmount = ProposalFeeAmount;
 }
 
 parameter_types! {
diff --git a/frame/democracy/src/lib.rs b/frame/democracy/src/lib.rs
index 92255cd958..2b56b4d19f 100644
--- a/frame/democracy/src/lib.rs
+++ b/frame/democracy/src/lib.rs
@@ -166,7 +166,7 @@ use frame_support::{
 		schedule::{v3::Named as ScheduleNamed, DispatchTime},
 		Bounded, Currency, Get, Hash as PreimageHash, LockIdentifier, LockableCurrency, QueryPreimage,
 		ReservableCurrency, StorePreimage,
-		Contains,
+		Contains, OnUnbalanced
 	},
 	pallet_prelude::{MaxEncodedLen, TypeInfo},
 	BoundedVec,
@@ -322,6 +322,9 @@ pub mod pallet {
 		#[pallet::constant]
 		type MaxAdditionalFields: Get<u32>;
 
+		#[pallet::constant]
+		type ProposalFeeAmount: Get<BalanceOf<Self>>;
+
 		/// Origin from which the next tabled referendum may be forced; this allows for the tabling
 		/// of a negative-turnout-bias (default-carries) referendum.
 		type ExternalDefaultOrigin: EnsureOrigin<Self::RuntimeOrigin>;
@@ -360,6 +363,8 @@ pub mod pallet {
 		type LLM: LLM<Self::AccountId, BalanceOf<Self>>;
 		type DelegateeFilter: Contains<Self::AccountId>;
 		type LLInitializer: LLInitializer<Self::AccountId>;
+
+		type ProposalFee: OnUnbalanced<<<Self as Config>::Currency as Currency<<Self as frame_system::Config>::AccountId>>::NegativeImbalance>;
 	}
 
 	/// The number of (public) proposals that have been made so far.
@@ -1237,7 +1242,9 @@ impl<T: Config> Pallet<T> {
 	fn do_propose(who: T::AccountId, proposal: BoundedCallOf<T>, value: BalanceOf<T>, dispatch_origin: DispatchOrigin) -> DispatchResult {
 		T::Citizenship::ensure_politics_allowed(&who)?;
 
-		ensure!(value >= T::MinimumDeposit::get(), Error::<T>::ValueLow);
+		ensure!(T::Currency::can_slash(&who, T::ProposalFeeAmount::get()), Error::<T>::InsufficientFunds);
+
+		T::ProposalFee::on_unbalanced(T::Currency::slash(&who, T::ProposalFeeAmount::get()).0);
 
 		let index = Self::public_prop_count();
 		let real_prop_count = PublicProps::<T>::decode_len().unwrap_or(0) as u32;
diff --git a/frame/democracy/src/tests.rs b/frame/democracy/src/tests.rs
index 0e901162a5..b0ab7b9c99 100644
--- a/frame/democracy/src/tests.rs
+++ b/frame/democracy/src/tests.rs
@@ -326,6 +326,8 @@ impl Config for Test {
 	type LLM = LLM;
 	type LLInitializer = LiberlandInitializer;
 	type DelegateeFilter = Everything;
+	type ProposalFee = ();
+	type ProposalFeeAmount = ConstU64<10>;
 }
 
 pub fn new_test_ext() -> sp_io::TestExternalities {
diff --git a/frame/democracy/src/tests/delegation.rs b/frame/democracy/src/tests/delegation.rs
index 2e71ff4623..b320648587 100644
--- a/frame/democracy/src/tests/delegation.rs
+++ b/frame/democracy/src/tests/delegation.rs
@@ -36,19 +36,19 @@ fn single_proposal_should_work_with_delegation() {
 		assert_ok!(Democracy::delegate(RuntimeOrigin::signed(2), 1, Conviction::None, 20));
 		let r = 0;
 		assert_ok!(Democracy::vote(RuntimeOrigin::signed(1), r, aye(1)));
-		assert_eq!(tally(r), Tally { ayes: 30, nays: 0, turnout: 30, aye_voters: 20000, nay_voters: 0 });
+		assert_eq!(tally(r), Tally { ayes: 20, nays: 0, turnout: 20, aye_voters: 20000, nay_voters: 0 });
 
 		// Delegate a second vote.
 		assert_ok!(Democracy::delegate(RuntimeOrigin::signed(3), 1, Conviction::None, 30));
-		assert_eq!(tally(r), Tally { ayes: 60, nays: 0, turnout: 60, aye_voters: 30000, nay_voters: 0 });
+		assert_eq!(tally(r), Tally { ayes: 50, nays: 0, turnout: 50, aye_voters: 30000, nay_voters: 0 });
 
 		// Reduce first vote.
 		assert_ok!(Democracy::delegate(RuntimeOrigin::signed(2), 1, Conviction::None, 10));
-		assert_eq!(tally(r), Tally { ayes: 50, nays: 0, turnout: 50, aye_voters: 30000, nay_voters: 0 });
+		assert_eq!(tally(r), Tally { ayes: 40, nays: 0, turnout: 40, aye_voters: 30000, nay_voters: 0 });
 
 		// Second vote delegates to first; we don't do tiered delegation, so it doesn't get used.
 		assert_ok!(Democracy::delegate(RuntimeOrigin::signed(3), 2, Conviction::None, 30));
-		assert_eq!(tally(r), Tally { ayes: 20, nays: 0, turnout: 20, aye_voters: 20000, nay_voters: 0 });
+		assert_eq!(tally(r), Tally { ayes: 10, nays: 0, turnout: 10, aye_voters: 20000, nay_voters: 0 });
 
 		// Main voter cancels their vote
 		assert_ok!(Democracy::remove_vote(RuntimeOrigin::signed(1), r));
@@ -60,7 +60,7 @@ fn single_proposal_should_work_with_delegation() {
 
 		// Main voter reinstates their vote
 		assert_ok!(Democracy::vote(RuntimeOrigin::signed(1), r, aye(1)));
-		assert_eq!(tally(r), Tally { ayes: 20, nays: 0, turnout: 20, aye_voters: 20000, nay_voters: 0 });
+		assert_eq!(tally(r), Tally { ayes: 10, nays: 0, turnout: 10, aye_voters: 20000, nay_voters: 0 });
 	});
 }
 
@@ -94,7 +94,7 @@ fn cyclic_delegation_should_unwind() {
 		assert_ok!(Democracy::vote(RuntimeOrigin::signed(1), r, nay(1)));
 
 		// Delegated vote is counted.
-		assert_eq!(tally(r), Tally { ayes: 30, nays: 30, turnout: 60, aye_voters: 10000, nay_voters: 20000  });
+		assert_eq!(tally(r), Tally { ayes: 30, nays: 20, turnout: 50, aye_voters: 10000, nay_voters: 20000  });
 	});
 }
 
@@ -111,13 +111,13 @@ fn single_proposal_should_work_with_vote_and_delegation() {
 		let r = 0;
 		assert_ok!(Democracy::vote(RuntimeOrigin::signed(1), r, aye(1)));
 		assert_ok!(Democracy::vote(RuntimeOrigin::signed(2), r, nay(2)));
-		assert_eq!(tally(r), Tally { ayes: 10, nays: 20, turnout: 30, aye_voters: 10000, nay_voters: 10000  });
+		assert_eq!(tally(r), Tally { ayes: 0, nays: 20, turnout: 20, aye_voters: 10000, nay_voters: 10000  });
 
 		// Delegate vote.
 		assert_ok!(Democracy::remove_vote(RuntimeOrigin::signed(2), r));
 		assert_ok!(Democracy::delegate(RuntimeOrigin::signed(2), 1, Conviction::None, 20));
 		// Delegated vote replaces the explicit vote.
-		assert_eq!(tally(r), Tally { ayes: 30, nays: 0, turnout: 30 , aye_voters: 20000, nay_voters: 0 });
+		assert_eq!(tally(r), Tally { ayes: 20, nays: 0, turnout: 20 , aye_voters: 20000, nay_voters: 0 });
 	});
 }
 
@@ -137,7 +137,7 @@ fn single_proposal_should_work_with_undelegation() {
 		assert_ok!(Democracy::vote(RuntimeOrigin::signed(1), r, aye(1)));
 
 		// Delegated vote is not counted.
-		assert_eq!(tally(r), Tally { ayes: 10, nays: 0, turnout: 10, aye_voters: 10000, nay_voters: 0  });
+		assert_eq!(tally(r), Tally { ayes: 0, nays: 0, turnout: 0, aye_voters: 10000, nay_voters: 0  });
 	});
 }
 
@@ -149,11 +149,11 @@ fn single_proposal_should_work_with_delegation_and_vote() {
 		// Delegate, undelegate and vote.
 		assert_ok!(Democracy::vote(RuntimeOrigin::signed(1), r, aye(1)));
 		assert_ok!(Democracy::delegate(RuntimeOrigin::signed(2), 1, Conviction::None, 20));
-		assert_eq!(tally(r), Tally { ayes: 30, nays: 0, turnout: 30, aye_voters: 20000, nay_voters: 0  });
+		assert_eq!(tally(r), Tally { ayes: 20, nays: 0, turnout: 20, aye_voters: 20000, nay_voters: 0  });
 		assert_ok!(Democracy::undelegate(RuntimeOrigin::signed(2)));
 		assert_ok!(Democracy::vote(RuntimeOrigin::signed(2), r, aye(2)));
 		// Delegated vote is not counted.
-		assert_eq!(tally(r), Tally { ayes: 30, nays: 0, turnout: 30, aye_voters: 20000, nay_voters: 0  });
+		assert_eq!(tally(r), Tally { ayes: 20, nays: 0, turnout: 20, aye_voters: 20000, nay_voters: 0  });
 	});
 }
 
@@ -166,7 +166,7 @@ fn conviction_should_be_honored_in_delegation() {
 		assert_ok!(Democracy::delegate(RuntimeOrigin::signed(2), 1, Conviction::Locked6x, 20));
 		assert_ok!(Democracy::vote(RuntimeOrigin::signed(1), r, aye(1)));
 		// Delegated vote is huge.
-		assert_eq!(tally(r), Tally { ayes: 30, nays: 0, turnout: 30, aye_voters: 20000, nay_voters: 0  });
+		assert_eq!(tally(r), Tally { ayes: 20, nays: 0, turnout: 20, aye_voters: 20000, nay_voters: 0  });
 	});
 }
 
@@ -195,7 +195,7 @@ fn redelegation_keeps_lock() {
 		assert_ok!(Democracy::delegate(RuntimeOrigin::signed(2), 1, Conviction::Locked6x, 20));
 		assert_ok!(Democracy::vote(RuntimeOrigin::signed(1), r, aye(1)));
 		// Delegated vote is huge.
-		assert_eq!(tally(r), Tally { ayes: 30, nays: 0, turnout: 30, aye_voters: 20000, nay_voters: 0  });
+		assert_eq!(tally(r), Tally { ayes: 20, nays: 0, turnout: 20, aye_voters: 20000, nay_voters: 0  });
 
 		let mut prior_lock = vote::PriorLock::default();
 
diff --git a/frame/democracy/src/tests/public_proposals.rs b/frame/democracy/src/tests/public_proposals.rs
index 1e70a82ffa..b68cd44b39 100644
--- a/frame/democracy/src/tests/public_proposals.rs
+++ b/frame/democracy/src/tests/public_proposals.rs
@@ -26,9 +26,9 @@ use super::*;
 #[test]
 fn backing_for_should_work() {
 	new_test_ext().execute_with(|| {
-		assert_ok!(propose_set_balance(1, 2, 2));
-		assert_ok!(propose_set_balance(1, 4, 4));
-		assert_ok!(propose_set_balance(1, 3, 3));
+		assert_ok!(propose_set_balance(3, 2, 2));
+		assert_ok!(propose_set_balance(3, 4, 4));
+		assert_ok!(propose_set_balance(3, 3, 3));
 		assert_eq!(Democracy::backing_for(0), Some(2));
 		assert_eq!(Democracy::backing_for(1), Some(4));
 		assert_eq!(Democracy::backing_for(2), Some(3));
@@ -45,7 +45,7 @@ fn deposit_for_proposals_should_be_taken() {
 		assert_ok!(Democracy::second(RuntimeOrigin::signed(5), 0));
 		// liberland specific - free balance shouldn't change, seconds shouldn't
 		// lock anything
-		assert_eq!(Balances::free_balance(1), 10);
+		assert_eq!(Balances::free_balance(1), 0);
 		assert_eq!(Balances::free_balance(2), 20);
 		assert_eq!(Balances::free_balance(5), 50);
 	});
@@ -60,16 +60,31 @@ fn deposit_for_proposals_should_be_returned() {
 		assert_ok!(Democracy::second(RuntimeOrigin::signed(5), 0));
 		assert_ok!(Democracy::second(RuntimeOrigin::signed(5), 0));
 		fast_forward_to(3);
-		assert_eq!(Balances::free_balance(1), 10);
+		assert_eq!(Balances::free_balance(1), 0);
 		assert_eq!(Balances::free_balance(2), 20);
 		assert_eq!(Balances::free_balance(5), 50);
 	});
 }
 
 #[test]
-fn proposal_with_deposit_below_minimum_should_not_work() {
+fn proposal_with_funds_below_minimum_should_not_work() {
 	new_test_ext().execute_with(|| {
-		assert_noop!(propose_set_balance(1, 2, 0), Error::<Test>::ValueLow);
+		assert_ok!(propose_set_balance(1, 2, 5));
+
+		assert_noop!(propose_set_balance(1, 2, 0), Error::<Test>::InsufficientFunds);
+	});
+}
+
+#[test]
+fn creating_proposal_takes_fee() {
+	new_test_ext().execute_with(|| {
+		System::set_block_number(0);
+		assert_eq!(Balances::total_balance(&1), 10);
+
+		assert_ok!(propose_set_balance(1, 2, 5));
+
+		assert_eq!(Balances::total_balance(&1), 0);
+		
 	});
 }
 
@@ -94,12 +109,12 @@ fn poor_seconder_should_not_work() {
 #[test]
 fn cancel_proposal_should_work() {
 	new_test_ext().execute_with(|| {
-		assert_ok!(propose_set_balance(1, 2, 2));
-		assert_ok!(propose_set_balance(1, 4, 4));
+		assert_ok!(propose_set_balance(2, 2, 2));
+		assert_ok!(propose_set_balance(2, 4, 4));
 		assert_noop!(Democracy::cancel_proposal(RuntimeOrigin::signed(1), 0), BadOrigin);
 		let hash = note_preimage(1);
 		assert_ok!(Democracy::set_metadata(
-			RuntimeOrigin::signed(1),
+			RuntimeOrigin::signed(2),
 			MetadataOwner::Proposal(0),
 			Some(hash)
 		));
@@ -122,8 +137,8 @@ fn blacklisting_should_work() {
 		System::set_block_number(0);
 		let hash = set_balance_proposal(2).hash();
 
-		assert_ok!(propose_set_balance(1, 2, 2));
-		assert_ok!(propose_set_balance(1, 4, 4));
+		assert_ok!(propose_set_balance(3, 2, 2));
+		assert_ok!(propose_set_balance(3, 4, 4));
 
 		assert_noop!(Democracy::blacklist(RuntimeOrigin::signed(1), hash, None), BadOrigin);
 		assert_ok!(Democracy::blacklist(RuntimeOrigin::root(), hash, None));
@@ -131,7 +146,7 @@ fn blacklisting_should_work() {
 		assert_eq!(Democracy::backing_for(0), None);
 		assert_eq!(Democracy::backing_for(1), Some(4));
 
-		assert_noop!(propose_set_balance(1, 2, 2), Error::<Test>::ProposalBlacklisted);
+		assert_noop!(propose_set_balance(3, 2, 2), Error::<Test>::ProposalBlacklisted);
 
 		fast_forward_to(2);
 
@@ -146,9 +161,9 @@ fn blacklisting_should_work() {
 fn runners_up_should_come_after() {
 	new_test_ext().execute_with(|| {
 		System::set_block_number(0);
-		assert_ok!(propose_set_balance(1, 2, 2));
-		assert_ok!(propose_set_balance(1, 4, 4));
-		assert_ok!(propose_set_balance(1, 3, 3));
+		assert_ok!(propose_set_balance(3, 2, 2));
+		assert_ok!(propose_set_balance(3, 4, 4));
+		assert_ok!(propose_set_balance(3, 3, 3));
 		fast_forward_to(2);
 		assert_ok!(Democracy::vote(RuntimeOrigin::signed(1), 0, aye(1)));
 		fast_forward_to(4);
diff --git a/frame/democracy/src/tests/voting.rs b/frame/democracy/src/tests/voting.rs
index 5dd0fdbe33..89a2d8e659 100644
--- a/frame/democracy/src/tests/voting.rs
+++ b/frame/democracy/src/tests/voting.rs
@@ -73,7 +73,7 @@ fn single_proposal_should_work() {
 
 		// start of 2 => next referendum scheduled.
 		fast_forward_to(2);
-		assert_ok!(Democracy::vote(RuntimeOrigin::signed(1), r, aye(1)));
+		assert_ok!(Democracy::vote(RuntimeOrigin::signed(2), r, aye(2)));
 
 		assert_eq!(Democracy::referendum_count(), 1);
 		assert_eq!(
@@ -84,7 +84,7 @@ fn single_proposal_should_work() {
 				dispatch_origin: DispatchOrigin::Root, 
 				threshold: VoteThreshold::SuperMajorityApprove,
 				delay: 2,
-				tally: Tally { ayes: 10, nays: 0, turnout: 10, aye_voters: 10000, nay_voters: 0  },
+				tally: Tally { ayes: 20, nays: 0, turnout: 20, aye_voters: 10000, nay_voters: 0  },
 			})
 		);
 
@@ -97,6 +97,7 @@ fn single_proposal_should_work() {
 		fast_forward_to(4);
 
 		assert_noop!(Democracy::referendum_status(0), Error::<Test>::ReferendumInvalid);
+
 		assert!(pallet_scheduler::Agenda::<Test>::get(6)[0].is_some());
 
 		// referendum passes and wait another two blocks for enactment.

From b2981df4af303cfbd12a5ed1e35d02f6151a2fa5 Mon Sep 17 00:00:00 2001
From: Michal Lustyk <MichalLustykNeti>
Date: Fri, 17 Nov 2023 11:10:18 +0100
Subject: [PATCH 2/2] BLOCKCHAIN-176 hanged slash to withdraw

---
 frame/democracy/src/lib.rs                    | 13 +++++--
 frame/democracy/src/tests.rs                  |  5 ++-
 frame/democracy/src/tests/delegation.rs       | 27 +++++++-------
 frame/democracy/src/tests/public_proposals.rs | 37 ++++++++++++++-----
 frame/democracy/src/tests/scheduling.rs       | 10 ++---
 frame/democracy/src/tests/voting.rs           |  6 +--
 6 files changed, 61 insertions(+), 37 deletions(-)

diff --git a/frame/democracy/src/lib.rs b/frame/democracy/src/lib.rs
index 2b56b4d19f..c19e06c3c1 100644
--- a/frame/democracy/src/lib.rs
+++ b/frame/democracy/src/lib.rs
@@ -166,7 +166,7 @@ use frame_support::{
 		schedule::{v3::Named as ScheduleNamed, DispatchTime},
 		Bounded, Currency, Get, Hash as PreimageHash, LockIdentifier, LockableCurrency, QueryPreimage,
 		ReservableCurrency, StorePreimage,
-		Contains, OnUnbalanced
+		Contains, OnUnbalanced, tokens::{ExistenceRequirement, WithdrawReasons}
 	},
 	pallet_prelude::{MaxEncodedLen, TypeInfo},
 	BoundedVec,
@@ -1242,9 +1242,14 @@ impl<T: Config> Pallet<T> {
 	fn do_propose(who: T::AccountId, proposal: BoundedCallOf<T>, value: BalanceOf<T>, dispatch_origin: DispatchOrigin) -> DispatchResult {
 		T::Citizenship::ensure_politics_allowed(&who)?;
 
-		ensure!(T::Currency::can_slash(&who, T::ProposalFeeAmount::get()), Error::<T>::InsufficientFunds);
-
-		T::ProposalFee::on_unbalanced(T::Currency::slash(&who, T::ProposalFeeAmount::get()).0);
+		T::ProposalFee::on_unbalanced(
+			T::Currency::withdraw(
+				&who,
+				T::ProposalFeeAmount::get(),
+				WithdrawReasons::FEE,
+				ExistenceRequirement::KeepAlive
+			)?
+		);
 
 		let index = Self::public_prop_count();
 		let real_prop_count = PublicProps::<T>::decode_len().unwrap_or(0) as u32;
diff --git a/frame/democracy/src/tests.rs b/frame/democracy/src/tests.rs
index b0ab7b9c99..0e3155c426 100644
--- a/frame/democracy/src/tests.rs
+++ b/frame/democracy/src/tests.rs
@@ -332,7 +332,7 @@ impl Config for Test {
 
 pub fn new_test_ext() -> sp_io::TestExternalities {
 	let mut t = frame_system::GenesisConfig::default().build_storage::<Test>().unwrap();
-	let balances = vec![(1, 10), (2, 20), (3, 30), (4, 40), (5, 50), (6, 60)];
+	let balances = vec![(1, 100), (2, 200), (3, 300), (4, 400), (5, 500), (6, 600)];
 	let mut llm_balances: Vec<(u64, u64, u64)> = balances.iter().map(|(id, _)| (*id, 6000, 5000)).collect();
 	llm_balances.push((7, 1000, 1000));
 
@@ -360,7 +360,7 @@ fn params_should_work() {
 	new_test_ext().execute_with(|| {
 		assert_eq!(Democracy::referendum_count(), 0);
 		assert_eq!(Balances::free_balance(42), 0);
-		assert_eq!(Balances::total_issuance(), 210);
+		assert_eq!(Balances::total_issuance(), 2100);
 	});
 }
 
@@ -396,6 +396,7 @@ fn fast_forward_to(n: u64) {
 
 fn begin_referendum() -> ReferendumIndex {
 	System::set_block_number(0);
+	Balances::make_free_balance_be(&1, 100);
 	assert_ok!(propose_set_balance(1, 2, 1));
 	fast_forward_to(2);
 	0
diff --git a/frame/democracy/src/tests/delegation.rs b/frame/democracy/src/tests/delegation.rs
index b320648587..90091edf9e 100644
--- a/frame/democracy/src/tests/delegation.rs
+++ b/frame/democracy/src/tests/delegation.rs
@@ -36,19 +36,19 @@ fn single_proposal_should_work_with_delegation() {
 		assert_ok!(Democracy::delegate(RuntimeOrigin::signed(2), 1, Conviction::None, 20));
 		let r = 0;
 		assert_ok!(Democracy::vote(RuntimeOrigin::signed(1), r, aye(1)));
-		assert_eq!(tally(r), Tally { ayes: 20, nays: 0, turnout: 20, aye_voters: 20000, nay_voters: 0 });
+		assert_eq!(tally(r), Tally { ayes: 110, nays: 0, turnout: 110, aye_voters: 20000, nay_voters: 0 });
 
 		// Delegate a second vote.
 		assert_ok!(Democracy::delegate(RuntimeOrigin::signed(3), 1, Conviction::None, 30));
-		assert_eq!(tally(r), Tally { ayes: 50, nays: 0, turnout: 50, aye_voters: 30000, nay_voters: 0 });
+		assert_eq!(tally(r), Tally { ayes: 140, nays: 0, turnout: 140, aye_voters: 30000, nay_voters: 0 });
 
 		// Reduce first vote.
 		assert_ok!(Democracy::delegate(RuntimeOrigin::signed(2), 1, Conviction::None, 10));
-		assert_eq!(tally(r), Tally { ayes: 40, nays: 0, turnout: 40, aye_voters: 30000, nay_voters: 0 });
+		assert_eq!(tally(r), Tally { ayes: 130, nays: 0, turnout: 130, aye_voters: 30000, nay_voters: 0 });
 
 		// Second vote delegates to first; we don't do tiered delegation, so it doesn't get used.
 		assert_ok!(Democracy::delegate(RuntimeOrigin::signed(3), 2, Conviction::None, 30));
-		assert_eq!(tally(r), Tally { ayes: 10, nays: 0, turnout: 10, aye_voters: 20000, nay_voters: 0 });
+		assert_eq!(tally(r), Tally { ayes: 100, nays: 0, turnout: 100, aye_voters: 20000, nay_voters: 0 });
 
 		// Main voter cancels their vote
 		assert_ok!(Democracy::remove_vote(RuntimeOrigin::signed(1), r));
@@ -60,7 +60,7 @@ fn single_proposal_should_work_with_delegation() {
 
 		// Main voter reinstates their vote
 		assert_ok!(Democracy::vote(RuntimeOrigin::signed(1), r, aye(1)));
-		assert_eq!(tally(r), Tally { ayes: 10, nays: 0, turnout: 10, aye_voters: 20000, nay_voters: 0 });
+		assert_eq!(tally(r), Tally { ayes: 100, nays: 0, turnout: 100, aye_voters: 20000, nay_voters: 0 });
 	});
 }
 
@@ -78,7 +78,6 @@ fn self_delegation_not_allowed() {
 fn cyclic_delegation_should_unwind() {
 	new_test_ext().execute_with(|| {
 		System::set_block_number(0);
-
 		assert_ok!(propose_set_balance(1, 2, 1));
 
 		fast_forward_to(2);
@@ -94,7 +93,7 @@ fn cyclic_delegation_should_unwind() {
 		assert_ok!(Democracy::vote(RuntimeOrigin::signed(1), r, nay(1)));
 
 		// Delegated vote is counted.
-		assert_eq!(tally(r), Tally { ayes: 30, nays: 20, turnout: 50, aye_voters: 10000, nay_voters: 20000  });
+		assert_eq!(tally(r), Tally { ayes: 300, nays: 110, turnout: 410, aye_voters: 10000, nay_voters: 20000  });
 	});
 }
 
@@ -111,13 +110,13 @@ fn single_proposal_should_work_with_vote_and_delegation() {
 		let r = 0;
 		assert_ok!(Democracy::vote(RuntimeOrigin::signed(1), r, aye(1)));
 		assert_ok!(Democracy::vote(RuntimeOrigin::signed(2), r, nay(2)));
-		assert_eq!(tally(r), Tally { ayes: 0, nays: 20, turnout: 20, aye_voters: 10000, nay_voters: 10000  });
+		assert_eq!(tally(r), Tally { ayes: 90, nays: 200, turnout: 290, aye_voters: 10000, nay_voters: 10000  });
 
 		// Delegate vote.
 		assert_ok!(Democracy::remove_vote(RuntimeOrigin::signed(2), r));
 		assert_ok!(Democracy::delegate(RuntimeOrigin::signed(2), 1, Conviction::None, 20));
 		// Delegated vote replaces the explicit vote.
-		assert_eq!(tally(r), Tally { ayes: 20, nays: 0, turnout: 20 , aye_voters: 20000, nay_voters: 0 });
+		assert_eq!(tally(r), Tally { ayes: 110, nays: 0, turnout: 110 , aye_voters: 20000, nay_voters: 0 });
 	});
 }
 
@@ -137,7 +136,7 @@ fn single_proposal_should_work_with_undelegation() {
 		assert_ok!(Democracy::vote(RuntimeOrigin::signed(1), r, aye(1)));
 
 		// Delegated vote is not counted.
-		assert_eq!(tally(r), Tally { ayes: 0, nays: 0, turnout: 0, aye_voters: 10000, nay_voters: 0  });
+		assert_eq!(tally(r), Tally { ayes: 90, nays: 0, turnout: 90, aye_voters: 10000, nay_voters: 0  });
 	});
 }
 
@@ -149,11 +148,11 @@ fn single_proposal_should_work_with_delegation_and_vote() {
 		// Delegate, undelegate and vote.
 		assert_ok!(Democracy::vote(RuntimeOrigin::signed(1), r, aye(1)));
 		assert_ok!(Democracy::delegate(RuntimeOrigin::signed(2), 1, Conviction::None, 20));
-		assert_eq!(tally(r), Tally { ayes: 20, nays: 0, turnout: 20, aye_voters: 20000, nay_voters: 0  });
+		assert_eq!(tally(r), Tally { ayes: 110, nays: 0, turnout: 110, aye_voters: 20000, nay_voters: 0  });
 		assert_ok!(Democracy::undelegate(RuntimeOrigin::signed(2)));
 		assert_ok!(Democracy::vote(RuntimeOrigin::signed(2), r, aye(2)));
 		// Delegated vote is not counted.
-		assert_eq!(tally(r), Tally { ayes: 20, nays: 0, turnout: 20, aye_voters: 20000, nay_voters: 0  });
+		assert_eq!(tally(r), Tally { ayes: 290, nays: 0, turnout: 290, aye_voters: 20000, nay_voters: 0  });
 	});
 }
 
@@ -166,7 +165,7 @@ fn conviction_should_be_honored_in_delegation() {
 		assert_ok!(Democracy::delegate(RuntimeOrigin::signed(2), 1, Conviction::Locked6x, 20));
 		assert_ok!(Democracy::vote(RuntimeOrigin::signed(1), r, aye(1)));
 		// Delegated vote is huge.
-		assert_eq!(tally(r), Tally { ayes: 20, nays: 0, turnout: 20, aye_voters: 20000, nay_voters: 0  });
+		assert_eq!(tally(r), Tally { ayes: 110, nays: 0, turnout: 110, aye_voters: 20000, nay_voters: 0  });
 	});
 }
 
@@ -195,7 +194,7 @@ fn redelegation_keeps_lock() {
 		assert_ok!(Democracy::delegate(RuntimeOrigin::signed(2), 1, Conviction::Locked6x, 20));
 		assert_ok!(Democracy::vote(RuntimeOrigin::signed(1), r, aye(1)));
 		// Delegated vote is huge.
-		assert_eq!(tally(r), Tally { ayes: 20, nays: 0, turnout: 20, aye_voters: 20000, nay_voters: 0  });
+		assert_eq!(tally(r), Tally { ayes: 110, nays: 0, turnout: 110, aye_voters: 20000, nay_voters: 0  });
 
 		let mut prior_lock = vote::PriorLock::default();
 
diff --git a/frame/democracy/src/tests/public_proposals.rs b/frame/democracy/src/tests/public_proposals.rs
index b68cd44b39..e3ae7f9016 100644
--- a/frame/democracy/src/tests/public_proposals.rs
+++ b/frame/democracy/src/tests/public_proposals.rs
@@ -45,9 +45,9 @@ fn deposit_for_proposals_should_be_taken() {
 		assert_ok!(Democracy::second(RuntimeOrigin::signed(5), 0));
 		// liberland specific - free balance shouldn't change, seconds shouldn't
 		// lock anything
-		assert_eq!(Balances::free_balance(1), 0);
-		assert_eq!(Balances::free_balance(2), 20);
-		assert_eq!(Balances::free_balance(5), 50);
+		assert_eq!(Balances::free_balance(1), 90);
+		assert_eq!(Balances::free_balance(2), 200);
+		assert_eq!(Balances::free_balance(5), 500);
 	});
 }
 
@@ -60,9 +60,23 @@ fn deposit_for_proposals_should_be_returned() {
 		assert_ok!(Democracy::second(RuntimeOrigin::signed(5), 0));
 		assert_ok!(Democracy::second(RuntimeOrigin::signed(5), 0));
 		fast_forward_to(3);
-		assert_eq!(Balances::free_balance(1), 0);
-		assert_eq!(Balances::free_balance(2), 20);
-		assert_eq!(Balances::free_balance(5), 50);
+		assert_eq!(Balances::free_balance(1), 90);
+		assert_eq!(Balances::free_balance(2), 200);
+		assert_eq!(Balances::free_balance(5), 500);
+	});
+}
+
+#[test]
+fn proposal_with_funds_below_save_value_should_not_work() {
+	new_test_ext().execute_with(|| {
+		assert_ok!(propose_set_balance(1, 2, 5));
+
+		Balances::make_free_balance_be(&1, 0);
+
+		assert_noop!(
+			propose_set_balance(1, 2, 0), 
+			pallet_balances::Error::<Test, _>::InsufficientBalance,
+	);
 	});
 }
 
@@ -71,7 +85,12 @@ fn proposal_with_funds_below_minimum_should_not_work() {
 	new_test_ext().execute_with(|| {
 		assert_ok!(propose_set_balance(1, 2, 5));
 
-		assert_noop!(propose_set_balance(1, 2, 0), Error::<Test>::InsufficientFunds);
+		Balances::make_free_balance_be(&1, 10);
+		
+		assert_noop!(
+			propose_set_balance(1, 2, 0), 
+			pallet_balances::pallet::Error::<Test>::Expendability
+	);
 	});
 }
 
@@ -79,11 +98,11 @@ fn proposal_with_funds_below_minimum_should_not_work() {
 fn creating_proposal_takes_fee() {
 	new_test_ext().execute_with(|| {
 		System::set_block_number(0);
-		assert_eq!(Balances::total_balance(&1), 10);
+		assert_eq!(Balances::total_balance(&1), 100);
 
 		assert_ok!(propose_set_balance(1, 2, 5));
 
-		assert_eq!(Balances::total_balance(&1), 0);
+		assert_eq!(Balances::total_balance(&1), 90);
 		
 	});
 }
diff --git a/frame/democracy/src/tests/scheduling.rs b/frame/democracy/src/tests/scheduling.rs
index c158f796bc..0f8556f2e9 100644
--- a/frame/democracy/src/tests/scheduling.rs
+++ b/frame/democracy/src/tests/scheduling.rs
@@ -34,7 +34,7 @@ fn simple_passing_should_work() {
 			0,
 		);
 		assert_ok!(Democracy::vote(RuntimeOrigin::signed(1), r, aye(1)));
-		assert_eq!(tally(r), Tally { ayes: 10, nays: 0, turnout: 10, aye_voters: 10000, nay_voters: 0  });
+		assert_eq!(tally(r), Tally { ayes: 100, nays: 0, turnout: 100, aye_voters: 10000, nay_voters: 0  });
 		assert_eq!(Democracy::lowest_unbaked(), 0);
 		next_block();
 		next_block();
@@ -54,7 +54,7 @@ fn simple_failing_should_work() {
 			0,
 		);
 		assert_ok!(Democracy::vote(RuntimeOrigin::signed(1), r, nay(1)));
-		assert_eq!(tally(r), Tally { ayes: 0, nays: 10, turnout: 10, aye_voters: 00000, nay_voters: 10000  });
+		assert_eq!(tally(r), Tally { ayes: 0, nays: 100, turnout: 100, aye_voters: 00000, nay_voters: 10000  });
 
 		next_block();
 		next_block();
@@ -82,12 +82,12 @@ fn ooo_inject_referendums_should_work() {
 		);
 
 		assert_ok!(Democracy::vote(RuntimeOrigin::signed(1), r2, aye(1)));
-		assert_eq!(tally(r2), Tally { ayes: 10, nays: 0, turnout: 10, aye_voters: 10000, nay_voters: 0  });
+		assert_eq!(tally(r2), Tally { ayes: 100, nays: 0, turnout: 100, aye_voters: 10000, nay_voters: 0  });
 
 		next_block();
 
 		assert_ok!(Democracy::vote(RuntimeOrigin::signed(1), r1, aye(1)));
-		assert_eq!(tally(r1), Tally { ayes: 10, nays: 0, turnout: 10, aye_voters: 10000, nay_voters: 0  });
+		assert_eq!(tally(r1), Tally { ayes: 100, nays: 0, turnout: 100, aye_voters: 10000, nay_voters: 0  });
 
 		next_block();
 		assert_eq!(Balances::free_balance(42), 2);
@@ -114,7 +114,7 @@ fn delayed_enactment_should_work() {
 		assert_ok!(Democracy::vote(RuntimeOrigin::signed(5), r, aye(5)));
 		assert_ok!(Democracy::vote(RuntimeOrigin::signed(6), r, aye(6)));
 
-		assert_eq!(tally(r), Tally { ayes: 210, nays: 0, turnout: 210, aye_voters: 60000, nay_voters: 0  });
+		assert_eq!(tally(r), Tally { ayes: 2100, nays: 0, turnout: 2100, aye_voters: 60000, nay_voters: 0  });
 
 		next_block();
 		assert_eq!(Balances::free_balance(42), 0);
diff --git a/frame/democracy/src/tests/voting.rs b/frame/democracy/src/tests/voting.rs
index 89a2d8e659..dc005ae4df 100644
--- a/frame/democracy/src/tests/voting.rs
+++ b/frame/democracy/src/tests/voting.rs
@@ -84,7 +84,7 @@ fn single_proposal_should_work() {
 				dispatch_origin: DispatchOrigin::Root, 
 				threshold: VoteThreshold::SuperMajorityApprove,
 				delay: 2,
-				tally: Tally { ayes: 20, nays: 0, turnout: 20, aye_voters: 10000, nay_voters: 0  },
+				tally: Tally { ayes: 200, nays: 0, turnout: 200, aye_voters: 10000, nay_voters: 0  },
 			})
 		);
 
@@ -147,7 +147,7 @@ fn controversial_low_turnout_voting_should_work() {
 		assert_ok!(Democracy::vote(RuntimeOrigin::signed(5), r, big_nay(5)));
 		assert_ok!(Democracy::vote(RuntimeOrigin::signed(6), r, big_aye(6)));
 
-		assert_eq!(tally(r), Tally { ayes: 60, nays: 50, turnout: 110, aye_voters: 10000, nay_voters: 10000  });
+		assert_eq!(tally(r), Tally { ayes: 600, nays: 500, turnout: 1100, aye_voters: 10000, nay_voters: 10000  });
 
 		next_block();
 		next_block();
@@ -160,7 +160,7 @@ fn controversial_low_turnout_voting_should_work() {
 fn passing_low_turnout_voting_should_work() {
 	new_test_ext().execute_with(|| {
 		assert_eq!(Balances::free_balance(42), 0);
-		assert_eq!(Balances::total_issuance(), 210);
+		assert_eq!(Balances::total_issuance(), 2100);
 
 		let r = Democracy::inject_referendum(
 			2,