diff --git a/README.md b/README.md index c0ca209..105eded 100644 --- a/README.md +++ b/README.md @@ -62,6 +62,7 @@ After learning about Substrate, FRAME, Runtime, and Pallets in Polkadot SDK, thi ### Project Structure This challenge simulates three core components: + - `system.rs`: Foundation module similar to `frame_system` - `staking.rs`: Token staking module similar to `pallet_staking` - `governance.rs`: On-chain proposal system similar to `pallet_collective` or `pallet_democracy` @@ -94,3 +95,8 @@ 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 + +| 🦄 | Name | Github username | Your current occupation | +| 🦄 | I Gusti Agung Ramananda Wira Dharma | [agungramananda](https://github.com/agungramananda) | Computer Science Student | diff --git a/src/governance.rs b/src/governance.rs index f71f10b..f8ac893 100644 --- a/src/governance.rs +++ b/src/governance.rs @@ -11,7 +11,7 @@ pub struct Proposal { status: ProposalStatus, } -#[derive(Clone)] +#[derive(Clone,PartialEq)] pub enum ProposalStatus { Active, Approved, @@ -26,7 +26,11 @@ pub struct GovernancePallet { impl GovernancePallet { pub fn new() -> Self { - todo!() + Self { + proposals : HashMap::new(), + votes : HashMap::new(), + next_proposal_id: 0, + } } // Create a new proposal @@ -35,7 +39,18 @@ impl GovernancePallet { creator: T::AccountId, description: String, ) -> Result { - todo!() + let proposal_id = self.next_proposal_id; + let new_proposal = Proposal { + description, + yes_votes : 0, + no_votes : 0, + status : ProposalStatus::Active, + }; + + self.proposals.insert(proposal_id, new_proposal); + self.next_proposal_id += 1; + + Ok(proposal_id) } // Vote on a proposal (true = yes, false = no) @@ -45,17 +60,50 @@ impl GovernancePallet { proposal_id: u32, vote_type: bool, ) -> Result<(), &'static str> { - todo!() + if !self.proposals.contains_key(&proposal_id){ + return Err("Proposal not found"); + } + + if self.votes.contains_key(&(voter.clone(), proposal_id)){ + return Err("Has already voted on this proposal"); + } + + let proposal = self.proposals.get_mut(&proposal_id).unwrap(); + + if vote_type { + proposal.yes_votes += 1; + } else { + proposal.no_votes += 1; + } + + self.votes.insert((voter,proposal_id), vote_type); + 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!() + if !self.proposals.contains_key(&proposal_id){ + return Err("Proposal not found"); + } + + let proposal = self.proposals.get_mut(&proposal_id).unwrap(); + + if proposal.status != ProposalStatus::Active { + return Err("Proposal is not active and already finalized"); + } + + if proposal.yes_votes > proposal.no_votes { + proposal.status = ProposalStatus::Approved; + } else { + proposal.status = ProposalStatus::Rejected; + } + + Ok(proposal.status.clone()) } } diff --git a/src/staking.rs b/src/staking.rs index 7bd646e..5b04237 100644 --- a/src/staking.rs +++ b/src/staking.rs @@ -16,32 +16,61 @@ 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,amount); } // Stake tokens (move from free to staked) pub fn stake(&mut self, who: T::AccountId, amount: T::Balance) -> Result<(), &'static str> { - todo!() + let user_free_balance = self.free_balances.get(&who).copied().unwrap_or_else(Zero::zero); + let user_stacked_balance = self.staked_balances.get(&who).copied().unwrap_or_else(Zero::zero); + + if user_free_balance.checked_sub(&amount).is_none() { + return Err("Not enough free balance to stake"); + } + + let new_free_balance = user_free_balance - amount; + let new_stacked_balance = user_stacked_balance + amount; + + self.free_balances.insert(who.clone(), new_free_balance); + self.staked_balances.insert(who, new_stacked_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 user_free_balance = self.free_balances.get(&who).copied().unwrap_or_else(Zero::zero); + let user_stacked_balance = self.staked_balances.get(&who).copied().unwrap_or_else(Zero::zero); + + if user_stacked_balance.checked_sub(&amount).is_none() { + return Err("Not enough stacked balance to unstake"); + } + + let new_free_balance = user_free_balance + amount; + let new_stacked_balance = user_stacked_balance - amount; + + self.staked_balances.insert(who.clone(), new_stacked_balance); + self.free_balances.insert(who, new_free_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).copied().unwrap_or_else(Zero::zero) } // Get staked balance for an account pub fn get_staked_balance(&self, who: T::AccountId) -> T::Balance { - todo!() + self.staked_balances.get(&who).copied().unwrap_or_else(Zero::zero) } }