Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions token-lending/program/src/processor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -255,11 +255,13 @@ pub fn process_instruction(
}
LendingInstruction::ClaimReward {
reward_authority_bump,
position_kind,
} => {
msg!("Instruction: Claim Reward");
liquidity_mining::claim_user_reward::process(
program_id,
reward_authority_bump,
position_kind,
accounts,
)
}
Expand Down
4 changes: 2 additions & 2 deletions token-lending/program/src/processor/liquidity_mining.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,10 @@
//! - [close_pool_reward]
//!
//! There is an ix related to migration:
//! - [upgrade_reserve] (TODO: add bpf tests)
//! - [upgrade_reserve] (has anchor integration test)
//!
//! There is one user ix:
//! - [claim_user_reward] (TODO: add bpf tests)
//! - [claim_user_reward]
//!
//! [suilend-lm]: https://github.com/solendprotocol/suilend/blob/dc53150416f352053ac3acbb320ee143409c4a5d/contracts/suilend/sources/liquidity_mining.move#L2

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ struct ClaimUserReward<'a, 'info> {
pub(crate) fn process(
program_id: &Pubkey,
reward_authority_bump: u8,
position_kind: PositionKind,
accounts: &[AccountInfo],
) -> ProgramResult {
let clock = &Clock::get()?;
Expand All @@ -89,90 +90,94 @@ pub(crate) fn process(

// 1.

let position_kind = accounts.obligation.find_position_kind(reserve_key)?;
let pool_reward_manager = accounts.reserve.pool_reward_manager_mut(position_kind);

let Some(user_reward_manager) = accounts
if let Some(user_reward_manager) = accounts
.obligation
.user_reward_managers
.find_mut(reserve_key, position_kind)
else {
{
msg!(
"Found user reward manager that was last updated at {} and has {}/{} shares",
user_reward_manager.last_update_time_secs,
user_reward_manager.share,
pool_reward_manager.total_shares
);

// 2.

let total_reward_amount = user_reward_manager.claim_rewards(
pool_reward_manager,
*accounts.reward_token_vault_info.key,
clock,
)?;

// 3.

if total_reward_amount > 0 {
spl_token_transfer(TokenTransferParams {
source: accounts.reward_token_vault_info.clone(),
destination: accounts.obligation_owner_token_account_info.clone(),
amount: total_reward_amount,
authority: accounts.reward_authority_info.clone(),
authority_signer_seeds: &[
reward_vault_authority_seeds(
accounts.lending_market_info.key,
&accounts.reserve.key(),
accounts.reward_mint_info.key,
)
.as_slice(),
&[&[reward_authority_bump]],
]
.concat(),
token_program: accounts.token_program_info.clone(),
})?;
}
} else {
let expected_position_kind = accounts.obligation.find_position_kind(reserve_key)?;

if expected_position_kind != position_kind {
msg!("Obligation does not have {:?} for reserve", position_kind);
return Err(LendingError::InvalidAccountInput.into());
}

// We've checked that the obligation associates this reserve but it's
// not in the user reward managers yet.
// This means that the obligation hasn't been migrated to track the
// pool reward manager.
//
// We'll upgrade it here.

let reserve_key = accounts.reserve.key();

let (pool_reward_manager, migrated_share) = match position_kind {
PositionKind::Borrow => {
let share = accounts
.obligation
.find_liquidity_in_borrows(reserve_key)?
.0
.liability_shares()?;

(&mut accounts.reserve.borrows_pool_reward_manager, share)
}
let migrated_share = match position_kind {
PositionKind::Borrow => accounts
.obligation
.find_liquidity_in_borrows(reserve_key)?
.0
.liability_shares()?,
PositionKind::Deposit => {
let share = accounts
accounts
.obligation
.find_collateral_in_deposits(reserve_key)?
.0
.deposited_amount;

(&mut accounts.reserve.deposits_pool_reward_manager, share)
.deposited_amount
}
};

msg!(
"Migrating obligation to track pool reward manager with share of {}/{}",
migrated_share,
pool_reward_manager.total_shares
);

accounts.obligation.user_reward_managers.set_share(
reserve_key,
position_kind,
pool_reward_manager,
migrated_share,
clock,
)?;

realloc_obligation_if_necessary(&accounts.obligation, accounts.obligation_info)?;
Obligation::pack(
*accounts.obligation,
&mut accounts.obligation_info.data.borrow_mut(),
)?;

return Ok(());
};

let pool_reward_manager = accounts.reserve.pool_reward_manager_mut(position_kind);

// 2.

let total_reward_amount = user_reward_manager.claim_rewards(
pool_reward_manager,
*accounts.reward_token_vault_info.key,
clock,
)?;

// 3.

spl_token_transfer(TokenTransferParams {
source: accounts.reward_token_vault_info.clone(),
destination: accounts.obligation_owner_token_account_info.clone(),
amount: total_reward_amount,
authority: accounts.reward_authority_info.clone(),
authority_signer_seeds: &[
reward_vault_authority_seeds(
accounts.lending_market_info.key,
&accounts.reserve.key(),
accounts.reward_mint_info.key,
)
.as_slice(),
&[&[reward_authority_bump]],
]
.concat(),
token_program: accounts.token_program_info.clone(),
})?;

// 4.

realloc_obligation_if_necessary(&accounts.obligation, accounts.obligation_info)?;
Expand Down
14 changes: 5 additions & 9 deletions token-lending/program/tests/add_pool_reward.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,19 +54,15 @@ async fn test_(position_kind: PositionKind) {
let obligation = lending_market
.init_obligation(&mut test, Keypair::new(), &user)
.await
.expect("This should succeed");
.expect("Should init obligation");

let usdc_reserve_post = test.load_account::<Reserve>(usdc_reserve.pubkey).await;

let expected_reward_manager = Box::new(PoolRewardManager {
total_shares: 0,
last_update_time_secs: current_time as _,
pool_rewards: {
let mut og = usdc_reserve
.account
.deposits_pool_reward_manager
.pool_rewards
.clone();
let mut og = PoolRewardManager::default().pool_rewards;

og[0] = PoolRewardSlot::Occupied(Box::new(PoolReward {
id: PoolRewardId(1),
Expand Down Expand Up @@ -102,7 +98,7 @@ async fn test_(position_kind: PositionKind) {
deposit_amount,
)
.await
.expect("This should succeed");
.expect("Should deposit $USDC");

deposit_amount
}
Expand All @@ -124,7 +120,7 @@ async fn test_(position_kind: PositionKind) {
420_000_000,
)
.await
.expect("This should succeed");
.expect("Should borrow $wSOL");

lending_market
.borrow_obligation_liquidity(
Expand All @@ -136,7 +132,7 @@ async fn test_(position_kind: PositionKind) {
690,
)
.await
.unwrap();
.expect("Should borrow $USDC");

690
}
Expand Down
17 changes: 6 additions & 11 deletions token-lending/program/tests/cancel_pool_reward.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,13 +31,12 @@ async fn test_cancel_pool_reward_for_borrow() {
async fn test_(position_kind: PositionKind) {
let (mut test, lending_market, usdc_reserve, _, mut lending_market_owner, _) =
setup_world(&test_reserve_config(), &test_reserve_config()).await;
let mut clock = test.get_clock().await;

let reward_mint = test.create_mint_as_test_authority().await;
let reward_vault = Keypair::new();
let duration_secs = 3_600;
let total_rewards = 1_000_000;
let initial_time = clock.unix_timestamp as u64;
let initial_time = test.get_clock().await.unix_timestamp as u64;
let reward = LiqMiningReward {
mint: reward_mint,
vault: reward_vault.insecure_clone(),
Expand All @@ -63,9 +62,9 @@ async fn test_(position_kind: PositionKind) {
)
.await;

clock.unix_timestamp += duration_secs as i64 / 2;
test.context.set_sysvar(&clock);
let time_when_cancelling = clock.unix_timestamp as u64;
let current_time = test
.advance_clock_by_slots_and_secs(1, duration_secs as u64 / 2)
.await;

let pool_reward_index = 0;
lending_market
Expand Down Expand Up @@ -100,13 +99,9 @@ async fn test_(position_kind: PositionKind) {

let expected_reward_manager = Box::new(PoolRewardManager {
total_shares: 0,
last_update_time_secs: time_when_cancelling as _,
last_update_time_secs: current_time,
pool_rewards: {
let mut og = usdc_reserve
.account
.deposits_pool_reward_manager
.pool_rewards
.clone();
let mut og = PoolRewardManager::default().pool_rewards;

og[0] = PoolRewardSlot::Occupied(Box::new(PoolReward {
id: PoolRewardId(1),
Expand Down
Loading
Loading