Skip to main content

winterwallet_client/
state.rs

1use winterwallet_common::{
2    WALLET_ACCOUNT_LEN, WALLET_BUMP_OFFSET, WALLET_ID_OFFSET, WALLET_ROOT_OFFSET,
3};
4use winterwallet_core::WinternitzRoot;
5
6/// Deserialized WinterWallet account state.
7///
8/// Mirrors the on-chain `WinterWallet` layout: `id(32) + root(32) + bump(1)`.
9#[repr(C)]
10pub struct WinterWalletAccount {
11    /// Wallet ID — the merklized root of the initial Winternitz pubkey.
12    pub id: [u8; 32],
13    /// Current Winternitz root the wallet expects for signature verification.
14    pub root: WinternitzRoot,
15    /// PDA bump seed.
16    pub bump: [u8; 1],
17}
18
19// Compile-time check that our layout matches the shared constant.
20const _: () = assert!(core::mem::size_of::<WinterWalletAccount>() == WALLET_ACCOUNT_LEN);
21
22impl WinterWalletAccount {
23    /// Deserialize from raw account data bytes.
24    ///
25    /// Requires exactly [`WALLET_ACCOUNT_LEN`] (65) bytes.
26    pub fn from_bytes(data: &[u8]) -> Result<Self, crate::Error> {
27        if data.len() != WALLET_ACCOUNT_LEN {
28            return Err(crate::Error::InvalidAccountData);
29        }
30        let id: [u8; 32] = data[WALLET_ID_OFFSET..WALLET_ID_OFFSET + 32]
31            .try_into()
32            .unwrap();
33        let root_bytes: [u8; 32] = data[WALLET_ROOT_OFFSET..WALLET_ROOT_OFFSET + 32]
34            .try_into()
35            .unwrap();
36        let bump = data[WALLET_BUMP_OFFSET];
37        Ok(Self {
38            id,
39            root: WinternitzRoot::new(root_bytes),
40            bump: [bump],
41        })
42    }
43}