Spaces:
Sleeping
Sleeping
| use anchor_lang::prelude::*; | |
| use anchor_lang::system_program::{transfer, Transfer}; | |
| declare_id!("EpB6hUZUf1vvvTVAYvEN57pjUWfYswaAuKGGQDHP5iH"); | |
| pub mod cardcli_fee_vault { | |
| use super::*; | |
| pub fn initialize( | |
| ctx: Context<Initialize>, | |
| fee_bps: u16, | |
| fixed_fee_usd_cents: u16, | |
| ) -> Result<()> { | |
| require!(fee_bps <= 10_000, FeeVaultError::InvalidFeeBasisPoints); | |
| let vault = &mut ctx.accounts.fee_vault; | |
| vault.authority = ctx.accounts.authority.key(); | |
| vault.fee_bps = fee_bps; | |
| vault.fixed_fee_usd_cents = fixed_fee_usd_cents; | |
| vault.total_lamports_collected = 0; | |
| vault.payment_count = 0; | |
| vault.bump = ctx.bumps.fee_vault; | |
| vault.created_at = Clock::get()?.unix_timestamp; | |
| Ok(()) | |
| } | |
| pub fn update_pricing( | |
| ctx: Context<UpdatePricing>, | |
| fee_bps: u16, | |
| fixed_fee_usd_cents: u16, | |
| ) -> Result<()> { | |
| require!(fee_bps <= 10_000, FeeVaultError::InvalidFeeBasisPoints); | |
| let vault = &mut ctx.accounts.fee_vault; | |
| require_keys_eq!( | |
| vault.authority, | |
| ctx.accounts.authority.key(), | |
| FeeVaultError::Unauthorized | |
| ); | |
| vault.fee_bps = fee_bps; | |
| vault.fixed_fee_usd_cents = fixed_fee_usd_cents; | |
| Ok(()) | |
| } | |
| pub fn collect_fee( | |
| ctx: Context<CollectFee>, | |
| amount_lamports: u64, | |
| fee_reference: [u8; 16], | |
| ) -> Result<()> { | |
| require!(amount_lamports > 0, FeeVaultError::InvalidFeeAmount); | |
| let cpi_accounts = Transfer { | |
| from: ctx.accounts.payer.to_account_info(), | |
| to: ctx.accounts.fee_vault.to_account_info(), | |
| }; | |
| let cpi_ctx = CpiContext::new(ctx.accounts.system_program.to_account_info(), cpi_accounts); | |
| transfer(cpi_ctx, amount_lamports)?; | |
| let vault = &mut ctx.accounts.fee_vault; | |
| vault.total_lamports_collected = vault | |
| .total_lamports_collected | |
| .checked_add(amount_lamports) | |
| .ok_or(FeeVaultError::MathOverflow)?; | |
| vault.payment_count = vault | |
| .payment_count | |
| .checked_add(1) | |
| .ok_or(FeeVaultError::MathOverflow)?; | |
| emit!(FeeCollected { | |
| payer: ctx.accounts.payer.key(), | |
| amount_lamports, | |
| fee_reference, | |
| payment_count: vault.payment_count, | |
| }); | |
| Ok(()) | |
| } | |
| pub fn withdraw(ctx: Context<Withdraw>, lamports: u64) -> Result<()> { | |
| let vault = &ctx.accounts.fee_vault; | |
| require_keys_eq!( | |
| vault.authority, | |
| ctx.accounts.authority.key(), | |
| FeeVaultError::Unauthorized | |
| ); | |
| require!(lamports > 0, FeeVaultError::InvalidFeeAmount); | |
| let vault_info = ctx.accounts.fee_vault.to_account_info(); | |
| let recipient_info = ctx.accounts.recipient.to_account_info(); | |
| let vault_balance = vault_info.lamports(); | |
| require!( | |
| vault_balance >= lamports, | |
| FeeVaultError::InsufficientVaultBalance | |
| ); | |
| **vault_info.try_borrow_mut_lamports()? -= lamports; | |
| **recipient_info.try_borrow_mut_lamports()? += lamports; | |
| Ok(()) | |
| } | |
| } | |
| pub struct Initialize<'info> { | |
| , | |
| bump, | |
| )] | |
| pub fee_vault: Account<'info, FeeVault>, | |
| pub authority: Signer<'info>, | |
| pub system_program: Program<'info, System>, | |
| } | |
| pub struct UpdatePricing<'info> { | |
| , bump = fee_vault.bump)] | |
| pub fee_vault: Account<'info, FeeVault>, | |
| pub authority: Signer<'info>, | |
| } | |
| pub struct CollectFee<'info> { | |
| , bump = fee_vault.bump)] | |
| pub fee_vault: Account<'info, FeeVault>, | |
| pub payer: Signer<'info>, | |
| pub system_program: Program<'info, System>, | |
| } | |
| pub struct Withdraw<'info> { | |
| , bump = fee_vault.bump)] | |
| pub fee_vault: Account<'info, FeeVault>, | |
| pub authority: Signer<'info>, | |
| pub recipient: SystemAccount<'info>, | |
| } | |
| pub struct FeeVault { | |
| pub authority: Pubkey, | |
| pub fee_bps: u16, | |
| pub fixed_fee_usd_cents: u16, | |
| pub total_lamports_collected: u64, | |
| pub payment_count: u64, | |
| pub bump: u8, | |
| pub created_at: i64, | |
| } | |
| impl FeeVault { | |
| pub const LEN: usize = 32 + 2 + 2 + 8 + 8 + 1 + 8; | |
| } | |
| pub struct FeeCollected { | |
| pub payer: Pubkey, | |
| pub amount_lamports: u64, | |
| pub fee_reference: [u8; 16], | |
| pub payment_count: u64, | |
| } | |
| pub enum FeeVaultError { | |
| InvalidFeeBasisPoints, | |
| InvalidFeeAmount, | |
| MathOverflow, | |
| Unauthorized, | |
| InsufficientVaultBalance, | |
| } | |
| mod tests { | |
| use super::*; | |
| fn fee_vault_length_stays_stable() { | |
| assert_eq!(FeeVault::LEN, 61); | |
| } | |
| } | |