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
use candid::CandidType;
use ex3_serde::bincode;
use ic_stable_structures::{storable::Bound, Storable};
use serde::{Deserialize, Serialize};

use crate::chain::ChainType;
use crate::{BlockHeight, CandidBlockHeight, CandidWalletRegisterId, PublicKey, WalletRegisterId};

#[derive(
    CandidType, Clone, Hash, Deserialize, Serialize, Debug, Eq, PartialEq, PartialOrd, Ord,
)]
pub struct WalletIdentifier {
    pub pub_key: PublicKey,
    pub chain_type: ChainType,
}

impl WalletIdentifier {
    pub fn new(pub_key: PublicKey, chain_type: ChainType) -> Self {
        Self {
            pub_key,
            chain_type,
        }
    }
}

impl Storable for WalletIdentifier {
    fn to_bytes(&self) -> std::borrow::Cow<[u8]> {
        bincode::serialize(&self).unwrap().into()
    }

    fn from_bytes(bytes: std::borrow::Cow<[u8]>) -> Self {
        bincode::deserialize(bytes.as_ref()).unwrap()
    }
    const BOUND: Bound = Bound::Bounded {
        max_size: 64,
        is_fixed_size: false,
    };
}

#[derive(Clone, Hash, Deserialize, Serialize, Debug, Eq, PartialEq, PartialOrd, Ord)]
pub struct RegisteredWalletIdentifier {
    pub wallet_id: WalletRegisterId,
    pub wallet_identifier: WalletIdentifier,
    pub registered_height: BlockHeight,
}

impl Storable for RegisteredWalletIdentifier {
    fn to_bytes(&self) -> std::borrow::Cow<[u8]> {
        bincode::serialize(self).unwrap().into()
    }

    fn from_bytes(bytes: std::borrow::Cow<[u8]>) -> Self {
        bincode::deserialize(bytes.as_ref()).unwrap()
    }

    const BOUND: Bound = Bound::Bounded {
        max_size: 224,
        is_fixed_size: false,
    };
}

#[derive(CandidType, Clone, Hash, Deserialize, Debug, Eq, PartialEq, PartialOrd, Ord)]
pub struct CandidRegisteredWalletIdentifier {
    pub wallet_id: CandidWalletRegisterId,
    pub wallet_identifier: WalletIdentifier,
    pub registered_height: CandidBlockHeight,
}

impl From<RegisteredWalletIdentifier> for CandidRegisteredWalletIdentifier {
    fn from(registered_wallet_identifier: RegisteredWalletIdentifier) -> Self {
        Self {
            wallet_id: registered_wallet_identifier.wallet_id.into(),
            wallet_identifier: registered_wallet_identifier.wallet_identifier,
            registered_height: registered_wallet_identifier.registered_height.into(),
        }
    }
}

impl From<CandidRegisteredWalletIdentifier> for RegisteredWalletIdentifier {
    fn from(candid_registered_wallet_identifier: CandidRegisteredWalletIdentifier) -> Self {
        Self {
            wallet_id: candid_registered_wallet_identifier.wallet_id.into(),
            wallet_identifier: candid_registered_wallet_identifier.wallet_identifier,
            registered_height: candid_registered_wallet_identifier.registered_height.into(),
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use ic_stable_structures::storable::Storable;

    #[test]
    fn test_storable_for_wallet_identifier() {
        let wallet_identifier =
            WalletIdentifier::new(PublicKey::from([0u8; 32]), ChainType::Bitcoin);
        let bytes = wallet_identifier.to_bytes();
        assert!(bytes.len() <= 64);
        let wallet_identifier2 = WalletIdentifier::from_bytes(bytes);
        assert_eq!(wallet_identifier, wallet_identifier2);
    }

    #[test]
    fn test_storable_for_registered_wallet_identifier() {
        let registered_wallet_identifier = RegisteredWalletIdentifier {
            wallet_id: WalletRegisterId::from(u128::MAX),
            wallet_identifier: WalletIdentifier::new(
                PublicKey::from([0u8; 32]),
                ChainType::Bitcoin,
            ),
            registered_height: BlockHeight::from(0u32),
        };
        let bytes = registered_wallet_identifier.to_bytes();
        assert!(bytes.len() <= 224);
        let registered_wallet_identifier2 = RegisteredWalletIdentifier::from_bytes(bytes);
        assert_eq!(registered_wallet_identifier, registered_wallet_identifier2);
    }
}