forked from solana-labs/solana-program-library
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
0xripleys manual liquidate (solana-labs#112)
* kinda working cli liquidation * dynamically create atas if they don't exist * adding compute budget request * fix clippy * liquidate scripts * withdraw ctokens command * add redeem reserve collateral function
- Loading branch information
Showing
6 changed files
with
577 additions
and
1 deletion.
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
set -ex | ||
|
||
ETH_RESERVE=CPDiKagfozERtJ33p7HHhEfJERjvfk1VAjMXAFLrvrKP | ||
SOL_RESERVE=8PbodeaosQP19SjYFx855UMqWxH2HynZLdBXmsrbac36 | ||
STSOL_RESERVE=5sjkv6HD8wycocJ4tC4U36HHbvgcXYqcyiPRUkncnwWs | ||
MSOL_RESERVE=CCpirWrgNuBVLdkP2haxLTbD6XqEgaYuVXixbbpxUB6 | ||
USDC_RESERVE=BgxfHJDzm44T7XG68MYKx7YisTjZu73tVovyZSjJMpmw | ||
USDT_RESERVE=8K9WC8xoh2rtQNY7iEGXtPvfbDCi563SdWhCAhuMP2xE | ||
BTC_RESERVE=GYzjMCXTDue12eUGKKWAqtF5jcBYNmewr6Db6LaguEaX | ||
RAY_RESERVE=9n2exoMQwMTzfw6NFoFFujxYPndWVLtKREJePssrKb36 | ||
SLND_RESERVE=CviGNzD2C9ZCMmjDt5DKCce5cLV4Emrcm3NFvwudBFKA | ||
|
||
USDC_ATA=Bqn9qMjFEHRNS4wBRVAs3Uc52Dr3vm2AXJ5GaMkepBiQ | ||
USDT_ATA=2bEeupwb9eC5R9LjCCrfetPm5yLwdGVLYng6XhNtue9H | ||
BTC_ATA=A6Fu8DtnUqeYpzUMbZnnDpUFE5URnNUd8toZzcNBMkJ4 | ||
|
||
OBLIGATION_PUBKEY=HLRd6Dn4RUs4XbVzYhdp6UswQMCJTqWc9PgJ6VxvsyXu | ||
# OBLIGATION_PUBKEY=3ErCznFWTRmhZE8C1mAQCkcneqcZQedB5ACqAwbbWUAP | ||
REPAY_RESERVE=$USDC_RESERVE | ||
WITHDRAW_RESERVE=$SOL_RESERVE | ||
LIQUIDITY_AMOUNT=1000000000 | ||
SOURCE_LIQUIDITY=$USDC_ATA | ||
|
||
|
||
cargo run liquidate-obligation \ | ||
--obligation $OBLIGATION_PUBKEY \ | ||
--repay-reserve $REPAY_RESERVE \ | ||
--withdraw-reserve $WITHDRAW_RESERVE \ | ||
--liquidity-amount $LIQUIDITY_AMOUNT \ | ||
--source-liquidity $SOURCE_LIQUIDITY |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
set -ex | ||
|
||
ETH_RESERVE=CPDiKagfozERtJ33p7HHhEfJERjvfk1VAjMXAFLrvrKP | ||
SOL_RESERVE=8PbodeaosQP19SjYFx855UMqWxH2HynZLdBXmsrbac36 | ||
STSOL_RESERVE=5sjkv6HD8wycocJ4tC4U36HHbvgcXYqcyiPRUkncnwWs | ||
MSOL_RESERVE=CCpirWrgNuBVLdkP2haxLTbD6XqEgaYuVXixbbpxUB6 | ||
USDC_RESERVE=BgxfHJDzm44T7XG68MYKx7YisTjZu73tVovyZSjJMpmw | ||
USDT_RESERVE=8K9WC8xoh2rtQNY7iEGXtPvfbDCi563SdWhCAhuMP2xE | ||
BTC_RESERVE=GYzjMCXTDue12eUGKKWAqtF5jcBYNmewr6Db6LaguEaX | ||
RAY_RESERVE=9n2exoMQwMTzfw6NFoFFujxYPndWVLtKREJePssrKb36 | ||
SLND_RESERVE=CviGNzD2C9ZCMmjDt5DKCce5cLV4Emrcm3NFvwudBFKA | ||
|
||
USDC_ATA=Bqn9qMjFEHRNS4wBRVAs3Uc52Dr3vm2AXJ5GaMkepBiQ | ||
USDT_ATA=2bEeupwb9eC5R9LjCCrfetPm5yLwdGVLYng6XhNtue9H | ||
BTC_ATA=A6Fu8DtnUqeYpzUMbZnnDpUFE5URnNUd8toZzcNBMkJ4 | ||
|
||
OBLIGATION_PUBKEY=9XQ18M6VvB9X9QVXxj1bCvKifAW2RWDePEfBwi6fsLhq | ||
WITHDRAW_RESERVE=$SOL_RESERVE | ||
COLLATERAL_AMOUNT=1000 | ||
|
||
|
||
cargo run withdraw-collateral \ | ||
--obligation $OBLIGATION_PUBKEY \ | ||
--withdraw-reserve $WITHDRAW_RESERVE \ | ||
--withdraw-amount $COLLATERAL_AMOUNT \ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,135 @@ | ||
use solana_program::instruction::Instruction; | ||
use solend_program::instruction::{ | ||
refresh_obligation, refresh_reserve, withdraw_obligation_collateral, | ||
}; | ||
use solend_program::state::{Obligation, Reserve}; | ||
|
||
use solana_client::rpc_client::RpcClient; | ||
use solana_program::program_pack::Pack; | ||
use solana_program::pubkey::Pubkey; | ||
use spl_associated_token_account::get_associated_token_address; | ||
use std::collections::HashSet; | ||
|
||
pub struct SolendState { | ||
lending_program_id: Pubkey, | ||
obligation_pubkey: Pubkey, | ||
obligation: Obligation, | ||
reserves: Vec<(Pubkey, Reserve)>, | ||
} | ||
|
||
impl SolendState { | ||
pub fn new( | ||
lending_program_id: Pubkey, | ||
obligation_pubkey: Pubkey, | ||
rpc_client: &RpcClient, | ||
) -> Self { | ||
let obligation = { | ||
let data = rpc_client.get_account(&obligation_pubkey).unwrap(); | ||
Obligation::unpack(&data.data).unwrap() | ||
}; | ||
|
||
// get reserve pubkeys | ||
let reserve_pubkeys: Vec<Pubkey> = { | ||
let mut r = HashSet::new(); | ||
r.extend(obligation.deposits.iter().map(|d| d.deposit_reserve)); | ||
r.extend(obligation.borrows.iter().map(|b| b.borrow_reserve)); | ||
r.into_iter().collect() | ||
}; | ||
|
||
// get reserve accounts | ||
let reserves: Vec<(Pubkey, Reserve)> = rpc_client | ||
.get_multiple_accounts(&reserve_pubkeys) | ||
.unwrap() | ||
.into_iter() | ||
.zip(reserve_pubkeys.iter()) | ||
.map(|(account, pubkey)| (*pubkey, Reserve::unpack(&account.unwrap().data).unwrap())) | ||
.collect(); | ||
|
||
assert!(reserve_pubkeys.len() == reserves.len()); | ||
|
||
Self { | ||
lending_program_id, | ||
obligation_pubkey, | ||
obligation, | ||
reserves, | ||
} | ||
} | ||
|
||
pub fn find_reserve_by_key(&self, pubkey: Pubkey) -> Option<&Reserve> { | ||
self.reserves.iter().find_map( | ||
|(p, reserve)| { | ||
if pubkey == *p { | ||
Some(reserve) | ||
} else { | ||
None | ||
} | ||
}, | ||
) | ||
} | ||
|
||
fn get_refresh_instructions(&self) -> Vec<Instruction> { | ||
let mut instructions = Vec::new(); | ||
instructions.extend(self.reserves.iter().map(|(pubkey, reserve)| { | ||
refresh_reserve( | ||
self.lending_program_id, | ||
*pubkey, | ||
reserve.liquidity.pyth_oracle_pubkey, | ||
reserve.liquidity.switchboard_oracle_pubkey, | ||
) | ||
})); | ||
|
||
let reserve_pubkeys: Vec<Pubkey> = { | ||
let mut r = Vec::new(); | ||
r.extend(self.obligation.deposits.iter().map(|d| d.deposit_reserve)); | ||
r.extend(self.obligation.borrows.iter().map(|b| b.borrow_reserve)); | ||
r | ||
}; | ||
|
||
// refresh obligation | ||
instructions.push(refresh_obligation( | ||
self.lending_program_id, | ||
self.obligation_pubkey, | ||
reserve_pubkeys, | ||
)); | ||
|
||
instructions | ||
} | ||
|
||
/// withdraw obligation ctokens to owner's ata | ||
pub fn withdraw( | ||
&self, | ||
withdraw_reserve_pubkey: &Pubkey, | ||
collateral_amount: u64, | ||
) -> Vec<Instruction> { | ||
let mut instructions = self.get_refresh_instructions(); | ||
|
||
// find repay, withdraw reserve states | ||
let withdraw_reserve = self | ||
.reserves | ||
.iter() | ||
.find_map(|(pubkey, reserve)| { | ||
if withdraw_reserve_pubkey == pubkey { | ||
Some(reserve) | ||
} else { | ||
None | ||
} | ||
}) | ||
.unwrap(); | ||
|
||
instructions.push(withdraw_obligation_collateral( | ||
self.lending_program_id, | ||
collateral_amount, | ||
withdraw_reserve.collateral.supply_pubkey, | ||
get_associated_token_address( | ||
&self.obligation.owner, | ||
&withdraw_reserve.collateral.mint_pubkey, | ||
), | ||
*withdraw_reserve_pubkey, | ||
self.obligation_pubkey, | ||
withdraw_reserve.lending_market, | ||
self.obligation.owner, | ||
)); | ||
|
||
instructions | ||
} | ||
} |
Oops, something went wrong.