Skip to content
mowro

Program

The source the deployed program was built from (crate name metra, from before the rename), Anchor 0.31, 571 lines. A verified build is not published yet, and the program is still upgradeable by its deploy key. Program id 4qkLCTx4Ssp8gFBonFTUeopPhEBVcttD7PjwB7Wg1QvH on Solana mainnet.

programs/metra/src/lib.rs
//! METRA - a prepaid meter for an agent.//!//! An owner opens a meter for one agent key: a cap of lamports per window of time. Anyone can//! top the meter up. A coin launched through `launch` has the meter as its pump.fun creator; its//! creator fees are moved onto the meter by `collect_curve` (bonding curve) or `collect_amm`//! (PumpSwap, after graduation), which anyone can call and which leave a receipt. The agent draws//! SOL to any address with `draw`, never more than the cap inside one window; every draw is a//! receipt (an event in the transaction) and a running total in the meter. A window opens with the//! first draw after the previous one ended and runs its full length.//!//! The owner can raise or lower the cap, cut the meter (no draws until it is turned back on), take//! the balance back, or close a meter that has no coin. The owner can also `seal` a meter, for//! good: after that there is no withdraw and no close, and the cap and window can only move toward//! a slower rate, so SOL leaves only through the agent's draws. The agent key can do nothing else://! it cannot change the cap, cannot cut, cannot withdraw.//!//! No fee to us and no admin instruction. One meter per (owner, agent) pair. use anchor_lang::prelude::*;use anchor_lang::solana_program::instruction::{AccountMeta, Instruction};use anchor_lang::solana_program::program::{invoke, invoke_signed};use anchor_lang::system_program; declare_id!("4qkLCTx4Ssp8gFBonFTUeopPhEBVcttD7PjwB7Wg1QvH"); 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 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 METER_SEED: &[u8] = b"meter";pub const SEAL_SEED: &[u8] = b"seal";pub const MAX_NAME: usize = 32;pub const MAX_SYMBOL: usize = 10;pub const MAX_URI: usize = 200;pub const MAX_LABEL: usize = 24;pub const MIN_WINDOW: i64 = 60; // a minutepub const MAX_WINDOW: i64 = 30 * 86_400; // a month pub const SOURCE_CURVE: u8 = 0;pub const SOURCE_AMM: u8 = 1; #[program]pub mod metra {    use super::*;     /// Open a meter: `cap` lamports per `window` seconds for `agent`. The owner pays the rent.    pub fn open(ctx: Context<Open>, cap: u64, window: i64, label: String) -> Result<()> {        require!(window >= MIN_WINDOW && window <= MAX_WINDOW, MetraError::BadWindow);        require!(cap > 0, MetraError::BadCap);        require!(label.len() <= MAX_LABEL, MetraError::BadText);        let now = Clock::get()?.unix_timestamp;        let m = &mut ctx.accounts.meter;        m.owner = ctx.accounts.owner.key();        m.agent = ctx.accounts.agent.key();        m.cap = cap;        m.window = window;        m.window_start = now;        m.spent_in_window = 0;        m.drawn_total = 0;        m.topped_total = 0;        m.draws = 0;        m.cut = false;        m.mint = Pubkey::default();        m.opened_ts = now;        m.label = label;        m.bump = ctx.bumps.meter;        emit!(Opened { meter: m.key(), owner: m.owner, agent: m.agent, cap, window, ts: now });        Ok(())    }     /// Put SOL on the meter. Anyone can.    pub fn top_up(ctx: Context<TopUp>, lamports: u64) -> Result<()> {        require!(lamports > 0, MetraError::Nothing);        system_program::transfer(            CpiContext::new(ctx.accounts.system_program.to_account_info(), system_program::Transfer { from: ctx.accounts.payer.to_account_info(), to: ctx.accounts.meter.to_account_info() }),            lamports,        )?;        let m = &mut ctx.accounts.meter;        m.topped_total = m.topped_total.checked_add(lamports).ok_or(MetraError::Math)?;        emit!(ToppedUp { meter: m.key(), from: ctx.accounts.payer.key(), lamports, balance: meter_balance(&ctx.accounts.meter.to_account_info())? });        Ok(())    }     /// The agent draws `lamports` to `to`. Refused when cut, over the cap for this window, or over the balance.    pub fn draw(ctx: Context<Draw>, lamports: u64, memo: String) -> Result<()> {        require!(lamports > 0, MetraError::Nothing);        require!(memo.len() <= 64, MetraError::BadText);        let now = Clock::get()?.unix_timestamp;        let meter_info = ctx.accounts.meter.to_account_info();        let available = meter_balance(&meter_info)?;        let m = &mut ctx.accounts.meter;        require!(!m.cut, MetraError::Cut);        if now - m.window_start >= m.window {            // a new window starts at the first draw after the old one ended            m.window_start = now;            m.spent_in_window = 0;        }        let after = m.spent_in_window.checked_add(lamports).ok_or(MetraError::Math)?;        require!(after <= m.cap, MetraError::OverCap);        require!(lamports <= available, MetraError::Empty);        m.spent_in_window = after;        m.drawn_total = m.drawn_total.checked_add(lamports).ok_or(MetraError::Math)?;        m.draws += 1;        let n = m.draws;        let key = m.key();        let agent = m.agent;        let cap = m.cap;        **meter_info.try_borrow_mut_lamports()? -= lamports;        **ctx.accounts.to.to_account_info().try_borrow_mut_lamports()? += lamports;        emit!(Drew { meter: key, agent, to: ctx.accounts.to.key(), lamports, n, left_in_window: cap - after, balance: available - lamports, memo, ts: now });        Ok(())    }     /// Owner: change the cap or the window. Takes effect on the next draw.    /// On a sealed meter only a slower rate is allowed: the cap can only go down, the window only up.    pub fn set_cap(ctx: Context<OwnerGuarded>, cap: u64, window: i64) -> Result<()> {        require!(window >= MIN_WINDOW && window <= MAX_WINDOW, MetraError::BadWindow);        require!(cap > 0, MetraError::BadCap);        let sealed = is_sealed(&ctx.accounts.seal);        let m = &mut ctx.accounts.meter;        if sealed {            require!(cap <= m.cap && window >= m.window, MetraError::Sealed);        }        m.cap = cap;        m.window = window;        emit!(CapSet { meter: m.key(), cap, window });        Ok(())    }     /// Owner: cut the meter (no draws) or turn it back on.    pub fn cut(ctx: Context<OwnerOnly>, off: bool) -> Result<()> {        let m = &mut ctx.accounts.meter;        m.cut = off;        emit!(CutSet { meter: m.key(), cut: off, ts: Clock::get()?.unix_timestamp });        Ok(())    }     /// Owner: take SOL back off the meter. Refused on a sealed meter.    pub fn withdraw(ctx: Context<OwnerGuarded>, lamports: u64) -> Result<()> {        require!(!is_sealed(&ctx.accounts.seal), MetraError::Sealed);        let meter_info = ctx.accounts.meter.to_account_info();        let available = meter_balance(&meter_info)?;        require!(lamports > 0 && lamports <= available, MetraError::Empty);        **meter_info.try_borrow_mut_lamports()? -= lamports;        **ctx.accounts.owner.to_account_info().try_borrow_mut_lamports()? += lamports;        emit!(Withdrawn { meter: ctx.accounts.meter.key(), lamports, balance: available - lamports });        Ok(())    }     /// Owner: close a meter that has no coin. The balance and the rent go back to the owner.    /// Refused on a sealed meter, and on a meter that launched a coin (it stays that coin's creator).    pub fn close(ctx: Context<CloseMeter>) -> Result<()> {        require!(!is_sealed(&ctx.accounts.seal), MetraError::Sealed);        require!(ctx.accounts.meter.mint == Pubkey::default(), MetraError::HasCoin);        let lamports = ctx.accounts.meter.to_account_info().lamports();        emit!(Closed { meter: ctx.accounts.meter.key(), lamports, ts: Clock::get()?.unix_timestamp });        Ok(())    }     /// Owner: seal the meter, for good. No instruction removes a seal.    pub fn seal(ctx: Context<SealMeter>) -> Result<()> {        let now = Clock::get()?.unix_timestamp;        let s = &mut ctx.accounts.seal;        s.meter = ctx.accounts.meter.key();        s.ts = now;        emit!(Sealed { meter: s.meter, ts: now });        Ok(())    }     /// Anyone: move the coin's bonding-curve creator fees from pump.fun's creator vault onto the meter.    pub fn collect_curve(ctx: Context<CollectCurve>) -> Result<()> {        let a = &ctx.accounts;        let meter_info = a.meter.to_account_info();        let before = meter_info.lamports();        invoke(            &Instruction {                program_id: PUMP_PROGRAM_ID,                accounts: vec![                    AccountMeta::new(meter_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(),            },            &[meter_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 = meter_info.lamports().checked_sub(before).ok_or(MetraError::Math)?;        require!(got > 0, MetraError::Nothing);        emit!(Collected { meter: meter_info.key(), source: SOURCE_CURVE, lamports: got, balance: meter_balance(&meter_info)?, ts: Clock::get()?.unix_timestamp });        Ok(())    }     /// Anyone: move the coin's PumpSwap creator fees onto the meter. PumpSwap pays them in wrapped    /// SOL to the meter's WSOL account; the meter signs to close that account, so they land as SOL.    /// If the caller had to create the WSOL account, its rent goes back to the caller.    pub fn collect_amm(ctx: Context<CollectAmm>) -> Result<()> {        let a = &ctx.accounts;        let meter_info = a.meter.to_account_info();        let meter_key = meter_info.key();        let (expected_ata, _) = Pubkey::find_program_address(&[meter_key.as_ref(), TOKEN_PROGRAM_ID.as_ref(), WSOL_MINT.as_ref()], &ATA_PROGRAM_ID);        require_keys_eq!(a.meter_wsol.key(), expected_ata, MetraError::BadAccount);         // 1. the meter's WSOL account, created by the caller when it is missing        let created_here = a.meter_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.meter_wsol.key(), false),                        AccountMeta::new_readonly(meter_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], // CreateIdempotent                },                &[a.payer.to_account_info(), a.meter_wsol.to_account_info(), meter_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()],            )?;        }         // 2. PumpSwap pays the creator fees into it        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(meter_key, false),                    AccountMeta::new_readonly(a.vault_authority.key(), false),                    AccountMeta::new(a.vault_ata.key(), false),                    AccountMeta::new(a.meter_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(), meter_info.clone(), a.vault_authority.to_account_info(), a.vault_ata.to_account_info(), a.meter_wsol.to_account_info(), a.amm_event_authority.to_account_info(), a.amm_program.to_account_info()],        )?;         // 3. the meter closes its WSOL account: everything in it lands on the meter as SOL        let before = meter_info.lamports();        let m = &a.meter;        let seeds: &[&[u8]] = &[METER_SEED, m.owner.as_ref(), m.agent.as_ref(), &[m.bump]];        invoke_signed(            &Instruction {                program_id: TOKEN_PROGRAM_ID,                accounts: vec![                    AccountMeta::new(a.meter_wsol.key(), false),                    AccountMeta::new(meter_key, false),                    AccountMeta::new_readonly(meter_key, true),                ],                data: vec![9], // CloseAccount            },            &[a.meter_wsol.to_account_info(), meter_info.clone(), a.token_program.to_account_info()],            &[seeds],        )?;        let landed = meter_info.lamports().checked_sub(before).ok_or(MetraError::Math)?;         // 4. the WSOL account's rent: back to the caller who paid it, otherwise it stays on the meter        let rent = Rent::get()?.minimum_balance(TOKEN_ACCOUNT_LEN);        let refund = if created_here { rent.min(landed) } else { 0 };        if refund > 0 {            **meter_info.try_borrow_mut_lamports()? -= refund;            **a.payer.to_account_info().try_borrow_mut_lamports()? += refund;        }        let got = landed - refund;        require!(got > 0, MetraError::Nothing);        emit!(Collected { meter: meter_key, source: SOURCE_AMM, lamports: got, balance: meter_balance(&meter_info)?, ts: Clock::get()?.unix_timestamp });        Ok(())    }     /// Owner: create a coin on pump.fun with the meter as its creator.    pub fn launch(ctx: Context<Launch>, name: String, symbol: String, uri: String) -> Result<()> {        require!(!name.is_empty() && name.len() <= MAX_NAME, MetraError::BadText);        require!(!symbol.is_empty() && symbol.len() <= MAX_SYMBOL, MetraError::BadText);        require!(!uri.is_empty() && uri.len() <= MAX_URI, MetraError::BadText);        require!(ctx.accounts.meter.mint == Pubkey::default(), MetraError::HasCoin);        let a = &ctx.accounts;        require!(a.mint.is_signer, MetraError::MintMustSign);        let meter_key = a.meter.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(meter_key.as_ref());        let metas = 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.owner.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),        ];        invoke(            &Instruction { program_id: PUMP_PROGRAM_ID, accounts: metas, 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.owner.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 m = &mut ctx.accounts.meter;        m.mint = ctx.accounts.mint.key();        emit!(Launched { meter: meter_key, mint: m.mint, 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 the meter above its own rentfn meter_balance(info: &AccountInfo) -> Result<u64> {    let rent = Rent::get()?.minimum_balance(info.data_len());    Ok(info.lamports().saturating_sub(rent))} /// a meter is sealed when its seal account exists and belongs to this programfn is_sealed(seal: &UncheckedAccount) -> bool {    let info = seal.to_account_info();    info.owner == &crate::ID && !info.data_is_empty()} #[account]#[derive(InitSpace)]pub struct Meter {    pub owner: Pubkey,    pub agent: Pubkey,    pub cap: u64,    pub window: i64,    pub window_start: i64,    pub spent_in_window: u64,    pub drawn_total: u64,    pub topped_total: u64,    pub draws: u64,    pub cut: bool,    pub mint: Pubkey,    pub opened_ts: i64,    #[max_len(24)]    pub label: String,    pub bump: u8,} #[account]#[derive(InitSpace)]pub struct Seal {    pub meter: Pubkey,    pub ts: i64,} #[derive(Accounts)]pub struct Open<'info> {    #[account(init, payer = owner, space = 8 + Meter::INIT_SPACE, seeds = [METER_SEED, owner.key().as_ref(), agent.key().as_ref()], bump)]    pub meter: Account<'info, Meter>,    #[account(mut)]    pub owner: Signer<'info>,    /// CHECK: the agent's key, any pubkey, it does not sign here    pub agent: UncheckedAccount<'info>,    pub system_program: Program<'info, System>,} #[derive(Accounts)]pub struct TopUp<'info> {    #[account(mut, seeds = [METER_SEED, meter.owner.as_ref(), meter.agent.as_ref()], bump = meter.bump)]    pub meter: Account<'info, Meter>,    #[account(mut)]    pub payer: Signer<'info>,    pub system_program: Program<'info, System>,} #[derive(Accounts)]pub struct Draw<'info> {    #[account(mut, seeds = [METER_SEED, meter.owner.as_ref(), meter.agent.as_ref()], bump = meter.bump, has_one = agent)]    pub meter: Account<'info, Meter>,    pub agent: Signer<'info>,    /// CHECK: any address, it only receives lamports    #[account(mut)]    pub to: UncheckedAccount<'info>,} #[derive(Accounts)]pub struct OwnerOnly<'info> {    #[account(mut, seeds = [METER_SEED, meter.owner.as_ref(), meter.agent.as_ref()], bump = meter.bump, has_one = owner)]    pub meter: Account<'info, Meter>,    #[account(mut)]    pub owner: Signer<'info>,} /// owner instructions that a seal restricts#[derive(Accounts)]pub struct OwnerGuarded<'info> {    #[account(mut, seeds = [METER_SEED, meter.owner.as_ref(), meter.agent.as_ref()], bump = meter.bump, has_one = owner)]    pub meter: Account<'info, Meter>,    #[account(mut)]    pub owner: Signer<'info>,    /// CHECK: the meter's seal PDA; empty while the meter is not sealed    #[account(seeds = [SEAL_SEED, meter.key().as_ref()], bump)]    pub seal: UncheckedAccount<'info>,} #[derive(Accounts)]pub struct CloseMeter<'info> {    #[account(mut, close = owner, seeds = [METER_SEED, meter.owner.as_ref(), meter.agent.as_ref()], bump = meter.bump, has_one = owner)]    pub meter: Account<'info, Meter>,    #[account(mut)]    pub owner: Signer<'info>,    /// CHECK: the meter's seal PDA; empty while the meter is not sealed    #[account(seeds = [SEAL_SEED, meter.key().as_ref()], bump)]    pub seal: UncheckedAccount<'info>,} #[derive(Accounts)]pub struct SealMeter<'info> {    #[account(seeds = [METER_SEED, meter.owner.as_ref(), meter.agent.as_ref()], bump = meter.bump, has_one = owner)]    pub meter: Account<'info, Meter>,    #[account(init, payer = owner, space = 8 + Seal::INIT_SPACE, seeds = [SEAL_SEED, meter.key().as_ref()], bump)]    pub seal: Account<'info, Seal>,    #[account(mut)]    pub owner: Signer<'info>,    pub system_program: Program<'info, System>,} #[derive(Accounts)]pub struct CollectCurve<'info> {    #[account(mut, seeds = [METER_SEED, meter.owner.as_ref(), meter.agent.as_ref()], bump = meter.bump)]    pub meter: Account<'info, Meter>,    /// CHECK: pump.fun's creator vault for this meter    #[account(mut, seeds = [b"creator-vault", meter.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 = [METER_SEED, meter.owner.as_ref(), meter.agent.as_ref()], bump = meter.bump)]    pub meter: Account<'info, Meter>,    /// pays the meter's WSOL account rent if it has to be created, and gets it back    #[account(mut)]    pub payer: Signer<'info>,    /// CHECK: the meter's WSOL associated token account, checked in the handler    #[account(mut)]    pub meter_wsol: UncheckedAccount<'info>,    /// CHECK: PumpSwap's creator vault authority for this meter    #[account(seeds = [b"creator_vault", meter.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>,} #[derive(Accounts)]pub struct Launch<'info> {    #[account(mut, seeds = [METER_SEED, meter.owner.as_ref(), meter.agent.as_ref()], bump = meter.bump, has_one = owner)]    pub meter: Account<'info, Meter>,    #[account(mut)]    pub owner: 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>,} #[event]pub struct Opened { pub meter: Pubkey, pub owner: Pubkey, pub agent: Pubkey, pub cap: u64, pub window: i64, pub ts: i64 }#[event]pub struct ToppedUp { pub meter: Pubkey, pub from: Pubkey, pub lamports: u64, pub balance: u64 }#[event]pub struct Drew { pub meter: Pubkey, pub agent: Pubkey, pub to: Pubkey, pub lamports: u64, pub n: u64, pub left_in_window: u64, pub balance: u64, pub memo: String, pub ts: i64 }#[event]pub struct CapSet { pub meter: Pubkey, pub cap: u64, pub window: i64 }#[event]pub struct CutSet { pub meter: Pubkey, pub cut: bool, pub ts: i64 }#[event]pub struct Withdrawn { pub meter: Pubkey, pub lamports: u64, pub balance: u64 }#[event]pub struct Launched { pub meter: Pubkey, pub mint: Pubkey, pub ts: i64 }#[event]pub struct Collected { pub meter: Pubkey, pub source: u8, pub lamports: u64, pub balance: u64, pub ts: i64 }#[event]pub struct Closed { pub meter: Pubkey, pub lamports: u64, pub ts: i64 }#[event]pub struct Sealed { pub meter: Pubkey, pub ts: i64 } #[error_code]pub enum MetraError {    #[msg("a window is between a minute and a month")] BadWindow,    #[msg("the cap must be above zero")] BadCap,    #[msg("text out of range")] BadText,    #[msg("nothing to move")] Nothing,    #[msg("the meter is cut")] Cut,    #[msg("that draw goes over the cap for this window")] OverCap,    #[msg("the meter does not hold that much")] Empty,    #[msg("this meter already has a coin")] HasCoin,    #[msg("the mint keypair must sign")] MintMustSign,    #[msg("math")] Math,    #[msg("the meter is sealed: no withdraw, no close, and the rate can only go down")] Sealed,    #[msg("wrong account")] BadAccount,}