Skip to content

Commit

Permalink
Merge pull request #17 from Samuellyworld/dev
Browse files Browse the repository at this point in the history
Dev
  • Loading branch information
Samuellyworld authored Feb 29, 2024
2 parents 0d7bdb3 + 8b77b48 commit 7c19058
Show file tree
Hide file tree
Showing 3 changed files with 138 additions and 120 deletions.
52 changes: 17 additions & 35 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,49 +29,20 @@
</p>

## 📝 About

Exploring the development of a crowdfunding smart contract on the Solana blockchain, leveraging the Rust programming language and the Anchor framework. Crowdfunding has emerged as a popular method for raising funds for various projects, initiatives, and charitable causes, and blockchain technology introduces new possibilities for enhancing transparency, security, and efficiency in this process.

## 🏛️ Architecture

<p align="center">
<br>
<img src="./public/system-design.png" alt="system design"/>
<br>
</p>

```sh
- User Interface
┌───────────────┐ ┌───────────────┐ ┌───────────────┐
│ Frontend │ │ Frontend │ │ Frontend │
└───────┬───────┘ └───────┬───────┘ └───────┬───────┘
│ │ │
▼ ▼ ▼
┌───────────────┐ ┌───────────────┐ ┌───────────────┐
│ User Wallet │ │ User Wallet │ │ User Wallet │
└───────────────┘ └───────────────┘ └───────────────┘
│ │ │
└───────────────┬──────────┼───────────────┬──────────┼───────────────┐
▼ │ ▼ │ │
┌───────────────┐ │ ┌───────────────┐ │ Smart │
│ Solana RPC │ │ │ Solana RPC │ │ Contracts │
└───────────────┘ │ └───────────────┘ │ │
│ │ │ │ │
└──────────┼──────────────┼──────────┼───────────────┘
▼ ▼ │
┌─────────────────────────┐ │
│ Anchor Lang Program │◀──────┘
└─────────────────────────┘
│ │ │
│ │ │
┌────────────┘ │ └────────────┐
│ │ │
┌────────────────┐┌────────────────┐┌────────────────┐
│ Create ││ Withdraw ││ Donate │
│ Function ││ Function ││ Function │
└────────────────┘└────────────────┘└────────────────┘
```

## 🎯 Features
The crowdfunding smart contract implemented using the Anchor framework on the Solana blockchain offers a range of features designed to enhance the fundraising experience while ensuring transparency, security, and efficiency.

The crowdfunding smart contract implemented using the Anchor framework on the Solana blockchain offers a range of features designed to enhance the fundraising experience while ensuring transparency, security, and efficiency.

1. Campaign Creation:

Expand Down Expand Up @@ -122,6 +93,17 @@ category : "which type of campaign"
8. Immutable Record Keeping:

- Transactional data and campaign details recorded on the Solana blockchain are immutable and tamper-proof, providing a permanent and verifiable record of fundraising activities.
Immutable records enhance auditability, mitigating the risk of fraud or data manipulation and fostering trust among stakeholders.
Immutable records enhance auditability, mitigating the risk of fraud or data manipulation and fostering trust among stakeholders.

##
## 🗂️ Folder Structure.

```sh
CrowdFund/
├── programs/smart-contracts/
├ ├── src/
├ ├── lib.rs (contains smart contracts code)
├── tests/
├── smart-contracts.ts (contains test cases for smart contracts)


```
206 changes: 121 additions & 85 deletions programs/smart-contracts/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,111 +1,147 @@
use anchor_lang::prelude::*;
use anchor_lang::solana_program::entrypoint::ProgramResult;

declare_id!("HYCWfDk8ZU8SF5oF9CE2CyChgBU6yndn82Umo4iE1Q9T");
declare_id!("E4fXqx7ybioeqZsHWNndNnqnpQ93DnV99gKnnxWXjvdu");

