use crate::domain::entities::error::MemoError;
#[cfg(all(feature = "parity-scale-codec", feature = "scale-info"))]
use parity_scale_codec::{Decode, Encode};
#[cfg(all(feature = "parity-scale-codec", feature = "scale-info"))]
use scale_info::TypeInfo;
#[derive(Clone, Debug, PartialEq, Eq)]
#[cfg_attr(
all(feature = "parity-scale-codec", feature = "scale-info"),
derive(Encode, Decode, TypeInfo)
)]
pub struct DisclosureMask {
pub disclose_value: bool,
pub disclose_owner: bool,
pub disclose_blinding: bool,
pub disclose_asset_id: bool,
}
impl DisclosureMask {
pub fn all() -> Self {
Self {
disclose_value: true,
disclose_owner: true,
disclose_blinding: false, disclose_asset_id: true,
}
}
pub fn only_value() -> Self {
Self {
disclose_value: true,
disclose_owner: false,
disclose_blinding: false,
disclose_asset_id: false,
}
}
pub fn value_and_asset() -> Self {
Self {
disclose_value: true,
disclose_owner: false,
disclose_blinding: false,
disclose_asset_id: true,
}
}
pub fn none() -> Self {
Self {
disclose_value: false,
disclose_owner: false,
disclose_blinding: false,
disclose_asset_id: false,
}
}
pub fn to_bitmap(&self) -> u8 {
(self.disclose_value as u8)
| (self.disclose_owner as u8) << 1
| (self.disclose_blinding as u8) << 2
| (self.disclose_asset_id as u8) << 3
}
pub fn from_bitmap(bits: u8) -> Self {
Self {
disclose_value: (bits & 0b0001) != 0,
disclose_owner: (bits & 0b0010) != 0,
disclose_blinding: (bits & 0b0100) != 0,
disclose_asset_id: (bits & 0b1000) != 0,
}
}
pub fn validate(&self) -> Result<(), MemoError> {
if self.disclose_blinding {
return Err(MemoError::InvalidDisclosureMask(
"Cannot disclose blinding factor — compromises commitment privacy",
));
}
if !self.disclose_value && !self.disclose_owner && !self.disclose_asset_id {
return Err(MemoError::InvalidDisclosureMask(
"Must disclose at least one field (value, owner, or asset_id)",
));
}
Ok(())
}
pub fn disclosed_field_count(&self) -> usize {
[
self.disclose_value,
self.disclose_owner,
self.disclose_blinding,
self.disclose_asset_id,
]
.iter()
.filter(|&&v| v)
.count()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_mask_all() {
let mask = DisclosureMask::all();
assert!(mask.disclose_value);
assert!(mask.disclose_owner);
assert!(!mask.disclose_blinding);
assert!(mask.disclose_asset_id);
}
#[test]
fn test_mask_only_value() {
let mask = DisclosureMask::only_value();
assert!(mask.disclose_value);
assert!(!mask.disclose_owner);
assert!(!mask.disclose_blinding);
assert!(!mask.disclose_asset_id);
}
#[test]
fn test_mask_value_and_asset() {
let mask = DisclosureMask::value_and_asset();
assert!(mask.disclose_value);
assert!(!mask.disclose_owner);
assert!(!mask.disclose_blinding);
assert!(mask.disclose_asset_id);
}
#[test]
fn test_mask_none() {
let mask = DisclosureMask::none();
assert!(!mask.disclose_value);
assert!(!mask.disclose_owner);
assert!(!mask.disclose_blinding);
assert!(!mask.disclose_asset_id);
}
#[test]
fn test_mask_to_bitmap() {
assert_eq!(DisclosureMask::only_value().to_bitmap(), 0b0001);
assert_eq!(DisclosureMask::value_and_asset().to_bitmap(), 0b1001);
assert_eq!(DisclosureMask::all().to_bitmap(), 0b1011);
assert_eq!(DisclosureMask::none().to_bitmap(), 0b0000);
}
#[test]
fn test_mask_bitmap_roundtrip() {
for i in 0..16u8 {
let mask = DisclosureMask::from_bitmap(i);
assert_eq!(mask.to_bitmap(), i);
}
}
#[test]
fn test_mask_validate_ok() {
assert!(DisclosureMask::only_value().validate().is_ok());
assert!(DisclosureMask::all().validate().is_ok());
assert!(DisclosureMask::value_and_asset().validate().is_ok());
}
#[test]
fn test_mask_validate_blinding_error() {
let mask = DisclosureMask {
disclose_blinding: true,
..DisclosureMask::only_value()
};
assert!(mask.validate().is_err());
}
#[test]
fn test_mask_validate_empty_error() {
assert!(DisclosureMask::none().validate().is_err());
}
#[test]
fn test_mask_disclosed_field_count() {
assert_eq!(DisclosureMask::none().disclosed_field_count(), 0);
assert_eq!(DisclosureMask::only_value().disclosed_field_count(), 1);
assert_eq!(DisclosureMask::value_and_asset().disclosed_field_count(), 2);
assert_eq!(DisclosureMask::all().disclosed_field_count(), 3);
}
#[test]
fn test_mask_clone() {
let m1 = DisclosureMask::value_and_asset();
let m2 = m1.clone();
assert_eq!(m1, m2);
}
#[test]
fn test_mask_from_bitmap_specific_values() {
let owner_only = DisclosureMask::from_bitmap(0b0010);
assert!(!owner_only.disclose_value);
assert!(owner_only.disclose_owner);
assert!(!owner_only.disclose_blinding);
assert!(!owner_only.disclose_asset_id);
}
#[test]
fn test_mask_validate_only_owner() {
let mask = DisclosureMask::from_bitmap(0b0010); assert!(mask.validate().is_ok());
}
}