Skip to content

Commit

Permalink
Merge branch 'main' into metastaking-token-merge-calculation-fix
Browse files Browse the repository at this point in the history
  • Loading branch information
dorin-iancu authored Mar 4, 2022
2 parents aacd658 + 69b9e45 commit a92e31e
Show file tree
Hide file tree
Showing 18 changed files with 1,187 additions and 0 deletions.
2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ members = [
"dex/farm_v1_2_mock",
"dex/farm_v1_2_mock/meta",
"dex/fuzz",
"dex/governance",
"dex/governance/meta",

"locked-asset/",
"locked-asset/distribution",
Expand Down
4 changes: 4 additions & 0 deletions dex/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -45,3 +45,7 @@ path = "pair"

[dev-dependencies.router]
path = "router"

[dev-dependencies.governance]
path = "governance"

7 changes: 7 additions & 0 deletions dex/governance/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# Generated by Cargo
# will have compiled files and executables
/target/
*/target/

# The erdpy output
output*
18 changes: 18 additions & 0 deletions dex/governance/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
[package]
name = "governance"
version = "0.0.0"
authors = [ "you",]
edition = "2018"
publish = false

[lib]
path = "src/contract.rs"

[dependencies.elrond-wasm]
version = "0.28"

[dev-dependencies.elrond-wasm-debug]
version = "0.28"

[dev-dependencies]
num-bigint = "0.4.2"
3 changes: 3 additions & 0 deletions dex/governance/elrond.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"language": "rust"
}
17 changes: 17 additions & 0 deletions dex/governance/meta/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
[package]
name = "governance-meta"
version = "0.0.0"
edition = "2018"
publish = false
authors = [ "you",]

[dev-dependencies]

[dependencies.governance]
path = ".."

[dependencies.elrond-wasm]
version = "0.28"

[dependencies.elrond-wasm-debug]
version = "0.28"
3 changes: 3 additions & 0 deletions dex/governance/meta/src/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
fn main() {
elrond_wasm_debug::meta::perform::<governance::AbiProvider>();
}
139 changes: 139 additions & 0 deletions dex/governance/src/config.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
elrond_wasm::imports!();

use crate::proposal::*;

