Skip to content

Commit c083d89

Browse files
committed
improve update_stake instruction to keep track of partially unstake
1 parent a178c0a commit c083d89

File tree

1 file changed

+51
-9
lines changed
  • solana/merkle-distributor/src

1 file changed

+51
-9
lines changed

solana/merkle-distributor/src/lib.rs

Lines changed: 51 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -131,32 +131,74 @@ pub mod merkle_distributor {
131131
amount: u64,
132132
is_staked: bool, //true if staked, false if unstaked
133133
) -> Result<()> {
134+
// Check program ID
134135
let program_id = get_staking_caller(&ctx.accounts.instruction)?;
135136
let staking_contract = ctx.accounts.distributor.staking_contract_address;
136137
if program_id != staking_contract {
137-
panic!("Invalid program id");
138+
panic!("Invalid program ID");
138139
}
140+
141+
// Get the current timestamp
139142
let current_ts = Clock::get()?.unix_timestamp;
140143
let claimer_status = &mut ctx.accounts.claim_status;
144+
141145
if is_staked {
146+
// Handle staking: Add a new item to `staked_list`
142147
claimer_status.staked_list.push(StakedItem {
143148
stake_amount: amount,
144149
stake_timestamp_start: Some(current_ts),
145150
already_staked_duration_time: 0,
146151
});
147152
} else {
148-
let curr_ts = Clock::get()?.unix_timestamp;
149-
let mut _unstake_amount = 0;
150-
for i in claimer_status.staked_list.iter_mut(){
151-
let Some(stake_timestamp_start) = i.stake_timestamp_start else{
153+
// Handle unstaking: Process the required unstake amount
154+
let mut remaining_unstake_amount = amount;
155+
156+
// We need a new list to store updated staked items after partial unstaking
157+
let mut new_staked_item = None;
158+
159+
for staked_item in claimer_status.staked_list.iter_mut() {
160+
if remaining_unstake_amount == 0 {
161+
// If no more amount needs to be unstaked, keep the rest as-is
162+
break;
163+
}
164+
165+
// Only process items that have a start timestamp (still staked)
166+
let Some(stake_timestamp_start) = staked_item.stake_timestamp_start else {
152167
continue;
153168
};
154-
i.stake_timestamp_start = None;
155-
let diff = curr_ts.checked_sub(stake_timestamp_start).ok_or(crate::error::ErrorCode::ArithmeticError)?;
156-
i.already_staked_duration_time = i.already_staked_duration_time.checked_add(diff).ok_or(crate::error::ErrorCode::ArithmeticError)?;
157-
_unstake_amount += i.stake_amount;
169+
170+
// Calculate time staked and update the duration
171+
let time_staked = current_ts.checked_sub(stake_timestamp_start)
172+
.ok_or(crate::error::ErrorCode::ArithmeticError)?;
173+
staked_item.already_staked_duration_time = staked_item
174+
.already_staked_duration_time
175+
.checked_add(time_staked)
176+
.ok_or(crate::error::ErrorCode::ArithmeticError)?;
177+
178+
if staked_item.stake_amount <= remaining_unstake_amount {
179+
// Fully unstake this item and update the remaining amount
180+
remaining_unstake_amount -= staked_item.stake_amount;
181+
} else {
182+
// Partially unstake: Keep original as-is, and create a new item for unstaked portion
183+
new_staked_item = Some(StakedItem {
184+
stake_amount: staked_item.stake_amount - remaining_unstake_amount,
185+
stake_timestamp_start: Some(current_ts), // New start time for remaining amount
186+
already_staked_duration_time: 0,
187+
});
188+
189+
// Adjust the original item to reflect the unstaked portion
190+
staked_item.stake_amount = remaining_unstake_amount;
191+
staked_item.stake_timestamp_start = None;
192+
remaining_unstake_amount = 0;
193+
}
194+
}
195+
196+
if let Some(new_item) = new_staked_item.clone() {
197+
claimer_status.staked_list.push(new_item);
158198
}
199+
159200
}
201+
160202
Ok(())
161203
}
162204
}

0 commit comments

Comments
 (0)