Skip to content
holvo

Program

G7ccWHbdA4iqGXzBND8CkYTPpK9SqPt4AqgTk5h96A9Q · Solana mainnet · Anchor 0.31 · 506 lines

The source the deployed program was built from. A verified build is not published yet, and the program is still upgradeable by its deploy key until we freeze it. Check on Solscan ↗

Instructions

Raw lib.rs ↗

Accounts, in order

launch(name, symbol, uri)
pact (PDA "pact", mint) · dev, signer · mint, signer · pump mint authority · bonding curve · curve ATA · pump global · metaplex · metadata · system · token · associated token · rent · pump event authority · pump
pledge(amount)
pact · dev, signer · mint · dev ATA · vault (ATA of the pact) · token · associated token · system
release()
pact · dev, signer · mint · dev ATA · vault · token
claim()
pact · dev, signer
burn()
pact · incinerator 1nc1nerator11111111111111111111111111111111
collect_curve()
pact · pump creator vault (PDA "creator-vault", pact) · system · pump event authority · pump
collect_amm()
pact · payer, signer · pact WSOL ATA · PumpSwap vault authority (PDA "creator_vault", pact) · its WSOL ATA · WSOL mint · token · associated token · system · PumpSwap event authority · PumpSwap

Instruction data is Anchor's: the first 8 bytes of sha256("global:<name>"), then the arguments; strings are u32 length plus bytes, amounts u64 little-endian. Events are "Program data:" lines with sha256("event:<Name>") as the first 8 bytes.

