light_token_interface/state/token/
borsh.rs

1use borsh::{BorshDeserialize, BorshSerialize};
2use light_compressed_account::Pubkey;
3
4use crate::state::{AccountState, ExtensionStruct, Token, ACCOUNT_TYPE_TOKEN_ACCOUNT};
5
6// Manual implementation of BorshSerialize for SPL compatibility
7impl BorshSerialize for Token {
8    fn serialize<W: std::io::Write>(&self, writer: &mut W) -> std::io::Result<()> {
9        // Write mint (32 bytes)
10        writer.write_all(&self.mint.to_bytes())?;
11
12        // Write owner (32 bytes)
13        writer.write_all(&self.owner.to_bytes())?;
14
15        // Write amount (8 bytes)
16        writer.write_all(&self.amount.to_le_bytes())?;
17
18        // Write delegate as COption (4 bytes + 32 bytes)
19        if let Some(delegate) = self.delegate {
20            writer.write_all(&[1, 0, 0, 0])?; // COption Some discriminator
21            writer.write_all(&delegate.to_bytes())?;
22        } else {
23            writer.write_all(&[0; 36])?; // COption None (4 bytes) + empty pubkey (32 bytes)
24        }
25
26        // Write state (1 byte)
27        writer.write_all(&[self.state as u8])?;
28
29        // Write is_native as COption (4 bytes + 8 bytes)
30        if let Some(is_native) = self.is_native {
31            writer.write_all(&[1, 0, 0, 0])?; // COption Some discriminator
32            writer.write_all(&is_native.to_le_bytes())?;
33        } else {
34            writer.write_all(&[0; 12])?; // COption None (4 bytes) + empty u64 (8 bytes)
35        }
36
37        // Write delegated_amount (8 bytes)
38        writer.write_all(&self.delegated_amount.to_le_bytes())?;
39
40        // Write close_authority as COption (4 bytes + 32 bytes)
41        if let Some(close_authority) = self.close_authority {
42            writer.write_all(&[1, 0, 0, 0])?; // COption Some discriminator
43            writer.write_all(&close_authority.to_bytes())?;
44        } else {
45            writer.write_all(&[0; 36])?; // COption None (4 bytes) + empty pubkey (32 bytes)
46        }
47
48        // End of SPL Token Account base layout (165 bytes)
49
50        // Write account_type and extensions only if extensions are present
51        if self.extensions.is_some() {
52            // Write account_type byte at position 165
53            writer.write_all(&[self.account_type])?;
54
55            // Write extensions as Option<Vec<ExtensionStruct>>
56            self.extensions.serialize(writer)?;
57        }
58
59        Ok(())
60    }
61}
62
63// Manual implementation of BorshDeserialize for SPL compatibility
64impl BorshDeserialize for Token {
65    fn deserialize_reader<R: std::io::Read>(buf: &mut R) -> std::io::Result<Self> {
66        // Read mint (32 bytes)
67        let mut mint_bytes = [0u8; 32];
68        buf.read_exact(&mut mint_bytes)?;
69        let mint = Pubkey::from(mint_bytes);
70
71        // Read owner (32 bytes)
72        let mut owner_bytes = [0u8; 32];
73        buf.read_exact(&mut owner_bytes)?;
74        let owner = Pubkey::from(owner_bytes);
75
76        // Read amount (8 bytes)
77        let mut amount_bytes = [0u8; 8];
78        buf.read_exact(&mut amount_bytes)?;
79        let amount = u64::from_le_bytes(amount_bytes);
80
81        // Read delegate COption (4 bytes + 32 bytes)
82        let mut discriminator = [0u8; 4];
83        buf.read_exact(&mut discriminator)?;
84        let mut pubkey_bytes = [0u8; 32];
85        buf.read_exact(&mut pubkey_bytes)?;
86        let delegate = if u32::from_le_bytes(discriminator) == 1 {
87            Some(Pubkey::from(pubkey_bytes))
88        } else {
89            None
90        };
91
92        // Read state (1 byte)
93        let mut state = [0u8; 1];
94        buf.read_exact(&mut state)?;
95        let state = state[0];
96
97        // Read is_native COption (4 bytes + 8 bytes)
98        let mut discriminator = [0u8; 4];
99        buf.read_exact(&mut discriminator)?;
100        let mut value_bytes = [0u8; 8];
101        buf.read_exact(&mut value_bytes)?;
102        let is_native = if u32::from_le_bytes(discriminator) == 1 {
103            Some(u64::from_le_bytes(value_bytes))
104        } else {
105            None
106        };
107
108        // Read delegated_amount (8 bytes)
109        let mut delegated_amount_bytes = [0u8; 8];
110        buf.read_exact(&mut delegated_amount_bytes)?;
111        let delegated_amount = u64::from_le_bytes(delegated_amount_bytes);
112
113        // Read close_authority COption (4 bytes + 32 bytes)
114        let mut discriminator = [0u8; 4];
115        buf.read_exact(&mut discriminator)?;
116        let mut pubkey_bytes = [0u8; 32];
117        buf.read_exact(&mut pubkey_bytes)?;
118        let close_authority = if u32::from_le_bytes(discriminator) == 1 {
119            Some(Pubkey::from(pubkey_bytes))
120        } else {
121            None
122        };
123
124        // End of SPL Token Account base layout (165 bytes)
125
126        // Try to read account_type byte at position 165
127        let mut account_type_byte = [0u8; 1];
128        let (account_type, extensions) = if buf.read_exact(&mut account_type_byte).is_ok() {
129            let account_type = account_type_byte[0];
130            if account_type == ACCOUNT_TYPE_TOKEN_ACCOUNT {
131                // Read extensions
132                let extensions =
133                    Option::<Vec<ExtensionStruct>>::deserialize_reader(buf).unwrap_or_default();
134                (account_type, extensions)
135            } else {
136                // Account type byte present but not Token - store it but no extensions
137                (account_type, None)
138            }
139        } else {
140            // No account_type byte - base SPL token account without extensions
141            // Default to ACCOUNT_TYPE_TOKEN_ACCOUNT for Token
142            (ACCOUNT_TYPE_TOKEN_ACCOUNT, None)
143        };
144
145        Ok(Self {
146            mint,
147            owner,
148            amount,
149            delegate,
150            state: AccountState::try_from(state)
151                .map_err(|e| std::io::Error::from_raw_os_error(u32::from(e) as i32))?,
152            is_native,
153            delegated_amount,
154            close_authority,
155            account_type,
156            extensions,
157        })
158    }
159}