Skip to content
Open
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
1 change: 1 addition & 0 deletions Anchor.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ skip-lint = false
conditional_vault = "VLTX1ishMBbcX3rdBWGssxawAo1Q2X2qxYFYqiGodVg"
futarchy = "FUTARELBfJfQ8RDGhg1wdhddq1odMAJUePHFuBYfUxKq"
launchpad = "MooNyh4CBUYEKyXVnjGYQ8mEiJDpGvJMdvrZx1iGeHV"
launchpad_v7 = "moontUzsdepotRGe5xsfip7vLPTJnVuafqdUWexVnPM"
price_based_performance_package = "pbPPQH7jyKoSLu8QYs3rSY3YkDRXEBojKbTgnUg7NDS"

[registry]
Expand Down
17 changes: 17 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

32 changes: 32 additions & 0 deletions programs/launchpad_v7/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
[package]
name = "launchpad_v7"
version = "0.7.0"
description = "Created with Anchor"
edition = "2021"

[lib]
crate-type = ["cdylib", "lib"]
name = "launchpad_v7"

[features]
no-entrypoint = []
no-idl = []
no-log-ix-name = []
cpi = ["no-entrypoint"]
default = ["custom-heap"]
devnet = []
production = []
custom-heap = []

[dependencies]
anchor-lang = "0.29.0"
anchor-spl = "0.29.0"
futarchy = { path = "../futarchy", features = ["cpi"] }
price_based_performance_package = { path = "../price_based_performance_package", features = ["cpi"] }
spl-memo = "=4.0.0"
solana-program = "=1.17.14"
spl-token = "=4.0.0"
ahash = "=0.8.6"
solana-security-txt = "1.1.1"
squads-multisig-program = { git = "https://github.com/Squads-Protocol/v4", package = "squads-multisig-program", rev = "6d5235da621a2e9b7379ea358e48760e981053be", features = ["cpi"] }
damm_v2_cpi = { path = "../damm_v2_cpi", features = ["cpi"] }
2 changes: 2 additions & 0 deletions programs/launchpad_v7/Xargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
[target.bpfel-unknown-unknown.dependencies.std]
features = []
136 changes: 136 additions & 0 deletions programs/launchpad_v7/src/allocator.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
// THIS COMES DIRECTLY FROM SQUADS V4, WHICH HAS BEEN AUDITED 10 TIMES:
// https://github.com/Squads-Protocol/v4/blob/8a5642853b3dda9817477c9b540d0f84d67ede13/programs/squads_multisig_program/src/allocator.rs#L1

/*
Optimizing Bump Heap Allocation

Objective: Increase available heap memory while maintaining flexibility in program invocation.

1. Initial State: Default 32 KiB Heap

Memory Layout:
0x300000000 0x300008000
| |
v v
[--------------------]
^ ^
| |
VM Lower VM Upper
Boundary Boundary

Default Allocator (Allocates Backwards / Top Down) (Default 32 KiB):
0x300000000 0x300008000
| |
[--------------------]
^
|
Allocation starts here (SAFE)

2. Naive Approach: Increase HEAP_LENGTH to 8 * 32 KiB + Default Allocator

Memory Layout with Increased HEAP_LENGTH:
0x300000000 0x300008000 0x300040000
| | |
v v v
[--------------------|------------------------------------|]
^ ^ ^
| | |
VM Lower VM Upper Allocation starts here
Boundary Boundary (ACCESS VIOLATION!)

Issue: Access violation occurs without requestHeapFrame, requiring it for every transaction.

3. Optimized Solution: Forward Allocation with Flexible Heap Usage

Memory Layout (Same as Naive Approach):
0x300000000 0x300008000 0x300040000
| | |
v v v
[--------------------|------------------------------------|]
^ ^ ^
| | |
VM Lower VM Upper Allocator & VM
Boundary Boundary Heap Limit

Forward Allocator Behavior:

a) Without requestHeapFrame:
0x300000000 0x300008000
| |
[--------------------]
^ ^
| |
VM Lower VM Upper
Boundary Boundary
Allocation
starts here (SAFE)

b) With requestHeapFrame:
0x300000000 0x300008000 0x300040000
| | |
[--------------------|------------------------------------|]
^ ^ ^
| | |
VM Lower | VM Upper
Boundary Boundary
Allocation Allocation continues Maximum allocation
starts here with requestHeapFrame with requestHeapFrame
(SAFE)

Key Advantages:
1. Compatibility: Functions without requestHeapFrame for allocations ≤32 KiB.
2. Extensibility: Supports larger allocations when requestHeapFrame is invoked.
3. Efficiency: Eliminates mandatory requestHeapFrame calls for all transactions.

Conclusion:
The forward allocation strategy offers a robust solution, providing both backward
compatibility for smaller heap requirements and the flexibility to utilize extended
heap space when necessary.

The following allocator is a copy of the bump allocator found in
solana_program::entrypoint and
https://github.com/solana-labs/solana-program-library/blob/master/examples/rust/custom-heap/src/entrypoint.rs

but with changes to its HEAP_LENGTH and its
starting allocation address.
*/

