1use {
4 solana_farm_sdk::{
5 error::FarmError,
6 fund::Fund,
7 refdb,
8 refdb::{RefDB, Reference, ReferenceType, StorageType},
9 string::{str_to_as64, ArrayString64},
10 },
11 solana_program::{
12 account_info::AccountInfo, entrypoint::ProgramResult, program_error::ProgramError,
13 pubkey::Pubkey,
14 },
15 std::cell::RefMut,
16};
17
18pub struct UserInfo<'a, 'b> {
19 pub key: &'a Pubkey,
20 pub data: RefMut<'a, &'b mut [u8]>,
21}
22
23impl<'a, 'b> UserInfo<'a, 'b> {
24 pub const LEN: usize = StorageType::get_storage_size_for_records(ReferenceType::U64, 2);
25 pub const VIRTUAL_TOKENS_BALANCE_INDEX: usize = 0;
26 pub const USER_BUMP_INDEX: usize = 1;
27
28 pub fn new(account: &'a AccountInfo<'b>) -> Self {
29 Self {
30 key: account.key,
31 data: account.data.borrow_mut(),
32 }
33 }
34
35 pub fn init(&mut self, refdb_name: &ArrayString64, user_bump: u8) -> ProgramResult {
36 if RefDB::is_initialized(&self.data) {
37 return Ok(());
38 }
39 RefDB::init(&mut self.data, refdb_name, ReferenceType::U64)?;
40
41 self.init_refdb_field(
42 UserInfo::VIRTUAL_TOKENS_BALANCE_INDEX,
43 "VirtualTokensBalance",
44 Reference::U64 { data: 0 },
45 )?;
46 self.init_refdb_field(
47 UserInfo::USER_BUMP_INDEX,
48 "UserBump",
49 Reference::U64 {
50 data: user_bump as u64,
51 },
52 )
53 }
54
55 pub fn set_virtual_tokens_balance(&mut self, virtual_tokens_balance: u64) -> ProgramResult {
56 RefDB::update_at(
57 &mut self.data,
58 UserInfo::VIRTUAL_TOKENS_BALANCE_INDEX,
59 &Reference::U64 {
60 data: virtual_tokens_balance,
61 },
62 )
63 .map(|_| ())
64 }
65
66 pub fn get_virtual_tokens_balance(&self) -> Result<u64, ProgramError> {
67 if let Some(rec) = RefDB::read_at(&self.data, UserInfo::VIRTUAL_TOKENS_BALANCE_INDEX)? {
68 if let Reference::U64 { data } = rec.reference {
69 return Ok(data);
70 }
71 }
72 Err(FarmError::InvalidRefdbRecord.into())
73 }
74
75 pub fn get_user_bump(&self) -> Result<u8, ProgramError> {
76 if let Some(user_bump_rec) = RefDB::read_at(&self.data, UserInfo::USER_BUMP_INDEX)? {
77 if let Reference::U64 { data } = user_bump_rec.reference {
78 return Ok(data as u8);
79 }
80 }
81 Err(ProgramError::UninitializedAccount)
82 }
83
84 pub fn validate_account(
85 fund: &Fund,
86 user_info_account: &'a AccountInfo<'b>,
87 user_account: &Pubkey,
88 ) -> bool {
89 if let Ok(refdb) = user_info_account.try_borrow_data() {
90 if let Ok(Some(user_bump_rec)) = RefDB::read_at(&refdb, UserInfo::USER_BUMP_INDEX) {
91 if let Reference::U64 { data } = user_bump_rec.reference {
92 if let Ok(key) = Pubkey::create_program_address(
93 &[
94 b"user_info_account",
95 user_account.as_ref(),
96 fund.name.as_bytes(),
97 &[data as u8],
98 ],
99 &fund.fund_program_id,
100 ) {
101 if user_info_account.key == &key {
102 return true;
103 }
104 }
105 }
106 }
107 }
108 false
109 }
110
111 fn init_refdb_field(
113 &mut self,
114 index: usize,
115 field_name: &str,
116 reference: Reference,
117 ) -> ProgramResult {
118 RefDB::write(
119 &mut self.data,
120 &refdb::Record {
121 index: Some(index as u32),
122 counter: 0,
123 tag: 0,
124 name: str_to_as64(field_name)?,
125 reference,
126 },
127 )
128 .map(|_| ())
129 }
130}