Skip to main content

sumchain_primitives/
property.rs

1//! SRC-86X Property, Real Estate & Insurance Domain
2//!
3//! Privacy-first infrastructure for:
4//! - SRC-861: Asset Anchor (Property/Asset Identity)
5//! - SRC-862: Title/Ownership State Event
6//! - SRC-863: Encumbrance Standard (Lien/Mortgage/Leasehold)
7//! - SRC-864: Insurance Coverage Standard
8//! - SRC-865: Insurance Claim Lifecycle
9//! - SRC-866: 86X Proof Profiles
10
11use serde::{Deserialize, Serialize};
12use crate::{Address, BlockHeight, Timestamp};
13use crate::agreement::{AttachmentRef, PartyRef};
14
15// =============================================================================
16// Type Aliases
17// =============================================================================
18
19/// Unique asset anchor identifier
20pub type AssetId = [u8; 32];
21/// Title event identifier
22pub type TitleEventId = [u8; 32];
23/// Encumbrance identifier
24pub type EncumbranceId = [u8; 32];
25/// Insurance coverage identifier
26pub type CoverageId = [u8; 32];
27/// Insurance claim identifier
28pub type ClaimId = [u8; 32];
29/// Policy identifier (SRC-803 compatible)
30pub type PolicyId = [u8; 32];
31/// Proof identifier (SRC-806 compatible)
32pub type ProofId = [u8; 32];
33/// Subject identifier (SRC-801 compatible)
34pub type SubjectId = [u8; 32];
35
36// =============================================================================
37// Domain Separators (for deterministic hashing)
38// =============================================================================
39
40pub const ASSET_DOMAIN_SEP: &[u8] = b"SRC861-ASSET:";
41pub const ASSET_COMMITMENT_SEP: &[u8] = b"SRC861-COMMITMENT:v1:";
42pub const TITLE_DOMAIN_SEP: &[u8] = b"SRC862-TITLE:";
43pub const TITLE_COMMITMENT_SEP: &[u8] = b"SRC862-COMMITMENT:v1:";
44pub const ENCUMBRANCE_DOMAIN_SEP: &[u8] = b"SRC863-ENCUMBRANCE:";
45pub const ENCUMBRANCE_COMMITMENT_SEP: &[u8] = b"SRC863-COMMITMENT:v1:";
46pub const COVERAGE_DOMAIN_SEP: &[u8] = b"SRC864-COVERAGE:";
47pub const COVERAGE_COMMITMENT_SEP: &[u8] = b"SRC864-COMMITMENT:v1:";
48pub const CLAIM_DOMAIN_SEP: &[u8] = b"SRC865-CLAIM:";
49pub const CLAIM_COMMITMENT_SEP: &[u8] = b"SRC865-COMMITMENT:v1:";
50pub const PROPERTY_PROOF_DOMAIN_SEP: &[u8] = b"SRC866-PROOF:";
51
52// =============================================================================
53// SRC-861: Asset Anchor (Property/Asset Identity)
54// =============================================================================
55
56/// Asset type classification
57#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
58#[repr(u8)]
59pub enum AssetType {
60    // Real Estate (0-19)
61    /// Single family residence
62    SingleFamilyResidence = 0,
63    /// Multi-family residence
64    MultiFamilyResidence = 1,
65    /// Condominium
66    Condominium = 2,
67    /// Townhouse
68    Townhouse = 3,
69    /// Commercial property
70    Commercial = 4,
71    /// Industrial property
72    Industrial = 5,
73    /// Vacant land
74    VacantLand = 6,
75    /// Agricultural land
76    Agricultural = 7,
77    /// Mixed use
78    MixedUse = 8,
79    /// Manufactured home
80    ManufacturedHome = 9,
81
82    // Vehicles (20-39)
83    /// Automobile
84    Automobile = 20,
85    /// Motorcycle
86    Motorcycle = 21,
87    /// Boat/Watercraft
88    Watercraft = 22,
89    /// Aircraft
90    Aircraft = 23,
91    /// Recreational vehicle
92    RecreationalVehicle = 24,
93    /// Commercial vehicle
94    CommercialVehicle = 25,
95    /// Heavy equipment
96    HeavyEquipment = 26,
97
98    // Personal Property (40-59)
99    /// Fine art
100    FineArt = 40,
101    /// Jewelry
102    Jewelry = 41,
103    /// Collectibles
104    Collectibles = 42,
105    /// Antiques
106    Antiques = 43,
107    /// Musical instruments
108    MusicalInstruments = 44,
109    /// Electronics
110    Electronics = 45,
111    /// Furniture
112    Furniture = 46,
113
114    // Business Assets (60-79)
115    /// Inventory
116    Inventory = 60,
117    /// Equipment
118    Equipment = 61,
119    /// Fixtures
120    Fixtures = 62,
121    /// Intellectual property bundle
122    IpBundle = 63,
123    /// Goodwill
124    Goodwill = 64,
125
126    /// Other asset type
127    Other = 255,
128}
129
130/// Asset status
131#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
132#[repr(u8)]
133pub enum AssetStatus {
134    /// Asset registered and active
135    Active = 0,
136    /// Asset under transfer
137    PendingTransfer = 1,
138    /// Asset encumbered
139    Encumbered = 2,
140    /// Asset seized/frozen
141    Seized = 3,
142    /// Asset destroyed/demolished
143    Destroyed = 4,
144    /// Asset merged with another
145    Merged = 5,
146    /// Asset subdivided
147    Subdivided = 6,
148    /// Asset deregistered
149    Deregistered = 7,
150}
151
152/// Property issuer class (SRC-802 compatible)
153#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
154#[repr(u8)]
155pub enum PropertyIssuerClass {
156    // Official/Phase 2 Issuers (0-9)
157    /// Land registry/recorder's office
158    LandRegistry = 0,
159    /// Motor vehicle department
160    MotorVehicleDept = 1,
161    /// Tax assessor
162    TaxAssessor = 2,
163    /// Government agency
164    GovernmentAgency = 3,
165    /// FAA (aircraft registry)
166    AviationAuthority = 4,
167    /// Coast Guard (vessel registry)
168    MaritimeAuthority = 5,
169
170    // Phase 1/Lowkey Issuers (10-29)
171    /// Title company
172    TitleCompany = 10,
173    /// Escrow company
174    EscrowCompany = 11,
175    /// Real estate attorney
176    RealEstateAttorney = 12,
177    /// Appraiser
178    Appraiser = 13,
179    /// Surveyor
180    Surveyor = 14,
181    /// Insurance company
182    InsuranceCompany = 15,
183    /// Mortgage lender
184    MortgageLender = 16,
185    /// Property manager
186    PropertyManager = 17,
187    /// Notary
188    Notary = 18,
189
190    /// Other authorized issuer
191    Other = 255,
192}
193
194impl PropertyIssuerClass {
195    /// Check if this is an official (Phase 2) issuer
196    pub fn is_official(&self) -> bool {
197        matches!(
198            self,
199            Self::LandRegistry
200                | Self::MotorVehicleDept
201                | Self::TaxAssessor
202                | Self::GovernmentAgency
203                | Self::AviationAuthority
204                | Self::MaritimeAuthority
205        )
206    }
207
208    /// Check if this is a Phase 1 (lowkey) issuer
209    pub fn is_lowkey(&self) -> bool {
210        matches!(
211            self,
212            Self::TitleCompany
213                | Self::EscrowCompany
214                | Self::RealEstateAttorney
215                | Self::Appraiser
216                | Self::Surveyor
217                | Self::InsuranceCompany
218                | Self::MortgageLender
219        )
220    }
221}
222
223/// SRC-861 Asset Anchor
224#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
225pub struct AssetAnchor {
226    /// Unique asset identifier
227    pub asset_id: AssetId,
228    /// BLAKE3 commitment of asset details (address, parcel, VIN, etc.)
229    pub asset_commitment: [u8; 32],
230    /// Asset type classification
231    pub asset_type: AssetType,
232    /// Jurisdiction code (e.g., "US-CA-LA" for Los Angeles County)
233    pub jurisdiction_code: String,
234    /// Optional public reference (APN, VIN last 4, etc. - only if opted in)
235    pub public_reference: Option<String>,
236    /// Policy ID governing this asset
237    pub policy_id: PolicyId,
238    /// Issuer class that registered this
239    pub issuer_class: PropertyIssuerClass,
240    /// Issuer address
241    pub issuer_address: Address,
242    /// Current status
243    pub status: AssetStatus,
244    /// Creation timestamp
245    pub created_at: Timestamp,
246    /// Last update timestamp
247    pub updated_at: Timestamp,
248    /// Block height when anchored
249    pub anchored_at_height: BlockHeight,
250    /// Related asset IDs (for subdivisions, mergers)
251    pub related_assets: Vec<AssetId>,
252    /// Attachments (encrypted references)
253    pub attachments: Vec<AttachmentRef>,
254}
255
256impl AssetAnchor {
257    /// Generate deterministic asset ID
258    pub fn generate_id(
259        issuer: &Address,
260        asset_commitment: &[u8; 32],
261        asset_type: AssetType,
262        jurisdiction: &str,
263        nonce: &[u8; 32],
264    ) -> AssetId {
265        let mut hasher = blake3::Hasher::new();
266        hasher.update(ASSET_DOMAIN_SEP);
267        hasher.update(b":v1:");
268        hasher.update(issuer.as_ref());
269        hasher.update(asset_commitment);
270        hasher.update(&[asset_type as u8]);
271        hasher.update(jurisdiction.as_bytes());
272        hasher.update(nonce);
273        *hasher.finalize().as_bytes()
274    }
275
276    /// Generate asset commitment from details
277    pub fn generate_commitment(
278        asset_details: &[u8],
279        location_commitment: Option<&[u8; 32]>,
280        identifier_commitment: Option<&[u8; 32]>,
281    ) -> [u8; 32] {
282        let mut hasher = blake3::Hasher::new();
283        hasher.update(ASSET_COMMITMENT_SEP);
284        hasher.update(asset_details);
285        if let Some(loc) = location_commitment {
286            hasher.update(loc);
287        }
288        if let Some(id) = identifier_commitment {
289            hasher.update(id);
290        }
291        *hasher.finalize().as_bytes()
292    }
293}
294
295// =============================================================================
296// SRC-862: Title/Ownership State Event
297// =============================================================================
298
299/// Title event type
300#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
301#[repr(u8)]
302pub enum TitleEventType {
303    // Initial Events (0-9)
304    /// Initial title registration
305    InitialRegistration = 0,
306    /// Title search completed
307    TitleSearch = 1,
308    /// Title examination
309    TitleExamination = 2,
310    /// Title insurance commitment
311    TitleCommitment = 3,
312
313    // Transfer Events (10-19)
314    /// Deed recorded
315    DeedRecorded = 10,
316    /// Grant deed
317    GrantDeed = 11,
318    /// Warranty deed
319    WarrantyDeed = 12,
320    /// Quitclaim deed
321    QuitclaimDeed = 13,
322    /// Trust deed
323    TrustDeed = 14,
324    /// Deed of gift
325    DeedOfGift = 15,
326    /// Executor's deed
327    ExecutorsDeed = 16,
328    /// Tax deed
329    TaxDeed = 17,
330    /// Sheriff's deed
331    SheriffsDeed = 18,
332
333    // Ownership Changes (20-29)
334    /// Ownership transfer
335    OwnershipTransfer = 20,
336    /// Joint tenancy creation
337    JointTenancyCreated = 21,
338    /// Tenancy in common
339    TenancyInCommon = 22,
340    /// Trust assignment
341    TrustAssignment = 23,
342    /// Inheritance
343    Inheritance = 24,
344    /// Divorce decree transfer
345    DivorceTransfer = 25,
346
347    // Title Adjustments (30-39)
348    /// Title correction
349    TitleCorrection = 30,
350    /// Name change
351    NameChange = 31,
352    /// Legal description update
353    LegalDescriptionUpdate = 32,
354    /// Easement recorded
355    EasementRecorded = 33,
356    /// Covenant recorded
357    CovenantRecorded = 34,
358
359    // Termination Events (40-49)
360    /// Title cleared
361    TitleCleared = 40,
362    /// Foreclosure completed
363    ForeclosureCompleted = 41,
364    /// Tax sale completed
365    TaxSaleCompleted = 42,
366    /// Condemnation
367    Condemnation = 43,
368
369    /// Other event
370    Other = 255,
371}
372
373/// Title event status
374#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
375#[repr(u8)]
376pub enum TitleEventStatus {
377    /// Event recorded
378    Recorded = 0,
379    /// Event pending
380    Pending = 1,
381    /// Event superseded
382    Superseded = 2,
383    /// Event voided
384    Voided = 3,
385    /// Event corrected
386    Corrected = 4,
387}
388
389/// SRC-862 Title Event
390#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
391pub struct TitleEvent {
392    /// Unique event identifier
393    pub event_id: TitleEventId,
394    /// Asset this event relates to
395    pub asset_id: AssetId,
396    /// Event type
397    pub event_type: TitleEventType,
398    /// BLAKE3 commitment of event details
399    pub event_commitment: [u8; 32],
400    /// Grantor (current owner) reference
401    pub grantor_ref: Option<PartyRef>,
402    /// Grantee (new owner) reference
403    pub grantee_ref: Option<PartyRef>,
404    /// Issuer address
405    pub issuer_address: Address,
406    /// Issuer class
407    pub issuer_class: PropertyIssuerClass,
408    /// Event effective date
409    pub effective_date: Timestamp,
410    /// Recording reference (instrument number, etc.)
411    pub recording_ref: Option<String>,
412    /// Policy ID
413    pub policy_id: PolicyId,
414    /// Revocation reference (SRC-805 compatible)
415    pub revocation_ref: Option<[u8; 32]>,
416    /// Status
417    pub status: TitleEventStatus,
418    /// Creation timestamp
419    pub created_at: Timestamp,
420    /// Block height when recorded
421    pub recorded_at_height: BlockHeight,
422    /// Supersedes event ID
423    pub supersedes: Option<TitleEventId>,
424    /// Attachments
425    pub attachments: Vec<AttachmentRef>,
426}
427
428impl TitleEvent {
429    /// Generate event ID
430    pub fn generate_id(
431        asset_id: &AssetId,
432        event_type: TitleEventType,
433        issuer: &Address,
434        nonce: &[u8; 32],
435    ) -> TitleEventId {
436        let mut hasher = blake3::Hasher::new();
437        hasher.update(TITLE_DOMAIN_SEP);
438        hasher.update(b":v1:");
439        hasher.update(asset_id);
440        hasher.update(&[event_type as u8]);
441        hasher.update(issuer.as_ref());
442        hasher.update(nonce);
443        *hasher.finalize().as_bytes()
444    }
445
446    /// Generate event commitment
447    pub fn generate_commitment(
448        deed_hash: &[u8; 32],
449        parties_commitment: &[u8; 32],
450        consideration_commitment: Option<&[u8; 32]>,
451    ) -> [u8; 32] {
452        let mut hasher = blake3::Hasher::new();
453        hasher.update(TITLE_COMMITMENT_SEP);
454        hasher.update(deed_hash);
455        hasher.update(parties_commitment);
456        if let Some(cc) = consideration_commitment {
457            hasher.update(cc);
458        }
459        *hasher.finalize().as_bytes()
460    }
461}
462
463// =============================================================================
464// SRC-863: Encumbrance Standard (Lien/Mortgage/Leasehold)
465// =============================================================================
466
467/// Encumbrance type
468#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
469#[repr(u8)]
470pub enum EncumbranceType {
471    // Mortgages (0-9)
472    /// First mortgage/deed of trust
473    FirstMortgage = 0,
474    /// Second mortgage
475    SecondMortgage = 1,
476    /// Home equity line of credit
477    Heloc = 2,
478    /// Reverse mortgage
479    ReverseMortgage = 3,
480    /// Construction loan
481    ConstructionLoan = 4,
482    /// Commercial mortgage
483    CommercialMortgage = 5,
484
485    // Liens (10-29)
486    /// Mechanics lien
487    MechanicsLien = 10,
488    /// Tax lien
489    TaxLien = 11,
490    /// Judgment lien
491    JudgmentLien = 12,
492    /// HOA lien
493    HoaLien = 13,
494    /// Child support lien
495    ChildSupportLien = 14,
496    /// IRS lien
497    IrsLien = 15,
498    /// Municipal lien
499    MunicipalLien = 16,
500    /// UCC lien
501    UccLien = 17,
502    /// Voluntary lien
503    VoluntaryLien = 18,
504    /// Attachment lien
505    AttachmentLien = 19,
506
507    // Leaseholds (30-39)
508    /// Residential lease
509    ResidentialLease = 30,
510    /// Commercial lease
511    CommercialLease = 31,
512    /// Ground lease
513    GroundLease = 32,
514    /// Sublease
515    Sublease = 33,
516
517    // Easements & Restrictions (40-49)
518    /// Easement
519    Easement = 40,
520    /// Right of way
521    RightOfWay = 41,
522    /// Restrictive covenant
523    RestrictiveCovenant = 42,
524    /// Conservation easement
525    ConservationEasement = 43,
526    /// Utility easement
527    UtilityEasement = 44,
528
529    // Other (50-59)
530    /// Lis pendens
531    LisPendens = 50,
532    /// Notice of default
533    NoticeOfDefault = 51,
534    /// Notice of trustee sale
535    NoticeOfTrusteeSale = 52,
536
537    /// Other encumbrance
538    Other = 255,
539}
540
541/// Encumbrance status
542#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
543#[repr(u8)]
544pub enum EncumbranceStatus {
545    /// Encumbrance active
546    Active = 0,
547    /// Encumbrance pending
548    Pending = 1,
549    /// Encumbrance subordinated
550    Subordinated = 2,
551    /// Encumbrance released/satisfied
552    Released = 3,
553    /// Encumbrance foreclosed
554    Foreclosed = 4,
555    /// Encumbrance expired
556    Expired = 5,
557    /// Encumbrance disputed
558    Disputed = 6,
559    /// Encumbrance voided
560    Voided = 7,
561}
562
563/// Priority position for encumbrance
564#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
565#[repr(u8)]
566pub enum PriorityPosition {
567    First = 1,
568    Second = 2,
569    Third = 3,
570    Fourth = 4,
571    Fifth = 5,
572    Subordinate = 10,
573    Unspecified = 255,
574}
575
576/// SRC-863 Encumbrance
577#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
578pub struct Encumbrance {
579    /// Unique encumbrance identifier
580    pub encumbrance_id: EncumbranceId,
581    /// Asset being encumbered
582    pub asset_id: AssetId,
583    /// Encumbrance type
584    pub encumbrance_type: EncumbranceType,
585    /// BLAKE3 commitment of encumbrance details
586    pub encumbrance_commitment: [u8; 32],
587    /// Holder of the encumbrance (lender, lienor, lessor)
588    pub holder_ref: PartyRef,
589    /// Obligor (borrower, debtor, lessee)
590    pub obligor_ref: Option<PartyRef>,
591    /// Priority position
592    pub priority: PriorityPosition,
593    /// Amount commitment (for monetary encumbrances)
594    pub amount_commitment: Option<[u8; 32]>,
595    /// Effective date
596    pub effective_from: Timestamp,
597    /// Expiry/maturity date
598    pub expiry: Option<Timestamp>,
599    /// Issuer address
600    pub issuer_address: Address,
601    /// Issuer class
602    pub issuer_class: PropertyIssuerClass,
603    /// Policy ID
604    pub policy_id: PolicyId,
605    /// Revocation reference (SRC-805 compatible)
606    pub revocation_ref: Option<[u8; 32]>,
607    /// Status
608    pub status: EncumbranceStatus,
609    /// Creation timestamp
610    pub created_at: Timestamp,
611    /// Last update timestamp
612    pub updated_at: Timestamp,
613    /// Block height when recorded
614    pub recorded_at_height: BlockHeight,
615    /// Related agreement ID (SRC-841)
616    pub agreement_id: Option<[u8; 32]>,
617    /// Attachments
618    pub attachments: Vec<AttachmentRef>,
619}
620
621impl Encumbrance {
622    /// Generate encumbrance ID
623    pub fn generate_id(
624        asset_id: &AssetId,
625        encumbrance_type: EncumbranceType,
626        holder_ref: &PartyRef,
627        nonce: &[u8; 32],
628    ) -> EncumbranceId {
629        let mut hasher = blake3::Hasher::new();
630        hasher.update(ENCUMBRANCE_DOMAIN_SEP);
631        hasher.update(b":v1:");
632        hasher.update(asset_id);
633        hasher.update(&[encumbrance_type as u8]);
634        hasher.update(&holder_ref.as_hash());
635        hasher.update(nonce);
636        *hasher.finalize().as_bytes()
637    }
638
639    /// Generate encumbrance commitment
640    pub fn generate_commitment(
641        terms_hash: &[u8; 32],
642        amount_commitment: Option<&[u8; 32]>,
643        parties_commitment: &[u8; 32],
644    ) -> [u8; 32] {
645        let mut hasher = blake3::Hasher::new();
646        hasher.update(ENCUMBRANCE_COMMITMENT_SEP);
647        hasher.update(terms_hash);
648        if let Some(ac) = amount_commitment {
649            hasher.update(ac);
650        }
651        hasher.update(parties_commitment);
652        *hasher.finalize().as_bytes()
653    }
654
655    /// Check if encumbrance is currently active
656    pub fn is_active(&self, current_time: Timestamp) -> bool {
657        if !matches!(self.status, EncumbranceStatus::Active | EncumbranceStatus::Subordinated) {
658            return false;
659        }
660        if current_time < self.effective_from {
661            return false;
662        }
663        if let Some(exp) = self.expiry {
664            if current_time >= exp {
665                return false;
666            }
667        }
668        true
669    }
670}
671
672// =============================================================================
673// SRC-864: Insurance Coverage Standard
674// =============================================================================
675
676/// Insurance coverage type
677#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
678#[repr(u8)]
679pub enum CoverageType {
680    // Property Insurance (0-19)
681    /// Homeowners insurance
682    Homeowners = 0,
683    /// Renters insurance
684    Renters = 1,
685    /// Landlord insurance
686    Landlord = 2,
687    /// Commercial property
688    CommercialProperty = 3,
689    /// Flood insurance
690    Flood = 4,
691    /// Earthquake insurance
692    Earthquake = 5,
693    /// Fire insurance
694    Fire = 6,
695    /// Windstorm/hurricane
696    Windstorm = 7,
697
698    // Vehicle Insurance (20-39)
699    /// Auto liability
700    AutoLiability = 20,
701    /// Auto collision
702    AutoCollision = 21,
703    /// Auto comprehensive
704    AutoComprehensive = 22,
705    /// Uninsured motorist
706    UninsuredMotorist = 23,
707    /// Personal injury protection
708    PersonalInjuryProtection = 24,
709    /// Gap insurance
710    GapInsurance = 25,
711    /// Watercraft insurance
712    Watercraft = 26,
713    /// Aircraft insurance
714    Aircraft = 27,
715
716    // Title Insurance (40-49)
717    /// Owner's title policy
718    OwnersTitlePolicy = 40,
719    /// Lender's title policy
720    LendersTitlePolicy = 41,
721    /// Extended coverage
722    ExtendedCoverage = 42,
723
724    // Liability Insurance (50-59)
725    /// General liability
726    GeneralLiability = 50,
727    /// Professional liability
728    ProfessionalLiability = 51,
729    /// Umbrella policy
730    UmbrellaPolicy = 52,
731    /// Product liability
732    ProductLiability = 53,
733
734    // Specialty (60-69)
735    /// Builder's risk
736    BuildersRisk = 60,
737    /// Inland marine
738    InlandMarine = 61,
739    /// Valuable articles
740    ValuableArticles = 62,
741    /// Equipment breakdown
742    EquipmentBreakdown = 63,
743
744    /// Other coverage
745    Other = 255,
746}
747
748/// Coverage status
749#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
750#[repr(u8)]
751pub enum CoverageStatus {
752    /// Coverage active
753    Active = 0,
754    /// Coverage pending
755    Pending = 1,
756    /// Coverage suspended
757    Suspended = 2,
758    /// Coverage cancelled
759    Cancelled = 3,
760    /// Coverage expired
761    Expired = 4,
762    /// Coverage lapsed
763    Lapsed = 5,
764    /// Coverage renewed
765    Renewed = 6,
766    /// Coverage non-renewed
767    NonRenewed = 7,
768}
769
770/// SRC-864 Insurance Coverage
771#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
772pub struct InsuranceCoverage {
773    /// Unique coverage identifier
774    pub coverage_id: CoverageId,
775    /// Asset being insured
776    pub asset_id: AssetId,
777    /// Coverage type
778    pub coverage_type: CoverageType,
779    /// BLAKE3 commitment of coverage details
780    pub coverage_commitment: [u8; 32],
781    /// Insurer reference
782    pub insurer_ref: PartyRef,
783    /// Insured (policyholder) reference
784    pub insured_ref: PartyRef,
785    /// Additional insureds
786    pub additional_insureds: Vec<PartyRef>,
787    /// Coverage limit commitment
788    pub limit_commitment: [u8; 32],
789    /// Deductible commitment
790    pub deductible_commitment: Option<[u8; 32]>,
791    /// Premium commitment
792    pub premium_commitment: Option<[u8; 32]>,
793    /// Policy effective date
794    pub effective_from: Timestamp,
795    /// Policy expiry date
796    pub expiry: Timestamp,
797    /// Issuer address
798    pub issuer_address: Address,
799    /// Issuer class
800    pub issuer_class: PropertyIssuerClass,
801    /// Policy ID (SRC-803)
802    pub policy_id: PolicyId,
803    /// Revocation reference (SRC-805 compatible)
804    pub revocation_ref: Option<[u8; 32]>,
805    /// Status
806    pub status: CoverageStatus,
807    /// Creation timestamp
808    pub created_at: Timestamp,
809    /// Last update timestamp
810    pub updated_at: Timestamp,
811    /// Block height when recorded
812    pub recorded_at_height: BlockHeight,
813    /// Prior coverage ID (for renewals)
814    pub prior_coverage_id: Option<CoverageId>,
815    /// Attachments
816    pub attachments: Vec<AttachmentRef>,
817}
818
819impl InsuranceCoverage {
820    /// Generate coverage ID
821    pub fn generate_id(
822        asset_id: &AssetId,
823        coverage_type: CoverageType,
824        insurer_ref: &PartyRef,
825        insured_ref: &PartyRef,
826        nonce: &[u8; 32],
827    ) -> CoverageId {
828        let mut hasher = blake3::Hasher::new();
829        hasher.update(COVERAGE_DOMAIN_SEP);
830        hasher.update(b":v1:");
831        hasher.update(asset_id);
832        hasher.update(&[coverage_type as u8]);
833        hasher.update(&insurer_ref.as_hash());
834        hasher.update(&insured_ref.as_hash());
835        hasher.update(nonce);
836        *hasher.finalize().as_bytes()
837    }
838
839    /// Generate coverage commitment
840    pub fn generate_commitment(
841        policy_terms_hash: &[u8; 32],
842        limit_commitment: &[u8; 32],
843        exclusions_hash: Option<&[u8; 32]>,
844    ) -> [u8; 32] {
845        let mut hasher = blake3::Hasher::new();
846        hasher.update(COVERAGE_COMMITMENT_SEP);
847        hasher.update(policy_terms_hash);
848        hasher.update(limit_commitment);
849        if let Some(eh) = exclusions_hash {
850            hasher.update(eh);
851        }
852        *hasher.finalize().as_bytes()
853    }
854
855    /// Check if coverage is currently in force
856    pub fn is_in_force(&self, current_time: Timestamp) -> bool {
857        if !matches!(self.status, CoverageStatus::Active | CoverageStatus::Renewed) {
858            return false;
859        }
860        if current_time < self.effective_from {
861            return false;
862        }
863        if current_time >= self.expiry {
864            return false;
865        }
866        true
867    }
868}
869
870// =============================================================================
871// SRC-865: Insurance Claim Lifecycle
872// =============================================================================
873
874/// Claim type
875#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
876#[repr(u8)]
877pub enum ClaimType {
878    // Property Claims (0-19)
879    /// Fire damage
880    FireDamage = 0,
881    /// Water damage
882    WaterDamage = 1,
883    /// Storm damage
884    StormDamage = 2,
885    /// Theft
886    Theft = 3,
887    /// Vandalism
888    Vandalism = 4,
889    /// Structural damage
890    StructuralDamage = 5,
891    /// Flood damage
892    FloodDamage = 6,
893    /// Earthquake damage
894    EarthquakeDamage = 7,
895
896    // Vehicle Claims (20-39)
897    /// Collision
898    Collision = 20,
899    /// Comprehensive (non-collision)
900    Comprehensive = 21,
901    /// Hit and run
902    HitAndRun = 22,
903    /// Total loss
904    TotalLoss = 23,
905    /// Uninsured motorist
906    UninsuredMotoristClaim = 24,
907
908    // Liability Claims (40-49)
909    /// Bodily injury
910    BodilyInjury = 40,
911    /// Property damage liability
912    PropertyDamageLiability = 41,
913    /// Personal injury
914    PersonalInjuryClaim = 42,
915
916    // Title Claims (50-59)
917    /// Title defect
918    TitleDefect = 50,
919    /// Lien not shown
920    LienNotShown = 51,
921    /// Forgery
922    Forgery = 52,
923    /// Fraud
924    Fraud = 53,
925    /// Encroachment
926    Encroachment = 54,
927
928    /// Other claim type
929    Other = 255,
930}
931
932/// Claim status
933#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
934#[repr(u8)]
935pub enum ClaimStatus {
936    /// Claim filed
937    Filed = 0,
938    /// Claim acknowledged
939    Acknowledged = 1,
940    /// Under investigation
941    UnderInvestigation = 2,
942    /// Pending documentation
943    PendingDocumentation = 3,
944    /// In review
945    InReview = 4,
946    /// Approved
947    Approved = 5,
948    /// Partially approved
949    PartiallyApproved = 6,
950    /// Denied
951    Denied = 7,
952    /// Paid
953    Paid = 8,
954    /// Closed
955    Closed = 9,
956    /// Reopened
957    Reopened = 10,
958    /// In litigation
959    InLitigation = 11,
960    /// Subrogation pending
961    SubrogationPending = 12,
962    /// Withdrawn
963    Withdrawn = 13,
964}
965
966/// SRC-865 Insurance Claim
967#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
968pub struct InsuranceClaim {
969    /// Unique claim identifier
970    pub claim_id: ClaimId,
971    /// Coverage under which claim is made
972    pub coverage_id: CoverageId,
973    /// Asset involved
974    pub asset_id: AssetId,
975    /// Claim type
976    pub claim_type: ClaimType,
977    /// BLAKE3 commitment of claim details
978    pub claim_commitment: [u8; 32],
979    /// Claimant reference
980    pub claimant_ref: PartyRef,
981    /// Date of loss
982    pub date_of_loss: Timestamp,
983    /// Date claim filed
984    pub date_filed: Timestamp,
985    /// Loss amount commitment
986    pub loss_amount_commitment: Option<[u8; 32]>,
987    /// Approved amount commitment
988    pub approved_amount_commitment: Option<[u8; 32]>,
989    /// Paid amount commitment
990    pub paid_amount_commitment: Option<[u8; 32]>,
991    /// Adjuster assigned
992    pub adjuster_ref: Option<PartyRef>,
993    /// Issuer address
994    pub issuer_address: Address,
995    /// Issuer class
996    pub issuer_class: PropertyIssuerClass,
997    /// Policy ID (SRC-803)
998    pub policy_id: PolicyId,
999    /// Revocation reference (SRC-805 compatible)
1000    pub revocation_ref: Option<[u8; 32]>,
1001    /// Status
1002    pub status: ClaimStatus,
1003    /// Creation timestamp
1004    pub created_at: Timestamp,
1005    /// Last update timestamp
1006    pub updated_at: Timestamp,
1007    /// Block height when recorded
1008    pub recorded_at_height: BlockHeight,
1009    /// Related claim IDs (for split claims, etc.)
1010    pub related_claims: Vec<ClaimId>,
1011    /// Attachments
1012    pub attachments: Vec<AttachmentRef>,
1013}
1014
1015impl InsuranceClaim {
1016    /// Generate claim ID
1017    pub fn generate_id(
1018        coverage_id: &CoverageId,
1019        claim_type: ClaimType,
1020        claimant_ref: &PartyRef,
1021        date_of_loss: Timestamp,
1022        nonce: &[u8; 32],
1023    ) -> ClaimId {
1024        let mut hasher = blake3::Hasher::new();
1025        hasher.update(CLAIM_DOMAIN_SEP);
1026        hasher.update(b":v1:");
1027        hasher.update(coverage_id);
1028        hasher.update(&[claim_type as u8]);
1029        hasher.update(&claimant_ref.as_hash());
1030        hasher.update(&date_of_loss.to_le_bytes());
1031        hasher.update(nonce);
1032        *hasher.finalize().as_bytes()
1033    }
1034
1035    /// Generate claim commitment
1036    pub fn generate_commitment(
1037        loss_description_hash: &[u8; 32],
1038        loss_amount_commitment: Option<&[u8; 32]>,
1039        documentation_hash: Option<&[u8; 32]>,
1040    ) -> [u8; 32] {
1041        let mut hasher = blake3::Hasher::new();
1042        hasher.update(CLAIM_COMMITMENT_SEP);
1043        hasher.update(loss_description_hash);
1044        if let Some(lac) = loss_amount_commitment {
1045            hasher.update(lac);
1046        }
1047        if let Some(dh) = documentation_hash {
1048            hasher.update(dh);
1049        }
1050        *hasher.finalize().as_bytes()
1051    }
1052
1053    /// Check if claim is open
1054    pub fn is_open(&self) -> bool {
1055        matches!(
1056            self.status,
1057            ClaimStatus::Filed
1058                | ClaimStatus::Acknowledged
1059                | ClaimStatus::UnderInvestigation
1060                | ClaimStatus::PendingDocumentation
1061                | ClaimStatus::InReview
1062                | ClaimStatus::Reopened
1063                | ClaimStatus::InLitigation
1064                | ClaimStatus::SubrogationPending
1065        )
1066    }
1067
1068    /// Check if claim is resolved
1069    pub fn is_resolved(&self) -> bool {
1070        matches!(
1071            self.status,
1072            ClaimStatus::Approved
1073                | ClaimStatus::PartiallyApproved
1074                | ClaimStatus::Denied
1075                | ClaimStatus::Paid
1076                | ClaimStatus::Closed
1077                | ClaimStatus::Withdrawn
1078        )
1079    }
1080}
1081
1082// =============================================================================
1083// SRC-866: 86X Proof Profiles
1084// =============================================================================
1085
1086/// Proof profile types for SRC-86X
1087#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
1088#[repr(u8)]
1089pub enum PropertyProofProfile {
1090    /// Prove ownership of asset
1091    OwnershipProof = 0,
1092    /// Prove asset is unencumbered (or encumbrance status)
1093    EncumbranceStatus = 1,
1094    /// Prove coverage exists
1095    CoverageExists = 2,
1096    /// Prove coverage is in force
1097    CoverageInForce = 3,
1098    /// Prove claim status
1099    ClaimStatus = 4,
1100    /// Prove title event occurred
1101    TitleEventOccurred = 5,
1102    /// Prove asset type
1103    AssetTypeProof = 6,
1104    /// Prove no liens of type
1105    NoLiensOfType = 7,
1106}
1107
1108/// Proof type (SRC-806 compatible)
1109#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
1110#[repr(u8)]
1111pub enum PropertyProofType {
1112    /// Mock proof (for testing)
1113    Mock = 0,
1114    /// Groth16 ZK-SNARK
1115    Groth16 = 1,
1116    /// PLONK proof
1117    Plonk = 2,
1118    /// Threshold signature proof
1119    ThresholdSignature = 3,
1120    /// Merkle inclusion proof
1121    MerkleInclusion = 4,
1122}
1123
1124/// SRC-866 Property Proof Envelope
1125#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
1126pub struct PropertyProofEnvelope {
1127    /// Proof identifier
1128    pub proof_id: ProofId,
1129    /// Proof profile being proven
1130    pub profile: PropertyProofProfile,
1131    /// Profile version string (e.g., "property.ownership.v1")
1132    pub profile_id: String,
1133    /// Policy IDs that were checked
1134    pub policy_ids: Vec<PolicyId>,
1135    /// Public inputs to the proof
1136    pub public_inputs: Vec<u8>,
1137    /// The proof data
1138    pub proof_data: Vec<u8>,
1139    /// Proof type
1140    pub proof_type: PropertyProofType,
1141    /// Subject nullifier (for revocation checking)
1142    pub subject_nullifier: [u8; 32],
1143    /// When proof was generated
1144    pub generated_at: Timestamp,
1145    /// When proof expires
1146    pub expires_at: Timestamp,
1147}
1148
1149impl PropertyProofEnvelope {
1150    /// Generate proof ID
1151    pub fn generate_id(
1152        profile: PropertyProofProfile,
1153        subject_nullifier: &[u8; 32],
1154        policy_ids: &[PolicyId],
1155        nonce: &[u8; 32],
1156    ) -> ProofId {
1157        let mut hasher = blake3::Hasher::new();
1158        hasher.update(PROPERTY_PROOF_DOMAIN_SEP);
1159        hasher.update(b":v1:");
1160        hasher.update(&[profile as u8]);
1161        hasher.update(subject_nullifier);
1162        for policy_id in policy_ids {
1163            hasher.update(policy_id);
1164        }
1165        hasher.update(nonce);
1166        *hasher.finalize().as_bytes()
1167    }
1168}
1169
1170// =============================================================================
1171// Operations
1172// =============================================================================
1173
1174/// SRC-86X Operation codes
1175#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
1176#[repr(u8)]
1177pub enum PropertyOperation {
1178    // SRC-861: Asset Anchor (0-9)
1179    AnchorAsset = 0,
1180    UpdateAsset = 1,
1181    TransferAsset = 2,
1182    MergeAssets = 3,
1183    SubdivideAsset = 4,
1184    DeregisterAsset = 5,
1185
1186    // SRC-862: Title Events (10-19)
1187    RecordTitleEvent = 10,
1188    UpdateTitleEvent = 11,
1189    SupersedeTitleEvent = 12,
1190    VoidTitleEvent = 13,
1191
1192    // SRC-863: Encumbrances (20-29)
1193    RecordEncumbrance = 20,
1194    UpdateEncumbrance = 21,
1195    SubordinateEncumbrance = 22,
1196    ReleaseEncumbrance = 23,
1197    ForecloseEncumbrance = 24,
1198
1199    // SRC-864: Coverage (30-39)
1200    IssueCoverage = 30,
1201    UpdateCoverage = 31,
1202    RenewCoverage = 32,
1203    CancelCoverage = 33,
1204    SuspendCoverage = 34,
1205    ReinstateCoverage = 35,
1206
1207    // SRC-865: Claims (40-49)
1208    FileClaim = 40,
1209    UpdateClaim = 41,
1210    ApproveClaim = 42,
1211    DenyClaim = 43,
1212    PayClaim = 44,
1213    CloseClaim = 45,
1214    ReopenClaim = 46,
1215    WithdrawClaim = 47,
1216
1217    // SRC-866: Proof Operations (50-59)
1218    SubmitProof = 50,
1219    VerifyProof = 51,
1220}
1221
1222/// Transaction data for SRC-86X operations
1223#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
1224pub struct PropertyTxData {
1225    pub operation: PropertyOperation,
1226    pub data: Vec<u8>,
1227    /// Token recipient address - the owner of the minted token
1228    pub recipient: crate::Address,
1229}
1230
1231// =============================================================================
1232// Events
1233// =============================================================================
1234
1235/// SRC-86X Events
1236#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
1237pub enum PropertyEvent {
1238    // SRC-861 Events
1239    AssetAnchored {
1240        asset_id: AssetId,
1241        asset_type: AssetType,
1242        jurisdiction: String,
1243        timestamp: Timestamp,
1244    },
1245    AssetUpdated {
1246        asset_id: AssetId,
1247        new_status: AssetStatus,
1248        timestamp: Timestamp,
1249    },
1250    AssetTransferred {
1251        asset_id: AssetId,
1252        from_ref_hash: [u8; 32],
1253        to_ref_hash: [u8; 32],
1254        timestamp: Timestamp,
1255    },
1256
1257    // SRC-862 Events
1258    TitleEventRecorded {
1259        event_id: TitleEventId,
1260        asset_id: AssetId,
1261        event_type: TitleEventType,
1262        timestamp: Timestamp,
1263    },
1264    TitleEventSuperseded {
1265        old_event_id: TitleEventId,
1266        new_event_id: TitleEventId,
1267        timestamp: Timestamp,
1268    },
1269
1270    // SRC-863 Events
1271    EncumbranceRecorded {
1272        encumbrance_id: EncumbranceId,
1273        asset_id: AssetId,
1274        encumbrance_type: EncumbranceType,
1275        priority: PriorityPosition,
1276        timestamp: Timestamp,
1277    },
1278    EncumbranceReleased {
1279        encumbrance_id: EncumbranceId,
1280        asset_id: AssetId,
1281        timestamp: Timestamp,
1282    },
1283    EncumbranceForeclosed {
1284        encumbrance_id: EncumbranceId,
1285        asset_id: AssetId,
1286        timestamp: Timestamp,
1287    },
1288
1289    // SRC-864 Events
1290    CoverageIssued {
1291        coverage_id: CoverageId,
1292        asset_id: AssetId,
1293        coverage_type: CoverageType,
1294        effective_from: Timestamp,
1295        expiry: Timestamp,
1296        timestamp: Timestamp,
1297    },
1298    CoverageStatusUpdated {
1299        coverage_id: CoverageId,
1300        new_status: CoverageStatus,
1301        timestamp: Timestamp,
1302    },
1303
1304    // SRC-865 Events
1305    ClaimFiled {
1306        claim_id: ClaimId,
1307        coverage_id: CoverageId,
1308        claim_type: ClaimType,
1309        date_of_loss: Timestamp,
1310        timestamp: Timestamp,
1311    },
1312    ClaimStatusUpdated {
1313        claim_id: ClaimId,
1314        new_status: ClaimStatus,
1315        timestamp: Timestamp,
1316    },
1317    ClaimPaid {
1318        claim_id: ClaimId,
1319        amount_commitment: [u8; 32],
1320        timestamp: Timestamp,
1321    },
1322
1323    // SRC-866 Events
1324    PropertyProofSubmitted {
1325        proof_id: ProofId,
1326        profile: PropertyProofProfile,
1327        timestamp: Timestamp,
1328    },
1329    PropertyProofVerified {
1330        proof_id: ProofId,
1331        valid: bool,
1332        timestamp: Timestamp,
1333    },
1334}
1335
1336#[cfg(test)]
1337mod tests {
1338    use super::*;
1339
1340    #[test]
1341    fn test_asset_id_generation() {
1342        let issuer = Address::new([1u8; 20]);
1343        let commitment = [2u8; 32];
1344        let nonce = [3u8; 32];
1345
1346        let id = AssetAnchor::generate_id(
1347            &issuer,
1348            &commitment,
1349            AssetType::SingleFamilyResidence,
1350            "US-CA-LA",
1351            &nonce,
1352        );
1353        assert_ne!(id, [0u8; 32]);
1354
1355        // Same inputs = same ID
1356        let id2 = AssetAnchor::generate_id(
1357            &issuer,
1358            &commitment,
1359            AssetType::SingleFamilyResidence,
1360            "US-CA-LA",
1361            &nonce,
1362        );
1363        assert_eq!(id, id2);
1364
1365        // Different asset type = different ID
1366        let id3 = AssetAnchor::generate_id(
1367            &issuer,
1368            &commitment,
1369            AssetType::Commercial,
1370            "US-CA-LA",
1371            &nonce,
1372        );
1373        assert_ne!(id, id3);
1374    }
1375
1376    #[test]
1377    fn test_asset_commitment() {
1378        let details = b"property details here";
1379        let commitment = AssetAnchor::generate_commitment(details, None, None);
1380        assert_ne!(commitment, [0u8; 32]);
1381    }
1382
1383    #[test]
1384    fn test_title_event_id() {
1385        let asset_id = [1u8; 32];
1386        let issuer = Address::new([2u8; 20]);
1387        let nonce = [3u8; 32];
1388
1389        let id = TitleEvent::generate_id(
1390            &asset_id,
1391            TitleEventType::DeedRecorded,
1392            &issuer,
1393            &nonce,
1394        );
1395        assert_ne!(id, [0u8; 32]);
1396    }
1397
1398    #[test]
1399    fn test_encumbrance_active() {
1400        let encumbrance = Encumbrance {
1401            encumbrance_id: [1u8; 32],
1402            asset_id: [2u8; 32],
1403            encumbrance_type: EncumbranceType::FirstMortgage,
1404            encumbrance_commitment: [3u8; 32],
1405            holder_ref: PartyRef::Commitment([4u8; 32]),
1406            obligor_ref: Some(PartyRef::Commitment([5u8; 32])),
1407            priority: PriorityPosition::First,
1408            amount_commitment: Some([6u8; 32]),
1409            effective_from: 1000,
1410            expiry: Some(2000),
1411            issuer_address: Address::new([7u8; 20]),
1412            issuer_class: PropertyIssuerClass::MortgageLender,
1413            policy_id: [8u8; 32],
1414            revocation_ref: None,
1415            status: EncumbranceStatus::Active,
1416            created_at: 1000,
1417            updated_at: 1000,
1418            recorded_at_height: 100,
1419            agreement_id: None,
1420            attachments: vec![],
1421        };
1422
1423        assert!(!encumbrance.is_active(500));  // Before effective
1424        assert!(encumbrance.is_active(1500)); // During validity
1425        assert!(!encumbrance.is_active(2500)); // After expiry
1426    }
1427
1428    #[test]
1429    fn test_coverage_in_force() {
1430        let coverage = InsuranceCoverage {
1431            coverage_id: [1u8; 32],
1432            asset_id: [2u8; 32],
1433            coverage_type: CoverageType::Homeowners,
1434            coverage_commitment: [3u8; 32],
1435            insurer_ref: PartyRef::Commitment([4u8; 32]),
1436            insured_ref: PartyRef::Commitment([5u8; 32]),
1437            additional_insureds: vec![],
1438            limit_commitment: [6u8; 32],
1439            deductible_commitment: None,
1440            premium_commitment: None,
1441            effective_from: 1000,
1442            expiry: 2000,
1443            issuer_address: Address::new([7u8; 20]),
1444            issuer_class: PropertyIssuerClass::InsuranceCompany,
1445            policy_id: [8u8; 32],
1446            revocation_ref: None,
1447            status: CoverageStatus::Active,
1448            created_at: 1000,
1449            updated_at: 1000,
1450            recorded_at_height: 100,
1451            prior_coverage_id: None,
1452            attachments: vec![],
1453        };
1454
1455        assert!(!coverage.is_in_force(500));  // Before effective
1456        assert!(coverage.is_in_force(1500)); // During validity
1457        assert!(!coverage.is_in_force(2500)); // After expiry
1458    }
1459
1460    #[test]
1461    fn test_claim_status() {
1462        let claim = InsuranceClaim {
1463            claim_id: [1u8; 32],
1464            coverage_id: [2u8; 32],
1465            asset_id: [3u8; 32],
1466            claim_type: ClaimType::WaterDamage,
1467            claim_commitment: [4u8; 32],
1468            claimant_ref: PartyRef::Commitment([5u8; 32]),
1469            date_of_loss: 900,
1470            date_filed: 1000,
1471            loss_amount_commitment: Some([6u8; 32]),
1472            approved_amount_commitment: None,
1473            paid_amount_commitment: None,
1474            adjuster_ref: None,
1475            issuer_address: Address::new([7u8; 20]),
1476            issuer_class: PropertyIssuerClass::InsuranceCompany,
1477            policy_id: [8u8; 32],
1478            revocation_ref: None,
1479            status: ClaimStatus::Filed,
1480            created_at: 1000,
1481            updated_at: 1000,
1482            recorded_at_height: 100,
1483            related_claims: vec![],
1484            attachments: vec![],
1485        };
1486
1487        assert!(claim.is_open());
1488        assert!(!claim.is_resolved());
1489    }
1490
1491    #[test]
1492    fn test_property_issuer_class() {
1493        assert!(PropertyIssuerClass::LandRegistry.is_official());
1494        assert!(PropertyIssuerClass::MotorVehicleDept.is_official());
1495        assert!(!PropertyIssuerClass::TitleCompany.is_official());
1496
1497        assert!(PropertyIssuerClass::TitleCompany.is_lowkey());
1498        assert!(PropertyIssuerClass::MortgageLender.is_lowkey());
1499        assert!(!PropertyIssuerClass::LandRegistry.is_lowkey());
1500    }
1501
1502    #[test]
1503    fn test_property_proof_id() {
1504        let nullifier = [1u8; 32];
1505        let policies = vec![[2u8; 32], [3u8; 32]];
1506        let nonce = [4u8; 32];
1507
1508        let id = PropertyProofEnvelope::generate_id(
1509            PropertyProofProfile::OwnershipProof,
1510            &nullifier,
1511            &policies,
1512            &nonce,
1513        );
1514        assert_ne!(id, [0u8; 32]);
1515    }
1516}