1
1
use lending_state:: SolendState ;
2
2
use solana_client:: rpc_config:: RpcSendTransactionConfig ;
3
3
use solana_sdk:: { commitment_config:: CommitmentLevel , compute_budget:: ComputeBudgetInstruction } ;
4
+ use solend_program:: { instruction:: set_lending_market_owner_and_config, state:: RateLimiterConfig } ;
4
5
use solend_sdk:: {
5
6
instruction:: {
6
7
liquidate_obligation_and_redeem_reserve_collateral, redeem_reserve_collateral,
@@ -88,6 +89,12 @@ struct PartialReserveConfig {
88
89
pub protocol_liquidation_fee : Option < u8 > ,
89
90
/// Protocol take rate is the amount borrowed interest protocol recieves, as a percentage
90
91
pub protocol_take_rate : Option < u8 > ,
92
+ /// Rate Limiter's max window size
93
+ pub rate_limiter_window_duration : Option < u64 > ,
94
+ /// Rate Limiter's max outflow per window
95
+ pub rate_limiter_max_outflow : Option < u64 > ,
96
+ /// Added borrow weight in basis points
97
+ pub added_borrow_weight_bps : Option < u64 > ,
91
98
}
92
99
93
100
/// Reserve Fees with optional fields
@@ -523,6 +530,55 @@ fn main() {
523
530
. help ( "Borrow limit" ) ,
524
531
)
525
532
)
533
+ . subcommand (
534
+ SubCommand :: with_name ( "set-lending-market-owner-and-config" )
535
+ . about ( "Set lending market owner and config" )
536
+ . arg (
537
+ Arg :: with_name ( "lending_market_owner" )
538
+ . long ( "market-owner" )
539
+ . validator ( is_keypair)
540
+ . value_name ( "KEYPAIR" )
541
+ . takes_value ( true )
542
+ . required ( true )
543
+ . help ( "Owner of the lending market" ) ,
544
+ )
545
+ . arg (
546
+ Arg :: with_name ( "lending_market" )
547
+ . long ( "market" )
548
+ . validator ( is_pubkey)
549
+ . value_name ( "PUBKEY" )
550
+ . takes_value ( true )
551
+ . required ( true )
552
+ . help ( "Lending market address" ) ,
553
+ )
554
+ . arg (
555
+ Arg :: with_name ( "new_lending_market_owner" )
556
+ . long ( "new-lending-market-owner" )
557
+ . validator ( is_keypair)
558
+ . value_name ( "KEYPAIR" )
559
+ . takes_value ( true )
560
+ . required ( false )
561
+ . help ( "Owner of the lending market" ) ,
562
+ )
563
+ . arg (
564
+ Arg :: with_name ( "rate_limiter_window_duration" )
565
+ . long ( "rate-limiter-window-duration" )
566
+ . validator ( is_parsable :: < u64 > )
567
+ . value_name ( "INTEGER" )
568
+ . takes_value ( true )
569
+ . required ( false )
570
+ . help ( "Rate Limiter Window Duration in Slots" ) ,
571
+ )
572
+ . arg (
573
+ Arg :: with_name ( "rate_limiter_max_outflow" )
574
+ . long ( "rate-limiter-max-outflow" )
575
+ . validator ( is_parsable :: < u64 > )
576
+ . value_name ( "INTEGER" )
577
+ . takes_value ( true )
578
+ . required ( false )
579
+ . help ( "Rate Limiter max outflow denominated in dollars within 1 window" ) ,
580
+ )
581
+ )
526
582
. subcommand (
527
583
SubCommand :: with_name ( "update-reserve" )
528
584
. about ( "Update a reserve config" )
@@ -716,6 +772,33 @@ fn main() {
716
772
. required ( false )
717
773
. help ( "Switchboard price feed account: https://switchboard.xyz/#/explorer" ) ,
718
774
)
775
+ . arg (
776
+ Arg :: with_name ( "rate_limiter_window_duration" )
777
+ . long ( "rate-limiter-window-duration" )
778
+ . validator ( is_parsable :: < u64 > )
779
+ . value_name ( "INTEGER" )
780
+ . takes_value ( true )
781
+ . required ( false )
782
+ . help ( "Rate Limiter Window Duration in Slots" ) ,
783
+ )
784
+ . arg (
785
+ Arg :: with_name ( "rate_limiter_max_outflow" )
786
+ . long ( "rate-limiter-max-outflow" )
787
+ . validator ( is_parsable :: < u64 > )
788
+ . value_name ( "INTEGER" )
789
+ . takes_value ( true )
790
+ . required ( false )
791
+ . help ( "Rate Limiter max outflow of token amounts within 1 window" ) ,
792
+ )
793
+ . arg (
794
+ Arg :: with_name ( "added_borrow_weight_bps" )
795
+ . long ( "added-borrow-weight-bps" )
796
+ . validator ( is_parsable :: < u64 > )
797
+ . value_name ( "INTEGER" )
798
+ . takes_value ( true )
799
+ . required ( false )
800
+ . help ( "Added borrow weight in basis points" ) ,
801
+ )
719
802
)
720
803
. get_matches ( ) ;
721
804
@@ -871,6 +954,7 @@ fn main() {
871
954
fee_receiver : liquidity_fee_receiver_keypair. pubkey ( ) ,
872
955
protocol_liquidation_fee,
873
956
protocol_take_rate,
957
+ added_borrow_weight_bps : 10000 ,
874
958
} ,
875
959
source_liquidity_pubkey,
876
960
source_liquidity_owner_keypair,
@@ -883,6 +967,24 @@ fn main() {
883
967
source_liquidity,
884
968
)
885
969
}
970
+ ( "set-lending-market-owner-and-config" , Some ( arg_matches) ) => {
971
+ let lending_market_owner_keypair =
972
+ keypair_of ( arg_matches, "lending_market_owner" ) . unwrap ( ) ;
973
+ let lending_market_pubkey = pubkey_of ( arg_matches, "lending_market" ) . unwrap ( ) ;
974
+ let new_lending_market_owner_keypair =
975
+ keypair_of ( arg_matches, "new_lending_market_owner" ) ;
976
+ let rate_limiter_window_duration =
977
+ value_of ( arg_matches, "rate_limiter_window_duration" ) ;
978
+ let rate_limiter_max_outflow = value_of ( arg_matches, "rate_limiter_max_outflow" ) ;
979
+ command_set_lending_market_owner_and_config (
980
+ & mut config,
981
+ lending_market_pubkey,
982
+ lending_market_owner_keypair,
983
+ new_lending_market_owner_keypair,
984
+ rate_limiter_window_duration,
985
+ rate_limiter_max_outflow,
986
+ )
987
+ }
886
988
( "update-reserve" , Some ( arg_matches) ) => {
887
989
let reserve_pubkey = pubkey_of ( arg_matches, "reserve" ) . unwrap ( ) ;
888
990
let lending_market_owner_keypair =
@@ -906,6 +1008,10 @@ fn main() {
906
1008
let pyth_product_pubkey = pubkey_of ( arg_matches, "pyth_product" ) ;
907
1009
let pyth_price_pubkey = pubkey_of ( arg_matches, "pyth_price" ) ;
908
1010
let switchboard_feed_pubkey = pubkey_of ( arg_matches, "switchboard_feed" ) ;
1011
+ let rate_limiter_window_duration =
1012
+ value_of ( arg_matches, "rate_limiter_window_duration" ) ;
1013
+ let rate_limiter_max_outflow = value_of ( arg_matches, "rate_limiter_max_outflow" ) ;
1014
+ let added_borrow_weight_bps = value_of ( arg_matches, "added_borrow_weight_bps" ) ;
909
1015
910
1016
let borrow_fee_wad = borrow_fee. map ( |fee| ( fee * WAD as f64 ) as u64 ) ;
911
1017
let flash_loan_fee_wad = flash_loan_fee. map ( |fee| ( fee * WAD as f64 ) as u64 ) ;
@@ -930,6 +1036,9 @@ fn main() {
930
1036
fee_receiver,
931
1037
protocol_liquidation_fee,
932
1038
protocol_take_rate,
1039
+ rate_limiter_window_duration,
1040
+ rate_limiter_max_outflow,
1041
+ added_borrow_weight_bps,
933
1042
} ,
934
1043
pyth_product_pubkey,
935
1044
pyth_price_pubkey,
@@ -1437,6 +1546,50 @@ fn command_add_reserve(
1437
1546
Ok ( ( ) )
1438
1547
}
1439
1548
1549
+ fn command_set_lending_market_owner_and_config (
1550
+ config : & mut Config ,
1551
+ lending_market_pubkey : Pubkey ,
1552
+ lending_market_owner_keypair : Keypair ,
1553
+ new_lending_market_owner_keypair : Option < Keypair > ,
1554
+ rate_limiter_window_duration : Option < u64 > ,
1555
+ rate_limiter_max_outflow : Option < u64 > ,
1556
+ ) -> CommandResult {
1557
+ let lending_market_info = config. rpc_client . get_account ( & lending_market_pubkey) ?;
1558
+ let lending_market = LendingMarket :: unpack_from_slice ( lending_market_info. data . borrow ( ) ) ?;
1559
+ println ! ( "{:#?}" , lending_market) ;
1560
+
1561
+ let recent_blockhash = config. rpc_client . get_latest_blockhash ( ) ?;
1562
+ let message = Message :: new_with_blockhash (
1563
+ & [ set_lending_market_owner_and_config (
1564
+ config. lending_program_id ,
1565
+ lending_market_pubkey,
1566
+ lending_market_owner_keypair. pubkey ( ) ,
1567
+ if let Some ( owner) = new_lending_market_owner_keypair {
1568
+ owner. pubkey ( )
1569
+ } else {
1570
+ lending_market. owner
1571
+ } ,
1572
+ RateLimiterConfig {
1573
+ window_duration : rate_limiter_window_duration
1574
+ . unwrap_or ( lending_market. rate_limiter . config . window_duration ) ,
1575
+ max_outflow : rate_limiter_max_outflow
1576
+ . unwrap_or ( lending_market. rate_limiter . config . max_outflow ) ,
1577
+ } ,
1578
+ ) ] ,
1579
+ Some ( & config. fee_payer . pubkey ( ) ) ,
1580
+ & recent_blockhash,
1581
+ ) ;
1582
+
1583
+ let transaction = Transaction :: new (
1584
+ & vec ! [ config. fee_payer. as_ref( ) , & lending_market_owner_keypair] ,
1585
+ message,
1586
+ recent_blockhash,
1587
+ ) ;
1588
+
1589
+ send_transaction ( config, transaction) ?;
1590
+ Ok ( ( ) )
1591
+ }
1592
+
1440
1593
#[ allow( clippy:: too_many_arguments, clippy:: unnecessary_unwrap) ]
1441
1594
fn command_update_reserve (
1442
1595
config : & mut Config ,
@@ -1450,6 +1603,7 @@ fn command_update_reserve(
1450
1603
) -> CommandResult {
1451
1604
let reserve_info = config. rpc_client . get_account ( & reserve_pubkey) ?;
1452
1605
let mut reserve = Reserve :: unpack_from_slice ( reserve_info. data . borrow ( ) ) ?;
1606
+ println ! ( "Reserve: {:#?}" , reserve) ;
1453
1607
let mut no_change = true ;
1454
1608
if reserve_config. optimal_utilization_rate . is_some ( )
1455
1609
&& reserve. config . optimal_utilization_rate
@@ -1664,6 +1818,46 @@ fn command_update_reserve(
1664
1818
) ;
1665
1819
reserve. liquidity . switchboard_oracle_pubkey = switchboard_feed_pubkey. unwrap ( ) ;
1666
1820
}
1821
+
1822
+ if reserve_config. rate_limiter_window_duration . is_some ( )
1823
+ && reserve. rate_limiter . config . window_duration
1824
+ != reserve_config. rate_limiter_window_duration . unwrap ( )
1825
+ {
1826
+ no_change = false ;
1827
+ println ! (
1828
+ "Updating rate_limiter_window_duration from {} to {}" ,
1829
+ reserve. rate_limiter. config. window_duration,
1830
+ reserve_config. rate_limiter_window_duration. unwrap( ) ,
1831
+ ) ;
1832
+ reserve. rate_limiter . config . window_duration =
1833
+ reserve_config. rate_limiter_window_duration . unwrap ( ) ;
1834
+ }
1835
+
1836
+ if reserve_config. rate_limiter_max_outflow . is_some ( )
1837
+ && reserve. rate_limiter . config . max_outflow
1838
+ != reserve_config. rate_limiter_max_outflow . unwrap ( )
1839
+ {
1840
+ no_change = false ;
1841
+ println ! (
1842
+ "Updating rate_limiter_max_outflow from {} to {}" ,
1843
+ reserve. rate_limiter. config. max_outflow,
1844
+ reserve_config. rate_limiter_max_outflow. unwrap( ) ,
1845
+ ) ;
1846
+ reserve. rate_limiter . config . max_outflow = reserve_config. rate_limiter_max_outflow . unwrap ( ) ;
1847
+ }
1848
+
1849
+ if reserve_config. added_borrow_weight_bps . is_some ( )
1850
+ && reserve. config . added_borrow_weight_bps != reserve_config. added_borrow_weight_bps . unwrap ( )
1851
+ {
1852
+ no_change = false ;
1853
+ println ! (
1854
+ "Updating added_borrow_weight_bps from {} to {}" ,
1855
+ reserve. config. added_borrow_weight_bps,
1856
+ reserve_config. added_borrow_weight_bps. unwrap( ) ,
1857
+ ) ;
1858
+ reserve. config . added_borrow_weight_bps = reserve_config. added_borrow_weight_bps . unwrap ( ) ;
1859
+ }
1860
+
1667
1861
if no_change {
1668
1862
println ! ( "No changes made for reserve {}" , reserve_pubkey) ;
1669
1863
return Ok ( ( ) ) ;
@@ -1675,6 +1869,10 @@ fn command_update_reserve(
1675
1869
& [ update_reserve_config (
1676
1870
config. lending_program_id ,
1677
1871
reserve. config ,
1872
+ RateLimiterConfig {
1873
+ window_duration : reserve. rate_limiter . config . window_duration ,
1874
+ max_outflow : reserve. rate_limiter . config . max_outflow ,
1875
+ } ,
1678
1876
reserve_pubkey,
1679
1877
lending_market_pubkey,
1680
1878
lending_market_owner_keypair. pubkey ( ) ,
0 commit comments