use solana_program::entrypoint::HEAP_START_ADDRESS;
use std::{alloc::Layout, mem::size_of, ptr::null_mut};

/// Length of the memory region used for program heap.
pub const HEAP_LENGTH: usize = 8 * 32 * 1024;

struct BumpAllocator;

unsafe impl std::alloc::GlobalAlloc for BumpAllocator {
#[inline]
unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
const POS_PTR: *mut usize = HEAP_START_ADDRESS as *mut usize;
const TOP_ADDRESS: usize = HEAP_START_ADDRESS as usize + HEAP_LENGTH;
const BOTTOM_ADDRESS: usize = HEAP_START_ADDRESS as usize + size_of::<*mut u8>();
let mut pos = *POS_PTR;
if pos == 0 {
// First time, set starting position to bottom address
pos = BOTTOM_ADDRESS;
}
// Align the position upwards
pos = (pos + layout.align() - 1) & !(layout.align() - 1);
let next_pos = pos.saturating_add(layout.size());
if next_pos > TOP_ADDRESS {
return null_mut();
}
*POS_PTR = next_pos;
pos as *mut u8
}

#[inline]
unsafe fn dealloc(&self, _: *mut u8, _: Layout) {
// I'm a bump allocator, I don't free
}
}

// Only use the allocator if we're not in a no-entrypoint context
#[cfg(not(feature = "no-entrypoint"))]
#[global_allocator]
static A: BumpAllocator = BumpAllocator;
53 changes: 53 additions & 0 deletions programs/launchpad_v7/src/error.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
use anchor_lang::prelude::*;

#[error_code]
pub enum LaunchpadError {
#[msg("Invalid amount")]
InvalidAmount,
#[msg("Supply must be zero")]
SupplyNonZero,
#[msg("Launch period must be between 1 hour and 2 weeks")]
InvalidSecondsForLaunch,
#[msg("Insufficient funds")]
InsufficientFunds,
#[msg("Token mint key must end in 'meta'")]
InvalidTokenKey,
#[msg("Invalid launch state")]
InvalidLaunchState,
#[msg("Launch period not over")]
LaunchPeriodNotOver,
#[msg("Launch is complete, no more funding allowed")]
LaunchExpired,
#[msg("For you to get a refund, either the launch needs to be in a refunding state or the launch must have been over-committed")]
LaunchNotRefunding,
#[msg("Launch must be initialized to be started")]
LaunchNotInitialized,
#[msg("Freeze authority can't be set on launchpad tokens")]
FreezeAuthoritySet,
#[msg("Monthly spending limit must be less than 1/6th of the minimum raise amount and cannot be 0")]
InvalidMonthlySpendingLimit,
#[msg("There can only be at most 10 monthly spending limit members")]
InvalidMonthlySpendingLimitMembers,
#[msg("Cannot do more than a 50% premine, minimum is 10 atoms of token")]
InvalidPriceBasedPremineAmount,
#[msg("Insiders must be forced to wait at least 18 months before unlocking their tokens")]
InvalidPerformancePackageMinUnlockTime,
#[msg("Launch authority must be set to complete the launch until 2 days after closing")]
LaunchAuthorityNotSet,
#[msg("The final amount raised must be greater than or equal to the minimum raise amount")]
FinalRaiseAmountTooLow,
#[msg("Tokens already claimed")]
TokensAlreadyClaimed,
#[msg("Money already refunded")]
MoneyAlreadyRefunded,
#[msg("An invariant was violated. You should get in contact with the MetaDAO team if you see this")]
InvariantViolated,
#[msg("Launch must be live to be closed")]
LaunchNotLive,
#[msg("Minimum raise amount must be greater than or equal to $0.5 so that there's enough liquidity for the launch")]
InvalidMinimumRaiseAmount,
#[msg("The final raise amount has already been set")]
FinalRaiseAmountAlreadySet,
#[msg("Total approved amount must be greater than or equal to the minimum raise amount")]
TotalApprovedAmountTooLow,
}
105 changes: 105 additions & 0 deletions programs/launchpad_v7/src/events.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
use crate::state::LaunchState;
use anchor_lang::prelude::*;

