2023-06-15 23:04:58 -07:00
import {
AnchorProvider ,
BN ,
Program ,
Provider ,
Wallet ,
} from '@coral-xyz/anchor' ;
2023-07-03 05:09:11 -07:00
import * as borsh from '@coral-xyz/borsh' ;
2023-07-04 00:26:59 -07:00
import { OpenOrders } from '@project-serum/serum' ;
2023-02-28 03:05:02 -08:00
import {
createCloseAccountInstruction ,
createInitializeAccount3Instruction ,
} from '@solana/spl-token' ;
2022-04-07 09:58:42 -07:00
import {
2023-07-04 00:26:59 -07:00
AccountInfo ,
2022-04-07 12:00:08 -07:00
AccountMeta ,
2022-12-15 14:22:10 -08:00
AddressLookupTableAccount ,
2022-06-11 04:49:45 -07:00
Cluster ,
2023-02-06 02:59:12 -08:00
Commitment ,
2023-09-19 22:08:23 -07:00
ComputeBudgetProgram ,
2023-04-13 03:44:12 -07:00
Connection ,
2022-05-11 04:33:01 -07:00
Keypair ,
2022-04-08 03:30:21 -07:00
MemcmpFilter ,
2022-04-07 12:00:08 -07:00
PublicKey ,
2023-09-07 23:28:34 -07:00
RecentPrioritizationFees ,
2022-07-06 21:45:01 -07:00
SYSVAR_INSTRUCTIONS_PUBKEY ,
2022-04-07 12:00:08 -07:00
SYSVAR_RENT_PUBKEY ,
2022-12-19 06:40:14 -08:00
SystemProgram ,
2022-05-25 17:29:06 -07:00
TransactionInstruction ,
2022-04-07 12:00:08 -07:00
} from '@solana/web3.js' ;
2022-04-07 23:29:35 -07:00
import bs58 from 'bs58' ;
2023-07-04 00:26:59 -07:00
import chunk from 'lodash/chunk' ;
2023-04-24 05:48:53 -07:00
import cloneDeep from 'lodash/cloneDeep' ;
2023-08-11 06:18:41 -07:00
import groupBy from 'lodash/groupBy' ;
import mapValues from 'lodash/mapValues' ;
import maxBy from 'lodash/maxBy' ;
2023-04-24 05:48:53 -07:00
import uniq from 'lodash/uniq' ;
2022-09-29 06:51:09 -07:00
import { Bank , MintInfo , TokenIndex } from './accounts/bank' ;
2022-04-12 08:28:47 -07:00
import { Group } from './accounts/group' ;
2023-01-10 07:51:03 -08:00
import {
MangoAccount ,
PerpPosition ,
Serum3Orders ,
2023-09-07 23:49:38 -07:00
TokenConditionalSwap ,
2023-08-03 03:37:01 -07:00
TokenConditionalSwapDisplayPriceStyle ,
2023-07-03 05:09:11 -07:00
TokenConditionalSwapDto ,
2023-08-08 09:16:59 -07:00
TokenConditionalSwapIntention ,
2023-01-10 07:51:03 -08:00
TokenPosition ,
} from './accounts/mangoAccount' ;
2022-04-12 08:28:47 -07:00
import { StubOracle } from './accounts/oracle' ;
2022-09-15 00:57:48 -07:00
import {
2022-09-27 06:13:53 -07:00
FillEvent ,
OutEvent ,
2022-09-15 00:57:48 -07:00
PerpEventQueue ,
PerpMarket ,
2022-09-29 06:51:09 -07:00
PerpMarketIndex ,
2022-09-15 00:57:48 -07:00
PerpOrderSide ,
2022-09-27 06:13:53 -07:00
PerpOrderType ,
2023-06-15 23:05:16 -07:00
PerpSelfTradeBehavior ,
2022-09-15 00:57:48 -07:00
} from './accounts/perp' ;
2022-04-08 03:30:21 -07:00
import {
2023-04-24 05:48:53 -07:00
MarketIndex ,
2022-04-08 03:30:21 -07:00
Serum3Market ,
Serum3OrderType ,
Serum3SelfTradeBehavior ,
Serum3Side ,
2022-12-19 06:40:14 -08:00
generateSerum3MarketExternalVaultSignerAddress ,
2022-04-12 08:28:47 -07:00
} from './accounts/serum3' ;
2023-01-26 11:27:39 -08:00
import {
IxGateParams ,
PerpEditParams ,
TokenEditParams ,
2023-08-09 04:55:53 -07:00
TokenRegisterParams ,
2023-09-07 23:28:34 -07:00
buildIxGate ,
2023-01-26 11:27:39 -08:00
} from './clientIxParamBuilder' ;
2023-08-09 14:13:55 -07:00
import {
MANGO_V4_ID ,
MAX_RECENT_PRIORITY_FEE_ACCOUNTS ,
OPENBOOK_PROGRAM_ID ,
RUST_U64_MAX ,
} from './constants' ;
2022-06-21 11:04:21 -07:00
import { Id } from './ids' ;
2022-06-01 01:10:43 -07:00
import { IDL , MangoV4 } from './mango_v4' ;
2022-09-30 06:07:43 -07:00
import { I80F48 } from './numbers/I80F48' ;
2023-09-07 23:28:34 -07:00
import { FlashLoanType , OracleConfigParams } from './types' ;
2022-06-02 10:30:39 -07:00
import {
2022-12-19 06:40:14 -08:00
I64_MAX_BN ,
2023-01-19 02:31:54 -08:00
U64_MAX_BN ,
2022-08-09 15:27:24 -07:00
createAssociatedTokenAccountIdempotentInstruction ,
2022-06-02 10:30:39 -07:00
getAssociatedTokenAddress ,
2022-09-30 06:07:43 -07:00
toNative ,
2023-08-07 04:09:19 -07:00
toNativeSellPerBuyTokenPrice ,
2022-06-02 10:30:39 -07:00
} from './utils' ;
2023-08-11 10:12:13 -07:00
import { MangoSignatureStatus , sendTransaction } from './utils/rpc' ;
2023-02-28 03:05:02 -08:00
import { NATIVE_MINT , TOKEN_PROGRAM_ID } from './utils/spl' ;
2022-02-23 02:09:17 -08:00
2023-08-07 04:09:19 -07:00
export const DEFAULT_TOKEN_CONDITIONAL_SWAP_COUNT = 8 ;
2023-09-19 22:08:23 -07:00
export const PERP_SETTLE_PNL_CU_LIMIT = 250000 ;
export const PERP_SETTLE_FEES_CU_LIMIT = 20000 ;
export const SERUM_SETTLE_FUNDS_CU_LIMIT = 65000 ;
2023-08-07 04:09:19 -07:00
2023-01-13 02:23:37 -08:00
export enum AccountRetriever {
2022-08-03 09:05:16 -07:00
Scanning ,
Fixed ,
}
2022-08-17 23:48:45 -07:00
export type IdsSource = 'api' | 'static' | 'get-program-accounts' ;
2022-11-04 07:35:40 -07:00
export type MangoClientOptions = {
idsSource? : IdsSource ;
postSendTxCallback ? : ( { txid } : { txid : string } ) = > void ;
prioritizationFee? : number ;
2023-08-09 14:13:55 -07:00
estimateFee? : boolean ;
2023-02-03 04:51:18 -08:00
txConfirmationCommitment? : Commitment ;
2023-03-03 05:04:45 -08:00
openbookFeesToDao? : boolean ;
2023-09-04 09:06:37 -07:00
prependedGlobalAdditionalInstructions? : TransactionInstruction [ ] ;
2022-11-04 07:35:40 -07:00
} ;
2022-02-23 02:09:17 -08:00
export class MangoClient {
2022-11-04 07:35:40 -07:00
private idsSource : IdsSource ;
2022-09-13 22:44:00 -07:00
private postSendTxCallback ? : ( { txid } ) = > void ;
2022-08-12 17:15:12 -07:00
private prioritizationFee : number ;
2023-08-09 14:13:55 -07:00
private estimateFee : boolean ;
2023-02-03 04:51:18 -08:00
private txConfirmationCommitment : Commitment ;
2023-03-03 05:04:45 -08:00
private openbookFeesToDao : boolean ;
2023-08-31 05:36:04 -07:00
private prependedGlobalAdditionalInstructions : TransactionInstruction [ ] = [ ] ;
2022-08-12 17:15:12 -07:00
2022-06-11 04:49:45 -07:00
constructor (
public program : Program < MangoV4 > ,
public programId : PublicKey ,
public cluster : Cluster ,
2022-11-04 07:35:40 -07:00
public opts : MangoClientOptions = { } ,
2022-07-17 04:26:57 -07:00
) {
2022-12-08 14:23:07 -08:00
this . idsSource = opts ? . idsSource || 'get-program-accounts' ;
2022-08-12 17:15:12 -07:00
this . prioritizationFee = opts ? . prioritizationFee || 0 ;
2023-08-09 14:13:55 -07:00
this . estimateFee = opts ? . estimateFee || false ;
2022-08-12 17:15:12 -07:00
this . postSendTxCallback = opts ? . postSendTxCallback ;
2023-03-03 05:04:45 -08:00
this . openbookFeesToDao = opts ? . openbookFeesToDao ? ? true ;
2023-09-04 09:06:37 -07:00
this . prependedGlobalAdditionalInstructions =
opts . prependedGlobalAdditionalInstructions ? ? [ ] ;
2023-02-03 04:51:18 -08:00
this . txConfirmationCommitment =
opts ? . txConfirmationCommitment ? ?
( program . provider as AnchorProvider ) . opts . commitment ? ?
'processed' ;
2022-07-17 04:26:57 -07:00
// TODO: evil side effect, but limited backtraces are a nightmare
Error . stackTraceLimit = 1000 ;
}
2022-02-23 02:09:17 -08:00
2023-03-21 15:01:15 -07:00
/// Convenience accessors
public get connection ( ) : Connection {
return this . program . provider . connection ;
}
public get walletPk ( ) : PublicKey {
return ( this . program . provider as AnchorProvider ) . wallet . publicKey ;
}
2023-01-02 12:35:39 -08:00
/// Transactions
2023-02-03 04:55:46 -08:00
public async sendAndConfirmTransaction (
2023-01-02 12:35:39 -08:00
ixs : TransactionInstruction [ ] ,
opts : any = { } ,
2023-08-31 05:36:04 -07:00
) : Promise < MangoSignatureStatus > {
2023-08-09 14:13:55 -07:00
let prioritizationFee : number ;
if ( opts . prioritizationFee ) {
prioritizationFee = opts . prioritizationFee ;
} else if ( this . estimateFee ) {
prioritizationFee = await this . estimatePrioritizationFee ( ixs ) ;
} else {
prioritizationFee = this . prioritizationFee ;
}
2023-08-31 05:36:04 -07:00
const status = await sendTransaction (
this . program . provider as AnchorProvider ,
2023-09-04 09:06:37 -07:00
[ . . . this . prependedGlobalAdditionalInstructions , . . . ixs ] ,
2023-02-03 04:55:46 -08:00
opts . alts ? ? [ ] ,
2023-01-02 12:35:39 -08:00
{
postSendTxCallback : this.postSendTxCallback ,
2023-08-09 14:13:55 -07:00
prioritizationFee ,
2023-02-03 04:51:18 -08:00
txConfirmationCommitment : this.txConfirmationCommitment ,
2023-01-02 12:35:39 -08:00
. . . opts ,
} ,
) ;
2023-08-31 05:36:04 -07:00
return status ;
2023-01-02 12:35:39 -08:00
}
2022-04-07 09:58:42 -07:00
2023-08-11 13:06:21 -07:00
public async sendAndConfirmTransactionForGroup (
2023-02-03 04:55:46 -08:00
group : Group ,
ixs : TransactionInstruction [ ] ,
opts : any = { } ,
2023-08-11 10:12:13 -07:00
) : Promise < MangoSignatureStatus > {
2023-02-03 04:55:46 -08:00
return await this . sendAndConfirmTransaction ( ixs , {
alts : group.addressLookupTablesList ,
. . . opts ,
} ) ;
}
2023-07-21 04:45:07 -07:00
public async adminTokenWithdrawFees (
group : Group ,
bank : Bank ,
tokenAccountPk : PublicKey ,
2023-08-11 10:12:13 -07:00
) : Promise < MangoSignatureStatus > {
2023-07-21 04:45:07 -07:00
const admin = ( this . program . provider as AnchorProvider ) . wallet . publicKey ;
const ix = await this . program . methods
2023-08-10 04:32:06 -07:00
. adminTokenWithdrawFees ( )
2023-07-21 04:45:07 -07:00
. accounts ( {
group : group.publicKey ,
bank : bank.publicKey ,
vault : bank.vault ,
tokenAccount : tokenAccountPk ,
admin ,
} )
. instruction ( ) ;
return await this . sendAndConfirmTransaction ( [ ix ] ) ;
}
public async adminPerpWithdrawFees (
group : Group ,
perpMarket : PerpMarket ,
tokenAccountPk : PublicKey ,
2023-08-11 10:12:13 -07:00
) : Promise < MangoSignatureStatus > {
2023-07-21 04:45:07 -07:00
const bank = group . getFirstBankByTokenIndex ( perpMarket . settleTokenIndex ) ;
const admin = ( this . program . provider as AnchorProvider ) . wallet . publicKey ;
const ix = await this . program . methods
. adminPerpWithdrawFees ( )
. accounts ( {
group : group.publicKey ,
perpMarket : perpMarket.publicKey ,
bank : bank.publicKey ,
vault : bank.vault ,
tokenAccount : tokenAccountPk ,
admin ,
} )
. instruction ( ) ;
return await this . sendAndConfirmTransaction ( [ ix ] ) ;
}
2022-04-07 10:42:00 -07:00
// Group
2022-07-06 05:51:15 -07:00
public async groupCreate (
2022-06-09 09:27:31 -07:00
groupNum : number ,
testing : boolean ,
2022-08-01 03:56:29 -07:00
version : number ,
2022-07-06 00:56:14 -07:00
insuranceMintPk : PublicKey ,
2023-08-11 10:12:13 -07:00
) : Promise < MangoSignatureStatus > {
2022-05-18 08:16:14 -07:00
const adminPk = ( this . program . provider as AnchorProvider ) . wallet . publicKey ;
2023-02-02 05:23:22 -08:00
const ix = await this . program . methods
2022-08-01 03:56:29 -07:00
. groupCreate ( groupNum , testing ? 1 : 0 , version )
2022-04-07 12:00:08 -07:00
. accounts ( {
2022-07-31 00:36:46 -07:00
creator : adminPk ,
2022-04-07 12:00:08 -07:00
payer : adminPk ,
2022-07-06 00:56:14 -07:00
insuranceMint : insuranceMintPk ,
2022-04-07 12:00:08 -07:00
} )
2023-02-02 05:23:22 -08:00
. instruction ( ) ;
return await this . sendAndConfirmTransaction ( [ ix ] ) ;
2022-04-07 10:42:00 -07:00
}
2022-08-03 01:25:09 -07:00
public async groupEdit (
group : Group ,
2022-11-21 10:34:41 -08:00
admin? : PublicKey ,
fastListingAdmin? : PublicKey ,
2023-01-12 00:12:55 -08:00
securityAdmin? : PublicKey ,
2022-11-21 10:34:41 -08:00
testing? : number ,
version? : number ,
2023-01-24 08:58:23 -08:00
depositLimitQuote? : BN ,
2023-02-25 11:34:16 -08:00
feesPayWithMngo? : boolean ,
feesMngoBonusRate? : number ,
feesSwapMangoAccount? : PublicKey ,
feesMngoTokenIndex? : TokenIndex ,
2023-02-27 07:36:27 -08:00
feesExpiryInterval? : BN ,
2023-08-11 10:12:13 -07:00
) : Promise < MangoSignatureStatus > {
2023-02-02 05:23:22 -08:00
const ix = await this . program . methods
2022-08-13 10:54:58 -07:00
. groupEdit (
admin ? ? null ,
fastListingAdmin ? ? null ,
2023-01-12 00:12:55 -08:00
securityAdmin ? ? null ,
2022-08-13 10:54:58 -07:00
testing ? ? null ,
version ? ? null ,
2023-01-24 08:58:23 -08:00
depositLimitQuote !== undefined ? depositLimitQuote : null ,
2023-02-25 11:34:16 -08:00
feesPayWithMngo ? ? null ,
feesMngoBonusRate ? ? null ,
feesSwapMangoAccount ? ? null ,
feesMngoTokenIndex ? ? null ,
2023-02-27 07:36:27 -08:00
feesExpiryInterval ? ? null ,
2022-08-13 10:54:58 -07:00
)
2022-08-03 01:25:09 -07:00
. accounts ( {
group : group.publicKey ,
admin : ( this . program . provider as AnchorProvider ) . wallet . publicKey ,
} )
2023-02-02 05:23:22 -08:00
. instruction ( ) ;
2023-02-03 04:55:46 -08:00
return await this . sendAndConfirmTransactionForGroup ( group , [ ix ] ) ;
2022-08-03 01:25:09 -07:00
}
2023-01-26 11:27:39 -08:00
public async ixGateSet (
2023-01-12 00:12:55 -08:00
group : Group ,
2023-01-26 11:27:39 -08:00
ixGateParams : IxGateParams ,
2023-08-11 10:12:13 -07:00
) : Promise < MangoSignatureStatus > {
2023-02-02 05:23:22 -08:00
const ix = await this . program . methods
2023-01-26 11:27:39 -08:00
. ixGateSet ( buildIxGate ( ixGateParams ) )
2023-01-12 00:12:55 -08:00
. accounts ( {
group : group.publicKey ,
admin : ( this . program . provider as AnchorProvider ) . wallet . publicKey ,
} )
2023-02-02 05:23:22 -08:00
. instruction ( ) ;
2023-02-03 04:55:46 -08:00
return await this . sendAndConfirmTransactionForGroup ( group , [ ix ] ) ;
2023-01-12 00:12:55 -08:00
}
2023-08-11 10:12:13 -07:00
public async groupClose ( group : Group ) : Promise < MangoSignatureStatus > {
2022-06-09 09:27:31 -07:00
const adminPk = ( this . program . provider as AnchorProvider ) . wallet . publicKey ;
2023-02-02 05:23:22 -08:00
const ix = await this . program . methods
2022-07-06 05:51:15 -07:00
. groupClose ( )
2022-06-09 09:27:31 -07:00
. accounts ( {
group : group.publicKey ,
2022-07-31 00:57:56 -07:00
insuranceVault : group.insuranceVault ,
2022-06-09 09:27:31 -07:00
admin : adminPk ,
solDestination : ( this . program . provider as AnchorProvider ) . wallet
. publicKey ,
} )
2023-02-02 05:23:22 -08:00
. instruction ( ) ;
2023-02-03 04:55:46 -08:00
return await this . sendAndConfirmTransactionForGroup ( group , [ ix ] ) ;
2022-06-09 09:27:31 -07:00
}
2022-04-08 11:47:12 -07:00
public async getGroup ( groupPk : PublicKey ) : Promise < Group > {
2022-05-02 09:26:25 -07:00
const groupAccount = await this . program . account . group . fetch ( groupPk ) ;
const group = Group . from ( groupPk , groupAccount ) ;
2023-01-12 11:43:37 -08:00
await group . reloadAll ( this ) ;
2022-04-08 11:47:12 -07:00
return group ;
}
2022-08-08 07:31:38 -07:00
public async getGroupsForCreator ( creatorPk : PublicKey ) : Promise < Group [ ] > {
2022-05-27 05:43:53 -07:00
const filters : MemcmpFilter [ ] = [
{
memcmp : {
2022-08-04 00:28:18 -07:00
bytes : creatorPk.toBase58 ( ) ,
2022-05-27 05:43:53 -07:00
offset : 8 ,
2022-04-07 12:00:08 -07:00
} ,
2022-05-27 05:43:53 -07:00
} ,
] ;
2022-08-13 11:51:09 -07:00
const groups = ( await this . program . account . group . all ( filters ) ) . map (
( tuple ) = > Group . from ( tuple . publicKey , tuple . account ) ,
2022-05-27 05:43:53 -07:00
) ;
2022-08-13 11:51:09 -07:00
groups . forEach ( ( group ) = > group . reloadAll ( this ) ) ;
return groups ;
2022-08-08 01:48:05 -07:00
}
public async getGroupForCreator (
creatorPk : PublicKey ,
2022-08-13 11:51:09 -07:00
groupNum : number ,
2022-08-08 01:48:05 -07:00
) : Promise < Group > {
2022-08-13 11:51:09 -07:00
const bbuf = Buffer . alloc ( 4 ) ;
bbuf . writeUInt32LE ( groupNum ) ;
const filters : MemcmpFilter [ ] = [
{
memcmp : {
bytes : creatorPk.toBase58 ( ) ,
offset : 8 ,
} ,
2022-08-08 07:31:38 -07:00
} ,
2022-08-13 11:51:09 -07:00
{
memcmp : {
bytes : bs58.encode ( bbuf ) ,
offset : 40 ,
} ,
} ,
] ;
const groups = ( await this . program . account . group . all ( filters ) ) . map (
( tuple ) = > Group . from ( tuple . publicKey , tuple . account ) ,
2022-08-08 07:31:38 -07:00
) ;
2022-08-14 04:30:08 -07:00
await groups [ 0 ] . reloadAll ( this ) ;
2022-04-07 12:00:08 -07:00
return groups [ 0 ] ;
2022-04-07 09:58:42 -07:00
}
2022-11-04 07:35:40 -07:00
public async getIds ( groupPk : PublicKey ) : Promise < Id | undefined > {
switch ( this . idsSource ) {
case 'api' :
return await Id . fromApi ( groupPk ) ;
case 'get-program-accounts' :
return undefined ;
case 'static' :
return Id . fromIdsByPk ( groupPk ) ;
}
}
2022-04-07 10:42:00 -07:00
// Tokens/Banks
2022-06-09 09:27:31 -07:00
public async tokenRegister (
2022-04-07 10:42:00 -07:00
group : Group ,
mintPk : PublicKey ,
oraclePk : PublicKey ,
tokenIndex : number ,
2022-04-12 07:19:58 -07:00
name : string ,
2023-08-09 04:55:53 -07:00
params : TokenRegisterParams ,
2023-08-11 10:12:13 -07:00
) : Promise < MangoSignatureStatus > {
2023-02-02 05:23:22 -08:00
const ix = await this . program . methods
2022-06-09 09:27:31 -07:00
. tokenRegister (
2022-04-07 12:00:08 -07:00
tokenIndex ,
2022-04-12 07:19:58 -07:00
name ,
2023-08-09 04:55:53 -07:00
params . oracleConfig ,
params . interestRateParams ,
params . loanFeeRate ,
params . loanOriginationFeeRate ,
params . maintAssetWeight ,
params . initAssetWeight ,
params . maintLiabWeight ,
params . initLiabWeight ,
params . liquidationFee ,
params . stablePriceDelayIntervalSeconds ,
params . stablePriceDelayGrowthLimit ,
params . stablePriceGrowthLimit ,
params . minVaultToDepositsRatio ,
new BN ( params . netBorrowLimitWindowSizeTs ) ,
new BN ( params . netBorrowLimitPerWindowQuote ) ,
params . borrowWeightScaleStartQuote ,
params . depositWeightScaleStartQuote ,
params . reduceOnly ,
params . tokenConditionalSwapTakerFeeRate ,
params . tokenConditionalSwapMakerFeeRate ,
2023-08-29 01:03:07 -07:00
params . flashLoanDepositFeeRate ,
2022-04-07 12:00:08 -07:00
)
. accounts ( {
group : group.publicKey ,
2022-05-18 08:16:14 -07:00
admin : ( this . program . provider as AnchorProvider ) . wallet . publicKey ,
2022-04-07 12:00:08 -07:00
mint : mintPk ,
oracle : oraclePk ,
2022-05-18 08:16:14 -07:00
payer : ( this . program . provider as AnchorProvider ) . wallet . publicKey ,
2022-04-07 12:00:08 -07:00
rent : SYSVAR_RENT_PUBKEY ,
} )
2023-02-02 05:23:22 -08:00
. instruction ( ) ;
2023-02-03 04:55:46 -08:00
return await this . sendAndConfirmTransactionForGroup ( group , [ ix ] ) ;
2022-04-07 10:42:00 -07:00
}
2022-08-03 01:25:09 -07:00
public async tokenRegisterTrustless (
group : Group ,
mintPk : PublicKey ,
oraclePk : PublicKey ,
tokenIndex : number ,
name : string ,
2023-08-11 10:12:13 -07:00
) : Promise < MangoSignatureStatus > {
2023-02-02 05:23:22 -08:00
const ix = await this . program . methods
2022-08-03 04:50:49 -07:00
. tokenRegisterTrustless ( tokenIndex , name )
2022-08-03 01:25:09 -07:00
. accounts ( {
group : group.publicKey ,
2023-02-28 06:04:28 -08:00
admin : ( this . program . provider as AnchorProvider ) . wallet . publicKey ,
2022-08-03 01:25:09 -07:00
mint : mintPk ,
oracle : oraclePk ,
payer : ( this . program . provider as AnchorProvider ) . wallet . publicKey ,
rent : SYSVAR_RENT_PUBKEY ,
} )
2023-02-02 05:23:22 -08:00
. instruction ( ) ;
2023-02-03 04:55:46 -08:00
return await this . sendAndConfirmTransactionForGroup ( group , [ ix ] ) ;
2022-08-03 01:25:09 -07:00
}
2022-07-05 10:31:47 -07:00
public async tokenEdit (
group : Group ,
2022-08-17 23:48:45 -07:00
mintPk : PublicKey ,
2023-01-14 05:09:26 -08:00
params : TokenEditParams ,
2023-08-11 10:12:13 -07:00
) : Promise < MangoSignatureStatus > {
2022-08-17 23:48:45 -07:00
const bank = group . getFirstBankByMint ( mintPk ) ;
const mintInfo = group . mintInfosMapByTokenIndex . get ( bank . tokenIndex ) ! ;
2022-07-05 10:31:47 -07:00
2023-02-02 05:23:22 -08:00
const ix = await this . program . methods
2022-07-05 10:31:47 -07:00
. tokenEdit (
2023-01-14 05:09:26 -08:00
params . oracle ,
params . oracleConfig ,
params . groupInsuranceFund ,
params . interestRateParams ,
params . loanFeeRate ,
params . loanOriginationFeeRate ,
params . maintAssetWeight ,
params . initAssetWeight ,
params . maintLiabWeight ,
params . initLiabWeight ,
params . liquidationFee ,
params . stablePriceDelayIntervalSeconds ,
params . stablePriceDelayGrowthLimit ,
params . stablePriceGrowthLimit ,
params . minVaultToDepositsRatio ,
params . netBorrowLimitPerWindowQuote !== null
? new BN ( params . netBorrowLimitPerWindowQuote )
2022-12-06 00:34:02 -08:00
: null ,
2023-01-14 05:09:26 -08:00
params . netBorrowLimitWindowSizeTs !== null
? new BN ( params . netBorrowLimitWindowSizeTs )
2022-12-06 00:34:02 -08:00
: null ,
2023-01-14 05:09:26 -08:00
params . borrowWeightScaleStartQuote ,
params . depositWeightScaleStartQuote ,
params . resetStablePrice ? ? false ,
params . resetNetBorrowLimit ? ? false ,
params . reduceOnly ,
2023-03-03 01:05:12 -08:00
params . name ,
2023-04-13 03:44:12 -07:00
params . forceClose ,
2023-08-08 01:21:13 -07:00
params . tokenConditionalSwapTakerFeeRate ,
params . tokenConditionalSwapMakerFeeRate ,
2023-08-29 01:03:07 -07:00
params . flashLoanDepositFeeRate ,
2022-07-05 10:31:47 -07:00
)
. accounts ( {
group : group.publicKey ,
2023-01-14 05:09:26 -08:00
oracle : params.oracle ? ? bank . oracle ,
2022-07-05 10:31:47 -07:00
admin : ( this . program . provider as AnchorProvider ) . wallet . publicKey ,
mintInfo : mintInfo.publicKey ,
} )
. remainingAccounts ( [
{
pubkey : bank.publicKey ,
isWritable : true ,
isSigner : false ,
} as AccountMeta ,
] )
2023-02-02 05:23:22 -08:00
. instruction ( ) ;
2023-02-03 04:55:46 -08:00
return await this . sendAndConfirmTransactionForGroup ( group , [ ix ] ) ;
2022-07-05 10:31:47 -07:00
}
2023-04-24 23:12:42 -07:00
public async tokenForceCloseBorrowsWithToken (
group : Group ,
liqor : MangoAccount ,
liqee : MangoAccount ,
assetTokenIndex : TokenIndex ,
liabTokenIndex : TokenIndex ,
maxLiabTransfer? : number ,
2023-08-11 10:12:13 -07:00
) : Promise < MangoSignatureStatus > {
2023-04-24 23:12:42 -07:00
const assetBank = group . getFirstBankByTokenIndex ( assetTokenIndex ) ;
const liabBank = group . getFirstBankByTokenIndex ( liabTokenIndex ) ;
const healthRemainingAccounts : PublicKey [ ] =
this . buildHealthRemainingAccounts (
group ,
[ liqor , liqee ] ,
[ assetBank , liabBank ] ,
[ ] ,
) ;
const parsedHealthAccounts = healthRemainingAccounts . map (
( pk ) = >
( {
pubkey : pk ,
isWritable :
pk . equals ( assetBank . publicKey ) || pk . equals ( liabBank . publicKey )
? true
: false ,
isSigner : false ,
} as AccountMeta ) ,
) ;
const ix = await this . program . methods
. tokenForceCloseBorrowsWithToken (
assetTokenIndex ,
liabTokenIndex ,
maxLiabTransfer
? toNative ( maxLiabTransfer , liabBank . mintDecimals )
: U64_MAX_BN ,
)
. accounts ( {
group : group.publicKey ,
liqor : liqor.publicKey ,
liqorOwner : ( this . program . provider as AnchorProvider ) . wallet . publicKey ,
liqee : liqee.publicKey ,
} )
. remainingAccounts ( parsedHealthAccounts )
. instruction ( ) ;
return await this . sendAndConfirmTransactionForGroup ( group , [ ix ] ) ;
}
2022-06-09 09:27:31 -07:00
public async tokenDeregister (
group : Group ,
2022-08-17 23:48:45 -07:00
mintPk : PublicKey ,
2023-08-11 10:12:13 -07:00
) : Promise < MangoSignatureStatus > {
2022-08-17 23:48:45 -07:00
const bank = group . getFirstBankByMint ( mintPk ) ;
2022-06-09 09:27:31 -07:00
const adminPk = ( this . program . provider as AnchorProvider ) . wallet . publicKey ;
2022-06-29 00:11:14 -07:00
const dustVaultPk = await getAssociatedTokenAddress ( bank . mint , adminPk ) ;
const ai = await this . program . provider . connection . getAccountInfo (
dustVaultPk ,
) ;
2022-12-09 03:49:11 -08:00
const preInstructions : TransactionInstruction [ ] = [ ] ;
2022-06-29 00:11:14 -07:00
if ( ! ai ) {
2022-12-09 03:49:11 -08:00
preInstructions . push (
await createAssociatedTokenAccountIdempotentInstruction (
2022-06-29 00:11:14 -07:00
adminPk ,
adminPk ,
2022-12-09 03:49:11 -08:00
bank . mint ,
2022-06-29 00:11:14 -07:00
) ,
) ;
}
2022-12-09 03:49:11 -08:00
const ix = await this . program . methods
2022-08-25 10:25:56 -07:00
. tokenDeregister ( )
2022-06-09 09:27:31 -07:00
. accounts ( {
group : group.publicKey ,
admin : adminPk ,
2022-08-17 23:48:45 -07:00
mintInfo : group.mintInfosMapByTokenIndex.get ( bank . tokenIndex )
? . publicKey ,
2022-06-29 00:11:14 -07:00
dustVault : dustVaultPk ,
2022-06-09 09:27:31 -07:00
solDestination : ( this . program . provider as AnchorProvider ) . wallet
. publicKey ,
} )
2022-06-27 02:27:17 -07:00
. remainingAccounts (
[ bank . publicKey , bank . vault ] . map (
( pk ) = >
( { pubkey : pk , isWritable : true , isSigner : false } as AccountMeta ) ,
) ,
)
2022-12-09 03:49:11 -08:00
. instruction ( ) ;
2023-02-03 04:55:46 -08:00
return await this . sendAndConfirmTransactionForGroup ( group , [
. . . preInstructions ,
ix ,
] ) ;
2022-06-09 09:27:31 -07:00
}
2022-04-07 09:58:42 -07:00
public async getBanksForGroup ( group : Group ) : Promise < Bank [ ] > {
2022-04-07 12:00:08 -07:00
return (
await this . program . account . bank . all ( [
{
memcmp : {
bytes : group.publicKey.toBase58 ( ) ,
2022-07-06 00:56:14 -07:00
offset : 8 ,
2022-04-07 12:00:08 -07:00
} ,
} ,
] )
) . map ( ( tuple ) = > Bank . from ( tuple . publicKey , tuple . account ) ) ;
2022-04-07 09:58:42 -07:00
}
2022-06-09 09:27:31 -07:00
public async getMintInfosForGroup ( group : Group ) : Promise < MintInfo [ ] > {
return (
await this . program . account . mintInfo . all ( [
{
memcmp : {
bytes : group.publicKey.toBase58 ( ) ,
offset : 8 ,
} ,
} ,
] )
) . map ( ( tuple ) = > {
return MintInfo . from ( tuple . publicKey , tuple . account ) ;
} ) ;
}
public async getMintInfoForTokenIndex (
group : Group ,
2022-09-29 06:51:09 -07:00
tokenIndex : TokenIndex ,
2022-06-09 09:27:31 -07:00
) : Promise < MintInfo [ ] > {
const tokenIndexBuf = Buffer . alloc ( 2 ) ;
tokenIndexBuf . writeUInt16LE ( tokenIndex ) ;
return (
await this . program . account . mintInfo . all ( [
{
memcmp : {
bytes : group.publicKey.toBase58 ( ) ,
offset : 8 ,
} ,
} ,
{
memcmp : {
bytes : bs58.encode ( tokenIndexBuf ) ,
2022-07-06 00:56:14 -07:00
offset : 40 ,
2022-06-09 09:27:31 -07:00
} ,
} ,
] )
) . map ( ( tuple ) = > {
return MintInfo . from ( tuple . publicKey , tuple . account ) ;
} ) ;
}
2022-04-07 11:05:06 -07:00
// Stub Oracle
2022-07-06 05:51:15 -07:00
public async stubOracleCreate (
2022-04-07 10:42:00 -07:00
group : Group ,
mintPk : PublicKey ,
price : number ,
2023-08-11 10:12:13 -07:00
) : Promise < MangoSignatureStatus > {
2023-02-02 05:23:22 -08:00
const ix = await this . program . methods
2022-07-06 05:51:15 -07:00
. stubOracleCreate ( { val : I80F48.fromNumber ( price ) . getData ( ) } )
2022-04-07 12:00:08 -07:00
. accounts ( {
group : group.publicKey ,
2022-05-18 08:16:14 -07:00
admin : ( this . program . provider as AnchorProvider ) . wallet . publicKey ,
2022-08-04 03:13:36 -07:00
mint : mintPk ,
2022-05-18 08:16:14 -07:00
payer : ( this . program . provider as AnchorProvider ) . wallet . publicKey ,
2022-04-07 12:00:08 -07:00
} )
2023-02-02 05:23:22 -08:00
. instruction ( ) ;
2023-02-03 04:55:46 -08:00
return await this . sendAndConfirmTransactionForGroup ( group , [ ix ] ) ;
2022-04-07 10:42:00 -07:00
}
2022-07-06 05:51:15 -07:00
public async stubOracleClose (
2022-06-09 09:27:31 -07:00
group : Group ,
oracle : PublicKey ,
2023-08-11 10:12:13 -07:00
) : Promise < MangoSignatureStatus > {
2023-02-02 05:23:22 -08:00
const ix = await this . program . methods
2022-07-06 05:51:15 -07:00
. stubOracleClose ( )
2022-06-09 09:27:31 -07:00
. accounts ( {
group : group.publicKey ,
oracle : oracle ,
solDestination : ( this . program . provider as AnchorProvider ) . wallet
. publicKey ,
} )
2023-02-02 05:23:22 -08:00
. instruction ( ) ;
2023-02-03 04:55:46 -08:00
return await this . sendAndConfirmTransactionForGroup ( group , [ ix ] ) ;
2022-06-09 09:27:31 -07:00
}
2022-07-06 05:51:15 -07:00
public async stubOracleSet (
2022-04-07 10:42:00 -07:00
group : Group ,
2022-06-18 07:31:28 -07:00
oraclePk : PublicKey ,
2022-04-07 10:42:00 -07:00
price : number ,
2023-08-11 10:12:13 -07:00
) : Promise < MangoSignatureStatus > {
2023-02-02 05:23:22 -08:00
const ix = await this . program . methods
2022-07-06 05:51:15 -07:00
. stubOracleSet ( { val : I80F48.fromNumber ( price ) . getData ( ) } )
2022-04-07 12:00:08 -07:00
. accounts ( {
group : group.publicKey ,
2022-05-18 08:16:14 -07:00
admin : ( this . program . provider as AnchorProvider ) . wallet . publicKey ,
2022-06-18 07:31:28 -07:00
oracle : oraclePk ,
2022-04-07 12:00:08 -07:00
} )
2023-02-02 05:23:22 -08:00
. instruction ( ) ;
2023-02-03 04:55:46 -08:00
return await this . sendAndConfirmTransactionForGroup ( group , [ ix ] ) ;
2022-04-07 10:42:00 -07:00
}
public async getStubOracle (
group : Group ,
2022-06-11 04:49:45 -07:00
mintPk? : PublicKey ,
) : Promise < StubOracle [ ] > {
const filters = [
{
memcmp : {
bytes : group.publicKey.toBase58 ( ) ,
offset : 8 ,
2022-04-07 12:00:08 -07:00
} ,
2022-06-11 04:49:45 -07:00
} ,
] ;
if ( mintPk ) {
filters . push ( {
memcmp : {
bytes : mintPk.toBase58 ( ) ,
offset : 40 ,
2022-04-07 12:00:08 -07:00
} ,
2022-06-11 04:49:45 -07:00
} ) ;
}
return ( await this . program . account . stubOracle . all ( filters ) ) . map ( ( pa ) = >
StubOracle . from ( pa . publicKey , pa . account ) ,
) ;
2022-04-07 10:42:00 -07:00
}
// MangoAccount
2022-04-07 09:58:42 -07:00
public async createMangoAccount (
group : Group ,
2022-08-04 08:35:05 -07:00
accountNumber? : number ,
2022-04-12 07:19:58 -07:00
name? : string ,
2022-09-15 00:57:48 -07:00
tokenCount? : number ,
serum3Count? : number ,
perpCount? : number ,
perpOoCount? : number ,
2023-08-11 10:12:13 -07:00
) : Promise < MangoSignatureStatus > {
2022-09-27 06:13:53 -07:00
const ix = await this . program . methods
2022-09-15 00:57:48 -07:00
. accountCreate (
accountNumber ? ? 0 ,
tokenCount ? ? 8 ,
2023-08-21 07:26:49 -07:00
serum3Count ? ? 4 ,
perpCount ? ? 4 ,
2023-02-21 01:40:15 -08:00
perpOoCount ? ? 32 ,
2022-09-15 00:57:48 -07:00
name ? ? '' ,
)
2022-04-07 12:00:08 -07:00
. accounts ( {
group : group.publicKey ,
2022-05-18 08:16:14 -07:00
owner : ( this . program . provider as AnchorProvider ) . wallet . publicKey ,
2022-08-04 08:35:05 -07:00
payer : ( this . program . provider as AnchorProvider ) . wallet . publicKey ,
2022-04-07 12:00:08 -07:00
} )
2022-09-27 06:13:53 -07:00
. instruction ( ) ;
2022-08-15 21:27:06 -07:00
2023-02-03 04:55:46 -08:00
return await this . sendAndConfirmTransactionForGroup ( group , [ ix ] ) ;
2022-04-07 09:58:42 -07:00
}
2023-07-03 05:09:11 -07:00
public async expandMangoAccount (
2022-09-15 00:57:48 -07:00
group : Group ,
2023-07-03 05:09:11 -07:00
account : MangoAccount ,
tokenCount : number ,
serum3Count : number ,
perpCount : number ,
perpOoCount : number ,
2023-08-11 10:12:13 -07:00
) : Promise < MangoSignatureStatus > {
2023-07-03 05:09:11 -07:00
const ix = await this . program . methods
. accountExpand ( tokenCount , serum3Count , perpCount , perpOoCount )
. accounts ( {
group : group.publicKey ,
account : account.publicKey ,
owner : ( this . program . provider as AnchorProvider ) . wallet . publicKey ,
payer : ( this . program . provider as AnchorProvider ) . wallet . publicKey ,
} )
. instruction ( ) ;
return await this . sendAndConfirmTransactionForGroup ( group , [ ix ] ) ;
2022-09-15 00:57:48 -07:00
}
2023-07-03 05:09:11 -07:00
public async accountExpandV2 (
2022-07-25 07:07:53 -07:00
group : Group ,
account : MangoAccount ,
2022-08-07 05:16:06 -07:00
tokenCount : number ,
serum3Count : number ,
perpCount : number ,
perpOoCount : number ,
2023-07-03 05:09:11 -07:00
tokenConditionalSwapCount : number ,
2023-08-11 10:12:13 -07:00
) : Promise < MangoSignatureStatus > {
2023-07-27 23:26:34 -07:00
const ix = await this . accountExpandV2Ix (
2022-09-15 00:57:48 -07:00
group ,
2023-07-27 23:26:34 -07:00
account ,
2022-09-15 00:57:48 -07:00
tokenCount ,
serum3Count ,
perpCount ,
perpOoCount ,
2023-07-27 23:26:34 -07:00
tokenConditionalSwapCount ,
2022-09-15 00:57:48 -07:00
) ;
2023-07-27 23:26:34 -07:00
return await this . sendAndConfirmTransactionForGroup ( group , [ ix ] ) ;
2022-09-15 00:57:48 -07:00
}
2023-07-27 23:26:34 -07:00
public async accountExpandV2Ix (
2022-07-25 07:07:53 -07:00
group : Group ,
account : MangoAccount ,
2022-08-07 05:16:06 -07:00
tokenCount : number ,
serum3Count : number ,
perpCount : number ,
perpOoCount : number ,
2023-07-27 23:26:34 -07:00
tokenConditionalSwapCount : number ,
) : Promise < TransactionInstruction > {
return await this . program . methods
2023-07-03 05:09:11 -07:00
. accountExpandV2 (
tokenCount ,
serum3Count ,
perpCount ,
perpOoCount ,
tokenConditionalSwapCount ,
)
2022-07-25 07:07:53 -07:00
. accounts ( {
group : group.publicKey ,
account : account.publicKey ,
owner : ( this . program . provider as AnchorProvider ) . wallet . publicKey ,
2022-05-18 08:16:14 -07:00
payer : ( this . program . provider as AnchorProvider ) . wallet . publicKey ,
2022-04-07 12:00:08 -07:00
} )
2023-02-02 05:23:22 -08:00
. instruction ( ) ;
2022-04-07 09:58:42 -07:00
}
2022-07-05 10:31:47 -07:00
public async editMangoAccount (
group : Group ,
2022-07-06 00:56:14 -07:00
mangoAccount : MangoAccount ,
2022-07-05 10:31:47 -07:00
name? : string ,
delegate? : PublicKey ,
2023-08-09 03:05:16 -07:00
temporaryDelegate? : PublicKey ,
delegateExpiry? : number ,
2023-08-11 10:12:13 -07:00
) : Promise < MangoSignatureStatus > {
2022-09-27 06:13:53 -07:00
const ix = await this . program . methods
2023-08-09 03:05:16 -07:00
. accountEdit (
name ? ? null ,
delegate ? ? null ,
temporaryDelegate ? ? null ,
delegateExpiry ? new BN ( delegateExpiry ) : null ,
)
2022-07-05 10:31:47 -07:00
. accounts ( {
group : group.publicKey ,
2022-07-06 00:56:14 -07:00
account : mangoAccount.publicKey ,
2022-07-05 10:31:47 -07:00
owner : ( this . program . provider as AnchorProvider ) . wallet . publicKey ,
} )
2022-09-27 06:13:53 -07:00
. instruction ( ) ;
2022-08-15 21:27:06 -07:00
2023-02-03 04:55:46 -08:00
return await this . sendAndConfirmTransactionForGroup ( group , [ ix ] ) ;
}
public async computeAccountData (
group : Group ,
mangoAccount : MangoAccount ,
2023-08-11 10:12:13 -07:00
) : Promise < MangoSignatureStatus > {
2023-02-03 04:55:46 -08:00
const healthRemainingAccounts : PublicKey [ ] =
2023-04-24 05:48:53 -07:00
this . buildHealthRemainingAccounts ( group , [ mangoAccount ] , [ ] , [ ] ) ;
2023-02-03 04:55:46 -08:00
const ix = await this . program . methods
. computeAccountData ( )
. accounts ( {
group : group.publicKey ,
account : mangoAccount.publicKey ,
} )
. remainingAccounts (
healthRemainingAccounts . map (
( pk ) = >
( { pubkey : pk , isWritable : false , isSigner : false } as AccountMeta ) ,
) ,
)
. instruction ( ) ;
return await this . sendAndConfirmTransactionForGroup ( group , [ ix ] ) ;
2022-07-05 10:31:47 -07:00
}
2023-01-12 04:08:10 -08:00
public async toggleMangoAccountFreeze (
group : Group ,
mangoAccount : MangoAccount ,
freeze : boolean ,
2023-08-11 10:12:13 -07:00
) : Promise < MangoSignatureStatus > {
2023-02-02 05:23:22 -08:00
const ix = await this . program . methods
2023-01-12 11:39:46 -08:00
. accountToggleFreeze ( freeze )
2023-01-12 04:08:10 -08:00
. accounts ( {
group : group.publicKey ,
account : mangoAccount.publicKey ,
admin : ( this . program . provider as AnchorProvider ) . wallet . publicKey ,
} )
2023-02-02 05:23:22 -08:00
. instruction ( ) ;
2023-02-03 04:55:46 -08:00
return await this . sendAndConfirmTransactionForGroup ( group , [ ix ] ) ;
2023-01-12 04:08:10 -08:00
}
2022-12-08 12:53:07 -08:00
public async getMangoAccount (
2023-07-03 05:09:11 -07:00
mangoAccountPk : PublicKey ,
2023-01-19 02:31:54 -08:00
loadSerum3Oo = false ,
2022-12-08 12:53:07 -08:00
) : Promise < MangoAccount > {
2023-07-03 05:09:11 -07:00
const mangoAccount = await this . getMangoAccountFromPk ( mangoAccountPk ) ;
2023-01-19 02:31:54 -08:00
if ( loadSerum3Oo ) {
2023-07-03 05:09:11 -07:00
await mangoAccount ? . reloadSerum3OpenOrders ( this ) ;
2023-01-19 02:31:54 -08:00
}
2023-07-03 05:09:11 -07:00
return mangoAccount ;
}
private async getMangoAccountFromPk (
mangoAccountPk : PublicKey ,
) : Promise < MangoAccount > {
2023-08-12 10:37:29 -07:00
return this . getMangoAccountFromAi (
2023-07-03 05:09:11 -07:00
mangoAccountPk ,
( await this . program . provider . connection . getAccountInfo (
mangoAccountPk ,
) ) as AccountInfo < Buffer > ,
) ;
}
2023-08-12 10:37:29 -07:00
public getMangoAccountFromAi (
2023-07-03 05:09:11 -07:00
mangoAccountPk : PublicKey ,
ai : AccountInfo < Buffer > ,
2023-08-12 10:37:29 -07:00
) : MangoAccount {
2023-07-03 05:09:11 -07:00
const decodedMangoAccount = this . program . coder . accounts . decode (
'mangoAccount' ,
ai . data ,
) ;
// Re-encode decoded mango account with v1 layout, this will help identifying
// if account is of type v1 or v2
// Do whole encoding manually, since anchor uses a buffer of a constant length which is too small
const mangoAccountV1Buffer = Buffer . alloc ( ai . data . length ) ;
const layout =
this . program . coder . accounts [ 'accountLayouts' ] . get ( 'mangoAccount' ) ;
const discriminatorLen = 8 ;
const v1DataLen = layout . encode ( decodedMangoAccount , mangoAccountV1Buffer ) ;
const v1Len = discriminatorLen + v1DataLen ;
const tokenConditionalSwaps =
ai . data . length > v1Len
? ( borsh
. vec (
( this . program as any ) . _coder . types . typeLayouts . get (
'TokenConditionalSwap' ,
) ,
)
. decode (
ai . data . subarray (
v1Len +
// This is the padding before tokenConditionalSwaps
4 ,
) ,
) as TokenConditionalSwapDto [ ] )
: new Array < TokenConditionalSwapDto > ( ) ;
return MangoAccount . from (
mangoAccountPk ,
decodedMangoAccount ,
tokenConditionalSwaps ,
) ;
2022-09-23 11:39:51 -07:00
}
2022-09-27 08:33:51 -07:00
2022-09-29 06:51:09 -07:00
public async getMangoAccountWithSlot (
mangoAccountPk : PublicKey ,
2023-01-19 02:31:54 -08:00
loadSerum3Oo = false ,
2022-09-29 06:51:09 -07:00
) : Promise < { slot : number ; value : MangoAccount } | undefined > {
2022-09-05 09:31:57 -07:00
const resp =
await this . program . provider . connection . getAccountInfoAndContext (
mangoAccountPk ,
) ;
if ( ! resp ? . value ) return ;
2023-07-03 05:09:11 -07:00
const mangoAccount = await this . getMangoAccountFromAi (
mangoAccountPk ,
resp . value ,
2022-09-05 09:31:57 -07:00
) ;
2023-01-19 02:31:54 -08:00
if ( loadSerum3Oo ) {
await mangoAccount ? . reloadSerum3OpenOrders ( this ) ;
}
2022-09-05 09:31:57 -07:00
return { slot : resp.context.slot , value : mangoAccount } ;
}
2022-08-08 07:31:38 -07:00
public async getMangoAccountForOwner (
group : Group ,
ownerPk : PublicKey ,
accountNumber : number ,
2023-01-19 02:31:54 -08:00
loadSerum3Oo = false ,
2022-08-31 02:41:12 -07:00
) : Promise < MangoAccount | undefined > {
2023-01-19 02:31:54 -08:00
const mangoAccounts = await this . getMangoAccountsForOwner (
group ,
ownerPk ,
loadSerum3Oo ,
) ;
2022-08-31 02:41:12 -07:00
const foundMangoAccount = mangoAccounts . find (
2022-08-08 07:31:38 -07:00
( a ) = > a . accountNum == accountNumber ,
) ;
2022-08-31 02:41:12 -07:00
return foundMangoAccount ;
2022-08-08 07:31:38 -07:00
}
2022-08-02 00:38:28 -07:00
public async getMangoAccountsForOwner (
2022-04-07 09:58:42 -07:00
group : Group ,
ownerPk : PublicKey ,
2023-01-19 02:31:54 -08:00
loadSerum3Oo = false ,
2022-04-07 09:58:42 -07:00
) : Promise < MangoAccount [ ] > {
2023-07-03 05:09:11 -07:00
const discriminatorMemcmp : {
offset : number ;
bytes : string ;
} = this . program . account . mangoAccount . coder . accounts . memcmp (
'mangoAccount' ,
undefined ,
) ;
const accounts = await Promise . all (
(
await this . program . provider . connection . getProgramAccounts (
this . programId ,
{
filters : [
{
memcmp : {
bytes : discriminatorMemcmp.bytes ,
offset : discriminatorMemcmp.offset ,
} ,
} ,
{
memcmp : {
bytes : group.publicKey.toBase58 ( ) ,
offset : 8 ,
} ,
} ,
{
memcmp : {
bytes : ownerPk.toBase58 ( ) ,
offset : 40 ,
} ,
} ,
] ,
2022-04-07 12:00:08 -07:00
} ,
2023-07-03 05:09:11 -07:00
)
) . map ( ( account ) = > {
return this . getMangoAccountFromAi ( account . pubkey , account . account ) ;
} ) ,
) ;
2023-01-19 02:31:54 -08:00
if ( loadSerum3Oo ) {
await Promise . all (
accounts . map ( async ( a ) = > await a . reloadSerum3OpenOrders ( this ) ) ,
) ;
}
return accounts ;
2022-04-07 09:58:42 -07:00
}
2022-10-07 04:52:04 -07:00
public async getMangoAccountsForDelegate (
group : Group ,
delegate : PublicKey ,
2023-01-19 02:31:54 -08:00
loadSerum3Oo = false ,
2022-10-07 04:52:04 -07:00
) : Promise < MangoAccount [ ] > {
2023-07-03 05:09:11 -07:00
const discriminatorMemcmp : {
offset : number ;
bytes : string ;
} = this . program . account . mangoAccount . coder . accounts . memcmp (
'mangoAccount' ,
undefined ,
) ;
const accounts = await Promise . all (
(
await this . program . provider . connection . getProgramAccounts (
this . programId ,
{
filters : [
{
memcmp : {
bytes : discriminatorMemcmp.bytes ,
offset : discriminatorMemcmp.offset ,
} ,
} ,
{
memcmp : {
bytes : group.publicKey.toBase58 ( ) ,
offset : 8 ,
} ,
} ,
{
memcmp : {
bytes : delegate.toBase58 ( ) ,
offset : 104 ,
} ,
} ,
] ,
2022-10-07 04:52:04 -07:00
} ,
2023-07-03 05:09:11 -07:00
)
) . map ( ( account ) = > {
return this . getMangoAccountFromAi ( account . pubkey , account . account ) ;
} ) ,
) ;
2023-01-19 02:31:54 -08:00
if ( loadSerum3Oo ) {
await Promise . all (
accounts . map ( async ( a ) = > await a . reloadSerum3OpenOrders ( this ) ) ,
) ;
}
return accounts ;
2022-10-07 04:52:04 -07:00
}
2023-01-19 02:31:54 -08:00
public async getAllMangoAccounts (
group : Group ,
loadSerum3Oo = false ,
) : Promise < MangoAccount [ ] > {
2023-07-03 05:09:11 -07:00
const discriminatorMemcmp : {
offset : number ;
bytes : string ;
} = this . program . account . mangoAccount . coder . accounts . memcmp (
'mangoAccount' ,
undefined ,
) ;
const accounts = await Promise . all (
(
await this . program . provider . connection . getProgramAccounts (
this . programId ,
{
filters : [
{
memcmp : {
bytes : discriminatorMemcmp.bytes ,
offset : discriminatorMemcmp.offset ,
} ,
} ,
{
memcmp : {
bytes : group.publicKey.toBase58 ( ) ,
offset : 8 ,
} ,
} ,
] ,
2022-08-13 10:36:09 -07:00
} ,
2023-07-03 05:09:11 -07:00
)
) . map ( ( account ) = > {
return this . getMangoAccountFromAi ( account . pubkey , account . account ) ;
} ) ,
) ;
2023-01-19 02:31:54 -08:00
if ( loadSerum3Oo ) {
2023-07-04 00:26:59 -07:00
const ooPks = accounts
. map ( ( a ) = > a . serum3Active ( ) . map ( ( serum3 ) = > serum3 . openOrders ) )
. flat ( ) ;
const ais : AccountInfo < Buffer > [ ] = (
await Promise . all (
chunk ( ooPks , 100 ) . map (
async ( ooPksChunk ) = >
await this . program . provider . connection . getMultipleAccountsInfo (
ooPksChunk ,
) ,
) ,
)
) . flat ( ) ;
if ( ooPks . length != ais . length ) {
throw new Error ( ` Error in fetch all open orders accounts! ` ) ;
}
const serum3OosMapByOo = new Map (
Array . from (
ais . map ( ( ai , i ) = > {
if ( ai == null ) {
throw new Error ( ` Undefined AI for open orders ${ ooPks [ i ] } ! ` ) ;
}
const oo = OpenOrders . fromAccountInfo (
ooPks [ i ] ,
ai ,
OPENBOOK_PROGRAM_ID [ this . cluster ] ,
) ;
return [ ooPks [ i ] . toBase58 ( ) , oo ] ;
} ) ,
) ,
) ;
accounts . forEach (
async ( a ) = > await a . loadSerum3OpenOrders ( serum3OosMapByOo ) ,
2023-01-19 02:31:54 -08:00
) ;
}
return accounts ;
2022-04-07 09:58:42 -07:00
}
2022-12-15 12:10:56 -08:00
/ * *
* Note : this ix doesn ' t settle liabs , reduce open positions , or withdraw tokens to wallet ,
* it simply closes the account . To close successfully ensure all positions are closed , or
* use forceClose flag
* @param group
* @param mangoAccount
* @param forceClose
* @returns
* /
2022-04-08 08:21:49 -07:00
public async closeMangoAccount (
2022-07-04 03:09:33 -07:00
group : Group ,
2022-04-08 08:21:49 -07:00
mangoAccount : MangoAccount ,
2022-12-15 12:10:56 -08:00
forceClose = false ,
2023-08-11 10:12:13 -07:00
) : Promise < MangoSignatureStatus > {
2022-09-27 06:13:53 -07:00
const ix = await this . program . methods
2022-12-15 12:10:56 -08:00
. accountClose ( forceClose )
2022-04-08 08:21:49 -07:00
. accounts ( {
2022-07-04 03:09:33 -07:00
group : group.publicKey ,
2022-04-08 08:21:49 -07:00
account : mangoAccount.publicKey ,
2022-05-18 08:16:14 -07:00
owner : ( this . program . provider as AnchorProvider ) . wallet . publicKey ,
2022-06-09 09:27:31 -07:00
solDestination : mangoAccount.owner ,
2022-04-08 08:21:49 -07:00
} )
2022-09-27 06:13:53 -07:00
. instruction ( ) ;
2022-09-02 10:50:01 -07:00
2023-02-03 04:55:46 -08:00
return await this . sendAndConfirmTransactionForGroup ( group , [ ix ] ) ;
2022-04-08 08:21:49 -07:00
}
2023-01-12 16:38:02 -08:00
public async emptyAndCloseMangoAccount (
2023-01-12 13:34:48 -08:00
group : Group ,
mangoAccount : MangoAccount ,
2023-08-11 10:12:13 -07:00
) : Promise < MangoSignatureStatus > {
2023-04-24 05:48:53 -07:00
// Work on a deep cloned mango account, since we would deactivating positions
// before deactivation reaches on-chain state in order to simplify building a fresh list
// of healthRemainingAccounts to each subsequent ix
const clonedMangoAccount = cloneDeep ( mangoAccount ) ;
2023-01-13 04:19:04 -08:00
const instructions : TransactionInstruction [ ] = [ ] ;
2023-04-24 05:48:53 -07:00
for ( const serum3Account of clonedMangoAccount . serum3Active ( ) ) {
2023-01-13 04:19:04 -08:00
const serum3Market = group . serum3MarketsMapByMarketIndex . get (
serum3Account . marketIndex ,
2023-01-13 14:32:12 -08:00
) ! ;
2023-01-13 04:19:04 -08:00
const closeOOIx = await this . serum3CloseOpenOrdersIx (
group ,
2023-04-24 05:48:53 -07:00
clonedMangoAccount ,
2023-01-13 14:32:12 -08:00
serum3Market . serumMarketExternal ,
2023-01-13 04:19:04 -08:00
) ;
instructions . push ( closeOOIx ) ;
2023-04-24 05:48:53 -07:00
serum3Account . marketIndex =
Serum3Orders . Serum3MarketIndexUnset as MarketIndex ;
2023-01-13 04:19:04 -08:00
}
2023-04-24 05:48:53 -07:00
for ( const pp of clonedMangoAccount . perpActive ( ) ) {
const perpMarketIndex = pp . marketIndex ;
2023-01-13 14:32:12 -08:00
const perpMarket = group . getPerpMarketByMarketIndex ( perpMarketIndex ) ;
2023-01-13 04:19:04 -08:00
const deactivatingPositionIx = await this . perpDeactivatePositionIx (
group ,
2023-04-24 05:48:53 -07:00
clonedMangoAccount ,
2023-01-13 14:32:12 -08:00
perpMarketIndex ,
2023-01-13 04:19:04 -08:00
) ;
instructions . push ( deactivatingPositionIx ) ;
2023-04-24 05:48:53 -07:00
pp . marketIndex = PerpPosition . PerpMarketIndexUnset as PerpMarketIndex ;
2023-01-13 04:19:04 -08:00
}
2023-04-24 05:48:53 -07:00
for ( const tp of clonedMangoAccount . tokensActive ( ) ) {
const bank = group . getFirstBankByTokenIndex ( tp . tokenIndex ) ;
2023-01-13 14:32:12 -08:00
const withdrawIx = await this . tokenWithdrawNativeIx (
group ,
2023-04-24 05:48:53 -07:00
clonedMangoAccount ,
2023-01-13 14:32:12 -08:00
bank . mint ,
U64_MAX_BN ,
false ,
) ;
instructions . push ( . . . withdrawIx ) ;
2023-04-24 05:48:53 -07:00
tp . tokenIndex = TokenPosition . TokenIndexUnset as TokenIndex ;
2023-01-13 14:32:12 -08:00
}
2023-01-13 04:19:04 -08:00
const closeIx = await this . program . methods
2023-01-13 14:32:12 -08:00
. accountClose ( false )
2022-04-08 08:21:49 -07:00
. accounts ( {
2022-07-04 03:09:33 -07:00
group : group.publicKey ,
2023-04-24 05:48:53 -07:00
account : clonedMangoAccount.publicKey ,
2022-05-18 08:16:14 -07:00
owner : ( this . program . provider as AnchorProvider ) . wallet . publicKey ,
2023-04-24 05:48:53 -07:00
solDestination : clonedMangoAccount.owner ,
2022-04-08 08:21:49 -07:00
} )
2022-09-27 06:13:53 -07:00
. instruction ( ) ;
2023-01-13 04:19:04 -08:00
instructions . push ( closeIx ) ;
2022-09-02 10:50:01 -07:00
2023-02-03 04:55:46 -08:00
return await this . sendAndConfirmTransactionForGroup ( group , instructions ) ;
2022-04-08 08:21:49 -07:00
}
2023-02-28 03:05:02 -08:00
public async accountBuybackFeesWithMngoIx (
group : Group ,
mangoAccount : MangoAccount ,
2023-03-20 03:18:11 -07:00
maxBuybackUsd? : number ,
2023-02-28 03:05:02 -08:00
) : Promise < TransactionInstruction > {
2023-03-20 03:18:11 -07:00
maxBuybackUsd = maxBuybackUsd ? ? mangoAccount . getMaxFeesBuybackUi ( group ) ;
2023-02-28 03:05:02 -08:00
return await this . program . methods
2023-03-20 03:18:11 -07:00
. accountBuybackFeesWithMngo ( toNative ( maxBuybackUsd , 6 ) )
2023-02-28 03:05:02 -08:00
. accounts ( {
group : group.publicKey ,
account : mangoAccount.publicKey ,
daoAccount : group.buybackFeesSwapMangoAccount ,
mngoBank : group.getFirstBankForMngo ( ) . publicKey ,
mngoOracle : group.getFirstBankForMngo ( ) . oracle ,
feesBank : group.getFirstBankByTokenIndex ( 0 as TokenIndex ) . publicKey ,
feesOracle : group.getFirstBankByTokenIndex ( 0 as TokenIndex ) . oracle ,
} )
. instruction ( ) ;
}
public async accountBuybackFeesWithMngo (
group : Group ,
mangoAccount : MangoAccount ,
maxBuyback? : number ,
2023-08-11 10:12:13 -07:00
) : Promise < MangoSignatureStatus > {
2023-02-28 03:05:02 -08:00
const ix = await this . accountBuybackFeesWithMngoIx (
group ,
mangoAccount ,
maxBuyback ,
) ;
return await this . sendAndConfirmTransactionForGroup ( group , [ ix ] ) ;
}
2022-06-09 09:27:31 -07:00
public async tokenDeposit (
2022-04-07 09:58:42 -07:00
group : Group ,
mangoAccount : MangoAccount ,
2022-08-17 23:48:45 -07:00
mintPk : PublicKey ,
2022-04-07 09:58:42 -07:00
amount : number ,
2023-01-04 00:24:40 -08:00
reduceOnly = false ,
2023-08-11 10:12:13 -07:00
) : Promise < MangoSignatureStatus > {
2022-08-31 02:41:12 -07:00
const decimals = group . getMintDecimals ( mintPk ) ;
2022-09-30 06:07:43 -07:00
const nativeAmount = toNative ( amount , decimals ) ;
2022-08-08 07:31:38 -07:00
return await this . tokenDepositNative (
group ,
mangoAccount ,
2022-08-17 23:48:45 -07:00
mintPk ,
2022-08-08 07:31:38 -07:00
nativeAmount ,
2023-01-04 00:24:40 -08:00
reduceOnly ,
2022-08-08 07:31:38 -07:00
) ;
}
public async tokenDepositNative (
group : Group ,
mangoAccount : MangoAccount ,
2022-08-17 23:48:45 -07:00
mintPk : PublicKey ,
2022-09-30 06:07:43 -07:00
nativeAmount : BN ,
2023-01-04 00:24:40 -08:00
reduceOnly = false ,
2023-08-11 10:12:13 -07:00
) : Promise < MangoSignatureStatus > {
2022-08-17 23:48:45 -07:00
const bank = group . getFirstBankByMint ( mintPk ) ;
2022-04-08 03:30:21 -07:00
2022-05-25 17:29:06 -07:00
const tokenAccountPk = await getAssociatedTokenAddress (
2022-08-17 23:48:45 -07:00
mintPk ,
2022-04-07 09:58:42 -07:00
mangoAccount . owner ,
) ;
2023-08-11 00:35:57 -07:00
let wrappedSolAccount : PublicKey | undefined ;
2022-05-25 17:29:06 -07:00
let preInstructions : TransactionInstruction [ ] = [ ] ;
let postInstructions : TransactionInstruction [ ] = [ ] ;
2023-02-21 23:36:59 -08:00
if ( mintPk . equals ( NATIVE_MINT ) ) {
2023-08-11 00:35:57 -07:00
// Generate a random seed for wrappedSolAccount.
const seed = Keypair . generate ( ) . publicKey . toBase58 ( ) . slice ( 0 , 32 ) ;
// Calculate a publicKey that will be controlled by the `mangoAccount.owner`.
wrappedSolAccount = await PublicKey . createWithSeed (
mangoAccount . owner ,
seed ,
TOKEN_PROGRAM_ID ,
) ;
2022-09-30 06:07:43 -07:00
const lamports = nativeAmount . add ( new BN ( 1 e7 ) ) ;
2022-05-25 17:29:06 -07:00
preInstructions = [
2023-08-11 00:35:57 -07:00
SystemProgram . createAccountWithSeed ( {
2022-05-25 17:29:06 -07:00
fromPubkey : mangoAccount.owner ,
2023-08-11 00:35:57 -07:00
basePubkey : mangoAccount.owner ,
seed ,
newAccountPubkey : wrappedSolAccount ,
2022-09-30 06:07:43 -07:00
lamports : lamports.toNumber ( ) ,
2022-05-25 17:29:06 -07:00
space : 165 ,
programId : TOKEN_PROGRAM_ID ,
} ) ,
2023-02-21 23:36:59 -08:00
createInitializeAccount3Instruction (
2023-08-11 00:35:57 -07:00
wrappedSolAccount ,
2023-02-21 23:36:59 -08:00
NATIVE_MINT ,
mangoAccount . owner ,
) ,
2022-05-25 17:29:06 -07:00
] ;
postInstructions = [
2023-02-21 23:36:59 -08:00
createCloseAccountInstruction (
2023-08-11 00:35:57 -07:00
wrappedSolAccount ,
2023-02-21 23:36:59 -08:00
mangoAccount . owner ,
mangoAccount . owner ,
) ,
2022-05-25 17:29:06 -07:00
] ;
}
2022-04-07 09:58:42 -07:00
const healthRemainingAccounts : PublicKey [ ] =
2023-04-24 05:48:53 -07:00
this . buildHealthRemainingAccounts ( group , [ mangoAccount ] , [ bank ] , [ ] ) ;
2022-04-07 09:58:42 -07:00
2022-09-27 06:13:53 -07:00
const ix = await this . program . methods
2023-01-04 00:24:40 -08:00
. tokenDeposit ( new BN ( nativeAmount ) , reduceOnly )
2022-04-07 12:00:08 -07:00
. accounts ( {
group : group.publicKey ,
account : mangoAccount.publicKey ,
2022-09-30 04:21:01 -07:00
owner : mangoAccount.owner ,
2022-04-07 12:00:08 -07:00
bank : bank.publicKey ,
vault : bank.vault ,
2022-08-22 02:02:01 -07:00
oracle : bank.oracle ,
2023-08-11 00:35:57 -07:00
tokenAccount : wrappedSolAccount ? ? tokenAccountPk ,
2022-08-03 09:05:16 -07:00
tokenAuthority : mangoAccount.owner ,
2022-04-07 12:00:08 -07:00
} )
. remainingAccounts (
healthRemainingAccounts . map (
( pk ) = >
( { pubkey : pk , isWritable : false , isSigner : false } as AccountMeta ) ,
) ,
)
2022-09-27 06:13:53 -07:00
. instruction ( ) ;
2022-08-15 21:27:06 -07:00
2023-08-11 00:35:57 -07:00
return await this . sendAndConfirmTransactionForGroup ( group , [
. . . preInstructions ,
ix ,
. . . postInstructions ,
] ) ;
2022-04-07 09:58:42 -07:00
}
2023-09-11 04:37:11 -07:00
/ * *
* Withdraw the entire deposit balance for a token , effectively freeing the token position
*
* @param group
* @param mangoAccount
* @param mintPk
* @returns
* /
public async tokenWithdrawAllDepositForMint (
group : Group ,
mangoAccount : MangoAccount ,
mintPk : PublicKey ,
) : Promise < MangoSignatureStatus > {
const bank = group . getFirstBankByMint ( mintPk ) ;
const b = mangoAccount . getTokenBalance ( bank ) . toNumber ( ) ;
if ( b < 0 ) {
throw new Error ( ` Only call this method for deposits and not borrows! ` ) ;
}
const ixes = await this . tokenWithdrawNativeIx (
group ,
mangoAccount ,
mintPk ,
U64_MAX_BN ,
false ,
) ;
return await this . sendAndConfirmTransactionForGroup ( group , ixes ) ;
}
2022-06-09 09:27:31 -07:00
public async tokenWithdraw (
2022-04-07 09:58:42 -07:00
group : Group ,
mangoAccount : MangoAccount ,
2022-08-17 23:48:45 -07:00
mintPk : PublicKey ,
2022-04-07 09:58:42 -07:00
amount : number ,
allowBorrow : boolean ,
2023-08-11 10:12:13 -07:00
) : Promise < MangoSignatureStatus > {
2022-09-30 06:07:43 -07:00
const nativeAmount = toNative ( amount , group . getMintDecimals ( mintPk ) ) ;
2023-01-12 16:38:02 -08:00
const ixes = await this . tokenWithdrawNativeIx (
2022-08-08 07:31:38 -07:00
group ,
mangoAccount ,
2022-08-17 23:48:45 -07:00
mintPk ,
2022-08-08 07:31:38 -07:00
nativeAmount ,
allowBorrow ,
2022-04-07 09:58:42 -07:00
) ;
2023-01-12 16:38:02 -08:00
2023-02-03 04:55:46 -08:00
return await this . sendAndConfirmTransactionForGroup ( group , ixes ) ;
2022-04-07 09:58:42 -07:00
}
2023-01-12 16:38:02 -08:00
public async tokenWithdrawNativeIx (
2022-07-04 03:09:33 -07:00
group : Group ,
mangoAccount : MangoAccount ,
2022-08-17 23:48:45 -07:00
mintPk : PublicKey ,
2022-09-30 06:07:43 -07:00
nativeAmount : BN ,
2022-07-04 03:09:33 -07:00
allowBorrow : boolean ,
2023-01-12 16:38:02 -08:00
) : Promise < TransactionInstruction [ ] > {
2022-08-17 23:48:45 -07:00
const bank = group . getFirstBankByMint ( mintPk ) ;
2022-07-04 03:09:33 -07:00
const tokenAccountPk = await getAssociatedTokenAddress (
bank . mint ,
mangoAccount . owner ,
2023-07-25 04:35:25 -07:00
true ,
2022-07-04 03:09:33 -07:00
) ;
2022-09-01 03:11:31 -07:00
// ensure withdraws don't fail with missing ATAs
2022-09-01 02:25:58 -07:00
const preInstructions : TransactionInstruction [ ] = [
await createAssociatedTokenAccountIdempotentInstruction (
mangoAccount . owner ,
mangoAccount . owner ,
bank . mint ,
) ,
] ;
const postInstructions : TransactionInstruction [ ] = [ ] ;
2023-02-21 23:36:59 -08:00
if ( mintPk . equals ( NATIVE_MINT ) ) {
2022-09-01 02:25:58 -07:00
postInstructions . push (
2023-02-21 23:36:59 -08:00
createCloseAccountInstruction (
tokenAccountPk ,
mangoAccount . owner ,
mangoAccount . owner ,
) ,
2022-09-01 02:25:58 -07:00
) ;
}
2022-07-04 03:09:33 -07:00
const healthRemainingAccounts : PublicKey [ ] =
2023-04-24 05:48:53 -07:00
this . buildHealthRemainingAccounts ( group , [ mangoAccount ] , [ bank ] , [ ] , [ ] ) ;
2022-07-04 03:09:33 -07:00
2022-09-27 06:13:53 -07:00
const ix = await this . program . methods
2022-07-04 03:09:33 -07:00
. tokenWithdraw ( new BN ( nativeAmount ) , allowBorrow )
. accounts ( {
group : group.publicKey ,
account : mangoAccount.publicKey ,
2022-10-08 03:48:13 -07:00
owner : mangoAccount.owner ,
2022-07-04 03:09:33 -07:00
bank : bank.publicKey ,
vault : bank.vault ,
2022-08-22 02:02:01 -07:00
oracle : bank.oracle ,
2022-07-04 03:09:33 -07:00
tokenAccount : tokenAccountPk ,
} )
. remainingAccounts (
2023-04-24 05:48:53 -07:00
healthRemainingAccounts . map (
( pk ) = >
( {
pubkey : pk ,
isWritable : false ,
isSigner : false ,
} as AccountMeta ) ,
) ,
2022-07-04 03:09:33 -07:00
)
2022-09-27 06:13:53 -07:00
. instruction ( ) ;
2022-08-12 17:15:12 -07:00
2023-01-12 16:38:02 -08:00
return [ . . . preInstructions , ix , . . . postInstructions ] ;
2022-07-04 03:09:33 -07:00
}
2023-02-02 06:08:57 -08:00
public async tokenWithdrawNative (
group : Group ,
mangoAccount : MangoAccount ,
mintPk : PublicKey ,
nativeAmount : BN ,
allowBorrow : boolean ,
2023-08-11 10:12:13 -07:00
) : Promise < MangoSignatureStatus > {
2023-02-02 06:08:57 -08:00
const ixs = await this . tokenWithdrawNativeIx (
group ,
mangoAccount ,
mintPk ,
nativeAmount ,
allowBorrow ,
) ;
2023-02-03 04:55:46 -08:00
return await this . sendAndConfirmTransactionForGroup ( group , ixs ) ;
2023-02-02 06:08:57 -08:00
}
2022-04-07 23:29:35 -07:00
// Serum
public async serum3RegisterMarket (
group : Group ,
serum3MarketExternalPk : PublicKey ,
baseBank : Bank ,
quoteBank : Bank ,
marketIndex : number ,
2022-04-12 07:19:58 -07:00
name : string ,
2023-08-11 10:12:13 -07:00
) : Promise < MangoSignatureStatus > {
2023-02-02 05:23:22 -08:00
const ix = await this . program . methods
2022-04-12 07:19:58 -07:00
. serum3RegisterMarket ( marketIndex , name )
2022-04-07 23:29:35 -07:00
. accounts ( {
group : group.publicKey ,
2022-05-18 08:16:14 -07:00
admin : ( this . program . provider as AnchorProvider ) . wallet . publicKey ,
2022-12-08 01:16:06 -08:00
serumProgram : OPENBOOK_PROGRAM_ID [ this . cluster ] ,
2022-04-07 23:29:35 -07:00
serumMarketExternal : serum3MarketExternalPk ,
baseBank : baseBank.publicKey ,
quoteBank : quoteBank.publicKey ,
2022-05-18 08:16:14 -07:00
payer : ( this . program . provider as AnchorProvider ) . wallet . publicKey ,
2022-04-07 23:29:35 -07:00
} )
2023-02-02 05:23:22 -08:00
. instruction ( ) ;
2023-02-03 04:55:46 -08:00
return await this . sendAndConfirmTransactionForGroup ( group , [ ix ] ) ;
2022-04-07 23:29:35 -07:00
}
2023-04-24 23:12:42 -07:00
public async serum3EditMarket (
group : Group ,
serum3MarketIndex : MarketIndex ,
reduceOnly : boolean | null ,
forceClose : boolean | null ,
2023-06-21 06:38:27 -07:00
name : string | null ,
2023-08-11 10:12:13 -07:00
) : Promise < MangoSignatureStatus > {
2023-04-24 23:12:42 -07:00
const serum3Market =
group . serum3MarketsMapByMarketIndex . get ( serum3MarketIndex ) ;
const ix = await this . program . methods
2023-06-21 06:38:27 -07:00
. serum3EditMarket ( reduceOnly , forceClose , name )
2023-04-24 23:12:42 -07:00
. accounts ( {
group : group.publicKey ,
admin : ( this . program . provider as AnchorProvider ) . wallet . publicKey ,
market : serum3Market?.publicKey ,
} )
. instruction ( ) ;
return await this . sendAndConfirmTransactionForGroup ( group , [ ix ] ) ;
}
2022-06-09 09:27:31 -07:00
public async serum3deregisterMarket (
group : Group ,
2022-08-31 02:36:44 -07:00
externalMarketPk : PublicKey ,
2023-08-11 10:12:13 -07:00
) : Promise < MangoSignatureStatus > {
2022-08-31 02:36:44 -07:00
const serum3Market = group . serum3MarketsMapByExternal . get (
externalMarketPk . toBase58 ( ) ,
) ! ;
2022-06-09 09:27:31 -07:00
2022-09-20 02:41:15 -07:00
const marketIndexBuf = Buffer . alloc ( 2 ) ;
marketIndexBuf . writeUInt16LE ( serum3Market . marketIndex ) ;
const [ indexReservation ] = await PublicKey . findProgramAddress (
[ Buffer . from ( 'Serum3Index' ) , group . publicKey . toBuffer ( ) , marketIndexBuf ] ,
this . program . programId ,
) ;
2023-02-02 05:23:22 -08:00
const ix = await this . program . methods
2022-06-09 09:27:31 -07:00
. serum3DeregisterMarket ( )
. accounts ( {
group : group.publicKey ,
serumMarket : serum3Market.publicKey ,
2022-09-20 02:41:15 -07:00
indexReservation ,
2022-06-09 09:27:31 -07:00
solDestination : ( this . program . provider as AnchorProvider ) . wallet
. publicKey ,
} )
2023-02-02 05:23:22 -08:00
. instruction ( ) ;
2023-02-03 04:55:46 -08:00
return await this . sendAndConfirmTransactionForGroup ( group , [ ix ] ) ;
2022-06-09 09:27:31 -07:00
}
2022-06-11 04:49:45 -07:00
public async serum3GetMarkets (
2022-04-07 23:29:35 -07:00
group : Group ,
2022-04-08 03:30:21 -07:00
baseTokenIndex? : number ,
quoteTokenIndex? : number ,
2022-04-07 23:29:35 -07:00
) : Promise < Serum3Market [ ] > {
const bumpfbuf = Buffer . alloc ( 1 ) ;
bumpfbuf . writeUInt8 ( 255 ) ;
2022-04-08 03:30:21 -07:00
const filters : MemcmpFilter [ ] = [
{
memcmp : {
bytes : group.publicKey.toBase58 ( ) ,
2022-07-06 00:56:14 -07:00
offset : 8 ,
2022-04-07 23:29:35 -07:00
} ,
2022-04-08 03:30:21 -07:00
} ,
] ;
if ( baseTokenIndex ) {
const bbuf = Buffer . alloc ( 2 ) ;
bbuf . writeUInt16LE ( baseTokenIndex ) ;
filters . push ( {
memcmp : {
bytes : bs58.encode ( bbuf ) ,
2022-07-06 00:56:14 -07:00
offset : 40 ,
2022-04-07 23:29:35 -07:00
} ,
2022-04-08 03:30:21 -07:00
} ) ;
}
if ( quoteTokenIndex ) {
const qbuf = Buffer . alloc ( 2 ) ;
qbuf . writeUInt16LE ( quoteTokenIndex ) ;
filters . push ( {
memcmp : {
bytes : bs58.encode ( qbuf ) ,
2022-07-06 00:56:14 -07:00
offset : 42 ,
2022-04-07 23:29:35 -07:00
} ,
2022-04-08 03:30:21 -07:00
} ) ;
}
return ( await this . program . account . serum3Market . all ( filters ) ) . map ( ( tuple ) = >
Serum3Market . from ( tuple . publicKey , tuple . account ) ,
) ;
2022-04-07 23:29:35 -07:00
}
public async serum3CreateOpenOrders (
group : Group ,
mangoAccount : MangoAccount ,
2022-09-01 01:48:50 -07:00
externalMarketPk : PublicKey ,
2023-08-11 10:12:13 -07:00
) : Promise < MangoSignatureStatus > {
2022-09-01 01:48:50 -07:00
const serum3Market : Serum3Market = group . serum3MarketsMapByExternal . get (
externalMarketPk . toBase58 ( ) ,
) ! ;
2022-04-08 03:30:21 -07:00
2023-02-02 05:23:22 -08:00
const ix = await this . program . methods
2022-04-07 23:29:35 -07:00
. serum3CreateOpenOrders ( )
. accounts ( {
group : group.publicKey ,
account : mangoAccount.publicKey ,
serumMarket : serum3Market.publicKey ,
serumProgram : serum3Market.serumProgram ,
serumMarketExternal : serum3Market.serumMarketExternal ,
2022-05-18 08:16:14 -07:00
owner : ( this . program . provider as AnchorProvider ) . wallet . publicKey ,
payer : ( this . program . provider as AnchorProvider ) . wallet . publicKey ,
2022-04-07 23:29:35 -07:00
} )
2023-02-02 05:23:22 -08:00
. instruction ( ) ;
2023-02-03 04:55:46 -08:00
return await this . sendAndConfirmTransactionForGroup ( group , [ ix ] ) ;
2022-04-07 23:29:35 -07:00
}
2023-01-04 23:30:15 -08:00
public async serum3CreateOpenOrdersIx (
2022-06-09 09:27:31 -07:00
group : Group ,
mangoAccount : MangoAccount ,
2022-08-31 02:36:44 -07:00
externalMarketPk : PublicKey ,
2023-01-04 23:30:15 -08:00
) : Promise < TransactionInstruction > {
const serum3Market : Serum3Market = group . serum3MarketsMapByExternal . get (
externalMarketPk . toBase58 ( ) ,
) ! ;
const ix = await this . program . methods
. serum3CreateOpenOrders ( )
. accounts ( {
group : group.publicKey ,
account : mangoAccount.publicKey ,
serumMarket : serum3Market.publicKey ,
serumProgram : serum3Market.serumProgram ,
serumMarketExternal : serum3Market.serumMarketExternal ,
owner : ( this . program . provider as AnchorProvider ) . wallet . publicKey ,
payer : ( this . program . provider as AnchorProvider ) . wallet . publicKey ,
} )
. instruction ( ) ;
return ix ;
}
public async serum3CloseOpenOrdersIx (
group : Group ,
mangoAccount : MangoAccount ,
externalMarketPk : PublicKey ,
) : Promise < TransactionInstruction > {
2022-08-31 02:36:44 -07:00
const serum3Market = group . serum3MarketsMapByExternal . get (
externalMarketPk . toBase58 ( ) ,
) ! ;
2022-06-09 09:27:31 -07:00
return await this . program . methods
. serum3CloseOpenOrders ( )
. accounts ( {
group : group.publicKey ,
account : mangoAccount.publicKey ,
serumMarket : serum3Market.publicKey ,
serumProgram : serum3Market.serumProgram ,
serumMarketExternal : serum3Market.serumMarketExternal ,
2023-04-19 09:15:39 -07:00
openOrders : await serum3Market . findOoPda (
this . programId ,
mangoAccount . publicKey ,
) ,
2022-06-09 09:27:31 -07:00
solDestination : ( this . program . provider as AnchorProvider ) . wallet
. publicKey ,
} )
2023-01-04 23:30:15 -08:00
. instruction ( ) ;
}
public async serum3CloseOpenOrders (
group : Group ,
mangoAccount : MangoAccount ,
externalMarketPk : PublicKey ,
2023-08-11 10:12:13 -07:00
) : Promise < MangoSignatureStatus > {
2023-01-04 23:30:15 -08:00
const ix = await this . serum3CloseOpenOrdersIx (
group ,
mangoAccount ,
externalMarketPk ,
) ;
return await sendTransaction (
this . program . provider as AnchorProvider ,
[ ix ] ,
group . addressLookupTablesList ,
{
postSendTxCallback : this.postSendTxCallback ,
} ,
) ;
2022-06-09 09:27:31 -07:00
}
2023-04-24 23:12:42 -07:00
public async serum3LiqForceCancelOrders (
group : Group ,
mangoAccount : MangoAccount ,
externalMarketPk : PublicKey ,
limit? : number ,
2023-08-11 10:12:13 -07:00
) : Promise < MangoSignatureStatus > {
2023-04-24 23:12:42 -07:00
const serum3Market = group . serum3MarketsMapByExternal . get (
externalMarketPk . toBase58 ( ) ,
) ! ;
const serum3MarketExternal = group . serum3ExternalMarketsMap . get (
externalMarketPk . toBase58 ( ) ,
) ! ;
const openOrders = await serum3Market . findOoPda (
this . programId ,
mangoAccount . publicKey ,
) ;
const healthRemainingAccounts : PublicKey [ ] =
this . buildHealthRemainingAccounts (
group ,
[ mangoAccount ] ,
[ ] ,
[ ] ,
[ [ serum3Market , openOrders ] ] ,
) ;
const ix = await this . program . methods
. serum3LiqForceCancelOrders ( limit ? ? 10 )
. accounts ( {
group : group.publicKey ,
account : mangoAccount.publicKey ,
openOrders ,
serumMarket : serum3Market.publicKey ,
serumProgram : OPENBOOK_PROGRAM_ID [ this . cluster ] ,
serumMarketExternal : serum3Market.serumMarketExternal ,
marketBids : serum3MarketExternal.bidsAddress ,
marketAsks : serum3MarketExternal.asksAddress ,
marketEventQueue : serum3MarketExternal.decoded.eventQueue ,
marketBaseVault : serum3MarketExternal.decoded.baseVault ,
marketQuoteVault : serum3MarketExternal.decoded.quoteVault ,
marketVaultSigner : await generateSerum3MarketExternalVaultSignerAddress (
this . cluster ,
serum3Market ,
serum3MarketExternal ,
) ,
quoteBank : group.getFirstBankByTokenIndex ( serum3Market . quoteTokenIndex )
. publicKey ,
quoteVault : group.getFirstBankByTokenIndex ( serum3Market . quoteTokenIndex )
. vault ,
baseBank : group.getFirstBankByTokenIndex ( serum3Market . baseTokenIndex )
. publicKey ,
baseVault : group.getFirstBankByTokenIndex ( serum3Market . baseTokenIndex )
. vault ,
} )
. remainingAccounts (
healthRemainingAccounts . map (
( pk ) = >
( { pubkey : pk , isWritable : false , isSigner : false } as AccountMeta ) ,
) ,
)
. instruction ( ) ;
return await this . sendAndConfirmTransactionForGroup ( group , [ ix ] ) ;
}
2022-12-15 01:40:45 -08:00
public async serum3PlaceOrderIx (
2022-04-08 03:30:21 -07:00
group : Group ,
mangoAccount : MangoAccount ,
2022-08-31 02:36:44 -07:00
externalMarketPk : PublicKey ,
2022-04-08 03:30:21 -07:00
side : Serum3Side ,
2022-04-08 07:57:37 -07:00
price : number ,
size : number ,
2022-04-08 03:30:21 -07:00
selfTradeBehavior : Serum3SelfTradeBehavior ,
orderType : Serum3OrderType ,
clientOrderId : number ,
limit : number ,
2023-01-04 23:30:15 -08:00
) : Promise < TransactionInstruction [ ] > {
const ixs : TransactionInstruction [ ] = [ ] ;
2022-08-31 02:36:44 -07:00
const serum3Market = group . serum3MarketsMapByExternal . get (
externalMarketPk . toBase58 ( ) ,
) ! ;
2023-01-04 23:30:15 -08:00
2023-01-07 14:06:35 -08:00
let openOrderPk : PublicKey | undefined = undefined ;
const banks : Bank [ ] = [ ] ;
const openOrdersForMarket : [ Serum3Market , PublicKey ] [ ] = [ ] ;
2022-09-29 06:51:09 -07:00
if ( ! mangoAccount . getSerum3Account ( serum3Market . marketIndex ) ) {
2023-01-04 23:30:15 -08:00
const ix = await this . serum3CreateOpenOrdersIx (
2022-09-01 01:48:50 -07:00
group ,
mangoAccount ,
serum3Market . serumMarketExternal ,
) ;
2023-01-07 14:06:35 -08:00
ixs . push ( ix ) ;
openOrderPk = await serum3Market . findOoPda (
2023-01-04 23:30:15 -08:00
this . program . programId ,
mangoAccount . publicKey ,
2022-04-08 03:30:21 -07:00
) ;
2023-01-07 14:06:35 -08:00
openOrdersForMarket . push ( [ serum3Market , openOrderPk ] ) ;
2023-01-07 14:23:58 -08:00
const baseTokenIndex = serum3Market . baseTokenIndex ;
const quoteTokenIndex = serum3Market . quoteTokenIndex ;
// only include banks if no deposit has been previously made for same token
2023-04-25 02:13:40 -07:00
banks . push ( group . getFirstBankByTokenIndex ( quoteTokenIndex ) ) ;
banks . push ( group . getFirstBankByTokenIndex ( baseTokenIndex ) ) ;
2023-01-04 23:30:15 -08:00
}
2022-04-08 03:30:21 -07:00
const healthRemainingAccounts : PublicKey [ ] =
2022-08-31 02:36:44 -07:00
this . buildHealthRemainingAccounts (
group ,
[ mangoAccount ] ,
2023-01-07 14:06:35 -08:00
banks ,
2022-08-31 02:36:44 -07:00
[ ] ,
2023-01-07 14:06:35 -08:00
openOrdersForMarket ,
2023-01-04 23:30:15 -08:00
) ;
const serum3MarketExternal = group . serum3ExternalMarketsMap . get (
externalMarketPk . toBase58 ( ) ,
) ! ;
const serum3MarketExternalVaultSigner =
await generateSerum3MarketExternalVaultSignerAddress (
this . cluster ,
serum3Market ,
serum3MarketExternal ,
2022-08-31 02:36:44 -07:00
) ;
2022-04-08 03:30:21 -07:00
2022-04-08 07:57:37 -07:00
const limitPrice = serum3MarketExternal . priceNumberToLots ( price ) ;
const maxBaseQuantity = serum3MarketExternal . baseSizeNumberToLots ( size ) ;
2022-12-21 01:21:24 -08:00
const isTaker = orderType !== Serum3OrderType . postOnly ;
2022-12-17 10:01:57 -08:00
const maxQuoteQuantity = new BN (
2023-05-07 23:13:50 -07:00
Math . ceil (
serum3MarketExternal . decoded . quoteLotSize . toNumber ( ) *
( 1 + Math . max ( serum3Market . getFeeRates ( isTaker ) , 0 ) ) *
serum3MarketExternal . baseSizeNumberToLots ( size ) . toNumber ( ) *
serum3MarketExternal . priceNumberToLots ( price ) . toNumber ( ) ,
) ,
2022-12-17 10:01:57 -08:00
) ;
2022-12-17 11:08:48 -08:00
2022-09-29 06:51:09 -07:00
const payerTokenIndex = ( ( ) : TokenIndex = > {
2022-08-30 00:55:19 -07:00
if ( side == Serum3Side . bid ) {
return serum3Market . quoteTokenIndex ;
} else {
return serum3Market . baseTokenIndex ;
}
} ) ( ) ;
2022-04-08 07:57:37 -07:00
2022-12-09 04:41:43 -08:00
const payerBank = group . getFirstBankByTokenIndex ( payerTokenIndex ) ;
2022-09-27 06:13:53 -07:00
const ix = await this . program . methods
2022-04-08 03:30:21 -07:00
. serum3PlaceOrder (
side ,
2022-04-08 07:57:37 -07:00
limitPrice ,
maxBaseQuantity ,
maxQuoteQuantity ,
2022-04-08 03:30:21 -07:00
selfTradeBehavior ,
orderType ,
new BN ( clientOrderId ) ,
limit ,
)
. accounts ( {
group : group.publicKey ,
account : mangoAccount.publicKey ,
2022-05-18 08:16:14 -07:00
owner : ( this . program . provider as AnchorProvider ) . wallet . publicKey ,
2023-01-04 23:30:15 -08:00
openOrders :
2023-01-07 14:06:35 -08:00
openOrderPk ||
2023-01-04 23:30:15 -08:00
mangoAccount . getSerum3Account ( serum3Market . marketIndex ) ? . openOrders ,
2022-04-08 03:30:21 -07:00
serumMarket : serum3Market.publicKey ,
2022-12-08 01:16:06 -08:00
serumProgram : OPENBOOK_PROGRAM_ID [ this . cluster ] ,
2022-04-08 03:30:21 -07:00
serumMarketExternal : serum3Market.serumMarketExternal ,
marketBids : serum3MarketExternal.bidsAddress ,
marketAsks : serum3MarketExternal.asksAddress ,
marketEventQueue : serum3MarketExternal.decoded.eventQueue ,
marketRequestQueue : serum3MarketExternal.decoded.requestQueue ,
marketBaseVault : serum3MarketExternal.decoded.baseVault ,
marketQuoteVault : serum3MarketExternal.decoded.quoteVault ,
marketVaultSigner : serum3MarketExternalVaultSigner ,
2022-12-09 04:41:43 -08:00
payerBank : payerBank.publicKey ,
payerVault : payerBank.vault ,
payerOracle : payerBank.oracle ,
2022-04-08 03:30:21 -07:00
} )
. remainingAccounts (
healthRemainingAccounts . map (
( pk ) = >
( { pubkey : pk , isWritable : false , isSigner : false } as AccountMeta ) ,
) ,
)
2022-09-27 06:13:53 -07:00
. instruction ( ) ;
2022-09-13 22:44:00 -07:00
2023-01-04 23:30:15 -08:00
ixs . push ( ix ) ;
return ixs ;
2022-12-15 01:40:45 -08:00
}
public async serum3PlaceOrder (
group : Group ,
mangoAccount : MangoAccount ,
externalMarketPk : PublicKey ,
side : Serum3Side ,
price : number ,
size : number ,
selfTradeBehavior : Serum3SelfTradeBehavior ,
orderType : Serum3OrderType ,
clientOrderId : number ,
limit : number ,
2023-08-11 10:12:13 -07:00
) : Promise < MangoSignatureStatus > {
2023-01-04 23:30:15 -08:00
const placeOrderIxes = await this . serum3PlaceOrderIx (
2022-12-15 01:40:45 -08:00
group ,
mangoAccount ,
externalMarketPk ,
side ,
price ,
size ,
selfTradeBehavior ,
orderType ,
clientOrderId ,
limit ,
) ;
2023-04-19 09:15:39 -07:00
2023-01-04 23:30:15 -08:00
const settleIx = await this . serum3SettleFundsIx (
2022-12-27 15:50:29 -08:00
group ,
mangoAccount ,
externalMarketPk ,
) ;
2023-04-19 09:15:39 -07:00
const ixs = [ . . . placeOrderIxes , settleIx ] ;
return await this . sendAndConfirmTransactionForGroup ( group , ixs ) ;
2022-04-08 03:30:21 -07:00
}
2023-04-19 09:15:39 -07:00
public async serum3CancelAllOrdersIx (
2022-06-09 09:27:31 -07:00
group : Group ,
mangoAccount : MangoAccount ,
2022-08-31 02:36:44 -07:00
externalMarketPk : PublicKey ,
2022-11-04 08:07:26 -07:00
limit? : number ,
2023-04-19 09:15:39 -07:00
) : Promise < TransactionInstruction > {
2022-08-31 02:36:44 -07:00
const serum3Market = group . serum3MarketsMapByExternal . get (
externalMarketPk . toBase58 ( ) ,
) ! ;
2022-06-09 09:27:31 -07:00
2022-09-29 06:51:09 -07:00
const serum3MarketExternal = group . serum3ExternalMarketsMap . get (
2022-08-31 02:36:44 -07:00
externalMarketPk . toBase58 ( ) ,
) ! ;
2022-06-09 09:27:31 -07:00
2023-04-19 09:15:39 -07:00
return await this . program . methods
2022-11-04 08:07:26 -07:00
. serum3CancelAllOrders ( limit ? limit : 10 )
2022-06-09 09:27:31 -07:00
. accounts ( {
group : group.publicKey ,
account : mangoAccount.publicKey ,
owner : ( this . program . provider as AnchorProvider ) . wallet . publicKey ,
2023-04-19 09:15:39 -07:00
openOrders : await serum3Market . findOoPda (
this . programId ,
mangoAccount . publicKey ,
) ,
2022-06-09 09:27:31 -07:00
serumMarket : serum3Market.publicKey ,
2022-12-08 01:16:06 -08:00
serumProgram : OPENBOOK_PROGRAM_ID [ this . cluster ] ,
2022-06-09 09:27:31 -07:00
serumMarketExternal : serum3Market.serumMarketExternal ,
marketBids : serum3MarketExternal.bidsAddress ,
marketAsks : serum3MarketExternal.asksAddress ,
marketEventQueue : serum3MarketExternal.decoded.eventQueue ,
} )
2022-09-27 06:13:53 -07:00
. instruction ( ) ;
2023-04-19 09:15:39 -07:00
}
2022-09-13 22:44:00 -07:00
2023-04-19 09:15:39 -07:00
public async serum3CancelAllOrders (
group : Group ,
mangoAccount : MangoAccount ,
externalMarketPk : PublicKey ,
limit? : number ,
2023-08-11 10:12:13 -07:00
) : Promise < MangoSignatureStatus > {
2023-04-19 09:15:39 -07:00
return await this . sendAndConfirmTransactionForGroup ( group , [
await this . serum3CancelAllOrdersIx (
group ,
mangoAccount ,
externalMarketPk ,
limit ,
) ,
] ) ;
2022-06-09 09:27:31 -07:00
}
2022-12-15 04:41:45 -08:00
public async serum3SettleFundsIx (
2022-04-08 11:47:12 -07:00
group : Group ,
mangoAccount : MangoAccount ,
2022-08-31 02:36:44 -07:00
externalMarketPk : PublicKey ,
2022-12-15 04:41:45 -08:00
) : Promise < TransactionInstruction > {
2023-03-03 05:04:45 -08:00
if ( this . openbookFeesToDao == false ) {
throw new Error (
` openbookFeesToDao is set to false, please use serum3SettleFundsV2Ix ` ,
) ;
}
2023-06-15 08:34:56 -07:00
return await this . serum3SettleFundsV2Ix (
group ,
mangoAccount ,
externalMarketPk ,
) ;
2022-12-15 04:41:45 -08:00
}
2023-03-03 05:04:45 -08:00
public async serum3SettleFundsV2Ix (
group : Group ,
mangoAccount : MangoAccount ,
externalMarketPk : PublicKey ,
) : Promise < TransactionInstruction > {
const serum3Market = group . serum3MarketsMapByExternal . get (
externalMarketPk . toBase58 ( ) ,
) ! ;
const serum3MarketExternal = group . serum3ExternalMarketsMap . get (
externalMarketPk . toBase58 ( ) ,
) ! ;
const [ serum3MarketExternalVaultSigner , openOrderPublicKey ] =
await Promise . all ( [
generateSerum3MarketExternalVaultSignerAddress (
this . cluster ,
serum3Market ,
serum3MarketExternal ,
) ,
serum3Market . findOoPda ( this . program . programId , mangoAccount . publicKey ) ,
] ) ;
const ix = await this . program . methods
. serum3SettleFundsV2 ( this . openbookFeesToDao )
. accounts ( {
v1 : {
group : group.publicKey ,
account : mangoAccount.publicKey ,
owner : ( this . program . provider as AnchorProvider ) . wallet . publicKey ,
openOrders : openOrderPublicKey ,
serumMarket : serum3Market.publicKey ,
serumProgram : OPENBOOK_PROGRAM_ID [ this . cluster ] ,
serumMarketExternal : serum3Market.serumMarketExternal ,
marketBaseVault : serum3MarketExternal.decoded.baseVault ,
marketQuoteVault : serum3MarketExternal.decoded.quoteVault ,
marketVaultSigner : serum3MarketExternalVaultSigner ,
quoteBank : group.getFirstBankByTokenIndex (
serum3Market . quoteTokenIndex ,
) . publicKey ,
quoteVault : group.getFirstBankByTokenIndex (
serum3Market . quoteTokenIndex ,
) . vault ,
baseBank : group.getFirstBankByTokenIndex ( serum3Market . baseTokenIndex )
. publicKey ,
baseVault : group.getFirstBankByTokenIndex ( serum3Market . baseTokenIndex )
. vault ,
} ,
v2 : {
quoteOracle : group.getFirstBankByTokenIndex (
serum3Market . quoteTokenIndex ,
) . oracle ,
baseOracle : group.getFirstBankByTokenIndex (
serum3Market . baseTokenIndex ,
) . oracle ,
} ,
} )
. instruction ( ) ;
return ix ;
}
2022-12-15 04:41:45 -08:00
public async serum3SettleFunds (
group : Group ,
mangoAccount : MangoAccount ,
externalMarketPk : PublicKey ,
2023-08-11 10:12:13 -07:00
) : Promise < MangoSignatureStatus > {
2023-03-03 05:04:45 -08:00
const ix = await this . serum3SettleFundsV2Ix (
2022-12-15 04:41:45 -08:00
group ,
mangoAccount ,
externalMarketPk ,
) ;
2023-02-03 04:55:46 -08:00
return await this . sendAndConfirmTransactionForGroup ( group , [ ix ] ) ;
2022-04-08 11:47:12 -07:00
}
2022-12-15 01:40:45 -08:00
public async serum3CancelOrderIx (
2022-04-08 07:57:37 -07:00
group : Group ,
mangoAccount : MangoAccount ,
2022-08-31 02:36:44 -07:00
externalMarketPk : PublicKey ,
2022-04-08 07:57:37 -07:00
side : Serum3Side ,
orderId : BN ,
2022-12-15 01:40:45 -08:00
) : Promise < TransactionInstruction > {
2022-08-31 02:36:44 -07:00
const serum3Market = group . serum3MarketsMapByExternal . get (
externalMarketPk . toBase58 ( ) ,
) ! ;
2022-04-08 07:57:37 -07:00
2022-09-29 06:51:09 -07:00
const serum3MarketExternal = group . serum3ExternalMarketsMap . get (
2022-08-31 02:36:44 -07:00
externalMarketPk . toBase58 ( ) ,
) ! ;
2022-06-11 04:49:45 -07:00
2022-09-27 06:13:53 -07:00
const ix = await this . program . methods
2022-04-08 07:57:37 -07:00
. serum3CancelOrder ( side , orderId )
. accounts ( {
group : group.publicKey ,
account : mangoAccount.publicKey ,
2022-09-29 06:51:09 -07:00
openOrders : mangoAccount.getSerum3Account ( serum3Market . marketIndex )
2022-04-08 07:57:37 -07:00
? . openOrders ,
serumMarket : serum3Market.publicKey ,
2022-12-08 01:16:06 -08:00
serumProgram : OPENBOOK_PROGRAM_ID [ this . cluster ] ,
2022-04-08 07:57:37 -07:00
serumMarketExternal : serum3Market.serumMarketExternal ,
marketBids : serum3MarketExternal.bidsAddress ,
marketAsks : serum3MarketExternal.asksAddress ,
marketEventQueue : serum3MarketExternal.decoded.eventQueue ,
} )
2022-09-27 06:13:53 -07:00
. instruction ( ) ;
2022-09-13 22:44:00 -07:00
2022-12-15 01:40:45 -08:00
return ix ;
}
public async serum3CancelOrder (
group : Group ,
mangoAccount : MangoAccount ,
externalMarketPk : PublicKey ,
side : Serum3Side ,
orderId : BN ,
2023-08-11 10:12:13 -07:00
) : Promise < MangoSignatureStatus > {
2022-12-15 11:06:10 -08:00
const ixes = await Promise . all ( [
this . serum3CancelOrderIx (
group ,
mangoAccount ,
externalMarketPk ,
side ,
orderId ,
) ,
2023-03-03 05:04:45 -08:00
this . serum3SettleFundsV2Ix ( group , mangoAccount , externalMarketPk ) ,
2022-12-15 11:06:10 -08:00
] ) ;
2022-12-15 01:40:45 -08:00
2023-02-03 04:55:46 -08:00
return await this . sendAndConfirmTransactionForGroup ( group , ixes ) ;
2022-04-08 07:57:37 -07:00
}
2022-05-11 04:33:01 -07:00
/// perps
2022-10-07 04:52:04 -07:00
public async perpCreateMarket (
2022-05-11 04:33:01 -07:00
group : Group ,
oraclePk : PublicKey ,
perpMarketIndex : number ,
name : string ,
2022-11-09 04:25:53 -08:00
oracleConfig : OracleConfigParams ,
2022-09-21 00:42:45 -07:00
baseDecimals : number ,
2022-05-11 04:33:01 -07:00
quoteLotSize : number ,
baseLotSize : number ,
2023-01-16 07:49:09 -08:00
maintBaseAssetWeight : number ,
initBaseAssetWeight : number ,
maintBaseLiabWeight : number ,
initBaseLiabWeight : number ,
2023-02-01 07:15:45 -08:00
maintOverallAssetWeight : number ,
initOverallAssetWeight : number ,
2023-02-02 00:00:37 -08:00
baseLiquidationFee : number ,
2022-05-11 04:33:01 -07:00
makerFee : number ,
takerFee : number ,
2022-09-22 10:03:45 -07:00
feePenalty : number ,
2022-05-17 06:06:29 -07:00
minFunding : number ,
maxFunding : number ,
impactQuantity : number ,
2022-09-12 06:25:50 -07:00
groupInsuranceFund : boolean ,
2022-09-29 03:59:55 -07:00
settleFeeFlat : number ,
settleFeeAmountThreshold : number ,
settleFeeFractionLowHealth : number ,
2022-09-29 05:13:28 -07:00
settleTokenIndex : number ,
2022-12-02 03:24:11 -08:00
settlePnlLimitFactor : number ,
settlePnlLimitWindowSize : number ,
2023-02-02 00:00:37 -08:00
positivePnlLiquidationFee : number ,
2023-08-11 10:12:13 -07:00
) : Promise < MangoSignatureStatus > {
2022-05-11 04:33:01 -07:00
const bids = new Keypair ( ) ;
const asks = new Keypair ( ) ;
const eventQueue = new Keypair ( ) ;
2022-09-30 04:33:21 -07:00
const bookSideSize = ( this . program as any ) . _coder . accounts . size (
( this . program . account . bookSide as any ) . _idlAccount ,
) ;
const eventQueueSize = ( this . program as any ) . _coder . accounts . size (
( this . program . account . eventQueue as any ) . _idlAccount ,
) ;
2023-02-02 05:23:22 -08:00
const ix = await this . program . methods
2022-05-11 04:33:01 -07:00
. perpCreateMarket (
perpMarketIndex ,
name ,
2022-11-09 04:25:53 -08:00
oracleConfig ,
2022-09-21 00:42:45 -07:00
baseDecimals ,
2022-05-11 04:33:01 -07:00
new BN ( quoteLotSize ) ,
new BN ( baseLotSize ) ,
2023-01-16 07:49:09 -08:00
maintBaseAssetWeight ,
initBaseAssetWeight ,
maintBaseLiabWeight ,
initBaseLiabWeight ,
2023-02-01 07:15:45 -08:00
maintOverallAssetWeight ,
initOverallAssetWeight ,
2023-02-02 00:00:37 -08:00
baseLiquidationFee ,
2022-05-11 04:33:01 -07:00
makerFee ,
takerFee ,
2022-05-17 06:06:29 -07:00
minFunding ,
maxFunding ,
new BN ( impactQuantity ) ,
2022-09-12 06:25:50 -07:00
groupInsuranceFund ,
2022-09-27 06:13:53 -07:00
feePenalty ,
2022-09-29 03:59:55 -07:00
settleFeeFlat ,
settleFeeAmountThreshold ,
settleFeeFractionLowHealth ,
2022-09-29 05:13:28 -07:00
settleTokenIndex ,
2022-12-02 03:24:11 -08:00
settlePnlLimitFactor ,
new BN ( settlePnlLimitWindowSize ) ,
2023-02-02 00:00:37 -08:00
positivePnlLiquidationFee ,
2022-05-11 04:33:01 -07:00
)
. accounts ( {
group : group.publicKey ,
2022-05-18 08:16:14 -07:00
admin : ( this . program . provider as AnchorProvider ) . wallet . publicKey ,
2022-05-11 04:33:01 -07:00
oracle : oraclePk ,
bids : bids.publicKey ,
asks : asks.publicKey ,
eventQueue : eventQueue.publicKey ,
2022-05-18 08:16:14 -07:00
payer : ( this . program . provider as AnchorProvider ) . wallet . publicKey ,
2022-05-11 04:33:01 -07:00
} )
2023-02-02 05:23:22 -08:00
. instruction ( ) ;
const preInstructions = [
// book sides
SystemProgram . createAccount ( {
programId : this.program.programId ,
space : bookSideSize ,
lamports :
await this . program . provider . connection . getMinimumBalanceForRentExemption (
bookSideSize ,
) ,
fromPubkey : ( this . program . provider as AnchorProvider ) . wallet . publicKey ,
newAccountPubkey : bids.publicKey ,
} ) ,
SystemProgram . createAccount ( {
programId : this.program.programId ,
space : bookSideSize ,
lamports :
await this . program . provider . connection . getMinimumBalanceForRentExemption (
bookSideSize ,
) ,
fromPubkey : ( this . program . provider as AnchorProvider ) . wallet . publicKey ,
newAccountPubkey : asks.publicKey ,
} ) ,
// event queue
SystemProgram . createAccount ( {
programId : this.program.programId ,
space : eventQueueSize ,
lamports :
await this . program . provider . connection . getMinimumBalanceForRentExemption (
eventQueueSize ,
) ,
fromPubkey : ( this . program . provider as AnchorProvider ) . wallet . publicKey ,
newAccountPubkey : eventQueue.publicKey ,
} ) ,
] ;
2023-02-03 04:55:46 -08:00
return await this . sendAndConfirmTransactionForGroup (
group ,
2023-02-02 05:23:22 -08:00
[ . . . preInstructions , ix ] ,
{
additionalSigners : [ bids , asks , eventQueue ] ,
} ,
) ;
2022-05-11 04:33:01 -07:00
}
2022-10-07 04:52:04 -07:00
public async perpEditMarket (
2022-07-05 10:31:47 -07:00
group : Group ,
2022-09-29 06:51:09 -07:00
perpMarketIndex : PerpMarketIndex ,
2023-01-14 05:09:26 -08:00
params : PerpEditParams ,
2023-08-11 10:12:13 -07:00
) : Promise < MangoSignatureStatus > {
2022-09-29 06:51:09 -07:00
const perpMarket = group . getPerpMarketByMarketIndex ( perpMarketIndex ) ;
2022-07-05 10:31:47 -07:00
2023-02-02 05:23:22 -08:00
const ix = await this . program . methods
2022-07-05 10:31:47 -07:00
. perpEditMarket (
2023-01-14 05:09:26 -08:00
params . oracle ,
params . oracleConfig ,
params . baseDecimals ,
2023-01-16 07:49:09 -08:00
params . maintBaseAssetWeight ,
params . initBaseAssetWeight ,
params . maintBaseLiabWeight ,
params . initBaseLiabWeight ,
2023-02-01 07:15:45 -08:00
params . maintOverallAssetWeight ,
params . initOverallAssetWeight ,
2023-02-02 00:00:37 -08:00
params . baseLiquidationFee ,
2023-01-14 05:09:26 -08:00
params . makerFee ,
params . takerFee ,
params . minFunding ,
params . maxFunding ,
params . impactQuantity !== null ? new BN ( params . impactQuantity ) : null ,
params . groupInsuranceFund ,
params . feePenalty ,
params . settleFeeFlat ,
params . settleFeeAmountThreshold ,
params . settleFeeFractionLowHealth ,
params . stablePriceDelayIntervalSeconds ,
params . stablePriceDelayGrowthLimit ,
params . stablePriceGrowthLimit ,
params . settlePnlLimitFactor ,
params . settlePnlLimitWindowSize !== null
? new BN ( params . settlePnlLimitWindowSize )
2022-12-02 03:24:11 -08:00
: null ,
2023-01-14 05:09:26 -08:00
params . reduceOnly ,
2023-01-18 04:27:45 -08:00
params . resetStablePrice ? ? false ,
2023-02-02 00:00:37 -08:00
params . positivePnlLiquidationFee ,
2023-03-03 01:05:12 -08:00
params . name ,
2023-04-19 08:42:01 -07:00
params . forceClose ,
2022-07-05 10:31:47 -07:00
)
. accounts ( {
group : group.publicKey ,
2023-01-14 05:09:26 -08:00
oracle : params.oracle ? ? perpMarket . oracle ,
2022-07-05 10:31:47 -07:00
admin : ( this . program . provider as AnchorProvider ) . wallet . publicKey ,
perpMarket : perpMarket.publicKey ,
} )
2023-02-02 05:23:22 -08:00
. instruction ( ) ;
2023-02-03 04:55:46 -08:00
return await this . sendAndConfirmTransactionForGroup ( group , [ ix ] ) ;
2022-07-05 10:31:47 -07:00
}
2023-04-24 23:12:42 -07:00
public async perpForceClosePosition (
group : Group ,
perpMarketIndex : PerpMarketIndex ,
accountA : MangoAccount ,
accountB : MangoAccount ,
2023-08-11 10:12:13 -07:00
) : Promise < MangoSignatureStatus > {
2023-04-24 23:12:42 -07:00
const perpMarket = group . getPerpMarketByMarketIndex ( perpMarketIndex ) ;
const ix = await this . program . methods
. perpForceClosePosition ( )
. accounts ( {
group : group.publicKey ,
perpMarket : perpMarket.publicKey ,
accountA : accountA.publicKey ,
accountB : accountB.publicKey ,
oracle : perpMarket.oracle ,
} )
. instruction ( ) ;
return await this . sendAndConfirmTransactionForGroup ( group , [ ix ] ) ;
}
2022-10-07 04:52:04 -07:00
public async perpCloseMarket (
2022-06-09 09:27:31 -07:00
group : Group ,
2022-09-29 06:51:09 -07:00
perpMarketIndex : PerpMarketIndex ,
2023-08-11 10:12:13 -07:00
) : Promise < MangoSignatureStatus > {
2022-09-29 06:51:09 -07:00
const perpMarket = group . getPerpMarketByMarketIndex ( perpMarketIndex ) ;
2022-06-09 09:27:31 -07:00
2023-02-02 05:23:22 -08:00
const ix = await this . program . methods
2022-06-09 09:27:31 -07:00
. perpCloseMarket ( )
. accounts ( {
group : group.publicKey ,
admin : ( this . program . provider as AnchorProvider ) . wallet . publicKey ,
perpMarket : perpMarket.publicKey ,
bids : perpMarket.bids ,
2022-12-07 12:03:28 -08:00
asks : perpMarket.asks ,
2022-06-09 09:27:31 -07:00
eventQueue : perpMarket.eventQueue ,
solDestination : ( this . program . provider as AnchorProvider ) . wallet
. publicKey ,
} )
2023-02-02 05:23:22 -08:00
. instruction ( ) ;
2023-02-03 04:55:46 -08:00
return await this . sendAndConfirmTransactionForGroup ( group , [ ix ] ) ;
2022-06-09 09:27:31 -07:00
}
2022-09-21 00:42:45 -07:00
public async perpGetMarkets ( group : Group ) : Promise < PerpMarket [ ] > {
2022-05-11 04:33:01 -07:00
const bumpfbuf = Buffer . alloc ( 1 ) ;
bumpfbuf . writeUInt8 ( 255 ) ;
const filters : MemcmpFilter [ ] = [
{
memcmp : {
bytes : group.publicKey.toBase58 ( ) ,
2022-07-06 00:56:14 -07:00
offset : 8 ,
2022-05-11 04:33:01 -07:00
} ,
} ,
] ;
return ( await this . program . account . perpMarket . all ( filters ) ) . map ( ( tuple ) = >
PerpMarket . from ( tuple . publicKey , tuple . account ) ,
) ;
}
2023-01-13 04:19:04 -08:00
public async perpDeactivatePositionIx (
2022-09-15 00:57:48 -07:00
group : Group ,
mangoAccount : MangoAccount ,
2022-09-29 06:51:09 -07:00
perpMarketIndex : PerpMarketIndex ,
2023-01-13 04:19:04 -08:00
) : Promise < TransactionInstruction > {
2022-09-29 06:51:09 -07:00
const perpMarket = group . getPerpMarketByMarketIndex ( perpMarketIndex ) ;
2022-09-15 00:57:48 -07:00
const healthRemainingAccounts : PublicKey [ ] =
2023-04-24 05:48:53 -07:00
this . buildHealthRemainingAccounts ( group , [ mangoAccount ] , [ ] , [ ] ) ;
2022-09-15 00:57:48 -07:00
return await this . program . methods
. perpDeactivatePosition ( )
. accounts ( {
group : group.publicKey ,
account : mangoAccount.publicKey ,
perpMarket : perpMarket.publicKey ,
owner : ( this . program . provider as AnchorProvider ) . wallet . publicKey ,
} )
. remainingAccounts (
healthRemainingAccounts . map (
( pk ) = >
( { pubkey : pk , isWritable : false , isSigner : false } as AccountMeta ) ,
) ,
)
2023-01-13 04:19:04 -08:00
. instruction ( ) ;
}
public async perpDeactivatePosition (
group : Group ,
mangoAccount : MangoAccount ,
perpMarketIndex : PerpMarketIndex ,
2023-08-11 10:12:13 -07:00
) : Promise < MangoSignatureStatus > {
2023-01-13 04:19:04 -08:00
const ix = await this . perpDeactivatePositionIx (
group ,
mangoAccount ,
perpMarketIndex ,
) ;
2023-02-03 04:55:46 -08:00
return await this . sendAndConfirmTransactionForGroup ( group , [ ix ] ) ;
2022-09-15 00:57:48 -07:00
}
2023-07-13 08:10:16 -07:00
public async perpCloseAll (
group : Group ,
mangoAccount : MangoAccount ,
slippage = 0.01 , // 1%, 100bps
2023-08-11 10:12:13 -07:00
) : Promise < MangoSignatureStatus > {
2023-07-13 08:10:16 -07:00
if ( mangoAccount . perpActive ( ) . length == 0 ) {
throw new Error ( ` No perp positions found. ` ) ;
}
if ( mangoAccount . perpActive ( ) . length > 8 ) {
// Technically we can fit in 16, 1.6M CU, 100k CU per ix, but lets be conservative
throw new Error (
` Can't close more than 8 positions in one tx, due to compute usage limit. ` ,
) ;
}
const hrix1 = await this . healthRegionBeginIx ( group , mangoAccount ) ;
const ixs = await Promise . all (
mangoAccount . perpActive ( ) . map ( async ( pa ) = > {
const pm = group . getPerpMarketByMarketIndex ( pa . marketIndex ) ;
const isLong = pa . basePositionLots . gt ( new BN ( 0 ) ) ;
return await this . perpPlaceOrderV2Ix (
group ,
mangoAccount ,
pa . marketIndex ,
isLong ? PerpOrderSide.ask : PerpOrderSide.bid ,
pm . uiPrice * ( isLong ? 1 - slippage : 1 + slippage ) , // Try to cross the spread to guarantee matching
2023-08-27 23:44:13 -07:00
Math . abs ( pa . getBasePositionUi ( pm ) * 1.01 ) , // Send a larger size to ensure full order is closed
2023-07-13 08:10:16 -07:00
undefined ,
Date . now ( ) ,
PerpOrderType . immediateOrCancel ,
PerpSelfTradeBehavior . decrementTake ,
true , // Reduce only
undefined ,
undefined ,
) ;
} ) ,
) ;
const hrix2 = await this . healthRegionEndIx ( group , mangoAccount ) ;
return await this . sendAndConfirmTransactionForGroup (
group ,
[ hrix1 , . . . ixs , hrix2 ] ,
{
prioritizationFee : true ,
} ,
) ;
}
2023-01-25 00:03:35 -08:00
// perpPlaceOrder ix returns an optional, custom order id,
// but, since we use a customer tx sender, this method
// doesn't return it
2022-10-07 04:52:04 -07:00
public async perpPlaceOrder (
2022-05-11 04:33:01 -07:00
group : Group ,
mangoAccount : MangoAccount ,
2022-09-29 06:51:09 -07:00
perpMarketIndex : PerpMarketIndex ,
2022-09-23 02:43:26 -07:00
side : PerpOrderSide ,
2022-06-02 10:30:39 -07:00
price : number ,
quantity : number ,
2022-11-21 10:34:41 -08:00
maxQuoteQuantity? : number ,
clientOrderId? : number ,
orderType? : PerpOrderType ,
reduceOnly? : boolean ,
expiryTimestamp? : number ,
limit? : number ,
2023-08-11 10:12:13 -07:00
) : Promise < MangoSignatureStatus > {
2023-06-15 23:05:16 -07:00
const ix = await this . perpPlaceOrderV2Ix (
2023-01-02 12:35:39 -08:00
group ,
mangoAccount ,
perpMarketIndex ,
side ,
price ,
quantity ,
maxQuoteQuantity ,
clientOrderId ,
orderType ,
2023-06-15 23:05:16 -07:00
PerpSelfTradeBehavior . decrementTake ,
2023-01-02 12:35:39 -08:00
reduceOnly ,
expiryTimestamp ,
limit ,
) ;
2023-02-03 04:55:46 -08:00
return await this . sendAndConfirmTransactionForGroup ( group , [ ix ] ) ;
2022-10-07 04:52:04 -07:00
}
public async perpPlaceOrderIx (
group : Group ,
mangoAccount : MangoAccount ,
perpMarketIndex : PerpMarketIndex ,
side : PerpOrderSide ,
price : number ,
quantity : number ,
maxQuoteQuantity? : number ,
clientOrderId? : number ,
orderType? : PerpOrderType ,
2022-11-09 00:59:34 -08:00
reduceOnly? : boolean ,
2022-10-07 04:52:04 -07:00
expiryTimestamp? : number ,
limit? : number ,
) : Promise < TransactionInstruction > {
2022-09-29 06:51:09 -07:00
const perpMarket = group . getPerpMarketByMarketIndex ( perpMarketIndex ) ;
2022-06-02 10:30:39 -07:00
const healthRemainingAccounts : PublicKey [ ] =
2022-08-31 02:36:44 -07:00
this . buildHealthRemainingAccounts (
group ,
[ mangoAccount ] ,
2022-09-21 03:50:10 -07:00
// Settlement token bank, because a position for it may be created
2023-02-28 03:05:02 -08:00
[ group . getFirstBankForPerpSettlement ( ) ] ,
2022-08-31 02:36:44 -07:00
[ perpMarket ] ,
) ;
2022-10-07 04:52:04 -07:00
return await this . program . methods
2022-05-11 04:33:01 -07:00
. perpPlaceOrder (
side ,
2022-09-20 03:57:01 -07:00
perpMarket . uiPriceToLots ( price ) ,
perpMarket . uiBaseToLots ( quantity ) ,
maxQuoteQuantity
? perpMarket . uiQuoteToLots ( maxQuoteQuantity )
: I64_MAX_BN ,
2022-10-07 04:52:04 -07:00
new BN ( clientOrderId ? clientOrderId : Date.now ( ) ) ,
orderType ? orderType : PerpOrderType.limit ,
2022-11-09 00:59:34 -08:00
reduceOnly ? reduceOnly : false ,
2022-10-07 04:52:04 -07:00
new BN ( expiryTimestamp ? expiryTimestamp : 0 ) ,
limit ? limit : 10 ,
2022-05-11 04:33:01 -07:00
)
. accounts ( {
group : group.publicKey ,
account : mangoAccount.publicKey ,
perpMarket : perpMarket.publicKey ,
2022-12-07 12:03:28 -08:00
bids : perpMarket.bids ,
2022-05-11 04:33:01 -07:00
asks : perpMarket.asks ,
2022-11-21 10:34:41 -08:00
eventQueue : perpMarket.eventQueue ,
oracle : perpMarket.oracle ,
owner : ( this . program . provider as AnchorProvider ) . wallet . publicKey ,
} )
. remainingAccounts (
healthRemainingAccounts . map (
( pk ) = >
( { pubkey : pk , isWritable : false , isSigner : false } as AccountMeta ) ,
) ,
)
. instruction ( ) ;
}
2023-06-15 23:05:16 -07:00
public async perpPlaceOrderV2Ix (
group : Group ,
mangoAccount : MangoAccount ,
perpMarketIndex : PerpMarketIndex ,
side : PerpOrderSide ,
price : number ,
quantity : number ,
maxQuoteQuantity? : number ,
clientOrderId? : number ,
orderType? : PerpOrderType ,
selfTradeBehavior? : PerpSelfTradeBehavior ,
reduceOnly? : boolean ,
expiryTimestamp? : number ,
limit? : number ,
) : Promise < TransactionInstruction > {
const perpMarket = group . getPerpMarketByMarketIndex ( perpMarketIndex ) ;
const healthRemainingAccounts : PublicKey [ ] =
this . buildHealthRemainingAccounts (
group ,
[ mangoAccount ] ,
// Settlement token bank, because a position for it may be created
[ group . getFirstBankForPerpSettlement ( ) ] ,
[ perpMarket ] ,
) ;
return await this . program . methods
. perpPlaceOrderV2 (
side ,
perpMarket . uiPriceToLots ( price ) ,
perpMarket . uiBaseToLots ( quantity ) ,
maxQuoteQuantity
? perpMarket . uiQuoteToLots ( maxQuoteQuantity )
: I64_MAX_BN ,
new BN ( clientOrderId ? clientOrderId : Date.now ( ) ) ,
orderType ? ? PerpOrderType . limit ,
selfTradeBehavior ? ? PerpSelfTradeBehavior . decrementTake ,
reduceOnly ? ? false ,
new BN ( expiryTimestamp ? expiryTimestamp : 0 ) ,
limit ? ? 10 ,
)
. accounts ( {
group : group.publicKey ,
account : mangoAccount.publicKey ,
perpMarket : perpMarket.publicKey ,
bids : perpMarket.bids ,
asks : perpMarket.asks ,
eventQueue : perpMarket.eventQueue ,
oracle : perpMarket.oracle ,
owner : ( this . program . provider as AnchorProvider ) . wallet . publicKey ,
} )
. remainingAccounts (
healthRemainingAccounts . map (
( pk ) = >
( { pubkey : pk , isWritable : false , isSigner : false } as AccountMeta ) ,
) ,
)
. instruction ( ) ;
}
2022-11-21 10:34:41 -08:00
public async perpPlaceOrderPegged (
group : Group ,
mangoAccount : MangoAccount ,
perpMarketIndex : PerpMarketIndex ,
side : PerpOrderSide ,
priceOffset : number ,
quantity : number ,
2023-03-21 15:01:15 -07:00
pegLimit? : number ,
2022-11-21 10:34:41 -08:00
maxQuoteQuantity? : number ,
clientOrderId? : number ,
orderType? : PerpOrderType ,
reduceOnly? : boolean ,
expiryTimestamp? : number ,
limit? : number ,
2023-08-11 10:12:13 -07:00
) : Promise < MangoSignatureStatus > {
2023-06-15 23:10:52 -07:00
const ix = await this . perpPlaceOrderPeggedV2Ix (
2023-01-02 12:35:39 -08:00
group ,
mangoAccount ,
perpMarketIndex ,
side ,
priceOffset ,
quantity ,
2023-03-21 15:01:15 -07:00
pegLimit ,
2023-01-02 12:35:39 -08:00
maxQuoteQuantity ,
clientOrderId ,
orderType ,
2023-06-15 23:05:16 -07:00
PerpSelfTradeBehavior . decrementTake ,
2023-01-02 12:35:39 -08:00
reduceOnly ,
expiryTimestamp ,
limit ,
) ;
2023-02-03 04:55:46 -08:00
return await this . sendAndConfirmTransactionForGroup ( group , [ ix ] ) ;
2022-11-21 10:34:41 -08:00
}
public async perpPlaceOrderPeggedIx (
group : Group ,
mangoAccount : MangoAccount ,
perpMarketIndex : PerpMarketIndex ,
side : PerpOrderSide ,
priceOffset : number ,
quantity : number ,
2023-03-21 15:01:15 -07:00
pegLimit? : number ,
2022-11-21 10:34:41 -08:00
maxQuoteQuantity? : number ,
clientOrderId? : number ,
orderType? : PerpOrderType ,
reduceOnly? : boolean ,
expiryTimestamp? : number ,
limit? : number ,
) : Promise < TransactionInstruction > {
const perpMarket = group . getPerpMarketByMarketIndex ( perpMarketIndex ) ;
const healthRemainingAccounts : PublicKey [ ] =
this . buildHealthRemainingAccounts (
group ,
[ mangoAccount ] ,
// Settlement token bank, because a position for it may be created
2023-02-28 03:05:02 -08:00
[ group . getFirstBankForPerpSettlement ( ) ] ,
2022-11-21 10:34:41 -08:00
[ perpMarket ] ,
) ;
return await this . program . methods
. perpPlaceOrderPegged (
side ,
perpMarket . uiPriceToLots ( priceOffset ) ,
2023-03-21 15:01:15 -07:00
pegLimit ? perpMarket . uiPriceToLots ( pegLimit ) : new BN ( - 1 ) ,
2022-11-21 10:34:41 -08:00
perpMarket . uiBaseToLots ( quantity ) ,
maxQuoteQuantity
? perpMarket . uiQuoteToLots ( maxQuoteQuantity )
: I64_MAX_BN ,
new BN ( clientOrderId ? ? Date . now ( ) ) ,
orderType ? orderType : PerpOrderType.limit ,
reduceOnly ? reduceOnly : false ,
2022-12-02 06:48:43 -08:00
new BN ( expiryTimestamp ? ? 0 ) ,
2022-11-21 10:34:41 -08:00
limit ? limit : 10 ,
2022-12-01 01:43:47 -08:00
- 1 ,
2022-11-21 10:34:41 -08:00
)
. accounts ( {
group : group.publicKey ,
account : mangoAccount.publicKey ,
perpMarket : perpMarket.publicKey ,
2022-05-11 04:33:01 -07:00
bids : perpMarket.bids ,
2022-12-07 12:03:28 -08:00
asks : perpMarket.asks ,
2023-06-15 23:05:16 -07:00
eventQueue : perpMarket.eventQueue ,
oracle : perpMarket.oracle ,
owner : ( this . program . provider as AnchorProvider ) . wallet . publicKey ,
} )
. remainingAccounts (
healthRemainingAccounts . map (
( pk ) = >
( { pubkey : pk , isWritable : false , isSigner : false } as AccountMeta ) ,
) ,
)
. instruction ( ) ;
}
2023-06-15 23:10:07 -07:00
public async perpPlaceOrderPeggedV2Ix (
2023-06-15 23:05:16 -07:00
group : Group ,
mangoAccount : MangoAccount ,
perpMarketIndex : PerpMarketIndex ,
side : PerpOrderSide ,
priceOffset : number ,
quantity : number ,
pegLimit? : number ,
maxQuoteQuantity? : number ,
clientOrderId? : number ,
orderType? : PerpOrderType ,
selfTradeBehavior? : PerpSelfTradeBehavior ,
reduceOnly? : boolean ,
expiryTimestamp? : number ,
limit? : number ,
) : Promise < TransactionInstruction > {
const perpMarket = group . getPerpMarketByMarketIndex ( perpMarketIndex ) ;
const healthRemainingAccounts : PublicKey [ ] =
this . buildHealthRemainingAccounts (
group ,
[ mangoAccount ] ,
// Settlement token bank, because a position for it may be created
[ group . getFirstBankForPerpSettlement ( ) ] ,
[ perpMarket ] ,
) ;
return await this . program . methods
. perpPlaceOrderPeggedV2 (
side ,
perpMarket . uiPriceToLots ( priceOffset ) ,
pegLimit ? perpMarket . uiPriceToLots ( pegLimit ) : new BN ( - 1 ) ,
perpMarket . uiBaseToLots ( quantity ) ,
maxQuoteQuantity
? perpMarket . uiQuoteToLots ( maxQuoteQuantity )
: I64_MAX_BN ,
new BN ( clientOrderId ? ? Date . now ( ) ) ,
orderType ? ? PerpOrderType . limit ,
selfTradeBehavior ? ? PerpSelfTradeBehavior . decrementTake ,
reduceOnly ? ? false ,
new BN ( expiryTimestamp ? ? 0 ) ,
limit ? ? 10 ,
- 1 ,
)
. accounts ( {
group : group.publicKey ,
account : mangoAccount.publicKey ,
perpMarket : perpMarket.publicKey ,
bids : perpMarket.bids ,
asks : perpMarket.asks ,
2022-05-11 04:33:01 -07:00
eventQueue : perpMarket.eventQueue ,
oracle : perpMarket.oracle ,
2022-05-18 08:16:14 -07:00
owner : ( this . program . provider as AnchorProvider ) . wallet . publicKey ,
2022-05-11 04:33:01 -07:00
} )
2022-06-02 10:30:39 -07:00
. remainingAccounts (
healthRemainingAccounts . map (
( pk ) = >
( { pubkey : pk , isWritable : false , isSigner : false } as AccountMeta ) ,
) ,
)
2022-09-27 06:13:53 -07:00
. instruction ( ) ;
2022-10-07 04:52:04 -07:00
}
2022-09-27 06:13:53 -07:00
2023-08-29 22:21:03 -07:00
public async perpCancelOrderByClientOrderIdIx (
group : Group ,
mangoAccount : MangoAccount ,
perpMarketIndex : PerpMarketIndex ,
clientOrderId : BN ,
) : Promise < TransactionInstruction > {
const perpMarket = group . getPerpMarketByMarketIndex ( perpMarketIndex ) ;
return await this . program . methods
. perpCancelOrderByClientOrderId ( new BN ( clientOrderId ) )
. accounts ( {
group : group.publicKey ,
account : mangoAccount.publicKey ,
owner : ( this . program . provider as AnchorProvider ) . wallet . publicKey ,
perpMarket : perpMarket.publicKey ,
bids : perpMarket.bids ,
asks : perpMarket.asks ,
} )
. instruction ( ) ;
}
2022-11-01 10:19:19 -07:00
public async perpCancelOrderIx (
group : Group ,
mangoAccount : MangoAccount ,
perpMarketIndex : PerpMarketIndex ,
2022-11-01 10:37:21 -07:00
orderId : BN ,
2022-11-01 10:19:19 -07:00
) : Promise < TransactionInstruction > {
const perpMarket = group . getPerpMarketByMarketIndex ( perpMarketIndex ) ;
return await this . program . methods
. perpCancelOrder ( new BN ( orderId ) )
. accounts ( {
group : group.publicKey ,
account : mangoAccount.publicKey ,
owner : ( this . program . provider as AnchorProvider ) . wallet . publicKey ,
perpMarket : perpMarket.publicKey ,
bids : perpMarket.bids ,
2022-12-07 12:03:28 -08:00
asks : perpMarket.asks ,
2022-11-01 10:19:19 -07:00
} )
. instruction ( ) ;
}
public async perpCancelOrder (
group : Group ,
mangoAccount : MangoAccount ,
perpMarketIndex : PerpMarketIndex ,
2022-11-01 10:37:21 -07:00
orderId : BN ,
2023-08-11 10:12:13 -07:00
) : Promise < MangoSignatureStatus > {
2023-01-02 12:35:39 -08:00
const ix = await this . perpCancelOrderIx (
group ,
mangoAccount ,
perpMarketIndex ,
orderId ,
) ;
2023-02-03 04:55:46 -08:00
return await this . sendAndConfirmTransactionForGroup ( group , [ ix ] ) ;
2022-11-01 10:19:19 -07:00
}
2022-10-07 04:52:04 -07:00
public async perpCancelAllOrders (
group : Group ,
mangoAccount : MangoAccount ,
perpMarketIndex : PerpMarketIndex ,
limit : number ,
2023-08-11 10:12:13 -07:00
) : Promise < MangoSignatureStatus > {
2023-01-02 12:35:39 -08:00
const ix = await this . perpCancelAllOrdersIx (
group ,
mangoAccount ,
perpMarketIndex ,
limit ,
) ;
2023-02-03 04:55:46 -08:00
return await this . sendAndConfirmTransactionForGroup ( group , [ ix ] ) ;
2022-05-11 04:33:01 -07:00
}
2022-10-07 04:52:04 -07:00
public async perpCancelAllOrdersIx (
2022-09-20 03:57:01 -07:00
group : Group ,
mangoAccount : MangoAccount ,
2022-09-29 06:51:09 -07:00
perpMarketIndex : PerpMarketIndex ,
2022-09-20 03:57:01 -07:00
limit : number ,
2022-10-07 04:52:04 -07:00
) : Promise < TransactionInstruction > {
2022-09-29 06:51:09 -07:00
const perpMarket = group . getPerpMarketByMarketIndex ( perpMarketIndex ) ;
2022-10-07 04:52:04 -07:00
return await this . program . methods
2022-09-20 03:57:01 -07:00
. perpCancelAllOrders ( limit )
. accounts ( {
group : group.publicKey ,
account : mangoAccount.publicKey ,
perpMarket : perpMarket.publicKey ,
bids : perpMarket.bids ,
2022-12-07 12:03:28 -08:00
asks : perpMarket.asks ,
2022-09-20 03:57:01 -07:00
owner : ( this . program . provider as AnchorProvider ) . wallet . publicKey ,
} )
2022-09-27 06:13:53 -07:00
. instruction ( ) ;
2022-09-20 03:57:01 -07:00
}
2023-07-14 04:19:17 -07:00
async settleAll (
2023-07-13 08:10:16 -07:00
client : MangoClient ,
group : Group ,
mangoAccount : MangoAccount ,
allMangoAccounts? : MangoAccount [ ] ,
2023-08-11 10:12:13 -07:00
) : Promise < MangoSignatureStatus > {
2023-07-13 08:10:16 -07:00
if ( ! allMangoAccounts ) {
allMangoAccounts = await client . getAllMangoAccounts ( group , true ) ;
}
2023-07-14 04:19:17 -07:00
const ixs1 = new Array < TransactionInstruction > ( ) ;
2023-07-13 08:10:16 -07:00
// This is optimistic, since we might find the same opponent candidate for all markets,
// and they have might not be able to settle at some point due to safety limits
// Future: correct way to do is, to apply the settlement on a copy and then move to next position
for ( const pa of mangoAccount . perpActive ( ) ) {
const pm = group . getPerpMarketByMarketIndex ( pa . marketIndex ) ;
const candidates = await pm . getSettlePnlCandidates (
client ,
group ,
allMangoAccounts ,
pa . getUnsettledPnlUi ( pm ) > 0 ? 'negative' : 'positive' ,
2 ,
) ;
if ( candidates . length == 0 ) {
continue ;
}
2023-07-14 04:19:17 -07:00
ixs1 . push (
2023-09-19 22:08:23 -07:00
// Takes ~250k CU
2023-07-13 08:10:16 -07:00
await this . perpSettlePnlIx (
group ,
pa . getUnsettledPnlUi ( pm ) > 0 ? mangoAccount : candidates [ 0 ] . account ,
pa . getUnsettledPnlUi ( pm ) < 0 ? candidates [ 0 ] . account : mangoAccount ,
mangoAccount ,
pm . perpMarketIndex ,
) ,
) ;
2023-07-14 04:19:17 -07:00
ixs1 . push (
// Takes ~20k CU
2023-07-13 08:10:16 -07:00
await this . perpSettleFeesIx (
group ,
mangoAccount ,
pm . perpMarketIndex ,
undefined ,
) ,
) ;
}
2023-07-14 04:19:17 -07:00
const ixs2 = await Promise . all (
mangoAccount . serum3Active ( ) . map ( ( s ) = > {
const serum3Market = group . getSerum3MarketByMarketIndex ( s . marketIndex ) ;
// Takes ~65k CU
return this . serum3SettleFundsV2Ix (
group ,
mangoAccount ,
serum3Market . serumMarketExternal ,
) ;
} ) ,
) ;
if (
2023-09-19 22:08:23 -07:00
mangoAccount . perpActive ( ) . length *
( PERP_SETTLE_PNL_CU_LIMIT + PERP_SETTLE_FEES_CU_LIMIT ) +
mangoAccount . serum3Active ( ) . length * SERUM_SETTLE_FUNDS_CU_LIMIT >
1600000
2023-07-14 04:19:17 -07:00
) {
throw new Error (
` Too many perp positions and serum open orders to settle in one tx! Please try settling individually! ` ,
) ;
}
return await this . sendAndConfirmTransactionForGroup (
group ,
2023-09-19 22:08:23 -07:00
[
ComputeBudgetProgram . setComputeUnitLimit ( {
units :
mangoAccount . perpActive ( ) . length *
( PERP_SETTLE_PNL_CU_LIMIT + PERP_SETTLE_FEES_CU_LIMIT ) +
mangoAccount . serum3Active ( ) . length * SERUM_SETTLE_FUNDS_CU_LIMIT ,
} ) ,
. . . ixs1 ,
. . . ixs2 ,
] ,
2023-07-14 04:19:17 -07:00
{
prioritizationFee : true ,
} ,
) ;
2023-07-13 08:10:16 -07:00
}
2023-03-30 01:30:15 -07:00
async perpSettlePnlAndFees (
group : Group ,
profitableAccount : MangoAccount ,
unprofitableAccount : MangoAccount ,
accountToSettleFeesFor : MangoAccount ,
settler : MangoAccount ,
perpMarketIndex : PerpMarketIndex ,
maxSettleAmount? : number ,
2023-08-11 10:12:13 -07:00
) : Promise < MangoSignatureStatus > {
2023-03-30 01:30:15 -07:00
return await this . sendAndConfirmTransactionForGroup ( group , [
2023-09-19 22:08:23 -07:00
ComputeBudgetProgram . setComputeUnitLimit ( {
units : PERP_SETTLE_PNL_CU_LIMIT + PERP_SETTLE_FEES_CU_LIMIT ,
} ) ,
2023-03-30 01:30:15 -07:00
await this . perpSettlePnlIx (
group ,
profitableAccount ,
unprofitableAccount ,
settler ,
perpMarketIndex ,
) ,
await this . perpSettleFeesIx (
group ,
accountToSettleFeesFor ,
perpMarketIndex ,
maxSettleAmount ,
) ,
] ) ;
}
2022-10-08 03:48:13 -07:00
async perpSettlePnl (
group : Group ,
profitableAccount : MangoAccount ,
unprofitableAccount : MangoAccount ,
settler : MangoAccount ,
perpMarketIndex : PerpMarketIndex ,
2023-08-11 10:12:13 -07:00
) : Promise < MangoSignatureStatus > {
2023-03-30 01:19:00 -07:00
return await this . sendAndConfirmTransactionForGroup ( group , [
2023-09-19 22:08:23 -07:00
ComputeBudgetProgram . setComputeUnitLimit ( {
units : PERP_SETTLE_PNL_CU_LIMIT ,
} ) ,
2023-03-30 01:19:00 -07:00
await this . perpSettlePnlIx (
group ,
profitableAccount ,
unprofitableAccount ,
settler ,
perpMarketIndex ,
) ,
] ) ;
}
async perpSettlePnlIx (
group : Group ,
profitableAccount : MangoAccount ,
unprofitableAccount : MangoAccount ,
settler : MangoAccount ,
perpMarketIndex : PerpMarketIndex ,
) : Promise < TransactionInstruction > {
2022-10-08 03:48:13 -07:00
const perpMarket = group . getPerpMarketByMarketIndex ( perpMarketIndex ) ;
const healthRemainingAccounts : PublicKey [ ] =
this . buildHealthRemainingAccounts (
group ,
[ profitableAccount , unprofitableAccount ] ,
2023-02-28 03:05:02 -08:00
[ group . getFirstBankForPerpSettlement ( ) ] ,
2022-10-08 03:48:13 -07:00
[ perpMarket ] ,
) ;
2022-10-18 12:10:20 -07:00
const bank = group . banksMapByTokenIndex . get ( 0 as TokenIndex ) ! [ 0 ] ;
2023-03-30 01:19:00 -07:00
return await this . program . methods
2022-10-08 03:48:13 -07:00
. perpSettlePnl ( )
. accounts ( {
group : group.publicKey ,
accountA : profitableAccount.publicKey ,
accountB : unprofitableAccount.publicKey ,
perpMarket : perpMarket.publicKey ,
oracle : perpMarket.oracle ,
settleOracle : bank.oracle ,
settleBank : bank.publicKey ,
settler : settler.publicKey ,
2022-12-07 20:50:37 -08:00
settlerOwner : ( this . program . provider as AnchorProvider ) . wallet
. publicKey ,
2022-10-08 03:48:13 -07:00
} )
. remainingAccounts (
healthRemainingAccounts . map (
( pk ) = >
( { pubkey : pk , isWritable : false , isSigner : false } as AccountMeta ) ,
) ,
)
. instruction ( ) ;
}
async perpSettleFees (
group : Group ,
account : MangoAccount ,
perpMarketIndex : PerpMarketIndex ,
2023-03-30 01:19:00 -07:00
maxSettleAmount? : number ,
2023-08-11 10:12:13 -07:00
) : Promise < MangoSignatureStatus > {
2023-03-30 01:19:00 -07:00
return await this . sendAndConfirmTransactionForGroup ( group , [
await this . perpSettleFeesIx (
group ,
account ,
perpMarketIndex ,
maxSettleAmount ,
) ,
] ) ;
}
async perpSettleFeesIx (
group : Group ,
account : MangoAccount ,
perpMarketIndex : PerpMarketIndex ,
maxSettleAmount? : number ,
) : Promise < TransactionInstruction > {
2022-10-08 03:48:13 -07:00
const perpMarket = group . getPerpMarketByMarketIndex ( perpMarketIndex ) ;
const healthRemainingAccounts : PublicKey [ ] =
this . buildHealthRemainingAccounts (
group ,
[ account ] , // Account must be unprofitable
2023-02-28 03:05:02 -08:00
[ group . getFirstBankForPerpSettlement ( ) ] ,
2022-10-08 03:48:13 -07:00
[ perpMarket ] ,
) ;
2022-10-18 12:10:20 -07:00
const bank = group . banksMapByTokenIndex . get ( 0 as TokenIndex ) ! [ 0 ] ;
2023-03-30 01:19:00 -07:00
return await this . program . methods
. perpSettleFees (
maxSettleAmount ? toNative ( maxSettleAmount , 6 ) : RUST_U64_MAX ( ) ,
)
2022-10-08 03:48:13 -07:00
. accounts ( {
group : group.publicKey ,
account : account.publicKey ,
perpMarket : perpMarket.publicKey ,
oracle : perpMarket.oracle ,
settleOracle : bank.oracle ,
settleBank : bank.publicKey ,
} )
. remainingAccounts (
healthRemainingAccounts . map (
( pk ) = >
( { pubkey : pk , isWritable : false , isSigner : false } as AccountMeta ) ,
) ,
)
. instruction ( ) ;
}
2022-10-07 04:52:04 -07:00
public async perpConsumeEvents (
2022-09-15 00:57:48 -07:00
group : Group ,
2022-09-29 06:51:09 -07:00
perpMarketIndex : PerpMarketIndex ,
2022-09-15 00:57:48 -07:00
accounts : PublicKey [ ] ,
limit : number ,
2023-08-11 10:12:13 -07:00
) : Promise < MangoSignatureStatus > {
2023-04-19 08:42:13 -07:00
return await this . sendAndConfirmTransactionForGroup ( group , [
await this . perpConsumeEventsIx ( group , perpMarketIndex , accounts , limit ) ,
] ) ;
}
public async perpConsumeEventsIx (
group : Group ,
perpMarketIndex : PerpMarketIndex ,
accounts : PublicKey [ ] ,
limit : number ,
) : Promise < TransactionInstruction > {
2022-09-29 06:51:09 -07:00
const perpMarket = group . getPerpMarketByMarketIndex ( perpMarketIndex ) ;
2023-04-19 08:42:13 -07:00
return await this . program . methods
2022-09-15 00:57:48 -07:00
. perpConsumeEvents ( new BN ( limit ) )
. accounts ( {
group : group.publicKey ,
perpMarket : perpMarket.publicKey ,
eventQueue : perpMarket.eventQueue ,
} )
. remainingAccounts (
accounts . map (
( pk ) = >
( { pubkey : pk , isWritable : true , isSigner : false } as AccountMeta ) ,
) ,
)
2023-02-02 05:23:22 -08:00
. instruction ( ) ;
2022-09-20 03:57:01 -07:00
}
2022-10-07 04:52:04 -07:00
public async perpConsumeAllEvents (
2022-09-15 00:57:48 -07:00
group : Group ,
2022-09-29 06:51:09 -07:00
perpMarketIndex : PerpMarketIndex ,
2022-09-15 00:57:48 -07:00
) : Promise < void > {
const limit = 8 ;
2022-09-29 06:51:09 -07:00
const perpMarket = group . getPerpMarketByMarketIndex ( perpMarketIndex ) ;
2022-09-15 00:57:48 -07:00
const eventQueue = await perpMarket . loadEventQueue ( this ) ;
2022-09-27 06:13:53 -07:00
const unconsumedEvents = eventQueue . getUnconsumedEvents ( ) ;
2022-09-15 00:57:48 -07:00
while ( unconsumedEvents . length > 0 ) {
const events = unconsumedEvents . splice ( 0 , limit ) ;
const accounts = events
. map ( ( ev ) = > {
switch ( ev . eventType ) {
2022-09-27 06:13:53 -07:00
case PerpEventQueue . FILL_EVENT_TYPE : {
2022-09-15 00:57:48 -07:00
const fill = < FillEvent > ev ;
return [ fill . maker , fill . taker ] ;
2022-09-27 06:13:53 -07:00
}
case PerpEventQueue . OUT_EVENT_TYPE : {
2022-09-15 00:57:48 -07:00
const out = < OutEvent > ev ;
return [ out . owner ] ;
2022-09-27 06:13:53 -07:00
}
2022-09-15 00:57:48 -07:00
case PerpEventQueue . LIQUIDATE_EVENT_TYPE :
return [ ] ;
default :
2022-09-29 06:51:09 -07:00
throw new Error ( ` Unknown event with eventType ${ ev . eventType } ! ` ) ;
2022-09-15 00:57:48 -07:00
}
} )
. flat ( ) ;
2022-09-29 06:51:09 -07:00
await this . perpConsumeEvents ( group , perpMarketIndex , accounts , limit ) ;
2022-09-15 00:57:48 -07:00
}
}
2023-03-30 12:05:36 -07:00
public async perpUpdateFundingIx (
group : Group ,
perpMarket : PerpMarket ,
) : Promise < TransactionInstruction > {
return await this . program . methods
. perpUpdateFunding ( )
. accounts ( {
group : group.publicKey ,
perpMarket : perpMarket.publicKey ,
bids : perpMarket.bids ,
asks : perpMarket.asks ,
oracle : perpMarket.oracle ,
} )
. instruction ( ) ;
}
2022-05-24 11:10:01 -07:00
public async marginTrade ( {
group ,
mangoAccount ,
2022-08-17 23:48:45 -07:00
inputMintPk ,
2022-05-24 11:10:01 -07:00
amountIn ,
2022-08-17 23:48:45 -07:00
outputMintPk ,
2022-07-05 20:38:53 -07:00
userDefinedInstructions ,
2022-12-15 14:22:10 -08:00
userDefinedAlts = [ ] ,
2022-08-17 03:36:55 -07:00
// margin trade is a general function
// set flash_loan_type to FlashLoanType.swap if you desire the transaction to be recorded as a swap
flashLoanType ,
2022-05-24 11:10:01 -07:00
} : {
group : Group ;
mangoAccount : MangoAccount ;
2022-08-17 23:48:45 -07:00
inputMintPk : PublicKey ;
2022-05-24 11:10:01 -07:00
amountIn : number ;
2022-08-17 23:48:45 -07:00
outputMintPk : PublicKey ;
2022-07-05 20:38:53 -07:00
userDefinedInstructions : TransactionInstruction [ ] ;
2022-12-15 14:22:10 -08:00
userDefinedAlts : AddressLookupTableAccount [ ] ;
2022-08-17 03:36:55 -07:00
flashLoanType : FlashLoanType ;
2023-08-11 10:12:13 -07:00
} ) : Promise < MangoSignatureStatus > {
2023-06-16 07:07:09 -07:00
const isDelegate = (
this . program . provider as AnchorProvider
) . wallet . publicKey . equals ( mangoAccount . delegate ) ;
const swapExecutingWallet = isDelegate
? mangoAccount . delegate
: mangoAccount . owner ;
2022-08-17 23:48:45 -07:00
const inputBank : Bank = group . getFirstBankByMint ( inputMintPk ) ;
const outputBank : Bank = group . getFirstBankByMint ( outputMintPk ) ;
2022-05-31 18:38:47 -07:00
2022-05-24 11:10:01 -07:00
const healthRemainingAccounts : PublicKey [ ] =
2022-08-04 00:07:32 -07:00
this . buildHealthRemainingAccounts (
group ,
[ mangoAccount ] ,
[ inputBank , outputBank ] ,
2022-08-31 02:36:44 -07:00
[ ] ,
2022-08-04 00:07:32 -07:00
) ;
2022-06-29 20:36:57 -07:00
const parsedHealthAccounts = healthRemainingAccounts . map (
( pk ) = >
( {
pubkey : pk ,
2022-07-06 21:45:01 -07:00
isWritable : false ,
2022-06-29 20:36:57 -07:00
isSigner : false ,
} as AccountMeta ) ,
) ;
/ *
* Find or create associated token accounts
* /
2022-08-04 10:42:41 -07:00
const inputTokenAccountPk = await getAssociatedTokenAddress (
2022-06-29 20:36:57 -07:00
inputBank . mint ,
2023-06-16 07:07:09 -07:00
swapExecutingWallet ,
2023-07-25 04:35:25 -07:00
true ,
2022-06-29 20:36:57 -07:00
) ;
const inputTokenAccExists =
await this . program . provider . connection . getAccountInfo (
inputTokenAccountPk ,
) ;
2022-08-31 02:41:12 -07:00
const preInstructions : TransactionInstruction [ ] = [ ] ;
2022-06-29 20:36:57 -07:00
if ( ! inputTokenAccExists ) {
preInstructions . push (
2022-08-09 15:27:24 -07:00
await createAssociatedTokenAccountIdempotentInstruction (
2023-06-16 07:07:09 -07:00
swapExecutingWallet ,
swapExecutingWallet ,
2022-06-29 20:36:57 -07:00
inputBank . mint ,
) ,
) ;
}
2022-08-04 10:42:41 -07:00
const outputTokenAccountPk = await getAssociatedTokenAddress (
2022-06-29 20:36:57 -07:00
outputBank . mint ,
2023-06-16 07:07:09 -07:00
swapExecutingWallet ,
2023-07-25 04:35:25 -07:00
true ,
2022-06-29 20:36:57 -07:00
) ;
const outputTokenAccExists =
await this . program . provider . connection . getAccountInfo (
outputTokenAccountPk ,
) ;
if ( ! outputTokenAccExists ) {
preInstructions . push (
2022-08-09 15:27:24 -07:00
await createAssociatedTokenAccountIdempotentInstruction (
2023-06-16 07:07:09 -07:00
swapExecutingWallet ,
swapExecutingWallet ,
2022-06-29 20:36:57 -07:00
outputBank . mint ,
) ,
) ;
}
2022-07-07 10:04:54 -07:00
const inputBankAccount = {
2022-06-29 20:36:57 -07:00
pubkey : inputBank.publicKey ,
2022-07-06 21:45:01 -07:00
isWritable : true ,
2022-06-29 20:36:57 -07:00
isSigner : false ,
} ;
2022-07-07 10:04:54 -07:00
const outputBankAccount = {
2022-07-06 21:45:01 -07:00
pubkey : outputBank.publicKey ,
2022-06-29 20:36:57 -07:00
isWritable : true ,
2022-07-06 21:45:01 -07:00
isSigner : false ,
} ;
2022-07-07 10:04:54 -07:00
const inputBankVault = {
2022-06-29 20:36:57 -07:00
pubkey : inputBank.vault ,
2022-07-06 21:45:01 -07:00
isWritable : true ,
2022-06-29 20:36:57 -07:00
isSigner : false ,
} ;
2022-07-07 10:04:54 -07:00
const outputBankVault = {
2022-07-06 21:45:01 -07:00
pubkey : outputBank.vault ,
2022-06-29 20:36:57 -07:00
isWritable : true ,
2022-07-06 21:45:01 -07:00
isSigner : false ,
} ;
2022-07-07 10:04:54 -07:00
const inputATA = {
2022-06-29 20:36:57 -07:00
pubkey : inputTokenAccountPk ,
2022-07-06 21:45:01 -07:00
isWritable : true ,
isSigner : false ,
} ;
2022-07-07 10:04:54 -07:00
const outputATA = {
2022-07-06 21:45:01 -07:00
pubkey : outputTokenAccountPk ,
isWritable : false ,
isSigner : false ,
2022-06-29 20:36:57 -07:00
} ;
2022-08-16 01:19:15 -07:00
const groupAM = {
pubkey : group.publicKey ,
isWritable : false ,
isSigner : false ,
} ;
2022-06-29 20:36:57 -07:00
const flashLoanEndIx = await this . program . methods
2023-04-14 06:18:02 -07:00
. flashLoanEndV2 ( 2 , flashLoanType )
2022-06-29 20:36:57 -07:00
. accounts ( {
account : mangoAccount.publicKey ,
2023-06-16 07:07:09 -07:00
owner : ( this . program . provider as AnchorProvider ) . wallet . publicKey ,
2022-06-29 20:36:57 -07:00
} )
2022-07-06 21:45:01 -07:00
. remainingAccounts ( [
. . . parsedHealthAccounts ,
2022-07-07 10:04:54 -07:00
inputBankVault ,
outputBankVault ,
inputATA ,
2022-07-06 21:45:01 -07:00
{
isWritable : true ,
pubkey : outputTokenAccountPk ,
isSigner : false ,
} ,
2022-08-16 01:19:15 -07:00
groupAM ,
2022-07-06 21:45:01 -07:00
] )
2022-06-29 20:36:57 -07:00
. instruction ( ) ;
2022-07-07 13:43:19 -07:00
const flashLoanBeginIx = await this . program . methods
2022-08-01 07:55:17 -07:00
. flashLoanBegin ( [
2022-09-30 06:07:43 -07:00
toNative ( amountIn , inputBank . mintDecimals ) ,
2022-07-06 21:45:01 -07:00
new BN (
0 ,
) /* we don't care about borrowing the target amount, this is just a dummy */ ,
] )
2022-06-29 20:36:57 -07:00
. accounts ( {
2022-11-09 00:35:13 -08:00
account : mangoAccount.publicKey ,
owner : ( this . program . provider as AnchorProvider ) . wallet . publicKey ,
2022-07-06 21:45:01 -07:00
instructions : SYSVAR_INSTRUCTIONS_PUBKEY ,
2022-06-29 20:36:57 -07:00
} )
2022-07-06 21:45:01 -07:00
. remainingAccounts ( [
2022-07-07 10:04:54 -07:00
inputBankAccount ,
outputBankAccount ,
inputBankVault ,
outputBankVault ,
inputATA ,
outputATA ,
2022-08-16 01:19:15 -07:00
groupAM ,
2022-07-06 21:45:01 -07:00
] )
. instruction ( ) ;
2023-02-03 04:55:46 -08:00
return await this . sendAndConfirmTransactionForGroup (
group ,
2022-09-27 06:13:53 -07:00
[
. . . preInstructions ,
flashLoanBeginIx ,
. . . userDefinedInstructions . filter ( ( ix ) = > ix . keys . length > 2 ) ,
flashLoanEndIx ,
] ,
2023-02-03 04:55:46 -08:00
{ alts : [ . . . group . addressLookupTablesList , . . . userDefinedAlts ] } ,
2022-09-27 06:13:53 -07:00
) ;
2022-07-06 21:45:01 -07:00
}
2022-08-03 09:05:16 -07:00
2023-04-19 08:42:13 -07:00
public async tokenUpdateIndexAndRate (
2022-09-29 06:51:09 -07:00
group : Group ,
mintPk : PublicKey ,
2023-08-11 10:12:13 -07:00
) : Promise < MangoSignatureStatus > {
2023-04-19 08:42:13 -07:00
return await this . sendAndConfirmTransactionForGroup ( group , [
await this . tokenUpdateIndexAndRateIx ( group , mintPk ) ,
] ) ;
}
public async tokenUpdateIndexAndRateIx (
group : Group ,
mintPk : PublicKey ,
) : Promise < TransactionInstruction > {
2022-08-17 23:48:45 -07:00
const bank = group . getFirstBankByMint ( mintPk ) ;
const mintInfo = group . mintInfosMapByMint . get ( mintPk . toString ( ) ) ! ;
2022-08-07 05:16:06 -07:00
2023-04-19 08:42:13 -07:00
return await this . program . methods
2022-08-07 05:16:06 -07:00
. tokenUpdateIndexAndRate ( )
. accounts ( {
group : group.publicKey ,
mintInfo : mintInfo.publicKey ,
oracle : mintInfo.oracle ,
instructions : SYSVAR_INSTRUCTIONS_PUBKEY ,
} )
2022-08-05 10:11:44 -07:00
. remainingAccounts ( [
{
pubkey : bank.publicKey ,
isWritable : true ,
isSigner : false ,
} as AccountMeta ,
] )
2023-02-02 05:23:22 -08:00
. instruction ( ) ;
2022-08-05 10:11:44 -07:00
}
2022-08-04 00:07:32 -07:00
/// liquidations
2022-10-07 04:52:04 -07:00
public async liqTokenWithToken (
2022-08-04 00:07:32 -07:00
group : Group ,
liqor : MangoAccount ,
liqee : MangoAccount ,
2022-08-17 23:48:45 -07:00
assetMintPk : PublicKey ,
liabMintPk : PublicKey ,
2022-08-04 00:07:32 -07:00
maxLiabTransfer : number ,
2023-08-11 10:12:13 -07:00
) : Promise < MangoSignatureStatus > {
2022-08-17 23:48:45 -07:00
const assetBank : Bank = group . getFirstBankByMint ( assetMintPk ) ;
const liabBank : Bank = group . getFirstBankByMint ( liabMintPk ) ;
2022-08-04 00:07:32 -07:00
const healthRemainingAccounts : PublicKey [ ] =
this . buildHealthRemainingAccounts (
group ,
[ liqor , liqee ] ,
[ assetBank , liabBank ] ,
2022-08-31 02:36:44 -07:00
[ ] ,
2022-08-04 00:07:32 -07:00
) ;
const parsedHealthAccounts = healthRemainingAccounts . map (
( pk ) = >
( {
pubkey : pk ,
isWritable :
pk . equals ( assetBank . publicKey ) || pk . equals ( liabBank . publicKey )
? true
: false ,
isSigner : false ,
} as AccountMeta ) ,
2022-08-03 09:05:16 -07:00
) ;
2022-09-27 06:13:53 -07:00
const ix = await this . program . methods
2022-08-04 00:07:32 -07:00
. liqTokenWithToken ( assetBank . tokenIndex , liabBank . tokenIndex , {
val : I80F48.fromNumber ( maxLiabTransfer ) . getData ( ) ,
} )
. accounts ( {
group : group.publicKey ,
liqor : liqor.publicKey ,
liqee : liqee.publicKey ,
2022-08-04 08:35:05 -07:00
liqorOwner : liqor.owner ,
2022-08-04 00:07:32 -07:00
} )
. remainingAccounts ( parsedHealthAccounts )
2022-09-27 06:13:53 -07:00
. instruction ( ) ;
2023-02-03 04:55:46 -08:00
return await this . sendAndConfirmTransactionForGroup ( group , [ ix ] ) ;
2022-09-27 06:13:53 -07:00
}
2023-08-07 04:09:19 -07:00
public async tcsTakeProfitOnDeposit (
2023-07-27 23:26:34 -07:00
group : Group ,
account : MangoAccount ,
2023-08-07 04:09:19 -07:00
sellBank : Bank ,
buyBank : Bank ,
thresholdPriceUi : number ,
thresholdPriceInSellPerBuyToken : boolean ,
maxSellUi : number | null ,
pricePremium : number | null ,
2023-07-27 23:26:34 -07:00
expiryTimestamp : number | null ,
2023-08-11 10:12:13 -07:00
) : Promise < MangoSignatureStatus > {
2023-08-07 04:09:19 -07:00
if ( account . getTokenBalanceUi ( sellBank ) < 0 ) {
throw new Error (
` Only allowed to take profits on deposits! Current balance ${ account . getTokenBalanceUi (
sellBank ,
) } ` ,
) ;
}
2023-08-11 07:46:19 -07:00
if ( ! thresholdPriceInSellPerBuyToken ) {
thresholdPriceUi = 1 / thresholdPriceUi ;
}
const thresholdPrice = toNativeSellPerBuyTokenPrice (
thresholdPriceUi ,
sellBank ,
buyBank ,
) ;
const lowerLimit = 0 ;
const upperLimit = thresholdPrice ;
2023-08-07 04:09:19 -07:00
return await this . tokenConditionalSwapCreate (
group ,
account ,
sellBank ,
buyBank ,
2023-08-11 07:46:19 -07:00
lowerLimit ,
upperLimit ,
2023-08-07 04:09:19 -07:00
Number . MAX_SAFE_INTEGER ,
maxSellUi ? ? account . getTokenBalanceUi ( sellBank ) ,
'TakeProfitOnDeposit' ,
pricePremium ,
true ,
false ,
expiryTimestamp ,
2023-09-07 03:40:37 -07:00
thresholdPriceInSellPerBuyToken ,
2023-07-28 06:32:50 -07:00
) ;
2023-08-07 04:09:19 -07:00
}
public async tcsStopLossOnDeposit (
group : Group ,
account : MangoAccount ,
sellBank : Bank ,
buyBank : Bank ,
thresholdPriceUi : number ,
thresholdPriceInSellPerBuyToken : boolean ,
maxSellUi : number | null ,
pricePremium : number | null ,
expiryTimestamp : number | null ,
2023-08-11 10:12:13 -07:00
) : Promise < MangoSignatureStatus > {
2023-08-07 04:09:19 -07:00
if ( account . getTokenBalanceUi ( sellBank ) < 0 ) {
throw new Error (
` Only allowed to set a stop loss on deposits! Current balance ${ account . getTokenBalanceUi (
sellBank ,
) } ` ,
) ;
}
2023-08-11 07:46:19 -07:00
if ( ! thresholdPriceInSellPerBuyToken ) {
thresholdPriceUi = 1 / thresholdPriceUi ;
}
const thresholdPrice = toNativeSellPerBuyTokenPrice (
thresholdPriceUi ,
sellBank ,
buyBank ,
) ;
const lowerLimit = thresholdPrice ;
const upperLimit = Number . MAX_SAFE_INTEGER ;
2023-08-07 04:09:19 -07:00
return await this . tokenConditionalSwapCreate (
group ,
account ,
sellBank ,
buyBank ,
2023-08-11 07:46:19 -07:00
lowerLimit ,
upperLimit ,
2023-08-07 04:09:19 -07:00
Number . MAX_SAFE_INTEGER ,
maxSellUi ? ? account . getTokenBalanceUi ( sellBank ) ,
'StopLossOnDeposit' ,
pricePremium ,
true ,
false ,
expiryTimestamp ,
2023-09-07 03:40:37 -07:00
thresholdPriceInSellPerBuyToken ,
2023-08-07 04:09:19 -07:00
) ;
}
public async tcsTakeProfitOnBorrow (
group : Group ,
account : MangoAccount ,
sellBank : Bank ,
buyBank : Bank ,
thresholdPriceUi : number ,
thresholdPriceInSellPerBuyToken : boolean ,
maxBuyUi : number | null ,
pricePremium : number | null ,
allowMargin : boolean | null ,
expiryTimestamp : number | null ,
2023-08-11 10:12:13 -07:00
) : Promise < MangoSignatureStatus > {
2023-08-07 04:09:19 -07:00
if ( account . getTokenBalanceUi ( buyBank ) > 0 ) {
throw new Error (
` Only allowed to take profits on borrows! Current balance ${ account . getTokenBalanceUi (
buyBank ,
) } ` ,
) ;
}
2023-08-11 07:46:19 -07:00
if ( ! thresholdPriceInSellPerBuyToken ) {
thresholdPriceUi = 1 / thresholdPriceUi ;
}
const thresholdPrice = toNativeSellPerBuyTokenPrice (
thresholdPriceUi ,
sellBank ,
buyBank ,
) ;
2023-09-08 04:45:51 -07:00
const lowerLimit = 0 ;
const upperLimit = thresholdPrice ;
2023-08-11 07:46:19 -07:00
2023-08-07 04:09:19 -07:00
return await this . tokenConditionalSwapCreate (
group ,
account ,
sellBank ,
buyBank ,
2023-08-11 07:46:19 -07:00
lowerLimit ,
upperLimit ,
2023-08-07 04:09:19 -07:00
maxBuyUi ? ? - account . getTokenBalanceUi ( buyBank ) ,
Number . MAX_SAFE_INTEGER ,
'TakeProfitOnBorrow' ,
pricePremium ,
false ,
allowMargin ? ? false ,
expiryTimestamp ,
2023-09-07 03:40:37 -07:00
thresholdPriceInSellPerBuyToken ,
2023-08-07 04:09:19 -07:00
) ;
}
public async tcsStopLossOnBorrow (
group : Group ,
account : MangoAccount ,
sellBank : Bank ,
buyBank : Bank ,
thresholdPriceUi : number ,
thresholdPriceInSellPerBuyToken : boolean ,
maxBuyUi : number | null ,
pricePremium : number | null ,
allowMargin : boolean | null ,
expiryTimestamp : number | null ,
2023-08-11 10:12:13 -07:00
) : Promise < MangoSignatureStatus > {
2023-08-07 04:09:19 -07:00
if ( account . getTokenBalanceUi ( buyBank ) > 0 ) {
throw new Error (
` Only allowed to set stop loss on borrows! Current balance ${ account . getTokenBalanceUi (
buyBank ,
) } ` ,
) ;
}
2023-08-11 07:46:19 -07:00
if ( ! thresholdPriceInSellPerBuyToken ) {
thresholdPriceUi = 1 / thresholdPriceUi ;
}
const thresholdPrice = toNativeSellPerBuyTokenPrice (
thresholdPriceUi ,
sellBank ,
buyBank ,
) ;
2023-09-08 04:45:51 -07:00
const lowerLimit = thresholdPrice ;
const upperLimit = Number . MAX_SAFE_INTEGER ;
2023-08-11 07:46:19 -07:00
2023-08-07 04:09:19 -07:00
return await this . tokenConditionalSwapCreate (
group ,
account ,
sellBank ,
buyBank ,
2023-08-11 07:46:19 -07:00
lowerLimit ,
upperLimit ,
2023-08-07 04:09:19 -07:00
maxBuyUi ? ? - account . getTokenBalanceUi ( buyBank ) ,
Number . MAX_SAFE_INTEGER ,
'StopLossOnBorrow' ,
pricePremium ,
false ,
allowMargin ? ? false ,
expiryTimestamp ,
2023-09-07 03:40:37 -07:00
thresholdPriceInSellPerBuyToken ,
2023-08-07 04:09:19 -07:00
) ;
}
public async tokenConditionalSwapCreate (
group : Group ,
account : MangoAccount ,
sellBank : Bank ,
buyBank : Bank ,
2023-08-11 07:46:19 -07:00
lowerLimit : number ,
upperLimit : number ,
2023-08-07 04:09:19 -07:00
maxBuyUi : number ,
maxSellUi : number ,
tcsIntention :
| 'TakeProfitOnDeposit'
| 'StopLossOnDeposit'
| 'TakeProfitOnBorrow'
| 'StopLossOnBorrow'
| null ,
pricePremium : number | null ,
allowCreatingDeposits : boolean ,
allowCreatingBorrows : boolean ,
expiryTimestamp : number | null ,
2023-09-07 03:40:37 -07:00
displayPriceInSellTokenPerBuyToken : boolean ,
2023-08-11 10:12:13 -07:00
) : Promise < MangoSignatureStatus > {
2023-09-07 23:49:38 -07:00
const maxBuy =
maxBuyUi == Number . MAX_SAFE_INTEGER
? U64_MAX_BN
: toNative ( maxBuyUi , buyBank . mintDecimals ) ;
const maxSell =
maxSellUi == Number . MAX_SAFE_INTEGER
? U64_MAX_BN
: toNative ( maxSellUi , sellBank . mintDecimals ) ;
pricePremium = TokenConditionalSwap . computePremium (
group ,
buyBank ,
sellBank ,
maxBuy ,
maxSell ,
maxBuyUi ,
maxSellUi ,
) ;
2023-08-10 04:32:06 -07:00
const pricePremiumRate = pricePremium > 0 ? pricePremium / 100 : 0.03 ;
2023-08-07 04:09:19 -07:00
2023-08-10 04:39:39 -07:00
let intention : TokenConditionalSwapIntention ;
switch ( tcsIntention ) {
case 'StopLossOnBorrow' :
case 'StopLossOnDeposit' :
intention = TokenConditionalSwapIntention . stopLoss ;
break ;
case 'TakeProfitOnBorrow' :
case 'TakeProfitOnDeposit' :
intention = TokenConditionalSwapIntention . takeProfit ;
break ;
default :
intention = TokenConditionalSwapIntention . unknown ;
break ;
2023-07-27 23:26:34 -07:00
}
2023-08-10 04:48:28 -07:00
return await this . tokenConditionalSwapCreateRaw (
group ,
account ,
buyBank . mint ,
sellBank . mint ,
maxBuy ,
maxSell ,
expiryTimestamp ,
lowerLimit ,
upperLimit ,
pricePremiumRate ,
allowCreatingDeposits ,
allowCreatingBorrows ,
2023-09-08 03:07:51 -07:00
displayPriceInSellTokenPerBuyToken
? TokenConditionalSwapDisplayPriceStyle . sellTokenPerBuyToken
: TokenConditionalSwapDisplayPriceStyle . buyTokenPerSellToken ,
2023-08-10 04:48:28 -07:00
intention ,
) ;
2023-07-27 23:26:34 -07:00
}
2023-08-07 04:09:19 -07:00
public async tokenConditionalSwapCreateRaw (
2023-07-03 05:09:11 -07:00
group : Group ,
account : MangoAccount ,
buyMintPk : PublicKey ,
sellMintPk : PublicKey ,
2023-08-10 04:48:28 -07:00
maxBuy : BN ,
maxSell : BN ,
2023-07-03 05:09:11 -07:00
expiryTimestamp : number | null ,
priceLowerLimit : number ,
priceUpperLimit : number ,
2023-08-09 04:27:25 -07:00
pricePremiumRate : number ,
2023-07-03 05:09:11 -07:00
allowCreatingDeposits : boolean ,
allowCreatingBorrows : boolean ,
2023-08-03 03:37:01 -07:00
priceDisplayStyle : TokenConditionalSwapDisplayPriceStyle ,
2023-08-08 09:16:59 -07:00
intention : TokenConditionalSwapIntention ,
2023-08-11 10:12:13 -07:00
) : Promise < MangoSignatureStatus > {
2023-07-03 05:09:11 -07:00
const buyBank : Bank = group . getFirstBankByMint ( buyMintPk ) ;
const sellBank : Bank = group . getFirstBankByMint ( sellMintPk ) ;
2023-08-10 04:48:28 -07:00
const tcsIx = await this . program . methods
2023-08-03 03:37:01 -07:00
. tokenConditionalSwapCreateV2 (
2023-08-10 04:48:28 -07:00
maxBuy ,
maxSell ,
2023-07-03 05:09:11 -07:00
expiryTimestamp !== null ? new BN ( expiryTimestamp ) : U64_MAX_BN ,
priceLowerLimit ,
priceUpperLimit ,
2023-08-09 04:27:25 -07:00
pricePremiumRate ,
2023-07-03 05:09:11 -07:00
allowCreatingDeposits ,
allowCreatingBorrows ,
2023-08-03 03:37:01 -07:00
priceDisplayStyle ,
2023-08-08 09:16:59 -07:00
intention ,
2023-07-03 05:09:11 -07:00
)
. accounts ( {
group : group.publicKey ,
account : account.publicKey ,
authority : ( this . program . provider as AnchorProvider ) . wallet . publicKey ,
buyBank : buyBank.publicKey ,
sellBank : sellBank.publicKey ,
} )
. instruction ( ) ;
2023-08-10 04:48:28 -07:00
const ixs : TransactionInstruction [ ] = [ ] ;
2023-07-27 23:26:34 -07:00
if ( account . tokenConditionalSwaps . length == 0 ) {
ixs . push (
await this . accountExpandV2Ix (
group ,
account ,
account . tokens . length ,
account . serum3 . length ,
account . perps . length ,
account . perpOpenOrders . length ,
2023-08-10 04:48:28 -07:00
DEFAULT_TOKEN_CONDITIONAL_SWAP_COUNT ,
2023-07-27 23:26:34 -07:00
) ,
) ;
}
2023-08-10 04:48:28 -07:00
ixs . push ( tcsIx ) ;
2023-07-27 23:26:34 -07:00
return await this . sendAndConfirmTransactionForGroup ( group , ixs ) ;
2023-07-03 05:09:11 -07:00
}
public async tokenConditionalSwapCancel (
group : Group ,
account : MangoAccount ,
2023-07-17 04:14:53 -07:00
tokenConditionalSwapId : BN ,
2023-08-11 10:12:13 -07:00
) : Promise < MangoSignatureStatus > {
2023-07-28 06:57:25 -07:00
const tokenConditionalSwapIndex = account . tokenConditionalSwaps . findIndex (
( tcs ) = > tcs . id . eq ( tokenConditionalSwapId ) ,
) ;
if ( tokenConditionalSwapIndex == - 1 ) {
2023-07-17 04:14:53 -07:00
throw new Error ( 'tcs with id not found' ) ;
}
2023-07-28 06:57:25 -07:00
const tcs = account . tokenConditionalSwaps [ tokenConditionalSwapIndex ] ;
2023-07-17 04:14:53 -07:00
const buyBank = group . banksMapByTokenIndex . get ( tcs . buyTokenIndex ) ! [ 0 ] ;
const sellBank = group . banksMapByTokenIndex . get ( tcs . sellTokenIndex ) ! [ 0 ] ;
2023-07-03 05:09:11 -07:00
const ix = await this . program . methods
. tokenConditionalSwapCancel (
tokenConditionalSwapIndex ,
new BN ( tokenConditionalSwapId ) ,
)
. accounts ( {
group : group.publicKey ,
account : account.publicKey ,
authority : ( this . program . provider as AnchorProvider ) . wallet . publicKey ,
2023-07-17 04:14:53 -07:00
buyBank : buyBank.publicKey ,
sellBank : sellBank.publicKey ,
2023-07-03 05:09:11 -07:00
} )
. instruction ( ) ;
return await this . sendAndConfirmTransactionForGroup ( group , [ ix ] ) ;
}
2023-07-31 05:54:39 -07:00
public async tokenConditionalSwapCancelAll (
group : Group ,
account : MangoAccount ,
2023-08-11 10:12:13 -07:00
) : Promise < MangoSignatureStatus > {
2023-07-31 05:54:39 -07:00
const ixs = await Promise . all (
account . tokenConditionalSwaps
. filter ( ( tcs ) = > tcs . hasData )
. map ( async ( tcs , i ) = > {
const buyBank = group . banksMapByTokenIndex . get ( tcs . buyTokenIndex ) ! [ 0 ] ;
const sellBank = group . banksMapByTokenIndex . get (
tcs . sellTokenIndex ,
) ! [ 0 ] ;
return await this . program . methods
. tokenConditionalSwapCancel ( i , new BN ( tcs . id ) )
. accounts ( {
group : group.publicKey ,
account : account.publicKey ,
authority : ( this . program . provider as AnchorProvider ) . wallet
. publicKey ,
buyBank : buyBank.publicKey ,
sellBank : sellBank.publicKey ,
} )
. instruction ( ) ;
} ) ,
) ;
return await this . sendAndConfirmTransactionForGroup ( group , ixs ) ;
}
2023-07-03 05:09:11 -07:00
public async tokenConditionalSwapTrigger (
group : Group ,
liqee : MangoAccount ,
liqor : MangoAccount ,
2023-07-17 04:14:53 -07:00
tokenConditionalSwapId : BN ,
2023-07-03 05:09:11 -07:00
maxBuyTokenToLiqee : number ,
maxSellTokenToLiqor : number ,
2023-08-11 10:12:13 -07:00
) : Promise < MangoSignatureStatus > {
2023-07-28 06:57:25 -07:00
const tokenConditionalSwapIndex = liqee . tokenConditionalSwaps . findIndex (
( tcs ) = > tcs . id . eq ( tokenConditionalSwapId ) ,
) ;
if ( tokenConditionalSwapIndex == - 1 ) {
2023-07-17 04:14:53 -07:00
throw new Error ( 'tcs with id not found' ) ;
}
2023-07-28 06:57:25 -07:00
const tcs = liqee . tokenConditionalSwaps [ tokenConditionalSwapIndex ] ;
2023-07-17 04:14:53 -07:00
const buyBank = group . banksMapByTokenIndex . get ( tcs . buyTokenIndex ) ! [ 0 ] ;
const sellBank = group . banksMapByTokenIndex . get ( tcs . sellTokenIndex ) ! [ 0 ] ;
const healthRemainingAccounts : PublicKey [ ] =
this . buildHealthRemainingAccounts (
group ,
[ liqor , liqee ] ,
[ buyBank , sellBank ] ,
[ ] ,
) ;
const parsedHealthAccounts = healthRemainingAccounts . map (
( pk ) = >
( {
pubkey : pk ,
isWritable :
pk . equals ( buyBank . publicKey ) || pk . equals ( sellBank . publicKey )
? true
: false ,
isSigner : false ,
} as AccountMeta ) ,
) ;
2023-07-03 05:09:11 -07:00
const ix = await this . program . methods
. tokenConditionalSwapTrigger (
tokenConditionalSwapIndex ,
new BN ( tokenConditionalSwapId ) ,
new BN ( maxBuyTokenToLiqee ) ,
new BN ( maxSellTokenToLiqor ) ,
)
. accounts ( {
group : group.publicKey ,
liqee : liqee.publicKey ,
liqor : liqor.publicKey ,
liqorAuthority : ( this . program . provider as AnchorProvider ) . wallet
. publicKey ,
} )
2023-07-17 04:14:53 -07:00
. remainingAccounts ( parsedHealthAccounts )
2023-07-03 05:09:11 -07:00
. instruction ( ) ;
return await this . sendAndConfirmTransactionForGroup ( group , [ ix ] ) ;
}
2022-10-07 04:52:04 -07:00
public async altSet (
2022-09-29 06:51:09 -07:00
group : Group ,
addressLookupTable : PublicKey ,
index : number ,
2023-08-11 10:12:13 -07:00
) : Promise < MangoSignatureStatus > {
2022-09-27 06:13:53 -07:00
const ix = await this . program . methods
. altSet ( index )
. accounts ( {
group : group.publicKey ,
admin : ( this . program . provider as AnchorProvider ) . wallet . publicKey ,
addressLookupTable ,
} )
. instruction ( ) ;
2023-02-03 04:55:46 -08:00
return await this . sendAndConfirmTransactionForGroup ( group , [ ix ] ) ;
2022-09-27 06:13:53 -07:00
}
2022-10-07 04:52:04 -07:00
public async altExtend (
2022-09-27 06:13:53 -07:00
group : Group ,
addressLookupTable : PublicKey ,
index : number ,
pks : PublicKey [ ] ,
2023-08-11 10:12:13 -07:00
) : Promise < MangoSignatureStatus > {
2023-02-02 05:23:22 -08:00
const ix = await this . program . methods
2022-09-27 06:13:53 -07:00
. altExtend ( index , pks )
. accounts ( {
group : group.publicKey ,
admin : ( this . program . provider as AnchorProvider ) . wallet . publicKey ,
payer : ( this . program . provider as AnchorProvider ) . wallet . publicKey ,
addressLookupTable ,
} )
2023-02-02 05:23:22 -08:00
. instruction ( ) ;
2023-02-03 04:55:46 -08:00
return await this . sendAndConfirmTransactionForGroup ( group , [ ix ] ) ;
2022-08-04 00:07:32 -07:00
}
2022-06-18 07:31:28 -07:00
2022-10-11 00:39:57 -07:00
public async healthRegionBeginIx (
group : Group ,
account : MangoAccount ,
banks : Bank [ ] = [ ] ,
perpMarkets : PerpMarket [ ] = [ ] ,
) : Promise < TransactionInstruction > {
const healthRemainingAccounts : PublicKey [ ] =
this . buildHealthRemainingAccounts (
group ,
[ account ] ,
[ . . . banks ] ,
[ . . . perpMarkets ] ,
) ;
const parsedHealthAccounts = healthRemainingAccounts . map (
( pk ) = >
( {
pubkey : pk ,
isWritable : false ,
isSigner : false ,
} as AccountMeta ) ,
) ;
return await this . program . methods
. healthRegionBegin ( )
. accounts ( {
2023-02-02 10:02:30 -08:00
group : group.publicKey ,
2022-10-11 00:39:57 -07:00
account : account.publicKey ,
instructions : SYSVAR_INSTRUCTIONS_PUBKEY ,
} )
. remainingAccounts ( parsedHealthAccounts )
. instruction ( ) ;
}
public async healthRegionEndIx (
group : Group ,
account : MangoAccount ,
banks : Bank [ ] = [ ] ,
perpMarkets : PerpMarket [ ] = [ ] ,
) : Promise < TransactionInstruction > {
const healthRemainingAccounts : PublicKey [ ] =
this . buildHealthRemainingAccounts (
group ,
[ account ] ,
[ . . . banks ] ,
[ . . . perpMarkets ] ,
) ;
const parsedHealthAccounts = healthRemainingAccounts . map (
( pk ) = >
( {
pubkey : pk ,
isWritable : false ,
isSigner : false ,
} as AccountMeta ) ,
) ;
return await this . program . methods
. healthRegionEnd ( )
. accounts ( { account : account.publicKey } )
. remainingAccounts ( parsedHealthAccounts )
. instruction ( ) ;
}
2022-04-07 09:58:42 -07:00
/// static
2022-06-11 04:49:45 -07:00
static connect (
provider : Provider ,
cluster : Cluster ,
programId : PublicKey ,
2022-11-04 07:35:40 -07:00
opts? : MangoClientOptions ,
2022-06-11 04:49:45 -07:00
) : MangoClient {
2022-08-04 10:42:41 -07:00
const idl = IDL ;
2022-03-31 00:10:06 -07:00
2022-02-23 02:09:17 -08:00
return new MangoClient (
2022-06-11 04:49:45 -07:00
new Program < MangoV4 > ( idl as MangoV4 , programId , provider ) ,
programId ,
cluster ,
2022-08-12 17:15:12 -07:00
opts ,
2022-06-21 11:04:21 -07:00
) ;
}
2023-06-15 23:04:58 -07:00
/ * *
* Connect with defaults ,
* - random ephemeral keypair ,
* - fetch ids using gPa
* - connects to mainnet - beta
* - uses well known program Id
* @param clusterUrl
* @returns
* /
static connectDefault ( clusterUrl : string ) : MangoClient {
const idl = IDL ;
const options = AnchorProvider . defaultOptions ( ) ;
const connection = new Connection ( clusterUrl , options ) ;
return new MangoClient (
new Program < MangoV4 > (
idl as MangoV4 ,
MANGO_V4_ID [ 'mainnet-beta' ] ,
new AnchorProvider ( connection , new Wallet ( new Keypair ( ) ) , options ) ,
) ,
MANGO_V4_ID [ 'mainnet-beta' ] ,
'mainnet-beta' as Cluster ,
{
idsSource : 'get-program-accounts' ,
} ,
) ;
}
2022-06-21 11:04:21 -07:00
static connectForGroupName (
provider : Provider ,
groupName : string ,
) : MangoClient {
2022-08-04 10:42:41 -07:00
const idl = IDL ;
2022-06-21 11:04:21 -07:00
2022-08-17 23:48:45 -07:00
const id = Id . fromIdsByName ( groupName ) ;
2022-06-21 11:04:21 -07:00
return new MangoClient (
new Program < MangoV4 > (
idl as MangoV4 ,
2022-06-23 06:22:59 -07:00
new PublicKey ( id . mangoProgramId ) ,
2022-06-21 11:04:21 -07:00
provider ,
) ,
2022-06-23 06:22:59 -07:00
new PublicKey ( id . mangoProgramId ) ,
2022-06-21 11:04:21 -07:00
id . cluster ,
2022-02-23 02:09:17 -08:00
) ;
}
2022-04-07 08:16:46 -07:00
2023-04-24 05:48:53 -07:00
/ * *
* Builds health remaining accounts .
*
* For single mango account it builds a list of PublicKeys
* which is compatbile with Fixed account retriever .
*
* For multiple mango accounts it uses same logic as for fixed
* but packing all banks , then perp markets , and then serum oo accounts , which
* should always be compatible with Scanning account retriever .
*
* @param group
* @param mangoAccounts
* @param banks - banks in which new positions might be opened
* @param perpMarkets - markets in which new positions might be opened
* @param openOrdersForMarket - markets in which new positions might be opened
* @returns
* /
buildHealthRemainingAccounts (
2022-08-03 09:05:16 -07:00
group : Group ,
mangoAccounts : MangoAccount [ ] ,
2023-04-24 05:48:53 -07:00
// Banks and markets for whom positions don't exist on mango account,
// but user would potentially open new positions.
2023-01-07 14:06:35 -08:00
banks : Bank [ ] = [ ] ,
perpMarkets : PerpMarket [ ] = [ ] ,
openOrdersForMarket : [ Serum3Market , PublicKey ] [ ] = [ ] ,
2022-08-10 01:15:28 -07:00
) : PublicKey [ ] {
2022-04-07 09:58:42 -07:00
const healthRemainingAccounts : PublicKey [ ] = [ ] ;
2022-04-07 08:58:20 -07:00
2023-04-25 02:13:40 -07:00
const tokenPositionIndices = mangoAccounts
. map ( ( mangoAccount ) = > mangoAccount . tokens . map ( ( t ) = > t . tokenIndex ) )
. flat ( ) ;
2023-01-07 14:06:35 -08:00
for ( const bank of banks ) {
2023-01-10 07:51:03 -08:00
const tokenPositionExists =
2023-01-13 02:23:37 -08:00
tokenPositionIndices . indexOf ( bank . tokenIndex ) > - 1 ;
2023-01-07 14:06:35 -08:00
if ( ! tokenPositionExists ) {
2023-01-10 07:51:03 -08:00
const inactiveTokenPosition = tokenPositionIndices . findIndex (
( index ) = > index === TokenPosition . TokenIndexUnset ,
) ;
2023-01-13 02:23:37 -08:00
if ( inactiveTokenPosition != - 1 ) {
2023-01-10 07:51:03 -08:00
tokenPositionIndices [ inactiveTokenPosition ] = bank . tokenIndex ;
2023-09-07 23:28:34 -07:00
} else {
throw new Error (
` All token positions are occupied, either expand mango account, or close an existing token position, e.g. by withdrawing token deposits, or repaying all borrows! ` ,
) ;
2022-08-10 01:15:28 -07:00
}
2022-05-31 18:38:47 -07:00
}
2022-04-07 09:58:42 -07:00
}
2023-04-25 02:13:40 -07:00
const mintInfos = uniq (
tokenPositionIndices
. filter ( ( tokenIndex ) = > tokenIndex !== TokenPosition . TokenIndexUnset )
. map ( ( tokenIndex ) = > group . mintInfosMapByTokenIndex . get ( tokenIndex ) ! ) ,
( mintInfo ) = > {
mintInfo . tokenIndex ;
} ,
) ;
2022-06-27 02:27:17 -07:00
healthRemainingAccounts . push (
. . . mintInfos . map ( ( mintInfo ) = > mintInfo . firstBank ( ) ) ,
) ;
2022-04-08 03:30:21 -07:00
healthRemainingAccounts . push (
2022-06-11 04:49:45 -07:00
. . . mintInfos . map ( ( mintInfo ) = > mintInfo . oracle ) ,
2022-04-08 03:30:21 -07:00
) ;
2022-08-31 02:36:44 -07:00
2023-04-24 05:48:53 -07:00
// Insert any extra perp markets in the free perp position slots
2023-04-25 02:13:40 -07:00
const perpPositionsMarketIndices = mangoAccounts
. map ( ( mangoAccount ) = > mangoAccount . perps . map ( ( p ) = > p . marketIndex ) )
. flat ( ) ;
2023-01-07 14:06:35 -08:00
for ( const perpMarket of perpMarkets ) {
2023-01-10 07:51:03 -08:00
const perpPositionExists =
2023-04-24 05:48:53 -07:00
perpPositionsMarketIndices . indexOf ( perpMarket . perpMarketIndex ) > - 1 ;
2023-01-07 14:06:35 -08:00
if ( ! perpPositionExists ) {
2023-04-24 05:48:53 -07:00
const inactivePerpPosition = perpPositionsMarketIndices . findIndex (
2023-01-10 07:51:03 -08:00
( perpIdx ) = > perpIdx === PerpPosition . PerpMarketIndexUnset ,
) ;
2023-01-13 02:23:37 -08:00
if ( inactivePerpPosition != - 1 ) {
2023-04-24 05:48:53 -07:00
perpPositionsMarketIndices [ inactivePerpPosition ] =
2023-01-10 07:51:03 -08:00
perpMarket . perpMarketIndex ;
2022-09-21 03:50:10 -07:00
}
2022-08-31 02:36:44 -07:00
}
}
2023-04-25 02:13:40 -07:00
const allPerpMarkets = uniq (
perpPositionsMarketIndices
. filter (
( perpMarktIndex ) = >
perpMarktIndex !== PerpPosition . PerpMarketIndexUnset ,
)
. map ( ( perpIdx ) = > group . getPerpMarketByMarketIndex ( perpIdx ) ! ) ,
( pm ) = > pm . perpMarketIndex ,
) ;
2022-09-21 03:50:10 -07:00
healthRemainingAccounts . push (
. . . allPerpMarkets . map ( ( perp ) = > perp . publicKey ) ,
) ;
healthRemainingAccounts . push ( . . . allPerpMarkets . map ( ( perp ) = > perp . oracle ) ) ;
2022-08-31 02:36:44 -07:00
2023-04-24 05:48:53 -07:00
// Insert any extra open orders accounts in the cooresponding free serum market slot
const serumPositionMarketIndices = mangoAccounts
. map ( ( mangoAccount ) = >
mangoAccount . serum3 . map ( ( s ) = > ( {
marketIndex : s.marketIndex ,
openOrders : s.openOrders ,
} ) ) ,
)
. flat ( ) ;
2023-01-07 14:06:35 -08:00
for ( const [ serum3Market , openOrderPk ] of openOrdersForMarket ) {
2023-01-10 07:51:03 -08:00
const ooPositionExists =
2023-04-24 05:48:53 -07:00
serumPositionMarketIndices . findIndex (
2023-01-10 07:51:03 -08:00
( i ) = > i . marketIndex === serum3Market . marketIndex ,
2023-01-13 02:23:37 -08:00
) > - 1 ;
2023-01-07 14:06:35 -08:00
if ( ! ooPositionExists ) {
2023-04-24 05:48:53 -07:00
const inactiveSerumPosition = serumPositionMarketIndices . findIndex (
2023-01-10 07:51:03 -08:00
( serumPos ) = >
serumPos . marketIndex === Serum3Orders . Serum3MarketIndexUnset ,
2023-01-07 14:06:35 -08:00
) ;
2023-01-13 02:23:37 -08:00
if ( inactiveSerumPosition != - 1 ) {
2023-04-24 05:48:53 -07:00
serumPositionMarketIndices [ inactiveSerumPosition ] . marketIndex =
2023-01-13 02:23:37 -08:00
serum3Market . marketIndex ;
2023-04-24 05:48:53 -07:00
serumPositionMarketIndices [ inactiveSerumPosition ] . openOrders =
openOrderPk ;
2023-01-07 14:06:35 -08:00
}
}
}
2022-08-31 02:36:44 -07:00
healthRemainingAccounts . push (
2023-04-24 05:48:53 -07:00
. . . serumPositionMarketIndices
2023-01-10 07:51:03 -08:00
. filter (
( serumPosition ) = >
serumPosition . marketIndex !== Serum3Orders . Serum3MarketIndexUnset ,
)
. map ( ( serumPosition ) = > serumPosition . openOrders ) ,
2022-08-31 02:36:44 -07:00
) ;
2022-08-03 09:05:16 -07:00
return healthRemainingAccounts ;
}
2022-12-14 06:15:35 -08:00
public async modifyPerpOrder (
group : Group ,
mangoAccount : MangoAccount ,
perpMarketIndex : PerpMarketIndex ,
orderId : BN ,
side : PerpOrderSide ,
price : number ,
quantity : number ,
maxQuoteQuantity? : number ,
clientOrderId? : number ,
orderType? : PerpOrderType ,
reduceOnly? : boolean ,
expiryTimestamp? : number ,
limit? : number ,
2023-08-11 10:12:13 -07:00
) : Promise < MangoSignatureStatus > {
2022-12-14 06:15:35 -08:00
const transactionInstructions : TransactionInstruction [ ] = [ ] ;
const [ cancelOrderIx , placeOrderIx ] = await Promise . all ( [
this . perpCancelOrderIx ( group , mangoAccount , perpMarketIndex , orderId ) ,
this . perpPlaceOrderIx (
group ,
mangoAccount ,
perpMarketIndex ,
side ,
price ,
quantity ,
maxQuoteQuantity ,
clientOrderId ,
orderType ,
reduceOnly ,
expiryTimestamp ,
limit ,
) ,
] ) ;
transactionInstructions . push ( cancelOrderIx , placeOrderIx ) ;
2023-02-03 04:55:46 -08:00
return await this . sendAndConfirmTransactionForGroup (
group ,
2022-12-15 01:40:45 -08:00
transactionInstructions ,
) ;
}
public async modifySerum3Order (
group : Group ,
orderId : BN ,
mangoAccount : MangoAccount ,
externalMarketPk : PublicKey ,
side : Serum3Side ,
price : number ,
size : number ,
selfTradeBehavior : Serum3SelfTradeBehavior ,
orderType : Serum3OrderType ,
clientOrderId : number ,
limit : number ,
2023-08-11 10:12:13 -07:00
) : Promise < MangoSignatureStatus > {
2022-12-15 01:40:45 -08:00
const transactionInstructions : TransactionInstruction [ ] = [ ] ;
2022-12-15 11:06:10 -08:00
const [ cancelOrderIx , settleIx , placeOrderIx ] = await Promise . all ( [
2022-12-15 01:40:45 -08:00
this . serum3CancelOrderIx (
group ,
mangoAccount ,
externalMarketPk ,
side ,
orderId ,
) ,
2023-03-03 05:04:45 -08:00
this . serum3SettleFundsV2Ix ( group , mangoAccount , externalMarketPk ) ,
2022-12-15 01:40:45 -08:00
this . serum3PlaceOrderIx (
group ,
mangoAccount ,
externalMarketPk ,
side ,
price ,
size ,
selfTradeBehavior ,
orderType ,
clientOrderId ,
limit ,
) ,
] ) ;
2023-01-04 23:30:15 -08:00
transactionInstructions . push ( cancelOrderIx , settleIx , . . . placeOrderIx ) ;
2022-12-15 01:40:45 -08:00
2023-02-03 04:55:46 -08:00
return await this . sendAndConfirmTransactionForGroup (
group ,
2022-12-14 06:15:35 -08:00
transactionInstructions ,
) ;
}
2023-08-09 14:13:55 -07:00
/ * *
* Returns an estimate of a prioritization fee for a set of instructions .
*
2023-08-11 06:18:41 -07:00
* The estimate is based on the median fees of writable accounts that will be involved in the transaction .
2023-08-09 14:13:55 -07:00
*
* @param ixs - the instructions that make up the transaction
* @returns prioritizationFeeEstimate -- in microLamports
* /
public async estimatePrioritizationFee (
ixs : TransactionInstruction [ ] ,
) : Promise < number > {
2023-08-11 06:18:41 -07:00
const writableAccounts = ixs
. map ( ( x ) = > x . keys . filter ( ( a ) = > a . isWritable ) . map ( ( k ) = > k . pubkey ) )
. flat ( ) ;
const uniqueWritableAccounts = uniq (
writableAccounts . map ( ( x ) = > x . toBase58 ( ) ) ,
)
. map ( ( a ) = > new PublicKey ( a ) )
. slice ( 0 , MAX_RECENT_PRIORITY_FEE_ACCOUNTS ) ;
2023-08-09 14:13:55 -07:00
const priorityFees = await this . connection . getRecentPrioritizationFees ( {
2023-08-11 06:18:41 -07:00
lockedWritableAccounts : uniqueWritableAccounts ,
2023-08-09 14:13:55 -07:00
} ) ;
2023-08-11 06:18:41 -07:00
if ( priorityFees . length < 1 ) {
return 1 ;
}
2023-08-09 14:13:55 -07:00
// get max priority fee per slot (and sort by slot from old to new)
2023-08-11 06:18:41 -07:00
const maxFeeBySlot = mapValues ( groupBy ( priorityFees , 'slot' ) , ( items ) = >
maxBy ( items , 'prioritizationFee' ) ,
2023-08-09 14:13:55 -07:00
) ;
const maximumFees = Object . values ( maxFeeBySlot ) . sort (
2023-08-11 06:18:41 -07:00
( a : RecentPrioritizationFees , b : RecentPrioritizationFees ) = >
a . slot - b . slot ,
) as RecentPrioritizationFees [ ] ;
// get median of last 20 fees
const recentFees = maximumFees . slice ( Math . max ( maximumFees . length - 20 , 0 ) ) ;
const mid = Math . floor ( recentFees . length / 2 ) ;
const medianFee =
recentFees . length % 2 !== 0
? recentFees [ mid ] . prioritizationFee
: ( recentFees [ mid - 1 ] . prioritizationFee +
recentFees [ mid ] . prioritizationFee ) /
2 ;
return Math . max ( 1 , Math . ceil ( medianFee ) ) ;
2023-08-09 14:13:55 -07:00
}
2022-02-23 02:09:17 -08:00
}