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