Skip to main content

light_token_interface/state/token/
borsh.rs

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