add borrowAndWithdraw function

This commit is contained in:
Tyler Shipe 2021-04-20 14:10:16 -04:00
parent 9c539e7945
commit a203b31eab
2 changed files with 201 additions and 52 deletions

View File

@ -40,9 +40,11 @@ import { SRM_DECIMALS } from '@project-serum/serum/lib/token-instructions';
import { Order } from '@project-serum/serum/lib/market';
import Wallet from '@project-serum/sol-wallet-adapter';
import {
makeBorrowInstruction,
makeCancelOrderInstruction,
makeForceCancelOrdersInstruction, makePartialLiquidateInstruction,
makeSettleFundsInstruction,
makeWithdrawInstruction,
} from './instruction';
import { Aggregator } from './schema';
import { TOKEN_PROGRAM_ID } from '@solana/spl-token';
@ -574,22 +576,18 @@ export class MangoClient {
const tokenIndex = mangoGroup.getTokenIndex(token)
const nativeQuantity = uiToNative(quantity, mangoGroup.mintDecimals[tokenIndex])
const keys = [
{ isSigner: false, isWritable: true, pubkey: mangoGroup.publicKey},
{ isSigner: false, isWritable: true, pubkey: marginAccount.publicKey },
{ isSigner: true, isWritable: false, pubkey: owner.publicKey },
{ isSigner: false, isWritable: true, pubkey: tokenAcc },
{ isSigner: false, isWritable: true, pubkey: mangoGroup.vaults[tokenIndex] },
{ isSigner: false, isWritable: false, pubkey: mangoGroup.signerKey },
{ isSigner: false, isWritable: false, pubkey: TOKEN_PROGRAM_ID },
{ isSigner: false, isWritable: false, pubkey: SYSVAR_CLOCK_PUBKEY },
...marginAccount.openOrders.map( (pubkey) => ( { isSigner: false, isWritable: false, pubkey })),
...mangoGroup.oracles.map( (pubkey) => ( { isSigner: false, isWritable: false, pubkey }))
]
const data = encodeMangoInstruction({Withdraw: {quantity: nativeQuantity}})
const instruction = new TransactionInstruction( { keys, data, programId })
const instruction = makeWithdrawInstruction(
programId,
mangoGroup.publicKey,
marginAccount.publicKey,
owner.publicKey,
mangoGroup.signerKey,
tokenAcc,
mangoGroup.vaults[tokenIndex],
marginAccount.openOrders,
mangoGroup.oracles,
nativeQuantity,
);
const transaction = new Transaction()
transaction.add(instruction)
@ -611,18 +609,16 @@ export class MangoClient {
const tokenIndex = mangoGroup.getTokenIndex(token)
const nativeQuantity = uiToNative(quantity, mangoGroup.mintDecimals[tokenIndex])
const keys = [
{ isSigner: false, isWritable: true, pubkey: mangoGroup.publicKey},
{ isSigner: false, isWritable: true, pubkey: marginAccount.publicKey },
{ isSigner: true, isWritable: false, pubkey: owner.publicKey },
{ isSigner: false, isWritable: false, pubkey: SYSVAR_CLOCK_PUBKEY },
...marginAccount.openOrders.map( (pubkey) => ( { isSigner: false, isWritable: false, pubkey })),
...mangoGroup.oracles.map( (pubkey) => ( { isSigner: false, isWritable: false, pubkey })),
]
const data = encodeMangoInstruction({Borrow: {tokenIndex: new BN(tokenIndex), quantity: nativeQuantity}})
const instruction = new TransactionInstruction( { keys, data, programId })
const instruction = makeBorrowInstruction(
programId,
mangoGroup.publicKey,
marginAccount.publicKey,
owner.publicKey,
tokenIndex,
marginAccount.openOrders,
mangoGroup.oracles,
nativeQuantity,
);
const transaction = new Transaction()
transaction.add(instruction)
@ -631,6 +627,65 @@ export class MangoClient {
return await this.sendTransaction(connection, transaction, owner, additionalSigners)
}
async borrowAndWithdraw(
connection: Connection,
programId: PublicKey,
mangoGroup: MangoGroup,
marginAccount: MarginAccount,
wallet: Wallet | Account,
token: PublicKey,
tokenAcc: PublicKey,
withdrawQuantity: number
): Promise<TransactionSignature> {
const transaction = new Transaction()
const tokenIndex = mangoGroup.getTokenIndex(token)
const tokenBalance = marginAccount.getUiDeposit(mangoGroup, tokenIndex)
const borrowQuantity = withdrawQuantity - tokenBalance
const nativeBorrowQuantity = uiToNative(
borrowQuantity,
mangoGroup.mintDecimals[tokenIndex]
)
const borrowInstruction = makeBorrowInstruction(
programId,
mangoGroup.publicKey,
marginAccount.publicKey,
wallet.publicKey,
tokenIndex,
marginAccount.openOrders,
mangoGroup.oracles,
nativeBorrowQuantity,
);
transaction.add(borrowInstruction);
// uiToNative() uses Math.round resulting in rounding
// errors, so we use Math.floor here instead
const nativeWithdrawQuantity = new BN(
Math.floor(
withdrawQuantity * Math.pow(10, mangoGroup.mintDecimals[tokenIndex]),
) * 0.98,
);
const withdrawInstruction = makeWithdrawInstruction(
programId,
mangoGroup.publicKey,
marginAccount.publicKey,
wallet.publicKey,
mangoGroup.signerKey,
tokenAcc,
mangoGroup.vaults[tokenIndex],
marginAccount.openOrders,
mangoGroup.oracles,
nativeWithdrawQuantity,
);
transaction.add(withdrawInstruction);
const signers = []
return await this.sendTransaction(connection, transaction, wallet, signers)
}
async settleBorrow(
connection: Connection,
programId: PublicKey,

View File

@ -115,6 +115,85 @@ export function makeSettleFundsInstruction(
return new TransactionInstruction({ keys, data, programId });
}
export function makeBorrowInstruction(
programId: PublicKey,
mangoGroupPk: PublicKey,
marginAccountPk: PublicKey,
walletPk: PublicKey,
tokenIndex: number,
openOrders: PublicKey[],
oracles: PublicKey[],
nativeQuantity: BN,
): TransactionInstruction {
const borrowKeys = [
{ isSigner: false, isWritable: true, pubkey: mangoGroupPk },
{ isSigner: false, isWritable: true, pubkey: marginAccountPk },
{ isSigner: true, isWritable: false, pubkey: walletPk },
{ isSigner: false, isWritable: false, pubkey: SYSVAR_CLOCK_PUBKEY },
...openOrders.map((pubkey) => ({
isSigner: false,
isWritable: false,
pubkey,
})),
...oracles.map((pubkey) => ({
isSigner: false,
isWritable: false,
pubkey,
})),
];
const borrowData = encodeMangoInstruction({
Borrow: { tokenIndex: new BN(tokenIndex), quantity: nativeQuantity },
});
return new TransactionInstruction({
keys: borrowKeys,
data: borrowData,
programId,
});
}
export function makeWithdrawInstruction(
programId: PublicKey,
mangoGroupPk: PublicKey,
marginAccountPk: PublicKey,
walletPk: PublicKey,
signerKey: PublicKey,
tokenAccPk: PublicKey,
vaultPk: PublicKey,
openOrders: PublicKey[],
oracles: PublicKey[],
nativeQuantity: BN,
): TransactionInstruction {
const withdrawKeys = [
{ isSigner: false, isWritable: true, pubkey: mangoGroupPk },
{ isSigner: false, isWritable: true, pubkey: marginAccountPk },
{ isSigner: true, isWritable: false, pubkey: walletPk },
{ isSigner: false, isWritable: true, pubkey: tokenAccPk },
{ isSigner: false, isWritable: true, pubkey: vaultPk },
{ isSigner: false, isWritable: false, pubkey: signerKey },
{ isSigner: false, isWritable: false, pubkey: TOKEN_PROGRAM_ID },
{ isSigner: false, isWritable: false, pubkey: SYSVAR_CLOCK_PUBKEY },
...openOrders.map((pubkey) => ({
isSigner: false,
isWritable: false,
pubkey,
})),
...oracles.map((pubkey) => ({
isSigner: false,
isWritable: false,
pubkey,
})),
];
const withdrawData = encodeMangoInstruction({
Withdraw: { quantity: nativeQuantity },
});
return new TransactionInstruction({
keys: withdrawKeys,
data: withdrawData,
programId,
});
}
export function makeSettleBorrowInstruction(
programId: PublicKey,
mangoGroupPk: PublicKey,
@ -153,32 +232,39 @@ export function makeForceCancelOrdersInstruction(
dexProgramId: PublicKey,
openOrders: PublicKey[],
oracles: PublicKey[],
limit: BN
limit: BN,
): TransactionInstruction {
const keys = [
{ isSigner: false, isWritable: true, pubkey: mangoGroup},
{ isSigner: false, isWritable: true, pubkey: mangoGroup },
{ isSigner: true, isWritable: false, pubkey: liqor },
{ isSigner: false, isWritable: true, pubkey: liqeeMarginAccount },
{ isSigner: false, isWritable: true, pubkey: baseVault },
{ isSigner: false, isWritable: true, pubkey: quoteVault },
{ isSigner: false, isWritable: true, pubkey: spotMarket },
{ isSigner: false, isWritable: true, pubkey: bids },
{ isSigner: false, isWritable: true, pubkey: asks },
{ isSigner: false, isWritable: false, pubkey: signerKey },
{ isSigner: false, isWritable: true, pubkey: dexEventQueue },
{ isSigner: false, isWritable: true, pubkey: liqeeMarginAccount },
{ isSigner: false, isWritable: true, pubkey: baseVault },
{ isSigner: false, isWritable: true, pubkey: quoteVault },
{ isSigner: false, isWritable: true, pubkey: spotMarket },
{ isSigner: false, isWritable: true, pubkey: bids },
{ isSigner: false, isWritable: true, pubkey: asks },
{ isSigner: false, isWritable: false, pubkey: signerKey },
{ isSigner: false, isWritable: true, pubkey: dexEventQueue },
{ isSigner: false, isWritable: true, pubkey: dexBaseVault },
{ isSigner: false, isWritable: true, pubkey: dexQuoteVault },
{ isSigner: false, isWritable: false, pubkey: dexSigner },
{ isSigner: false, isWritable: false, pubkey: TOKEN_PROGRAM_ID },
{ isSigner: false, isWritable: false, pubkey: dexProgramId },
{ isSigner: false, isWritable: false, pubkey: SYSVAR_CLOCK_PUBKEY },
...openOrders.map( (pubkey) => ( { isSigner: false, isWritable: true, pubkey })),
...oracles.map( (pubkey) => ( { isSigner: false, isWritable: false, pubkey })),
]
...openOrders.map((pubkey) => ({
isSigner: false,
isWritable: true,
pubkey,
})),
...oracles.map((pubkey) => ({
isSigner: false,
isWritable: false,
pubkey,
})),
];
const data = encodeMangoInstruction({ForceCancelOrders: { limit }})
return new TransactionInstruction( { keys, data, programId })
const data = encodeMangoInstruction({ ForceCancelOrders: { limit } });
return new TransactionInstruction({ keys, data, programId });
}
export function makePartialLiquidateInstruction(
@ -193,23 +279,31 @@ export function makePartialLiquidateInstruction(
signerKey: PublicKey,
openOrders: PublicKey[],
oracles: PublicKey[],
maxDeposit: BN
maxDeposit: BN,
): TransactionInstruction {
const keys = [
{ isSigner: false, isWritable: true, pubkey: mangoGroup },
{ isSigner: true, isWritable: false, pubkey: liqor },
{ isSigner: false, isWritable: true, pubkey: liqorInTokenWallet },
{ isSigner: false, isWritable: true, pubkey: liqorOutTokenWallet },
{ isSigner: false, isWritable: true, pubkey: liqeeMarginAccount },
{ isSigner: false, isWritable: true, pubkey: liqeeMarginAccount },
{ isSigner: false, isWritable: true, pubkey: inTokenVault },
{ isSigner: false, isWritable: true, pubkey: outTokenVault },
{ isSigner: false, isWritable: false, pubkey: signerKey },
{ isSigner: false, isWritable: false, pubkey: TOKEN_PROGRAM_ID },
{ isSigner: false, isWritable: false, pubkey: SYSVAR_CLOCK_PUBKEY },
...openOrders.map( (pubkey) => ( { isSigner: false, isWritable: false, pubkey })),
...oracles.map( (pubkey) => ( { isSigner: false, isWritable: false, pubkey })),
]
const data = encodeMangoInstruction({PartialLiquidate: { maxDeposit }})
...openOrders.map((pubkey) => ({
isSigner: false,
isWritable: false,
pubkey,
})),
...oracles.map((pubkey) => ({
isSigner: false,
isWritable: false,
pubkey,
})),
];
const data = encodeMangoInstruction({ PartialLiquidate: { maxDeposit } });
return new TransactionInstruction( { keys, data, programId })
}
return new TransactionInstruction({ keys, data, programId });
}