-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
43 changed files
with
1,890 additions
and
493 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
pub const ANCHOR_DISCRIMINATOR_SIZE: usize = 8; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
use anchor_lang::prelude::*; | ||
|
||
#[error_code] | ||
pub enum ErrorCode { | ||
#[msg("Th program has already been initialied.")] | ||
AlreadyInitialized, | ||
#[msg("Title exceeds the maximum length of 64 characters.")] | ||
TitleTooLong, | ||
#[msg("Description exceeds the maximum length of 512 characters.")] | ||
DescriptionTooLong, | ||
#[msg("Image URL exceeds the maximum length of 256 characters.")] | ||
ImageUrlTooLong, | ||
#[msg("Invalid goal amount. Goal must be greater than zero.")] | ||
InvalidGoalAmount, | ||
#[msg("Unauthorized access.")] | ||
Unauthorized, | ||
#[msg("Campaign not found.")] | ||
CampaignNotFound, | ||
#[msg("Campaign is inactive.")] | ||
InactiveCampaign, | ||
#[msg("Donation amount must be at least 1 SOL.")] | ||
InvalidDonationAmount, | ||
#[msg("Campaign goal reached.")] | ||
CampaignGoalActualized, | ||
#[msg("Withdrawal amount must be at least 1 SOL.")] | ||
InvalidWithdrawalAmount, | ||
#[msg("Insufficient funds in the campaign.")] | ||
InsufficientFund, | ||
#[msg("The provided platform address is invalid.")] | ||
InvalidPlatformAddress, | ||
#[msg("Invalid platform fee percentage.")] | ||
InvalidPlatformFee, | ||
} |
66 changes: 66 additions & 0 deletions
66
anchor/programs/fundus/src/instructions/create_campaign.rs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
use crate::constants::ANCHOR_DISCRIMINATOR_SIZE; | ||
use crate::errors::ErrorCode::*; | ||
use crate::states::{Campaign, ProgramState}; | ||
use anchor_lang::prelude::*; | ||
|
||
pub fn create_campaign( | ||
ctx: Context<CreateCampaignCtx>, | ||
title: String, | ||
description: String, | ||
image_url: String, | ||
goal: u64, | ||
) -> Result<()> { | ||
let campaign = &mut ctx.accounts.campaign; | ||
let state = &mut ctx.accounts.program_state; | ||
|
||
if title.len() > 64 { | ||
return Err(TitleTooLong.into()); | ||
} | ||
if description.len() > 512 { | ||
return Err(DescriptionTooLong.into()); | ||
} | ||
if image_url.len() > 256 { | ||
return Err(ImageUrlTooLong.into()); | ||
} | ||
if goal < 1_000_000_000 { | ||
return Err(InvalidGoalAmount.into()); | ||
} | ||
|
||
state.campaign_count += 1; | ||
|
||
campaign.cid = state.campaign_count; | ||
campaign.creator = ctx.accounts.creator.key(); | ||
campaign.title = title; | ||
campaign.description = description; | ||
campaign.image_url = image_url; | ||
campaign.goal = goal; | ||
campaign.amount_raised = 0; | ||
campaign.donors = 0; | ||
campaign.withdrawals = 0; | ||
campaign.timestamp = Clock::get()?.unix_timestamp as u64; | ||
campaign.active = true; | ||
|
||
Ok(()) | ||
} | ||
|
||
#[derive(Accounts)] | ||
pub struct CreateCampaignCtx<'info> { | ||
#[account(mut)] | ||
pub program_state: Account<'info, ProgramState>, | ||
|
||
#[account( | ||
init, | ||
payer = creator, | ||
space = ANCHOR_DISCRIMINATOR_SIZE + Campaign::INIT_SPACE, | ||
seeds = [ | ||
b"campaign", | ||
(program_state.campaign_count + 1).to_le_bytes().as_ref() | ||
], | ||
bump | ||
)] | ||
pub campaign: Account<'info, Campaign>, | ||
|
||
#[account(mut)] | ||
pub creator: Signer<'info>, | ||
pub system_program: Program<'info, System>, | ||
} |
42 changes: 42 additions & 0 deletions
42
anchor/programs/fundus/src/instructions/delete_campaign.rs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
use crate::errors::ErrorCode::*; | ||
use crate::states::Campaign; | ||
use anchor_lang::prelude::*; | ||
|
||
pub fn delete_campaign(ctx: Context<DeleteCampaignCtx>, cid: u64) -> Result<()> { | ||
let campaign = &mut ctx.accounts.campaign; | ||
let creator = &mut ctx.accounts.creator; | ||
|
||
if campaign.creator != creator.key() { | ||
return Err(Unauthorized.into()); | ||
} | ||
|
||
if campaign.cid != cid { | ||
return Err(CampaignNotFound.into()); | ||
} | ||
|
||
if !campaign.active { | ||
return Err(InactiveCampaign.into()); | ||
} | ||
|
||
campaign.active = false; | ||
|
||
Ok(()) | ||
} | ||
|
||
#[derive(Accounts)] | ||
#[instruction(cid: u64)] | ||
pub struct DeleteCampaignCtx<'info> { | ||
#[account( | ||
mut, | ||
seeds = [ | ||
b"campaign", | ||
cid.to_le_bytes().as_ref() | ||
], | ||
bump | ||
)] | ||
pub campaign: Account<'info, Campaign>, | ||
|
||
#[account(mut)] | ||
pub creator: Signer<'info>, | ||
pub system_program: Program<'info, System>, | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,86 @@ | ||
use crate::constants::ANCHOR_DISCRIMINATOR_SIZE; | ||
use crate::errors::ErrorCode::*; | ||
use crate::states::{Campaign, Transaction}; | ||
use anchor_lang::prelude::*; | ||
|
||
pub fn donate(ctx: Context<DonateCtx>, cid: u64, amount: u64) -> Result<()> { | ||
let campaign = &mut ctx.accounts.campaign; | ||
let donor = &mut ctx.accounts.donor; | ||
let transaction = &mut ctx.accounts.transaction; | ||
|
||
if campaign.cid != cid { | ||
return Err(CampaignNotFound.into()); | ||
} | ||
|
||
if !campaign.active { | ||
return Err(InactiveCampaign.into()); | ||
} | ||
|
||
if amount < 1_000_000_000 { | ||
return Err(InvalidGoalAmount.into()); | ||
} | ||
|
||
if campaign.amount_raised >= campaign.goal { | ||
return Err(CampaignGoalActualized.into()); | ||
} | ||
|
||
let tx_instruction = anchor_lang::solana_program::system_instruction::transfer( | ||
&donor.key(), | ||
&campaign.key(), | ||
amount, | ||
); | ||
|
||
let result = anchor_lang::solana_program::program::invoke( | ||
&tx_instruction, | ||
&[donor.to_account_info(), campaign.to_account_info()], | ||
); | ||
|
||
if let Err(e) = result { | ||
msg!("Donation transfer failed: {:?}", e); | ||
return Err(e.into()); | ||
} | ||
|
||
campaign.amount_raised += amount; | ||
campaign.balance += amount; | ||
campaign.donors += 1; | ||
|
||
transaction.amount = amount; | ||
transaction.cid = cid; | ||
transaction.owner = donor.key(); | ||
transaction.timestamp = Clock::get()?.unix_timestamp as u64; | ||
transaction.credited = true; | ||
|
||
Ok(()) | ||
} | ||
|
||
#[derive(Accounts)] | ||
#[instruction(cid: u64)] | ||
pub struct DonateCtx<'info> { | ||
#[account( | ||
mut, | ||
seeds = [ | ||
b"campaign", | ||
cid.to_le_bytes().as_ref() | ||
], | ||
bump | ||
)] | ||
pub campaign: Account<'info, Campaign>, | ||
|
||
#[account( | ||
init, | ||
payer = donor, | ||
space = ANCHOR_DISCRIMINATOR_SIZE + Transaction::INIT_SPACE, | ||
seeds = [ | ||
b"donor", | ||
donor.key().as_ref(), | ||
cid.to_le_bytes().as_ref(), | ||
(campaign.donors + 1).to_le_bytes().as_ref() | ||
], | ||
bump | ||
)] | ||
pub transaction: Account<'info, Transaction>, | ||
|
||
#[account(mut)] | ||
pub donor: Signer<'info>, | ||
pub system_program: Program<'info, System>, | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
use anchor_lang::prelude::*; | ||
|
||
use crate::constants::ANCHOR_DISCRIMINATOR_SIZE; | ||
use crate::errors::ErrorCode::AlreadyInitialized; | ||
use crate::states::ProgramState; | ||
|
||
pub fn initialize(ctx: Context<InitializeCtx>) -> Result<()> { | ||
let state = &mut ctx.accounts.program_state; | ||
let deployer = &ctx.accounts.deployer; | ||
|
||
if state.initialized { | ||
return Err(AlreadyInitialized.into()); | ||
} | ||
|
||
state.campaign_count = 0; | ||
state.platform_fee = 5; | ||
state.platform_address = deployer.key(); | ||
state.initialized = true; | ||
|
||
Ok(()) | ||
} | ||
|
||
#[derive(Accounts)] | ||
pub struct InitializeCtx<'info> { | ||
#[account( | ||
init, | ||
payer = deployer, | ||
space = ANCHOR_DISCRIMINATOR_SIZE + ProgramState::INIT_SPACE, | ||
seeds = [b"program_state"], | ||
bump | ||
)] | ||
pub program_state: Account<'info, ProgramState>, | ||
|
||
#[account(mut)] | ||
pub deployer: Signer<'info>, | ||
pub system_program: Program<'info, System>, | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
pub mod create_campaign; | ||
pub mod delete_campaign; | ||
pub mod donate; | ||
pub mod initialize; | ||
pub mod update_campaign; | ||
pub mod update_platform_settings; | ||
pub mod withdraw; | ||
|
||
pub use create_campaign::*; | ||
pub use delete_campaign::*; | ||
pub use donate::*; | ||
pub use initialize::*; | ||
pub use update_campaign::*; | ||
pub use update_platform_settings::*; | ||
pub use withdraw::*; |
61 changes: 61 additions & 0 deletions
61
anchor/programs/fundus/src/instructions/update_campaign.rs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
use crate::errors::ErrorCode::*; | ||
use crate::states::Campaign; | ||
use anchor_lang::prelude::*; | ||
|
||
pub fn update_campaign( | ||
ctx: Context<UpdateCampaignCtx>, | ||
cid: u64, | ||
title: String, | ||
description: String, | ||
image_url: String, | ||
goal: u64, | ||
) -> Result<()> { | ||
let campaign = &mut ctx.accounts.campaign; | ||
let creator = &mut ctx.accounts.creator; | ||
|
||
if campaign.creator != creator.key() { | ||
return Err(Unauthorized.into()); | ||
} | ||
|
||
if campaign.cid != cid { | ||
return Err(CampaignNotFound.into()); | ||
} | ||
|
||
if title.len() > 64 { | ||
return Err(TitleTooLong.into()); | ||
} | ||
if description.len() > 512 { | ||
return Err(DescriptionTooLong.into()); | ||
} | ||
if image_url.len() > 256 { | ||
return Err(ImageUrlTooLong.into()); | ||
} | ||
if goal < 1_000_000_000 { | ||
return Err(InvalidGoalAmount.into()); | ||
} | ||
|
||
campaign.title = title; | ||
campaign.description = description; | ||
campaign.image_url = image_url; | ||
campaign.goal = goal; | ||
|
||
Ok(()) | ||
} | ||
|
||
#[derive(Accounts)] | ||
#[instruction(cid: u64)] | ||
pub struct UpdateCampaignCtx<'info> { | ||
#[account( | ||
mut, | ||
seeds = [ | ||
b"campaign", | ||
cid.to_le_bytes().as_ref() | ||
], | ||
bump | ||
)] | ||
pub campaign: Account<'info, Campaign>, | ||
|
||
#[account(mut)] | ||
pub creator: Signer<'info>, | ||
pub system_program: Program<'info, System>, | ||
} |
36 changes: 36 additions & 0 deletions
36
anchor/programs/fundus/src/instructions/update_platform_settings.rs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
use crate::errors::ErrorCode::*; | ||
use crate::states::ProgramState; | ||
use anchor_lang::prelude::*; | ||
|
||
pub fn update_platform_settings( | ||
ctx: Context<UpdatePlatformSettingsCtx>, | ||
new_platform_fee: u64, | ||
) -> Result<()> { | ||
let state = &mut ctx.accounts.program_state; | ||
let updater = &ctx.accounts.updater; | ||
|
||
if updater.key() != state.platform_address { | ||
return Err(Unauthorized.into()); | ||
} | ||
|
||
if !(1..=15).contains(&new_platform_fee) { | ||
return Err(InvalidPlatformFee.into()); | ||
} | ||
|
||
state.platform_fee = new_platform_fee; | ||
|
||
Ok(()) | ||
} | ||
|
||
#[derive(Accounts)] | ||
pub struct UpdatePlatformSettingsCtx<'info> { | ||
#[account(mut)] | ||
pub updater: Signer<'info>, | ||
|
||
#[account( | ||
mut, | ||
seeds = [b"program_state"], | ||
bump | ||
)] | ||
pub program_state: Account<'info, ProgramState>, | ||
} |
Oops, something went wrong.