1use crate::{
4 error::LendingError,
5 state::{ReserveConfig, ReserveFees},
6};
7use solana_program::{
8 instruction::{AccountMeta, Instruction},
9 msg,
10 program_error::ProgramError,
11 pubkey::{Pubkey, PUBKEY_BYTES},
12 sysvar,
13};
14use std::{convert::TryInto, mem::size_of};
15
16#[derive(Clone, Debug, PartialEq, Eq)]
18pub enum LendingInstruction {
19 InitLendingMarket {
30 owner: Pubkey,
32 quote_currency: [u8; 32],
35 },
36
37 SetLendingMarketOwner {
45 new_owner: Pubkey,
47 },
48
49 InitReserve {
75 liquidity_amount: u64,
77 config: ReserveConfig,
79 },
80
81 RefreshReserve,
93
94 DepositReserveLiquidity {
112 liquidity_amount: u64,
114 },
115
116 RedeemReserveCollateral {
133 collateral_amount: u64,
135 },
136
137 InitObligation,
149
150 RefreshObligation,
162
163 DepositObligationCollateral {
180 collateral_amount: u64,
182 },
183
184 WithdrawObligationCollateral {
200 collateral_amount: u64,
202 },
203
204 BorrowObligationLiquidity {
224 liquidity_amount: u64,
226 },
228
229 RepayObligationLiquidity {
245 liquidity_amount: u64,
247 },
248
249 LiquidateObligation {
271 liquidity_amount: u64,
273 },
274
275 FlashLoan {
313 amount: u64,
315 },
316
317 DepositReserveLiquidityAndObligationCollateral {
339 liquidity_amount: u64,
341 },
342
343 WithdrawObligationCollateralAndRedeemReserveCollateral {
363 collateral_amount: u64,
365 },
366
367 UpdateReserveConfig {
380 config: ReserveConfig,
382 },
383
384 LiquidateObligationAndRedeemReserveCollateral {
409 liquidity_amount: u64,
411 },
412
413 RedeemFees,
422
423 FlashBorrowReserveLiquidity {
437 liquidity_amount: u64,
439 },
440
441 FlashRepayReserveLiquidity {
458 liquidity_amount: u64,
460 borrow_instruction_index: u8,
462 },
463}
464
465impl LendingInstruction {
466 pub fn unpack(input: &[u8]) -> Result<Self, ProgramError> {
468 let (&tag, rest) = input
469 .split_first()
470 .ok_or(LendingError::InstructionUnpackError)?;
471 Ok(match tag {
472 0 => {
473 let (owner, rest) = Self::unpack_pubkey(rest)?;
474 let (quote_currency, _rest) = Self::unpack_bytes32(rest)?;
475 Self::InitLendingMarket {
476 owner,
477 quote_currency: *quote_currency,
478 }
479 }
480 1 => {
481 let (new_owner, _rest) = Self::unpack_pubkey(rest)?;
482 Self::SetLendingMarketOwner { new_owner }
483 }
484 2 => {
485 let (liquidity_amount, rest) = Self::unpack_u64(rest)?;
486 let (optimal_utilization_rate, rest) = Self::unpack_u8(rest)?;
487 let (loan_to_value_ratio, rest) = Self::unpack_u8(rest)?;
488 let (liquidation_bonus, rest) = Self::unpack_u8(rest)?;
489 let (liquidation_threshold, rest) = Self::unpack_u8(rest)?;
490 let (min_borrow_rate, rest) = Self::unpack_u8(rest)?;
491 let (optimal_borrow_rate, rest) = Self::unpack_u8(rest)?;
492 let (max_borrow_rate, rest) = Self::unpack_u8(rest)?;
493 let (borrow_fee_wad, rest) = Self::unpack_u64(rest)?;
494 let (flash_loan_fee_wad, rest) = Self::unpack_u64(rest)?;
495 let (host_fee_percentage, rest) = Self::unpack_u8(rest)?;
496 let (deposit_limit, rest) = Self::unpack_u64(rest)?;
497 let (borrow_limit, rest) = Self::unpack_u64(rest)?;
498 let (fee_receiver, rest) = Self::unpack_pubkey(rest)?;
499 let (protocol_liquidation_fee, rest) = Self::unpack_u8(rest)?;
500 let (protocol_take_rate, _rest) = Self::unpack_u8(rest)?;
501 Self::InitReserve {
502 liquidity_amount,
503 config: ReserveConfig {
504 optimal_utilization_rate,
505 loan_to_value_ratio,
506 liquidation_bonus,
507 liquidation_threshold,
508 min_borrow_rate,
509 optimal_borrow_rate,
510 max_borrow_rate,
511 fees: ReserveFees {
512 borrow_fee_wad,
513 flash_loan_fee_wad,
514 host_fee_percentage,
515 },
516 deposit_limit,
517 borrow_limit,
518 fee_receiver,
519 protocol_liquidation_fee,
520 protocol_take_rate,
521 },
522 }
523 }
524 3 => Self::RefreshReserve,
525 4 => {
526 let (liquidity_amount, _rest) = Self::unpack_u64(rest)?;
527 Self::DepositReserveLiquidity { liquidity_amount }
528 }
529 5 => {
530 let (collateral_amount, _rest) = Self::unpack_u64(rest)?;
531 Self::RedeemReserveCollateral { collateral_amount }
532 }
533 6 => Self::InitObligation,
534 7 => Self::RefreshObligation,
535 8 => {
536 let (collateral_amount, _rest) = Self::unpack_u64(rest)?;
537 Self::DepositObligationCollateral { collateral_amount }
538 }
539 9 => {
540 let (collateral_amount, _rest) = Self::unpack_u64(rest)?;
541 Self::WithdrawObligationCollateral { collateral_amount }
542 }
543 10 => {
544 let (liquidity_amount, _rest) = Self::unpack_u64(rest)?;
545 Self::BorrowObligationLiquidity { liquidity_amount }
546 }
547 11 => {
548 let (liquidity_amount, _rest) = Self::unpack_u64(rest)?;
549 Self::RepayObligationLiquidity { liquidity_amount }
550 }
551 12 => {
552 let (liquidity_amount, _rest) = Self::unpack_u64(rest)?;
553 Self::LiquidateObligation { liquidity_amount }
554 }
555 13 => {
556 let (amount, _rest) = Self::unpack_u64(rest)?;
557 Self::FlashLoan { amount }
558 }
559 14 => {
560 let (liquidity_amount, _rest) = Self::unpack_u64(rest)?;
561 Self::DepositReserveLiquidityAndObligationCollateral { liquidity_amount }
562 }
563 15 => {
564 let (collateral_amount, _rest) = Self::unpack_u64(rest)?;
565 Self::WithdrawObligationCollateralAndRedeemReserveCollateral { collateral_amount }
566 }
567 16 => {
568 let (optimal_utilization_rate, rest) = Self::unpack_u8(rest)?;
569 let (loan_to_value_ratio, rest) = Self::unpack_u8(rest)?;
570 let (liquidation_bonus, rest) = Self::unpack_u8(rest)?;
571 let (liquidation_threshold, rest) = Self::unpack_u8(rest)?;
572 let (min_borrow_rate, rest) = Self::unpack_u8(rest)?;
573 let (optimal_borrow_rate, rest) = Self::unpack_u8(rest)?;
574 let (max_borrow_rate, rest) = Self::unpack_u8(rest)?;
575 let (borrow_fee_wad, rest) = Self::unpack_u64(rest)?;
576 let (flash_loan_fee_wad, rest) = Self::unpack_u64(rest)?;
577 let (host_fee_percentage, rest) = Self::unpack_u8(rest)?;
578 let (deposit_limit, rest) = Self::unpack_u64(rest)?;
579 let (borrow_limit, rest) = Self::unpack_u64(rest)?;
580 let (fee_receiver, rest) = Self::unpack_pubkey(rest)?;
581 let (protocol_liquidation_fee, rest) = Self::unpack_u8(rest)?;
582 let (protocol_take_rate, _rest) = Self::unpack_u8(rest)?;
583 Self::UpdateReserveConfig {
584 config: ReserveConfig {
585 optimal_utilization_rate,
586 loan_to_value_ratio,
587 liquidation_bonus,
588 liquidation_threshold,
589 min_borrow_rate,
590 optimal_borrow_rate,
591 max_borrow_rate,
592 fees: ReserveFees {
593 borrow_fee_wad,
594 flash_loan_fee_wad,
595 host_fee_percentage,
596 },
597 deposit_limit,
598 borrow_limit,
599 fee_receiver,
600 protocol_liquidation_fee,
601 protocol_take_rate,
602 },
603 }
604 }
605 17 => {
606 let (liquidity_amount, _rest) = Self::unpack_u64(rest)?;
607 Self::LiquidateObligationAndRedeemReserveCollateral { liquidity_amount }
608 }
609 18 => Self::RedeemFees,
610 19 => {
611 let (liquidity_amount, _rest) = Self::unpack_u64(rest)?;
612 Self::FlashBorrowReserveLiquidity { liquidity_amount }
613 }
614 20 => {
615 let (liquidity_amount, rest) = Self::unpack_u64(rest)?;
616 let (borrow_instruction_index, _rest) = Self::unpack_u8(rest)?;
617 Self::FlashRepayReserveLiquidity {
618 liquidity_amount,
619 borrow_instruction_index,
620 }
621 }
622 _ => {
623 msg!("Instruction cannot be unpacked");
624 return Err(LendingError::InstructionUnpackError.into());
625 }
626 })
627 }
628
629 fn unpack_u64(input: &[u8]) -> Result<(u64, &[u8]), ProgramError> {
630 if input.len() < 8 {
631 msg!("u64 cannot be unpacked");
632 return Err(LendingError::InstructionUnpackError.into());
633 }
634 let (bytes, rest) = input.split_at(8);
635 let value = bytes
636 .get(..8)
637 .and_then(|slice| slice.try_into().ok())
638 .map(u64::from_le_bytes)
639 .ok_or(LendingError::InstructionUnpackError)?;
640 Ok((value, rest))
641 }
642
643 fn unpack_u8(input: &[u8]) -> Result<(u8, &[u8]), ProgramError> {
644 if input.is_empty() {
645 msg!("u8 cannot be unpacked");
646 return Err(LendingError::InstructionUnpackError.into());
647 }
648 let (bytes, rest) = input.split_at(1);
649 let value = bytes
650 .get(..1)
651 .and_then(|slice| slice.try_into().ok())
652 .map(u8::from_le_bytes)
653 .ok_or(LendingError::InstructionUnpackError)?;
654 Ok((value, rest))
655 }
656
657 fn unpack_bytes32(input: &[u8]) -> Result<(&[u8; 32], &[u8]), ProgramError> {
658 if input.len() < 32 {
659 msg!("32 bytes cannot be unpacked");
660 return Err(LendingError::InstructionUnpackError.into());
661 }
662 let (bytes, rest) = input.split_at(32);
663 Ok((
664 bytes
665 .try_into()
666 .map_err(|_| LendingError::InstructionUnpackError)?,
667 rest,
668 ))
669 }
670
671 fn unpack_pubkey(input: &[u8]) -> Result<(Pubkey, &[u8]), ProgramError> {
672 if input.len() < PUBKEY_BYTES {
673 msg!("Pubkey cannot be unpacked");
674 return Err(LendingError::InstructionUnpackError.into());
675 }
676 let (key, rest) = input.split_at(PUBKEY_BYTES);
677 let pk = Pubkey::new(key);
678 Ok((pk, rest))
679 }
680
681 pub fn pack(&self) -> Vec<u8> {
683 let mut buf = Vec::with_capacity(size_of::<Self>());
684 match *self {
685 Self::InitLendingMarket {
686 owner,
687 quote_currency,
688 } => {
689 buf.push(0);
690 buf.extend_from_slice(owner.as_ref());
691 buf.extend_from_slice(quote_currency.as_ref());
692 }
693 Self::SetLendingMarketOwner { new_owner } => {
694 buf.push(1);
695 buf.extend_from_slice(new_owner.as_ref());
696 }
697 Self::InitReserve {
698 liquidity_amount,
699 config:
700 ReserveConfig {
701 optimal_utilization_rate,
702 loan_to_value_ratio,
703 liquidation_bonus,
704 liquidation_threshold,
705 min_borrow_rate,
706 optimal_borrow_rate,
707 max_borrow_rate,
708 fees:
709 ReserveFees {
710 borrow_fee_wad,
711 flash_loan_fee_wad,
712 host_fee_percentage,
713 },
714 deposit_limit,
715 borrow_limit,
716 fee_receiver,
717 protocol_liquidation_fee,
718 protocol_take_rate,
719 },
720 } => {
721 buf.push(2);
722 buf.extend_from_slice(&liquidity_amount.to_le_bytes());
723 buf.extend_from_slice(&optimal_utilization_rate.to_le_bytes());
724 buf.extend_from_slice(&loan_to_value_ratio.to_le_bytes());
725 buf.extend_from_slice(&liquidation_bonus.to_le_bytes());
726 buf.extend_from_slice(&liquidation_threshold.to_le_bytes());
727 buf.extend_from_slice(&min_borrow_rate.to_le_bytes());
728 buf.extend_from_slice(&optimal_borrow_rate.to_le_bytes());
729 buf.extend_from_slice(&max_borrow_rate.to_le_bytes());
730 buf.extend_from_slice(&borrow_fee_wad.to_le_bytes());
731 buf.extend_from_slice(&flash_loan_fee_wad.to_le_bytes());
732 buf.extend_from_slice(&host_fee_percentage.to_le_bytes());
733 buf.extend_from_slice(&deposit_limit.to_le_bytes());
734 buf.extend_from_slice(&borrow_limit.to_le_bytes());
735 buf.extend_from_slice(&fee_receiver.to_bytes());
736 buf.extend_from_slice(&protocol_liquidation_fee.to_le_bytes());
737 buf.extend_from_slice(&protocol_take_rate.to_le_bytes());
738 }
739 Self::RefreshReserve => {
740 buf.push(3);
741 }
742 Self::DepositReserveLiquidity { liquidity_amount } => {
743 buf.push(4);
744 buf.extend_from_slice(&liquidity_amount.to_le_bytes());
745 }
746 Self::RedeemReserveCollateral { collateral_amount } => {
747 buf.push(5);
748 buf.extend_from_slice(&collateral_amount.to_le_bytes());
749 }
750 Self::InitObligation => {
751 buf.push(6);
752 }
753 Self::RefreshObligation => {
754 buf.push(7);
755 }
756 Self::DepositObligationCollateral { collateral_amount } => {
757 buf.push(8);
758 buf.extend_from_slice(&collateral_amount.to_le_bytes());
759 }
760 Self::WithdrawObligationCollateral { collateral_amount } => {
761 buf.push(9);
762 buf.extend_from_slice(&collateral_amount.to_le_bytes());
763 }
764 Self::BorrowObligationLiquidity { liquidity_amount } => {
765 buf.push(10);
766 buf.extend_from_slice(&liquidity_amount.to_le_bytes());
767 }
768 Self::RepayObligationLiquidity { liquidity_amount } => {
769 buf.push(11);
770 buf.extend_from_slice(&liquidity_amount.to_le_bytes());
771 }
772 Self::LiquidateObligation { liquidity_amount } => {
773 buf.push(12);
774 buf.extend_from_slice(&liquidity_amount.to_le_bytes());
775 }
776 Self::FlashLoan { amount } => {
777 buf.push(13);
778 buf.extend_from_slice(&amount.to_le_bytes());
779 }
780 Self::DepositReserveLiquidityAndObligationCollateral { liquidity_amount } => {
781 buf.push(14);
782 buf.extend_from_slice(&liquidity_amount.to_le_bytes());
783 }
784 Self::WithdrawObligationCollateralAndRedeemReserveCollateral { collateral_amount } => {
785 buf.push(15);
786 buf.extend_from_slice(&collateral_amount.to_le_bytes());
787 }
788 Self::UpdateReserveConfig { config } => {
789 buf.push(16);
790 buf.extend_from_slice(&config.optimal_utilization_rate.to_le_bytes());
791 buf.extend_from_slice(&config.loan_to_value_ratio.to_le_bytes());
792 buf.extend_from_slice(&config.liquidation_bonus.to_le_bytes());
793 buf.extend_from_slice(&config.liquidation_threshold.to_le_bytes());
794 buf.extend_from_slice(&config.min_borrow_rate.to_le_bytes());
795 buf.extend_from_slice(&config.optimal_borrow_rate.to_le_bytes());
796 buf.extend_from_slice(&config.max_borrow_rate.to_le_bytes());
797 buf.extend_from_slice(&config.fees.borrow_fee_wad.to_le_bytes());
798 buf.extend_from_slice(&config.fees.flash_loan_fee_wad.to_le_bytes());
799 buf.extend_from_slice(&config.fees.host_fee_percentage.to_le_bytes());
800 buf.extend_from_slice(&config.deposit_limit.to_le_bytes());
801 buf.extend_from_slice(&config.borrow_limit.to_le_bytes());
802 buf.extend_from_slice(&config.fee_receiver.to_bytes());
803 buf.extend_from_slice(&config.protocol_liquidation_fee.to_le_bytes());
804 buf.extend_from_slice(&config.protocol_take_rate.to_le_bytes());
805 }
806 Self::LiquidateObligationAndRedeemReserveCollateral { liquidity_amount } => {
807 buf.push(17);
808 buf.extend_from_slice(&liquidity_amount.to_le_bytes());
809 }
810 Self::RedeemFees {} => {
811 buf.push(18);
812 }
813 Self::FlashBorrowReserveLiquidity { liquidity_amount } => {
814 buf.push(19);
815 buf.extend_from_slice(&liquidity_amount.to_le_bytes());
816 }
817 Self::FlashRepayReserveLiquidity {
818 liquidity_amount,
819 borrow_instruction_index,
820 } => {
821 buf.push(20);
822 buf.extend_from_slice(&liquidity_amount.to_le_bytes());
823 buf.extend_from_slice(&borrow_instruction_index.to_le_bytes());
824 }
825 }
826 buf
827 }
828}
829
830pub fn init_lending_market(
832 program_id: Pubkey,
833 owner: Pubkey,
834 quote_currency: [u8; 32],
835 lending_market_pubkey: Pubkey,
836 oracle_program_id: Pubkey,
837 switchboard_oracle_program_id: Pubkey,
838) -> Instruction {
839 Instruction {
840 program_id,
841 accounts: vec![
842 AccountMeta::new(lending_market_pubkey, false),
843 AccountMeta::new_readonly(sysvar::rent::id(), false),
844 AccountMeta::new_readonly(spl_token::id(), false),
845 AccountMeta::new_readonly(oracle_program_id, false),
846 AccountMeta::new_readonly(switchboard_oracle_program_id, false),
847 ],
848 data: LendingInstruction::InitLendingMarket {
849 owner,
850 quote_currency,
851 }
852 .pack(),
853 }
854}
855
856pub fn set_lending_market_owner(
858 program_id: Pubkey,
859 lending_market_pubkey: Pubkey,
860 lending_market_owner: Pubkey,
861 new_owner: Pubkey,
862) -> Instruction {
863 Instruction {
864 program_id,
865 accounts: vec![
866 AccountMeta::new(lending_market_pubkey, false),
867 AccountMeta::new_readonly(lending_market_owner, true),
868 ],
869 data: LendingInstruction::SetLendingMarketOwner { new_owner }.pack(),
870 }
871}
872
873#[allow(clippy::too_many_arguments)]
875pub fn init_reserve(
876 program_id: Pubkey,
877 liquidity_amount: u64,
878 config: ReserveConfig,
879 source_liquidity_pubkey: Pubkey,
880 destination_collateral_pubkey: Pubkey,
881 reserve_pubkey: Pubkey,
882 reserve_liquidity_mint_pubkey: Pubkey,
883 reserve_liquidity_supply_pubkey: Pubkey,
884 reserve_collateral_mint_pubkey: Pubkey,
885 reserve_collateral_supply_pubkey: Pubkey,
886 pyth_product_pubkey: Pubkey,
887 pyth_price_pubkey: Pubkey,
888 switchboard_feed_pubkey: Pubkey,
889 lending_market_pubkey: Pubkey,
890 lending_market_owner_pubkey: Pubkey,
891 user_transfer_authority_pubkey: Pubkey,
892) -> Instruction {
893 let (lending_market_authority_pubkey, _bump_seed) = Pubkey::find_program_address(
894 &[&lending_market_pubkey.to_bytes()[..PUBKEY_BYTES]],
895 &program_id,
896 );
897 let accounts = vec![
898 AccountMeta::new(source_liquidity_pubkey, false),
899 AccountMeta::new(destination_collateral_pubkey, false),
900 AccountMeta::new(reserve_pubkey, false),
901 AccountMeta::new_readonly(reserve_liquidity_mint_pubkey, false),
902 AccountMeta::new(reserve_liquidity_supply_pubkey, false),
903 AccountMeta::new(config.fee_receiver, false),
904 AccountMeta::new(reserve_collateral_mint_pubkey, false),
905 AccountMeta::new(reserve_collateral_supply_pubkey, false),
906 AccountMeta::new_readonly(pyth_product_pubkey, false),
907 AccountMeta::new_readonly(pyth_price_pubkey, false),
908 AccountMeta::new_readonly(switchboard_feed_pubkey, false),
909 AccountMeta::new_readonly(lending_market_pubkey, false),
910 AccountMeta::new_readonly(lending_market_authority_pubkey, false),
911 AccountMeta::new_readonly(lending_market_owner_pubkey, true),
912 AccountMeta::new_readonly(user_transfer_authority_pubkey, true),
913 AccountMeta::new_readonly(sysvar::rent::id(), false),
914 AccountMeta::new_readonly(spl_token::id(), false),
915 ];
916 Instruction {
917 program_id,
918 accounts,
919 data: LendingInstruction::InitReserve {
920 liquidity_amount,
921 config,
922 }
923 .pack(),
924 }
925}
926
927pub fn refresh_reserve(
929 program_id: Pubkey,
930 reserve_pubkey: Pubkey,
931 reserve_liquidity_pyth_oracle_pubkey: Pubkey,
932 reserve_liquidity_switchboard_oracle_pubkey: Pubkey,
933) -> Instruction {
934 let accounts = vec![
935 AccountMeta::new(reserve_pubkey, false),
936 AccountMeta::new_readonly(reserve_liquidity_pyth_oracle_pubkey, false),
937 AccountMeta::new_readonly(reserve_liquidity_switchboard_oracle_pubkey, false),
938 ];
939 Instruction {
940 program_id,
941 accounts,
942 data: LendingInstruction::RefreshReserve.pack(),
943 }
944}
945
946#[allow(clippy::too_many_arguments)]
948pub fn deposit_reserve_liquidity(
949 program_id: Pubkey,
950 liquidity_amount: u64,
951 source_liquidity_pubkey: Pubkey,
952 destination_collateral_pubkey: Pubkey,
953 reserve_pubkey: Pubkey,
954 reserve_liquidity_supply_pubkey: Pubkey,
955 reserve_collateral_mint_pubkey: Pubkey,
956 lending_market_pubkey: Pubkey,
957 user_transfer_authority_pubkey: Pubkey,
958) -> Instruction {
959 let (lending_market_authority_pubkey, _bump_seed) = Pubkey::find_program_address(
960 &[&lending_market_pubkey.to_bytes()[..PUBKEY_BYTES]],
961 &program_id,
962 );
963 Instruction {
964 program_id,
965 accounts: vec![
966 AccountMeta::new(source_liquidity_pubkey, false),
967 AccountMeta::new(destination_collateral_pubkey, false),
968 AccountMeta::new(reserve_pubkey, false),
969 AccountMeta::new(reserve_liquidity_supply_pubkey, false),
970 AccountMeta::new(reserve_collateral_mint_pubkey, false),
971 AccountMeta::new_readonly(lending_market_pubkey, false),
972 AccountMeta::new_readonly(lending_market_authority_pubkey, false),
973 AccountMeta::new_readonly(user_transfer_authority_pubkey, true),
974 AccountMeta::new_readonly(spl_token::id(), false),
975 ],
976 data: LendingInstruction::DepositReserveLiquidity { liquidity_amount }.pack(),
977 }
978}
979
980#[allow(clippy::too_many_arguments)]
982pub fn redeem_reserve_collateral(
983 program_id: Pubkey,
984 collateral_amount: u64,
985 source_collateral_pubkey: Pubkey,
986 destination_liquidity_pubkey: Pubkey,
987 reserve_pubkey: Pubkey,
988 reserve_collateral_mint_pubkey: Pubkey,
989 reserve_liquidity_supply_pubkey: Pubkey,
990 lending_market_pubkey: Pubkey,
991 user_transfer_authority_pubkey: Pubkey,
992) -> Instruction {
993 let (lending_market_authority_pubkey, _bump_seed) = Pubkey::find_program_address(
994 &[&lending_market_pubkey.to_bytes()[..PUBKEY_BYTES]],
995 &program_id,
996 );
997 Instruction {
998 program_id,
999 accounts: vec![
1000 AccountMeta::new(source_collateral_pubkey, false),
1001 AccountMeta::new(destination_liquidity_pubkey, false),
1002 AccountMeta::new(reserve_pubkey, false),
1003 AccountMeta::new(reserve_collateral_mint_pubkey, false),
1004 AccountMeta::new(reserve_liquidity_supply_pubkey, false),
1005 AccountMeta::new_readonly(lending_market_pubkey, false),
1006 AccountMeta::new_readonly(lending_market_authority_pubkey, false),
1007 AccountMeta::new_readonly(user_transfer_authority_pubkey, true),
1008 AccountMeta::new_readonly(spl_token::id(), false),
1009 ],
1010 data: LendingInstruction::RedeemReserveCollateral { collateral_amount }.pack(),
1011 }
1012}
1013
1014#[allow(clippy::too_many_arguments)]
1016pub fn init_obligation(
1017 program_id: Pubkey,
1018 obligation_pubkey: Pubkey,
1019 lending_market_pubkey: Pubkey,
1020 obligation_owner_pubkey: Pubkey,
1021) -> Instruction {
1022 Instruction {
1023 program_id,
1024 accounts: vec![
1025 AccountMeta::new(obligation_pubkey, false),
1026 AccountMeta::new_readonly(lending_market_pubkey, false),
1027 AccountMeta::new_readonly(obligation_owner_pubkey, true),
1028 AccountMeta::new_readonly(sysvar::rent::id(), false),
1029 AccountMeta::new_readonly(spl_token::id(), false),
1030 ],
1031 data: LendingInstruction::InitObligation.pack(),
1032 }
1033}
1034
1035#[allow(clippy::too_many_arguments)]
1037pub fn refresh_obligation(
1038 program_id: Pubkey,
1039 obligation_pubkey: Pubkey,
1040 reserve_pubkeys: Vec<Pubkey>,
1041) -> Instruction {
1042 let mut accounts = vec![AccountMeta::new(obligation_pubkey, false)];
1043 accounts.extend(
1044 reserve_pubkeys
1045 .into_iter()
1046 .map(|pubkey| AccountMeta::new_readonly(pubkey, false)),
1047 );
1048 Instruction {
1049 program_id,
1050 accounts,
1051 data: LendingInstruction::RefreshObligation.pack(),
1052 }
1053}
1054
1055#[allow(clippy::too_many_arguments)]
1057pub fn deposit_obligation_collateral(
1058 program_id: Pubkey,
1059 collateral_amount: u64,
1060 source_collateral_pubkey: Pubkey,
1061 destination_collateral_pubkey: Pubkey,
1062 deposit_reserve_pubkey: Pubkey,
1063 obligation_pubkey: Pubkey,
1064 lending_market_pubkey: Pubkey,
1065 obligation_owner_pubkey: Pubkey,
1066 user_transfer_authority_pubkey: Pubkey,
1067) -> Instruction {
1068 Instruction {
1069 program_id,
1070 accounts: vec![
1071 AccountMeta::new(source_collateral_pubkey, false),
1072 AccountMeta::new(destination_collateral_pubkey, false),
1073 AccountMeta::new(deposit_reserve_pubkey, false),
1074 AccountMeta::new(obligation_pubkey, false),
1075 AccountMeta::new_readonly(lending_market_pubkey, false),
1076 AccountMeta::new_readonly(obligation_owner_pubkey, true),
1077 AccountMeta::new_readonly(user_transfer_authority_pubkey, true),
1078 AccountMeta::new_readonly(spl_token::id(), false),
1079 ],
1080 data: LendingInstruction::DepositObligationCollateral { collateral_amount }.pack(),
1081 }
1082}
1083
1084#[allow(clippy::too_many_arguments)]
1086pub fn deposit_reserve_liquidity_and_obligation_collateral(
1087 program_id: Pubkey,
1088 liquidity_amount: u64,
1089 source_liquidity_pubkey: Pubkey,
1090 user_collateral_pubkey: Pubkey,
1091 reserve_pubkey: Pubkey,
1092 reserve_liquidity_supply_pubkey: Pubkey,
1093 reserve_collateral_mint_pubkey: Pubkey,
1094 lending_market_pubkey: Pubkey,
1095 destination_deposit_collateral_pubkey: Pubkey,
1096 obligation_pubkey: Pubkey,
1097 obligation_owner_pubkey: Pubkey,
1098 reserve_liquidity_pyth_oracle_pubkey: Pubkey,
1099 reserve_liquidity_switchboard_oracle_pubkey: Pubkey,
1100 user_transfer_authority_pubkey: Pubkey,
1101) -> Instruction {
1102 let (lending_market_authority_pubkey, _bump_seed) = Pubkey::find_program_address(
1103 &[&lending_market_pubkey.to_bytes()[..PUBKEY_BYTES]],
1104 &program_id,
1105 );
1106 Instruction {
1107 program_id,
1108 accounts: vec![
1109 AccountMeta::new(source_liquidity_pubkey, false),
1110 AccountMeta::new(user_collateral_pubkey, false),
1111 AccountMeta::new(reserve_pubkey, false),
1112 AccountMeta::new(reserve_liquidity_supply_pubkey, false),
1113 AccountMeta::new(reserve_collateral_mint_pubkey, false),
1114 AccountMeta::new_readonly(lending_market_pubkey, false),
1115 AccountMeta::new_readonly(lending_market_authority_pubkey, false),
1116 AccountMeta::new(destination_deposit_collateral_pubkey, false),
1117 AccountMeta::new(obligation_pubkey, false),
1118 AccountMeta::new(obligation_owner_pubkey, true),
1119 AccountMeta::new_readonly(reserve_liquidity_pyth_oracle_pubkey, false),
1120 AccountMeta::new_readonly(reserve_liquidity_switchboard_oracle_pubkey, false),
1121 AccountMeta::new_readonly(user_transfer_authority_pubkey, true),
1122 AccountMeta::new_readonly(spl_token::id(), false),
1123 ],
1124 data: LendingInstruction::DepositReserveLiquidityAndObligationCollateral {
1125 liquidity_amount,
1126 }
1127 .pack(),
1128 }
1129}
1130
1131#[allow(clippy::too_many_arguments)]
1133pub fn withdraw_obligation_collateral_and_redeem_reserve_collateral(
1134 program_id: Pubkey,
1135 collateral_amount: u64,
1136 source_collateral_pubkey: Pubkey,
1137 destination_collateral_pubkey: Pubkey,
1138 withdraw_reserve_pubkey: Pubkey,
1139 obligation_pubkey: Pubkey,
1140 lending_market_pubkey: Pubkey,
1141 destination_liquidity_pubkey: Pubkey,
1142 reserve_collateral_mint_pubkey: Pubkey,
1143 reserve_liquidity_supply_pubkey: Pubkey,
1144 obligation_owner_pubkey: Pubkey,
1145 user_transfer_authority_pubkey: Pubkey,
1146) -> Instruction {
1147 let (lending_market_authority_pubkey, _bump_seed) = Pubkey::find_program_address(
1148 &[&lending_market_pubkey.to_bytes()[..PUBKEY_BYTES]],
1149 &program_id,
1150 );
1151 Instruction {
1152 program_id,
1153 accounts: vec![
1154 AccountMeta::new(source_collateral_pubkey, false),
1155 AccountMeta::new(destination_collateral_pubkey, false),
1156 AccountMeta::new(withdraw_reserve_pubkey, false),
1157 AccountMeta::new(obligation_pubkey, false),
1158 AccountMeta::new_readonly(lending_market_pubkey, false),
1159 AccountMeta::new_readonly(lending_market_authority_pubkey, false),
1160 AccountMeta::new(destination_liquidity_pubkey, false),
1161 AccountMeta::new(reserve_collateral_mint_pubkey, false),
1162 AccountMeta::new(reserve_liquidity_supply_pubkey, false),
1163 AccountMeta::new_readonly(obligation_owner_pubkey, true),
1164 AccountMeta::new_readonly(user_transfer_authority_pubkey, true),
1165 AccountMeta::new_readonly(spl_token::id(), false),
1166 ],
1167 data: LendingInstruction::WithdrawObligationCollateralAndRedeemReserveCollateral {
1168 collateral_amount,
1169 }
1170 .pack(),
1171 }
1172}
1173
1174#[allow(clippy::too_many_arguments)]
1176pub fn withdraw_obligation_collateral(
1177 program_id: Pubkey,
1178 collateral_amount: u64,
1179 source_collateral_pubkey: Pubkey,
1180 destination_collateral_pubkey: Pubkey,
1181 withdraw_reserve_pubkey: Pubkey,
1182 obligation_pubkey: Pubkey,
1183 lending_market_pubkey: Pubkey,
1184 obligation_owner_pubkey: Pubkey,
1185) -> Instruction {
1186 let (lending_market_authority_pubkey, _bump_seed) = Pubkey::find_program_address(
1187 &[&lending_market_pubkey.to_bytes()[..PUBKEY_BYTES]],
1188 &program_id,
1189 );
1190 Instruction {
1191 program_id,
1192 accounts: vec![
1193 AccountMeta::new(source_collateral_pubkey, false),
1194 AccountMeta::new(destination_collateral_pubkey, false),
1195 AccountMeta::new_readonly(withdraw_reserve_pubkey, false),
1196 AccountMeta::new(obligation_pubkey, false),
1197 AccountMeta::new_readonly(lending_market_pubkey, false),
1198 AccountMeta::new_readonly(lending_market_authority_pubkey, false),
1199 AccountMeta::new_readonly(obligation_owner_pubkey, true),
1200 AccountMeta::new_readonly(spl_token::id(), false),
1201 ],
1202 data: LendingInstruction::WithdrawObligationCollateral { collateral_amount }.pack(),
1203 }
1204}
1205
1206#[allow(clippy::too_many_arguments)]
1208pub fn borrow_obligation_liquidity(
1209 program_id: Pubkey,
1210 liquidity_amount: u64,
1211 source_liquidity_pubkey: Pubkey,
1212 destination_liquidity_pubkey: Pubkey,
1213 borrow_reserve_pubkey: Pubkey,
1214 borrow_reserve_liquidity_fee_receiver_pubkey: Pubkey,
1215 obligation_pubkey: Pubkey,
1216 lending_market_pubkey: Pubkey,
1217 obligation_owner_pubkey: Pubkey,
1218 host_fee_receiver_pubkey: Option<Pubkey>,
1219) -> Instruction {
1220 let (lending_market_authority_pubkey, _bump_seed) = Pubkey::find_program_address(
1221 &[&lending_market_pubkey.to_bytes()[..PUBKEY_BYTES]],
1222 &program_id,
1223 );
1224 let mut accounts = vec![
1225 AccountMeta::new(source_liquidity_pubkey, false),
1226 AccountMeta::new(destination_liquidity_pubkey, false),
1227 AccountMeta::new(borrow_reserve_pubkey, false),
1228 AccountMeta::new(borrow_reserve_liquidity_fee_receiver_pubkey, false),
1229 AccountMeta::new(obligation_pubkey, false),
1230 AccountMeta::new_readonly(lending_market_pubkey, false),
1231 AccountMeta::new_readonly(lending_market_authority_pubkey, false),
1232 AccountMeta::new_readonly(obligation_owner_pubkey, true),
1233 AccountMeta::new_readonly(spl_token::id(), false),
1234 ];
1235 if let Some(host_fee_receiver_pubkey) = host_fee_receiver_pubkey {
1236 accounts.push(AccountMeta::new(host_fee_receiver_pubkey, false));
1237 }
1238 Instruction {
1239 program_id,
1240 accounts,
1241 data: LendingInstruction::BorrowObligationLiquidity { liquidity_amount }.pack(),
1242 }
1243}
1244
1245#[allow(clippy::too_many_arguments)]
1247pub fn repay_obligation_liquidity(
1248 program_id: Pubkey,
1249 liquidity_amount: u64,
1250 source_liquidity_pubkey: Pubkey,
1251 destination_liquidity_pubkey: Pubkey,
1252 repay_reserve_pubkey: Pubkey,
1253 obligation_pubkey: Pubkey,
1254 lending_market_pubkey: Pubkey,
1255 user_transfer_authority_pubkey: Pubkey,
1256) -> Instruction {
1257 Instruction {
1258 program_id,
1259 accounts: vec![
1260 AccountMeta::new(source_liquidity_pubkey, false),
1261 AccountMeta::new(destination_liquidity_pubkey, false),
1262 AccountMeta::new(repay_reserve_pubkey, false),
1263 AccountMeta::new(obligation_pubkey, false),
1264 AccountMeta::new_readonly(lending_market_pubkey, false),
1265 AccountMeta::new_readonly(user_transfer_authority_pubkey, true),
1266 AccountMeta::new_readonly(spl_token::id(), false),
1267 ],
1268 data: LendingInstruction::RepayObligationLiquidity { liquidity_amount }.pack(),
1269 }
1270}
1271
1272#[allow(clippy::too_many_arguments)]
1274pub fn liquidate_obligation(
1275 program_id: Pubkey,
1276 liquidity_amount: u64,
1277 source_liquidity_pubkey: Pubkey,
1278 destination_collateral_pubkey: Pubkey,
1279 repay_reserve_pubkey: Pubkey,
1280 repay_reserve_liquidity_supply_pubkey: Pubkey,
1281 withdraw_reserve_pubkey: Pubkey,
1282 withdraw_reserve_collateral_supply_pubkey: Pubkey,
1283 obligation_pubkey: Pubkey,
1284 lending_market_pubkey: Pubkey,
1285 user_transfer_authority_pubkey: Pubkey,
1286) -> Instruction {
1287 let (lending_market_authority_pubkey, _bump_seed) = Pubkey::find_program_address(
1288 &[&lending_market_pubkey.to_bytes()[..PUBKEY_BYTES]],
1289 &program_id,
1290 );
1291 Instruction {
1292 program_id,
1293 accounts: vec![
1294 AccountMeta::new(source_liquidity_pubkey, false),
1295 AccountMeta::new(destination_collateral_pubkey, false),
1296 AccountMeta::new(repay_reserve_pubkey, false),
1297 AccountMeta::new(repay_reserve_liquidity_supply_pubkey, false),
1298 AccountMeta::new_readonly(withdraw_reserve_pubkey, false),
1299 AccountMeta::new(withdraw_reserve_collateral_supply_pubkey, false),
1300 AccountMeta::new(obligation_pubkey, false),
1301 AccountMeta::new_readonly(lending_market_pubkey, false),
1302 AccountMeta::new_readonly(lending_market_authority_pubkey, false),
1303 AccountMeta::new_readonly(user_transfer_authority_pubkey, true),
1304 AccountMeta::new_readonly(spl_token::id(), false),
1305 ],
1306 data: LendingInstruction::LiquidateObligation { liquidity_amount }.pack(),
1307 }
1308}
1309
1310#[allow(clippy::too_many_arguments)]
1312pub fn update_reserve_config(
1313 program_id: Pubkey,
1314 config: ReserveConfig,
1315 reserve_pubkey: Pubkey,
1316 lending_market_pubkey: Pubkey,
1317 lending_market_owner_pubkey: Pubkey,
1318 pyth_product_pubkey: Pubkey,
1319 pyth_price_pubkey: Pubkey,
1320 switchboard_feed_pubkey: Pubkey,
1321) -> Instruction {
1322 let (lending_market_authority_pubkey, _bump_seed) = Pubkey::find_program_address(
1323 &[&lending_market_pubkey.to_bytes()[..PUBKEY_BYTES]],
1324 &program_id,
1325 );
1326 let accounts = vec![
1327 AccountMeta::new(reserve_pubkey, false),
1328 AccountMeta::new_readonly(lending_market_pubkey, false),
1329 AccountMeta::new_readonly(lending_market_authority_pubkey, false),
1330 AccountMeta::new_readonly(lending_market_owner_pubkey, true),
1331 AccountMeta::new_readonly(pyth_product_pubkey, false),
1332 AccountMeta::new_readonly(pyth_price_pubkey, false),
1333 AccountMeta::new_readonly(switchboard_feed_pubkey, false),
1334 ];
1335 Instruction {
1336 program_id,
1337 accounts,
1338 data: LendingInstruction::UpdateReserveConfig { config }.pack(),
1339 }
1340}
1341
1342#[allow(clippy::too_many_arguments)]
1344pub fn liquidate_obligation_and_redeem_reserve_collateral(
1345 program_id: Pubkey,
1346 liquidity_amount: u64,
1347 source_liquidity_pubkey: Pubkey,
1348 destination_collateral_pubkey: Pubkey,
1349 destination_liquidity_pubkey: Pubkey,
1350 repay_reserve_pubkey: Pubkey,
1351 repay_reserve_liquidity_supply_pubkey: Pubkey,
1352 withdraw_reserve_pubkey: Pubkey,
1353 withdraw_reserve_collateral_mint_pubkey: Pubkey,
1354 withdraw_reserve_collateral_supply_pubkey: Pubkey,
1355 withdraw_reserve_liquidity_supply_pubkey: Pubkey,
1356 withdraw_reserve_liquidity_fee_receiver_pubkey: Pubkey,
1357 obligation_pubkey: Pubkey,
1358 lending_market_pubkey: Pubkey,
1359 user_transfer_authority_pubkey: Pubkey,
1360) -> Instruction {
1361 let (lending_market_authority_pubkey, _bump_seed) = Pubkey::find_program_address(
1362 &[&lending_market_pubkey.to_bytes()[..PUBKEY_BYTES]],
1363 &program_id,
1364 );
1365 Instruction {
1366 program_id,
1367 accounts: vec![
1368 AccountMeta::new(source_liquidity_pubkey, false),
1369 AccountMeta::new(destination_collateral_pubkey, false),
1370 AccountMeta::new(destination_liquidity_pubkey, false),
1371 AccountMeta::new(repay_reserve_pubkey, false),
1372 AccountMeta::new(repay_reserve_liquidity_supply_pubkey, false),
1373 AccountMeta::new(withdraw_reserve_pubkey, false),
1374 AccountMeta::new(withdraw_reserve_collateral_mint_pubkey, false),
1375 AccountMeta::new(withdraw_reserve_collateral_supply_pubkey, false),
1376 AccountMeta::new(withdraw_reserve_liquidity_supply_pubkey, false),
1377 AccountMeta::new(withdraw_reserve_liquidity_fee_receiver_pubkey, false),
1378 AccountMeta::new(obligation_pubkey, false),
1379 AccountMeta::new_readonly(lending_market_pubkey, false),
1380 AccountMeta::new_readonly(lending_market_authority_pubkey, false),
1381 AccountMeta::new_readonly(user_transfer_authority_pubkey, true),
1382 AccountMeta::new_readonly(spl_token::id(), false),
1383 ],
1384 data: LendingInstruction::LiquidateObligationAndRedeemReserveCollateral {
1385 liquidity_amount,
1386 }
1387 .pack(),
1388 }
1389}
1390
1391pub fn redeem_fees(
1393 program_id: Pubkey,
1394 reserve_pubkey: Pubkey,
1395 reserve_liquidity_fee_receiver_pubkey: Pubkey,
1396 reserve_supply_liquidity_pubkey: Pubkey,
1397 lending_market_pubkey: Pubkey,
1398) -> Instruction {
1399 let (lending_market_authority_pubkey, _bump_seed) = Pubkey::find_program_address(
1400 &[&lending_market_pubkey.to_bytes()[..PUBKEY_BYTES]],
1401 &program_id,
1402 );
1403 let accounts = vec![
1404 AccountMeta::new(reserve_pubkey, false),
1405 AccountMeta::new(reserve_liquidity_fee_receiver_pubkey, false),
1406 AccountMeta::new(reserve_supply_liquidity_pubkey, false),
1407 AccountMeta::new_readonly(lending_market_pubkey, false),
1408 AccountMeta::new_readonly(lending_market_authority_pubkey, false),
1409 AccountMeta::new_readonly(spl_token::id(), false),
1410 ];
1411 Instruction {
1412 program_id,
1413 accounts,
1414 data: LendingInstruction::RedeemFees.pack(),
1415 }
1416}
1417
1418#[allow(clippy::too_many_arguments)]
1420pub fn flash_borrow_reserve_liquidity(
1421 program_id: Pubkey,
1422 liquidity_amount: u64,
1423 source_liquidity_pubkey: Pubkey,
1424 destination_liquidity_pubkey: Pubkey,
1425 reserve_pubkey: Pubkey,
1426 lending_market_pubkey: Pubkey,
1427) -> Instruction {
1428 let (lending_market_authority_pubkey, _bump_seed) = Pubkey::find_program_address(
1429 &[&lending_market_pubkey.to_bytes()[..PUBKEY_BYTES]],
1430 &program_id,
1431 );
1432
1433 Instruction {
1434 program_id,
1435 accounts: vec![
1436 AccountMeta::new(source_liquidity_pubkey, false),
1437 AccountMeta::new(destination_liquidity_pubkey, false),
1438 AccountMeta::new(reserve_pubkey, false),
1439 AccountMeta::new_readonly(lending_market_pubkey, false),
1440 AccountMeta::new_readonly(lending_market_authority_pubkey, false),
1441 AccountMeta::new_readonly(sysvar::instructions::id(), false),
1442 AccountMeta::new_readonly(spl_token::id(), false),
1443 ],
1444 data: LendingInstruction::FlashBorrowReserveLiquidity { liquidity_amount }.pack(),
1445 }
1446}
1447
1448#[allow(clippy::too_many_arguments)]
1450pub fn flash_repay_reserve_liquidity(
1451 program_id: Pubkey,
1452 liquidity_amount: u64,
1453 borrow_instruction_index: u8,
1454 source_liquidity_pubkey: Pubkey,
1455 destination_liquidity_pubkey: Pubkey,
1456 reserve_liquidity_fee_receiver_pubkey: Pubkey,
1457 host_fee_receiver_pubkey: Pubkey,
1458 reserve_pubkey: Pubkey,
1459 lending_market_pubkey: Pubkey,
1460 user_transfer_authority_pubkey: Pubkey,
1461) -> Instruction {
1462 Instruction {
1463 program_id,
1464 accounts: vec![
1465 AccountMeta::new(source_liquidity_pubkey, false),
1466 AccountMeta::new(destination_liquidity_pubkey, false),
1467 AccountMeta::new(reserve_liquidity_fee_receiver_pubkey, false),
1468 AccountMeta::new(host_fee_receiver_pubkey, false),
1469 AccountMeta::new(reserve_pubkey, false),
1470 AccountMeta::new_readonly(lending_market_pubkey, false),
1471 AccountMeta::new_readonly(user_transfer_authority_pubkey, true),
1472 AccountMeta::new_readonly(sysvar::instructions::id(), false),
1473 AccountMeta::new_readonly(spl_token::id(), false),
1474 ],
1475 data: LendingInstruction::FlashRepayReserveLiquidity {
1476 liquidity_amount,
1477 borrow_instruction_index,
1478 }
1479 .pack(),
1480 }
1481}