@@ -120,6 +120,22 @@ pub enum MarketState {
120120 Canceled = 2 ,
121121}
122122
123+ #[ contracttype]
124+ #[ derive( Clone ) ]
125+ pub struct CreatePoolParams {
126+ pub end_time : u64 ,
127+ pub token : Address ,
128+ pub options_count : u32 ,
129+ pub description : String ,
130+ pub metadata_url : String ,
131+ pub min_stake : i128 ,
132+ pub max_stake : i128 ,
133+ pub initial_liquidity : i128 ,
134+ pub category : Symbol ,
135+ pub private : bool ,
136+ pub whitelist_key : Option < Symbol > ,
137+ }
138+
123139#[ contracttype]
124140#[ derive( Clone ) ]
125141pub struct Pool {
@@ -1159,32 +1175,38 @@ impl PredifiContract {
11591175
11601176 // Validate: category must be in the allowed list
11611177 assert ! (
1162- Self :: validate_category( & env, & category) ,
1178+ Self :: validate_category( & env, & params . category) ,
11631179 "category must be one of the allowed categories"
11641180 ) ;
11651181
11661182 // Validate: token must be on the allowed betting whitelist
1167- if !Self :: is_token_whitelisted ( & env, & token) {
1183+ if !Self :: is_token_whitelisted ( & env, & params . token ) {
11681184 soroban_sdk:: panic_with_error!( & env, PredifiError :: TokenNotWhitelisted ) ;
11691185 }
11701186
11711187 let current_time = env. ledger ( ) . timestamp ( ) ;
11721188
11731189 // Validate: end_time must be in the future
1174- assert ! ( end_time > current_time, "end_time must be in the future" ) ;
1190+ assert ! (
1191+ params. end_time > current_time,
1192+ "end_time must be in the future"
1193+ ) ;
11751194
11761195 // Validate: minimum pool duration (1 hour)
11771196 assert ! (
1178- end_time >= current_time + MIN_POOL_DURATION ,
1197+ params . end_time >= current_time + MIN_POOL_DURATION ,
11791198 "end_time must be at least 1 hour in the future"
11801199 ) ;
11811200
11821201 // Validate: options_count must be at least 2 (binary or more outcomes)
1183- assert ! ( options_count >= 2 , "options_count must be at least 2" ) ;
1202+ assert ! (
1203+ params. options_count >= 2 ,
1204+ "options_count must be at least 2"
1205+ ) ;
11841206
11851207 // Validate: options_count must not exceed maximum limit
11861208 assert ! (
1187- options_count <= MAX_OPTIONS_COUNT ,
1209+ params . options_count <= MAX_OPTIONS_COUNT ,
11881210 "options_count exceeds maximum allowed value"
11891211 ) ;
11901212
@@ -1233,7 +1255,7 @@ impl PredifiContract {
12331255 . unwrap_or ( 0 ) ;
12341256 // Initialize pool data structure
12351257 let pool = Pool {
1236- end_time,
1258+ end_time : params . end_time ,
12371259 resolved : false ,
12381260 canceled : false ,
12391261 state : MarketState :: Active ,
@@ -1271,14 +1293,14 @@ impl PredifiContract {
12711293 }
12721294
12731295 // Update category index
1274- let category_count_key = DataKey :: CatPoolCt ( category. clone ( ) ) ;
1296+ let category_count_key = DataKey :: CatPoolCt ( params . category . clone ( ) ) ;
12751297 let category_count: u32 = env
12761298 . storage ( )
12771299 . persistent ( )
12781300 . get ( & category_count_key)
12791301 . unwrap_or ( 0 ) ;
12801302
1281- let category_index_key = DataKey :: CatPoolIx ( category. clone ( ) , category_count) ;
1303+ let category_index_key = DataKey :: CatPoolIx ( params . category . clone ( ) , category_count) ;
12821304 env. storage ( )
12831305 . persistent ( )
12841306 . set ( & category_index_key, & pool_id) ;
@@ -1615,6 +1637,7 @@ impl PredifiContract {
16151637 amount : i128 ,
16161638 outcome : u32 ,
16171639 referrer : Option < Address > ,
1640+ invite_key : Option < Symbol > ,
16181641 ) {
16191642 Self :: require_not_paused ( & env) ;
16201643 user. require_auth ( ) ;
@@ -1643,6 +1666,32 @@ impl PredifiContract {
16431666 assert ! ( pool. state == MarketState :: Active , "Pool is not active" ) ;
16441667 assert ! ( env. ledger( ) . timestamp( ) < pool. end_time, "Pool has ended" ) ;
16451668
1669+ // Check private pool authorization
1670+ // Check private pool authorization
1671+ if pool. private {
1672+ let whitelist_key_data = DataKey :: Whitelist ( pool_id, user. clone ( ) ) ;
1673+ let is_whitelisted = env
1674+ . storage ( )
1675+ . persistent ( )
1676+ . get ( & whitelist_key_data)
1677+ . unwrap_or ( false ) ;
1678+
1679+ let has_valid_invite = if let Some ( ref pool_key) = pool. whitelist_key {
1680+ if let Some ( ref prov_key) = invite_key {
1681+ pool_key == prov_key
1682+ } else {
1683+ false
1684+ }
1685+ } else {
1686+ false
1687+ } ;
1688+
1689+ assert ! (
1690+ is_whitelisted || user == pool. creator || has_valid_invite,
1691+ "User not authorized for private pool"
1692+ ) ;
1693+ }
1694+
16461695 // Validate: outcome must be within the valid options range
16471696 assert ! (
16481697 outcome < pool. options_count,
@@ -2223,6 +2272,97 @@ impl PredifiContract {
22232272 results
22242273 }
22252274
2275+ /// Add a user to a private pool's whitelist. Only callable by pool creator.
2276+ pub fn add_to_whitelist (
2277+ env : Env ,
2278+ creator : Address ,
2279+ pool_id : u64 ,
2280+ user : Address ,
2281+ ) -> Result < ( ) , PredifiError > {
2282+ Self :: require_not_paused ( & env) ;
2283+ creator. require_auth ( ) ;
2284+
2285+ let pool_key = DataKey :: Pool ( pool_id) ;
2286+ let pool: Pool = env
2287+ . storage ( )
2288+ . persistent ( )
2289+ . get ( & pool_key)
2290+ . expect ( "Pool not found" ) ;
2291+ Self :: extend_persistent ( & env, & pool_key) ;
2292+
2293+ if pool. creator != creator {
2294+ return Err ( PredifiError :: Unauthorized ) ;
2295+ }
2296+
2297+ assert ! ( pool. private, "Pool is not private" ) ;
2298+
2299+ let whitelist_key = DataKey :: Whitelist ( pool_id, user) ;
2300+ env. storage ( ) . persistent ( ) . set ( & whitelist_key, & true ) ;
2301+ Self :: extend_persistent ( & env, & whitelist_key) ;
2302+
2303+ Ok ( ( ) )
2304+ }
2305+
2306+ /// Remove a user from a private pool's whitelist. Only callable by pool creator.
2307+ pub fn remove_from_whitelist (
2308+ env : Env ,
2309+ creator : Address ,
2310+ pool_id : u64 ,
2311+ user : Address ,
2312+ ) -> Result < ( ) , PredifiError > {
2313+ Self :: require_not_paused ( & env) ;
2314+ creator. require_auth ( ) ;
2315+
2316+ let pool_key = DataKey :: Pool ( pool_id) ;
2317+ let pool: Pool = env
2318+ . storage ( )
2319+ . persistent ( )
2320+ . get ( & pool_key)
2321+ . expect ( "Pool not found" ) ;
2322+ Self :: extend_persistent ( & env, & pool_key) ;
2323+
2324+ if pool. creator != creator {
2325+ return Err ( PredifiError :: Unauthorized ) ;
2326+ }
2327+
2328+ assert ! ( pool. private, "Pool is not private" ) ;
2329+
2330+ let whitelist_key = DataKey :: Whitelist ( pool_id, user) ;
2331+ env. storage ( ) . persistent ( ) . remove ( & whitelist_key) ;
2332+
2333+ Ok ( ( ) )
2334+ }
2335+
2336+ /// Check if a user is whitelisted for a private pool.
2337+ pub fn is_whitelisted ( env : Env , pool_id : u64 , user : Address ) -> bool {
2338+ let pool_key = DataKey :: Pool ( pool_id) ;
2339+ let pool: Pool = env
2340+ . storage ( )
2341+ . persistent ( )
2342+ . get ( & pool_key)
2343+ . expect ( "Pool not found" ) ;
2344+ Self :: extend_persistent ( & env, & pool_key) ;
2345+
2346+ if !pool. private {
2347+ return true ;
2348+ }
2349+
2350+ if user == pool. creator {
2351+ return true ;
2352+ }
2353+
2354+ let whitelist_key = DataKey :: Whitelist ( pool_id, user) ;
2355+ let is_whitelisted = env
2356+ . storage ( )
2357+ . persistent ( )
2358+ . get ( & whitelist_key)
2359+ . unwrap_or ( false ) ;
2360+ if env. storage ( ) . persistent ( ) . has ( & whitelist_key) {
2361+ Self :: extend_persistent ( & env, & whitelist_key) ;
2362+ }
2363+ is_whitelisted
2364+ }
2365+
22262366 /// Get comprehensive stats for a pool.
22272367 pub fn get_pool_stats ( env : Env , pool_id : u64 ) -> PoolStats {
22282368 let pool_key = DataKey :: Pool ( pool_id) ;
0 commit comments