mc/flash loan for delegate (#271)
* flash loan for delegates Signed-off-by: microwavedcola1 <microwavedcola@gmail.com> * Fix rust client Signed-off-by: microwavedcola1 <microwavedcola@gmail.com> * prettier Signed-off-by: microwavedcola1 <microwavedcola@gmail.com> Signed-off-by: microwavedcola1 <microwavedcola@gmail.com>
This commit is contained in:
parent
7da421ea1c
commit
e8ba511c45
|
@ -1275,6 +1275,8 @@ impl MangoClient {
|
|||
accounts: {
|
||||
let mut ams = anchor_lang::ToAccountMetas::to_account_metas(
|
||||
&mango_v4::accounts::FlashLoanBegin {
|
||||
account: self.mango_account_address,
|
||||
owner: self.owner(),
|
||||
token_program: Token::id(),
|
||||
instructions: solana_sdk::sysvar::instructions::id(),
|
||||
},
|
||||
|
|
|
@ -11,9 +11,19 @@ use crate::util::checked_math as cm;
|
|||
use anchor_lang::prelude::*;
|
||||
use anchor_lang::solana_program::sysvar::instructions as tx_instructions;
|
||||
use anchor_lang::Discriminator;
|
||||
use anchor_spl::associated_token::AssociatedToken;
|
||||
use anchor_spl::token::{self, Token, TokenAccount};
|
||||
use fixed::types::I80F48;
|
||||
|
||||
pub mod jupiter_mainnet_4 {
|
||||
use solana_program::declare_id;
|
||||
declare_id!("JUP4Fb2cqiRUcaTHdrPC8h2gNsA2ETXiPDD33WcGuJB");
|
||||
}
|
||||
pub mod jupiter_mainnet_3 {
|
||||
use solana_program::declare_id;
|
||||
declare_id!("JUP3c2Uh3WA4Ng34tw6kPd2G4C5BB21Xo36Je1s32Ph");
|
||||
}
|
||||
|
||||
/// Sets up mango vaults for flash loan
|
||||
///
|
||||
/// In addition to these accounts, there must be remaining_accounts:
|
||||
|
@ -24,6 +34,10 @@ use fixed::types::I80F48;
|
|||
/// 4. the mango group
|
||||
#[derive(Accounts)]
|
||||
pub struct FlashLoanBegin<'info> {
|
||||
pub account: AccountLoaderDynamic<'info, MangoAccount>,
|
||||
// owner is checked at #1
|
||||
pub owner: Signer<'info>,
|
||||
|
||||
pub token_program: Program<'info, Token>,
|
||||
|
||||
/// Instructions Sysvar for instruction introspection
|
||||
|
@ -42,11 +56,9 @@ pub struct FlashLoanBegin<'info> {
|
|||
/// 4. the mango group
|
||||
#[derive(Accounts)]
|
||||
pub struct FlashLoanEnd<'info> {
|
||||
#[account(
|
||||
mut,
|
||||
has_one = owner
|
||||
)]
|
||||
#[account(mut)]
|
||||
pub account: AccountLoaderDynamic<'info, MangoAccount>,
|
||||
// owner is checked at #1
|
||||
pub owner: Signer<'info>,
|
||||
|
||||
pub token_program: Program<'info, Token>,
|
||||
|
@ -65,6 +77,14 @@ pub fn flash_loan_begin<'key, 'accounts, 'remaining, 'info>(
|
|||
ctx: Context<'key, 'accounts, 'remaining, 'info, FlashLoanBegin<'info>>,
|
||||
loan_amounts: Vec<u64>,
|
||||
) -> Result<()> {
|
||||
let account = ctx.accounts.account.load_mut()?;
|
||||
|
||||
// account constraint #1
|
||||
require!(
|
||||
account.fixed.is_owner_or_delegate(ctx.accounts.owner.key()),
|
||||
MangoError::SomeError
|
||||
);
|
||||
|
||||
let num_loans = loan_amounts.len();
|
||||
require_eq!(ctx.remaining_accounts.len(), 3 * num_loans + 1);
|
||||
let banks = &ctx.remaining_accounts[..num_loans];
|
||||
|
@ -156,6 +176,15 @@ pub fn flash_loan_begin<'key, 'accounts, 'remaining, 'info>(
|
|||
Err(e) => return Err(e.into()),
|
||||
};
|
||||
|
||||
if account.fixed.is_delegate(ctx.accounts.owner.key()) {
|
||||
require_msg!(
|
||||
ix.program_id == AssociatedToken::id()
|
||||
|| ix.program_id == jupiter_mainnet_3::ID
|
||||
|| ix.program_id == jupiter_mainnet_4::ID,
|
||||
"delegate is only allowed to pass in ixs to ATA or Jupiter v3 or v4 programs"
|
||||
);
|
||||
}
|
||||
|
||||
// Check that the mango program key is not used
|
||||
if ix.program_id == crate::id() {
|
||||
// must be the last mango ix -- this could possibly be relaxed, but right now
|
||||
|
@ -172,6 +201,11 @@ pub fn flash_loan_begin<'key, 'accounts, 'remaining, 'info>(
|
|||
MangoError::SomeError
|
||||
);
|
||||
|
||||
require_msg!(
|
||||
ctx.accounts.account.key() == ix.accounts[0].pubkey,
|
||||
"the mango account passed to FlashLoanBegin and End must match"
|
||||
);
|
||||
|
||||
// check that the same vaults and token accounts are passed
|
||||
let begin_accounts = &ctx.remaining_accounts[num_loans..];
|
||||
let end_accounts = &ix.accounts[ix.accounts.len() - begin_accounts.len()..];
|
||||
|
@ -208,6 +242,13 @@ pub fn flash_loan_end<'key, 'accounts, 'remaining, 'info>(
|
|||
flash_loan_type: FlashLoanType,
|
||||
) -> Result<()> {
|
||||
let mut account = ctx.accounts.account.load_mut()?;
|
||||
|
||||
// account constraint #1
|
||||
require!(
|
||||
account.fixed.is_owner_or_delegate(ctx.accounts.owner.key()),
|
||||
MangoError::SomeError
|
||||
);
|
||||
|
||||
let group = account.fixed.group;
|
||||
|
||||
let remaining_len = ctx.remaining_accounts.len();
|
||||
|
|
|
@ -220,6 +220,10 @@ impl MangoAccountFixed {
|
|||
self.owner == ix_signer || self.delegate == ix_signer
|
||||
}
|
||||
|
||||
pub fn is_delegate(&self, ix_signer: Pubkey) -> bool {
|
||||
self.delegate == ix_signer
|
||||
}
|
||||
|
||||
pub fn being_liquidated(&self) -> bool {
|
||||
self.being_liquidated == 1
|
||||
}
|
||||
|
|
|
@ -367,7 +367,9 @@ pub async fn check_prev_instruction_post_health(solana: &SolanaCookie, account:
|
|||
//
|
||||
|
||||
pub struct FlashLoanBeginInstruction {
|
||||
pub account: Pubkey,
|
||||
pub group: Pubkey,
|
||||
pub owner: TestKeypair,
|
||||
pub mango_token_bank: Pubkey,
|
||||
pub mango_token_vault: Pubkey,
|
||||
pub target_token_account: Pubkey,
|
||||
|
@ -384,6 +386,8 @@ impl ClientInstruction for FlashLoanBeginInstruction {
|
|||
let program_id = mango_v4::id();
|
||||
|
||||
let accounts = Self::Accounts {
|
||||
account: self.account,
|
||||
owner: self.owner.pubkey(),
|
||||
token_program: Token::id(),
|
||||
instructions: solana_program::sysvar::instructions::id(),
|
||||
};
|
||||
|
|
|
@ -123,6 +123,8 @@ async fn test_margin_trade() -> Result<(), BanksClientError> {
|
|||
let send_flash_loan_tx = |solana, withdraw_amount, deposit_amount| async move {
|
||||
let mut tx = ClientTransaction::new(solana);
|
||||
tx.add_instruction(FlashLoanBeginInstruction {
|
||||
account,
|
||||
owner,
|
||||
group,
|
||||
mango_token_bank: bank,
|
||||
mango_token_vault: vault,
|
||||
|
|
|
@ -203,7 +203,7 @@ describe('Health Cache', () => {
|
|||
0,
|
||||
new BN(0),
|
||||
new BN(0),
|
||||
new BN(0),
|
||||
new BN(0),
|
||||
);
|
||||
const pi1 = PerpInfo.fromPerpPosition(pM, pp);
|
||||
|
||||
|
|
|
@ -2052,7 +2052,6 @@ export class MangoClient {
|
|||
.flashLoanEnd(flashLoanType)
|
||||
.accounts({
|
||||
account: mangoAccount.publicKey,
|
||||
owner: (this.program.provider as AnchorProvider).wallet.publicKey,
|
||||
})
|
||||
.remainingAccounts([
|
||||
...parsedHealthAccounts,
|
||||
|
@ -2076,6 +2075,8 @@ export class MangoClient {
|
|||
) /* we don't care about borrowing the target amount, this is just a dummy */,
|
||||
])
|
||||
.accounts({
|
||||
account: mangoAccount.publicKey,
|
||||
owner: (this.program.provider as AnchorProvider).wallet.publicKey,
|
||||
instructions: SYSVAR_INSTRUCTIONS_PUBKEY,
|
||||
})
|
||||
.remainingAccounts([
|
||||
|
|
|
@ -1239,6 +1239,16 @@ export type MangoV4 = {
|
|||
{
|
||||
"name": "flashLoanBegin",
|
||||
"accounts": [
|
||||
{
|
||||
"name": "account",
|
||||
"isMut": false,
|
||||
"isSigner": false
|
||||
},
|
||||
{
|
||||
"name": "owner",
|
||||
"isMut": false,
|
||||
"isSigner": true
|
||||
},
|
||||
{
|
||||
"name": "tokenProgram",
|
||||
"isMut": false,
|
||||
|
@ -8058,6 +8068,16 @@ export const IDL: MangoV4 = {
|
|||
{
|
||||
"name": "flashLoanBegin",
|
||||
"accounts": [
|
||||
{
|
||||
"name": "account",
|
||||
"isMut": false,
|
||||
"isSigner": false
|
||||
},
|
||||
{
|
||||
"name": "owner",
|
||||
"isMut": false,
|
||||
"isSigner": true
|
||||
},
|
||||
{
|
||||
"name": "tokenProgram",
|
||||
"isMut": false,
|
||||
|
|
Loading…
Reference in New Issue