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
use ex3_serde::{bincode, cbor};
use serde::{Deserialize, Serialize};

use ex3_error::OtherError;

use crate::{AssetAmount, AssetId, BlockHeight, WalletRegisterId};

#[derive(Deserialize, Serialize, Debug, Clone, PartialEq, Eq, Hash)]
pub struct DepositIdentifier {
    pub asset_id: AssetId,
    /// The block height
    /// Any chain does not have a block height? we use the timestamp instead? (TBD)
    pub block_height: BlockHeight,
    /// The block chain transaction id
    /// For UTXO, it is the transaction id + tx index
    pub tx_id: Option<String>,
}

impl DepositIdentifier {
    pub fn encode(&self) -> Vec<u8> {
        bincode::serialize(&(&self.asset_id, &self.block_height, &self.tx_id)).unwrap()
    }
    pub fn decode(bytes: &[u8]) -> Result<Self, OtherError> {
        let (asset_id, block_height, tx_id) = bincode::deserialize(bytes)
            .map_err(|e| OtherError::new(format!("deserialize error: {}", e)))?;
        Ok(DepositIdentifier {
            asset_id,
            block_height,
            tx_id,
        })
    }
}

/// Deposit
#[derive(Deserialize, Serialize, Debug, Clone, Eq, PartialEq)]
pub struct Deposit {
    pub identifier: DepositIdentifier,
    pub amount: AssetAmount,
}

impl Deposit {
    pub fn encode(&self) -> Vec<u8> {
        bincode::serialize(&(&self.identifier, &self.amount)).unwrap()
    }
    pub fn decode(bytes: &[u8]) -> Result<Self, OtherError> {
        let (identifier, amount) = bincode::deserialize(bytes)
            .map_err(|e| OtherError::new(format!("deserialize error: {}", e)))?;
        Ok(Deposit { identifier, amount })
    }

    pub fn cbor_encode(&self) -> Vec<u8> {
        cbor::serialize(&(&self.identifier, &self.amount)).unwrap()
    }

    pub fn cbor_decode(bytes: &[u8]) -> Result<Self, OtherError> {
        let (identifier, amount) = cbor::deserialize(bytes)
            .map_err(|e| OtherError::new(format!("deserialize error: {}", e)))?;
        Ok(Deposit { identifier, amount })
    }
}

impl TryFrom<&[u8]> for Deposit {
    type Error = OtherError;

    fn try_from(value: &[u8]) -> Result<Self, Self::Error> {
        match Deposit::cbor_decode(value) {
            Ok(deposit) => Ok(deposit),
            Err(_) => match Deposit::decode(value) {
                Ok(deposit) => Ok(deposit),
                Err(e) => Err(e),
            },
        }
    }
}