-
Notifications
You must be signed in to change notification settings - Fork 43
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge branch 'main' into metastaking-token-merge-calculation-fix
- Loading branch information
Showing
18 changed files
with
1,187 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -45,3 +45,7 @@ path = "pair" | |
|
||
[dev-dependencies.router] | ||
path = "router" | ||
|
||
[dev-dependencies.governance] | ||
path = "governance" | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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* |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
{ | ||
"language": "rust" | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
fn main() { | ||
elrond_wasm_debug::meta::perform::<governance::AbiProvider>(); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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>; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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) | ||
} | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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"; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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, | ||
&[], | ||
); | ||
} | ||
} |
Oops, something went wrong.