|
@@ -35,19 +35,21 @@
|
|
|
// used dependencies
|
|
|
use codec::{Codec, Decode, Encode};
|
|
|
use core::marker::PhantomData;
|
|
|
-use frame_support::traits::{
|
|
|
- Currency, EnsureOrigin, Get, LockIdentifier, LockableCurrency, WithdrawReason,
|
|
|
-};
|
|
|
+use frame_support::traits::{EnsureOrigin, Get, WithdrawReason};
|
|
|
use frame_support::weights::Weight;
|
|
|
use frame_support::{
|
|
|
- decl_error, decl_event, decl_module, decl_storage, error::BadOrigin, Parameter, StorageValue,
|
|
|
+ decl_error, decl_event, decl_module, decl_storage, ensure, error::BadOrigin, Parameter,
|
|
|
+ StorageValue,
|
|
|
};
|
|
|
use frame_system::ensure_signed;
|
|
|
use sp_arithmetic::traits::BaseArithmetic;
|
|
|
use sp_runtime::traits::{MaybeSerialize, Member};
|
|
|
+use sp_runtime::SaturatedConversion;
|
|
|
use sp_std::vec;
|
|
|
use sp_std::vec::Vec;
|
|
|
|
|
|
+use staking_handler::StakingHandler;
|
|
|
+
|
|
|
#[cfg(feature = "std")]
|
|
|
use serde::{Deserialize, Serialize};
|
|
|
|
|
@@ -95,10 +97,14 @@ pub struct ReferendumStageVoting<BlockNumber> {
|
|
|
#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
|
|
|
#[derive(Encode, Decode, PartialEq, Eq, Debug, Default)]
|
|
|
pub struct ReferendumStageRevealing<BlockNumber, MemberId, VotePower> {
|
|
|
- pub started: BlockNumber, // block in which referendum started
|
|
|
- pub winning_target_count: u64, // target number of winners
|
|
|
- pub intermediate_winners: Vec<OptionResult<MemberId, VotePower>>, // intermediate winning options
|
|
|
- pub current_cycle_id: u64, // index of current election
|
|
|
+ // block in which referendum started
|
|
|
+ pub started: BlockNumber,
|
|
|
+ // target number of winners
|
|
|
+ pub winning_target_count: u64,
|
|
|
+ // intermediate winning options
|
|
|
+ pub intermediate_winners: Vec<OptionResult<MemberId, VotePower>>,
|
|
|
+ // index of current election
|
|
|
+ pub current_cycle_id: u64,
|
|
|
}
|
|
|
|
|
|
#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
|
|
@@ -112,22 +118,26 @@ pub struct OptionResult<MemberId, VotePower> {
|
|
|
#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
|
|
|
#[derive(Encode, Decode, PartialEq, Eq, Debug, Default)]
|
|
|
pub struct CastVote<Hash, Currency, MemberId> {
|
|
|
- pub commitment: Hash, // a commitment that a user submits in the voting stage before revealing what this vote is actually for
|
|
|
- pub cycle_id: u64, // current referendum cycle number
|
|
|
- pub stake: Currency, // stake locked for vote
|
|
|
- pub vote_for: Option<MemberId>, // target option this vote favors; is `None` before the vote is revealed
|
|
|
+ // A commitment that a user submits in the voting stage before revealing what this vote is
|
|
|
+ // actually for
|
|
|
+ pub commitment: Hash,
|
|
|
+ // current referendum cycle number
|
|
|
+ pub cycle_id: u64,
|
|
|
+ // stake locked for vote
|
|
|
+ pub stake: Currency,
|
|
|
+ // target option this vote favors; is `None` before the vote is revealed
|
|
|
+ pub vote_for: Option<MemberId>,
|
|
|
}
|
|
|
|
|
|
/////////////////// Type aliases ///////////////////////////////////////////////
|
|
|
|
|
|
-// `Ez` prefix in some of the following type aliases means *easy* and is meant to create unique short names
|
|
|
-// aliasing existing structs and enums
|
|
|
+// `Ez` prefix in some of the following type aliases means *easy* and is meant to create unique
|
|
|
+// short names aliasing existing structs and enums
|
|
|
|
|
|
// types simplifying access to common structs and enums
|
|
|
-pub type Balance<T, I> =
|
|
|
- <<T as Trait<I>>::Currency as Currency<<T as frame_system::Trait>::AccountId>>::Balance;
|
|
|
-pub type CastVoteOf<T, I> =
|
|
|
- CastVote<<T as frame_system::Trait>::Hash, Balance<T, I>, <T as common::Trait>::MemberId>;
|
|
|
+pub type BalanceOf<T> = <T as balances::Trait>::Balance;
|
|
|
+pub type CastVoteOf<T> =
|
|
|
+ CastVote<<T as frame_system::Trait>::Hash, BalanceOf<T>, <T as common::Trait>::MemberId>;
|
|
|
pub type ReferendumStageVotingOf<T> =
|
|
|
ReferendumStageVoting<<T as frame_system::Trait>::BlockNumber>;
|
|
|
pub type ReferendumStageRevealingOf<T, I> = ReferendumStageRevealing<
|
|
@@ -142,7 +152,7 @@ pub type OptionResultOf<T, I> =
|
|
|
pub type CanRevealResult<T, I> = (
|
|
|
ReferendumStageRevealingOf<T, I>,
|
|
|
<T as frame_system::Trait>::AccountId,
|
|
|
- CastVoteOf<T, I>,
|
|
|
+ CastVoteOf<T>,
|
|
|
);
|
|
|
|
|
|
/////////////////// Traits, Storage, Errors, and Events /////////////////////////
|
|
@@ -160,7 +170,7 @@ pub trait WeightInfo {
|
|
|
fn release_vote_stake() -> Weight;
|
|
|
}
|
|
|
|
|
|
-const MAX_WINNERS: u32 = 500; // TODO: Replace with a trait type
|
|
|
+type ReferendumWeightInfo<T, I> = <T as Trait<I>>::WeightInfo;
|
|
|
|
|
|
/// Trait that should be used by other modules to start the referendum, etc.
|
|
|
pub trait ReferendumManager<Origin, AccountId, MemberId, Hash> {
|
|
@@ -174,9 +184,6 @@ pub trait ReferendumManager<Origin, AccountId, MemberId, Hash> {
|
|
|
+ MaybeSerialize
|
|
|
+ PartialEq;
|
|
|
|
|
|
- /// Currency for referendum staking.
|
|
|
- type Currency: LockableCurrency<AccountId>;
|
|
|
-
|
|
|
/// Start a new referendum.
|
|
|
fn start_referendum(
|
|
|
origin: Origin,
|
|
@@ -185,7 +192,10 @@ pub trait ReferendumManager<Origin, AccountId, MemberId, Hash> {
|
|
|
) -> Result<(), ()>;
|
|
|
|
|
|
/// Start referendum independent of the current state.
|
|
|
- /// If an election is running before calling this function, it will be discontinued without any winners selected.
|
|
|
+ /// If an election is running before calling this function, it will be discontinued without
|
|
|
+ /// any winners selected.
|
|
|
+ /// If it is called with a bigger winning target count greated than the max allowed the max
|
|
|
+ /// will be used
|
|
|
fn force_start(extra_winning_target_count: u64, cycle_id: u64);
|
|
|
|
|
|
/// Calculate commitment for a vote.
|
|
@@ -198,18 +208,18 @@ pub trait ReferendumManager<Origin, AccountId, MemberId, Hash> {
|
|
|
}
|
|
|
|
|
|
/// The main Referendum module's trait.
|
|
|
-pub trait Trait<I: Instance = DefaultInstance>: frame_system::Trait + common::Trait {
|
|
|
+pub trait Trait<I: Instance = DefaultInstance>:
|
|
|
+ frame_system::Trait + common::Trait + balances::Trait
|
|
|
+{
|
|
|
/// The overarching event type.
|
|
|
type Event: From<Event<Self, I>> + Into<<Self as frame_system::Trait>::Event>;
|
|
|
|
|
|
- /// Maximum length of vote commitment salt. Use length that ensures uniqueness for hashing e.g. std::u64::MAX.
|
|
|
+ /// Maximum length of vote commitment salt. Use length that ensures uniqueness for hashing
|
|
|
+ /// e.g. std::u64::MAX.
|
|
|
type MaxSaltLength: Get<u64>;
|
|
|
|
|
|
- /// Currency for referendum staking.
|
|
|
- type Currency: LockableCurrency<Self::AccountId, Moment = Self::BlockNumber>;
|
|
|
-
|
|
|
- /// Identifier for currency locks used for staking.
|
|
|
- type LockId: Get<LockIdentifier>;
|
|
|
+ /// Stakes and balance locks handler.
|
|
|
+ type StakingHandler: StakingHandler<Self::AccountId, BalanceOf<Self>, Self::MemberId>;
|
|
|
|
|
|
/// Origin from which the referendum can be started.
|
|
|
type ManagerOrigin: EnsureOrigin<Self::Origin>;
|
|
@@ -230,21 +240,23 @@ pub trait Trait<I: Instance = DefaultInstance>: frame_system::Trait + common::Tr
|
|
|
type RevealStageDuration: Get<Self::BlockNumber>;
|
|
|
|
|
|
/// Minimum stake needed for voting
|
|
|
- type MinimumStake: Get<Balance<Self, I>>;
|
|
|
+ type MinimumStake: Get<BalanceOf<Self>>;
|
|
|
|
|
|
/// Weight information for extrinsics in this pallet.
|
|
|
type WeightInfo: WeightInfo;
|
|
|
|
|
|
+ /// Maximum number of winning target count
|
|
|
+ type MaxWinnerTargetCount: Get<u64>;
|
|
|
+
|
|
|
/// Calculate the vote's power for user and his stake.
|
|
|
fn calculate_vote_power(
|
|
|
account_id: &<Self as frame_system::Trait>::AccountId,
|
|
|
- stake: &Balance<Self, I>,
|
|
|
+ stake: &BalanceOf<Self>,
|
|
|
) -> <Self as Trait<I>>::VotePower;
|
|
|
|
|
|
/// Checks if user can unlock his stake from the given vote.
|
|
|
/// Gives runtime an ability to penalize user for not revealing stake, etc.
|
|
|
- fn can_unlock_vote_stake(vote: &CastVote<Self::Hash, Balance<Self, I>, Self::MemberId>)
|
|
|
- -> bool;
|
|
|
+ fn can_unlock_vote_stake(vote: &CastVote<Self::Hash, BalanceOf<Self>, Self::MemberId>) -> bool;
|
|
|
|
|
|
/// Gives runtime an ability to react on referendum result.
|
|
|
fn process_results(winners: &[OptionResult<Self::MemberId, Self::VotePower>]);
|
|
@@ -252,30 +264,36 @@ pub trait Trait<I: Instance = DefaultInstance>: frame_system::Trait + common::Tr
|
|
|
/// Check if an option a user is voting for actually exists.
|
|
|
fn is_valid_option_id(option_id: &Self::MemberId) -> bool;
|
|
|
|
|
|
- // If the id is a valid alternative, the current total voting mass backing it is returned, otherwise nothing.
|
|
|
+ /// If the id is a valid alternative, the current total voting mass backing it is returned,
|
|
|
+ /// otherwise nothing.
|
|
|
fn get_option_power(option_id: &Self::MemberId) -> Self::VotePower;
|
|
|
|
|
|
- // Increases voting mass behind given alternative by given amount, if present and return true, otherwise return false.
|
|
|
+ /// Increases voting mass behind given alternative by given amount, if present and return true,
|
|
|
+ /// otherwise return false.
|
|
|
fn increase_option_power(option_id: &Self::MemberId, amount: &Self::VotePower);
|
|
|
}
|
|
|
|
|
|
decl_storage! {
|
|
|
trait Store for Module<T: Trait<I>, I: Instance = DefaultInstance> as Referendum {
|
|
|
/// Current referendum stage.
|
|
|
- pub Stage get(fn stage) config(): ReferendumStage<T::BlockNumber, T::MemberId, T::VotePower>;
|
|
|
+ pub Stage get(fn stage) config():
|
|
|
+ ReferendumStage<T::BlockNumber, T::MemberId, T::VotePower>;
|
|
|
|
|
|
- /// Votes cast in the referendum. A new record is added to this map when a user casts a sealed vote.
|
|
|
+ /// Votes cast in the referendum. A new record is added to this map when a user casts a
|
|
|
+ /// sealed vote.
|
|
|
/// It is modified when a user reveals the vote's commitment proof.
|
|
|
- /// A record is finally removed when the user unstakes, which can happen during a voting stage or after the current cycle ends.
|
|
|
+ /// A record is finally removed when the user unstakes, which can happen during a voting
|
|
|
+ /// stage or after the current cycle ends.
|
|
|
/// A stake for a vote can be reused in future referendum cycles.
|
|
|
- pub Votes get(fn votes) config(): map hasher(blake2_128_concat) T::AccountId => CastVoteOf<T, I>;
|
|
|
+ pub Votes get(fn votes) config(): map hasher(blake2_128_concat)
|
|
|
+ T::AccountId => CastVoteOf<T>;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
decl_event! {
|
|
|
pub enum Event<T, I = DefaultInstance>
|
|
|
where
|
|
|
- Balance = Balance<T, I>,
|
|
|
+ Balance = BalanceOf<T>,
|
|
|
<T as frame_system::Trait>::Hash,
|
|
|
<T as frame_system::Trait>::AccountId,
|
|
|
<T as Trait<I>>::VotePower,
|
|
@@ -316,8 +334,11 @@ decl_error! {
|
|
|
/// Revealing stage is not in progress right now
|
|
|
RevealingNotInProgress,
|
|
|
|
|
|
- /// Account can't stake enough currency (now)
|
|
|
- InsufficientBalanceToStakeCurrency,
|
|
|
+ /// Staking account contains conflicting stakes.
|
|
|
+ ConflictStakesOnAccount,
|
|
|
+
|
|
|
+ /// Account Insufficient Free Balance (now)
|
|
|
+ InsufficientBalanceToStake,
|
|
|
|
|
|
/// Insufficient stake provided to cast a vote
|
|
|
InsufficientStake,
|
|
@@ -360,23 +381,23 @@ impl<T: Trait<I>, I: Instance> From<BadOrigin> for Error<T, I> {
|
|
|
/////////////////// Module definition and implementation ///////////////////////
|
|
|
|
|
|
decl_module! {
|
|
|
- pub struct Module<T: Trait<I>, I: Instance = DefaultInstance> for enum Call where origin: T::Origin {
|
|
|
+ pub struct Module<T: Trait<I>, I: Instance = DefaultInstance> for enum Call
|
|
|
+ where origin: T::Origin {
|
|
|
/// Predefined errors
|
|
|
type Error = Error<T, I>;
|
|
|
|
|
|
/// Setup events
|
|
|
fn deposit_event() = default;
|
|
|
|
|
|
- /// Maximum length of vote commitment salt. Use length that ensures uniqueness for hashing e.g. std::u64::MAX.
|
|
|
+ /// Maximum length of vote commitment salt. Use length that ensures uniqueness for hashing
|
|
|
+ /// e.g. std::u64::MAX.
|
|
|
const MaxSaltLength: u64 = T::MaxSaltLength::get();
|
|
|
- /// Identifier for currency locks used for staking.
|
|
|
- const LockId: LockIdentifier = T::LockId::get();
|
|
|
/// Duration of voting stage (number of blocks)
|
|
|
const VoteStageDuration: T::BlockNumber = T::VoteStageDuration::get();
|
|
|
/// Duration of revealing stage (number of blocks)
|
|
|
const RevealStageDuration: T::BlockNumber = T::RevealStageDuration::get();
|
|
|
/// Minimum stake needed for voting
|
|
|
- const MinimumStake: Balance<T, I> = T::MinimumStake::get();
|
|
|
+ const MinimumStake: BalanceOf<T> = T::MinimumStake::get();
|
|
|
|
|
|
/////////////////// Lifetime ///////////////////////////////////////////
|
|
|
|
|
@@ -384,8 +405,10 @@ decl_module! {
|
|
|
fn on_initialize() -> Weight {
|
|
|
Self::try_progress_stage(frame_system::Module::<T>::block_number());
|
|
|
|
|
|
- T::WeightInfo::on_initialize_voting()
|
|
|
- .max(T::WeightInfo::on_initialize_revealing(MAX_WINNERS))
|
|
|
+ ReferendumWeightInfo::<T, I>::on_initialize_voting()
|
|
|
+ .max(ReferendumWeightInfo::<T, I>::on_initialize_revealing(
|
|
|
+ T::MaxWinnerTargetCount::get().saturated_into()
|
|
|
+ ))
|
|
|
}
|
|
|
|
|
|
/////////////////// User actions ///////////////////////////////////////
|
|
@@ -399,8 +422,8 @@ decl_module! {
|
|
|
/// - db:
|
|
|
/// - `O(1)` doesn't depend on the state or parameters
|
|
|
/// # </weight>
|
|
|
- #[weight = T::WeightInfo::vote()]
|
|
|
- pub fn vote(origin, commitment: T::Hash, stake: Balance<T, I>) -> Result<(), Error<T, I>> {
|
|
|
+ #[weight = ReferendumWeightInfo::<T, I>::vote()]
|
|
|
+ pub fn vote(origin, commitment: T::Hash, stake: BalanceOf<T>) -> Result<(), Error<T, I>> {
|
|
|
// ensure action can be started
|
|
|
let (current_cycle_id, account_id) = EnsureChecks::<T, I>::can_vote(origin, &stake)?;
|
|
|
|
|
@@ -423,13 +446,21 @@ decl_module! {
|
|
|
///
|
|
|
/// ## Weight
|
|
|
/// `O (W)` where:
|
|
|
- /// - `W` is the number of `intermediate_winners` stored in the current `Stage::<T, I>::get()`
|
|
|
+ /// - `W` is the number of `intermediate_winners` stored in the current
|
|
|
+ /// `Stage::<T, I>::get()`
|
|
|
/// - DB:
|
|
|
/// - `O(1)` doesn't depend on the state or parameters
|
|
|
/// # </weight>
|
|
|
- #[weight = Module::<T, I>::calculate_reveal_vote_weight(MAX_WINNERS)]
|
|
|
- pub fn reveal_vote(origin, salt: Vec<u8>, vote_option_id: <T as common::Trait>::MemberId) -> Result<(), Error<T, I>> {
|
|
|
- let (stage_data, account_id, cast_vote) = EnsureChecks::<T, I>::can_reveal_vote::<Self>(origin, &salt, &vote_option_id)?;
|
|
|
+ #[weight = Module::<T, I>::calculate_reveal_vote_weight(
|
|
|
+ T::MaxWinnerTargetCount::get().saturated_into()
|
|
|
+ )]
|
|
|
+ pub fn reveal_vote(
|
|
|
+ origin,
|
|
|
+ salt: Vec<u8>,
|
|
|
+ vote_option_id: <T as common::Trait>::MemberId
|
|
|
+ ) -> Result<(), Error<T, I>> {
|
|
|
+ let (stage_data, account_id, cast_vote) =
|
|
|
+ EnsureChecks::<T, I>::can_reveal_vote::<Self>(origin, &salt, &vote_option_id)?;
|
|
|
|
|
|
//
|
|
|
// == MUTATION SAFE ==
|
|
@@ -452,7 +483,7 @@ decl_module! {
|
|
|
/// - db:
|
|
|
/// - `O(1)` doesn't depend on the state or parameters
|
|
|
/// # </weight>
|
|
|
- #[weight = T::WeightInfo::release_vote_stake()]
|
|
|
+ #[weight = ReferendumWeightInfo::<T, I>::release_vote_stake()]
|
|
|
pub fn release_vote_stake(origin) -> Result<(), Error<T, I>> {
|
|
|
let account_id = EnsureChecks::<T, I>::can_release_vote_stake(origin)?;
|
|
|
|
|
@@ -476,17 +507,19 @@ decl_module! {
|
|
|
impl<T: Trait<I>, I: Instance> Module<T, I> {
|
|
|
// Calculate reveal_vote weight
|
|
|
fn calculate_reveal_vote_weight(number_of_winners: u32) -> Weight {
|
|
|
- T::WeightInfo::reveal_vote_space_for_new_winner(number_of_winners)
|
|
|
- .max(T::WeightInfo::reveal_vote_space_not_in_winners(
|
|
|
- number_of_winners,
|
|
|
- ))
|
|
|
- .max(T::WeightInfo::reveal_vote_space_replace_last_winner(
|
|
|
- number_of_winners,
|
|
|
- ))
|
|
|
- .max(T::WeightInfo::reveal_vote_space_replace_last_winner(
|
|
|
- number_of_winners,
|
|
|
- ))
|
|
|
- .max(T::WeightInfo::reveal_vote_already_existing(
|
|
|
+ ReferendumWeightInfo::<T, I>::reveal_vote_space_for_new_winner(number_of_winners)
|
|
|
+ .max(ReferendumWeightInfo::<T, I>::reveal_vote_space_not_in_winners(number_of_winners))
|
|
|
+ .max(
|
|
|
+ ReferendumWeightInfo::<T, I>::reveal_vote_space_replace_last_winner(
|
|
|
+ number_of_winners,
|
|
|
+ ),
|
|
|
+ )
|
|
|
+ .max(
|
|
|
+ ReferendumWeightInfo::<T, I>::reveal_vote_space_replace_last_winner(
|
|
|
+ number_of_winners,
|
|
|
+ ),
|
|
|
+ )
|
|
|
+ .max(ReferendumWeightInfo::<T, I>::reveal_vote_already_existing(
|
|
|
number_of_winners,
|
|
|
))
|
|
|
}
|
|
@@ -536,7 +569,6 @@ impl<T: Trait<I>, I: Instance> ReferendumManager<T::Origin, T::AccountId, T::Mem
|
|
|
for Module<T, I>
|
|
|
{
|
|
|
type VotePower = T::VotePower;
|
|
|
- type Currency = T::Currency;
|
|
|
|
|
|
// Start new referendum run.
|
|
|
fn start_referendum(
|
|
@@ -549,6 +581,9 @@ impl<T: Trait<I>, I: Instance> ReferendumManager<T::Origin, T::AccountId, T::Mem
|
|
|
// ensure action can be started
|
|
|
EnsureChecks::<T, I>::can_start_referendum(origin)?;
|
|
|
|
|
|
+ // ensure that the winning target count doesn't go over the limit
|
|
|
+ ensure!(winning_target_count <= T::MaxWinnerTargetCount::get(), ());
|
|
|
+
|
|
|
//
|
|
|
// == MUTATION SAFE ==
|
|
|
//
|
|
@@ -563,10 +598,14 @@ impl<T: Trait<I>, I: Instance> ReferendumManager<T::Origin, T::AccountId, T::Mem
|
|
|
}
|
|
|
|
|
|
// Start referendum independent of the current state.
|
|
|
- // If an election is running before calling this function, it will be discontinued without any winners selected.
|
|
|
+ // If an election is running before calling this function, it will be discontinued without any
|
|
|
+ // winners selected.
|
|
|
fn force_start(extra_winning_target_count: u64, cycle_id: u64) {
|
|
|
let winning_target_count = extra_winning_target_count + 1;
|
|
|
|
|
|
+ // If a greater than the max allowed target count is used the max will be used in its place
|
|
|
+ let winning_target_count = winning_target_count.min(T::MaxWinnerTargetCount::get());
|
|
|
+
|
|
|
// remember if referendum is running
|
|
|
let referendum_running = !matches!(Stage::<T, I>::get(), ReferendumStage::Inactive);
|
|
|
|
|
@@ -649,16 +688,11 @@ impl<T: Trait<I>, I: Instance> Mutations<T, I> {
|
|
|
fn vote(
|
|
|
account_id: &<T as frame_system::Trait>::AccountId,
|
|
|
commitment: &T::Hash,
|
|
|
- stake: &Balance<T, I>,
|
|
|
+ stake: &BalanceOf<T>,
|
|
|
current_cycle_id: &u64,
|
|
|
) -> Result<(), Error<T, I>> {
|
|
|
- // lock stake amount
|
|
|
- T::Currency::set_lock(
|
|
|
- T::LockId::get(),
|
|
|
- account_id,
|
|
|
- *stake,
|
|
|
- WithdrawReason::Transfer.into(),
|
|
|
- );
|
|
|
+ // Should call after `can_vote`
|
|
|
+ T::StakingHandler::lock_with_reasons(account_id, *stake, WithdrawReason::Transfer.into());
|
|
|
|
|
|
// store vote
|
|
|
Votes::<T, I>::insert(
|
|
@@ -679,7 +713,7 @@ impl<T: Trait<I>, I: Instance> Mutations<T, I> {
|
|
|
stage_data: ReferendumStageRevealingOf<T, I>,
|
|
|
account_id: &<T as frame_system::Trait>::AccountId,
|
|
|
option_id: &<T as common::Trait>::MemberId,
|
|
|
- cast_vote: CastVoteOf<T, I>,
|
|
|
+ cast_vote: CastVoteOf<T>,
|
|
|
) -> Result<(), Error<T, I>> {
|
|
|
// prepare new values
|
|
|
let vote_power = T::calculate_vote_power(&account_id, &cast_vote.stake);
|
|
@@ -712,14 +746,15 @@ impl<T: Trait<I>, I: Instance> Mutations<T, I> {
|
|
|
|
|
|
// Release stake associated to the user's last vote.
|
|
|
fn release_vote_stake(account_id: &<T as frame_system::Trait>::AccountId) {
|
|
|
- // lock stake amount
|
|
|
- T::Currency::remove_lock(T::LockId::get(), account_id);
|
|
|
+ // unlock stake amount
|
|
|
+ T::StakingHandler::unlock(account_id);
|
|
|
|
|
|
// remove vote record
|
|
|
Votes::<T, I>::remove(account_id);
|
|
|
}
|
|
|
|
|
|
- // Tries to insert option to the proper place in the winners list. Utility for reaveal_vote() function.
|
|
|
+ // Tries to insert option to the proper place in the winners list. Utility for reaveal_vote()
|
|
|
+ // function.
|
|
|
fn try_winner_insert(
|
|
|
option_result: OptionResultOf<T, I>,
|
|
|
current_winners: &[OptionResultOf<T, I>],
|
|
@@ -740,7 +775,8 @@ impl<T: Trait<I>, I: Instance> Mutations<T, I> {
|
|
|
.find(|(_, value)| option_result.option_id == value.option_id)
|
|
|
.map(|(index, _)| index);
|
|
|
|
|
|
- // espace when item is currently not in winning list and still has not enough vote power to make it to already full list
|
|
|
+ // espace when item is currently not in winning list and still has not enough vote
|
|
|
+ // power to make it to already full list
|
|
|
if current_winners_index_of_vote_recipient.is_none()
|
|
|
&& current_winners_count as u64 == winning_target_count
|
|
|
&& option_result.vote_power <= current_winners[current_winners_count - 1].vote_power
|
|
@@ -837,7 +873,7 @@ impl<T: Trait<I>, I: Instance> EnsureChecks<T, I> {
|
|
|
|
|
|
fn can_vote(
|
|
|
origin: T::Origin,
|
|
|
- stake: &Balance<T, I>,
|
|
|
+ stake: &BalanceOf<T>,
|
|
|
) -> Result<(u64, T::AccountId), Error<T, I>> {
|
|
|
fn prevent_repeated_vote<T: Trait<I>, I: Instance>(
|
|
|
cycle_id: &u64,
|
|
@@ -870,14 +906,19 @@ impl<T: Trait<I>, I: Instance> EnsureChecks<T, I> {
|
|
|
prevent_repeated_vote::<T, I>(¤t_cycle_id, &account_id)?;
|
|
|
|
|
|
// ensure stake is enough for voting
|
|
|
- if stake < &T::MinimumStake::get() {
|
|
|
- return Err(Error::InsufficientStake);
|
|
|
- }
|
|
|
+ ensure!(stake >= &T::MinimumStake::get(), Error::InsufficientStake);
|
|
|
|
|
|
- // ensure account can lock the stake
|
|
|
- if T::Currency::total_balance(&account_id) < *stake {
|
|
|
- return Err(Error::InsufficientBalanceToStakeCurrency);
|
|
|
- }
|
|
|
+ // Ensure account doesn't have conflicting stakes
|
|
|
+ ensure!(
|
|
|
+ T::StakingHandler::is_account_free_of_conflicting_stakes(&account_id),
|
|
|
+ Error::ConflictStakesOnAccount
|
|
|
+ );
|
|
|
+
|
|
|
+ // ensure stake is enough for voting
|
|
|
+ ensure!(
|
|
|
+ T::StakingHandler::is_enough_balance_for_stake(&account_id, *stake),
|
|
|
+ Error::InsufficientStake
|
|
|
+ );
|
|
|
|
|
|
Ok((current_cycle_id, account_id))
|
|
|
}
|
|
@@ -941,7 +982,7 @@ impl<T: Trait<I>, I: Instance> EnsureChecks<T, I> {
|
|
|
Ok(account_id)
|
|
|
}
|
|
|
|
|
|
- fn ensure_vote_exists(account_id: &T::AccountId) -> Result<CastVoteOf<T, I>, Error<T, I>> {
|
|
|
+ fn ensure_vote_exists(account_id: &T::AccountId) -> Result<CastVoteOf<T>, Error<T, I>> {
|
|
|
// ensure there is some vote with locked stake
|
|
|
if !Votes::<T, I>::contains_key(account_id) {
|
|
|
return Err(Error::VoteNotExisting);
|