Skip to content
Open
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
39 changes: 24 additions & 15 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,12 @@ This project provides a hands-on introduction to Substrate's FRAME development p

TLDR: If you are not familiar with Git & Github, follow these steps below to fork and setup your own repository.

- Step 1: Install Git & Github Desktop (optional) on your local device
- Step 2: Fork this repository by click the `Fork button` on Github
- Step 1: Install Git & Github Desktop (optional) on your local device
- Step 2: Fork this repository by click the `Fork button` on Github

![image](https://github.com/openguild-labs/open-hack-rust-starter/assets/56880684/7fa2f01a-b523-4208-92db-d8af7a274d98)

- Step 3: `Clone` the forked repository to your local device using the below command
- Step 3: `Clone` the forked repository to your local device using the below command

```sh
git clone https://github.com/<your_github_username>/frame-challenges.git
Expand All @@ -23,22 +23,22 @@ Replace the `[name-of-your-account]` with your Github username. For example, if
git clone https://github.com/openguild-labs/frame-challenges.git
```

- Step 4: Edit the `README.md` file to register for official participation
- Step 4: Edit the `README.md` file to register for official participation

Go to **Participant Registration** section and register to be the workshop participants. Add the below to the list, replace any placeholder with your personal information.

```
| 🦄 | Name | Github username | Your current occupation |
```

- Step 5: `Commit` your code and push to the forked Github repository
- Step 5: `Commit` your code and push to the forked Github repository

```
git add .
git commit -m "Register for OpenGuild FRAME Challenges"
```

- Step 6: Create a `Pull Request` to merge your changes to this repository and name your PR as `Your name | Register for OpenGuild FRAME Challenges`
- Step 6: Create a `Pull Request` to merge your changes to this repository and name your PR as `Your name | Register for OpenGuild FRAME Challenges`

<img width="1166" alt="Screenshot 2024-04-19 at 16 23 45" src="https://github.com/openguild-labs/open-hack-rust-starter/assets/56880684/7554ca7d-da68-4a23-893a-4f2c11a78d37">

Expand All @@ -56,15 +56,16 @@ After learning about Substrate, FRAME, Runtime, and Pallets in Polkadot SDK, thi

### Key Concepts:

- **FRAME Pallets**: Libraries for building Substrate runtime, including core frame components and functional pallets
- **Runtime**: A collection of FRAME pallets that define blockchain logic
- **FRAME Pallets**: Libraries for building Substrate runtime, including core frame components and functional pallets
- **Runtime**: A collection of FRAME pallets that define blockchain logic

### 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`

- `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`

### Runtime Configuration

Expand All @@ -90,7 +91,15 @@ impl GovernanceConfig for Runtime {

OpenGuild is a builder-driven community centered around Polkadot. OpenGuild is built by Web3 builders for Web3 builders. Our primary aim is to cater to developers seeking a comprehensive understanding of the Polkadot blockchain, providing curated, in-depth materials with a low-level approach.

- **About us:** [Learn more about us](https://openguild.wtf/about)
- **Website:** [OpenGuild Website](https://openguild.wtf/)
- **Github:** [OpenGuild Labs](https://github.com/openguild-labs)
- **Discord**: [Openguild Discord Channel](https://discord.gg/bcjMzxqtD7)
- **About us:** [Learn more about us](https://openguild.wtf/about)
- **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 |
| :---: | ---------------------- | :-------------------------------------: | ------------------------------ |
| 💀 | Made Praba Jaya Kusuma | [mdepraba](https://github.com/mdepraba) | Information Technology Student |
68 changes: 59 additions & 9 deletions src/governance.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
use crate::staking::StakingConfig;
use crate::system::SystemConfig;
// use crate::system::SystemConfig;
use std::collections::HashMap;

pub trait GovernanceConfig: StakingConfig {}

pub struct Proposal {
pub struct Proposal<T: GovernanceConfig> {
creator: T::AccountId,
description: String,
yes_votes: u32,
no_votes: u32,
Expand All @@ -19,14 +20,18 @@ pub enum ProposalStatus {
}

pub struct GovernancePallet<T: GovernanceConfig> {
pub proposals: HashMap<u32, Proposal>,
pub proposals: HashMap<u32, Proposal<T>>,
pub votes: HashMap<(T::AccountId, u32), bool>, // (voter, proposal_id) -> vote_type
next_proposal_id: u32,
}

impl<T: GovernanceConfig> GovernancePallet<T> {
pub fn new() -> Self {
todo!()
Self {
proposals: HashMap::new(),
votes: HashMap::new(),
next_proposal_id: 0,
}
}

// Create a new proposal
Expand All @@ -35,7 +40,18 @@ impl<T: GovernanceConfig> GovernancePallet<T> {
creator: T::AccountId,
description: String,
) -> Result<u32, &'static str> {
todo!()
let proposal = Proposal {
creator,
description,
yes_votes: 0,
no_votes: 0,
status: ProposalStatus::Active,
};

self.next_proposal_id += 1;
self.proposals.insert(self.next_proposal_id, proposal);

Ok(self.next_proposal_id)
}

// Vote on a proposal (true = yes, false = no)
Expand All @@ -45,17 +61,51 @@ impl<T: GovernanceConfig> GovernancePallet<T> {
proposal_id: u32,
vote_type: bool,
) -> Result<(), &'static str> {
todo!()
let proposal = self
.proposals
.get_mut(&proposal_id)
.ok_or("Proposal not found")?;
let vote = self
.votes
.get(&(voter, proposal_id))
.copied()
.unwrap_or(false);

if vote {
return Err("Already voted");
}

if vote_type {
proposal.yes_votes += 1;
} else {
proposal.no_votes += 1;
}

Ok(())
}

// Get proposal details
pub fn get_proposal(&self, proposal_id: u32) -> Option<&Proposal> {
todo!()
pub fn get_proposal(&self, proposal_id: u32) -> Option<&Proposal<T>> {
match self.proposals.get(&proposal_id) {
Some(proposal) => Some(proposal),
None => None,
}
}

// Finalize a proposal (changes status based on votes)
pub fn finalize_proposal(&mut self, proposal_id: u32) -> Result<ProposalStatus, &'static str> {
todo!()
let proposal = self
.proposals
.get_mut(&proposal_id)
.ok_or("Proposal not found")?;

if proposal.yes_votes > proposal.no_votes {
proposal.status = ProposalStatus::Approved;
} else {
proposal.status = ProposalStatus::Rejected;
}

Ok(proposal.status.clone())
}
}

Expand Down
47 changes: 40 additions & 7 deletions src/staking.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use std::collections::HashMap;

pub trait StakingConfig: SystemConfig {
// Define the Balance type with ability to perform checked arithmetic operations
type Balance: Zero + CheckedSub + CheckedAdd + Copy;
type Balance: Zero + CheckedSub + CheckedAdd + Copy + PartialOrd;
}

pub struct StakingPallet<T: StakingConfig> {
Expand All @@ -16,32 +16,65 @@ pub struct StakingPallet<T: StakingConfig> {

impl<T: StakingConfig> StakingPallet<T> {
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 free_balance = self.get_free_balance(who.clone());
if free_balance < amount {
return Err("Insufficient balance");
}

self.free_balances
.insert(who.clone(), free_balance.checked_sub(&amount).unwrap());

let staked_balance = self.get_staked_balance(who.clone());
self.staked_balances
.insert(who, staked_balance.checked_add(&amount).unwrap());

Ok(())
}

// Unstake tokens (move from staked to free)
pub fn unstake(&mut self, who: T::AccountId, amount: T::Balance) -> Result<(), &'static str> {
todo!()
let staked_balance = self.get_staked_balance(who.clone());
if staked_balance < amount {
return Err("Insufficient staked balance");
}

self.staked_balances
.insert(who.clone(), staked_balance.checked_sub(&amount).unwrap());

let free_balance = self.get_free_balance(who.clone());
self.free_balances
.insert(who, free_balance.checked_add(&amount).unwrap());

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(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)
.copied()
.unwrap_or(T::Balance::zero())
}
}

Expand Down