diff --git a/README.md b/README.md index c0ca209..5f6d7fb 100644 --- a/README.md +++ b/README.md @@ -94,3 +94,11 @@ OpenGuild is a builder-driven community centered around Polkadot. OpenGuild is b - **Website:** [OpenGuild Website](https://openguild.wtf/) - **Github:** [OpenGuild Labs](https://github.com/openguild-labs) - **Discord**: [Openguild Discord Channel](https://discord.gg/bcjMzxqtD7) + +## Participant Registration + +Add your information to the below list to officially participate in the workshop challenge (This is the first mission of the whole workshop) + +| Emoji | Name | Github Username | Occupations | +| ----- | --------------- | ----------------------------------------------------- | ------------------------ | +| 🦁 | Aji Guruh Prasetyo | [ajiguruhprasetyo](https://github.com/ajiguruhprasetyo) | Software Engineer | diff --git a/src/governance.rs b/src/governance.rs index f71f10b..395f08e 100644 --- a/src/governance.rs +++ b/src/governance.rs @@ -1,7 +1,5 @@ use crate::staking::StakingConfig; -use crate::system::SystemConfig; use std::collections::HashMap; - pub trait GovernanceConfig: StakingConfig {} pub struct Proposal { @@ -25,17 +23,33 @@ pub struct GovernancePallet { } impl GovernancePallet { + // Create a new instance of the governance pallet pub fn new() -> Self { - todo!() + Self { + proposals: HashMap::new(), + votes: HashMap::new(), + next_proposal_id: 0, + } } // Create a new proposal pub fn create_proposal( &mut self, - creator: T::AccountId, + _creator: T::AccountId, description: String, ) -> Result { - todo!() + self.next_proposal_id += 1; + + self.proposals.insert( + self.next_proposal_id, + Proposal { + description, + yes_votes: 0, + no_votes: 0, + status: ProposalStatus::Active, + }, + ); + Ok(self.next_proposal_id) } // Vote on a proposal (true = yes, false = no) @@ -45,17 +59,70 @@ impl GovernancePallet { proposal_id: u32, vote_type: bool, ) -> Result<(), &'static str> { - todo!() + if self.votes.contains_key(&(voter.clone(), proposal_id)) { + return Err("You can only vote once"); + } + + if !self.proposals.contains_key(&proposal_id) { + return Err("the proposal data doesn't exist"); + } + + self.votes.insert((voter, proposal_id), vote_type); + let validate_proposal = self.get_proposal(proposal_id).expect("Proposal not found"); + + let yes_votes = if vote_type { + validate_proposal.yes_votes + 1 + } else { + validate_proposal.yes_votes + }; + let no_votes = if !vote_type { + validate_proposal.no_votes + 1 + } else { + validate_proposal.no_votes + }; + + let result_proposal = Proposal { + description: validate_proposal.description.clone(), + yes_votes, + no_votes, + status: validate_proposal.status.clone(), + }; + + self.proposals.insert(proposal_id, result_proposal); + + Ok(()) } // Get proposal details pub fn get_proposal(&self, proposal_id: u32) -> Option<&Proposal> { - todo!() + self.proposals.get(&proposal_id) } // Finalize a proposal (changes status based on votes) pub fn finalize_proposal(&mut self, proposal_id: u32) -> Result { - todo!() + let data_proposal = self + .get_proposal(proposal_id) + .expect("could not found the proposal"); + + let yes_votes = data_proposal.yes_votes; + let no_votes = data_proposal.no_votes; + + let status = if yes_votes > no_votes { + ProposalStatus::Approved + } else { + ProposalStatus::Rejected + }; + + let result_proposal = Proposal { + description: data_proposal.description.clone(), + yes_votes, + no_votes, + status: status.clone(), + }; + + self.proposals.insert(proposal_id, result_proposal); + + Ok(status) } } diff --git a/src/staking.rs b/src/staking.rs index 7bd646e..a8f2c25 100644 --- a/src/staking.rs +++ b/src/staking.rs @@ -16,32 +16,64 @@ pub struct StakingPallet { impl StakingPallet { pub fn new() -> Self { - todo!() + Self { + free_balances: HashMap::new(), + staked_balances: HashMap::new(), + } } // Set free balance for an account pub fn set_balance(&mut self, who: T::AccountId, amount: T::Balance) { - todo!() + self.free_balances.insert(who.clone(), amount); } // Stake tokens (move from free to staked) pub fn stake(&mut self, who: T::AccountId, amount: T::Balance) -> Result<(), &'static str> { - todo!() + let data_free_balance = self.get_free_balance(who.clone()); + let data_staked_balance = self.get_staked_balance(who.clone()); + + let validate_free_balance = data_free_balance + .checked_sub(&amount) + .ok_or("not enough funds")?; + let validate_staked_balance = data_staked_balance.checked_add(&amount).ok_or("overflow")?; + + self.free_balances + .insert(who.clone(), validate_free_balance); + self.staked_balances + .insert(who.clone(), validate_staked_balance); + + Ok(()) } // Unstake tokens (move from staked to free) pub fn unstake(&mut self, who: T::AccountId, amount: T::Balance) -> Result<(), &'static str> { - todo!() + let data_staked_balance = self.get_staked_balance(who.clone()); + let data_free_balance = self.get_free_balance(who.clone()); + + let validate_staked_balance = data_staked_balance + .checked_sub(&amount) + .ok_or("not enough funds")?; + let validate_free_balance = data_free_balance.checked_add(&amount).ok_or("overvlow")?; + + self.free_balances + .insert(who.clone(), validate_free_balance); + self.staked_balances + .insert(who.clone(), validate_staked_balance); + + Ok(()) } // Get free balance for an account pub fn get_free_balance(&self, who: T::AccountId) -> T::Balance { - todo!() + *self.free_balances.get(&who).unwrap_or(&T::Balance::zero()) } // Get staked balance for an account pub fn get_staked_balance(&self, who: T::AccountId) -> T::Balance { - todo!() + *self + .staked_balances + .get(&who) + .unwrap_or(&T::Balance::zero()) } }