Skip to content
Merged
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
2 changes: 2 additions & 0 deletions Anchor.toml
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,8 @@ v07-claim-launch-additional-tokens = "yarn run tsx scripts/v0.7/claimLaunchAddit
v07-remove-proposal = "yarn run tsx scripts/v0.7/removeProposal.ts"
v07-audit-liquidity-position-authorities = "yarn run tsx scripts/v0.7/auditLiquidityPositionAuthorities.ts"
v07-fix-position-authorities = "yarn run tsx scripts/v0.7/fixPositionAuthorities.ts"
v07-dump-launches-funding-records = "yarn run tsx scripts/v0.7/dumpLaunchesAndFundingRecords.ts"
v07-resize-launches-funding-records = "yarn run tsx scripts/v0.7/resizeLaunchesAndFundingRecords.ts"

[test]
startup_wait = 5000
Expand Down
2 changes: 2 additions & 0 deletions programs/v07_launchpad/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,4 +62,6 @@ pub enum LaunchpadError {
PerformancePackageAlreadyInitialized,
#[msg("Invalid DAO")]
InvalidDao,
#[msg("Accumulator activation delay must be less than the launch duration")]
InvalidAccumulatorActivationDelaySeconds,
}
2 changes: 2 additions & 0 deletions programs/v07_launchpad/src/events.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ pub struct LaunchInitializedEvent {
pub seconds_for_launch: u32,
pub additional_tokens_amount: u64,
pub additional_tokens_recipient: Option<Pubkey>,
pub accumulator_activation_delay_seconds: u32,
}

#[event]
Expand All @@ -58,6 +59,7 @@ pub struct LaunchFundedEvent {
pub amount: u64,
pub total_committed_by_funder: u64,
pub total_committed: u64,
pub committed_amount_accumulator: u128,
}

#[event]
Expand Down
19 changes: 18 additions & 1 deletion programs/v07_launchpad/src/instructions/fund.rs
Original file line number Diff line number Diff line change
Expand Up @@ -86,8 +86,23 @@ impl Fund<'_> {
)?;

let funding_record = &mut ctx.accounts.funding_record;
let clock = Clock::get()?;

if funding_record.funder == ctx.accounts.funder.key() {
// Existing funding record — flush accumulator before changing committed_amount
let activation_timestamp = ctx.accounts.launch.unix_timestamp_started.unwrap()
+ ctx.accounts.launch.accumulator_activation_delay_seconds as i64;
let now = clock.unix_timestamp;

if funding_record.last_accumulator_update > 0 && now > activation_timestamp {
let period_start =
std::cmp::max(funding_record.last_accumulator_update, activation_timestamp);
let elapsed = now - period_start;
funding_record.committed_amount_accumulator +=
(funding_record.committed_amount as u128) * (elapsed as u128);
}

funding_record.last_accumulator_update = now;
funding_record.committed_amount += amount;
} else {
funding_record.set_inner(FundingRecord {
Expand All @@ -98,6 +113,8 @@ impl Fund<'_> {
is_tokens_claimed: false,
is_usdc_refunded: false,
approved_amount: 0,
committed_amount_accumulator: 0,
last_accumulator_update: clock.unix_timestamp,
});
}

Expand All @@ -106,7 +123,6 @@ impl Fund<'_> {

ctx.accounts.launch.seq_num += 1;

let clock = Clock::get()?;
emit_cpi!(LaunchFundedEvent {
common: CommonFields::new(&clock, ctx.accounts.launch.seq_num),
launch: ctx.accounts.launch.key(),
Expand All @@ -115,6 +131,7 @@ impl Fund<'_> {
total_committed: ctx.accounts.launch.total_committed_amount,
funding_record: funding_record.key(),
total_committed_by_funder: funding_record.committed_amount,
committed_amount_accumulator: funding_record.committed_amount_accumulator,
});

Ok(())
Expand Down
9 changes: 9 additions & 0 deletions programs/v07_launchpad/src/instructions/initialize_launch.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ pub struct InitializeLaunchArgs {
pub months_until_insiders_can_unlock: u8,
pub team_address: Pubkey,
pub additional_tokens_amount: u64,
pub accumulator_activation_delay_seconds: u32,
}

#[event_cpi]
Expand Down Expand Up @@ -125,6 +126,12 @@ impl InitializeLaunch<'_> {
LaunchpadError::InvalidSecondsForLaunch
);

require_gt!(
args.seconds_for_launch,
args.accumulator_activation_delay_seconds,
LaunchpadError::InvalidAccumulatorActivationDelaySeconds
);