#[elrond_wasm::module]
pub trait Config {
#[endpoint(changeQuorum)]
fn change_quorum(&self, new_value: BigUint) {
self.require_caller_self();

self.try_change_quorum(new_value);
}

#[endpoint(changeMinTokenBalanceForProposing)]
fn change_min_weight_for_proposal(&self, new_value: BigUint) {
self.require_caller_self();

self.try_change_min_weight_for_proposal(new_value);
}

#[endpoint(changeVotingDelayInBlocks)]
fn change_voting_delay_in_blocks(&self, new_value: u64) {
self.require_caller_self();

self.try_change_voting_delay_in_blocks(new_value);
}

#[endpoint(changeVotingPeriodInBlocks)]
fn change_voting_period_in_blocks(&self, new_value: u64) {
self.require_caller_self();

self.try_change_voting_period_in_blocks(new_value);
}

fn require_caller_self(&self) {
let caller = self.blockchain().get_caller();
let sc_address = self.blockchain().get_sc_address();

require!(
caller == sc_address,
"Only the SC itself may call this function"
);
}

fn try_change_mex_token_id(&self, token_id: TokenIdentifier) {
require!(
token_id.is_esdt(),
"Invalid ESDT token ID provided for vote_nft"
);

self.mex_token_id().set(&token_id);
}

fn try_change_vote_nft_id(&self, token_id: TokenIdentifier) {
require!(
token_id.is_esdt(),
"Invalid ESDT token ID provided for vote_nft"
);

self.vote_nft_id().set(&token_id);
}

fn try_change_governance_token_ids(&self, token_ids: ManagedVec<TokenIdentifier>) {
for token_id in token_ids.iter() {
require!(
token_id.is_esdt(),
"Invalid ESDT token ID provided for token_ids"
);
}

self.governance_token_ids().set(&token_ids);
}

fn try_change_quorum(&self, new_value: BigUint) {
require!(new_value != 0u64, "Quorum can't be set to 0");

self.quorum().set(&new_value);
}

fn try_change_min_weight_for_proposal(&self, new_value: BigUint) {
require!(
new_value != 0u64,
"Min token balance for proposing can't be set to 0"
);

self.min_weight_for_proposal().set(&new_value);
}

fn try_change_voting_delay_in_blocks(&self, new_value: u64) {
require!(new_value != 0, "Voting delay in blocks can't be set to 0");

self.voting_delay_in_blocks().set(&new_value);
}

fn try_change_voting_period_in_blocks(&self, new_value: u64) {
require!(
new_value != 0,
"Voting period (in blocks) can't be set to 0"
);

self.voting_period_in_blocks().set(&new_value);
}

#[view(getGovernanceTokenId)]
#[storage_mapper("governanceTokenIds")]
fn governance_token_ids(&self) -> SingleValueMapper<ManagedVec<TokenIdentifier>>;

#[view(getQuorum)]
#[storage_mapper("quorum")]
fn quorum(&self) -> SingleValueMapper<BigUint>;

#[view(getMinWeightForProposal)]
#[storage_mapper("minWeightForProposal")]
fn min_weight_for_proposal(&self) -> SingleValueMapper<BigUint>;

#[view(getVotingDelayInBlocks)]
#[storage_mapper("votingDelayInBlocks")]
fn voting_delay_in_blocks(&self) -> SingleValueMapper<u64>;

#[view(getVotingPeriodInBlocks)]
#[storage_mapper("votingPeriodInBlocks")]
fn voting_period_in_blocks(&self) -> SingleValueMapper<u64>;

#[view(getProposal)]
#[storage_mapper("proposal")]
fn proposal(&self, id: u64) -> SingleValueMapper<Proposal<Self::Api>>;

#[view(getProposalIdCounter)]
#[storage_mapper("proposalIdCounter")]
fn proposal_id_counter(&self) -> SingleValueMapper<u64>;

#[view(getVoteNFTId)]
#[storage_mapper("voteNFTId")]
fn vote_nft_id(&self) -> SingleValueMapper<TokenIdentifier>;

#[view(getMexTokenId)]
#[storage_mapper("mexTokenId")]
fn mex_token_id(&self) -> SingleValueMapper<TokenIdentifier>;
}
138 changes: 138 additions & 0 deletions dex/governance/src/contract.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
#![no_std]
#![feature(generic_associated_types)]

use proposal::ProposalCreationArgs;

elrond_wasm::imports!();
elrond_wasm::derive_imports!();

pub mod config;
pub mod errors;
mod lib;
pub mod proposal;
mod validation;
pub mod vote;

use crate::errors::*;
use crate::proposal::*;
use crate::vote::*;