#[derive(AnchorSerialize, AnchorDeserialize)]
pub struct CommonFields {
pub slot: u64,
pub unix_timestamp: i64,
pub launch_seq_num: u64,
}

impl CommonFields {
pub fn new(clock: &Clock, launch_seq_num: u64) -> Self {
Self {
slot: clock.slot,
unix_timestamp: clock.unix_timestamp,
launch_seq_num,
}
}
}

#[event]
pub struct LaunchInitializedEvent {
pub common: CommonFields,
pub launch: Pubkey,
pub minimum_raise_amount: u64,
pub launch_authority: Pubkey,
pub launch_signer: Pubkey,
pub launch_signer_pda_bump: u8,
pub launch_usdc_vault: Pubkey,
pub launch_token_vault: Pubkey,
pub performance_package_grantee: Pubkey,
pub performance_package_token_amount: u64,
pub months_until_insiders_can_unlock: u8,
pub monthly_spending_limit_amount: u64,
pub monthly_spending_limit_members: Vec<Pubkey>,
pub base_mint: Pubkey,
pub quote_mint: Pubkey,
pub pda_bump: u8,
pub seconds_for_launch: u32,
}

#[event]
pub struct LaunchStartedEvent {
pub common: CommonFields,
pub launch: Pubkey,
pub launch_authority: Pubkey,
pub slot_started: u64,
}

#[event]
pub struct LaunchFundedEvent {
pub common: CommonFields,
pub funding_record: Pubkey,
pub launch: Pubkey,
pub funder: Pubkey,
pub amount: u64,
pub total_committed_by_funder: u64,
pub total_committed: u64,
}

#[event]
pub struct FundingRecordApprovalSetEvent {
pub common: CommonFields,
pub launch: Pubkey,
pub funding_record: Pubkey,
pub funder: Pubkey,
pub approved_amount: u64,
pub total_approved: u64,
}

#[event]
pub struct LaunchCompletedEvent {
pub common: CommonFields,
pub launch: Pubkey,
pub final_state: LaunchState,
pub total_committed: u64,
pub dao: Option<Pubkey>,
pub dao_treasury: Option<Pubkey>,
pub total_approved_amount: u64,
}

#[event]
pub struct LaunchRefundedEvent {
pub common: CommonFields,
pub launch: Pubkey,
pub funder: Pubkey,
pub usdc_refunded: u64,
pub funding_record: Pubkey,
}

#[event]
pub struct LaunchClaimEvent {
pub common: CommonFields,
pub launch: Pubkey,
pub funder: Pubkey,
pub tokens_claimed: u64,
pub funding_record: Pubkey,
}

#[event]
pub struct LaunchCloseEvent {
pub common: CommonFields,
pub launch: Pubkey,
pub new_state: LaunchState,
}
Loading