agsol_common/
signer_pda.rs1use solana_program::account_info::AccountInfo;
2use solana_program::program_error::ProgramError;
3use solana_program::pubkey::Pubkey;
4
5pub type SignerPdaError = &'static str;
6
7#[derive(Debug, Clone, Copy)]
9pub struct SignerPda<'a, 'b> {
10 pub pda: Pubkey,
11 pub bump: [u8; 1],
12 pub seeds: &'b [&'a [u8]],
13}
14
15impl<'a, 'b> SignerPda<'a, 'b> {
16 pub fn new_checked(
18 seeds: &'b [&'a [u8]],
19 program_id: &Pubkey,
20 expected: &AccountInfo,
21 ) -> Result<Self, ProgramError> {
22 let (pda, bump) = Self::find_and_check(seeds, program_id, expected.key)?;
23 Ok(Self {
24 pda,
25 bump: [bump],
26 seeds,
27 })
28 }
29
30 pub fn check_owner(
32 seeds: &'b [&'a [u8]],
33 program_id: &Pubkey,
34 owner: &Pubkey,
35 expected: &AccountInfo,
36 ) -> Result<(), ProgramError> {
37 Self::find_and_check(seeds, program_id, expected.key)?;
38 if expected.owner != owner {
39 Err(ProgramError::IllegalOwner)
40 } else {
41 Ok(())
42 }
43 }
44
45 fn find_and_check(
46 seeds: &'b [&'a [u8]],
47 program_id: &Pubkey,
48 expected: &Pubkey,
49 ) -> Result<(Pubkey, u8), ProgramError> {
50 let (pda, bump) = Pubkey::find_program_address(seeds, program_id);
51 if &pda != expected {
52 Err(ProgramError::InvalidSeeds)
53 } else {
54 Ok((pda, bump))
55 }
56 }
57
58 pub fn signer_seeds(&'a self) -> Vec<&'a [u8]> {
60 let mut signer_seeds = self.seeds.to_vec();
61 signer_seeds.push(&self.bump);
62 signer_seeds
63 }
64}
65
66#[cfg(test)]
67mod test {
68 use super::*;
69
70 #[test]
71 fn test_checks_and_seeds() {
72 let program_id = Pubkey::new_unique();
73 let seed_pubkey = Pubkey::new_unique();
74 let seeds = &[b"this is a seed", seed_pubkey.as_ref()];
75 let (pda, bump) = Pubkey::find_program_address(seeds, &program_id);
76
77 let mut data = [2_u8, 3, 4, 5, 6, 7];
78 let mut lamports = 1500;
79 let mut account_info = AccountInfo::new(
80 &pda,
81 false,
82 false,
83 &mut lamports,
84 data.as_mut_slice(),
85 &program_id,
86 false,
87 0,
88 );
89 let signer_pda = SignerPda::new_checked(seeds, &program_id, &account_info).unwrap();
90 assert_eq!(signer_pda.pda, pda);
91 let mut expected_signer_seeds = seeds.to_vec();
92 let bump_slice = [bump];
93 expected_signer_seeds.push(&bump_slice);
94 assert_eq!(signer_pda.signer_seeds(), expected_signer_seeds);
95
96 assert_eq!(
98 SignerPda::new_checked(seeds, &Pubkey::new_unique(), &account_info)
99 .err()
100 .unwrap(),
101 ProgramError::InvalidSeeds
102 );
103 assert_eq!(
105 SignerPda::new_checked(&[b"bad seed"], &program_id, &account_info)
106 .err()
107 .unwrap(),
108 ProgramError::InvalidSeeds
109 );
110 assert!(SignerPda::check_owner(seeds, &program_id, &program_id, &account_info).is_ok());
112 let new_owner = Pubkey::new_unique();
114 account_info.owner = &new_owner;
115 assert_eq!(
116 SignerPda::check_owner(seeds, &program_id, &program_id, &account_info)
117 .err()
118 .unwrap(),
119 ProgramError::IllegalOwner
120 );
121
122 assert!(SignerPda::check_owner(seeds, &program_id, &new_owner, &account_info).is_ok());
123 }
124}