diff --git a/README.md b/README.md index a3c538c..cf55bbc 100644 --- a/README.md +++ b/README.md @@ -29,49 +29,20 @@

## 📝 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 +


system design

-```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: @@ -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. -## \ No newline at end of file +## 🗂️ Folder Structure. + +```sh +CrowdFund/ +├── programs/smart-contracts/ +├ ├── src/ +├ ├── lib.rs (contains smart contracts code) +├── tests/ + ├── smart-contracts.ts (contains test cases for smart contracts) + + +``` diff --git a/programs/smart-contracts/src/lib.rs b/programs/smart-contracts/src/lib.rs index 3174354..6bc6eb2 100644 --- a/programs/smart-contracts/src/lib.rs +++ b/programs/smart-contracts/src/lib.rs @@ -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, - 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, + 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, 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, 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, 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, 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) -> 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, } diff --git a/public/system-design.png b/public/system-design.png index daaca26..c292bd3 100644 Binary files a/public/system-design.png and b/public/system-design.png differ