require!(
self.base_mint.freeze_authority.is_none(),
LaunchpadError::FreezeAuthoritySet
Expand Down Expand Up @@ -239,6 +246,7 @@ impl InitializeLaunch<'_> {
additional_tokens_claimed: false,
unix_timestamp_completed: None,
is_performance_package_initialized: false,
accumulator_activation_delay_seconds: args.accumulator_activation_delay_seconds,
});

let clock = Clock::get()?;
Expand Down Expand Up @@ -266,6 +274,7 @@ impl InitializeLaunch<'_> {
.additional_tokens_recipient
.as_ref()
.map(|a| a.key()),
accumulator_activation_delay_seconds: args.accumulator_activation_delay_seconds,
});

let launch_key = ctx.accounts.launch.key();
Expand Down
4 changes: 4 additions & 0 deletions programs/v07_launchpad/src/instructions/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ pub mod fund;
pub mod initialize_launch;
pub mod initialize_performance_package;
pub mod refund;
pub mod resize_funding_record;
pub mod resize_launch;
pub mod set_funding_record_approval;
pub mod start_launch;

Expand All @@ -17,5 +19,7 @@ pub use fund::*;
pub use initialize_launch::*;
pub use initialize_performance_package::*;
pub use refund::*;
pub use resize_funding_record::*;
pub use resize_launch::*;
pub use set_funding_record_approval::*;
pub use start_launch::*;
73 changes: 73 additions & 0 deletions programs/v07_launchpad/src/instructions/resize_funding_record.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
use anchor_lang::{prelude::*, system_program, Discriminator};

use crate::state::{FundingRecord, OldFundingRecord};
use crate::ID;

#[derive(Accounts)]
pub struct ResizeFundingRecord<'info> {
/// CHECK: we check the discriminator, owner, and size
#[account(mut)]
pub funding_record: UncheckedAccount<'info>,
#[account(mut)]
pub payer: Signer<'info>,
pub system_program: Program<'info, System>,
}

impl ResizeFundingRecord<'_> {
pub fn handle(ctx: Context<Self>) -> Result<()> {
let funding_record = &mut ctx.accounts.funding_record;

// Owner check
require_eq!(funding_record.owner, &ID);

// Discriminator check
let is_discriminator_correct =
funding_record.data.try_borrow_mut().unwrap()[..8] == FundingRecord::discriminator();
require_eq!(is_discriminator_correct, true);

const AFTER_REALLOC_SIZE: usize = 8 + FundingRecord::INIT_SPACE;
const BEFORE_REALLOC_SIZE: usize = 8 + OldFundingRecord::INIT_SPACE;

// Size check
if funding_record.data_len() != BEFORE_REALLOC_SIZE {
require_eq!(funding_record.data_len(), AFTER_REALLOC_SIZE);
return Ok(());
}

let old_data =
OldFundingRecord::deserialize(&mut &funding_record.try_borrow_data().unwrap()[8..])?;

let new_data = FundingRecord {
pda_bump: old_data.pda_bump,
funder: old_data.funder,
launch: old_data.launch,
committed_amount: old_data.committed_amount,
is_tokens_claimed: old_data.is_tokens_claimed,
is_usdc_refunded: old_data.is_usdc_refunded,
approved_amount: old_data.approved_amount,
committed_amount_accumulator: 0,
last_accumulator_update: 0,
};

funding_record.realloc(AFTER_REALLOC_SIZE, true)?;

let lamports_needed = Rent::get()?.minimum_balance(AFTER_REALLOC_SIZE);

if lamports_needed > funding_record.lamports() {
system_program::transfer(
CpiContext::new(
ctx.accounts.system_program.to_account_info(),
system_program::Transfer {
from: ctx.accounts.payer.to_account_info(),
to: funding_record.to_account_info(),
},
),
lamports_needed - funding_record.lamports(),
)?;
}

new_data.serialize(&mut &mut funding_record.try_borrow_mut_data().unwrap()[8..])?;

Ok(())
}
}
93 changes: 93 additions & 0 deletions programs/v07_launchpad/src/instructions/resize_launch.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
use anchor_lang::{prelude::*, system_program, Discriminator};

use crate::state::{Launch, OldLaunch};
use crate::ID;

#[derive(Accounts)]
pub struct ResizeLaunch<'info> {
/// CHECK: we check the discriminator, owner, and size
#[account(mut)]
pub launch: UncheckedAccount<'info>,
#[account(mut)]
pub payer: Signer<'info>,
pub system_program: Program<'info, System>,
}

