forked from InsurNiffy/niff-Stellar-shurance
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathissue.md1
More file actions
2039 lines (1267 loc) · 90.8 KB
/
Copy pathissue.md1
File metadata and controls
2039 lines (1267 loc) · 90.8 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
# niffyInsure — 125 New Issues
---
## Contract — Oracle price feed integration: on-chain asset price validation before payout
### Description
Approved claim payouts denominated in volatile assets may be worth far more or less than intended at settlement time. Integrating an on-chain oracle price feed allows the contract to validate that the payout asset's current price is within an acceptable band before executing the transfer, protecting the treasury from manipulation during price spikes.
### Tasks
- Define an `OracleConfig` struct storing oracle contract ID, accepted asset pair, and max staleness ledgers.
- Admin setter for oracle config with authentication and `OracleConfigUpdated` event.
- Before payout, call oracle to fetch latest price; revert if price is stale or outside configured band.
- Add tests for stale price rejection, out-of-band rejection, and successful payout within band.
### Additional Requirements
- Oracle integration must be behind a feature flag; default off for MVP.
- Document fallback behavior when oracle is unavailable.
### Acceptance Criteria
- Payouts with stale oracle data revert with a clear error in tests.
- Feature flag disables oracle check entirely when off.
- Oracle config changes are authenticated and emit events.
---
## Contract — Partial claim payout: installment disbursement for large claims
### Description
Large approved claims paid in a single transaction may exceed treasury liquidity at a given moment. Supporting partial payouts—where an approved claim is disbursed in configurable installments—allows the protocol to honor obligations over time without insolvency. Each installment must be tracked on-chain and the claim must not be marked `Paid` until the full amount is disbursed.
### Tasks
- Add `paid_amount: i128` and `installment_count: u32` fields to claim storage.
- Implement `disburse_installment(claim_id, amount)` admin entrypoint transferring partial amounts.
- Mark claim `Paid` only when `paid_amount >= amount`; emit `InstallmentDisbursed` and `ClaimFullyPaid` events.
- Add tests for single full payout, two-installment payout, and over-disbursement revert.
### Additional Requirements
- Installment amounts must be positive and not exceed the remaining unpaid balance.
- Document the expected disbursement cadence in the sweep runbook.
### Acceptance Criteria
- Claim status transitions to `Paid` only after full disbursement in tests.
- Over-disbursement attempts revert with a clear error.
- Indexer can display paid vs outstanding amounts from event data.
---
## Contract — Policy transfer: holder-to-holder ownership reassignment
### Description
Policyholders may need to transfer coverage to another address—for example, when selling an insured asset. A `transfer_policy` entrypoint authenticated by the current holder reassigns ownership while preserving all coverage terms. The new holder inherits all rights including claim filing and renewal, and the transfer is recorded as an on-chain event.
### Tasks
- Implement `transfer_policy(policy_id, new_holder: Address)` authenticated by current holder.
- Update `holder` field in policy storage; emit `PolicyTransferred` with old and new holder addresses.
- Validate that the new holder is not the zero address and is not the same as the current holder.
- Add tests for successful transfer, unauthorized transfer, and self-transfer revert.
### Additional Requirements
- Open claims at transfer time remain associated with the original filer, not the new holder.
- Document whether transferred policies reset the renewal window.
### Acceptance Criteria
- Transferred policies are queryable by the new holder address in tests.
- Unauthorized transfer attempts revert.
- `PolicyTransferred` event is emitted with correct old and new holder values.
---
## Contract — Claim appeal mechanism: second-round voting after initial rejection
### Description
A single voting round may produce incorrect outcomes due to low participation or coordinated voting. An appeal mechanism allows the original claimant to trigger a second voting round after rejection, with a higher quorum requirement and a shorter deadline. Appeals must be rate-limited per claim to prevent indefinite delays.
### Tasks
- Add `appeal_count: u32` and `appeal_deadline_ledger: u32` fields to claim storage.
- Implement `appeal_claim(claim_id)` authenticated by claimant; allowed only once per claim after `Rejected` status.
- Reset vote counts, set new deadline, and require elevated quorum for appeal round.
- Add tests for successful appeal, double-appeal revert, and appeal after non-rejection revert.
### Additional Requirements
- Appeal quorum must be configurable separately from initial quorum.
- Emit `ClaimAppealed` event with appeal round number.
### Acceptance Criteria
- Appeal resets vote counts and sets a new deadline in tests.
- Double-appeal attempts revert with a clear error.
- Appeal quorum is enforced at finalization of the appeal round.
---
## Contract — Whitelist-gated policy initiation: KYC address registry check
### Description
Regulatory requirements may mandate that only KYC-verified addresses can initiate policies. A whitelist registry stored in instance storage allows the admin to gate `initiate_policy` calls without redeployment. The whitelist check must be bypassable via a feature flag for permissionless deployments.
### Tasks
- Store `whitelist_enabled: bool` and `whitelisted: Map<Address, bool>` in instance storage.
- Admin entrypoints to add/remove addresses and toggle whitelist enforcement.
- `initiate_policy` checks whitelist when enabled; reverts with `NotWhitelisted` error if not present.
- Add tests for whitelisted address success, non-whitelisted revert, and disabled whitelist bypass.
### Additional Requirements
- Batch add/remove entrypoints for operational efficiency.
- Emit `WhitelistUpdated` event on each add/remove operation.
### Acceptance Criteria
- Non-whitelisted addresses cannot initiate policies when whitelist is enabled.
- Whitelist disabled allows any address to initiate policies.
- Batch operations are authenticated and emit individual events per address.
---
## Contract — Premium refund on early termination: pro-rata calculation and transfer
### Description
When a policyholder terminates a policy before expiry, they should receive a pro-rata refund of the unused premium. The refund amount must be calculated based on remaining ledgers relative to total policy duration, transferred from the treasury, and recorded as an on-chain event. Termination with open claims must be blocked.
### Tasks
- Implement `terminate_policy(policy_id)` authenticated by holder.
- Calculate refund as `premium * remaining_ledgers / total_ledgers`; transfer from treasury.
- Block termination if any claim is in `Processing` status.
- Emit `PolicyTerminated` with refund amount; add tests for mid-term, near-expiry, and blocked termination.
### Additional Requirements
- Minimum refund threshold: do not transfer dust amounts below a configurable minimum.
- Document rounding behavior for the pro-rata calculation.
### Acceptance Criteria
- Refund amounts match expected pro-rata values in tests.
- Termination with open claims reverts with a clear error.
- Treasury balance decreases by the correct refund amount in tests.
---
## Contract — Claim cooldown period: minimum ledger gap between successive claims per policy
### Description
Without a cooldown, a policyholder could file claims in rapid succession, overwhelming the governance system. A per-policy cooldown enforces a minimum ledger gap between the resolution of one claim and the filing of the next. The cooldown duration must be admin-configurable and must not apply to the first claim on a policy.
### Tasks
- Store `last_claim_resolved_ledger: u32` per policy; update on claim finalization.
- `file_claim` reverts with `CooldownActive` if `current_ledger - last_resolved < cooldown_ledgers`.
- Admin setter for `cooldown_ledgers` with bounds and `CooldownUpdated` event.
- Add tests for first claim (no cooldown), within-cooldown revert, and post-cooldown success.
### Additional Requirements
- Cooldown must not apply to withdrawn claims; only finalized (approved/rejected) claims reset the timer.
- Document interaction with the rolling claim cap.
### Acceptance Criteria
- Claims filed within the cooldown window revert in tests.
- First claim on a policy is never blocked by cooldown.
- Admin cooldown updates do not affect in-progress claims.
---
## Contract — Storage TTL bump on policy activity: prevent expiry of active policy data
### Description
Soroban persistent storage entries have TTLs that must be explicitly extended. Active policies and their associated claims must have their storage TTLs bumped on every mutating operation to prevent data expiry during long-running policies. A keeper entrypoint must allow anyone to bump TTLs for policies approaching expiry.
### Tasks
- Call `env.storage().persistent().extend_ttl(key, threshold, extend_to)` on every policy and claim write.
- Implement `bump_policy_ttl(policy_id)` permissionless keeper entrypoint.
- Define TTL constants aligned with Stellar protocol recommendations.
- Add tests verifying TTL is extended after policy creation and claim filing.
### Additional Requirements
- TTL bump must cover the full expected policy duration plus a safety buffer.
- Document the keeper cadence required to keep long-duration policies alive.
### Acceptance Criteria
- Policy data is not expired during a simulated long-duration test.
- Keeper entrypoint successfully extends TTL without other side effects.
- TTL constants are documented with rationale.
---
## Contract — Cross-contract calculator interface: versioned ABI for premium plugins
### Description
The premium calculator is a separate contract that the main contract calls via cross-contract invocation. The interface between them must be versioned so that calculator upgrades do not silently break the main contract. A version check at initialization and a compatibility assertion before each calculation call ensures ABI alignment.
### Tasks
- Define a `CalculatorInterface` trait with a `version() -> u32` method.
- Main contract stores expected calculator version; asserts match before each call.
- Admin entrypoint to update calculator contract ID and expected version atomically.
- Add tests for version mismatch revert and successful cross-contract call.
### Additional Requirements
- Version mismatch must produce a clear error distinguishable from calculation errors.
- Document the versioning scheme and upgrade procedure in `CALCULATOR-INTERFACE.md`.
### Acceptance Criteria
- Version mismatch reverts with a distinct error code in tests.
- Calculator update is atomic: both contract ID and version update together or neither does.
- Cross-contract call succeeds when versions match.
---
## Contract — Emergency pause with reason code: categorized halt for incident response
### Description
The existing pause toggle lacks context about why the contract was halted. Adding a reason code enum to the pause operation allows incident responders and users to understand the nature of the halt from on-chain data alone, without requiring off-chain communication. Reason codes must be documented and stable across contract versions.
### Tasks
- Define `PauseReason` enum with variants: `SecurityIncident`, `UpgradePending`, `SolvencyRisk`, `Regulatory`.
- Update `set_paused` to accept a `reason: PauseReason` parameter; store alongside pause state.
- Emit `PauseToggled` event with reason code on every pause/unpause.
- Add tests for each reason code and verify reason is readable via a getter.
### Additional Requirements
- Unpause must clear the stored reason code.
- Document each reason code's expected response procedure in `SECURITY.md`.
### Acceptance Criteria
- Pause reason is readable via simulation without authentication.
- Each reason code variant is covered by a test.
- Unpause clears the reason code in storage.
---
## Contract — Claim evidence URL count validation: per-filing minimum and maximum enforcement
### Description
Claims with zero evidence URLs should be rejected at filing time as they provide no basis for governance voting. Similarly, the existing maximum evidence count config must be enforced consistently. This item adds a minimum evidence count (configurable, default 1) alongside the existing maximum, with both validated atomically at `file_claim`.
### Tasks
- Store `min_evidence_count: u32` in instance storage; admin setter with event.
- `file_claim` reverts with `InsufficientEvidence` if evidence count < min or > max.
- Add tests for zero evidence, below-min, at-min, at-max, and above-max inputs.
- Document the default values and rationale.
### Additional Requirements
- Min must always be ≤ max; setter must enforce this invariant.
- Emit `MinEvidenceCountUpdated` event on changes.
### Acceptance Criteria
- Zero-evidence claims revert in tests.
- Min/max boundary conditions are all covered by tests.
- Admin cannot set min > max.
---
## Contract — Governance token voting weight: stake-proportional vote power
### Description
Equal voting weight regardless of stake creates governance capture risks. When the governance token feature is active, vote power should be proportional to the voter's token balance at the snapshot ledger. The weight calculation must be capped to prevent whale dominance and must fall back to equal weight when the governance token feature is disabled.
### Tasks
- When governance token is enabled, read voter balance from snapshot and compute weight as `min(balance, max_weight_cap)`.
- Store `max_weight_cap: i128` in instance storage; admin setter with event.
- Fall back to weight = 1 when governance token feature is disabled.
- Add tests for proportional weight, cap enforcement, and fallback behavior.
### Additional Requirements
- Weight calculation must use the snapshot balance, not the current balance.
- Document the cap rationale and expected distribution assumptions.
### Acceptance Criteria
- Vote weights match expected proportional values in tests.
- Cap prevents any single voter from exceeding the documented maximum weight.
- Fallback to equal weight works correctly when feature is disabled.
---
## Contract — Policy metadata URI: off-chain document link stored on-chain
### Description
Insurance policies typically reference a legal document describing coverage terms. Storing a metadata URI on-chain allows policyholders and auditors to retrieve the governing document for any policy without relying on the backend. The URI must be validated as non-empty at policy creation and must be updatable by the admin for document version changes.
### Tasks
- Add `metadata_uri: String` field to `Policy` struct; validate non-empty at `initiate_policy`.
- Admin entrypoint `update_policy_metadata_uri(policy_id, new_uri)` with authentication and event.
- Emit `PolicyMetadataUpdated` event with old and new URI values.
- Add tests for empty URI rejection, successful storage, and admin update.
### Additional Requirements
- URI format validation: must start with `https://` or `ipfs://`.
- Document that URI content is not verified on-chain.
### Acceptance Criteria
- Empty URI reverts at policy creation.
- Invalid URI format reverts with a clear error.
- Admin URI updates are authenticated and emit events.
---
## Contract — Claim dispute window: post-finalization challenge period
### Description
Finalized claims may have been decided on fraudulent evidence. A short dispute window after finalization allows the admin to flag a claim for review before the payout transfer executes. During the dispute window, the payout is held in escrow within the contract. If no dispute is raised, the payout executes automatically after the window closes.
### Tasks
- Add `dispute_window_ledgers: u32` config and `dispute_deadline_ledger: u32` per claim.
- After finalization, set dispute deadline; payout executes only after deadline passes.
- Admin `dispute_claim(claim_id)` freezes payout and sets status to `Disputed`.
- Add tests for undisputed payout after window, disputed freeze, and window expiry.
### Additional Requirements
- Dispute window must be configurable within absolute bounds.
- Emit `ClaimDisputed` and `DisputeWindowExpired` events.
### Acceptance Criteria
- Payouts do not execute before the dispute window closes in tests.
- Admin dispute freezes payout correctly.
- Undisputed claims auto-execute after the window in tests.
---
## Contract — Batch claim finalization: keeper processes multiple expired deadlines in one call
### Description
Processing claim deadlines one at a time is inefficient for keepers when many claims expire simultaneously. A batch finalization entrypoint allows a keeper to process up to a configurable maximum number of expired claims in a single transaction, reducing keeper operational costs and improving governance liveness.
### Tasks
- Implement `finalize_expired_batch(claim_ids: Vec<u32>)` permissionless entrypoint.
- Process each claim independently; skip already-finalized claims without reverting.
- Cap batch size at a documented maximum; revert if exceeded.
- Emit individual finalization events per claim; emit `BatchFinalized` summary event.
- Add tests for full batch, partial batch with already-finalized claims, and over-cap revert.
### Additional Requirements
- Batch must not exceed Soroban instruction limits; document the safe maximum.
- Individual claim errors must not abort the entire batch.
### Acceptance Criteria
- Batch processes all eligible claims and skips ineligible ones in tests.
- Over-cap input reverts before any processing.
- Individual finalization events are emitted for each processed claim.
## Contract — Reinsurance pool integration: secondary treasury for catastrophic claims
### Description
A single treasury pool may be insufficient for catastrophic loss events affecting many policies simultaneously. A reinsurance pool—a secondary contract or storage bucket—can absorb overflow when the primary treasury is depleted. The main contract must check primary treasury balance before falling back to the reinsurance pool, with clear accounting for each source.
### Tasks
- Add `reinsurance_contract_id: Option<Address>` to instance storage; admin setter with event.
- Payout logic: attempt primary treasury first; if insufficient, draw from reinsurance pool.
- Emit `ReinsuranceDrawdown` event when reinsurance is used, with amounts from each source.
- Add tests for primary-sufficient, primary-insufficient with reinsurance, and no-reinsurance revert.
### Additional Requirements
- Reinsurance pool must implement the same token interface as the primary treasury.
- Document the accounting implications for solvency monitoring.
### Acceptance Criteria
- Reinsurance drawdown occurs only when primary treasury is insufficient in tests.
- `ReinsuranceDrawdown` event contains correct amounts from each source.
- No reinsurance configured causes revert when primary treasury is insufficient.
---
## Contract — Policy type registry: admin-managed coverage product catalog
### Description
Hardcoded policy types limit product flexibility. An admin-managed registry of valid policy types with associated coverage parameters allows new products to be launched without contract redeployment. The registry must enforce that `initiate_policy` only accepts registered types and that deregistered types cannot be used for new policies.
### Tasks
- Store `policy_type_registry: Map<String, PolicyTypeConfig>` in instance storage.
- Admin entrypoints to register, update, and deregister policy types with events.
- `initiate_policy` validates that the requested type is in the registry and active.
- Add tests for valid type, unregistered type revert, and deregistered type revert.
### Additional Requirements
- Deregistering a type must not affect existing policies of that type.
- `PolicyTypeConfig` must include min/max coverage amounts and allowed assets.
### Acceptance Criteria
- Unregistered policy types revert at initiation in tests.
- Existing policies of a deregistered type remain valid.
- Registry changes are authenticated and emit events.
---
## Contract — Claim fraud score: on-chain risk signal from oracle
### Description
An external fraud scoring oracle can provide a risk signal for each claim based on off-chain analysis. Storing this score on-chain and surfacing it to voters gives governance participants additional context. High-risk claims may require elevated quorum. The score must be optional and must not block claim filing if the oracle is unavailable.
### Tasks
- Add `fraud_score: Option<u32>` field to claim storage (0–100 scale).
- Admin or oracle entrypoint `set_claim_fraud_score(claim_id, score)` with authentication.
- If score exceeds a configurable threshold, require elevated quorum at finalization.
- Add tests for score below threshold (normal quorum), above threshold (elevated quorum), and absent score.
### Additional Requirements
- Fraud score must be set before voting closes to affect quorum; late scores are ignored.
- Emit `FraudScoreSet` event with claim ID and score.
### Acceptance Criteria
- High-score claims require elevated quorum in finalization tests.
- Missing fraud score uses standard quorum.
- Score setter is authenticated and emits events.
---
## Contract — Voter eligibility snapshot: block-height-anchored eligibility freeze
### Description
Voter eligibility determined at vote time rather than at claim filing time allows eligibility manipulation by acquiring tokens after a claim is filed. Freezing eligibility at the filing ledger via a snapshot prevents this attack. The snapshot must be taken atomically with claim creation and must be immutable thereafter.
### Tasks
- At `file_claim`, snapshot the current eligible voter set (or token balances) into claim storage.
- `cast_vote` validates voter eligibility against the snapshot, not current state.
- Snapshot must be immutable after creation; no admin override.
- Add tests for voter eligible at filing but not at vote time (should succeed) and vice versa (should fail).
### Additional Requirements
- Snapshot storage must be bounded; document the maximum eligible voter set size.
- Document the gas cost implications of large voter sets.
### Acceptance Criteria
- Voters eligible at filing but not at vote time can still vote in tests.
- Voters not eligible at filing cannot vote even if they become eligible later.
- Snapshot is immutable after claim creation.
---
## Contract — Admin role delegation: temporary operator grants with expiry
### Description
The primary admin key should not be used for routine operations. A delegation mechanism allows the admin to grant temporary operator roles to other addresses with a specific permission set and expiry ledger. Expired delegations are automatically invalid without requiring explicit revocation.
### Tasks
- Store `delegations: Map<Address, DelegationConfig>` with permissions and expiry ledger.
- Admin entrypoints to grant and revoke delegations with events.
- Guarded entrypoints check delegation validity (not expired, correct permission) before executing.
- Add tests for valid delegation, expired delegation revert, wrong permission revert, and revocation.
### Additional Requirements
- Delegations must not grant more permissions than the delegating admin holds.
- Emit `DelegationGranted` and `DelegationRevoked` events.
### Acceptance Criteria
- Expired delegations are rejected without explicit revocation in tests.
- Delegated operators can only perform permitted operations.
- Admin cannot delegate permissions they do not hold.
---
## Contract — Coverage gap detection: revert on policy lapse before renewal
### Description
A policy that has lapsed (expired without renewal) must not accept new claims. Currently, the expiry check may have edge cases where a claim filed in the same ledger as expiry is accepted. This item hardens the expiry check to be strictly less-than and adds a test suite covering the exact expiry ledger boundary.
### Tasks
- Audit all `is_active` and expiry checks; replace `<=` with `<` where appropriate.
- Add boundary tests: claim at `end_ledger - 1` (success), at `end_ledger` (revert), at `end_ledger + 1` (revert).
- Add similar boundary tests for renewal eligibility.
- Document the chosen boundary semantics (inclusive vs exclusive) in code comments.
### Additional Requirements
- Boundary semantics must be consistent across all entrypoints that check policy validity.
- Document the boundary decision in the renewal runbook.
### Acceptance Criteria
- Claims at the exact expiry ledger revert in tests.
- Claims one ledger before expiry succeed.
- Boundary semantics are consistent across all policy validity checks.
---
## Contract — Claim amount denomination validation: asset-specific minimum and maximum
### Description
Claim amounts must be validated against asset-specific minimums and maximums to prevent dust claims and claims exceeding coverage. These bounds must be stored per allowed asset and enforced at `file_claim`. The bounds must be updatable by the admin without affecting in-progress claims.
### Tasks
- Add `min_claim_amount: i128` and `max_claim_amount: i128` to `AllowedAsset` config.
- `file_claim` validates claim amount against the asset's bounds; reverts with specific errors.
- Admin entrypoint to update asset bounds with authentication and event.
- Add tests for below-min, above-max, at-min, and at-max claim amounts.
### Additional Requirements
- Max claim amount must not exceed the policy's coverage amount.
- Emit `AssetBoundsUpdated` event on changes.
### Acceptance Criteria
- Dust claims below minimum revert with a clear error.
- Claims exceeding maximum revert with a clear error.
- Bound updates do not affect in-progress claims.
---
## Contract — Finalization quorum calculation: eligible voter count from snapshot
### Description
Quorum is currently calculated against a hardcoded eligible voter count. The calculation must use the actual eligible voter count from the claim's snapshot to be accurate. This requires the snapshot to store the total eligible count alongside individual voter eligibility, and the finalization logic to read this count.
### Tasks
- Store `eligible_voter_count: u32` in the claim snapshot at filing time.
- Finalization reads `eligible_voter_count` from snapshot for quorum calculation.
- Add tests with varying eligible voter counts verifying correct quorum thresholds.
- Document the source of eligible voter count (governance token holders, whitelist, etc.).
### Additional Requirements
- Zero eligible voters must be handled gracefully (revert or auto-approve per product spec).
- Document the expected range of eligible voter counts for gas estimation.
### Acceptance Criteria
- Quorum calculations use snapshot eligible count, not a hardcoded value, in tests.
- Zero eligible voter edge case is handled without silent failures.
- Finalization outcomes match expected results for boundary quorum inputs.
---
## Contract — Asset allowlist event: emit on add and remove for indexer sync
### Description
The backend indexer needs to maintain a synchronized copy of the allowed asset list to display correct asset metadata. Currently, asset allowlist changes may not emit events that the indexer can reliably detect. This item ensures `AssetAdded` and `AssetRemoved` events are emitted on every allowlist change with sufficient data for the indexer.
### Tasks
- Emit `AssetAdded` event with contract ID, symbol hint, and decimals on allowlist addition.
- Emit `AssetRemoved` event with contract ID on removal.
- Ensure events are emitted even when the asset was previously in the same state (idempotent add/remove).
- Add tests verifying event emission for add, remove, and re-add operations.
### Additional Requirements
- Events must include enough data for the indexer to populate `AllowedAsset` table without additional RPC calls.
- Document the event schema in `EVENT_DICTIONARY.md`.
### Acceptance Criteria
- Indexer can populate `AllowedAsset` table from events alone in tests.
- Re-adding an already-allowed asset emits an event without reverting.
- Event schema matches the `EVENT_DICTIONARY.md` specification.
---
## Contract — Claim payout timeout: auto-reject if treasury cannot pay within window
### Description
An approved claim that cannot be paid due to treasury insolvency should not remain in `Approved` status indefinitely. A configurable payout timeout ledger window after approval triggers an auto-rejection with a distinct `PayoutTimeout` status, allowing the claimant to refile when the treasury is replenished.
### Tasks
- Add `payout_deadline_ledger: u32` to claim storage; set at approval time.
- Keeper entrypoint `process_payout_timeout(claim_id)` transitions to `PayoutTimeout` if deadline passed and not paid.
- Emit `PayoutTimedOut` event with claim ID and deadline ledger.
- Add tests for payout within deadline, timeout after deadline, and premature timeout revert.
### Additional Requirements
- `PayoutTimeout` status must be distinct from `Rejected` in all displays.
- Document the expected payout timeout window relative to treasury replenishment cadence.
### Acceptance Criteria
- Claims not paid within the timeout window transition to `PayoutTimeout` in tests.
- Premature timeout keeper calls revert.
- `PayoutTimedOut` event is emitted with correct data.
---
## Contract — Wasm hash verification: deployment integrity check entrypoint
### Description
After a contract upgrade, operators need to verify that the deployed wasm matches the expected build artifact. A `get_wasm_hash() -> BytesN<32>` entrypoint returning the current contract's wasm hash allows automated deployment verification without requiring external tooling to parse ledger state directly.
### Tasks
- Implement `get_wasm_hash() -> BytesN<32>` using `env.current_contract_address()` and Soroban wasm hash APIs.
- Add a test asserting the returned hash is non-zero.
- Wire backend deployment registry to call this after each upgrade and compare against the expected hash.
- Document the hash format and how to compute the expected hash from a local build.
### Additional Requirements
- Entrypoint must be callable without authentication.
- Document the relationship between this hash and the `wasm-release.md` artifact hashes.
### Acceptance Criteria
- Returned hash is non-zero and consistent across repeated calls in tests.
- Backend deployment registry records and compares the hash after upgrades.
- Hash format is documented with a verification example.
---
## Contract — Per-asset premium table: coverage-amount-to-premium mapping per token
### Description
Different assets have different risk profiles and liquidity characteristics. The premium table must be configurable per allowed asset rather than using a single global table. This allows the protocol to price USDC-denominated policies differently from XLM-denominated ones without separate contract deployments.
### Tasks
- Extend premium table storage to be keyed by `(asset_contract_id, coverage_tier)`.
- Admin entrypoint to set premium table entries per asset with authentication and events.
- `quote` and `initiate_policy` use the asset-specific table; fall back to default table if asset-specific entry is absent.
- Add tests for asset-specific pricing, fallback to default, and missing asset revert.
### Additional Requirements
- Default table must remain functional for backward compatibility.
- Emit `PremiumTableUpdated` event with asset ID and tier on each change.
### Acceptance Criteria
- Asset-specific premium tables return correct values in tests.
- Fallback to default table works when no asset-specific entry exists.
- Missing asset with no default entry reverts with a clear error.
---
## Contract — Claim evidence IPFS CID validation: format check before storage
### Description
Evidence URLs stored on-chain should be valid IPFS CIDs or allowlisted gateway URLs. Storing arbitrary strings wastes storage and creates display issues in the frontend. A format validation step at `file_claim` rejects evidence entries that do not match expected patterns, reducing garbage data in claim storage.
### Tasks
- Implement `validate_evidence_url(url: &str) -> bool` checking for `ipfs://` prefix or allowlisted gateway prefix.
- Apply validation to each evidence entry at `file_claim`; revert with `InvalidEvidenceUrl` on failure.
- Admin entrypoint to update the gateway allowlist prefix list.
- Add tests for valid IPFS CID, valid gateway URL, invalid URL, and empty string.
### Additional Requirements
- Validation must be a prefix check only; full URL parsing is too expensive on-chain.
- Document the accepted URL formats in the contract comments.
### Acceptance Criteria
- Invalid evidence URLs revert at filing in tests.
- Valid IPFS and gateway URLs are accepted.
- Gateway allowlist is updatable by admin without redeployment.
---
## Contract — Claim vote delegation: assign voting rights to another address
### Description
Token holders who cannot actively participate in governance may want to delegate their voting rights to a trusted representative. A delegation registry allows a holder to assign their vote weight to another address for a configurable period. The delegate votes on behalf of the delegator; the delegator cannot vote directly while delegation is active.
### Tasks
- Store `vote_delegations: Map<Address, DelegationEntry>` with delegate address and expiry ledger.
- `cast_vote` checks if voter has an active delegation; if so, rejects direct vote with `VoteDelegated` error.
- Delegate's vote weight includes their own weight plus all active delegators' weights.
- Add tests for delegation, delegated vote, direct vote while delegated revert, and delegation expiry.
### Additional Requirements
- Circular delegations must be detected and rejected.
- Emit `VoteDelegated` and `VoteDelegationRevoked` events.
### Acceptance Criteria
- Delegated votes carry combined weight in tests.
- Direct votes while delegation is active revert.
- Circular delegation attempts revert with a clear error.
---
## Contract — Protocol fee: configurable basis-point fee on premium payments
### Description
The protocol needs a sustainable revenue model. A configurable basis-point fee deducted from each premium payment before it enters the treasury provides protocol revenue without requiring separate fee collection logic. The fee must be sent to a configurable fee recipient address and must be adjustable by the admin within absolute bounds.
### Tasks
- Store `protocol_fee_bps: u32` and `fee_recipient: Address` in instance storage; admin setters with events.
- Deduct fee from premium at `initiate_policy`; transfer fee to recipient and remainder to treasury.
- Emit `ProtocolFeeCollected` event with policy ID, fee amount, and recipient.
- Add tests for zero fee, non-zero fee, max fee, and fee recipient update.
### Additional Requirements
- Maximum fee must be bounded (e.g. 1000 bps = 10%) to prevent admin abuse.
- Fee calculation must round down to avoid overcharging.
### Acceptance Criteria
- Fee amounts match expected basis-point calculations in tests.
- Fee recipient receives correct amount in token transfer tests.
- Admin cannot set fee above the absolute maximum.
## Contract — Claim status webhook trigger: on-chain event for off-chain notification
### Description
The backend notification service needs a reliable trigger for claim status changes. While the indexer already processes events, adding explicit `ClaimStatusChanged` events with old and new status values makes the notification trigger unambiguous and reduces the risk of missed transitions during indexer restarts.
### Tasks
- Emit `ClaimStatusChanged` event on every status transition with `claim_id`, `old_status`, and `new_status`.
- Ensure emission covers all transition paths: filing, voting, finalization, payout, withdrawal.
- Add tests verifying event emission for each transition type.
- Update `EVENT_DICTIONARY.md` with the new event schema.
### Additional Requirements
- Event must be emitted even for admin-forced status changes.
- Document which transitions are possible from each status.
### Acceptance Criteria
- Every status transition emits a `ClaimStatusChanged` event in tests.
- Event schema matches `EVENT_DICTIONARY.md`.
- No transition path is missing event emission.
---
## Contract — Policy renewal with coverage upgrade: allow tier change at renewal
### Description
Policyholders renewing a policy may want to upgrade their coverage tier at the same time. The renewal entrypoint must accept an optional new coverage tier and premium amount, validate the upgrade against the premium table, and apply the new terms from the renewal ledger onward. Downgrades must be explicitly allowed or blocked per product spec.
### Tasks
- Extend `renew_policy` to accept optional `new_coverage_tier` and `new_coverage_amount` parameters.
- Validate new terms against the premium table; charge the difference or new full premium.
- Emit `PolicyRenewed` event with old and new coverage terms.
- Add tests for renewal without change, upgrade, and (if blocked) downgrade revert.
### Additional Requirements
- Coverage changes must take effect from the new policy period start, not retroactively.
- Document whether mid-term upgrades are supported or only at renewal.
### Acceptance Criteria
- Renewal with upgrade applies new terms from the renewal ledger in tests.
- Premium charged matches the new tier's table entry.
- `PolicyRenewed` event contains both old and new coverage terms.
---
## Contract — Claim payout asset override: pay in different asset than premium
### Description
Some claim scenarios may warrant payout in a stable asset (e.g. USDC) even when the premium was paid in a volatile asset (e.g. XLM). An admin-configurable payout asset override per policy type allows the protocol to offer stable payouts without requiring policyholders to pay premiums in stablecoins.
### Tasks
- Add `payout_asset_override: Option<Address>` to `PolicyTypeConfig` in the registry.
- Payout logic uses override asset if set; falls back to premium asset otherwise.
- Emit `PayoutAssetOverrideApplied` event when override is used.
- Add tests for override active, override absent (fallback), and override asset not allowlisted revert.
### Additional Requirements
- Override asset must be on the allowlist; admin cannot set an unallowlisted override.
- Document the oracle price feed requirement when override asset differs from premium asset.
### Acceptance Criteria
- Payouts use the override asset when configured in tests.
- Unallowlisted override asset reverts at config time.
- Fallback to premium asset works when no override is set.
---
## Contract — Claim evidence update: allow adding evidence before voting starts
### Description
A claimant may have additional evidence to submit after initial filing but before voting begins. Allowing evidence updates during the pre-vote window improves claim quality and reduces appeals. Once voting starts, evidence must be locked to prevent manipulation of in-progress governance rounds.
### Tasks
- Implement `add_claim_evidence(claim_id, new_urls: Vec<EvidenceEntry>)` authenticated by claimant.
- Allow only when `status == Processing` and `approve_votes + reject_votes == 0`.
- Validate new evidence against current `min_evidence_count` and `max_evidence_count` config.
- Emit `ClaimEvidenceUpdated` event; add tests for pre-vote success, post-vote revert, and cap enforcement.
### Additional Requirements
- Evidence update replaces the entire evidence list, not appends, to avoid unbounded growth.
- Document the evidence update window in the claims user guide.
### Acceptance Criteria
- Evidence updates succeed before any votes in tests.
- Updates after first vote revert with a clear error.
- Updated evidence is reflected in `get_claim` return value.
---
## Contract — Solvency ratio check: block new policies when treasury is undercapitalized
### Description
Issuing new policies when the treasury cannot cover existing approved claims is irresponsible. A solvency ratio check at `initiate_policy` compares the treasury balance against the sum of outstanding approved claim amounts plus the new policy's coverage amount. If the ratio falls below a configurable threshold, new policy issuance is blocked.
### Tasks
- Implement `check_solvency_ratio(new_coverage: i128) -> bool` reading treasury balance and outstanding claims.
- `initiate_policy` calls solvency check; reverts with `InsufficientSolvency` if ratio is below threshold.
- Admin setter for `min_solvency_ratio_bps` with bounds and event.
- Add tests for solvent state (success), insolvent state (revert), and threshold boundary.
### Additional Requirements
- Solvency check must use the same asset as the new policy's premium.
- Document the performance implications of reading outstanding claim totals on every policy initiation.
### Acceptance Criteria
- Policy initiation reverts when solvency ratio is below threshold in tests.
- Threshold boundary is correctly enforced.
- Admin can update the threshold within documented bounds.
---
## Contract — Claim batch query: fetch multiple claims by ID in one simulation
### Description
The claims board dashboard needs to fetch multiple claims efficiently. A batch query entrypoint reduces the number of simulation calls required for initial dashboard load, improving frontend performance. The entrypoint must enforce a hard cap on batch size and return `None` for missing claim IDs.
### Tasks
- Implement `get_claims_batch(ids: Vec<u32>) -> Vec<Option<Claim>>` capped at a documented maximum.
- Return `None` for missing IDs without reverting.
- Add tests for full batch, partial hits, empty input, and over-cap revert.
- Document the cap value and rationale.
### Additional Requirements
- Cap must be enforced before any storage reads.
- Return type must be consistent with `get_claim` for frontend parsing.
### Acceptance Criteria
- Over-cap requests revert before any storage reads.
- Mixed present/absent ID batches return correct `None` positions.
- Backend simulation service uses this for bulk dashboard loads.
---
## Contract — Admin action audit log: on-chain record of privileged operations
### Description
Off-chain audit logs can be tampered with or lost. Recording privileged admin operations as on-chain events creates an immutable audit trail that anyone can verify. Every admin entrypoint must emit an `AdminAction` event with the actor address, action type, and relevant parameters.
### Tasks
- Define `AdminAction` event with `actor`, `action_type: String`, and `params: Map<String, String>`.
- Emit `AdminAction` from every admin-authenticated entrypoint.
- Add tests verifying event emission for each admin operation.
- Document the `action_type` string values in `EVENT_DICTIONARY.md`.
### Additional Requirements
- `params` must not include sensitive values like private keys or raw amounts that could be misleading.
- Event must be emitted even when the admin operation is a no-op (e.g. setting same value).
### Acceptance Criteria
- Every admin entrypoint emits an `AdminAction` event in tests.
- Event schema matches `EVENT_DICTIONARY.md`.
- Non-admin callers cannot emit `AdminAction` events.
---
## Contract — Policy region validation: admin-managed region code registry
### Description
Free-text region fields in policies create inconsistency in premium calculations and reporting. An admin-managed registry of valid region codes enforces a closed set at policy initiation. The registry must support hierarchical regions (e.g. country > state) and must be updatable without redeployment.
### Tasks
- Store `region_registry: Map<String, RegionConfig>` in instance storage with admin management entrypoints.
- `initiate_policy` validates region against registry; reverts with `InvalidRegion` if not found.
- `RegionConfig` includes parent region, risk multiplier, and active flag.
- Add tests for valid region, invalid region revert, deactivated region revert, and registry update.
### Additional Requirements
- Deactivating a region must not affect existing policies in that region.
- Emit `RegionRegistryUpdated` event on each change.
### Acceptance Criteria
- Invalid region codes revert at policy initiation in tests.
- Deactivated regions block new policies but not existing ones.
- Risk multiplier from region config is used in premium calculation.
---
## Contract — Claim vote anonymization: commit-reveal scheme for private voting
### Description
Public voting allows early voters to influence later voters, potentially skewing outcomes. A commit-reveal scheme where voters submit a hash commitment in the voting phase and reveal their vote in a reveal phase prevents this influence while maintaining on-chain verifiability. The reveal phase must be time-bounded.
### Tasks
- Add `commit_phase_end_ledger` and `reveal_phase_end_ledger` to claim storage.