From 37df83769266e7477a4567d7a98fcc22a6e308e9 Mon Sep 17 00:00:00 2001 From: Maksym <3645723+makarychev@users.noreply.github.com> Date: Fri, 7 Jun 2024 10:29:01 +0300 Subject: [PATCH] refactor code base (#11) --- .../donaproto/src/contexts/create_donation.rs | 95 --------- programs/donaproto/src/contexts/donate.rs | 63 ------ .../src/contexts/initialize_contributor.rs | 50 ----- .../contexts/initialize_donation_protocol.rs | 57 ----- .../donaproto/src/contexts/withdraw_funds.rs | 46 ---- .../src/instructions/create_donation.rs | 89 ++++++++ programs/donaproto/src/instructions/donate.rs | 151 +++++++++++++ .../instructions/initialize_contributor.rs | 37 ++++ .../src/instructions/initialize_creator.rs | 38 ++++ .../initialize_donation_protocol.rs | 47 +++++ .../src/{contexts => instructions}/mod.rs | 1 - .../src/instructions/withdraw_funds.rs | 97 +++++++++ programs/donaproto/src/lib.rs | 199 ++---------------- .../src/{contexts => states}/common.rs | 0 .../donaproto/src/states/contributor_data.rs | 28 +++ .../creator_data.rs} | 24 +-- .../donaproto/src/states/donation_data.rs | 46 ++++ .../src/states/donation_protocol_data.rs | 32 +++ programs/donaproto/src/states/mod.rs | 14 ++ 19 files changed, 598 insertions(+), 516 deletions(-) delete mode 100644 programs/donaproto/src/contexts/create_donation.rs delete mode 100644 programs/donaproto/src/contexts/donate.rs delete mode 100644 programs/donaproto/src/contexts/initialize_contributor.rs delete mode 100644 programs/donaproto/src/contexts/initialize_donation_protocol.rs delete mode 100644 programs/donaproto/src/contexts/withdraw_funds.rs create mode 100644 programs/donaproto/src/instructions/create_donation.rs create mode 100644 programs/donaproto/src/instructions/donate.rs create mode 100644 programs/donaproto/src/instructions/initialize_contributor.rs create mode 100644 programs/donaproto/src/instructions/initialize_creator.rs create mode 100644 programs/donaproto/src/instructions/initialize_donation_protocol.rs rename programs/donaproto/src/{contexts => instructions}/mod.rs (95%) create mode 100644 programs/donaproto/src/instructions/withdraw_funds.rs rename programs/donaproto/src/{contexts => states}/common.rs (100%) create mode 100644 programs/donaproto/src/states/contributor_data.rs rename programs/donaproto/src/{contexts/initialize_creator.rs => states/creator_data.rs} (54%) create mode 100644 programs/donaproto/src/states/donation_data.rs create mode 100644 programs/donaproto/src/states/donation_protocol_data.rs create mode 100644 programs/donaproto/src/states/mod.rs diff --git a/programs/donaproto/src/contexts/create_donation.rs b/programs/donaproto/src/contexts/create_donation.rs deleted file mode 100644 index 72190cd..0000000 --- a/programs/donaproto/src/contexts/create_donation.rs +++ /dev/null @@ -1,95 +0,0 @@ -use anchor_lang::prelude::*; -use std::mem; -use crate::{common::DISCRIMINATOR_LEN, CreatorData, DonationProtocolData, CREATOR_PREFIX}; -use anchor_spl::token::{Mint, TokenAccount}; - -pub const HOLDING_PREFIX: &str = "holding"; - -#[account] -#[derive(Default)] -pub struct DonationData { - pub amount_collecting: u64, - pub total_amount_received: u64, - pub ending_timestamp: u64, - pub is_closed: bool, - pub recipient: Pubkey, - pub donation_protocol: Pubkey, - pub holding_wallet: Pubkey, - pub creator_data: Pubkey, - pub holding_bump: u8, - pub ipfs_hash: String, -} - -pub const MAX_IPFS_HASH_LEN: usize = 64; - -impl DonationData { - const AMOUNT_COLLECTING_LEN: usize = mem::size_of::(); - const TOTAL_AMOUNT_RECEIVED_LEN: usize = mem::size_of::(); - const ENDING_TIMESTAMP_LEN: usize = mem::size_of::(); - const IS_CLOSED_LEN: usize = mem::size_of::(); - const RECIPIENT_LEN: usize = mem::size_of::(); - const DONATION_PROTOCOL_LEN: usize = mem::size_of::(); - const HOLDING_WALLET_LEN: usize = mem::size_of::(); - const CREATOR_DATA_LEN: usize = mem::size_of::(); - const HOLDING_BUMP_LEN: usize = mem::size_of::(); - const IPFS_HASH_LEN: usize = MAX_IPFS_HASH_LEN; - - const LEN: usize = DISCRIMINATOR_LEN - + DonationData::AMOUNT_COLLECTING_LEN - + DonationData::TOTAL_AMOUNT_RECEIVED_LEN - + DonationData::ENDING_TIMESTAMP_LEN - + DonationData::IS_CLOSED_LEN - + DonationData::RECIPIENT_LEN - + DonationData::DONATION_PROTOCOL_LEN - + DonationData::HOLDING_WALLET_LEN - + DonationData::CREATOR_DATA_LEN - + DonationData::HOLDING_BUMP_LEN - + DonationData::IPFS_HASH_LEN; -} - - -#[derive(Accounts)] -pub struct CreateDonation<'info> { - #[account(init, payer = creator_wallet_address, space = DonationData::LEN)] - pub donation_data: Account<'info, DonationData>, - #[account( - constraint = donation_protocol.donation_mint.key() == donation_mint.key(), - )] - pub donation_protocol: Account<'info, DonationProtocolData>, - - #[account( - constraint = holding_wallet.owner == *holding_wallet_owner.key, - constraint = holding_wallet.mint == donation_mint.key(), - )] - pub holding_wallet: Account<'info, TokenAccount>, - #[account( - seeds = [ - HOLDING_PREFIX.as_bytes(), - donation_data.to_account_info().key.as_ref(), - ], - bump, - )] - /// CHECK: pda account ["holding", donation_data] - holding_wallet_owner: AccountInfo<'info>, - - #[account( - constraint = recipient.mint == donation_mint.key(), - )] - pub recipient: Account<'info, TokenAccount>, - - #[account(mut, - constraint = creator_data.donation_protocol.key() == donation_protocol.key(), - seeds = [ - CREATOR_PREFIX.as_bytes(), - donation_protocol.to_account_info().key.as_ref(), - creator_wallet_address.key().as_ref(), - ], - bump, - )] - pub creator_data: Account<'info, CreatorData>, - pub donation_mint: Account<'info, Mint>, - #[account(mut)] - pub creator_wallet_address: Signer<'info>, - pub system_program: Program<'info, System>, - pub rent: Sysvar<'info, Rent> -} \ No newline at end of file diff --git a/programs/donaproto/src/contexts/donate.rs b/programs/donaproto/src/contexts/donate.rs deleted file mode 100644 index 824c94d..0000000 --- a/programs/donaproto/src/contexts/donate.rs +++ /dev/null @@ -1,63 +0,0 @@ -use anchor_lang::prelude::*; -use crate::{ContributorData, DonationData, DonationProtocolData, CONTRIBUTOR_PREFIX, TREASURY_PREFIX}; -use anchor_spl::token::{Mint, TokenAccount}; - -#[derive(Accounts)] -pub struct Donate<'info> { - #[account(mut, - constraint = donation_data.donation_protocol == donation_protocol.key(), - constraint = donation_data.holding_wallet == holding_wallet.key(), - )] - pub donation_data: Account<'info, DonationData>, - #[account(mut, - constraint = contributor_data.donation_protocol == donation_protocol.key(), - seeds = [ - CONTRIBUTOR_PREFIX.as_bytes(), - donation_protocol.to_account_info().key.as_ref(), - user_wallet.to_account_info().key.as_ref(), - ], - bump = contributor_data.bump, - )] - pub contributor_data: Account<'info, ContributorData>, - pub donation_protocol: Account<'info, DonationProtocolData>, - - #[account(mut, - constraint = user_token_wallet.owner == *user_wallet.key, - constraint = user_token_wallet.mint == donation_mint.key(), - )] - pub user_token_wallet: Account<'info, TokenAccount>, - #[account(mut, - constraint = user_reward_token_wallet.owner == *user_wallet.key, - constraint = user_reward_token_wallet.mint == reward_mint.key(), - )] - pub user_reward_token_wallet: Account<'info, TokenAccount>, - #[account(mut, - constraint = donation_protocol.treasury_mint.key() == reward_mint.key(), - constraint = reward_treasury.key() == donation_protocol.treasury.key(), - )] - pub reward_treasury: Account<'info, TokenAccount>, - #[account( - seeds = [TREASURY_PREFIX.as_bytes(), donation_protocol.key().as_ref()], - bump = donation_protocol.treasury_owner_bump, - )] - /// CHECK: pda account ["treasury", donation_protocol_data] - pub reward_treasury_owner: AccountInfo<'info>, - - #[account(mut, - constraint = holding_wallet.mint == donation_mint.key(), - constraint = holding_wallet.key() == donation_data.holding_wallet, - )] - pub holding_wallet: Account<'info, TokenAccount>, - #[account( - constraint = donation_protocol.donation_mint.key() == donation_mint.key(), - )] - pub donation_mint: Account<'info, Mint>, - #[account( - constraint = donation_protocol.treasury_mint.key() == reward_mint.key(), - )] - pub reward_mint: Account<'info, Mint>, - - #[account(mut)] - pub user_wallet: Signer<'info>, - pub token_program: Program<'info, anchor_spl::token::Token>, -} \ No newline at end of file diff --git a/programs/donaproto/src/contexts/initialize_contributor.rs b/programs/donaproto/src/contexts/initialize_contributor.rs deleted file mode 100644 index bb61af3..0000000 --- a/programs/donaproto/src/contexts/initialize_contributor.rs +++ /dev/null @@ -1,50 +0,0 @@ -use anchor_lang::prelude::*; -use std::mem; -use crate::{common::DISCRIMINATOR_LEN, DonationProtocolData}; - -pub const CONTRIBUTOR_PREFIX: &str = "contributor"; - -#[account] -#[derive(Default)] -pub struct ContributorData { - pub total_amount_donated: u64, - pub total_amount_earned: u64, - pub donations_count: u64, - pub donation_protocol: Pubkey, - pub bump: u8, -} - -impl ContributorData { - const TOTAL_AMOUNT_DONATED_LEN: usize = mem::size_of::(); - const TOTAL_AMOUNT_EARNED_LEN: usize = mem::size_of::(); - const DONATIONS_COUNT_LEN: usize = mem::size_of::(); - const DONATION_PROTOCOL_LEN: usize = mem::size_of::(); - const BUMP_LEN: usize = mem::size_of::(); - pub const LEN: usize = DISCRIMINATOR_LEN - + ContributorData::TOTAL_AMOUNT_DONATED_LEN - + ContributorData::TOTAL_AMOUNT_EARNED_LEN - + ContributorData::DONATIONS_COUNT_LEN - + ContributorData::DONATION_PROTOCOL_LEN - + ContributorData::BUMP_LEN; -} - - -#[derive(Accounts)] -pub struct InitializeContributor<'info> { - #[account(init, payer = payer, space = ContributorData::LEN, - seeds = [ - CONTRIBUTOR_PREFIX.as_bytes(), - donation_protocol.to_account_info().key.as_ref(), - contributor_wallet_address.key.as_ref(), - ], - bump, - )] - pub contributor_data: Account<'info, ContributorData>, - pub donation_protocol: Account<'info, DonationProtocolData>, - /// CHECK: System account for which the ContributorData is being initialized - pub contributor_wallet_address: AccountInfo<'info>, - #[account(mut)] - pub payer: Signer<'info>, - pub system_program: Program<'info, System>, - pub rent: Sysvar<'info, Rent> -} \ No newline at end of file diff --git a/programs/donaproto/src/contexts/initialize_donation_protocol.rs b/programs/donaproto/src/contexts/initialize_donation_protocol.rs deleted file mode 100644 index 8f7550e..0000000 --- a/programs/donaproto/src/contexts/initialize_donation_protocol.rs +++ /dev/null @@ -1,57 +0,0 @@ -use anchor_lang::prelude::*; -use anchor_spl::token::{Mint, TokenAccount}; -use std::mem; -use crate::common::DISCRIMINATOR_LEN; - -pub const TREASURY_PREFIX: &str = "treasury"; - -#[account] -#[derive(Default)] -pub struct DonationProtocolData { - pub treasury_mint: Pubkey, - pub treasury: Pubkey, - pub donation_mint: Pubkey, - pub min_amount_to_earn: u64, - pub min_amount_to_collect: u64, - pub treasury_owner_bump: u8 -} - -impl DonationProtocolData { - const TREASURY_MINT_LEN: usize = mem::size_of::(); - const TREASURY_LEN: usize = mem::size_of::(); - const DONATION_MINT_LEN: usize = mem::size_of::(); - const MIN_AMOUNT_TO_EARN_LEN: usize = mem::size_of::(); - const MIN_AMOUNT_TO_COLLECT_LEN: usize = mem::size_of::(); - const TREASURY_OWNER_BUMP_LEN: usize = mem::size_of::(); - pub const LEN: usize = DISCRIMINATOR_LEN - + DonationProtocolData::TREASURY_MINT_LEN - + DonationProtocolData::TREASURY_LEN - + DonationProtocolData::DONATION_MINT_LEN - + DonationProtocolData::MIN_AMOUNT_TO_EARN_LEN - + DonationProtocolData::MIN_AMOUNT_TO_COLLECT_LEN - + DonationProtocolData::TREASURY_OWNER_BUMP_LEN; -} - -#[derive(Accounts)] -pub struct InitializeDonationProtocol<'info> { - #[account(init, payer = payer, space = DonationProtocolData::LEN)] - pub donation_protocol_data: Account<'info, DonationProtocolData>, - - #[account( - constraint = treasury.owner == *treasury_owner.key, - constraint = treasury.mint == treasury_mint.key(), - )] - pub treasury: Account<'info, TokenAccount>, - #[account( - seeds = [TREASURY_PREFIX.as_bytes(), donation_protocol_data.key().as_ref()], - bump, - )] - /// CHECK: pda account ["treasury", donation_protocol_data] - pub treasury_owner: AccountInfo<'info>, - pub treasury_mint: Account<'info, Mint>, - pub donation_mint: Account<'info, Mint>, - #[account(mut)] - pub payer: Signer<'info>, - pub system_program: Program<'info, System>, - pub rent: Sysvar<'info, Rent> -} diff --git a/programs/donaproto/src/contexts/withdraw_funds.rs b/programs/donaproto/src/contexts/withdraw_funds.rs deleted file mode 100644 index 15879ef..0000000 --- a/programs/donaproto/src/contexts/withdraw_funds.rs +++ /dev/null @@ -1,46 +0,0 @@ -use anchor_lang::prelude::*; -use crate::{CreatorData, DonationData, DonationProtocolData, HOLDING_PREFIX}; -use anchor_spl::token::{Mint, TokenAccount}; - - -#[derive(Accounts)] -pub struct WithdrawFunds<'info> { - #[account(mut, - constraint = donation_data.donation_protocol == donation_protocol.key(), - constraint = donation_data.holding_wallet == holding_wallet.key(), - constraint = donation_data.creator_data == creator_data.key(), - )] - pub donation_data: Account<'info, DonationData>, - #[account(mut, - constraint = creator_data.donation_protocol == donation_protocol.key(), - )] - pub creator_data: Account<'info, CreatorData>, - pub donation_protocol: Account<'info, DonationProtocolData>, - - #[account(mut, - constraint = holding_wallet.mint == donation_mint.key(), - constraint = holding_wallet.key() == donation_data.holding_wallet, - )] - pub holding_wallet: Account<'info, TokenAccount>, - #[account( - seeds = [ - HOLDING_PREFIX.as_bytes(), - donation_data.to_account_info().key.as_ref(), - ], - bump = donation_data.holding_bump, - )] - /// CHECK: pda account ["holding", donation_data] - pub holding_wallet_owner: AccountInfo<'info>, - #[account(mut, - constraint = recipient_token_wallet.owner == *payer.key, - constraint = recipient_token_wallet.mint == donation_mint.key(), - )] - pub recipient_token_wallet: Account<'info, TokenAccount>, - #[account( - constraint = donation_protocol.donation_mint.key() == donation_mint.key(), - )] - pub donation_mint: Account<'info, Mint>, - #[account(mut)] - pub payer: Signer<'info>, - pub token_program: Program<'info, anchor_spl::token::Token>, -} \ No newline at end of file diff --git a/programs/donaproto/src/instructions/create_donation.rs b/programs/donaproto/src/instructions/create_donation.rs new file mode 100644 index 0000000..ef41872 --- /dev/null +++ b/programs/donaproto/src/instructions/create_donation.rs @@ -0,0 +1,89 @@ +use anchor_lang::prelude::*; +use anchor_spl::token::{Mint, TokenAccount}; + +use crate::{errors::DonationError, states::{CreatorData, DonationData, DonationProtocolData, MAX_IPFS_HASH_LEN}, CREATOR_PREFIX}; + +pub const HOLDING_PREFIX: &str = "holding"; + + +#[derive(Accounts)] +pub struct CreateDonation<'info> { + #[account(init, payer = creator_wallet_address, space = DonationData::LEN)] + pub donation_data: Account<'info, DonationData>, + #[account( + constraint = donation_protocol.donation_mint.key() == donation_mint.key(), + )] + pub donation_protocol: Account<'info, DonationProtocolData>, + + #[account( + constraint = holding_wallet.owner == *holding_wallet_owner.key, + constraint = holding_wallet.mint == donation_mint.key(), + )] + pub holding_wallet: Account<'info, TokenAccount>, + #[account( + seeds = [ + HOLDING_PREFIX.as_bytes(), + donation_data.to_account_info().key.as_ref(), + ], + bump, + )] + /// CHECK: pda account ["holding", donation_data] + holding_wallet_owner: AccountInfo<'info>, + + #[account( + constraint = recipient.mint == donation_mint.key(), + )] + pub recipient: Account<'info, TokenAccount>, + + #[account(mut, + constraint = creator_data.donation_protocol.key() == donation_protocol.key(), + seeds = [ + CREATOR_PREFIX.as_bytes(), + donation_protocol.to_account_info().key.as_ref(), + creator_wallet_address.key().as_ref(), + ], + bump, + )] + pub creator_data: Account<'info, CreatorData>, + pub donation_mint: Account<'info, Mint>, + #[account(mut)] + pub creator_wallet_address: Signer<'info>, + pub system_program: Program<'info, System>, + pub rent: Sysvar<'info, Rent> +} + +pub fn create_donation( + ctx: Context, + amount: u64, + ipfs_hash: String, + ending_timestamp: u64, + holding_bump: u8, +) -> Result<()> { + let now_timestamp = Clock::get().expect("Time error").unix_timestamp as u64; + if ending_timestamp <= now_timestamp { + return Err(DonationError::InvalidEndingTimestamp.into()); + } + if ipfs_hash.len() > MAX_IPFS_HASH_LEN { + return Err(DonationError::IpfsHashTooLong.into()); + } + if amount < ctx.accounts.donation_protocol.min_amount_to_collect { + return Err(DonationError::DonationAmountTooLow.into()); + } + + let donation_data = &mut ctx.accounts.donation_data; + donation_data.amount_collecting = amount; + donation_data.ending_timestamp = ending_timestamp; + donation_data.is_closed = false; + donation_data.recipient = ctx.accounts.recipient.key(); + donation_data.creator_data = ctx.accounts.creator_data.key(); + donation_data.donation_protocol = ctx.accounts.donation_protocol.key(); + donation_data.holding_wallet = ctx.accounts.holding_wallet.key(); + donation_data.holding_bump = holding_bump; + donation_data.ipfs_hash = ipfs_hash; + + let creator_data = &mut ctx.accounts.creator_data; + creator_data.total_amount_collecting = creator_data.total_amount_collecting.checked_add(amount).unwrap(); + creator_data.donations_created_count = creator_data.donations_created_count.checked_add(1).unwrap(); + + Ok(()) +} diff --git a/programs/donaproto/src/instructions/donate.rs b/programs/donaproto/src/instructions/donate.rs new file mode 100644 index 0000000..fdcd85d --- /dev/null +++ b/programs/donaproto/src/instructions/donate.rs @@ -0,0 +1,151 @@ +use anchor_lang::prelude::*; +use anchor_spl::token::{self, Mint, TokenAccount, Transfer}; + +use crate::{ + errors::DonationError, + states::{ContributorData, DonationData, DonationProtocolData}, + CONTRIBUTOR_PREFIX, TREASURY_PREFIX, +}; + +#[derive(Accounts)] +pub struct Donate<'info> { + #[account(mut, + constraint = donation_data.donation_protocol == donation_protocol.key(), + constraint = donation_data.holding_wallet == holding_wallet.key(), + )] + pub donation_data: Account<'info, DonationData>, + #[account(mut, + constraint = contributor_data.donation_protocol == donation_protocol.key(), + seeds = [ + CONTRIBUTOR_PREFIX.as_bytes(), + donation_protocol.to_account_info().key.as_ref(), + user_wallet.to_account_info().key.as_ref(), + ], + bump = contributor_data.bump, + )] + pub contributor_data: Account<'info, ContributorData>, + pub donation_protocol: Account<'info, DonationProtocolData>, + + #[account(mut, + constraint = user_token_wallet.owner == *user_wallet.key, + constraint = user_token_wallet.mint == donation_mint.key(), + )] + pub user_token_wallet: Account<'info, TokenAccount>, + #[account(mut, + constraint = user_reward_token_wallet.owner == *user_wallet.key, + constraint = user_reward_token_wallet.mint == reward_mint.key(), + )] + pub user_reward_token_wallet: Account<'info, TokenAccount>, + #[account(mut, + constraint = donation_protocol.treasury_mint.key() == reward_mint.key(), + constraint = reward_treasury.key() == donation_protocol.treasury.key(), + )] + pub reward_treasury: Account<'info, TokenAccount>, + #[account( + seeds = [TREASURY_PREFIX.as_bytes(), donation_protocol.key().as_ref()], + bump = donation_protocol.treasury_owner_bump, + )] + /// CHECK: pda account ["treasury", donation_protocol_data] + pub reward_treasury_owner: AccountInfo<'info>, + + #[account(mut, + constraint = holding_wallet.mint == donation_mint.key(), + constraint = holding_wallet.key() == donation_data.holding_wallet, + )] + pub holding_wallet: Account<'info, TokenAccount>, + #[account( + constraint = donation_protocol.donation_mint.key() == donation_mint.key(), + )] + pub donation_mint: Account<'info, Mint>, + #[account( + constraint = donation_protocol.treasury_mint.key() == reward_mint.key(), + )] + pub reward_mint: Account<'info, Mint>, + + #[account(mut)] + pub user_wallet: Signer<'info>, + pub token_program: Program<'info, anchor_spl::token::Token>, +} + +pub fn donate(ctx: Context, amount: u64) -> Result<()> { + let donation_data = &mut ctx.accounts.donation_data; + + if donation_data.is_closed { + return Err(DonationError::DonationClosed.into()); + } + + if amount == 0 { + return Err(DonationError::DonationAmountZero.into()); + } + + // Transfer amount from user to donation holding wallet + token::transfer( + CpiContext::new( + ctx.accounts.token_program.to_account_info().clone(), + Transfer { + from: ctx.accounts.user_token_wallet.to_account_info().clone(), + to: ctx.accounts.holding_wallet.to_account_info().clone(), + authority: ctx.accounts.user_wallet.to_account_info().clone(), + }, + ), + amount, + )?; + + let contributor_data = &mut ctx.accounts.contributor_data; + donation_data.total_amount_received = donation_data + .total_amount_received + .checked_add(amount) + .unwrap(); + contributor_data.total_amount_donated = contributor_data + .total_amount_donated + .checked_add(amount) + .unwrap(); + contributor_data.donations_count = contributor_data.donations_count.checked_add(1).unwrap(); + let donation_protocol = &ctx.accounts.donation_protocol; + + if amount >= donation_protocol.min_amount_to_earn { + // TODO: add calculation for reward amount + let reward_treasury_balance = ctx.accounts.reward_treasury.amount; + let mut reward_amount = amount; + if reward_amount > reward_treasury_balance { + reward_amount = reward_treasury_balance.checked_div(100).unwrap(); + } + // END + + // Transfer amount of tokens from reward treasury wallet to user + let seeds = &[ + TREASURY_PREFIX.as_bytes(), + ctx.accounts + .donation_protocol + .to_account_info() + .key + .as_ref(), + &[ctx.accounts.donation_protocol.treasury_owner_bump], + ]; + let signer = &[&seeds[..]]; + if reward_amount > 0 { + token::transfer( + CpiContext::new_with_signer( + ctx.accounts.token_program.to_account_info().clone(), + Transfer { + from: ctx.accounts.reward_treasury.to_account_info().clone(), + to: ctx + .accounts + .user_reward_token_wallet + .to_account_info() + .clone(), + authority: ctx.accounts.reward_treasury_owner.to_account_info().clone(), + }, + signer, + ), + reward_amount, + )?; + contributor_data.total_amount_earned = contributor_data + .total_amount_earned + .checked_add(reward_amount) + .unwrap(); + } + } + + Ok(()) +} diff --git a/programs/donaproto/src/instructions/initialize_contributor.rs b/programs/donaproto/src/instructions/initialize_contributor.rs new file mode 100644 index 0000000..8c2221e --- /dev/null +++ b/programs/donaproto/src/instructions/initialize_contributor.rs @@ -0,0 +1,37 @@ +use anchor_lang::prelude::*; + +use crate::states::{ContributorData, DonationProtocolData}; + +pub const CONTRIBUTOR_PREFIX: &str = "contributor"; + +#[derive(Accounts)] +pub struct InitializeContributor<'info> { + #[account(init, payer = payer, space = ContributorData::LEN, + seeds = [ + CONTRIBUTOR_PREFIX.as_bytes(), + donation_protocol.to_account_info().key.as_ref(), + contributor_wallet_address.key.as_ref(), + ], + bump, + )] + pub contributor_data: Account<'info, ContributorData>, + pub donation_protocol: Account<'info, DonationProtocolData>, + /// CHECK: System account for which the ContributorData is being initialized + pub contributor_wallet_address: AccountInfo<'info>, + #[account(mut)] + pub payer: Signer<'info>, + pub system_program: Program<'info, System>, + pub rent: Sysvar<'info, Rent>, +} + +pub fn initialize_contributor(ctx: Context, bump: u8) -> Result<()> { + // TODO: verify bump + let contributor_data = &mut ctx.accounts.contributor_data; + contributor_data.total_amount_donated = 0; + contributor_data.total_amount_earned = 0; + contributor_data.donations_count = 0; + contributor_data.donation_protocol = ctx.accounts.donation_protocol.key(); + contributor_data.bump = bump; + + Ok(()) +} diff --git a/programs/donaproto/src/instructions/initialize_creator.rs b/programs/donaproto/src/instructions/initialize_creator.rs new file mode 100644 index 0000000..0b3671a --- /dev/null +++ b/programs/donaproto/src/instructions/initialize_creator.rs @@ -0,0 +1,38 @@ +use anchor_lang::prelude::*; + +use crate::states::{CreatorData, DonationProtocolData}; + +pub const CREATOR_PREFIX: &str = "creator"; + + +#[derive(Accounts)] +pub struct InitializeCreator<'info> { + #[account(init, payer = payer, space = CreatorData::LEN, + seeds = [ + CREATOR_PREFIX.as_bytes(), + donation_protocol.to_account_info().key.as_ref(), + creator_wallet_address.key.as_ref(), + ], + bump, + )] + pub creator_data: Account<'info, CreatorData>, + pub donation_protocol: Account<'info, DonationProtocolData>, + /// CHECK: System account for which the CreatorData is being initialized + pub creator_wallet_address: AccountInfo<'info>, + #[account(mut)] + pub payer: Signer<'info>, + pub system_program: Program<'info, System>, + pub rent: Sysvar<'info, Rent> +} + +pub fn initialize_creator(ctx: Context) -> Result<()> { + // TODO: verify bump + let creator_data = &mut ctx.accounts.creator_data; + creator_data.donation_protocol = ctx.accounts.donation_protocol.key(); + creator_data.donations_closed_count = 0; + creator_data.donations_created_count = 0; + creator_data.total_amount_collecting = 0; + creator_data.total_amount_received = 0; + + Ok(()) +} diff --git a/programs/donaproto/src/instructions/initialize_donation_protocol.rs b/programs/donaproto/src/instructions/initialize_donation_protocol.rs new file mode 100644 index 0000000..cb6031e --- /dev/null +++ b/programs/donaproto/src/instructions/initialize_donation_protocol.rs @@ -0,0 +1,47 @@ +use anchor_lang::prelude::*; +use anchor_spl::token::{Mint, TokenAccount}; + +use crate::states::DonationProtocolData; + +pub const TREASURY_PREFIX: &str = "treasury"; + +#[derive(Accounts)] +pub struct InitializeDonationProtocol<'info> { + #[account(init, payer = payer, space = DonationProtocolData::LEN)] + pub donation_protocol_data: Account<'info, DonationProtocolData>, + + #[account( + constraint = treasury.owner == *treasury_owner.key, + constraint = treasury.mint == treasury_mint.key(), + )] + pub treasury: Account<'info, TokenAccount>, + #[account( + seeds = [TREASURY_PREFIX.as_bytes(), donation_protocol_data.key().as_ref()], + bump, + )] + /// CHECK: pda account ["treasury", donation_protocol_data] + pub treasury_owner: AccountInfo<'info>, + pub treasury_mint: Account<'info, Mint>, + pub donation_mint: Account<'info, Mint>, + #[account(mut)] + pub payer: Signer<'info>, + pub system_program: Program<'info, System>, + pub rent: Sysvar<'info, Rent>, +} + +pub fn initialize_donation_protocol( + ctx: Context, + min_amount_to_earn: u64, + min_amount_to_collect: u64, + treasury_owner_bump: u8, +) -> Result<()> { + let donation_data = &mut ctx.accounts.donation_protocol_data; + donation_data.treasury_mint = ctx.accounts.treasury_mint.key(); + donation_data.treasury = ctx.accounts.treasury.key(); + donation_data.donation_mint = ctx.accounts.donation_mint.key(); + donation_data.min_amount_to_earn = min_amount_to_earn; + donation_data.treasury_owner_bump = treasury_owner_bump; + donation_data.min_amount_to_collect = min_amount_to_collect; + + Ok(()) +} diff --git a/programs/donaproto/src/contexts/mod.rs b/programs/donaproto/src/instructions/mod.rs similarity index 95% rename from programs/donaproto/src/contexts/mod.rs rename to programs/donaproto/src/instructions/mod.rs index 0631cc2..90ad7ae 100644 --- a/programs/donaproto/src/contexts/mod.rs +++ b/programs/donaproto/src/instructions/mod.rs @@ -1,6 +1,5 @@ pub mod initialize_donation_protocol; pub use initialize_donation_protocol::*; -pub mod common; pub mod initialize_contributor; pub use initialize_contributor::*; pub mod create_donation; diff --git a/programs/donaproto/src/instructions/withdraw_funds.rs b/programs/donaproto/src/instructions/withdraw_funds.rs new file mode 100644 index 0000000..fb1f74b --- /dev/null +++ b/programs/donaproto/src/instructions/withdraw_funds.rs @@ -0,0 +1,97 @@ +use anchor_lang::prelude::*; +use anchor_spl::token::{self, Mint, TokenAccount, Transfer}; + +use crate::{errors::DonationError, states::{CreatorData, DonationData, DonationProtocolData}, HOLDING_PREFIX}; + + +#[derive(Accounts)] +pub struct WithdrawFunds<'info> { + #[account(mut, + constraint = donation_data.donation_protocol == donation_protocol.key(), + constraint = donation_data.holding_wallet == holding_wallet.key(), + constraint = donation_data.creator_data == creator_data.key(), + )] + pub donation_data: Account<'info, DonationData>, + #[account(mut, + constraint = creator_data.donation_protocol == donation_protocol.key(), + )] + pub creator_data: Account<'info, CreatorData>, + pub donation_protocol: Account<'info, DonationProtocolData>, + + #[account(mut, + constraint = holding_wallet.mint == donation_mint.key(), + constraint = holding_wallet.key() == donation_data.holding_wallet, + )] + pub holding_wallet: Account<'info, TokenAccount>, + #[account( + seeds = [ + HOLDING_PREFIX.as_bytes(), + donation_data.to_account_info().key.as_ref(), + ], + bump = donation_data.holding_bump, + )] + /// CHECK: pda account ["holding", donation_data] + pub holding_wallet_owner: AccountInfo<'info>, + #[account(mut, + constraint = recipient_token_wallet.owner == *payer.key, + constraint = recipient_token_wallet.mint == donation_mint.key(), + )] + pub recipient_token_wallet: Account<'info, TokenAccount>, + #[account( + constraint = donation_protocol.donation_mint.key() == donation_mint.key(), + )] + pub donation_mint: Account<'info, Mint>, + #[account(mut)] + pub payer: Signer<'info>, + pub token_program: Program<'info, anchor_spl::token::Token>, +} + + // TODO: add functionality to set withdraw in any fundraising mint + pub fn withdraw_funds(ctx: Context) -> Result<()> { + let donation_data = &mut ctx.accounts.donation_data; + + if donation_data.is_closed { + return Err(DonationError::DonationClosed.into()); + } + + if donation_data.ending_timestamp > Clock::get().expect("Time error").unix_timestamp as u64 + && donation_data.total_amount_received < donation_data.amount_collecting + { + return Err(DonationError::DonationEndingReqiuirementsNotMet.into()); + } + + // Transfer amount from donation holding wallet to recipient + let seeds = &[ + HOLDING_PREFIX.as_bytes(), + donation_data.to_account_info().key.as_ref(), + &[donation_data.holding_bump], + ]; + let signer = &[&seeds[..]]; + token::transfer( + CpiContext::new_with_signer( + ctx.accounts.token_program.to_account_info().clone(), + Transfer { + from: ctx.accounts.holding_wallet.to_account_info().clone(), + to: ctx + .accounts + .recipient_token_wallet + .to_account_info() + .clone(), + authority: ctx.accounts.holding_wallet_owner.to_account_info().clone(), + }, + signer, + ), + donation_data.total_amount_received, + )?; + + let creator_data = &mut ctx.accounts.creator_data; + creator_data.total_amount_received = creator_data + .total_amount_received + .checked_add(donation_data.total_amount_received) + .unwrap(); + creator_data.donations_closed_count = + creator_data.donations_closed_count.checked_add(1).unwrap(); + donation_data.is_closed = true; + + Ok(()) +} diff --git a/programs/donaproto/src/lib.rs b/programs/donaproto/src/lib.rs index dc0d199..2832521 100644 --- a/programs/donaproto/src/lib.rs +++ b/programs/donaproto/src/lib.rs @@ -1,11 +1,9 @@ use anchor_lang::prelude::*; -mod contexts; -use contexts::*; -use anchor_spl::token::{self, Transfer}; +pub mod instructions; +use instructions::*; pub mod errors; - -use crate::errors::DonationError; +pub mod states; declare_id!("HbNNG85aBuR9W5F8YobTeDRRmXWFbDhLDS6WbLzWbLhH"); @@ -19,44 +17,20 @@ pub mod donaproto { min_amount_to_collect: u64, treasury_owner_bump: u8, ) -> Result<()> { - let donation_data = &mut ctx.accounts.donation_protocol_data; - donation_data.treasury_mint = ctx.accounts.treasury_mint.key(); - donation_data.treasury = ctx.accounts.treasury.key(); - donation_data.donation_mint = ctx.accounts.donation_mint.key(); - donation_data.min_amount_to_earn = min_amount_to_earn; - donation_data.treasury_owner_bump = treasury_owner_bump; - donation_data.min_amount_to_collect = min_amount_to_collect; - - Ok(()) + instructions::initialize_donation_protocol( + ctx, + min_amount_to_earn, + min_amount_to_collect, + treasury_owner_bump, + ) } - pub fn initialize_creator( - ctx: Context, - ) -> Result<()> { - // TODO: verify bump - let creator_data = &mut ctx.accounts.creator_data; - creator_data.donation_protocol = ctx.accounts.donation_protocol.key(); - creator_data.donations_closed_count = 0; - creator_data.donations_created_count = 0; - creator_data.total_amount_collecting = 0; - creator_data.total_amount_received = 0; - - Ok(()) + pub fn initialize_creator(ctx: Context) -> Result<()> { + instructions::initialize_creator(ctx) } - pub fn initialize_contributor( - ctx: Context, - bump: u8, - ) -> Result<()> { - // TODO: verify bump - let contributor_data = &mut ctx.accounts.contributor_data; - contributor_data.total_amount_donated = 0; - contributor_data.total_amount_earned = 0; - contributor_data.donations_count = 0; - contributor_data.donation_protocol = ctx.accounts.donation_protocol.key(); - contributor_data.bump = bump; - - Ok(()) + pub fn initialize_contributor(ctx: Context, bump: u8) -> Result<()> { + instructions::initialize_contributor(ctx, bump) } pub fn create_donation( @@ -66,151 +40,14 @@ pub mod donaproto { ending_timestamp: u64, holding_bump: u8, ) -> Result<()> { - let now_timestamp = Clock::get().expect("Time error").unix_timestamp as u64; - if ending_timestamp <= now_timestamp { - return Err(DonationError::InvalidEndingTimestamp.into()); - } - if ipfs_hash.len() > MAX_IPFS_HASH_LEN { - return Err(DonationError::IpfsHashTooLong.into()); - } - if amount < ctx.accounts.donation_protocol.min_amount_to_collect { - return Err(DonationError::DonationAmountTooLow.into()); - } - - let donation_data = &mut ctx.accounts.donation_data; - donation_data.amount_collecting = amount; - donation_data.ending_timestamp = ending_timestamp; - donation_data.is_closed = false; - donation_data.recipient = ctx.accounts.recipient.key(); - donation_data.creator_data = ctx.accounts.creator_data.key(); - donation_data.donation_protocol = ctx.accounts.donation_protocol.key(); - donation_data.holding_wallet = ctx.accounts.holding_wallet.key(); - donation_data.holding_bump = holding_bump; - donation_data.ipfs_hash = ipfs_hash; - - let creator_data = &mut ctx.accounts.creator_data; - creator_data.total_amount_collecting = creator_data.total_amount_collecting.checked_add(amount).unwrap(); - creator_data.donations_created_count = creator_data.donations_created_count.checked_add(1).unwrap(); - - Ok(()) + instructions::create_donation(ctx, amount, ipfs_hash, ending_timestamp, holding_bump) } - pub fn donate( - ctx: Context, - amount: u64, - ) -> Result<()> { - let donation_data = &mut ctx.accounts.donation_data; - - if donation_data.is_closed { - return Err(DonationError::DonationClosed.into()); - } - - if amount == 0 { - return Err(DonationError::DonationAmountZero.into()); - } - - // Transfer amount from user to donation holding wallet - token::transfer( - CpiContext::new( - ctx.accounts.token_program.to_account_info().clone(), - Transfer { - from: ctx.accounts.user_token_wallet.to_account_info().clone(), - to: ctx.accounts.holding_wallet.to_account_info().clone(), - authority: ctx - .accounts - .user_wallet - .to_account_info() - .clone(), - }, - ), - amount, - )?; - - let contributor_data = &mut ctx.accounts.contributor_data; - donation_data.total_amount_received = donation_data.total_amount_received.checked_add(amount).unwrap(); - contributor_data.total_amount_donated = contributor_data.total_amount_donated.checked_add(amount).unwrap(); - contributor_data.donations_count = contributor_data.donations_count.checked_add(1).unwrap(); - let donation_protocol = &ctx.accounts.donation_protocol; - - if amount >= donation_protocol.min_amount_to_earn { - // TODO: add calculation for reward amount - let reward_treasury_balance = ctx.accounts.reward_treasury.amount; - let mut reward_amount = amount; - if reward_amount > reward_treasury_balance { - reward_amount = reward_treasury_balance.checked_div(100).unwrap(); - } - // END - - // Transfer amount of tokens from reward treasury wallet to user - let seeds = &[ - TREASURY_PREFIX.as_bytes(), - ctx.accounts.donation_protocol.to_account_info().key.as_ref(), - &[ctx.accounts.donation_protocol.treasury_owner_bump], - ]; - let signer = &[&seeds[..]]; - if reward_amount > 0 { - token::transfer( - CpiContext::new_with_signer( - ctx.accounts.token_program.to_account_info().clone(), - Transfer { - from: ctx.accounts.reward_treasury.to_account_info().clone(), - to: ctx.accounts.user_reward_token_wallet.to_account_info().clone(), - authority: ctx.accounts.reward_treasury_owner.to_account_info().clone(), - }, - signer, - ), - reward_amount, - )?; - contributor_data.total_amount_earned = contributor_data.total_amount_earned.checked_add(reward_amount).unwrap(); - } - } - - Ok(()) + pub fn donate(ctx: Context, amount: u64) -> Result<()> { + instructions::donate(ctx, amount) } - pub fn withdraw_funds( - ctx: Context, - ) -> Result<()> { - let donation_data = &mut ctx.accounts.donation_data; - - if donation_data.is_closed { - return Err(DonationError::DonationClosed.into()); - } - - if donation_data.ending_timestamp > Clock::get().expect("Time error").unix_timestamp as u64 - && donation_data.total_amount_received < donation_data.amount_collecting { - return Err(DonationError::DonationEndingReqiuirementsNotMet.into()); - } - - // Transfer amount from donation holding wallet to recipient - let seeds = &[ - HOLDING_PREFIX.as_bytes(), - donation_data.to_account_info().key.as_ref(), - &[donation_data.holding_bump], - ]; - let signer = &[&seeds[..]]; - token::transfer( - CpiContext::new_with_signer( - ctx.accounts.token_program.to_account_info().clone(), - Transfer { - from: ctx.accounts.holding_wallet.to_account_info().clone(), - to: ctx.accounts.recipient_token_wallet.to_account_info().clone(), - authority: ctx - .accounts - .holding_wallet_owner - .to_account_info() - .clone(), - }, - signer, - ), - donation_data.total_amount_received, - )?; - - let creator_data = &mut ctx.accounts.creator_data; - creator_data.total_amount_received = creator_data.total_amount_received.checked_add(donation_data.total_amount_received).unwrap(); - creator_data.donations_closed_count = creator_data.donations_closed_count.checked_add(1).unwrap(); - donation_data.is_closed = true; - - Ok(()) + pub fn withdraw_funds(ctx: Context) -> Result<()> { + instructions::withdraw_funds(ctx) } } diff --git a/programs/donaproto/src/contexts/common.rs b/programs/donaproto/src/states/common.rs similarity index 100% rename from programs/donaproto/src/contexts/common.rs rename to programs/donaproto/src/states/common.rs diff --git a/programs/donaproto/src/states/contributor_data.rs b/programs/donaproto/src/states/contributor_data.rs new file mode 100644 index 0000000..96180bf --- /dev/null +++ b/programs/donaproto/src/states/contributor_data.rs @@ -0,0 +1,28 @@ +use anchor_lang::prelude::*; +use std::mem; + +use super::DISCRIMINATOR_LEN; + +#[account] +#[derive(Default)] +pub struct ContributorData { + pub total_amount_donated: u64, + pub total_amount_earned: u64, + pub donations_count: u64, + pub donation_protocol: Pubkey, + pub bump: u8, +} + +impl ContributorData { + const TOTAL_AMOUNT_DONATED_LEN: usize = mem::size_of::(); + const TOTAL_AMOUNT_EARNED_LEN: usize = mem::size_of::(); + const DONATIONS_COUNT_LEN: usize = mem::size_of::(); + const DONATION_PROTOCOL_LEN: usize = mem::size_of::(); + const BUMP_LEN: usize = mem::size_of::(); + pub const LEN: usize = DISCRIMINATOR_LEN + + ContributorData::TOTAL_AMOUNT_DONATED_LEN + + ContributorData::TOTAL_AMOUNT_EARNED_LEN + + ContributorData::DONATIONS_COUNT_LEN + + ContributorData::DONATION_PROTOCOL_LEN + + ContributorData::BUMP_LEN; +} diff --git a/programs/donaproto/src/contexts/initialize_creator.rs b/programs/donaproto/src/states/creator_data.rs similarity index 54% rename from programs/donaproto/src/contexts/initialize_creator.rs rename to programs/donaproto/src/states/creator_data.rs index ca11fb9..bd72711 100644 --- a/programs/donaproto/src/contexts/initialize_creator.rs +++ b/programs/donaproto/src/states/creator_data.rs @@ -1,8 +1,7 @@ use anchor_lang::prelude::*; use std::mem; -use crate::{common::DISCRIMINATOR_LEN, DonationProtocolData}; -pub const CREATOR_PREFIX: &str = "creator"; +use super::DISCRIMINATOR_LEN; #[account] #[derive(Default)] @@ -27,24 +26,3 @@ impl CreatorData { + CreatorData::DONATIONS_CLOSED_COUNT_LEN + CreatorData::DONATION_PROTOCOL_LEN; } - - -#[derive(Accounts)] -pub struct InitializeCreator<'info> { - #[account(init, payer = payer, space = CreatorData::LEN, - seeds = [ - CREATOR_PREFIX.as_bytes(), - donation_protocol.to_account_info().key.as_ref(), - creator_wallet_address.key.as_ref(), - ], - bump, - )] - pub creator_data: Account<'info, CreatorData>, - pub donation_protocol: Account<'info, DonationProtocolData>, - /// CHECK: System account for which the CreatorData is being initialized - pub creator_wallet_address: AccountInfo<'info>, - #[account(mut)] - pub payer: Signer<'info>, - pub system_program: Program<'info, System>, - pub rent: Sysvar<'info, Rent> -} \ No newline at end of file diff --git a/programs/donaproto/src/states/donation_data.rs b/programs/donaproto/src/states/donation_data.rs new file mode 100644 index 0000000..81b75b1 --- /dev/null +++ b/programs/donaproto/src/states/donation_data.rs @@ -0,0 +1,46 @@ +use anchor_lang::prelude::*; +use std::mem; + +use super::DISCRIMINATOR_LEN; + +#[account] +#[derive(Default)] +pub struct DonationData { + pub amount_collecting: u64, + pub total_amount_received: u64, + pub ending_timestamp: u64, + pub is_closed: bool, + pub recipient: Pubkey, + pub donation_protocol: Pubkey, + pub holding_wallet: Pubkey, + pub creator_data: Pubkey, + pub holding_bump: u8, + pub ipfs_hash: String, +} + +pub const MAX_IPFS_HASH_LEN: usize = 64; + +impl DonationData { + const AMOUNT_COLLECTING_LEN: usize = mem::size_of::(); + const TOTAL_AMOUNT_RECEIVED_LEN: usize = mem::size_of::(); + const ENDING_TIMESTAMP_LEN: usize = mem::size_of::(); + const IS_CLOSED_LEN: usize = mem::size_of::(); + const RECIPIENT_LEN: usize = mem::size_of::(); + const DONATION_PROTOCOL_LEN: usize = mem::size_of::(); + const HOLDING_WALLET_LEN: usize = mem::size_of::(); + const CREATOR_DATA_LEN: usize = mem::size_of::(); + const HOLDING_BUMP_LEN: usize = mem::size_of::(); + const IPFS_HASH_LEN: usize = MAX_IPFS_HASH_LEN; + + pub const LEN: usize = DISCRIMINATOR_LEN + + DonationData::AMOUNT_COLLECTING_LEN + + DonationData::TOTAL_AMOUNT_RECEIVED_LEN + + DonationData::ENDING_TIMESTAMP_LEN + + DonationData::IS_CLOSED_LEN + + DonationData::RECIPIENT_LEN + + DonationData::DONATION_PROTOCOL_LEN + + DonationData::HOLDING_WALLET_LEN + + DonationData::CREATOR_DATA_LEN + + DonationData::HOLDING_BUMP_LEN + + DonationData::IPFS_HASH_LEN; +} diff --git a/programs/donaproto/src/states/donation_protocol_data.rs b/programs/donaproto/src/states/donation_protocol_data.rs new file mode 100644 index 0000000..0a144e1 --- /dev/null +++ b/programs/donaproto/src/states/donation_protocol_data.rs @@ -0,0 +1,32 @@ +use anchor_lang::prelude::*; +use std::mem; + +use super::DISCRIMINATOR_LEN; + +#[account] +#[derive(Default)] +pub struct DonationProtocolData { + pub treasury_mint: Pubkey, + pub treasury: Pubkey, + pub donation_mint: Pubkey, + pub min_amount_to_earn: u64, + pub min_amount_to_collect: u64, + pub treasury_owner_bump: u8, +} + +impl DonationProtocolData { + const TREASURY_MINT_LEN: usize = mem::size_of::(); + const TREASURY_LEN: usize = mem::size_of::(); + const DONATION_MINT_LEN: usize = mem::size_of::(); + const MIN_AMOUNT_TO_EARN_LEN: usize = mem::size_of::(); + const MIN_AMOUNT_TO_COLLECT_LEN: usize = mem::size_of::(); + const TREASURY_OWNER_BUMP_LEN: usize = mem::size_of::(); + + pub const LEN: usize = DISCRIMINATOR_LEN + + DonationProtocolData::TREASURY_MINT_LEN + + DonationProtocolData::TREASURY_LEN + + DonationProtocolData::DONATION_MINT_LEN + + DonationProtocolData::MIN_AMOUNT_TO_EARN_LEN + + DonationProtocolData::MIN_AMOUNT_TO_COLLECT_LEN + + DonationProtocolData::TREASURY_OWNER_BUMP_LEN; +} diff --git a/programs/donaproto/src/states/mod.rs b/programs/donaproto/src/states/mod.rs new file mode 100644 index 0000000..af971f0 --- /dev/null +++ b/programs/donaproto/src/states/mod.rs @@ -0,0 +1,14 @@ +pub mod common; +pub use common::*; + +pub mod donation_data; +pub use donation_data::*; + +pub mod donation_protocol_data; +pub use donation_protocol_data::*; + +pub mod creator_data; +pub use creator_data::*; + +pub mod contributor_data; +pub use contributor_data::*;