impl ResizeLaunch<'_> {
pub fn handle(ctx: Context<Self>) -> Result<()> {
let launch = &mut ctx.accounts.launch;

// Owner check
require_eq!(launch.owner, &ID);

// Discriminator check
let is_discriminator_correct =
launch.data.try_borrow_mut().unwrap()[..8] == Launch::discriminator();
require_eq!(is_discriminator_correct, true);

const AFTER_REALLOC_SIZE: usize = 8 + Launch::INIT_SPACE;
const BEFORE_REALLOC_SIZE: usize = 8 + OldLaunch::INIT_SPACE;

// Size check
if launch.data_len() != BEFORE_REALLOC_SIZE {
require_eq!(launch.data_len(), AFTER_REALLOC_SIZE);
return Ok(());
}

let old_data = OldLaunch::deserialize(&mut &launch.try_borrow_data().unwrap()[8..])?;

let new_data = Launch {
pda_bump: old_data.pda_bump,
minimum_raise_amount: old_data.minimum_raise_amount,
monthly_spending_limit_amount: old_data.monthly_spending_limit_amount,
monthly_spending_limit_members: old_data.monthly_spending_limit_members,
launch_authority: old_data.launch_authority,
launch_signer: old_data.launch_signer,
launch_signer_pda_bump: old_data.launch_signer_pda_bump,
launch_quote_vault: old_data.launch_quote_vault,
launch_base_vault: old_data.launch_base_vault,
base_mint: old_data.base_mint,
quote_mint: old_data.quote_mint,
unix_timestamp_started: old_data.unix_timestamp_started,
unix_timestamp_closed: old_data.unix_timestamp_closed,
total_committed_amount: old_data.total_committed_amount,
state: old_data.state,
seq_num: old_data.seq_num,
seconds_for_launch: old_data.seconds_for_launch,
dao: old_data.dao,
dao_vault: old_data.dao_vault,
performance_package_grantee: old_data.performance_package_grantee,
performance_package_token_amount: old_data.performance_package_token_amount,
months_until_insiders_can_unlock: old_data.months_until_insiders_can_unlock,
team_address: old_data.team_address,
total_approved_amount: old_data.total_approved_amount,
additional_tokens_amount: old_data.additional_tokens_amount,
additional_tokens_recipient: old_data.additional_tokens_recipient,
additional_tokens_claimed: old_data.additional_tokens_claimed,
unix_timestamp_completed: old_data.unix_timestamp_completed,
is_performance_package_initialized: old_data.is_performance_package_initialized,
accumulator_activation_delay_seconds: 0,
};

launch.realloc(AFTER_REALLOC_SIZE, true)?;

let lamports_needed = Rent::get()?.minimum_balance(AFTER_REALLOC_SIZE);

if lamports_needed > launch.lamports() {
system_program::transfer(
CpiContext::new(
ctx.accounts.system_program.to_account_info(),
system_program::Transfer {
from: ctx.accounts.payer.to_account_info(),
to: launch.to_account_info(),
},
),
lamports_needed - launch.lamports(),
)?;
}

new_data.serialize(&mut &mut launch.try_borrow_mut_data().unwrap()[8..])?;

Ok(())
}
}
8 changes: 8 additions & 0 deletions programs/v07_launchpad/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -121,4 +121,12 @@ pub mod launchpad_v7 {
) -> Result<()> {
InitializePerformancePackage::handle(ctx)
}

pub fn resize_funding_record(ctx: Context<ResizeFundingRecord>) -> Result<()> {
ResizeFundingRecord::handle(ctx)
}

pub fn resize_launch(ctx: Context<ResizeLaunch>) -> Result<()> {
ResizeLaunch::handle(ctx)
}
}
24 changes: 24 additions & 0 deletions programs/v07_launchpad/src/state/funding_record.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,28 @@ pub struct FundingRecord {
/// The amount of USDC that the launch authority has approved for the funder.
/// If zero, the funder has not been approved for any amount.
pub approved_amount: u64,
/// Running integral of committed_amount over time (committed_amount * seconds).
pub committed_amount_accumulator: u128,
/// Unix timestamp of the last accumulator update.
pub last_accumulator_update: i64,
}

#[account]
#[derive(InitSpace)]
pub struct OldFundingRecord {
/// The PDA bump.
pub pda_bump: u8,
/// The funder.
pub funder: Pubkey,
/// The launch.
pub launch: Pubkey,
/// The amount of USDC that has been committed by the funder.
pub committed_amount: u64,
/// Whether the tokens have been claimed.
pub is_tokens_claimed: bool,
/// Whether the USDC has been refunded.
pub is_usdc_refunded: bool,
/// The amount of USDC that the launch authority has approved for the funder.
/// If zero, the funder has not been approved for any amount.
pub approved_amount: u64,
}
Loading
Loading