@@ -3,7 +3,8 @@ use std::collections::HashMap;
3
3
use astroport_v5:: incentives:: ExecuteMsg ;
4
4
use cosmwasm_std:: {
5
5
ensure_eq, to_json_binary, BankMsg , Coin , CosmosMsg , Decimal , DepsMut , Env , Event , MessageInfo ,
6
- Order :: Ascending , Response , StdResult , Storage , Uint128 , WasmMsg ,
6
+ Order :: { self , Ascending } ,
7
+ Response , StdResult , Storage , Uint128 , WasmMsg ,
7
8
} ;
8
9
use mars_types:: {
9
10
address_provider:: { helpers:: query_contract_addrs, MarsAddressType } ,
@@ -18,7 +19,10 @@ use crate::{
18
19
compute_updated_astro_incentive_states, MaybeMutStorage ,
19
20
} ,
20
21
query:: query_unclaimed_astro_lp_rewards,
21
- state:: { ASTRO_INCENTIVE_STATES , ASTRO_TOTAL_LP_DEPOSITS , ASTRO_USER_LP_DEPOSITS , CONFIG } ,
22
+ state:: {
23
+ ASTRO_INCENTIVE_STATES , ASTRO_TOTAL_LP_DEPOSITS , ASTRO_USER_LP_DEPOSITS , CONFIG ,
24
+ USER_ASTRO_INCENTIVE_STATES ,
25
+ } ,
22
26
ContractError :: { self , NoStakedLp } ,
23
27
} ;
24
28
@@ -232,29 +236,76 @@ fn decrement_staked_lp(
232
236
account_id : & str ,
233
237
lp_coin : & Coin ,
234
238
) -> Result < ( ) , ContractError > {
235
- // Update user staked lp state
236
- ASTRO_USER_LP_DEPOSITS . update (
237
- store,
238
- ( account_id, & lp_coin. denom ) ,
239
- |existing| -> StdResult < _ > {
240
- Ok ( existing
241
- . ok_or ( ContractError :: NoStakedLp {
242
- account_id : account_id. to_string ( ) ,
243
- denom : lp_coin. denom . clone ( ) ,
244
- } ) ?
245
- . checked_sub ( lp_coin. amount ) ?)
246
- } ,
247
- ) ?;
239
+ update_user_staked_lp ( store, lp_coin, account_id) ?;
240
+ update_total_staked_lp ( store, lp_coin) ?;
248
241
249
- // Update total staked lp state
250
- ASTRO_TOTAL_LP_DEPOSITS . update ( store, & lp_coin. denom , |existing| -> StdResult < _ > {
251
- Ok ( existing
252
- . ok_or ( ContractError :: NoDeposits {
242
+ Ok ( ( ) )
243
+ }
244
+
245
+ fn update_user_staked_lp (
246
+ store : & mut dyn Storage ,
247
+ lp_coin : & Coin ,
248
+ account_id : & str ,
249
+ ) -> Result < ( ) , ContractError > {
250
+ let key = ( account_id, lp_coin. denom . as_str ( ) ) ;
251
+ let existing_amount =
252
+ ASTRO_USER_LP_DEPOSITS . may_load ( store, key) ?. ok_or_else ( || ContractError :: NoStakedLp {
253
+ account_id : account_id. to_string ( ) ,
254
+ denom : lp_coin. denom . clone ( ) ,
255
+ } ) ?;
256
+
257
+ let new_amount = existing_amount. checked_sub ( lp_coin. amount ) ?;
258
+ if new_amount. is_zero ( ) {
259
+ ASTRO_USER_LP_DEPOSITS . remove ( store, key) ;
260
+
261
+ // Get all incentives for (user, lp_token_denom) key
262
+ let prefix = USER_ASTRO_INCENTIVE_STATES . prefix ( ( account_id, lp_coin. denom . as_str ( ) ) ) ;
263
+
264
+ // Iterate over all reward_denom keys
265
+ let keys_to_remove =
266
+ prefix. keys ( store, None , None , Order :: Ascending ) . collect :: < StdResult < Vec < String > > > ( ) ?;
267
+
268
+ // Delete each matching (account_id, lp_token_denom, reward_denom) incentive.
269
+ for incentive_denom in keys_to_remove {
270
+ USER_ASTRO_INCENTIVE_STATES
271
+ . remove ( store, ( account_id, lp_coin. denom . as_str ( ) , & incentive_denom) ) ;
272
+ }
273
+ } else {
274
+ ASTRO_USER_LP_DEPOSITS . save ( store, key, & new_amount) ?;
275
+ }
276
+
277
+ Ok ( ( ) )
278
+ }
279
+
280
+ fn update_total_staked_lp ( store : & mut dyn Storage , lp_coin : & Coin ) -> Result < ( ) , ContractError > {
281
+ let lp_denom = lp_coin. denom . as_str ( ) ;
282
+
283
+ let total_staked_lp_amount =
284
+ ASTRO_TOTAL_LP_DEPOSITS . may_load ( store, lp_denom) ?. ok_or_else ( || {
285
+ ContractError :: NoDeposits {
253
286
denom : lp_coin. denom . clone ( ) ,
254
- } ) ?
255
- . checked_sub ( lp_coin. amount ) ?)
256
- } ) ?;
287
+ }
288
+ } ) ?;
289
+
290
+ let new_total_staked_lp_amount = total_staked_lp_amount. checked_sub ( lp_coin. amount ) ?;
291
+
292
+ // If the new amount is zero, remove the entry and all associated incentive states
293
+ if new_total_staked_lp_amount. is_zero ( ) {
294
+ ASTRO_TOTAL_LP_DEPOSITS . remove ( store, lp_denom) ;
295
+
296
+ // Get all incentive states for the lp_key
297
+ let prefix = ASTRO_INCENTIVE_STATES . prefix ( lp_denom) ;
298
+ let keys_to_remove =
299
+ prefix. keys ( store, None , None , Order :: Ascending ) . collect :: < StdResult < Vec < String > > > ( ) ?;
257
300
301
+ // Remove all incentive states related to the lp_key
302
+ for incentive_denom in keys_to_remove {
303
+ ASTRO_INCENTIVE_STATES . remove ( store, ( lp_denom, incentive_denom. as_str ( ) ) ) ;
304
+ }
305
+ } else {
306
+ // Save the updated staked amount if it's not zero
307
+ ASTRO_TOTAL_LP_DEPOSITS . save ( store, lp_denom, & new_total_staked_lp_amount) ?;
308
+ }
258
309
Ok ( ( ) )
259
310
}
260
311
@@ -342,13 +393,17 @@ fn claim_rewards_for_staked_lp_position(
342
393
lp_denom,
343
394
staked_lp_amount,
344
395
) ?;
396
+ let total_claimed_amount =
397
+ user_claimable_rewards. iter ( ) . fold ( Uint128 :: zero ( ) , |acc, coin| acc + coin. amount ) ;
345
398
346
399
for coin in & user_claimable_rewards {
347
400
event = event
348
401
. add_attribute ( "denom" , coin. denom . to_string ( ) )
349
402
. add_attribute ( "amount" , coin. amount . to_string ( ) ) ;
350
403
}
351
- res = if !user_claimable_rewards. is_empty ( ) {
404
+
405
+ // Check if rewards not already claimed in the same block
406
+ res = if !user_claimable_rewards. is_empty ( ) && !total_claimed_amount. is_zero ( ) {
352
407
// Send the claimed rewards to the credit manager
353
408
let send_rewards_to_cm_msg = CosmosMsg :: Bank ( BankMsg :: Send {
354
409
to_address : credit_manager_addr. to_string ( ) ,
0 commit comments