1313//! v2 — full implementation; Risk Pool is now deployable and testable.
1414#![ no_std]
1515extern crate alloc;
16- use alloc:: string:: ToString ;
1716
1817use soroban_sdk:: {
1918 contract, contractimpl, contracttype, contracterror, panic_with_error,
20- token, Address , BytesN , Env , Symbol , Vec ,
19+ token, Address , Env , Symbol , Vec ,
2120} ;
2221
2322pub mod types;
@@ -47,12 +46,16 @@ enum StorageKey {
4746 TotalLocked ,
4847 TotalShares ,
4948 AccumulatedPremium ,
49+ AccumulatedBackstop ,
5050 Status ,
5151 LpPosition ( Address ) ,
52- LpList ,
52+ LpCount ,
53+ LpAddress ( u32 ) ,
5354 Lock ( u128 ) ,
5455 AdminWithdrawalRequest ,
5556 PendingAdmin ,
57+ PolicyEngine ,
58+ ClaimsProcessor ,
5659}
5760
5861#[ contracterror]
@@ -71,10 +74,10 @@ pub enum Error {
7174 AlreadyReleased = 10 ,
7275 Undercollateralized = 11 ,
7376 PoolCapExceeded = 12 ,
74- TimelockPending = 13 ,
75- TimelockNotReady = 14 ,
76- NoPendingWithdrawal = 15 ,
7777 InsufficientShares = 13 ,
78+ TimelockPending = 14 ,
79+ TimelockNotReady = 15 ,
80+ NoPendingWithdrawal = 16 ,
7881}
7982
8083#[ contract]
@@ -90,6 +93,8 @@ impl RiskPool {
9093 treasury : Address ,
9194 backstop : Address ,
9295 category : Symbol ,
96+ policy_engine : Address ,
97+ claims_processor : Address ,
9398 ) {
9499 if env. storage ( ) . instance ( ) . has ( & StorageKey :: Initialized ) {
95100 panic_with_error ! ( & env, Error :: AlreadyInitialized ) ;
@@ -128,29 +133,33 @@ impl RiskPool {
128133 }
129134
130135 admin. require_auth ( ) ;
131- env. storage ( ) . instance ( ) . set ( & StorageKey :: Initialized , & true ) ;
132- env. storage ( ) . instance ( ) . set ( & StorageKey :: Admin , & admin) ;
133- env. storage ( ) . instance ( ) . set ( & StorageKey :: UsdcToken , & usdc_token) ;
134- env. storage ( ) . instance ( ) . set ( & StorageKey :: Treasury , & treasury) ;
135- env. storage ( ) . instance ( ) . set ( & StorageKey :: Backstop , & backstop) ;
136- env. storage ( ) . instance ( ) . set ( & StorageKey :: Category , & category) ;
137- env. storage ( ) . instance ( ) . set ( & StorageKey :: TotalDeposited , & 0i128 ) ;
138- // No pending admin initially
139- env. storage ( ) . instance ( ) . set ( & StorageKey :: PendingAdmin , & Address :: from_uint ( & env, 0 ) ) ;
140- env. storage ( ) . instance ( ) . set ( & StorageKey :: TotalLocked , & 0i128 ) ;
141- env. storage ( ) . instance ( ) . set ( & StorageKey :: TotalShares , & 0i128 ) ;
142- env. storage ( ) . instance ( ) . set ( & StorageKey :: AccumulatedPremium , & 0i128 ) ;
143- env. storage ( ) . instance ( ) . set ( & StorageKey :: Status , & PoolStatus :: Active ) ;
144- env. storage ( ) . instance ( ) . set ( & StorageKey :: LpList , & Vec :: < Address > :: new ( & env) ) ;
136+ env. storage ( ) . instance ( ) . set ( & StorageKey :: Initialized , & true ) ;
137+ env. storage ( ) . instance ( ) . set ( & StorageKey :: Admin , & admin) ;
138+ env. storage ( ) . instance ( ) . set ( & StorageKey :: UsdcToken , & usdc_token) ;
139+ env. storage ( ) . instance ( ) . set ( & StorageKey :: Treasury , & treasury) ;
140+ env. storage ( ) . instance ( ) . set ( & StorageKey :: Backstop , & backstop) ;
141+ env. storage ( ) . instance ( ) . set ( & StorageKey :: Category , & category) ;
142+ env. storage ( ) . instance ( ) . set ( & StorageKey :: PolicyEngine , & policy_engine) ;
143+ env. storage ( ) . instance ( ) . set ( & StorageKey :: ClaimsProcessor , & claims_processor) ;
144+ env. storage ( ) . instance ( ) . set ( & StorageKey :: TotalDeposited , & 0i128 ) ;
145+ env. storage ( ) . instance ( ) . set ( & StorageKey :: TotalLocked , & 0i128 ) ;
146+ env. storage ( ) . instance ( ) . set ( & StorageKey :: TotalShares , & 0i128 ) ;
147+ env. storage ( ) . instance ( ) . set ( & StorageKey :: AccumulatedPremium , & 0i128 ) ;
148+ env. storage ( ) . instance ( ) . set ( & StorageKey :: AccumulatedBackstop , & 0i128 ) ;
149+ env. storage ( ) . instance ( ) . set ( & StorageKey :: Status , & PoolStatus :: Active ) ;
150+ env. storage ( ) . instance ( ) . set ( & StorageKey :: LpCount , & 0u32 ) ;
151+ // PendingAdmin is absent until propose_new_admin is called; no init needed.
145152
146153 env. events ( ) . publish (
147154 ( Symbol :: new ( & env, "initialized" ) , ) ,
148155 Initialized {
149- admin : admin. clone ( ) ,
150- usdc_token : usdc_token. clone ( ) ,
151- treasury : treasury. clone ( ) ,
152- backstop : backstop. clone ( ) ,
153- category : category. clone ( ) ,
156+ admin : admin. clone ( ) ,
157+ usdc_token : usdc_token. clone ( ) ,
158+ treasury : treasury. clone ( ) ,
159+ backstop : backstop. clone ( ) ,
160+ category : category. clone ( ) ,
161+ policy_engine : policy_engine. clone ( ) ,
162+ claims_processor : claims_processor. clone ( ) ,
154163 } ,
155164 ) ;
156165 }
@@ -195,10 +204,10 @@ env.storage().instance().set(&StorageKey::TotalDeposited, &0i128);
195204 pos
196205 }
197206 None => {
198- let mut lp_list : Vec < Address > = env. storage ( ) . instance ( )
199- . get ( & StorageKey :: LpList ) . unwrap_or_else ( || Vec :: new ( & env ) ) ;
200- lp_list . push_back ( provider . clone ( ) ) ;
201- env. storage ( ) . instance ( ) . set ( & StorageKey :: LpList , & lp_list ) ;
207+ let count : u32 = env. storage ( ) . instance ( )
208+ . get ( & StorageKey :: LpCount ) . unwrap_or ( 0 ) ;
209+ env . storage ( ) . persistent ( ) . set ( & StorageKey :: LpAddress ( count ) , & provider ) ;
210+ env. storage ( ) . instance ( ) . set ( & StorageKey :: LpCount , & ( count + 1 ) ) ;
202211 LpPosition {
203212 provider : provider. clone ( ) ,
204213 deposited : amount,
@@ -229,6 +238,7 @@ env.storage().instance().set(&StorageKey::TotalDeposited, &0i128);
229238 provider. require_auth ( ) ;
230239 // Guard: check for zero or negative shares input
231240 if shares <= 0 { panic_with_error ! ( & env, Error :: ZeroAmount ) ; }
241+ Self :: assert_active ( & env) ;
232242
233243 let lp_key = StorageKey :: LpPosition ( provider. clone ( ) ) ;
234244 let mut position: LpPosition = env. storage ( ) . persistent ( )
@@ -293,6 +303,10 @@ env.storage().instance().set(&StorageKey::TotalDeposited, &0i128);
293303 . get ( & StorageKey :: AccumulatedPremium ) . unwrap_or ( 0 ) ;
294304 env. storage ( ) . instance ( ) . set ( & StorageKey :: AccumulatedPremium , & ( acc + lp_share) ) ;
295305
306+ let acc_backstop: i128 = env. storage ( ) . instance ( )
307+ . get ( & StorageKey :: AccumulatedBackstop ) . unwrap_or ( 0 ) ;
308+ env. storage ( ) . instance ( ) . set ( & StorageKey :: AccumulatedBackstop , & ( acc_backstop + backstop_share) ) ;
309+
296310 env. events ( ) . publish (
297311 ( Symbol :: new ( & env, "premium_distributed" ) , ) ,
298312 PremiumDistributed {
@@ -377,7 +391,7 @@ env.storage().instance().set(&StorageKey::TotalDeposited, &0i128);
377391 // ── Capital locks ─────────────────────────────────────────────────────────
378392
379393 pub fn lock_for_policy ( env : Env , caller : Address , policy_id : u128 , amount : i128 ) {
380- Self :: require_admin ( & env, & caller) ;
394+ Self :: require_protocol_caller ( & env, & caller) ;
381395 // Guard: check for zero or negative lock amount input
382396 if amount <= 0 { panic_with_error ! ( & env, Error :: ZeroAmount ) ; }
383397
@@ -404,7 +418,7 @@ env.storage().instance().set(&StorageKey::TotalDeposited, &0i128);
404418 }
405419
406420 pub fn release_for_claim ( env : Env , caller : Address , policy_id : u128 ) {
407- Self :: require_admin ( & env, & caller) ;
421+ Self :: require_protocol_caller ( & env, & caller) ;
408422 let mut lock: CapitalLock = env. storage ( ) . persistent ( )
409423 . get ( & StorageKey :: Lock ( policy_id) )
410424 . unwrap_or_else ( || panic_with_error ! ( & env, Error :: LockNotFound ) ) ;
@@ -428,7 +442,7 @@ env.storage().instance().set(&StorageKey::TotalDeposited, &0i128);
428442 }
429443
430444 pub fn release_for_expiry ( env : Env , caller : Address , policy_id : u128 ) {
431- Self :: require_admin ( & env, & caller) ;
445+ Self :: require_protocol_caller ( & env, & caller) ;
432446 let mut lock: CapitalLock = env. storage ( ) . persistent ( )
433447 . get ( & StorageKey :: Lock ( policy_id) )
434448 . unwrap_or_else ( || panic_with_error ! ( & env, Error :: LockNotFound ) ) ;
@@ -443,12 +457,13 @@ env.storage().instance().set(&StorageKey::TotalDeposited, &0i128);
443457
444458 pub fn get_stats ( env : Env ) -> PoolStats {
445459 PoolStats {
446- category : env. storage ( ) . instance ( ) . get ( & StorageKey :: Category ) . unwrap ( ) ,
447- total_deposited : env. storage ( ) . instance ( ) . get ( & StorageKey :: TotalDeposited ) . unwrap_or ( 0 ) ,
448- total_locked : env. storage ( ) . instance ( ) . get ( & StorageKey :: TotalLocked ) . unwrap_or ( 0 ) ,
449- total_shares : env. storage ( ) . instance ( ) . get ( & StorageKey :: TotalShares ) . unwrap_or ( 0 ) ,
450- accumulated_premium : env. storage ( ) . instance ( ) . get ( & StorageKey :: AccumulatedPremium ) . unwrap_or ( 0 ) ,
451- status : env. storage ( ) . instance ( ) . get ( & StorageKey :: Status ) . unwrap_or ( PoolStatus :: Active ) ,
460+ category : env. storage ( ) . instance ( ) . get ( & StorageKey :: Category ) . unwrap ( ) ,
461+ total_deposited : env. storage ( ) . instance ( ) . get ( & StorageKey :: TotalDeposited ) . unwrap_or ( 0 ) ,
462+ total_locked : env. storage ( ) . instance ( ) . get ( & StorageKey :: TotalLocked ) . unwrap_or ( 0 ) ,
463+ total_shares : env. storage ( ) . instance ( ) . get ( & StorageKey :: TotalShares ) . unwrap_or ( 0 ) ,
464+ accumulated_premium : env. storage ( ) . instance ( ) . get ( & StorageKey :: AccumulatedPremium ) . unwrap_or ( 0 ) ,
465+ accumulated_backstop : env. storage ( ) . instance ( ) . get ( & StorageKey :: AccumulatedBackstop ) . unwrap_or ( 0 ) ,
466+ status : env. storage ( ) . instance ( ) . get ( & StorageKey :: Status ) . unwrap_or ( PoolStatus :: Active ) ,
452467 }
453468 }
454469
@@ -469,31 +484,28 @@ env.storage().instance().set(&StorageKey::TotalDeposited, &0i128);
469484 }
470485
471486 pub fn get_lp_count ( env : Env ) -> u32 {
472- let list: Vec < Address > = env. storage ( ) . instance ( )
473- . get ( & StorageKey :: LpList )
474- . unwrap_or_else ( || Vec :: new ( & env) ) ;
475- list. len ( )
487+ env. storage ( ) . instance ( ) . get ( & StorageKey :: LpCount ) . unwrap_or ( 0 )
476488 }
477489
478490 pub fn get_lp_list ( env : Env , offset : Option < u32 > , limit : Option < u32 > ) -> PaginatedLps {
479- let list: Vec < Address > = env. storage ( ) . instance ( )
480- . get ( & StorageKey :: LpList )
481- . unwrap_or_else ( || Vec :: new ( & env) ) ;
482- let total_count = list. len ( ) ;
483-
491+ let total_count: u32 = env. storage ( ) . instance ( )
492+ . get ( & StorageKey :: LpCount ) . unwrap_or ( 0 ) ;
493+
484494 let offset_val = offset. unwrap_or ( 0 ) ;
485495 let limit_val = core:: cmp:: min ( limit. unwrap_or ( 100 ) , 500 ) ;
486-
496+
487497 let mut paginated = Vec :: new ( & env) ;
488498 if offset_val < total_count {
489499 let end = core:: cmp:: min ( offset_val + limit_val, total_count) ;
490500 for i in offset_val..end {
491- if let Some ( addr) = list. get ( i) {
501+ if let Some ( addr) = env. storage ( ) . persistent ( )
502+ . get :: < _ , Address > ( & StorageKey :: LpAddress ( i) )
503+ {
492504 paginated. push_back ( addr) ;
493505 }
494506 }
495507 }
496-
508+
497509 PaginatedLps {
498510 lps : paginated,
499511 total_count,
@@ -643,19 +655,16 @@ env.storage().instance().set(&StorageKey::TotalDeposited, &0i128);
643655 pub fn accept_admin ( env : Env , admin : Address ) {
644656 let pending_admin: Address = env. storage ( ) . instance ( )
645657 . get ( & StorageKey :: PendingAdmin )
646- . unwrap_or_else ( || Address :: from_uint ( & env, 0 ) ) ;
658+ . unwrap_or_else ( || panic_with_error ! ( & env, Error :: Unauthorized ) ) ;
647659 // Only the pending admin can accept
648660 if admin != pending_admin {
649661 panic_with_error ! ( & env, Error :: Unauthorized ) ;
650662 }
651663 admin. require_auth ( ) ;
652- let current_admin: Address = env. storage ( ) . instance ( )
653- . get ( & StorageKey :: Admin )
654- . unwrap_or_else ( || panic_with_error ! ( env, Error :: NotInitialized ) ) ;
655664 // Update admin
656665 env. storage ( ) . instance ( ) . set ( & StorageKey :: Admin , & admin) ;
657666 // Clear the proposal
658- env. storage ( ) . instance ( ) . set ( & StorageKey :: PendingAdmin , & Address :: from_uint ( & env , 0 ) ) ;
667+ env. storage ( ) . instance ( ) . remove ( & StorageKey :: PendingAdmin ) ;
659668 // Emit event
660669 env. events ( ) . publish (
661670 ( Symbol :: new ( & env, "admin_updated" ) , ) ,
@@ -665,6 +674,21 @@ env.storage().instance().set(&StorageKey::TotalDeposited, &0i128);
665674 ) ;
666675 }
667676
677+ /// Enforces that only admin, the registered policy engine, or the registered
678+ /// claims processor may call capital-lock functions.
679+ fn require_protocol_caller ( env : & Env , caller : & Address ) {
680+ let admin: Address = env. storage ( ) . instance ( ) . get ( & StorageKey :: Admin )
681+ . unwrap_or_else ( || panic_with_error ! ( env, Error :: NotInitialized ) ) ;
682+ let pe: Address = env. storage ( ) . instance ( ) . get ( & StorageKey :: PolicyEngine )
683+ . unwrap_or_else ( || panic_with_error ! ( env, Error :: NotInitialized ) ) ;
684+ let cp: Address = env. storage ( ) . instance ( ) . get ( & StorageKey :: ClaimsProcessor )
685+ . unwrap_or_else ( || panic_with_error ! ( env, Error :: NotInitialized ) ) ;
686+ if * caller != admin && * caller != pe && * caller != cp {
687+ panic_with_error ! ( env, Error :: Unauthorized ) ;
688+ }
689+ caller. require_auth ( ) ;
690+ }
691+
668692 fn require_admin ( env : & Env , caller : & Address ) {
669693 let admin: Address = env. storage ( ) . instance ( ) . get ( & StorageKey :: Admin )
670694 . unwrap_or_else ( || panic_with_error ! ( env, Error :: NotInitialized ) ) ;
0 commit comments