#[elrond_wasm::contract]
pub trait Governance:
config::Config + validation::Validation + proposal::ProposalHelper + lib::Lib + vote::VoteHelper
{
#[init]
fn init(
&self,
quorum: BigUint,
voting_delay_in_blocks: u64,
voting_period_in_blocks: u64,
vote_nft_id: TokenIdentifier,
mex_token_id: TokenIdentifier,
min_weight_for_proposal: BigUint,
governance_token_ids: ManagedVec<TokenIdentifier>,
) {
self.try_change_quorum(quorum);
self.try_change_vote_nft_id(vote_nft_id);
self.try_change_mex_token_id(mex_token_id);
self.try_change_governance_token_ids(governance_token_ids);
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_min_weight_for_proposal(min_weight_for_proposal);
}

#[payable("*")]
#[endpoint]
fn propose(&self, args: ProposalCreationArgs<Self::Api>) -> u64 {
let payment = self.call_value().payment();
self.require_is_accepted_payment_for_proposal(&payment);

let vote_weight = self.get_vote_weight(&payment);
let min_weight = self.min_weight_for_proposal().get();
require!(vote_weight >= min_weight, NOT_ENOUGH_FUNDS_TO_PROPOSE);

let mut proposal = self.new_proposal_from_args(args);
self.proposal_id_counter().set(proposal.id + 1);

proposal.num_upvotes = vote_weight.clone();
self.proposal(proposal.id).set(&proposal);

let vote_nft = self.create_vote_nft(proposal.id, VoteType::Upvote, vote_weight, payment);
self.send_back(vote_nft);

proposal.id
}

#[payable("*")]
#[endpoint]
fn upvote(&self, proposal_id: u64) {
self.vote(proposal_id, VoteType::Upvote)
}

#[payable("*")]
#[endpoint]
fn downvote(&self, proposal_id: u64) {
self.vote(proposal_id, VoteType::DownVote)
}

#[endpoint]
fn execute(&self, proposal_id: u64) {
require!(!self.proposal(proposal_id).is_empty(), PROPOSAL_NOT_FOUND);
let mut proposal = self.proposal(proposal_id).get();

let pstat = self.get_proposal_status(&proposal);
require!(pstat == ProposalStatus::Succeeded, PROPOSAL_NOT_SUCCEEDED);

self.execute_proposal(&proposal);
proposal.was_executed = true;
self.proposal(proposal_id).set(&proposal);
}

fn vote(&self, proposal_id: u64, vote_type: VoteType) {
require!(!self.proposal(proposal_id).is_empty(), PROPOSAL_NOT_FOUND);
let mut proposal = self.proposal(proposal_id).get();

let pstat = self.get_proposal_status(&proposal);
require!(pstat == ProposalStatus::Active, PROPOSAL_NOT_ACTIVE);

let payment = self.call_value().payment();
self.require_is_accepted_payment_for_voting(&payment);

let vote_weight = self.get_vote_weight(&payment);
match vote_type {
VoteType::Upvote => proposal.num_upvotes += &vote_weight,
VoteType::DownVote => proposal.num_downvotes += &vote_weight,
}

let vote_nft = self.create_vote_nft(proposal.id, vote_type, vote_weight, payment);
self.send_back(vote_nft);

self.proposal(proposal_id).set(&proposal);
}

#[payable("*")]
#[endpoint]
fn redeem(&self) {
let payment = self.call_value().payment();

let vote_nft_id = self.vote_nft_id().get();
require!(payment.token_identifier == vote_nft_id, BAD_TOKEN_ID);

let attr = self.get_vote_attr(&payment);
let proposal = self.proposal(attr.proposal_id).get();

let pstat = self.get_proposal_status(&proposal);
match pstat {
ProposalStatus::Defeated | ProposalStatus::Executed => {
self.send_back(attr.payment);
self.burn_vote_nft(payment);
}
ProposalStatus::Succeeded => {
sc_panic!(PROPOSAL_NEEDS_TO_BE_EXECUTED)
}
ProposalStatus::Active | ProposalStatus::Pending => {
sc_panic!(VOTING_PERIOD_NOT_ENDED)
}
}
}
}
7 changes: 7 additions & 0 deletions dex/governance/src/errors.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
pub const BAD_TOKEN_ID: &[u8] = b"bad payment token id";
pub const PROPOSAL_NOT_ACTIVE: &[u8] = b"proposal not active";
pub const PROPOSAL_NOT_SUCCEEDED: &[u8] = b"proposal not succeeded";
pub const PROPOSAL_NOT_FOUND: &[u8] = b"proposal not found";
pub const NOT_ENOUGH_FUNDS_TO_PROPOSE: &[u8] = b"not enough funds to propose";
pub const VOTING_PERIOD_NOT_ENDED: &[u8] = b"voting period not ended";
pub const PROPOSAL_NEEDS_TO_BE_EXECUTED: &[u8] = b"successful proposal needs to be executed";
18 changes: 18 additions & 0 deletions dex/governance/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
elrond_wasm::imports!();

#[elrond_wasm::module]
pub trait Lib {
fn get_vote_weight(&self, payment: &EsdtTokenPayment<Self::Api>) -> BigUint {
payment.amount.clone()
}

fn send_back(&self, payment: EsdtTokenPayment<Self::Api>) {
self.send().direct(
&self.blockchain().get_caller(),
&payment.token_identifier,
payment.token_nonce,
&payment.amount,
&[],
);
}
}
Loading

0 comments on commit a92e31e

Please sign in to comment.