use serde::{Deserialize, Serialize};
use crate::{Address, BlockHeight, Timestamp};
use crate::agreement::{AttachmentRef, PartyRef};
pub type AssetId = [u8; 32];
pub type TitleEventId = [u8; 32];
pub type EncumbranceId = [u8; 32];
pub type CoverageId = [u8; 32];
pub type ClaimId = [u8; 32];
pub type PolicyId = [u8; 32];
pub type ProofId = [u8; 32];
pub type SubjectId = [u8; 32];
pub const ASSET_DOMAIN_SEP: &[u8] = b"SRC861-ASSET:";
pub const ASSET_COMMITMENT_SEP: &[u8] = b"SRC861-COMMITMENT:v1:";
pub const TITLE_DOMAIN_SEP: &[u8] = b"SRC862-TITLE:";
pub const TITLE_COMMITMENT_SEP: &[u8] = b"SRC862-COMMITMENT:v1:";
pub const ENCUMBRANCE_DOMAIN_SEP: &[u8] = b"SRC863-ENCUMBRANCE:";
pub const ENCUMBRANCE_COMMITMENT_SEP: &[u8] = b"SRC863-COMMITMENT:v1:";
pub const COVERAGE_DOMAIN_SEP: &[u8] = b"SRC864-COVERAGE:";
pub const COVERAGE_COMMITMENT_SEP: &[u8] = b"SRC864-COMMITMENT:v1:";
pub const CLAIM_DOMAIN_SEP: &[u8] = b"SRC865-CLAIM:";
pub const CLAIM_COMMITMENT_SEP: &[u8] = b"SRC865-COMMITMENT:v1:";
pub const PROPERTY_PROOF_DOMAIN_SEP: &[u8] = b"SRC866-PROOF:";
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[repr(u8)]
pub enum AssetType {
SingleFamilyResidence = 0,
MultiFamilyResidence = 1,
Condominium = 2,
Townhouse = 3,
Commercial = 4,
Industrial = 5,
VacantLand = 6,
Agricultural = 7,
MixedUse = 8,
ManufacturedHome = 9,
Automobile = 20,
Motorcycle = 21,
Watercraft = 22,
Aircraft = 23,
RecreationalVehicle = 24,
CommercialVehicle = 25,
HeavyEquipment = 26,
FineArt = 40,
Jewelry = 41,
Collectibles = 42,
Antiques = 43,
MusicalInstruments = 44,
Electronics = 45,
Furniture = 46,
Inventory = 60,
Equipment = 61,
Fixtures = 62,
IpBundle = 63,
Goodwill = 64,
Other = 255,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[repr(u8)]
pub enum AssetStatus {
Active = 0,
PendingTransfer = 1,
Encumbered = 2,
Seized = 3,
Destroyed = 4,
Merged = 5,
Subdivided = 6,
Deregistered = 7,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[repr(u8)]
pub enum PropertyIssuerClass {
LandRegistry = 0,
MotorVehicleDept = 1,
TaxAssessor = 2,
GovernmentAgency = 3,
AviationAuthority = 4,
MaritimeAuthority = 5,
TitleCompany = 10,
EscrowCompany = 11,
RealEstateAttorney = 12,
Appraiser = 13,
Surveyor = 14,
InsuranceCompany = 15,
MortgageLender = 16,
PropertyManager = 17,
Notary = 18,
Other = 255,
}
impl PropertyIssuerClass {
pub fn is_official(&self) -> bool {
matches!(
self,
Self::LandRegistry
| Self::MotorVehicleDept
| Self::TaxAssessor
| Self::GovernmentAgency
| Self::AviationAuthority
| Self::MaritimeAuthority
)
}
pub fn is_lowkey(&self) -> bool {
matches!(
self,
Self::TitleCompany
| Self::EscrowCompany
| Self::RealEstateAttorney
| Self::Appraiser
| Self::Surveyor
| Self::InsuranceCompany
| Self::MortgageLender
)
}
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct AssetAnchor {
pub asset_id: AssetId,
pub asset_commitment: [u8; 32],
pub asset_type: AssetType,
pub jurisdiction_code: String,
pub public_reference: Option<String>,
pub policy_id: PolicyId,
pub issuer_class: PropertyIssuerClass,
pub issuer_address: Address,
pub status: AssetStatus,
pub created_at: Timestamp,
pub updated_at: Timestamp,
pub anchored_at_height: BlockHeight,
pub related_assets: Vec<AssetId>,
pub attachments: Vec<AttachmentRef>,
}
impl AssetAnchor {
pub fn generate_id(
issuer: &Address,
asset_commitment: &[u8; 32],
asset_type: AssetType,
jurisdiction: &str,
nonce: &[u8; 32],
) -> AssetId {
let mut hasher = blake3::Hasher::new();
hasher.update(ASSET_DOMAIN_SEP);
hasher.update(b":v1:");
hasher.update(issuer.as_ref());
hasher.update(asset_commitment);
hasher.update(&[asset_type as u8]);
hasher.update(jurisdiction.as_bytes());
hasher.update(nonce);
*hasher.finalize().as_bytes()
}
pub fn generate_commitment(
asset_details: &[u8],
location_commitment: Option<&[u8; 32]>,
identifier_commitment: Option<&[u8; 32]>,
) -> [u8; 32] {
let mut hasher = blake3::Hasher::new();
hasher.update(ASSET_COMMITMENT_SEP);
hasher.update(asset_details);
if let Some(loc) = location_commitment {
hasher.update(loc);
}
if let Some(id) = identifier_commitment {
hasher.update(id);
}
*hasher.finalize().as_bytes()
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[repr(u8)]
pub enum TitleEventType {
InitialRegistration = 0,
TitleSearch = 1,
TitleExamination = 2,
TitleCommitment = 3,
DeedRecorded = 10,
GrantDeed = 11,
WarrantyDeed = 12,
QuitclaimDeed = 13,
TrustDeed = 14,
DeedOfGift = 15,
ExecutorsDeed = 16,
TaxDeed = 17,
SheriffsDeed = 18,
OwnershipTransfer = 20,
JointTenancyCreated = 21,
TenancyInCommon = 22,
TrustAssignment = 23,
Inheritance = 24,
DivorceTransfer = 25,
TitleCorrection = 30,
NameChange = 31,
LegalDescriptionUpdate = 32,
EasementRecorded = 33,
CovenantRecorded = 34,
TitleCleared = 40,
ForeclosureCompleted = 41,
TaxSaleCompleted = 42,
Condemnation = 43,
Other = 255,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[repr(u8)]
pub enum TitleEventStatus {
Recorded = 0,
Pending = 1,
Superseded = 2,
Voided = 3,
Corrected = 4,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct TitleEvent {
pub event_id: TitleEventId,
pub asset_id: AssetId,
pub event_type: TitleEventType,
pub event_commitment: [u8; 32],
pub grantor_ref: Option<PartyRef>,
pub grantee_ref: Option<PartyRef>,
pub issuer_address: Address,
pub issuer_class: PropertyIssuerClass,
pub effective_date: Timestamp,
pub recording_ref: Option<String>,
pub policy_id: PolicyId,
pub revocation_ref: Option<[u8; 32]>,
pub status: TitleEventStatus,
pub created_at: Timestamp,
pub recorded_at_height: BlockHeight,
pub supersedes: Option<TitleEventId>,
pub attachments: Vec<AttachmentRef>,
}
impl TitleEvent {
pub fn generate_id(
asset_id: &AssetId,
event_type: TitleEventType,
issuer: &Address,
nonce: &[u8; 32],
) -> TitleEventId {
let mut hasher = blake3::Hasher::new();
hasher.update(TITLE_DOMAIN_SEP);
hasher.update(b":v1:");
hasher.update(asset_id);
hasher.update(&[event_type as u8]);
hasher.update(issuer.as_ref());
hasher.update(nonce);
*hasher.finalize().as_bytes()
}
pub fn generate_commitment(
deed_hash: &[u8; 32],
parties_commitment: &[u8; 32],
consideration_commitment: Option<&[u8; 32]>,
) -> [u8; 32] {
let mut hasher = blake3::Hasher::new();
hasher.update(TITLE_COMMITMENT_SEP);
hasher.update(deed_hash);
hasher.update(parties_commitment);
if let Some(cc) = consideration_commitment {
hasher.update(cc);
}
*hasher.finalize().as_bytes()
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[repr(u8)]
pub enum EncumbranceType {
FirstMortgage = 0,
SecondMortgage = 1,
Heloc = 2,
ReverseMortgage = 3,
ConstructionLoan = 4,
CommercialMortgage = 5,
MechanicsLien = 10,
TaxLien = 11,
JudgmentLien = 12,
HoaLien = 13,
ChildSupportLien = 14,
IrsLien = 15,
MunicipalLien = 16,
UccLien = 17,
VoluntaryLien = 18,
AttachmentLien = 19,
ResidentialLease = 30,
CommercialLease = 31,
GroundLease = 32,
Sublease = 33,
Easement = 40,
RightOfWay = 41,
RestrictiveCovenant = 42,
ConservationEasement = 43,
UtilityEasement = 44,
LisPendens = 50,
NoticeOfDefault = 51,
NoticeOfTrusteeSale = 52,
Other = 255,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[repr(u8)]
pub enum EncumbranceStatus {
Active = 0,
Pending = 1,
Subordinated = 2,
Released = 3,
Foreclosed = 4,
Expired = 5,
Disputed = 6,
Voided = 7,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[repr(u8)]
pub enum PriorityPosition {
First = 1,
Second = 2,
Third = 3,
Fourth = 4,
Fifth = 5,
Subordinate = 10,
Unspecified = 255,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct Encumbrance {
pub encumbrance_id: EncumbranceId,
pub asset_id: AssetId,
pub encumbrance_type: EncumbranceType,
pub encumbrance_commitment: [u8; 32],
pub holder_ref: PartyRef,
pub obligor_ref: Option<PartyRef>,
pub priority: PriorityPosition,
pub amount_commitment: Option<[u8; 32]>,
pub effective_from: Timestamp,
pub expiry: Option<Timestamp>,
pub issuer_address: Address,
pub issuer_class: PropertyIssuerClass,
pub policy_id: PolicyId,
pub revocation_ref: Option<[u8; 32]>,
pub status: EncumbranceStatus,
pub created_at: Timestamp,
pub updated_at: Timestamp,
pub recorded_at_height: BlockHeight,
pub agreement_id: Option<[u8; 32]>,
pub attachments: Vec<AttachmentRef>,
}
impl Encumbrance {
pub fn generate_id(
asset_id: &AssetId,
encumbrance_type: EncumbranceType,
holder_ref: &PartyRef,
nonce: &[u8; 32],
) -> EncumbranceId {
let mut hasher = blake3::Hasher::new();
hasher.update(ENCUMBRANCE_DOMAIN_SEP);
hasher.update(b":v1:");
hasher.update(asset_id);
hasher.update(&[encumbrance_type as u8]);
hasher.update(&holder_ref.as_hash());
hasher.update(nonce);
*hasher.finalize().as_bytes()
}
pub fn generate_commitment(
terms_hash: &[u8; 32],
amount_commitment: Option<&[u8; 32]>,
parties_commitment: &[u8; 32],
) -> [u8; 32] {
let mut hasher = blake3::Hasher::new();
hasher.update(ENCUMBRANCE_COMMITMENT_SEP);
hasher.update(terms_hash);
if let Some(ac) = amount_commitment {
hasher.update(ac);
}
hasher.update(parties_commitment);
*hasher.finalize().as_bytes()
}
pub fn is_active(&self, current_time: Timestamp) -> bool {
if !matches!(self.status, EncumbranceStatus::Active | EncumbranceStatus::Subordinated) {
return false;
}
if current_time < self.effective_from {
return false;
}
if let Some(exp) = self.expiry {
if current_time >= exp {
return false;
}
}
true
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[repr(u8)]
pub enum CoverageType {
Homeowners = 0,
Renters = 1,
Landlord = 2,
CommercialProperty = 3,
Flood = 4,
Earthquake = 5,
Fire = 6,
Windstorm = 7,
AutoLiability = 20,
AutoCollision = 21,
AutoComprehensive = 22,
UninsuredMotorist = 23,
PersonalInjuryProtection = 24,
GapInsurance = 25,
Watercraft = 26,
Aircraft = 27,
OwnersTitlePolicy = 40,
LendersTitlePolicy = 41,
ExtendedCoverage = 42,
GeneralLiability = 50,
ProfessionalLiability = 51,
UmbrellaPolicy = 52,
ProductLiability = 53,
BuildersRisk = 60,
InlandMarine = 61,
ValuableArticles = 62,
EquipmentBreakdown = 63,
Other = 255,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[repr(u8)]
pub enum CoverageStatus {
Active = 0,
Pending = 1,
Suspended = 2,
Cancelled = 3,
Expired = 4,
Lapsed = 5,
Renewed = 6,
NonRenewed = 7,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct InsuranceCoverage {
pub coverage_id: CoverageId,
pub asset_id: AssetId,
pub coverage_type: CoverageType,
pub coverage_commitment: [u8; 32],
pub insurer_ref: PartyRef,
pub insured_ref: PartyRef,
pub additional_insureds: Vec<PartyRef>,
pub limit_commitment: [u8; 32],
pub deductible_commitment: Option<[u8; 32]>,
pub premium_commitment: Option<[u8; 32]>,
pub effective_from: Timestamp,
pub expiry: Timestamp,
pub issuer_address: Address,
pub issuer_class: PropertyIssuerClass,
pub policy_id: PolicyId,
pub revocation_ref: Option<[u8; 32]>,
pub status: CoverageStatus,
pub created_at: Timestamp,
pub updated_at: Timestamp,
pub recorded_at_height: BlockHeight,
pub prior_coverage_id: Option<CoverageId>,
pub attachments: Vec<AttachmentRef>,
}
impl InsuranceCoverage {
pub fn generate_id(
asset_id: &AssetId,
coverage_type: CoverageType,
insurer_ref: &PartyRef,
insured_ref: &PartyRef,
nonce: &[u8; 32],
) -> CoverageId {
let mut hasher = blake3::Hasher::new();
hasher.update(COVERAGE_DOMAIN_SEP);
hasher.update(b":v1:");
hasher.update(asset_id);
hasher.update(&[coverage_type as u8]);
hasher.update(&insurer_ref.as_hash());
hasher.update(&insured_ref.as_hash());
hasher.update(nonce);
*hasher.finalize().as_bytes()
}
pub fn generate_commitment(
policy_terms_hash: &[u8; 32],
limit_commitment: &[u8; 32],
exclusions_hash: Option<&[u8; 32]>,
) -> [u8; 32] {
let mut hasher = blake3::Hasher::new();
hasher.update(COVERAGE_COMMITMENT_SEP);
hasher.update(policy_terms_hash);
hasher.update(limit_commitment);
if let Some(eh) = exclusions_hash {
hasher.update(eh);
}
*hasher.finalize().as_bytes()
}
pub fn is_in_force(&self, current_time: Timestamp) -> bool {
if !matches!(self.status, CoverageStatus::Active | CoverageStatus::Renewed) {
return false;
}
if current_time < self.effective_from {
return false;
}
if current_time >= self.expiry {
return false;
}
true
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[repr(u8)]
pub enum ClaimType {
FireDamage = 0,
WaterDamage = 1,
StormDamage = 2,
Theft = 3,
Vandalism = 4,
StructuralDamage = 5,
FloodDamage = 6,
EarthquakeDamage = 7,
Collision = 20,
Comprehensive = 21,
HitAndRun = 22,
TotalLoss = 23,
UninsuredMotoristClaim = 24,
BodilyInjury = 40,
PropertyDamageLiability = 41,
PersonalInjuryClaim = 42,
TitleDefect = 50,
LienNotShown = 51,
Forgery = 52,
Fraud = 53,
Encroachment = 54,
Other = 255,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[repr(u8)]
pub enum ClaimStatus {
Filed = 0,
Acknowledged = 1,
UnderInvestigation = 2,
PendingDocumentation = 3,
InReview = 4,
Approved = 5,
PartiallyApproved = 6,
Denied = 7,
Paid = 8,
Closed = 9,
Reopened = 10,
InLitigation = 11,
SubrogationPending = 12,
Withdrawn = 13,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct InsuranceClaim {
pub claim_id: ClaimId,
pub coverage_id: CoverageId,
pub asset_id: AssetId,
pub claim_type: ClaimType,
pub claim_commitment: [u8; 32],
pub claimant_ref: PartyRef,
pub date_of_loss: Timestamp,
pub date_filed: Timestamp,
pub loss_amount_commitment: Option<[u8; 32]>,
pub approved_amount_commitment: Option<[u8; 32]>,
pub paid_amount_commitment: Option<[u8; 32]>,
pub adjuster_ref: Option<PartyRef>,
pub issuer_address: Address,
pub issuer_class: PropertyIssuerClass,
pub policy_id: PolicyId,
pub revocation_ref: Option<[u8; 32]>,
pub status: ClaimStatus,
pub created_at: Timestamp,
pub updated_at: Timestamp,
pub recorded_at_height: BlockHeight,
pub related_claims: Vec<ClaimId>,
pub attachments: Vec<AttachmentRef>,
}
impl InsuranceClaim {
pub fn generate_id(
coverage_id: &CoverageId,
claim_type: ClaimType,
claimant_ref: &PartyRef,
date_of_loss: Timestamp,
nonce: &[u8; 32],
) -> ClaimId {
let mut hasher = blake3::Hasher::new();
hasher.update(CLAIM_DOMAIN_SEP);
hasher.update(b":v1:");
hasher.update(coverage_id);
hasher.update(&[claim_type as u8]);
hasher.update(&claimant_ref.as_hash());
hasher.update(&date_of_loss.to_le_bytes());
hasher.update(nonce);
*hasher.finalize().as_bytes()
}
pub fn generate_commitment(
loss_description_hash: &[u8; 32],
loss_amount_commitment: Option<&[u8; 32]>,
documentation_hash: Option<&[u8; 32]>,
) -> [u8; 32] {
let mut hasher = blake3::Hasher::new();
hasher.update(CLAIM_COMMITMENT_SEP);
hasher.update(loss_description_hash);
if let Some(lac) = loss_amount_commitment {
hasher.update(lac);
}
if let Some(dh) = documentation_hash {
hasher.update(dh);
}
*hasher.finalize().as_bytes()
}
pub fn is_open(&self) -> bool {
matches!(
self.status,
ClaimStatus::Filed
| ClaimStatus::Acknowledged
| ClaimStatus::UnderInvestigation
| ClaimStatus::PendingDocumentation
| ClaimStatus::InReview
| ClaimStatus::Reopened
| ClaimStatus::InLitigation
| ClaimStatus::SubrogationPending
)
}
pub fn is_resolved(&self) -> bool {
matches!(
self.status,
ClaimStatus::Approved
| ClaimStatus::PartiallyApproved
| ClaimStatus::Denied
| ClaimStatus::Paid
| ClaimStatus::Closed
| ClaimStatus::Withdrawn
)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[repr(u8)]
pub enum PropertyProofProfile {
OwnershipProof = 0,
EncumbranceStatus = 1,
CoverageExists = 2,
CoverageInForce = 3,
ClaimStatus = 4,
TitleEventOccurred = 5,
AssetTypeProof = 6,
NoLiensOfType = 7,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[repr(u8)]
pub enum PropertyProofType {
Mock = 0,
Groth16 = 1,
Plonk = 2,
ThresholdSignature = 3,
MerkleInclusion = 4,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct PropertyProofEnvelope {
pub proof_id: ProofId,
pub profile: PropertyProofProfile,
pub profile_id: String,
pub policy_ids: Vec<PolicyId>,
pub public_inputs: Vec<u8>,
pub proof_data: Vec<u8>,
pub proof_type: PropertyProofType,
pub subject_nullifier: [u8; 32],
pub generated_at: Timestamp,
pub expires_at: Timestamp,
}
impl PropertyProofEnvelope {
pub fn generate_id(
profile: PropertyProofProfile,
subject_nullifier: &[u8; 32],
policy_ids: &[PolicyId],
nonce: &[u8; 32],
) -> ProofId {
let mut hasher = blake3::Hasher::new();
hasher.update(PROPERTY_PROOF_DOMAIN_SEP);
hasher.update(b":v1:");
hasher.update(&[profile as u8]);
hasher.update(subject_nullifier);
for policy_id in policy_ids {
hasher.update(policy_id);
}
hasher.update(nonce);
*hasher.finalize().as_bytes()
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[repr(u8)]
pub enum PropertyOperation {
AnchorAsset = 0,
UpdateAsset = 1,
TransferAsset = 2,
MergeAssets = 3,
SubdivideAsset = 4,
DeregisterAsset = 5,
RecordTitleEvent = 10,
UpdateTitleEvent = 11,
SupersedeTitleEvent = 12,
VoidTitleEvent = 13,
RecordEncumbrance = 20,
UpdateEncumbrance = 21,
SubordinateEncumbrance = 22,
ReleaseEncumbrance = 23,
ForecloseEncumbrance = 24,
IssueCoverage = 30,
UpdateCoverage = 31,
RenewCoverage = 32,
CancelCoverage = 33,
SuspendCoverage = 34,
ReinstateCoverage = 35,
FileClaim = 40,
UpdateClaim = 41,
ApproveClaim = 42,
DenyClaim = 43,
PayClaim = 44,
CloseClaim = 45,
ReopenClaim = 46,
WithdrawClaim = 47,
SubmitProof = 50,
VerifyProof = 51,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct PropertyTxData {
pub operation: PropertyOperation,
pub data: Vec<u8>,
pub recipient: crate::Address,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub enum PropertyEvent {
AssetAnchored {
asset_id: AssetId,
asset_type: AssetType,
jurisdiction: String,
timestamp: Timestamp,
},
AssetUpdated {
asset_id: AssetId,
new_status: AssetStatus,
timestamp: Timestamp,
},
AssetTransferred {
asset_id: AssetId,
from_ref_hash: [u8; 32],
to_ref_hash: [u8; 32],
timestamp: Timestamp,
},
TitleEventRecorded {
event_id: TitleEventId,
asset_id: AssetId,
event_type: TitleEventType,
timestamp: Timestamp,
},
TitleEventSuperseded {
old_event_id: TitleEventId,
new_event_id: TitleEventId,
timestamp: Timestamp,
},
EncumbranceRecorded {
encumbrance_id: EncumbranceId,
asset_id: AssetId,
encumbrance_type: EncumbranceType,
priority: PriorityPosition,
timestamp: Timestamp,
},
EncumbranceReleased {
encumbrance_id: EncumbranceId,
asset_id: AssetId,
timestamp: Timestamp,
},
EncumbranceForeclosed {
encumbrance_id: EncumbranceId,
asset_id: AssetId,
timestamp: Timestamp,
},
CoverageIssued {
coverage_id: CoverageId,
asset_id: AssetId,
coverage_type: CoverageType,
effective_from: Timestamp,
expiry: Timestamp,
timestamp: Timestamp,
},
CoverageStatusUpdated {
coverage_id: CoverageId,
new_status: CoverageStatus,
timestamp: Timestamp,
},
ClaimFiled {
claim_id: ClaimId,
coverage_id: CoverageId,
claim_type: ClaimType,
date_of_loss: Timestamp,
timestamp: Timestamp,
},
ClaimStatusUpdated {
claim_id: ClaimId,
new_status: ClaimStatus,
timestamp: Timestamp,
},
ClaimPaid {
claim_id: ClaimId,
amount_commitment: [u8; 32],
timestamp: Timestamp,
},
PropertyProofSubmitted {
proof_id: ProofId,
profile: PropertyProofProfile,
timestamp: Timestamp,
},
PropertyProofVerified {
proof_id: ProofId,
valid: bool,
timestamp: Timestamp,
},
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_asset_id_generation() {
let issuer = Address::new([1u8; 20]);
let commitment = [2u8; 32];
let nonce = [3u8; 32];
let id = AssetAnchor::generate_id(
&issuer,
&commitment,
AssetType::SingleFamilyResidence,
"US-CA-LA",
&nonce,
);
assert_ne!(id, [0u8; 32]);
let id2 = AssetAnchor::generate_id(
&issuer,
&commitment,
AssetType::SingleFamilyResidence,
"US-CA-LA",
&nonce,
);
assert_eq!(id, id2);
let id3 = AssetAnchor::generate_id(
&issuer,
&commitment,
AssetType::Commercial,
"US-CA-LA",
&nonce,
);
assert_ne!(id, id3);
}
#[test]
fn test_asset_commitment() {
let details = b"property details here";
let commitment = AssetAnchor::generate_commitment(details, None, None);
assert_ne!(commitment, [0u8; 32]);
}
#[test]
fn test_title_event_id() {
let asset_id = [1u8; 32];
let issuer = Address::new([2u8; 20]);
let nonce = [3u8; 32];
let id = TitleEvent::generate_id(
&asset_id,
TitleEventType::DeedRecorded,
&issuer,
&nonce,
);
assert_ne!(id, [0u8; 32]);
}
#[test]
fn test_encumbrance_active() {
let encumbrance = Encumbrance {
encumbrance_id: [1u8; 32],
asset_id: [2u8; 32],
encumbrance_type: EncumbranceType::FirstMortgage,
encumbrance_commitment: [3u8; 32],
holder_ref: PartyRef::Commitment([4u8; 32]),
obligor_ref: Some(PartyRef::Commitment([5u8; 32])),
priority: PriorityPosition::First,
amount_commitment: Some([6u8; 32]),
effective_from: 1000,
expiry: Some(2000),
issuer_address: Address::new([7u8; 20]),
issuer_class: PropertyIssuerClass::MortgageLender,
policy_id: [8u8; 32],
revocation_ref: None,
status: EncumbranceStatus::Active,
created_at: 1000,
updated_at: 1000,
recorded_at_height: 100,
agreement_id: None,
attachments: vec![],
};
assert!(!encumbrance.is_active(500)); assert!(encumbrance.is_active(1500)); assert!(!encumbrance.is_active(2500)); }
#[test]
fn test_coverage_in_force() {
let coverage = InsuranceCoverage {
coverage_id: [1u8; 32],
asset_id: [2u8; 32],
coverage_type: CoverageType::Homeowners,
coverage_commitment: [3u8; 32],
insurer_ref: PartyRef::Commitment([4u8; 32]),
insured_ref: PartyRef::Commitment([5u8; 32]),
additional_insureds: vec![],
limit_commitment: [6u8; 32],
deductible_commitment: None,
premium_commitment: None,
effective_from: 1000,
expiry: 2000,
issuer_address: Address::new([7u8; 20]),
issuer_class: PropertyIssuerClass::InsuranceCompany,
policy_id: [8u8; 32],
revocation_ref: None,
status: CoverageStatus::Active,
created_at: 1000,
updated_at: 1000,
recorded_at_height: 100,
prior_coverage_id: None,
attachments: vec![],
};
assert!(!coverage.is_in_force(500)); assert!(coverage.is_in_force(1500)); assert!(!coverage.is_in_force(2500)); }
#[test]
fn test_claim_status() {
let claim = InsuranceClaim {
claim_id: [1u8; 32],
coverage_id: [2u8; 32],
asset_id: [3u8; 32],
claim_type: ClaimType::WaterDamage,
claim_commitment: [4u8; 32],
claimant_ref: PartyRef::Commitment([5u8; 32]),
date_of_loss: 900,
date_filed: 1000,
loss_amount_commitment: Some([6u8; 32]),
approved_amount_commitment: None,
paid_amount_commitment: None,
adjuster_ref: None,
issuer_address: Address::new([7u8; 20]),
issuer_class: PropertyIssuerClass::InsuranceCompany,
policy_id: [8u8; 32],
revocation_ref: None,
status: ClaimStatus::Filed,
created_at: 1000,
updated_at: 1000,
recorded_at_height: 100,
related_claims: vec![],
attachments: vec![],
};
assert!(claim.is_open());
assert!(!claim.is_resolved());
}
#[test]
fn test_property_issuer_class() {
assert!(PropertyIssuerClass::LandRegistry.is_official());
assert!(PropertyIssuerClass::MotorVehicleDept.is_official());
assert!(!PropertyIssuerClass::TitleCompany.is_official());
assert!(PropertyIssuerClass::TitleCompany.is_lowkey());
assert!(PropertyIssuerClass::MortgageLender.is_lowkey());
assert!(!PropertyIssuerClass::LandRegistry.is_lowkey());
}
#[test]
fn test_property_proof_id() {
let nullifier = [1u8; 32];
let policies = vec![[2u8; 32], [3u8; 32]];
let nonce = [4u8; 32];
let id = PropertyProofEnvelope::generate_id(
PropertyProofProfile::OwnershipProof,
&nullifier,
&policies,
&nonce,
);
assert_ne!(id, [0u8; 32]);
}
}