Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Remove no-confidence logic #243

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 0 additions & 43 deletions pallets/proposals/src/benchmarking.rs
Original file line number Diff line number Diff line change
Expand Up @@ -118,49 +118,6 @@ mod benchmarks {
);
}

#[benchmark]
fn raise_vote_of_no_confidence() {
let alice: T::AccountId =
create_funded_user::<T>("initiator", 1, 1_000_000_000_000_000_000u128);
let bob: T::AccountId =
create_funded_user::<T>("contributor", 1, 1_000_000_000_000_000_000u128);
// TODO: should update the contributors list to have maximum available length
let contributions = get_contributions::<T>(vec![bob.clone()], 100_000_000_000_000_000u128);
let prop_milestones = get_max_milestones::<T>();
let project_key =
create_project::<T>(alice, contributions, prop_milestones, CurrencyId::Native);
#[extrinsic_call]
raise_vote_of_no_confidence(RawOrigin::Signed(bob.clone()), project_key);
assert_last_event::<T>(Event::<T>::NoConfidenceRoundCreated(bob, project_key).into());
}

#[benchmark]
fn vote_on_no_confidence_round() {
let alice: T::AccountId =
create_funded_user::<T>("initiator", 1, 1_000_000_000_000_000_000u128);
let bob: T::AccountId =
create_funded_user::<T>("contributor", 1, 1_000_000_000_000_000_000u128);
let charlie: T::AccountId =
create_funded_user::<T>("contributor", 2, 1_000_000_000_000_000_000u128);
// TODO: should update the contributors list to have maximum available length
let contributions = get_contributions::<T>(
vec![bob.clone(), charlie.clone()],
100_000_000_000_000_000u128,
);
let prop_milestones = get_max_milestones::<T>();
let project_key =
create_project::<T>(alice, contributions, prop_milestones, CurrencyId::Native);

assert_ok!(Pallet::<T>::raise_vote_of_no_confidence(
RawOrigin::Signed(bob).into(),
project_key
));

#[extrinsic_call]
vote_on_no_confidence_round(RawOrigin::Signed(charlie.clone()), project_key, true);
assert_last_event::<T>(Event::<T>::NoConfidenceRoundVotedUpon(charlie, project_key).into());
}

