use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use thiserror::Error;
#[derive(Debug, Error)]
pub enum LegalError {
#[error("Invalid legal wrapper: {0}")]
InvalidWrapper(String),
#[error("Jurisdiction not supported: {0}")]
UnsupportedJurisdiction(String),
#[error("Signature verification failed: {0}")]
SignatureError(String),
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct LegalEntity {
pub id: String,
pub name: String,
pub jurisdiction: String,
pub registration_number: String,
pub registration_date: DateTime<Utc>,
pub signatories: Vec<String>,
pub bitcoin_addresses: Vec<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct LegalSignature {
pub signer: String,
pub entity_id: String,
pub signature: String,
pub timestamp: DateTime<Utc>,
pub bitcoin_anchor: Option<String>,
pub jurisdiction: String,
}
pub struct LegalWrapper {
entities: HashMap<String, LegalEntity>,
jurisdictions: Vec<String>,
signature_requirements: HashMap<String, SignatureRequirement>,
}
#[derive(Debug, Clone)]
#[allow(dead_code)]
struct SignatureRequirement {
min_signatures: usize,
requires_bitcoin_anchor: bool,
}
impl Default for LegalWrapper {
fn default() -> Self {
Self::new()
}
}
impl LegalWrapper {
pub fn new() -> Self {
let mut wrapper = Self {
entities: HashMap::new(),
jurisdictions: vec![
"US".to_string(),
"EU".to_string(),
"UK".to_string(),
"SG".to_string(),
],
signature_requirements: HashMap::new(),
};
wrapper.signature_requirements.insert(
"US".to_string(),
SignatureRequirement {
min_signatures: 2,
requires_bitcoin_anchor: true,
},
);
wrapper.signature_requirements.insert(
"EU".to_string(),
SignatureRequirement {
min_signatures: 1,
requires_bitcoin_anchor: true,
},
);
wrapper.signature_requirements.insert(
"UK".to_string(),
SignatureRequirement {
min_signatures: 1,
requires_bitcoin_anchor: true,
},
);
wrapper.signature_requirements.insert(
"SG".to_string(),
SignatureRequirement {
min_signatures: 1,
requires_bitcoin_anchor: true,
},
);
wrapper
}
pub fn register_entity(&mut self, entity: LegalEntity) -> Result<(), LegalError> {
if !self.jurisdictions.contains(&entity.jurisdiction) {
return Err(LegalError::UnsupportedJurisdiction(format!(
"Jurisdiction not supported: {}",
entity.jurisdiction
)));
}
if entity.bitcoin_addresses.is_empty() {
return Err(LegalError::InvalidWrapper(
"Bitcoin addresses required for BPC-3 compliance".to_string(),
));
}
self.entities.insert(entity.id.clone(), entity);
Ok(())
}
pub fn verify_signature(&self, signature: &LegalSignature) -> Result<bool, LegalError> {
if !self.jurisdictions.contains(&signature.jurisdiction) {
return Err(LegalError::UnsupportedJurisdiction(format!(
"Jurisdiction not supported: {}",
signature.jurisdiction
)));
}
let entity = self.entities.get(&signature.entity_id).ok_or_else(|| {
LegalError::InvalidWrapper(format!("Entity not found: {}", signature.entity_id))
})?;
if !entity.signatories.contains(&signature.signer) {
return Err(LegalError::SignatureError(format!(
"Signer {} not authorized for entity {}",
signature.signer, entity.name
)));
}
let requirements = self
.signature_requirements
.get(&signature.jurisdiction)
.ok_or_else(|| {
LegalError::UnsupportedJurisdiction(format!(
"No requirements for jurisdiction: {}",
signature.jurisdiction
))
})?;
if requirements.requires_bitcoin_anchor && signature.bitcoin_anchor.is_none() {
return Err(LegalError::SignatureError(
"Bitcoin anchoring required for BPC-3 compliance".to_string(),
));
}
Ok(true)
}
}