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:
microwavedcola1 2022-11-09 09:35:13 +01:00 committed by GitHub
parent 7da421ea1c
commit e8ba511c45
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 80 additions and 6 deletions

View File

@ -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(),
},

View File

@ -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();

View File

@ -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
}

View File

@ -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(),
};

View File

@ -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,

View File

@ -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);

View File

@ -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([

View File

@ -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,