// Benchmark for a single loop of on_initialise as a voting round (most expensive).
#[benchmark]
fn on_initialize() {
Expand Down
228 changes: 0 additions & 228 deletions pallets/proposals/src/impls/pallet_impls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -196,234 +196,6 @@ impl<T: Config> Pallet<T> {
Ok(().into())
}

/// This function raises a vote of no confidence.
/// This round can only be called once and there after can only be voted on.
pub(crate) fn raise_no_confidence_round(
who: T::AccountId,
project_key: ProjectKey,
) -> DispatchResult {
//ensure that who is a contributor or root
let project = Self::projects(project_key).ok_or(Error::<T>::ProjectDoesNotExist)?;
let contribution = project
.contributions
.get(&who)
.ok_or(Error::<T>::OnlyContributorsCanVote)?;

// Also ensure that a vote has not already been raised.
ensure!(
!NoConfidenceVotes::<T>::contains_key(project_key),
Error::<T>::RoundStarted
);

let vote = Vote {
yay: Zero::zero(),
nay: contribution.value,
is_approved: false,
};

let expiry_block = frame_system::Pallet::<T>::block_number()
.saturating_add(<T as Config>::NoConfidenceTimeLimit::get());

Rounds::<T>::insert(
(project_key, 0),
RoundType::VoteOfNoConfidence,
expiry_block,
);
RoundsExpiring::<T>::try_mutate(expiry_block, |keys| {
// The milestone key does not matter here as we are voting on the entire project.
keys.try_push((project_key, RoundType::VoteOfNoConfidence, 0))
.map_err(|_| Error::<T>::Overflow)?;
Ok::<(), DispatchError>(())
})?;
UserHasVoted::<T>::try_mutate((project_key, RoundType::VoteOfNoConfidence, 0), |votes| {
ensure!(!votes.contains_key(&who), Error::<T>::VotesAreImmutable);
votes
.try_insert(who.clone(), false)
.map_err(|_| Error::<T>::Overflow)?;
Ok::<(), DispatchError>(())
})?;

NoConfidenceVotes::<T>::insert(project_key, vote);
Self::deposit_event(Event::NoConfidenceRoundCreated(who, project_key));
Ok(())
}

/// Allows a contributer to agree or disagree with a vote of no confidence.
pub(crate) fn add_vote_no_confidence(
who: T::AccountId,
project_key: ProjectKey,
is_yay: bool,
) -> DispatchResult {
ensure!(
Rounds::<T>::contains_key((project_key, 0), RoundType::VoteOfNoConfidence),
Error::<T>::ProjectNotInRound
);
let project = Self::projects(project_key).ok_or(Error::<T>::ProjectDoesNotExist)?;
let contribution = project
.contributions
.get(&who)
.ok_or(Error::<T>::OnlyContributorsCanVote)?;

let nay_vote = NoConfidenceVotes::<T>::try_mutate(project_key, |maybe_vote| {
if let Some(v) = maybe_vote {
if is_yay {
v.yay = v.yay.saturating_add(contribution.value);
} else {
v.nay = v.nay.saturating_add(contribution.value);
}
Ok::<BalanceOf<T>, DispatchError>(v.nay)
} else {
Err(Error::<T>::VotingRoundNotStarted.into())
}
})?;

UserHasVoted::<T>::try_mutate((project_key, RoundType::VoteOfNoConfidence, 0), |votes| {
ensure!(!votes.contains_key(&who), Error::<T>::VotesAreImmutable);
votes
.try_insert(who.clone(), false)
.map_err(|_| Error::<T>::Overflow)?;
Ok::<(), DispatchError>(())
})?;

Self::deposit_event(Event::NoConfidenceRoundVotedUpon(who.clone(), project_key));

//once the voting is complete check if the confidence vote could be auto finalized
//getting the total threshold required for the total confidence
let voting_no_confidence_threshold: BalanceOf<T> =
T::PercentRequiredForVoteNoConfidenceToPass::get().mul_floor(project.raised_funds);

//verifying whether the no confidence vote has passed the threshold if so then auto finalize it
if nay_vote >= voting_no_confidence_threshold {
let locked_milestone_percentage =
project.milestones.iter().fold(Percent::zero(), |acc, ms| {
if !ms.1.is_approved {
acc.saturating_add(ms.1.percentage_to_unlock)
} else {
acc
}
});

let project_account_id = Self::project_account_id(project_key);

match project.funding_type {
FundingType::Proposal => {
// Handle refunds on native chain, there is no need to deal with xcm here.
for (acc_id, contribution) in project.contributions.iter() {
let refund_amount =
locked_milestone_percentage.mul_floor(contribution.value);
<T as Config>::MultiCurrency::transfer(
project.currency_id,
&project_account_id,
acc_id,
refund_amount,
)?;
}
}

FundingType::Brief => {
//Have to handle it in the dispute pallet
}

// Must a grant be treasury funded?
FundingType::Grant(_) => {
let mut refund_amount: BalanceOf<T> = Zero::zero();
// Sum the contributions and send a single xcm.
for (_acc_id, contribution) in project.contributions.iter() {
let per_contributor =
locked_milestone_percentage.mul_floor(contribution.value);
refund_amount = refund_amount.saturating_add(per_contributor);
}
<T as Config>::RefundHandler::send_refund_message_to_treasury(
project_account_id,
refund_amount,
project.currency_id,
project.funding_type,
)?;
}
}
Projects::<T>::remove(project_key);
Rounds::<T>::remove((project_key, 0), RoundType::VoteOfNoConfidence);
<T as Config>::DepositHandler::return_deposit(project.deposit_id)?;
Self::deposit_event(Event::NoConfidenceRoundFinalised(who, project_key));
}
Ok(())
}

#[deprecated(since = "3.1.0", note = "autofinalisation has been implemented.")]
pub(crate) fn _call_finalise_no_confidence_vote(
who: T::AccountId,
project_key: ProjectKey,
majority_required: Percent,
) -> DispatchResultWithPostInfo {
let project = Projects::<T>::get(project_key).ok_or(Error::<T>::ProjectDoesNotExist)?;
ensure!(
Rounds::<T>::contains_key((project_key, 0), RoundType::VoteOfNoConfidence),
Error::<T>::ProjectNotInRound
);
ensure!(
project.contributions.contains_key(&who),
Error::<T>::OnlyContributorsCanVote
);

let vote = NoConfidenceVotes::<T>::get(project_key).ok_or(Error::<T>::NoActiveRound)?;
let threshold_votes: BalanceOf<T> = majority_required.mul_floor(project.raised_funds);

if vote.nay >= threshold_votes {
let locked_milestone_percentage =
project.milestones.iter().fold(Percent::zero(), |acc, ms| {
if !ms.1.is_approved {
acc.saturating_add(ms.1.percentage_to_unlock)
} else {
acc
}
});

let project_account_id = Self::project_account_id(project_key);

// TODO: this should be generic and not bound to funding type..
match project.funding_type {
FundingType::Brief | FundingType::Proposal => {
//
// Handle refunds on native chain, there is no need to deal with xcm here.
// Todo: Batch call using pallet-utility?
for (acc_id, contribution) in project.contributions.iter() {
let refund_amount =
locked_milestone_percentage.mul_floor(contribution.value);
<T as Config>::MultiCurrency::transfer(
project.currency_id,
&project_account_id,
acc_id,
refund_amount,
)?;
}
}
// Must a grant be treasury funded?
FundingType::Grant(_) => {
let mut refund_amount: BalanceOf<T> = Zero::zero();
// Sum the contributions and send a single xcm.
for (_acc_id, contribution) in project.contributions.iter() {
let per_contributor =
locked_milestone_percentage.mul_floor(contribution.value);
refund_amount = refund_amount.saturating_add(per_contributor);
}
<T as Config>::RefundHandler::send_refund_message_to_treasury(
project_account_id,
refund_amount,
project.currency_id,
project.funding_type,
)?;
}
}

Projects::<T>::remove(project_key);
<T as Config>::DepositHandler::return_deposit(project.deposit_id)?;
Self::deposit_event(Event::NoConfidenceRoundFinalised(who, project_key));
} else {
return Err(Error::<T>::VoteThresholdNotMet.into());
}
Ok(().into())
}

pub(crate) fn try_auto_finalise_milestone_voting(
project_key: ProjectKey,
vote: &Vote<BalanceOf<T>>,
Expand Down
37 changes: 0 additions & 37 deletions pallets/proposals/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -151,12 +151,6 @@ pub mod pallet {
ValueQuery,
>;

/// This holds the votes when a no confidence round is raised.
#[pallet::storage]
#[pallet::getter(fn no_confidence_votes)]
pub(super) type NoConfidenceVotes<T: Config> =
StorageMap<_, Identity, ProjectKey, Vote<BalanceOf<T>>, OptionQuery>;

#[pallet::storage]
#[pallet::getter(fn project_count)]
pub type ProjectCount<T> = StorageValue<_, ProjectKey, ValueQuery>;
Expand Down Expand Up @@ -360,35 +354,6 @@ pub mod pallet {
let who = ensure_signed(origin)?;
Self::new_withdrawal(who, project_key)
}

/// In case of contributors losing confidence in the initiator a "Vote of no confidence" can be called.
/// This will start a round which each contributor can vote on.
/// The round will last as long as set in the Config.
#[pallet::call_index(12)]
#[pallet::weight(<T as Config>::WeightInfo::raise_vote_of_no_confidence())]
pub fn raise_vote_of_no_confidence(
origin: OriginFor<T>,
project_key: ProjectKey,
) -> DispatchResult {
let who = ensure_signed(origin)?;
Self::raise_no_confidence_round(who, project_key)
}

/// pallet-disputes?
/// Vote on an already existing "Vote of no condidence" round.
/// is_yay is FOR the project's continuation.
/// so is_yay == false == against the project from continuing.
/// This autofinalises like in the milestone voting.
#[pallet::call_index(13)]
#[pallet::weight(<T as Config>::WeightInfo::vote_on_no_confidence_round())]
pub fn vote_on_no_confidence_round(
origin: OriginFor<T>,
project_key: ProjectKey,
is_yay: bool,
) -> DispatchResult {
let who = ensure_signed(origin)?;
Self::add_vote_no_confidence(who, project_key, is_yay)
}
}
impl<T: crate::Config> IntoProposal<AccountIdOf<T>, BalanceOf<T>, BlockNumberFor<T>>
for crate::Pallet<T>
Expand Down Expand Up @@ -591,7 +556,5 @@ pub trait WeightInfoT {
fn submit_milestone() -> Weight;
fn vote_on_milestone() -> Weight;
fn withdraw() -> Weight;
fn raise_vote_of_no_confidence() -> Weight;
fn vote_on_no_confidence_round() -> Weight;
fn on_initialize() -> Weight;
}
Loading