@@ -26,11 +26,10 @@ pub enum ClaimStatus {
2626#[ contracttype]
2727#[ derive( Clone , Debug , Eq , PartialEq ) ]
2828pub enum PolicyType {
29- Comprehensive ,
30- Theft ,
31- Damage ,
3229 Liability ,
33- BusinessInterruption ,
30+ Property ,
31+ Comprehensive ,
32+ Custom ,
3433}
3534
3635#[ contracttype]
@@ -50,6 +49,7 @@ pub struct InsurancePolicy {
5049 pub holder : Address ,
5150 pub insurer : Address ,
5251 pub asset_id : BytesN < 32 > ,
52+ pub policy_type : PolicyType ,
5353 pub coverage_amount : i128 ,
5454 pub deductible : i128 ,
5555 pub premium : i128 ,
@@ -81,22 +81,41 @@ pub enum DataKey {
8181 AssetPolicies ( BytesN < 32 > ) ,
8282}
8383
84+ /// Create a new insurance policy with date validation and asset indexing
8485pub fn create_policy ( env : Env , policy : InsurancePolicy ) -> Result < ( ) , Error > {
85- policy. insurer . require_auth ( ) ;
86-
86+ // Validate coverage and deductible
8787 if policy. coverage_amount <= 0 || policy. deductible >= policy. coverage_amount {
8888 return Err ( Error :: InvalidPayment ) ;
8989 }
9090
91+ // Validate premium
92+ if policy. premium <= 0 {
93+ return Err ( Error :: InvalidPayment ) ;
94+ }
95+
96+ // Validate dates: start_date must be before end_date
97+ if policy. start_date >= policy. end_date {
98+ return Err ( Error :: InvalidPayment ) ;
99+ }
100+
101+ // Validate that start_date is not in the past (allow current timestamp)
102+ let current_time = env. ledger ( ) . timestamp ( ) ;
103+ if policy. start_date < current_time {
104+ return Err ( Error :: InvalidPayment ) ;
105+ }
106+
91107 let key = DataKey :: Policy ( policy. policy_id . clone ( ) ) ;
92108 let store = env. storage ( ) . persistent ( ) ;
93109
110+ // Check if policy already exists
94111 if store. has ( & key) {
95112 return Err ( Error :: AssetAlreadyExists ) ;
96113 }
97114
115+ // Store the policy
98116 store. set ( & key, & policy) ;
99117
118+ // Maintain asset index: add policy to asset's policy list
100119 let mut list: Vec < BytesN < 32 > > = store
101120 . get ( & DataKey :: AssetPolicies ( policy. asset_id . clone ( ) ) )
102121 . unwrap_or_else ( || Vec :: new ( & env) ) ;
@@ -108,6 +127,135 @@ pub fn create_policy(env: Env, policy: InsurancePolicy) -> Result<(), Error> {
108127 Ok ( ( ) )
109128}
110129
130+ /// Cancel a policy (authorized by holder or insurer)
131+ pub fn cancel_policy ( env : Env , policy_id : BytesN < 32 > , caller : Address ) -> Result < ( ) , Error > {
132+ let store = env. storage ( ) . persistent ( ) ;
133+ let key = DataKey :: Policy ( policy_id. clone ( ) ) ;
134+
135+ let mut policy: InsurancePolicy = store. get ( & key) . ok_or ( Error :: AssetNotFound ) ?;
136+
137+ // Only holder or insurer can cancel
138+ if caller != policy. holder && caller != policy. insurer {
139+ return Err ( Error :: Unauthorized ) ;
140+ }
141+
142+ // Validate status transition: only Active or Suspended policies can be cancelled
143+ if policy. status != PolicyStatus :: Active && policy. status != PolicyStatus :: Suspended {
144+ return Err ( Error :: Unauthorized ) ;
145+ }
146+
147+ policy. status = PolicyStatus :: Cancelled ;
148+ store. set ( & key, & policy) ;
149+
150+ log ! ( & env, "PolicyCancelled: {:?}" , policy_id) ;
151+ Ok ( ( ) )
152+ }
153+
154+ /// Suspend a policy (insurer only)
155+ pub fn suspend_policy ( env : Env , policy_id : BytesN < 32 > , insurer : Address ) -> Result < ( ) , Error > {
156+ let store = env. storage ( ) . persistent ( ) ;
157+ let key = DataKey :: Policy ( policy_id. clone ( ) ) ;
158+
159+ let mut policy: InsurancePolicy = store. get ( & key) . ok_or ( Error :: AssetNotFound ) ?;
160+
161+ // Only insurer can suspend
162+ if insurer != policy. insurer {
163+ return Err ( Error :: Unauthorized ) ;
164+ }
165+
166+ // Validate status transition: only Active policies can be suspended
167+ if policy. status != PolicyStatus :: Active {
168+ return Err ( Error :: Unauthorized ) ;
169+ }
170+
171+ policy. status = PolicyStatus :: Suspended ;
172+ store. set ( & key, & policy) ;
173+
174+ log ! ( & env, "PolicySuspended: {:?}" , policy_id) ;
175+ Ok ( ( ) )
176+ }
177+
178+ /// Expire a policy (permissionless, but requires end_date < current timestamp)
179+ pub fn expire_policy ( env : Env , policy_id : BytesN < 32 > ) -> Result < ( ) , Error > {
180+ let store = env. storage ( ) . persistent ( ) ;
181+ let key = DataKey :: Policy ( policy_id. clone ( ) ) ;
182+
183+ let mut policy: InsurancePolicy = store. get ( & key) . ok_or ( Error :: AssetNotFound ) ?;
184+
185+ let current_time = env. ledger ( ) . timestamp ( ) ;
186+
187+ // Require that end_date has passed
188+ if policy. end_date >= current_time {
189+ return Err ( Error :: Unauthorized ) ;
190+ }
191+
192+ // Validate status transition: only Active or Suspended policies can expire
193+ if policy. status != PolicyStatus :: Active && policy. status != PolicyStatus :: Suspended {
194+ return Err ( Error :: Unauthorized ) ;
195+ }
196+
197+ policy. status = PolicyStatus :: Expired ;
198+ store. set ( & key, & policy) ;
199+
200+ log ! ( & env, "PolicyExpired: {:?}" , policy_id) ;
201+ Ok ( ( ) )
202+ }
203+
204+ /// Renew a policy (insurer only)
205+ pub fn renew_policy (
206+ env : Env ,
207+ policy_id : BytesN < 32 > ,
208+ new_end_date : u64 ,
209+ new_premium : i128 ,
210+ insurer : Address ,
211+ ) -> Result < ( ) , Error > {
212+ let store = env. storage ( ) . persistent ( ) ;
213+ let key = DataKey :: Policy ( policy_id. clone ( ) ) ;
214+
215+ let mut policy: InsurancePolicy = store. get ( & key) . ok_or ( Error :: AssetNotFound ) ?;
216+
217+ // Only insurer can renew
218+ if insurer != policy. insurer {
219+ return Err ( Error :: Unauthorized ) ;
220+ }
221+
222+ // Validate status transition: only Active or Expired policies can be renewed
223+ if policy. status != PolicyStatus :: Active && policy. status != PolicyStatus :: Expired {
224+ return Err ( Error :: Unauthorized ) ;
225+ }
226+
227+ let current_time = env. ledger ( ) . timestamp ( ) ;
228+
229+ // Validate new end date is in the future
230+ if new_end_date <= current_time {
231+ return Err ( Error :: InvalidPayment ) ;
232+ }
233+
234+ // Validate new premium is positive
235+ if new_premium <= 0 {
236+ return Err ( Error :: InvalidPayment ) ;
237+ }
238+
239+ // Update policy
240+ policy. end_date = new_end_date;
241+ policy. premium = new_premium;
242+ policy. status = PolicyStatus :: Active ;
243+ policy. last_payment = current_time;
244+
245+ store. set ( & key, & policy) ;
246+
247+ log ! ( & env, "PolicyRenewed: {:?}" , policy_id) ;
248+ Ok ( ( ) )
249+ }
250+
251+ /// Get all policies for a specific asset
252+ pub fn get_asset_policies ( env : Env , asset_id : BytesN < 32 > ) -> Vec < BytesN < 32 > > {
253+ env. storage ( )
254+ . persistent ( )
255+ . get ( & DataKey :: AssetPolicies ( asset_id) )
256+ . unwrap_or_else ( || Vec :: new ( & env) )
257+ }
258+
111259pub fn file_claim ( env : Env , claim : InsuranceClaim ) -> Result < ( ) , Error > {
112260 claim. claimant . require_auth ( ) ;
113261
0 commit comments