use std::fmt::Display;
use candid::CandidType;
use ex3_serde::bincode;
use ex3_timestamp::TimeInNs;
use ic_stable_structures::{storable::Bound, Storable};
use serde::{Deserialize, Serialize};
use crate::{
AssetAmount, AssetId, BlockHeight, CandidAssetAmount, CandidAssetId, CandidBlockHeight,
CandidDepositId, CandidWalletRegisterId, DepositId, WalletRegisterId,
};
#[derive(Debug, Clone, PartialEq, Eq, Hash, Deserialize, Serialize, PartialOrd, Ord)]
pub struct DepositIdentifier {
pub asset_id: AssetId,
pub block_height: BlockHeight,
pub tx_id: Option<String>,
}
impl Display for DepositIdentifier {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(
f,
"{}:{}:{}",
self.asset_id,
self.block_height,
self.tx_id.clone().unwrap_or("".to_string())
)
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash, Deserialize, CandidType, Ord, PartialOrd)]
pub struct CandidDepositIdentifier {
pub asset_id: CandidAssetId,
pub block_height: CandidBlockHeight,
pub tx_id: Option<String>,
}
impl From<DepositIdentifier> for CandidDepositIdentifier {
fn from(deposit_identifier: DepositIdentifier) -> Self {
Self {
asset_id: deposit_identifier.asset_id.into(),
block_height: deposit_identifier.block_height.into(),
tx_id: deposit_identifier.tx_id,
}
}
}
impl From<CandidDepositIdentifier> for DepositIdentifier {
fn from(deposit_identifier: CandidDepositIdentifier) -> Self {
Self {
asset_id: deposit_identifier.asset_id.into(),
block_height: deposit_identifier.block_height.into(),
tx_id: deposit_identifier.tx_id,
}
}
}
#[derive(Debug, Clone, Eq, PartialEq, Deserialize, Serialize)]
pub struct OriginalDeposit {
pub identifier: DepositIdentifier,
pub amount: AssetAmount,
}
#[derive(Serialize, Deserialize, Debug, Clone, Eq, PartialEq, Hash, Ord, PartialOrd)]
pub struct Deposit {
pub identifier: DepositIdentifier,
pub from_wallet: WalletRegisterId,
pub amount: AssetAmount,
}
#[derive(Deserialize, CandidType, Debug, Clone, Eq, PartialEq, Hash, Ord, PartialOrd)]
pub struct CandidDeposit {
pub identifier: CandidDepositIdentifier,
pub from_wallet: CandidWalletRegisterId,
pub amount: CandidAssetAmount,
}
#[derive(Serialize, Deserialize, Debug, Clone, Eq, PartialEq, Hash, Ord, PartialOrd)]
pub struct ConfirmedDeposit {
pub seq_id: DepositId,
pub deposit: Deposit,
pub confirmed_at: TimeInNs,
}
#[derive(Deserialize, CandidType, Debug, Clone, Eq, PartialEq, Hash, Ord, PartialOrd)]
pub struct CandidConfirmedDeposit {
pub seq_id: CandidDepositId,
pub deposit: CandidDeposit,
pub confirmed_at: TimeInNs,
}
impl Storable for DepositIdentifier {
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: 200,
is_fixed_size: false,
};
}
impl Storable for Deposit {
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: 264,
is_fixed_size: false,
};
}
impl Storable for ConfirmedDeposit {
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: 304,
is_fixed_size: false,
};
}
impl From<Deposit> for CandidDeposit {
fn from(deposit: Deposit) -> Self {
Self {
identifier: deposit.identifier.into(),
from_wallet: deposit.from_wallet.into(),
amount: deposit.amount.into(),
}
}
}
impl From<CandidDeposit> for Deposit {
fn from(deposit: CandidDeposit) -> Self {
Self {
identifier: deposit.identifier.into(),
from_wallet: deposit.from_wallet.into(),
amount: deposit.amount.into(),
}
}
}
impl From<ConfirmedDeposit> for CandidConfirmedDeposit {
fn from(deposit: ConfirmedDeposit) -> Self {
Self {
seq_id: deposit.seq_id.into(),
deposit: deposit.deposit.into(),
confirmed_at: deposit.confirmed_at,
}
}
}
impl From<CandidConfirmedDeposit> for ConfirmedDeposit {
fn from(deposit: CandidConfirmedDeposit) -> Self {
Self {
seq_id: deposit.seq_id.into(),
deposit: deposit.deposit.into(),
confirmed_at: deposit.confirmed_at,
}
}
}
#[cfg(test)]
mod tests {
use ex3_serde::bincode;
use super::*;
#[test]
fn test_serde() {
let deposit_identifier = DepositIdentifier {
asset_id: 1u64.into(),
block_height: 2u64.into(),
tx_id: Some("tx_id".to_string()),
};
let deposit = OriginalDeposit {
identifier: deposit_identifier.clone(),
amount: 3u64.into(),
};
let encoded = bincode::serialize(&deposit).unwrap();
let decoded: OriginalDeposit = bincode::deserialize(&encoded).unwrap();
assert_eq!(deposit, decoded);
let encoded = ex3_serde::cbor::serialize(&deposit).unwrap();
let decoded: OriginalDeposit = ex3_serde::cbor::deserialize(&encoded).unwrap();
assert_eq!(deposit, decoded);
}
#[test]
fn test_storable_for_deposit_identifier() {
let tx_id: String = std::iter::repeat('1').take(128).collect();
let deposit_identifier = DepositIdentifier {
asset_id: u128::MAX.into(),
block_height: u128::MAX.into(),
tx_id: Some(tx_id),
};
let bytes = deposit_identifier.to_bytes();
assert!(bytes.len() <= 200, "bytes.len() = {}", bytes.len());
let deposit_identifier2 = DepositIdentifier::from_bytes(bytes);
assert_eq!(deposit_identifier, deposit_identifier2);
}
#[test]
fn test_storable_for_deposit() {
let tx_id: String = std::iter::repeat('1').take(128).collect();
let deposit = Deposit {
identifier: DepositIdentifier {
asset_id: u128::MAX.into(),
block_height: u128::MAX.into(),
tx_id: Some(tx_id),
},
from_wallet: u128::MAX.into(),
amount: u128::MAX.into(),
};
let bytes = deposit.to_bytes();
assert!(bytes.len() <= 264, "bytes.len() = {}", bytes.len());
let deposit2 = Deposit::from_bytes(bytes);
assert_eq!(deposit, deposit2);
}
}