#[program]
pub mod smart_contracts {
use super::*;

//creates a campaign
pub fn create(
ctx: Context<Create>,
name: String,
description: String,
target_amount: u64,
project_url: String,
progress_update_url: String,
project_image_url: String,
category: String
) -> ProgramResult {
let campaign = &mut ctx.accounts.campaign;
campaign.name = name;
campaign.description = description;
campaign.target_amount = target_amount;
campaign.project_url = project_url;
campaign.progress_update_url = progress_update_url;
campaign.project_image_url = project_image_url;
campaign.category = category;
campaign.amount_donated = 0;
campaign.amount_withdrawn = 0;
campaign.admin = *ctx.accounts.user.key;
Ok(())
use super::*;

//creates a campaign
pub fn create(
ctx: Context<Create>,
name: String,
description: String,
target_amount: u64,
project_url: String,
progress_update_url: String,
project_image_url: String,
category: String
) -> ProgramResult {
let campaign = &mut ctx.accounts.campaign;
campaign.name = name;
campaign.description = description;
campaign.target_amount = target_amount;
campaign.project_url = project_url;
campaign.progress_update_url = progress_update_url;
campaign.project_image_url = project_image_url;
campaign.category = category;
campaign.amount_donated = 0;
campaign.amount_withdrawn = 0;
campaign.admin = *ctx.accounts.user.key;
Ok(())
}



//Withdraw from a campaign
pub fn withdraw(ctx: Context<Withdraw>, amount: u64) -> ProgramResult {
let campaign = &mut ctx.accounts.campaign;
let user = &mut ctx.accounts.user;
//restricts Withdrawal to campaign admin
if campaign.admin != *user.key {
return Err(ProgramError::IncorrectProgramId);
}
//Withdraw from a campaign
pub fn withdraw(ctx: Context<Withdraw>, amount: u64) -> ProgramResult {
let campaign = &mut ctx.accounts.campaign;
let user = &mut ctx.accounts.user;
//restricts Withdrawal to campaign admin
if campaign.admin != *user.key {
return Err(ProgramError::IncorrectProgramId);
}
let rent_balance = Rent::get()?.minimum_balance(campaign.to_account_info().data_len());
if **campaign.to_account_info().lamports.borrow() - rent_balance < amount {
return Err(ProgramError::InsufficientFunds);
}
**campaign.to_account_info().try_borrow_mut_lamports()? -= amount;
**user.to_account_info().try_borrow_mut_lamports()? += amount;
(&mut ctx.accounts.campaign).amount_withdrawn += amount;
Ok(())
let rent_balance = Rent::get()?.minimum_balance(campaign.to_account_info().data_len());
if **campaign.to_account_info().lamports.borrow() - rent_balance < amount {
return Err(ProgramError::InsufficientFunds);
}
//Donate to a campaign
pub fn donate(ctx: Context<Donate>, amount: u64) -> ProgramResult {
let ix = anchor_lang::solana_program::system_instruction::transfer(
&ctx.accounts.user.key(),
&ctx.accounts.campaign.key(),
amount
);
anchor_lang::solana_program::program::invoke(
&ix,
&[ctx.accounts.user.to_account_info(), ctx.accounts.campaign.to_account_info()]
);
(&mut ctx.accounts.campaign).amount_donated += amount;
Ok(())
**campaign.to_account_info().try_borrow_mut_lamports()? -= amount;
**user.to_account_info().try_borrow_mut_lamports()? += amount;
(&mut ctx.accounts.campaign).amount_withdrawn += amount;
Ok(())
}



//Donate to a campaign
pub fn donate(ctx: Context<Donate>, amount: u64) -> ProgramResult {
let ix = anchor_lang::solana_program::system_instruction::transfer(
&ctx.accounts.user.key(),
&ctx.accounts.campaign.key(),
amount
);
// Store the result of the invoke function call
let result = anchor_lang::solana_program::program::invoke(
&ix,
&[ctx.accounts.user.to_account_info(), ctx.accounts.campaign.to_account_info()]
);
// Check if the invoke operation was successful
if let Err(e) = result {
return Err(e.into()); // Convert the error to a ProgramResult
}
// Proceed with the rest of the function
(&mut ctx.accounts.campaign).amount_donated += amount;
Ok(())
}

//Get the campaign
pub fn get_campaign(ctx: Context<GetCampaign>) -> ProgramResult {
let campaign = &ctx.accounts.campaign;
let user = &ctx.accounts.user;
if campaign.admin != *user.key {
return Err(ProgramError::IncorrectProgramId);
}
Ok(())
}


}

#[derive(Accounts)]
pub struct Create<'info> {
#[account(
init,
payer = user,
space = 9000,
seeds = [b"CROWDFUND".as_ref(), user.key().as_ref()],
bump
)]
pub campaign: Account<'info, Campaign>,
#[account(mut)]
pub user: Signer<'info>,
pub system_program: Program<'info, System>,
#[account(
init,
payer = user,
space = 9000,
seeds = [b"CROWDFUND".as_ref(), user.key().as_ref()],
bump
)]
pub campaign: Account<'info, Campaign>,
#[account(mut)]
pub user: Signer<'info>,
pub system_program: Program<'info, System>,
}


#[derive(Accounts)]
pub struct Withdraw<'info> {
#[account(mut)]
pub campaign: Account<'info, Campaign>,
#[account(mut)]
pub user: Signer<'info>,
#[account(mut)]
pub campaign: Account<'info, Campaign>,
#[account(mut)]
pub user: Signer<'info>,
}



#[derive(Accounts)]
pub struct Donate<'info> {
#[account(mut)]
pub campaign: Account<'info, Campaign>,
#[account(mut)]
pub user: Signer<'info>,
pub system_program: Program<'info, System>,
#[account(mut)]
pub campaign: Account<'info, Campaign>,
#[account(mut)]
pub user: Signer<'info>,
pub system_program: Program<'info, System>,
}

#[derive(Accounts)]
pub struct GetCampaign<'info> {
#[account(mut)]
pub campaign: Account<'info, Campaign>,
#[account(mut)]
pub user: Signer<'info>,
}


#[account]
pub struct Campaign {
pub admin: Pubkey,
pub name: String,
pub description: String,
pub target_amount: u64,
pub project_url: String,
pub progress_update_url: String,
pub project_image_url: String,
pub category: String,
pub amount_donated: u64,
pub amount_withdrawn: u64,
pub admin: Pubkey,
pub name: String,
pub description: String,
pub target_amount: u64,
pub project_url: String,
pub progress_update_url: String,
pub project_image_url: String,
pub category: String,
pub amount_donated: u64,
pub amount_withdrawn: u64,
}
Binary file modified public/system-design.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit 7c19058

Please sign in to comment.