programs/holvo/src/lib.rs · 506 lines · scrollsraw ↗
//! HOLVO - the dev earns the coin's fees only while the dev's bag stays in the program.//!//! A coin launched here has the `pact` PDA as its pump.fun creator, so its creator fees land on the//! pact: `collect_curve` on the bonding curve, `collect_amm` after graduation (PumpSwap pays in//! wrapped SOL; the pact signs to unwrap it). Anyone can call both, and both leave a receipt.//!//! The dev locks tokens in the pact's vault with `pledge`. While the pledge is in, `claim` pays the//! collected fees to the dev. `release` hands the whole bag back to the dev and forfeits the fees for//! good: from then on `burn` sends every lamport the pact collects to the incinerator, an address//! nobody can spend from. The vault has no other way out and the fees have no other destination.//!//! No fee to us and no admin instruction. The program is upgradeable by its deploy key until frozen. use anchor_lang::prelude::*;use anchor_lang::solana_program::instruction::{AccountMeta, Instruction};use anchor_lang::solana_program::program::{invoke, invoke_signed}; declare_id!("G7ccWHbdA4iqGXzBND8CkYTPpK9SqPt4AqgTk5h96A9Q"); pub const PUMP_PROGRAM_ID: Pubkey = anchor_lang::pubkey!("6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P");pub const PUMP_AMM_PROGRAM_ID: Pubkey = anchor_lang::pubkey!("pAMMBay6oceH9fJKBRHGP5D4bD4sWpmSwMn52FMfXEA");pub const TOKEN_PROGRAM_ID: Pubkey = anchor_lang::pubkey!("TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA");pub const ATA_PROGRAM_ID: Pubkey = anchor_lang::pubkey!("ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL");pub const WSOL_MINT: Pubkey = anchor_lang::pubkey!("So11111111111111111111111111111111111111112");pub const INCINERATOR: Pubkey = anchor_lang::pubkey!("1nc1nerator11111111111111111111111111111111");pub const PUMP_CREATE_DISC: [u8; 8] = [24, 30, 200, 40, 5, 28, 7, 119];pub const PUMP_COLLECT_DISC: [u8; 8] = [20, 22, 86, 123, 198, 28, 219, 132];pub const AMM_COLLECT_DISC: [u8; 8] = [160, 57, 89, 42, 181, 139, 43, 66];pub const TOKEN_ACCOUNT_LEN: usize = 165; pub const PACT_SEED: &[u8] = b"pact";pub const MAX_NAME: usize = 32;pub const MAX_SYMBOL: usize = 10;pub const MAX_URI: usize = 200; pub const SOURCE_CURVE: u8 = 0;pub const SOURCE_AMM: u8 = 1; #[program]pub mod holvo {    use super::*;     /// Create the coin on pump.fun with the pact PDA as its creator. The signer becomes the dev.    pub fn launch(ctx: Context<Launch>, name: String, symbol: String, uri: String) -> Result<()> {        require!(!name.is_empty() && name.len() <= MAX_NAME, HolvoError::BadText);        require!(!symbol.is_empty() && symbol.len() <= MAX_SYMBOL, HolvoError::BadText);        require!(!uri.is_empty() && uri.len() <= MAX_URI, HolvoError::BadText);        let a = &ctx.accounts;        require!(a.mint.is_signer, HolvoError::MintMustSign);        let pact_key = a.pact.key();        let mut data = Vec::with_capacity(8 + 4 + MAX_NAME + 4 + MAX_SYMBOL + 4 + MAX_URI + 32);        data.extend_from_slice(&PUMP_CREATE_DISC);        put_str(&mut data, &name);        put_str(&mut data, &symbol);        put_str(&mut data, &uri);        data.extend_from_slice(pact_key.as_ref());        invoke(            &Instruction {                program_id: PUMP_PROGRAM_ID,                accounts: vec![                    AccountMeta::new(a.mint.key(), true),                    AccountMeta::new_readonly(a.mint_authority.key(), false),                    AccountMeta::new(a.bonding_curve.key(), false),                    AccountMeta::new(a.curve_ata.key(), false),                    AccountMeta::new_readonly(a.global.key(), false),                    AccountMeta::new_readonly(a.mpl.key(), false),                    AccountMeta::new(a.metadata.key(), false),                    AccountMeta::new(a.dev.key(), true),                    AccountMeta::new_readonly(a.system_program.key(), false),                    AccountMeta::new_readonly(a.token_program.key(), false),                    AccountMeta::new_readonly(a.ata_program.key(), false),                    AccountMeta::new_readonly(a.rent.key(), false),                    AccountMeta::new_readonly(a.event_authority.key(), false),                    AccountMeta::new_readonly(a.pump_program.key(), false),                ],                data,            },            &[                a.mint.to_account_info(), a.mint_authority.to_account_info(), a.bonding_curve.to_account_info(), a.curve_ata.to_account_info(),                a.global.to_account_info(), a.mpl.to_account_info(), a.metadata.to_account_info(), a.dev.to_account_info(),                a.system_program.to_account_info(), a.token_program.to_account_info(), a.ata_program.to_account_info(), a.rent.to_account_info(),                a.event_authority.to_account_info(), a.pump_program.to_account_info(),            ],        )?;        let now = Clock::get()?.unix_timestamp;        let p = &mut ctx.accounts.pact;        p.mint = ctx.accounts.mint.key();        p.dev = ctx.accounts.dev.key();        p.pledged = 0;        p.forfeited = false;        p.collected_total = 0;        p.claimed_total = 0;        p.burned_total = 0;        p.created_ts = now;        p.released_ts = 0;        p.bump = ctx.bumps.pact;        emit!(Launched { pact: pact_key, mint: p.mint, dev: p.dev, ts: now });        Ok(())    }     /// Dev: lock `amount` tokens in the pact's vault. Can be called again to add more.    pub fn pledge(ctx: Context<Pledge>, amount: u64) -> Result<()> {        require!(amount > 0, HolvoError::Nothing);        require!(!ctx.accounts.pact.forfeited, HolvoError::Forfeited);        let a = &ctx.accounts;        let pact_key = a.pact.key();        let (vault, _) = Pubkey::find_program_address(&[pact_key.as_ref(), TOKEN_PROGRAM_ID.as_ref(), a.mint.key().as_ref()], &ATA_PROGRAM_ID);        require_keys_eq!(a.vault.key(), vault, HolvoError::BadAccount);        // the vault is the pact's associated token account; the dev pays its rent the first time        if a.vault.to_account_info().data_is_empty() {            invoke(                &Instruction {                    program_id: ATA_PROGRAM_ID,                    accounts: vec![                        AccountMeta::new(a.dev.key(), true), AccountMeta::new(a.vault.key(), false),                        AccountMeta::new_readonly(pact_key, false), AccountMeta::new_readonly(a.mint.key(), false),                        AccountMeta::new_readonly(a.system_program.key(), false), AccountMeta::new_readonly(a.token_program.key(), false),                    ],                    data: vec![1],                },                &[a.dev.to_account_info(), a.vault.to_account_info(), a.pact.to_account_info(), a.mint.to_account_info(), a.system_program.to_account_info(), a.token_program.to_account_info(), a.ata_program.to_account_info()],            )?;        }        let before = token_amount(&a.vault.to_account_info())?;        let mut data = vec![3u8]; // spl-token Transfer        data.extend_from_slice(&amount.to_le_bytes());        invoke(            &Instruction {                program_id: TOKEN_PROGRAM_ID,                accounts: vec![AccountMeta::new(a.dev_ata.key(), false), AccountMeta::new(a.vault.key(), false), AccountMeta::new_readonly(a.dev.key(), true)],                data,            },            &[a.dev_ata.to_account_info(), a.vault.to_account_info(), a.dev.to_account_info(), a.token_program.to_account_info()],        )?;        let after = token_amount(&a.vault.to_account_info())?;        let added = after.checked_sub(before).ok_or(HolvoError::Math)?;        let p = &mut ctx.accounts.pact;        p.pledged = after;        emit!(Pledged { pact: pact_key, added, pledged: after, ts: Clock::get()?.unix_timestamp });        Ok(())    }     /// Dev: take the whole bag back. The fees are forfeited for good from this moment.    pub fn release(ctx: Context<Release>) -> Result<()> {        require!(!ctx.accounts.pact.forfeited, HolvoError::Forfeited);        let a = &ctx.accounts;        let pact_key = a.pact.key();        let (vault, _) = Pubkey::find_program_address(&[pact_key.as_ref(), TOKEN_PROGRAM_ID.as_ref(), a.mint.key().as_ref()], &ATA_PROGRAM_ID);        require_keys_eq!(a.vault.key(), vault, HolvoError::BadAccount);        let amount = token_amount(&a.vault.to_account_info())?;        require!(amount > 0, HolvoError::Nothing);        let mint_key = a.mint.key();        let seeds: &[&[u8]] = &[PACT_SEED, mint_key.as_ref(), &[a.pact.bump]];        let mut data = vec![3u8];        data.extend_from_slice(&amount.to_le_bytes());        invoke_signed(            &Instruction {                program_id: TOKEN_PROGRAM_ID,                accounts: vec![AccountMeta::new(a.vault.key(), false), AccountMeta::new(a.dev_ata.key(), false), AccountMeta::new_readonly(pact_key, true)],                data,            },            &[a.vault.to_account_info(), a.dev_ata.to_account_info(), a.pact.to_account_info(), a.token_program.to_account_info()],            &[seeds],        )?;        let now = Clock::get()?.unix_timestamp;        let p = &mut ctx.accounts.pact;        p.pledged = 0;        p.forfeited = true;        p.released_ts = now;        emit!(Released { pact: pact_key, amount, ts: now });        Ok(())    }     /// Dev: take the collected fees, while the pledge is in.    pub fn claim(ctx: Context<Claim>) -> Result<()> {        let p = &ctx.accounts.pact;        require!(!p.forfeited, HolvoError::Forfeited);        require!(p.pledged > 0, HolvoError::NoPledge);        let info = ctx.accounts.pact.to_account_info();        let amount = above_rent(&info)?;        require!(amount > 0, HolvoError::Nothing);        **info.try_borrow_mut_lamports()? -= amount;        **ctx.accounts.dev.to_account_info().try_borrow_mut_lamports()? += amount;        let p = &mut ctx.accounts.pact;        p.claimed_total = p.claimed_total.checked_add(amount).ok_or(HolvoError::Math)?;        emit!(Claimed { pact: info.key(), lamports: amount, ts: Clock::get()?.unix_timestamp });        Ok(())    }     /// Anyone: after a release, send what the pact holds to the incinerator.    pub fn burn(ctx: Context<Burn>) -> Result<()> {        require!(ctx.accounts.pact.forfeited, HolvoError::NotForfeited);        let info = ctx.accounts.pact.to_account_info();        let amount = above_rent(&info)?;        require!(amount > 0, HolvoError::Nothing);        **info.try_borrow_mut_lamports()? -= amount;        **ctx.accounts.incinerator.to_account_info().try_borrow_mut_lamports()? += amount;        let p = &mut ctx.accounts.pact;        p.burned_total = p.burned_total.checked_add(amount).ok_or(HolvoError::Math)?;        emit!(Burned { pact: info.key(), lamports: amount, ts: Clock::get()?.unix_timestamp });        Ok(())    }     /// Anyone: move the coin's bonding-curve creator fees onto the pact.    pub fn collect_curve(ctx: Context<CollectCurve>) -> Result<()> {        let a = &ctx.accounts;        let info = a.pact.to_account_info();        let before = info.lamports();        invoke(            &Instruction {                program_id: PUMP_PROGRAM_ID,                accounts: vec![                    AccountMeta::new(info.key(), false),                    AccountMeta::new(a.creator_vault.key(), false),                    AccountMeta::new_readonly(a.system_program.key(), false),                    AccountMeta::new_readonly(a.event_authority.key(), false),                    AccountMeta::new_readonly(a.pump_program.key(), false),                ],                data: PUMP_COLLECT_DISC.to_vec(),            },            &[info.clone(), a.creator_vault.to_account_info(), a.system_program.to_account_info(), a.event_authority.to_account_info(), a.pump_program.to_account_info()],        )?;        let got = info.lamports().checked_sub(before).ok_or(HolvoError::Math)?;        require!(got > 0, HolvoError::Nothing);        let p = &mut ctx.accounts.pact;        p.collected_total = p.collected_total.checked_add(got).ok_or(HolvoError::Math)?;        emit!(Collected { pact: info.key(), source: SOURCE_CURVE, lamports: got, ts: Clock::get()?.unix_timestamp });        Ok(())    }     /// Anyone: move the coin's PumpSwap creator fees onto the pact as SOL. If the caller had to    /// create the pact's WSOL account, its rent goes back to the caller.    pub fn collect_amm(ctx: Context<CollectAmm>) -> Result<()> {        let a = &ctx.accounts;        let info = a.pact.to_account_info();        let pact_key = info.key();        let (expected, _) = Pubkey::find_program_address(&[pact_key.as_ref(), TOKEN_PROGRAM_ID.as_ref(), WSOL_MINT.as_ref()], &ATA_PROGRAM_ID);        require_keys_eq!(a.pact_wsol.key(), expected, HolvoError::BadAccount);        let created_here = a.pact_wsol.to_account_info().data_is_empty();        if created_here {            invoke(                &Instruction {                    program_id: ATA_PROGRAM_ID,                    accounts: vec![                        AccountMeta::new(a.payer.key(), true), AccountMeta::new(a.pact_wsol.key(), false),                        AccountMeta::new_readonly(pact_key, false), AccountMeta::new_readonly(a.wsol_mint.key(), false),                        AccountMeta::new_readonly(a.system_program.key(), false), AccountMeta::new_readonly(a.token_program.key(), false),                    ],                    data: vec![1],                },                &[a.payer.to_account_info(), a.pact_wsol.to_account_info(), info.clone(), a.wsol_mint.to_account_info(), a.system_program.to_account_info(), a.token_program.to_account_info(), a.ata_program.to_account_info()],            )?;        }        invoke(            &Instruction {                program_id: PUMP_AMM_PROGRAM_ID,                accounts: vec![                    AccountMeta::new_readonly(a.wsol_mint.key(), false),                    AccountMeta::new_readonly(a.token_program.key(), false),                    AccountMeta::new_readonly(pact_key, false),                    AccountMeta::new_readonly(a.vault_authority.key(), false),                    AccountMeta::new(a.vault_ata.key(), false),                    AccountMeta::new(a.pact_wsol.key(), false),                    AccountMeta::new_readonly(a.amm_event_authority.key(), false),                    AccountMeta::new_readonly(a.amm_program.key(), false),                ],                data: AMM_COLLECT_DISC.to_vec(),            },            &[a.wsol_mint.to_account_info(), a.token_program.to_account_info(), info.clone(), a.vault_authority.to_account_info(), a.vault_ata.to_account_info(), a.pact_wsol.to_account_info(), a.amm_event_authority.to_account_info(), a.amm_program.to_account_info()],        )?;        let before = info.lamports();        let mint_key = a.pact.mint;        let seeds: &[&[u8]] = &[PACT_SEED, mint_key.as_ref(), &[a.pact.bump]];        invoke_signed(            &Instruction {                program_id: TOKEN_PROGRAM_ID,                accounts: vec![AccountMeta::new(a.pact_wsol.key(), false), AccountMeta::new(pact_key, false), AccountMeta::new_readonly(pact_key, true)],                data: vec![9], // CloseAccount            },            &[a.pact_wsol.to_account_info(), info.clone(), a.token_program.to_account_info()],            &[seeds],        )?;        let landed = info.lamports().checked_sub(before).ok_or(HolvoError::Math)?;        let rent = Rent::get()?.minimum_balance(TOKEN_ACCOUNT_LEN);        let refund = if created_here { rent.min(landed) } else { 0 };        if refund > 0 {            **info.try_borrow_mut_lamports()? -= refund;            **a.payer.to_account_info().try_borrow_mut_lamports()? += refund;        }        let got = landed - refund;        require!(got > 0, HolvoError::Nothing);        let p = &mut ctx.accounts.pact;        p.collected_total = p.collected_total.checked_add(got).ok_or(HolvoError::Math)?;        emit!(Collected { pact: pact_key, source: SOURCE_AMM, lamports: got, ts: Clock::get()?.unix_timestamp });        Ok(())    }} fn put_str(v: &mut Vec<u8>, s: &str) {    v.extend_from_slice(&(s.len() as u32).to_le_bytes());    v.extend_from_slice(s.as_bytes());} /// lamports on an account above its own rentfn above_rent(info: &AccountInfo) -> Result<u64> {    let rent = Rent::get()?.minimum_balance(info.data_len());    Ok(info.lamports().saturating_sub(rent))} /// spl-token account amount (u64 at offset 64), checked to be a token account of the token programfn token_amount(info: &AccountInfo) -> Result<u64> {    require_keys_eq!(*info.owner, TOKEN_PROGRAM_ID, HolvoError::BadAccount);    let d = info.try_borrow_data()?;    require!(d.len() >= 72, HolvoError::BadAccount);    Ok(u64::from_le_bytes(d[64..72].try_into().unwrap()))} #[account]#[derive(InitSpace)]pub struct Pact {    pub mint: Pubkey,    pub dev: Pubkey,    pub pledged: u64,    pub forfeited: bool,    pub collected_total: u64,    pub claimed_total: u64,    pub burned_total: u64,    pub created_ts: i64,    pub released_ts: i64,    pub bump: u8,} #[derive(Accounts)]pub struct Launch<'info> {    #[account(init, payer = dev, space = 8 + Pact::INIT_SPACE, seeds = [PACT_SEED, mint.key().as_ref()], bump)]    pub pact: Account<'info, Pact>,    #[account(mut)]    pub dev: Signer<'info>,    /// CHECK: new mint, must sign    #[account(mut)]    pub mint: UncheckedAccount<'info>,    /// CHECK: pump pda    pub mint_authority: UncheckedAccount<'info>,    /// CHECK: pump pda    #[account(mut)]    pub bonding_curve: UncheckedAccount<'info>,    /// CHECK: pump ata    #[account(mut)]    pub curve_ata: UncheckedAccount<'info>,    /// CHECK: pump global    pub global: UncheckedAccount<'info>,    /// CHECK: metaplex    pub mpl: UncheckedAccount<'info>,    /// CHECK: metadata pda    #[account(mut)]    pub metadata: UncheckedAccount<'info>,    pub system_program: Program<'info, System>,    /// CHECK: spl token    #[account(address = TOKEN_PROGRAM_ID)]    pub token_program: UncheckedAccount<'info>,    /// CHECK: ata program    #[account(address = ATA_PROGRAM_ID)]    pub ata_program: UncheckedAccount<'info>,    /// CHECK: rent sysvar    pub rent: UncheckedAccount<'info>,    /// CHECK: pump event authority    pub event_authority: UncheckedAccount<'info>,    /// CHECK: pump program    #[account(address = PUMP_PROGRAM_ID)]    pub pump_program: UncheckedAccount<'info>,} #[derive(Accounts)]pub struct Pledge<'info> {    #[account(mut, seeds = [PACT_SEED, pact.mint.as_ref()], bump = pact.bump, has_one = dev, has_one = mint)]    pub pact: Account<'info, Pact>,    #[account(mut)]    pub dev: Signer<'info>,    /// CHECK: the coin's mint, matched against the pact    pub mint: UncheckedAccount<'info>,    /// CHECK: the dev's token account; spl-token checks the dev owns it    #[account(mut)]    pub dev_ata: UncheckedAccount<'info>,    /// CHECK: the pact's associated token account, checked in the handler    #[account(mut)]    pub vault: UncheckedAccount<'info>,    /// CHECK: spl token    #[account(address = TOKEN_PROGRAM_ID)]    pub token_program: UncheckedAccount<'info>,    /// CHECK: ata program    #[account(address = ATA_PROGRAM_ID)]    pub ata_program: UncheckedAccount<'info>,    pub system_program: Program<'info, System>,} #[derive(Accounts)]pub struct Release<'info> {    #[account(mut, seeds = [PACT_SEED, pact.mint.as_ref()], bump = pact.bump, has_one = dev, has_one = mint)]    pub pact: Account<'info, Pact>,    #[account(mut)]    pub dev: Signer<'info>,    /// CHECK: the coin's mint, matched against the pact    pub mint: UncheckedAccount<'info>,    /// CHECK: where the bag goes; spl-token checks the mint    #[account(mut)]    pub dev_ata: UncheckedAccount<'info>,    /// CHECK: the pact's associated token account, checked in the handler    #[account(mut)]    pub vault: UncheckedAccount<'info>,    /// CHECK: spl token    #[account(address = TOKEN_PROGRAM_ID)]    pub token_program: UncheckedAccount<'info>,} #[derive(Accounts)]pub struct Claim<'info> {    #[account(mut, seeds = [PACT_SEED, pact.mint.as_ref()], bump = pact.bump, has_one = dev)]    pub pact: Account<'info, Pact>,    #[account(mut)]    pub dev: Signer<'info>,} #[derive(Accounts)]pub struct Burn<'info> {    #[account(mut, seeds = [PACT_SEED, pact.mint.as_ref()], bump = pact.bump)]    pub pact: Account<'info, Pact>,    /// CHECK: the incinerator, an address with no key    #[account(mut, address = INCINERATOR)]    pub incinerator: UncheckedAccount<'info>,} #[derive(Accounts)]pub struct CollectCurve<'info> {    #[account(mut, seeds = [PACT_SEED, pact.mint.as_ref()], bump = pact.bump)]    pub pact: Account<'info, Pact>,    /// CHECK: pump.fun's creator vault for this pact    #[account(mut, seeds = [b"creator-vault", pact.key().as_ref()], bump, seeds::program = PUMP_PROGRAM_ID)]    pub creator_vault: UncheckedAccount<'info>,    pub system_program: Program<'info, System>,    /// CHECK: pump.fun event authority    #[account(seeds = [b"__event_authority"], bump, seeds::program = PUMP_PROGRAM_ID)]    pub event_authority: UncheckedAccount<'info>,    /// CHECK: pump.fun    #[account(address = PUMP_PROGRAM_ID)]    pub pump_program: UncheckedAccount<'info>,} #[derive(Accounts)]pub struct CollectAmm<'info> {    #[account(mut, seeds = [PACT_SEED, pact.mint.as_ref()], bump = pact.bump)]    pub pact: Account<'info, Pact>,    /// pays the pact's WSOL account rent if it has to be created, and gets it back    #[account(mut)]    pub payer: Signer<'info>,    /// CHECK: the pact's WSOL associated token account, checked in the handler    #[account(mut)]    pub pact_wsol: UncheckedAccount<'info>,    /// CHECK: PumpSwap's creator vault authority for this pact    #[account(seeds = [b"creator_vault", pact.key().as_ref()], bump, seeds::program = PUMP_AMM_PROGRAM_ID)]    pub vault_authority: UncheckedAccount<'info>,    /// CHECK: the vault authority's WSOL account, PumpSwap checks it    #[account(mut)]    pub vault_ata: UncheckedAccount<'info>,    /// CHECK: wrapped SOL    #[account(address = WSOL_MINT)]    pub wsol_mint: UncheckedAccount<'info>,    /// CHECK: spl token    #[account(address = TOKEN_PROGRAM_ID)]    pub token_program: UncheckedAccount<'info>,    /// CHECK: ata program    #[account(address = ATA_PROGRAM_ID)]    pub ata_program: UncheckedAccount<'info>,    pub system_program: Program<'info, System>,    /// CHECK: PumpSwap event authority    #[account(seeds = [b"__event_authority"], bump, seeds::program = PUMP_AMM_PROGRAM_ID)]    pub amm_event_authority: UncheckedAccount<'info>,    /// CHECK: PumpSwap    #[account(address = PUMP_AMM_PROGRAM_ID)]    pub amm_program: UncheckedAccount<'info>,} #[event]pub struct Launched { pub pact: Pubkey, pub mint: Pubkey, pub dev: Pubkey, pub ts: i64 }#[event]pub struct Pledged { pub pact: Pubkey, pub added: u64, pub pledged: u64, pub ts: i64 }#[event]pub struct Released { pub pact: Pubkey, pub amount: u64, pub ts: i64 }#[event]pub struct Claimed { pub pact: Pubkey, pub lamports: u64, pub ts: i64 }#[event]pub struct Burned { pub pact: Pubkey, pub lamports: u64, pub ts: i64 }#[event]pub struct Collected { pub pact: Pubkey, pub source: u8, pub lamports: u64, pub ts: i64 } #[error_code]pub enum HolvoError {    #[msg("text out of range")] BadText,    #[msg("the mint keypair must sign")] MintMustSign,    #[msg("nothing to move")] Nothing,    #[msg("the fees of this coin are forfeited: the dev took the bag back")] Forfeited,    #[msg("the dev has not pledged a bag yet")] NoPledge,    #[msg("the fees are not forfeited")] NotForfeited,    #[msg("wrong account")] BadAccount,    #[msg("math")] Math,}