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

Governance v2 energy updates #761

Merged
merged 8 commits into from
Aug 22, 2023
Merged
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
12 changes: 8 additions & 4 deletions energy-integration/governance-v2/src/configurable.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,9 +60,9 @@ pub trait ConfigurablePropertiesModule:
}

#[only_owner]
#[endpoint(changeQuorum)]
fn change_quorum(&self, new_value: BigUint) {
self.try_change_quorum(new_value);
#[endpoint(changeQuorumPercentage)]
fn change_quorum_percentage(&self, new_value: BigUint) {
self.try_change_quorum_percentage(new_value);
}

#[only_owner]
Expand Down Expand Up @@ -96,7 +96,7 @@ pub trait ConfigurablePropertiesModule:
self.min_fee_for_propose().set(&new_value);
}

fn try_change_quorum(&self, new_value: BigUint) {
fn try_change_quorum_percentage(&self, new_value: BigUint) {
require!(
new_value > MIN_QUORUM && new_value < MAX_QUORUM,
"Not valid value for Quorum!"
Expand Down Expand Up @@ -137,6 +137,10 @@ pub trait ConfigurablePropertiesModule:
self.fee_token_id().set_if_empty(&fee_token_id);
}

fn smoothing_function(&self, input: &BigUint) -> BigUint {
input.sqrt()
}

#[view(getMinEnergyForPropose)]
#[storage_mapper("minEnergyForPropose")]
fn min_energy_for_propose(&self) -> SingleValueMapper<BigUint>;
Expand Down
6 changes: 6 additions & 0 deletions energy-integration/governance-v2/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,9 @@ pub const NOT_ENOUGH_ENERGY: &[u8] = b"Not enough energy for propose";
pub const TOO_MUCH_GAS: &[u8] = b"Actions require too much gas to be executed";
pub const PROPOSAL_NOT_ACTIVE: &[u8] = b"Proposal is not active";
pub const ERROR_NOT_AN_ESDT: &[u8] = b"Not a valid esdt id";
pub const ALREADY_VOTED_ERR_MSG: &[u8] = b"Already voted for this proposal";
pub const EXEEDED_MAX_ACTIONS: &[u8] = b"Exceeded max actions per proposal";
pub const ONLY_PROPOSER_CANCEL: &[u8] = b"Only original proposer may cancel a pending proposal";
pub const ONLY_PROPOSER_WITHDRAW: &[u8] = b"Only original proposer may withdraw a pending proposal";
pub const NO_PROPOSAL: &[u8] = b"Proposal does not exist";
pub const WITHDRAW_NOT_ALLOWED: &[u8] = b"You may not withdraw funds from this proposal!";
46 changes: 16 additions & 30 deletions energy-integration/governance-v2/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ use crate::proposal_storage::ProposalVotes;

const MAX_GAS_LIMIT_PER_BLOCK: u64 = 600_000_000;
const FULL_PERCENTAGE: u64 = 10_000;
static ALREADY_VOTED_ERR_MSG: &[u8] = b"Already voted for this proposal";

/// An empty contract. To be used as a template when starting a new contract from scratch.
#[multiversx_sc::contract]
Expand All @@ -35,11 +34,13 @@ pub trait GovernanceV2:
{
/// - `min_energy_for_propose` - the minimum energy required for submitting a proposal
/// - `min_fee_for_propose` - the minimum fee required for submitting a proposal
/// - `quorum` - the minimum number of (`votes` minus `downvotes`) at the end of voting period
/// - `maxActionsPerProposal` - Maximum number of actions (transfers and/or smart contract calls) that a proposal may have
/// - `quorum_percentage` - the minimum number of (`votes` minus `downvotes`) at the end of voting period
/// - `votingDelayInBlocks` - Number of blocks to wait after a block is proposed before being able to vote/downvote that proposal
/// - `votingPeriodInBlocks` - Number of blocks the voting period lasts (voting delay does not count towards this)
/// - `lockTimeAfterVotingEndsInBlocks` - Number of blocks to wait before a successful proposal can be executed
/// - `withdraw_percentage_defeated` - Percetange of the fee to be returned if proposal defetead
/// - `energy_factory_address`
/// - `fees_collector_address`
/// - `fee_token` - The token used to pay the fee
#[init]
fn init(
&self,
Expand All @@ -55,7 +56,7 @@ pub trait GovernanceV2:
) {
self.try_change_min_energy_for_propose(min_energy_for_propose);
self.try_change_min_fee_for_propose(min_fee_for_propose);
self.try_change_quorum(quorum_percentage);
self.try_change_quorum_percentage(quorum_percentage);
self.try_change_voting_delay_in_blocks(voting_delay_in_blocks);
self.try_change_voting_period_in_blocks(voting_period_in_blocks);
self.try_change_withdraw_percentage_defeated(withdraw_percentage_defeated);
Expand All @@ -67,16 +68,10 @@ pub trait GovernanceV2:
/// Propose a list of actions.
/// A maximum of MAX_GOVERNANCE_PROPOSAL_ACTIONS can be proposed at a time.
///
/// An action has the following format:
/// - gas limit for action execution
/// - destination address
/// - a fee payment for proposal (if smaller than min_fee_for_propose, state: WaitForFee)
/// - endpoint to be called on the destination
/// - a vector of arguments for the endpoint, in the form of ManagedVec<ManagedBuffer>
///
/// The proposer's energy is NOT automatically used for voting. A separate vote is needed.
///
/// Returns the ID of the newly created proposal.
#[only_owner]
#[payable("*")]
#[endpoint]
fn propose(
Expand All @@ -85,10 +80,10 @@ pub trait GovernanceV2:
actions: MultiValueEncoded<GovernanceActionAsMultiArg<Self::Api>>,
) -> ProposalId {
self.require_caller_not_self();
require!(!actions.is_empty(), "Proposal has no actions");

require!(
actions.len() <= MAX_GOVERNANCE_PROPOSAL_ACTIONS,
"Exceeded max actions per proposal"
EXEEDED_MAX_ACTIONS
);

let proposer = self.blockchain().get_caller();
Expand Down Expand Up @@ -187,7 +182,7 @@ pub trait GovernanceV2:
}

let user_quorum = self.get_energy_amount_non_zero(&voter);
let voting_power = user_quorum.sqrt();
let voting_power = self.smoothing_function(&user_quorum);

match vote {
VoteType::UpVote => {
Expand Down Expand Up @@ -230,16 +225,13 @@ pub trait GovernanceV2:

match self.get_proposal_status(proposal_id) {
GovernanceProposalStatus::None => {
sc_panic!("Proposal does not exist");
sc_panic!(NO_PROPOSAL);
}
GovernanceProposalStatus::Pending => {
let proposal = self.proposals().get(proposal_id);
let caller = self.blockchain().get_caller();

require!(
caller == proposal.proposer,
"Only original proposer may cancel a pending proposal"
);
require!(caller == proposal.proposer, ONLY_PROPOSER_CANCEL);
self.refund_proposal_fee(proposal_id, &proposal.fee_payment.amount);
self.clear_proposal(proposal_id);
self.proposal_canceled_event(proposal_id);
Expand All @@ -259,15 +251,12 @@ pub trait GovernanceV2:

match self.get_proposal_status(proposal_id) {
GovernanceProposalStatus::None => {
sc_panic!("Proposal does not exist");
sc_panic!(NO_PROPOSAL);
}
GovernanceProposalStatus::Succeeded | GovernanceProposalStatus::Defeated => {
let proposal = self.proposals().get(proposal_id);

require!(
caller == proposal.proposer,
"Only original proposer may cancel a pending proposal"
);
require!(caller == proposal.proposer, ONLY_PROPOSER_WITHDRAW);

self.refund_proposal_fee(proposal_id, &proposal.fee_payment.amount);
}
Expand All @@ -277,10 +266,7 @@ pub trait GovernanceV2:
let refund_amount =
refund_percentage * proposal.fee_payment.amount.clone() / FULL_PERCENTAGE;

require!(
caller == proposal.proposer,
"Only original proposer may cancel a pending proposal"
);
require!(caller == proposal.proposer, ONLY_PROPOSER_WITHDRAW);

self.refund_proposal_fee(proposal_id, &refund_amount);
let remaining_fee = proposal.fee_payment.amount - refund_amount;
Expand All @@ -294,7 +280,7 @@ pub trait GovernanceV2:
});
}
_ => {
sc_panic!("You may not withdraw funds from this proposal!");
sc_panic!(WITHDRAW_NOT_ALLOWED);
}
}
self.proposal_withdraw_after_defeated_event(proposal_id);
Expand Down
2 changes: 2 additions & 0 deletions energy-integration/governance-v2/src/views.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,8 @@ pub trait ViewsModule:
}
}

// private

fn vote_reached(&self, proposal_id: ProposalId) -> bool {
let proposal_votes = self.proposal_votes(proposal_id).get();
let total_votes = proposal_votes.get_total_votes();
Expand Down
8 changes: 4 additions & 4 deletions energy-integration/governance-v2/tests/gov_rust_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -295,7 +295,7 @@ fn gov_modify_quorum_after_end_vote_test() {
sc.get_proposal_status(1) == GovernanceProposalStatus::Defeated,
"Action should have been Defeated"
);
sc.try_change_quorum(managed_biguint!(QUORUM_PERCENTAGE / 2));
sc.try_change_quorum_percentage(managed_biguint!(QUORUM_PERCENTAGE / 2));
assert!(sc.quorum_percentage().get() == managed_biguint!(QUORUM_PERCENTAGE / 2));

assert!(
Expand Down Expand Up @@ -360,7 +360,7 @@ fn gov_withdraw_defeated_proposal_test() {
// Other user (not proposer) try to withdraw the fee -> Fail
gov_setup
.withdraw_after_defeated(&third_user_addr, proposal_id)
.assert_error(4, "Only original proposer may cancel a pending proposal");
.assert_error(4, "Only original proposer may withdraw a pending proposal");

// Proposer withdraw
gov_setup
Expand Down Expand Up @@ -435,7 +435,7 @@ fn gov_modify_withdraw_defeated_proposal_test() {
// Other user (not proposer) try to withdraw the fee -> Fail
gov_setup
.withdraw_after_defeated(&third_user_addr, proposal_id)
.assert_error(4, "Only original proposer may cancel a pending proposal");
.assert_error(4, "Only original proposer may withdraw a pending proposal");

// Proposer withdraw
gov_setup
Expand Down Expand Up @@ -506,7 +506,7 @@ fn gov_withdraw_no_with_veto_defeated_proposal_test() {
// Other user (not proposer) try to withdraw the fee -> Fail
gov_setup
.withdraw_after_defeated(&third_user_addr, proposal_id)
.assert_error(4, "Only original proposer may cancel a pending proposal");
.assert_error(4, "Only original proposer may withdraw a pending proposal");

// Proposer withdraw
gov_setup
Expand Down
8 changes: 5 additions & 3 deletions energy-integration/governance-v2/wasm/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@
////////////////////////////////////////////////////

// Init: 1
// Endpoints: 27
// Endpoints: 29
// Async Callback (empty): 1
// Total number of exported functions: 29
// Total number of exported functions: 31

#![no_std]
#![feature(alloc_error_handler, lang_items)]
Expand All @@ -24,7 +24,7 @@ multiversx_sc_wasm_adapter::endpoints! {
withdrawDeposit
changeMinEnergyForProposal
changeMinFeeForProposal
changeQuorum
changeQuorumPercentage
changeVotingDelayInBlocks
changeVotingPeriodInBlocks
getMinEnergyForPropose
Expand All @@ -38,6 +38,8 @@ multiversx_sc_wasm_adapter::endpoints! {
getUserVotedProposals
getProposalVotes
getProposalStatus
getUserVotingPower
getVotingPowerEquivalent
getFeesCollectorAddress
setEnergyFactoryAddress
getEnergyFactoryAddress
Expand Down