1use anchor_lang::prelude::*;
2use anchor_spl::token::TokenAccount;
3use solana_security_txt::security_txt;
4
5declare_id!("Z1PrGTgZp5Q1WKewjF4XaTW2nHvNxvbxs7qW8p9qz5U");
6
7security_txt! {
8 name: "Zipper",
9 project_url: "http://github.com/cavemanloverboy/zipper",
10 contacts: "caveycool@gmail.com",
11 policy: "https://github.com/cavemanloverboy/zipper/blob/main/SECURITY.md"
12}
13
14#[program]
15pub mod zipper {
16 use super::*;
17
18 pub fn verify(ctx: Context<VerifyAccounts>, balances: Vec<u64>) -> Result<()> {
19 require_eq!(
21 ctx.remaining_accounts.len(),
22 balances.len(),
23 ZipperError::InvalidNumberOfAccountsOrBalances
24 );
25
26 let actual_balances: Vec<(u64, String)> = ctx
28 .remaining_accounts
29 .into_iter()
30 .map(|acc| {
31 if let Ok(token_account) = TokenAccount::try_deserialize(&mut &**acc.data.borrow())
32 {
33 return Ok((
35 token_account.amount,
36 format!(
37 "spl addr {}, mint {}",
38 acc.key.to_string(),
39 token_account.mint
40 ),
41 ));
42 } else if acc.owner == &System::id() {
43 Ok((acc.lamports(), format!("sol addr {}", acc.key.to_string())))
45 } else {
46 Err(ZipperError::NonSOLOrSPLAccountProvided.into())
48 }
49 })
50 .collect::<Result<Vec<(u64, String)>>>()
51 .map_err(|_| ZipperError::NonSOLOrSPLAccountProvided)?;
52
53 for i in 0..actual_balances.len() {
55 if actual_balances[i].0 < balances[i] {
56 panic!(
57 "expected {} >= {} for {}",
58 actual_balances[i].0, balances[i], actual_balances[i].1,
59 );
60 } else {
61 msg!(
62 "expected {} >= {} for {}",
63 actual_balances[i].0,
64 balances[i],
65 actual_balances[i].1,
66 )
67 }
68 }
69 Ok(())
70 }
71}
72
73#[derive(Accounts)]
74pub struct VerifyAccounts {}
75
76pub struct AccountZipper;
77
78impl AccountZipper {
79 pub fn zip_accounts(keys: &[Pubkey]) -> Vec<AccountMeta> {
81 keys.into_iter()
82 .map(|&pubkey| AccountMeta {
83 pubkey,
84 is_signer: false,
85 is_writable: false,
86 })
87 .collect()
88 }
89}
90
91#[error_code]
92pub enum ZipperError {
93 #[msg("number of SOL + SPL accounts does not match the number of expected_balances provided")]
94 InvalidNumberOfAccountsOrBalances,
95 #[msg("one of the accounts has a lower-than-expected balance")]
96 InsufficientBalance,
97 #[msg("an account that is not an spl account was provided as an additional account")]
98 NonSOLOrSPLAccountProvided,
99}