2022-08-04 08:35:05 -07:00
|
|
|
import { AnchorProvider, BN, Program, Provider } from '@project-serum/anchor';
|
2022-05-25 17:29:06 -07:00
|
|
|
import {
|
|
|
|
closeAccount,
|
|
|
|
initializeAccount,
|
|
|
|
WRAPPED_SOL_MINT,
|
|
|
|
} from '@project-serum/serum/lib/token-instructions';
|
2022-06-23 03:58:43 -07:00
|
|
|
import {
|
|
|
|
ASSOCIATED_TOKEN_PROGRAM_ID,
|
2022-06-24 07:41:04 -07:00
|
|
|
Token,
|
2022-06-23 03:58:43 -07:00
|
|
|
TOKEN_PROGRAM_ID,
|
|
|
|
} from '@solana/spl-token';
|
2022-04-07 09:58:42 -07:00
|
|
|
import {
|
2022-04-07 12:00:08 -07:00
|
|
|
AccountMeta,
|
2022-06-11 04:49:45 -07:00
|
|
|
Cluster,
|
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,
|
2022-06-01 01:10:43 -07:00
|
|
|
Signer,
|
2022-05-11 04:33:01 -07:00
|
|
|
SystemProgram,
|
2022-07-06 21:45:01 -07:00
|
|
|
SYSVAR_INSTRUCTIONS_PUBKEY,
|
2022-04-07 12:00:08 -07:00
|
|
|
SYSVAR_RENT_PUBKEY,
|
2022-06-24 07:41:04 -07:00
|
|
|
Transaction,
|
2022-05-25 17:29:06 -07:00
|
|
|
TransactionInstruction,
|
2022-06-01 01:10:43 -07:00
|
|
|
TransactionSignature,
|
2022-04-07 12:00:08 -07:00
|
|
|
} from '@solana/web3.js';
|
2022-04-07 23:29:35 -07:00
|
|
|
import bs58 from 'bs58';
|
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';
|
|
|
|
import { I80F48 } from './accounts/I80F48';
|
2022-08-10 01:15:28 -07:00
|
|
|
import {
|
|
|
|
MangoAccount,
|
2022-09-21 03:50:10 -07:00
|
|
|
PerpPosition,
|
2022-09-29 06:51:09 -07:00
|
|
|
TokenPosition,
|
2022-08-10 01:15:28 -07:00
|
|
|
} 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,
|
2022-09-15 00:57:48 -07:00
|
|
|
} from './accounts/perp';
|
2022-04-08 03:30:21 -07:00
|
|
|
import {
|
2022-08-31 02:36:44 -07:00
|
|
|
generateSerum3MarketExternalVaultSignerAddress,
|
2022-04-08 03:30:21 -07:00
|
|
|
Serum3Market,
|
|
|
|
Serum3OrderType,
|
|
|
|
Serum3SelfTradeBehavior,
|
|
|
|
Serum3Side,
|
2022-04-12 08:28:47 -07:00
|
|
|
} from './accounts/serum3';
|
2022-06-11 04:49:45 -07:00
|
|
|
import { SERUM3_PROGRAM_ID } 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-02 00:42:47 -07:00
|
|
|
import { FlashLoanType, InterestRateParams } from './types';
|
2022-06-02 10:30:39 -07:00
|
|
|
import {
|
2022-08-09 15:27:24 -07:00
|
|
|
createAssociatedTokenAccountIdempotentInstruction,
|
2022-06-02 10:30:39 -07:00
|
|
|
getAssociatedTokenAddress,
|
|
|
|
I64_MAX_BN,
|
|
|
|
toNativeDecimals,
|
|
|
|
} from './utils';
|
2022-08-12 17:15:12 -07:00
|
|
|
import { sendTransaction } from './utils/rpc';
|
2022-02-23 02:09:17 -08:00
|
|
|
|
2022-08-03 09:05:16 -07:00
|
|
|
enum AccountRetriever {
|
|
|
|
Scanning,
|
|
|
|
Fixed,
|
|
|
|
}
|
|
|
|
|
2022-08-17 23:48:45 -07:00
|
|
|
export type IdsSource = 'api' | 'static' | 'get-program-accounts';
|
|
|
|
|
2022-07-04 03:09:33 -07:00
|
|
|
// TODO: replace ui values with native as input wherever possible
|
2022-02-23 02:09:17 -08:00
|
|
|
export class MangoClient {
|
2022-09-13 22:44:00 -07:00
|
|
|
private postSendTxCallback?: ({ txid }) => void;
|
2022-08-12 17:15:12 -07:00
|
|
|
private prioritizationFee: number;
|
|
|
|
|
2022-06-11 04:49:45 -07:00
|
|
|
constructor(
|
|
|
|
public program: Program<MangoV4>,
|
|
|
|
public programId: PublicKey,
|
|
|
|
public cluster: Cluster,
|
2022-08-12 17:15:12 -07:00
|
|
|
public opts: {
|
|
|
|
postSendTxCallback?: ({ txid }: { txid: string }) => void;
|
|
|
|
prioritizationFee?: number;
|
|
|
|
} = {},
|
2022-08-17 23:48:45 -07:00
|
|
|
public idsSource: IdsSource = 'api',
|
2022-07-17 04:26:57 -07:00
|
|
|
) {
|
2022-08-12 17:15:12 -07:00
|
|
|
this.prioritizationFee = opts?.prioritizationFee || 0;
|
|
|
|
this.postSendTxCallback = opts?.postSendTxCallback;
|
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
|
|
|
|
2022-04-07 09:58:42 -07:00
|
|
|
/// public
|
|
|
|
|
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,
|
2022-06-09 09:27:31 -07:00
|
|
|
): Promise<TransactionSignature> {
|
2022-05-18 08:16:14 -07:00
|
|
|
const adminPk = (this.program.provider as AnchorProvider).wallet.publicKey;
|
2022-04-07 12:00:08 -07:00
|
|
|
return 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
|
|
|
})
|
|
|
|
.rpc();
|
2022-04-07 10:42:00 -07:00
|
|
|
}
|
|
|
|
|
2022-08-03 01:25:09 -07:00
|
|
|
public async groupEdit(
|
|
|
|
group: Group,
|
2022-08-13 10:54:58 -07:00
|
|
|
admin: PublicKey | undefined,
|
|
|
|
fastListingAdmin: PublicKey | undefined,
|
|
|
|
testing: number | undefined,
|
|
|
|
version: number | undefined,
|
2022-08-03 01:25:09 -07:00
|
|
|
): Promise<TransactionSignature> {
|
|
|
|
return await this.program.methods
|
2022-08-13 10:54:58 -07:00
|
|
|
.groupEdit(
|
|
|
|
admin ?? null,
|
|
|
|
fastListingAdmin ?? null,
|
|
|
|
testing ?? null,
|
|
|
|
version ?? null,
|
|
|
|
)
|
2022-08-03 01:25:09 -07:00
|
|
|
.accounts({
|
|
|
|
group: group.publicKey,
|
|
|
|
admin: (this.program.provider as AnchorProvider).wallet.publicKey,
|
|
|
|
})
|
|
|
|
.rpc();
|
|
|
|
}
|
|
|
|
|
2022-07-06 05:51:15 -07:00
|
|
|
public async groupClose(group: Group): Promise<TransactionSignature> {
|
2022-06-09 09:27:31 -07:00
|
|
|
const adminPk = (this.program.provider as AnchorProvider).wallet.publicKey;
|
|
|
|
return 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,
|
|
|
|
})
|
|
|
|
.rpc();
|
|
|
|
}
|
|
|
|
|
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);
|
2022-06-11 04:49:45 -07: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-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,
|
2022-06-18 07:38:46 -07:00
|
|
|
oracleConfFilter: number,
|
2022-04-07 10:42:00 -07:00
|
|
|
tokenIndex: number,
|
2022-04-12 07:19:58 -07:00
|
|
|
name: string,
|
2022-07-11 08:08:32 -07:00
|
|
|
adjustmentFactor: number,
|
2022-04-09 08:09:06 -07:00
|
|
|
util0: number,
|
|
|
|
rate0: number,
|
|
|
|
util1: number,
|
|
|
|
rate1: number,
|
|
|
|
maxRate: number,
|
2022-05-09 23:03:46 -07:00
|
|
|
loanFeeRate: number,
|
|
|
|
loanOriginationFeeRate: number,
|
2022-04-09 08:09:06 -07:00
|
|
|
maintAssetWeight: number,
|
|
|
|
initAssetWeight: number,
|
|
|
|
maintLiabWeight: number,
|
|
|
|
initLiabWeight: number,
|
|
|
|
liquidationFee: number,
|
2022-04-07 10:42:00 -07:00
|
|
|
): Promise<TransactionSignature> {
|
2022-04-07 12:00:08 -07:00
|
|
|
return 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,
|
2022-06-18 07:38:46 -07:00
|
|
|
{
|
|
|
|
confFilter: {
|
|
|
|
val: I80F48.fromNumber(oracleConfFilter).getData(),
|
|
|
|
},
|
|
|
|
} as any, // future: nested custom types dont typecheck, fix if possible?
|
2022-07-11 08:08:32 -07:00
|
|
|
{ adjustmentFactor, util0, rate0, util1, rate1, maxRate },
|
2022-05-09 23:03:46 -07:00
|
|
|
loanFeeRate,
|
|
|
|
loanOriginationFeeRate,
|
2022-04-09 08:09:06 -07:00
|
|
|
maintAssetWeight,
|
|
|
|
initAssetWeight,
|
|
|
|
maintLiabWeight,
|
|
|
|
initLiabWeight,
|
|
|
|
liquidationFee,
|
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,
|
|
|
|
})
|
|
|
|
.rpc();
|
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,
|
|
|
|
): Promise<TransactionSignature> {
|
|
|
|
return 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,
|
|
|
|
fastListingAdmin: (this.program.provider as AnchorProvider).wallet
|
|
|
|
.publicKey,
|
|
|
|
mint: mintPk,
|
|
|
|
oracle: oraclePk,
|
|
|
|
payer: (this.program.provider as AnchorProvider).wallet.publicKey,
|
|
|
|
rent: SYSVAR_RENT_PUBKEY,
|
|
|
|
})
|
|
|
|
.rpc();
|
|
|
|
}
|
|
|
|
|
2022-07-05 10:31:47 -07:00
|
|
|
public async tokenEdit(
|
|
|
|
group: Group,
|
2022-08-17 23:48:45 -07:00
|
|
|
mintPk: PublicKey,
|
2022-09-02 00:42:47 -07:00
|
|
|
oracle: PublicKey | null,
|
|
|
|
oracleConfFilter: number | null,
|
|
|
|
groupInsuranceFund: boolean | null,
|
|
|
|
interestRateParams: InterestRateParams | null,
|
|
|
|
loanFeeRate: number | null,
|
|
|
|
loanOriginationFeeRate: number | null,
|
|
|
|
maintAssetWeight: number | null,
|
|
|
|
initAssetWeight: number | null,
|
|
|
|
maintLiabWeight: number | null,
|
|
|
|
initLiabWeight: number | null,
|
|
|
|
liquidationFee: number | null,
|
2022-07-05 10:31:47 -07:00
|
|
|
): Promise<TransactionSignature> {
|
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
|
|
|
|
2022-09-02 00:42:47 -07:00
|
|
|
let oracleConf;
|
|
|
|
if (oracleConfFilter !== null) {
|
|
|
|
oracleConf = {
|
|
|
|
confFilter: {
|
|
|
|
val: I80F48.fromNumber(oracleConfFilter).getData(),
|
|
|
|
},
|
|
|
|
} as any; // future: nested custom types dont typecheck, fix if possible?
|
|
|
|
} else {
|
|
|
|
oracleConf = null;
|
|
|
|
}
|
|
|
|
|
2022-07-05 10:31:47 -07:00
|
|
|
return await this.program.methods
|
|
|
|
.tokenEdit(
|
|
|
|
oracle,
|
2022-09-02 00:42:47 -07:00
|
|
|
oracleConf,
|
|
|
|
groupInsuranceFund,
|
|
|
|
interestRateParams,
|
2022-07-05 10:31:47 -07:00
|
|
|
loanFeeRate,
|
|
|
|
loanOriginationFeeRate,
|
|
|
|
maintAssetWeight,
|
|
|
|
initAssetWeight,
|
|
|
|
maintLiabWeight,
|
|
|
|
initLiabWeight,
|
|
|
|
liquidationFee,
|
|
|
|
)
|
|
|
|
.accounts({
|
|
|
|
group: group.publicKey,
|
|
|
|
admin: (this.program.provider as AnchorProvider).wallet.publicKey,
|
|
|
|
mintInfo: mintInfo.publicKey,
|
|
|
|
})
|
|
|
|
.remainingAccounts([
|
|
|
|
{
|
|
|
|
pubkey: bank.publicKey,
|
|
|
|
isWritable: true,
|
|
|
|
isSigner: false,
|
|
|
|
} as AccountMeta,
|
|
|
|
])
|
|
|
|
.rpc({ skipPreflight: true });
|
|
|
|
}
|
|
|
|
|
2022-06-09 09:27:31 -07:00
|
|
|
public async tokenDeregister(
|
|
|
|
group: Group,
|
2022-08-17 23:48:45 -07:00
|
|
|
mintPk: PublicKey,
|
2022-06-09 09:27:31 -07:00
|
|
|
): Promise<TransactionSignature> {
|
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,
|
|
|
|
);
|
|
|
|
if (!ai) {
|
|
|
|
const tx = new Transaction();
|
|
|
|
tx.add(
|
|
|
|
Token.createAssociatedTokenAccountInstruction(
|
|
|
|
ASSOCIATED_TOKEN_PROGRAM_ID,
|
|
|
|
TOKEN_PROGRAM_ID,
|
|
|
|
bank.mint,
|
|
|
|
dustVaultPk,
|
|
|
|
adminPk,
|
|
|
|
adminPk,
|
|
|
|
),
|
|
|
|
);
|
2022-08-31 02:41:12 -07:00
|
|
|
await (this.program.provider as AnchorProvider).sendAndConfirm(tx);
|
2022-06-29 00:11:14 -07:00
|
|
|
}
|
|
|
|
|
2022-06-09 09:27:31 -07:00
|
|
|
return 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-06-09 09:27:31 -07:00
|
|
|
.rpc();
|
|
|
|
}
|
|
|
|
|
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,
|
|
|
|
): Promise<TransactionSignature> {
|
2022-04-07 12:00:08 -07:00
|
|
|
return 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
|
|
|
})
|
|
|
|
.rpc();
|
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,
|
|
|
|
): Promise<TransactionSignature> {
|
|
|
|
return 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,
|
|
|
|
})
|
|
|
|
.rpc();
|
|
|
|
}
|
|
|
|
|
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,
|
|
|
|
): Promise<TransactionSignature> {
|
2022-04-07 12:00:08 -07:00
|
|
|
return 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-05-18 08:16:14 -07:00
|
|
|
payer: (this.program.provider as AnchorProvider).wallet.publicKey,
|
2022-04-07 12:00:08 -07:00
|
|
|
})
|
|
|
|
.rpc();
|
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-09-30 03:16:24 -07:00
|
|
|
public async getOrCreateMangoAccount(group: Group): Promise<MangoAccount> {
|
|
|
|
const clientOwner = (this.program.provider as AnchorProvider).wallet
|
|
|
|
.publicKey;
|
|
|
|
let mangoAccounts = await this.getMangoAccountsForOwner(
|
|
|
|
group,
|
|
|
|
(this.program.provider as AnchorProvider).wallet.publicKey,
|
|
|
|
);
|
|
|
|
if (mangoAccounts.length === 0) {
|
|
|
|
await this.createMangoAccount(group);
|
|
|
|
mangoAccounts = await this.getMangoAccountsForOwner(group, clientOwner);
|
2022-04-08 03:30:21 -07:00
|
|
|
}
|
2022-09-30 03:16:24 -07:00
|
|
|
return mangoAccounts.sort((a, b) => a.accountNum - b.accountNum)[0];
|
2022-04-08 03:30:21 -07:00
|
|
|
}
|
|
|
|
|
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,
|
2022-04-07 09:58:42 -07:00
|
|
|
): Promise<TransactionSignature> {
|
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,
|
|
|
|
serum3Count ?? 8,
|
|
|
|
perpCount ?? 0,
|
|
|
|
perpOoCount ?? 0,
|
|
|
|
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
|
|
|
|
|
|
|
return await sendTransaction(
|
|
|
|
this.program.provider as AnchorProvider,
|
2022-09-27 06:13:53 -07:00
|
|
|
[ix],
|
|
|
|
[],
|
2022-08-15 21:27:06 -07:00
|
|
|
{
|
|
|
|
postSendTxCallback: this.postSendTxCallback,
|
|
|
|
},
|
|
|
|
);
|
2022-04-07 09:58:42 -07:00
|
|
|
}
|
|
|
|
|
2022-09-15 00:57:48 -07:00
|
|
|
public async createAndFetchMangoAccount(
|
|
|
|
group: Group,
|
|
|
|
accountNumber?: number,
|
|
|
|
name?: string,
|
|
|
|
tokenCount?: number,
|
|
|
|
serum3Count?: number,
|
|
|
|
perpCount?: number,
|
|
|
|
perpOoCount?: number,
|
|
|
|
): Promise<MangoAccount | undefined> {
|
|
|
|
const accNum = accountNumber ?? 0;
|
|
|
|
await this.createMangoAccount(
|
|
|
|
group,
|
|
|
|
accNum,
|
|
|
|
name,
|
|
|
|
tokenCount,
|
|
|
|
serum3Count,
|
|
|
|
perpCount,
|
|
|
|
perpOoCount,
|
|
|
|
);
|
|
|
|
return await this.getMangoAccountForOwner(
|
|
|
|
group,
|
|
|
|
(this.program.provider as AnchorProvider).wallet.publicKey,
|
|
|
|
accNum,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2022-07-25 07:07:53 -07:00
|
|
|
public async expandMangoAccount(
|
|
|
|
group: Group,
|
|
|
|
account: MangoAccount,
|
2022-08-07 05:16:06 -07:00
|
|
|
tokenCount: number,
|
|
|
|
serum3Count: number,
|
|
|
|
perpCount: number,
|
|
|
|
perpOoCount: number,
|
2022-07-25 07:07:53 -07:00
|
|
|
): Promise<TransactionSignature> {
|
|
|
|
return await this.program.methods
|
2022-08-07 05:16:06 -07:00
|
|
|
.accountExpand(tokenCount, serum3Count, perpCount, perpOoCount)
|
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
|
|
|
})
|
|
|
|
.rpc();
|
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,
|
|
|
|
): Promise<TransactionSignature> {
|
2022-09-27 06:13:53 -07:00
|
|
|
const ix = await this.program.methods
|
2022-08-08 12:04:19 -07:00
|
|
|
.accountEdit(name ?? null, delegate ?? 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
|
|
|
|
|
|
|
return await sendTransaction(
|
|
|
|
this.program.provider as AnchorProvider,
|
2022-09-27 06:13:53 -07:00
|
|
|
[ix],
|
|
|
|
[],
|
2022-08-15 21:27:06 -07:00
|
|
|
{
|
|
|
|
postSendTxCallback: this.postSendTxCallback,
|
|
|
|
},
|
|
|
|
);
|
2022-07-05 10:31:47 -07:00
|
|
|
}
|
|
|
|
|
2022-09-29 06:51:09 -07:00
|
|
|
public async getMangoAccount(
|
|
|
|
mangoAccount: MangoAccount,
|
|
|
|
): Promise<MangoAccount> {
|
2022-04-08 03:30:21 -07:00
|
|
|
return MangoAccount.from(
|
|
|
|
mangoAccount.publicKey,
|
|
|
|
await this.program.account.mangoAccount.fetch(mangoAccount.publicKey),
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2022-09-29 06:51:09 -07:00
|
|
|
public async getMangoAccountForPublicKey(
|
|
|
|
mangoAccountPk: PublicKey,
|
|
|
|
): Promise<MangoAccount> {
|
2022-09-23 11:39:51 -07:00
|
|
|
return MangoAccount.from(
|
|
|
|
mangoAccountPk,
|
|
|
|
await this.program.account.mangoAccount.fetch(mangoAccountPk),
|
|
|
|
);
|
|
|
|
}
|
2022-09-27 08:33:51 -07:00
|
|
|
|
2022-09-29 06:51:09 -07:00
|
|
|
public async getMangoAccountWithSlot(
|
|
|
|
mangoAccountPk: PublicKey,
|
|
|
|
): 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;
|
|
|
|
const decodedMangoAccount = this.program.coder.accounts.decode(
|
|
|
|
'mangoAccount',
|
|
|
|
resp.value.data,
|
|
|
|
);
|
|
|
|
const mangoAccount = MangoAccount.from(mangoAccountPk, decodedMangoAccount);
|
|
|
|
return { slot: resp.context.slot, value: mangoAccount };
|
|
|
|
}
|
|
|
|
|
2022-08-08 07:31:38 -07:00
|
|
|
public async getMangoAccountForOwner(
|
|
|
|
group: Group,
|
|
|
|
ownerPk: PublicKey,
|
|
|
|
accountNumber: number,
|
2022-08-31 02:41:12 -07:00
|
|
|
): Promise<MangoAccount | undefined> {
|
|
|
|
const mangoAccounts = await this.getMangoAccountsForOwner(group, ownerPk);
|
|
|
|
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,
|
|
|
|
): Promise<MangoAccount[]> {
|
2022-04-07 12:00:08 -07:00
|
|
|
return (
|
|
|
|
await this.program.account.mangoAccount.all([
|
|
|
|
{
|
|
|
|
memcmp: {
|
|
|
|
bytes: group.publicKey.toBase58(),
|
2022-07-06 00:56:14 -07:00
|
|
|
offset: 8,
|
2022-04-07 12:00:08 -07:00
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
memcmp: {
|
|
|
|
bytes: ownerPk.toBase58(),
|
2022-07-06 00:56:14 -07:00
|
|
|
offset: 40,
|
2022-04-07 12:00:08 -07:00
|
|
|
},
|
|
|
|
},
|
|
|
|
])
|
|
|
|
).map((pa) => {
|
|
|
|
return MangoAccount.from(pa.publicKey, pa.account);
|
|
|
|
});
|
2022-04-07 09:58:42 -07:00
|
|
|
}
|
|
|
|
|
2022-08-13 10:36:09 -07:00
|
|
|
public async getAllMangoAccounts(group: Group): Promise<MangoAccount[]> {
|
|
|
|
return (
|
|
|
|
await this.program.account.mangoAccount.all([
|
|
|
|
{
|
|
|
|
memcmp: {
|
|
|
|
bytes: group.publicKey.toBase58(),
|
|
|
|
offset: 8,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
])
|
2022-04-07 12:00:08 -07:00
|
|
|
).map((pa) => {
|
|
|
|
return MangoAccount.from(pa.publicKey, pa.account);
|
|
|
|
});
|
2022-04-07 09:58:42 -07:00
|
|
|
}
|
|
|
|
|
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,
|
|
|
|
): Promise<TransactionSignature> {
|
2022-09-27 06:13:53 -07:00
|
|
|
const ix = await this.program.methods
|
2022-07-06 05:51:15 -07:00
|
|
|
.accountClose()
|
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
|
|
|
|
|
|
|
return await sendTransaction(
|
|
|
|
this.program.provider as AnchorProvider,
|
2022-09-27 06:13:53 -07:00
|
|
|
[ix],
|
|
|
|
[],
|
2022-09-02 10:50:01 -07:00
|
|
|
{
|
|
|
|
postSendTxCallback: this.postSendTxCallback,
|
|
|
|
},
|
|
|
|
);
|
2022-04-08 08:21:49 -07:00
|
|
|
}
|
|
|
|
|
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,
|
2022-08-07 05:16:23 -07:00
|
|
|
): Promise<TransactionSignature> {
|
2022-08-31 02:41:12 -07:00
|
|
|
const decimals = group.getMintDecimals(mintPk);
|
|
|
|
const nativeAmount = toNativeDecimals(amount, decimals).toNumber();
|
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,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
public async tokenDepositNative(
|
|
|
|
group: Group,
|
|
|
|
mangoAccount: MangoAccount,
|
2022-08-17 23:48:45 -07:00
|
|
|
mintPk: PublicKey,
|
2022-08-08 07:31:38 -07:00
|
|
|
nativeAmount: number,
|
2022-09-29 06:51:09 -07:00
|
|
|
): Promise<TransactionSignature> {
|
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,
|
|
|
|
);
|
|
|
|
|
2022-05-25 17:29:06 -07:00
|
|
|
let wrappedSolAccount: Keypair | undefined;
|
|
|
|
let preInstructions: TransactionInstruction[] = [];
|
|
|
|
let postInstructions: TransactionInstruction[] = [];
|
2022-08-04 10:42:41 -07:00
|
|
|
const additionalSigners: Signer[] = [];
|
2022-08-17 23:48:45 -07:00
|
|
|
if (mintPk.equals(WRAPPED_SOL_MINT)) {
|
2022-05-25 17:29:06 -07:00
|
|
|
wrappedSolAccount = new Keypair();
|
2022-08-08 07:31:38 -07:00
|
|
|
const lamports = nativeAmount + 1e7;
|
2022-05-25 17:29:06 -07:00
|
|
|
|
|
|
|
preInstructions = [
|
|
|
|
SystemProgram.createAccount({
|
|
|
|
fromPubkey: mangoAccount.owner,
|
|
|
|
newAccountPubkey: wrappedSolAccount.publicKey,
|
|
|
|
lamports,
|
|
|
|
space: 165,
|
|
|
|
programId: TOKEN_PROGRAM_ID,
|
|
|
|
}),
|
|
|
|
initializeAccount({
|
|
|
|
account: wrappedSolAccount.publicKey,
|
|
|
|
mint: WRAPPED_SOL_MINT,
|
|
|
|
owner: mangoAccount.owner,
|
|
|
|
}),
|
|
|
|
];
|
|
|
|
postInstructions = [
|
|
|
|
closeAccount({
|
|
|
|
source: wrappedSolAccount.publicKey,
|
|
|
|
destination: mangoAccount.owner,
|
|
|
|
owner: mangoAccount.owner,
|
|
|
|
}),
|
|
|
|
];
|
|
|
|
additionalSigners.push(wrappedSolAccount);
|
|
|
|
}
|
|
|
|
|
2022-04-07 09:58:42 -07:00
|
|
|
const healthRemainingAccounts: PublicKey[] =
|
2022-08-04 00:07:32 -07:00
|
|
|
this.buildHealthRemainingAccounts(
|
|
|
|
AccountRetriever.Fixed,
|
|
|
|
group,
|
|
|
|
[mangoAccount],
|
|
|
|
[bank],
|
2022-08-31 02:36:44 -07:00
|
|
|
[],
|
2022-08-04 00:07:32 -07:00
|
|
|
);
|
2022-04-07 09:58:42 -07:00
|
|
|
|
2022-09-27 06:13:53 -07:00
|
|
|
const ix = await this.program.methods
|
2022-08-08 07:31:38 -07:00
|
|
|
.tokenDeposit(new BN(nativeAmount))
|
2022-04-07 12:00:08 -07:00
|
|
|
.accounts({
|
|
|
|
group: group.publicKey,
|
|
|
|
account: mangoAccount.publicKey,
|
|
|
|
bank: bank.publicKey,
|
|
|
|
vault: bank.vault,
|
2022-08-22 02:02:01 -07:00
|
|
|
oracle: bank.oracle,
|
2022-05-25 17:29:06 -07:00
|
|
|
tokenAccount: wrappedSolAccount?.publicKey ?? 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
|
|
|
|
|
|
|
return await sendTransaction(
|
|
|
|
this.program.provider as AnchorProvider,
|
2022-09-27 06:13:53 -07:00
|
|
|
[...preInstructions, ix, ...postInstructions],
|
|
|
|
group.addressLookupTablesList,
|
2022-08-15 21:27:06 -07:00
|
|
|
{
|
2022-08-15 22:04:14 -07:00
|
|
|
additionalSigners,
|
2022-08-15 21:27:06 -07:00
|
|
|
postSendTxCallback: this.postSendTxCallback,
|
|
|
|
},
|
|
|
|
);
|
2022-04-07 09:58:42 -07:00
|
|
|
}
|
|
|
|
|
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,
|
2022-08-07 05:16:23 -07:00
|
|
|
): Promise<TransactionSignature> {
|
2022-08-17 23:48:45 -07:00
|
|
|
const nativeAmount = toNativeDecimals(
|
|
|
|
amount,
|
|
|
|
group.getMintDecimals(mintPk),
|
|
|
|
).toNumber();
|
2022-08-08 07:31:38 -07:00
|
|
|
return await this.tokenWithdrawNative(
|
|
|
|
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
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2022-08-03 09:05:16 -07:00
|
|
|
public async tokenWithdrawNative(
|
2022-07-04 03:09:33 -07:00
|
|
|
group: Group,
|
|
|
|
mangoAccount: MangoAccount,
|
2022-08-17 23:48:45 -07:00
|
|
|
mintPk: PublicKey,
|
2022-07-04 03:09:33 -07:00
|
|
|
nativeAmount: number,
|
|
|
|
allowBorrow: boolean,
|
2022-08-07 05:16:23 -07:00
|
|
|
): Promise<TransactionSignature> {
|
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,
|
|
|
|
);
|
|
|
|
|
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[] = [];
|
|
|
|
if (mintPk.equals(WRAPPED_SOL_MINT)) {
|
|
|
|
postInstructions.push(
|
|
|
|
closeAccount({
|
2022-09-01 03:11:31 -07:00
|
|
|
source: tokenAccountPk,
|
2022-09-01 02:25:58 -07:00
|
|
|
destination: mangoAccount.owner,
|
|
|
|
owner: mangoAccount.owner,
|
|
|
|
}),
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2022-07-04 03:09:33 -07:00
|
|
|
const healthRemainingAccounts: PublicKey[] =
|
2022-08-04 00:07:32 -07:00
|
|
|
this.buildHealthRemainingAccounts(
|
|
|
|
AccountRetriever.Fixed,
|
|
|
|
group,
|
|
|
|
[mangoAccount],
|
|
|
|
[bank],
|
2022-08-31 02:36:44 -07:00
|
|
|
[],
|
2022-08-04 00:07:32 -07:00
|
|
|
);
|
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,
|
|
|
|
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,
|
2022-08-03 09:05:16 -07:00
|
|
|
owner: mangoAccount.owner,
|
2022-07-04 03:09:33 -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-12 17:15:12 -07:00
|
|
|
|
2022-09-27 06:13:53 -07:00
|
|
|
return await sendTransaction(
|
|
|
|
this.program.provider as AnchorProvider,
|
|
|
|
[...preInstructions, ix, ...postInstructions],
|
|
|
|
group.addressLookupTablesList,
|
|
|
|
{
|
|
|
|
postSendTxCallback: this.postSendTxCallback,
|
|
|
|
},
|
|
|
|
);
|
2022-07-04 03:09:33 -07: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,
|
2022-04-07 23:29:35 -07:00
|
|
|
): Promise<TransactionSignature> {
|
|
|
|
return 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-06-11 04:49:45 -07:00
|
|
|
serumProgram: SERUM3_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
|
|
|
})
|
|
|
|
.rpc();
|
|
|
|
}
|
|
|
|
|
2022-06-09 09:27:31 -07:00
|
|
|
public async serum3deregisterMarket(
|
|
|
|
group: Group,
|
2022-08-31 02:36:44 -07:00
|
|
|
externalMarketPk: PublicKey,
|
2022-06-09 09:27:31 -07:00
|
|
|
): Promise<TransactionSignature> {
|
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,
|
|
|
|
);
|
|
|
|
|
2022-06-09 09:27:31 -07:00
|
|
|
return await this.program.methods
|
|
|
|
.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,
|
|
|
|
})
|
|
|
|
.rpc();
|
|
|
|
}
|
|
|
|
|
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,
|
2022-04-07 23:29:35 -07:00
|
|
|
): Promise<TransactionSignature> {
|
2022-09-01 01:48:50 -07:00
|
|
|
const serum3Market: Serum3Market = group.serum3MarketsMapByExternal.get(
|
|
|
|
externalMarketPk.toBase58(),
|
|
|
|
)!;
|
2022-04-08 03:30:21 -07:00
|
|
|
|
2022-04-07 23:29:35 -07:00
|
|
|
return await this.program.methods
|
|
|
|
.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
|
|
|
})
|
|
|
|
.rpc();
|
|
|
|
}
|
|
|
|
|
2022-06-09 09:27:31 -07:00
|
|
|
public async serum3CloseOpenOrders(
|
|
|
|
group: Group,
|
|
|
|
mangoAccount: MangoAccount,
|
2022-08-31 02:36:44 -07:00
|
|
|
externalMarketPk: PublicKey,
|
2022-06-09 09:27:31 -07:00
|
|
|
): Promise<TransactionSignature> {
|
2022-08-31 02:36:44 -07:00
|
|
|
const serum3Market = group.serum3MarketsMapByExternal.get(
|
|
|
|
externalMarketPk.toBase58(),
|
|
|
|
)!;
|
2022-06-09 09:27:31 -07:00
|
|
|
|
2022-08-04 10:42:41 -07:00
|
|
|
const openOrders = mangoAccount.serum3.find(
|
2022-06-09 09:27:31 -07:00
|
|
|
(account) => account.marketIndex === serum3Market.marketIndex,
|
|
|
|
)?.openOrders;
|
|
|
|
|
|
|
|
return await this.program.methods
|
|
|
|
.serum3CloseOpenOrders()
|
|
|
|
.accounts({
|
|
|
|
group: group.publicKey,
|
|
|
|
account: mangoAccount.publicKey,
|
|
|
|
serumMarket: serum3Market.publicKey,
|
|
|
|
serumProgram: serum3Market.serumProgram,
|
|
|
|
serumMarketExternal: serum3Market.serumMarketExternal,
|
|
|
|
openOrders,
|
|
|
|
solDestination: (this.program.provider as AnchorProvider).wallet
|
|
|
|
.publicKey,
|
|
|
|
})
|
|
|
|
.rpc();
|
|
|
|
}
|
|
|
|
|
2022-04-08 03:30:21 -07:00
|
|
|
public async serum3PlaceOrder(
|
|
|
|
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,
|
2022-09-29 06:51:09 -07:00
|
|
|
): Promise<TransactionSignature> {
|
2022-08-31 02:36:44 -07:00
|
|
|
const serum3Market = group.serum3MarketsMapByExternal.get(
|
|
|
|
externalMarketPk.toBase58(),
|
|
|
|
)!;
|
2022-09-29 06:51:09 -07:00
|
|
|
if (!mangoAccount.getSerum3Account(serum3Market.marketIndex)) {
|
2022-09-01 01:48:50 -07:00
|
|
|
await this.serum3CreateOpenOrders(
|
|
|
|
group,
|
|
|
|
mangoAccount,
|
|
|
|
serum3Market.serumMarketExternal,
|
|
|
|
);
|
2022-09-29 06:51:09 -07:00
|
|
|
await mangoAccount.reload(this);
|
2022-04-08 03:30:21 -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-04-08 03:30:21 -07:00
|
|
|
const serum3MarketExternalVaultSigner =
|
2022-08-31 02:36:44 -07:00
|
|
|
await generateSerum3MarketExternalVaultSignerAddress(
|
|
|
|
this.cluster,
|
|
|
|
serum3Market,
|
|
|
|
serum3MarketExternal,
|
2022-04-08 03:30:21 -07:00
|
|
|
);
|
|
|
|
|
|
|
|
const healthRemainingAccounts: PublicKey[] =
|
2022-08-31 02:36:44 -07:00
|
|
|
this.buildHealthRemainingAccounts(
|
|
|
|
AccountRetriever.Fixed,
|
|
|
|
group,
|
|
|
|
[mangoAccount],
|
|
|
|
[],
|
|
|
|
[],
|
|
|
|
);
|
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-08-31 02:36:44 -07:00
|
|
|
const maxQuoteQuantity = serum3MarketExternal.decoded.quoteLotSize
|
2022-09-29 06:51:09 -07:00
|
|
|
.mul(
|
|
|
|
new BN(
|
|
|
|
1 + group.getSerum3FeeRates(orderType === Serum3OrderType.postOnly),
|
|
|
|
),
|
|
|
|
)
|
2022-08-31 02:36:44 -07:00
|
|
|
.mul(
|
|
|
|
serum3MarketExternal
|
|
|
|
.baseSizeNumberToLots(size)
|
|
|
|
.mul(serum3MarketExternal.priceNumberToLots(price)),
|
|
|
|
);
|
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-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,
|
2022-09-29 06:51:09 -07:00
|
|
|
openOrders: mangoAccount.getSerum3Account(serum3Market.marketIndex)
|
2022-04-08 03:30:21 -07:00
|
|
|
?.openOrders,
|
|
|
|
serumMarket: serum3Market.publicKey,
|
2022-06-11 04:49:45 -07:00
|
|
|
serumProgram: SERUM3_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-08-30 00:55:19 -07:00
|
|
|
payerBank: group.getFirstBankByTokenIndex(payerTokenIndex).publicKey,
|
|
|
|
payerVault: group.getFirstBankByTokenIndex(payerTokenIndex).vault,
|
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
|
|
|
|
2022-09-27 06:13:53 -07:00
|
|
|
return await sendTransaction(
|
|
|
|
this.program.provider as AnchorProvider,
|
|
|
|
[ix],
|
|
|
|
group.addressLookupTablesList,
|
|
|
|
{
|
|
|
|
postSendTxCallback: this.postSendTxCallback,
|
|
|
|
},
|
|
|
|
);
|
2022-04-08 03:30:21 -07:00
|
|
|
}
|
|
|
|
|
2022-06-09 09:27:31 -07:00
|
|
|
async serum3CancelAllorders(
|
|
|
|
group: Group,
|
|
|
|
mangoAccount: MangoAccount,
|
2022-08-31 02:36:44 -07:00
|
|
|
externalMarketPk: PublicKey,
|
2022-06-09 09:27:31 -07:00
|
|
|
limit: number,
|
2022-09-29 06:51:09 -07:00
|
|
|
): Promise<TransactionSignature> {
|
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
|
|
|
|
2022-09-27 06:13:53 -07:00
|
|
|
const ix = await this.program.methods
|
2022-06-09 09:27:31 -07:00
|
|
|
.serum3CancelAllOrders(limit)
|
|
|
|
.accounts({
|
|
|
|
group: group.publicKey,
|
|
|
|
account: mangoAccount.publicKey,
|
|
|
|
owner: (this.program.provider as AnchorProvider).wallet.publicKey,
|
2022-09-29 06:51:09 -07:00
|
|
|
openOrders: mangoAccount.getSerum3Account(serum3Market.marketIndex)
|
2022-06-09 09:27:31 -07:00
|
|
|
?.openOrders,
|
|
|
|
serumMarket: serum3Market.publicKey,
|
2022-06-11 04:49:45 -07:00
|
|
|
serumProgram: SERUM3_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();
|
2022-09-13 22:44:00 -07:00
|
|
|
|
2022-09-27 06:13:53 -07:00
|
|
|
return await sendTransaction(
|
|
|
|
this.program.provider as AnchorProvider,
|
|
|
|
[ix],
|
|
|
|
group.addressLookupTablesList,
|
|
|
|
{
|
|
|
|
postSendTxCallback: this.postSendTxCallback,
|
|
|
|
},
|
|
|
|
);
|
2022-06-09 09:27:31 -07:00
|
|
|
}
|
|
|
|
|
2022-04-08 11:47:12 -07:00
|
|
|
async serum3SettleFunds(
|
|
|
|
group: Group,
|
|
|
|
mangoAccount: MangoAccount,
|
2022-08-31 02:36:44 -07:00
|
|
|
externalMarketPk: PublicKey,
|
2022-04-08 11:47:12 -07:00
|
|
|
): Promise<TransactionSignature> {
|
2022-08-31 02:36:44 -07:00
|
|
|
const serum3Market = group.serum3MarketsMapByExternal.get(
|
|
|
|
externalMarketPk.toBase58(),
|
|
|
|
)!;
|
2022-09-29 06:51:09 -07:00
|
|
|
const serum3MarketExternal = group.serum3ExternalMarketsMap.get(
|
2022-08-31 02:36:44 -07:00
|
|
|
externalMarketPk.toBase58(),
|
|
|
|
)!;
|
2022-04-08 11:47:12 -07:00
|
|
|
const serum3MarketExternalVaultSigner =
|
2022-08-31 02:36:44 -07:00
|
|
|
await generateSerum3MarketExternalVaultSignerAddress(
|
|
|
|
this.cluster,
|
|
|
|
serum3Market,
|
|
|
|
serum3MarketExternal,
|
2022-04-08 11:47:12 -07:00
|
|
|
);
|
|
|
|
|
2022-09-27 06:13:53 -07:00
|
|
|
const ix = await this.program.methods
|
2022-04-08 11:47:12 -07:00
|
|
|
.serum3SettleFunds()
|
|
|
|
.accounts({
|
|
|
|
group: group.publicKey,
|
|
|
|
account: mangoAccount.publicKey,
|
2022-05-18 08:16:14 -07:00
|
|
|
owner: (this.program.provider as AnchorProvider).wallet.publicKey,
|
2022-09-29 06:51:09 -07:00
|
|
|
openOrders: mangoAccount.getSerum3Account(serum3Market.marketIndex)
|
2022-04-08 11:47:12 -07:00
|
|
|
?.openOrders,
|
|
|
|
serumMarket: serum3Market.publicKey,
|
2022-06-11 04:49:45 -07:00
|
|
|
serumProgram: SERUM3_PROGRAM_ID[this.cluster],
|
2022-04-08 11:47:12 -07:00
|
|
|
serumMarketExternal: serum3Market.serumMarketExternal,
|
|
|
|
marketBaseVault: serum3MarketExternal.decoded.baseVault,
|
|
|
|
marketQuoteVault: serum3MarketExternal.decoded.quoteVault,
|
|
|
|
marketVaultSigner: serum3MarketExternalVaultSigner,
|
2022-08-17 23:48:45 -07:00
|
|
|
quoteBank: group.getFirstBankByTokenIndex(serum3Market.quoteTokenIndex)
|
|
|
|
.publicKey,
|
|
|
|
quoteVault: group.getFirstBankByTokenIndex(serum3Market.quoteTokenIndex)
|
|
|
|
.vault,
|
|
|
|
baseBank: group.getFirstBankByTokenIndex(serum3Market.baseTokenIndex)
|
|
|
|
.publicKey,
|
|
|
|
baseVault: group.getFirstBankByTokenIndex(serum3Market.baseTokenIndex)
|
|
|
|
.vault,
|
2022-04-08 11:47:12 -07:00
|
|
|
})
|
2022-09-27 06:13:53 -07:00
|
|
|
.instruction();
|
2022-09-13 22:44:00 -07:00
|
|
|
|
2022-09-27 06:13:53 -07:00
|
|
|
return await sendTransaction(
|
|
|
|
this.program.provider as AnchorProvider,
|
|
|
|
[ix],
|
|
|
|
group.addressLookupTablesList,
|
|
|
|
{
|
|
|
|
postSendTxCallback: this.postSendTxCallback,
|
|
|
|
},
|
|
|
|
);
|
2022-04-08 11:47:12 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
async serum3CancelOrder(
|
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,
|
|
|
|
): Promise<TransactionSignature> {
|
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-06-11 04:49:45 -07:00
|
|
|
serumProgram: SERUM3_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-09-27 06:13:53 -07:00
|
|
|
return await sendTransaction(
|
|
|
|
this.program.provider as AnchorProvider,
|
|
|
|
[ix],
|
|
|
|
group.addressLookupTablesList,
|
|
|
|
{
|
|
|
|
postSendTxCallback: this.postSendTxCallback,
|
|
|
|
},
|
|
|
|
);
|
2022-04-08 07:57:37 -07:00
|
|
|
}
|
|
|
|
|
2022-05-11 04:33:01 -07:00
|
|
|
/// perps
|
|
|
|
|
|
|
|
async perpCreateMarket(
|
|
|
|
group: Group,
|
|
|
|
oraclePk: PublicKey,
|
|
|
|
perpMarketIndex: number,
|
|
|
|
name: string,
|
2022-06-18 07:38:46 -07:00
|
|
|
oracleConfFilter: number,
|
2022-09-21 00:42:45 -07:00
|
|
|
baseDecimals: number,
|
2022-05-11 04:33:01 -07:00
|
|
|
quoteTokenIndex: number,
|
|
|
|
quoteLotSize: number,
|
|
|
|
baseLotSize: number,
|
|
|
|
maintAssetWeight: number,
|
|
|
|
initAssetWeight: number,
|
|
|
|
maintLiabWeight: number,
|
|
|
|
initLiabWeight: number,
|
|
|
|
liquidationFee: number,
|
|
|
|
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,
|
|
|
|
trustedMarket: boolean,
|
2022-09-29 03:59:55 -07:00
|
|
|
settleFeeFlat: number,
|
|
|
|
settleFeeAmountThreshold: number,
|
|
|
|
settleFeeFractionLowHealth: number,
|
2022-05-11 04:33:01 -07:00
|
|
|
): Promise<TransactionSignature> {
|
|
|
|
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,
|
|
|
|
);
|
|
|
|
|
2022-05-11 04:33:01 -07:00
|
|
|
return await this.program.methods
|
|
|
|
.perpCreateMarket(
|
|
|
|
perpMarketIndex,
|
|
|
|
name,
|
2022-06-18 07:38:46 -07:00
|
|
|
{
|
|
|
|
confFilter: {
|
|
|
|
val: I80F48.fromNumber(oracleConfFilter).getData(),
|
|
|
|
},
|
|
|
|
} as any, // future: nested custom types dont typecheck, fix if possible?
|
2022-09-21 00:42:45 -07:00
|
|
|
baseDecimals,
|
2022-05-11 04:33:01 -07:00
|
|
|
new BN(quoteLotSize),
|
|
|
|
new BN(baseLotSize),
|
|
|
|
maintAssetWeight,
|
|
|
|
initAssetWeight,
|
|
|
|
maintLiabWeight,
|
|
|
|
initLiabWeight,
|
|
|
|
liquidationFee,
|
|
|
|
makerFee,
|
|
|
|
takerFee,
|
2022-05-17 06:06:29 -07:00
|
|
|
minFunding,
|
|
|
|
maxFunding,
|
|
|
|
new BN(impactQuantity),
|
2022-09-12 06:25:50 -07:00
|
|
|
groupInsuranceFund,
|
|
|
|
trustedMarket,
|
2022-09-27 06:13:53 -07:00
|
|
|
feePenalty,
|
2022-09-29 03:59:55 -07:00
|
|
|
settleFeeFlat,
|
|
|
|
settleFeeAmountThreshold,
|
|
|
|
settleFeeFractionLowHealth,
|
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
|
|
|
})
|
|
|
|
.preInstructions([
|
2022-08-01 09:35:26 -07:00
|
|
|
// book sides
|
2022-05-11 04:33:01 -07:00
|
|
|
SystemProgram.createAccount({
|
|
|
|
programId: this.program.programId,
|
2022-09-30 04:33:21 -07:00
|
|
|
space: bookSideSize,
|
2022-05-11 04:33:01 -07:00
|
|
|
lamports:
|
|
|
|
await this.program.provider.connection.getMinimumBalanceForRentExemption(
|
2022-09-30 04:33:21 -07:00
|
|
|
bookSideSize,
|
2022-05-11 04:33:01 -07:00
|
|
|
),
|
2022-05-18 08:16:14 -07:00
|
|
|
fromPubkey: (this.program.provider as AnchorProvider).wallet
|
|
|
|
.publicKey,
|
2022-05-11 04:33:01 -07:00
|
|
|
newAccountPubkey: bids.publicKey,
|
|
|
|
}),
|
|
|
|
SystemProgram.createAccount({
|
|
|
|
programId: this.program.programId,
|
2022-09-30 04:33:21 -07:00
|
|
|
space: bookSideSize,
|
2022-05-11 04:33:01 -07:00
|
|
|
lamports:
|
|
|
|
await this.program.provider.connection.getMinimumBalanceForRentExemption(
|
2022-09-30 04:33:21 -07:00
|
|
|
bookSideSize,
|
2022-05-11 04:33:01 -07:00
|
|
|
),
|
2022-05-18 08:16:14 -07:00
|
|
|
fromPubkey: (this.program.provider as AnchorProvider).wallet
|
|
|
|
.publicKey,
|
2022-05-11 04:33:01 -07:00
|
|
|
newAccountPubkey: asks.publicKey,
|
|
|
|
}),
|
2022-08-01 09:35:26 -07:00
|
|
|
// event queue
|
2022-05-11 04:33:01 -07:00
|
|
|
SystemProgram.createAccount({
|
|
|
|
programId: this.program.programId,
|
2022-09-30 04:33:21 -07:00
|
|
|
space: eventQueueSize,
|
2022-05-11 04:33:01 -07:00
|
|
|
lamports:
|
|
|
|
await this.program.provider.connection.getMinimumBalanceForRentExemption(
|
2022-09-30 04:33:21 -07:00
|
|
|
eventQueueSize,
|
2022-05-11 04:33:01 -07:00
|
|
|
),
|
2022-05-18 08:16:14 -07:00
|
|
|
fromPubkey: (this.program.provider as AnchorProvider).wallet
|
|
|
|
.publicKey,
|
2022-05-11 04:33:01 -07:00
|
|
|
newAccountPubkey: eventQueue.publicKey,
|
|
|
|
}),
|
|
|
|
])
|
|
|
|
.signers([bids, asks, eventQueue])
|
|
|
|
.rpc();
|
|
|
|
}
|
|
|
|
|
2022-07-05 10:31:47 -07:00
|
|
|
async perpEditMarket(
|
|
|
|
group: Group,
|
2022-09-29 06:51:09 -07:00
|
|
|
perpMarketIndex: PerpMarketIndex,
|
2022-07-05 10:31:47 -07:00
|
|
|
oracle: PublicKey,
|
|
|
|
oracleConfFilter: number,
|
2022-09-21 00:42:45 -07:00
|
|
|
baseDecimals: number,
|
2022-07-05 10:31:47 -07:00
|
|
|
maintAssetWeight: number,
|
|
|
|
initAssetWeight: number,
|
|
|
|
maintLiabWeight: number,
|
|
|
|
initLiabWeight: number,
|
|
|
|
liquidationFee: number,
|
|
|
|
makerFee: number,
|
|
|
|
takerFee: number,
|
2022-09-22 10:03:45 -07:00
|
|
|
feePenalty: number,
|
2022-07-05 10:31:47 -07:00
|
|
|
minFunding: number,
|
|
|
|
maxFunding: number,
|
|
|
|
impactQuantity: number,
|
2022-09-12 06:25:50 -07:00
|
|
|
groupInsuranceFund: boolean,
|
|
|
|
trustedMarket: boolean,
|
2022-09-29 03:59:55 -07:00
|
|
|
settleFeeFlat: number,
|
|
|
|
settleFeeAmountThreshold: number,
|
|
|
|
settleFeeFractionLowHealth: number,
|
2022-07-05 10:31:47 -07:00
|
|
|
): Promise<TransactionSignature> {
|
2022-09-29 06:51:09 -07:00
|
|
|
const perpMarket = group.getPerpMarketByMarketIndex(perpMarketIndex);
|
2022-07-05 10:31:47 -07:00
|
|
|
|
|
|
|
return await this.program.methods
|
|
|
|
.perpEditMarket(
|
|
|
|
oracle,
|
|
|
|
{
|
|
|
|
confFilter: {
|
|
|
|
val: I80F48.fromNumber(oracleConfFilter).getData(),
|
|
|
|
},
|
|
|
|
} as any, // future: nested custom types dont typecheck, fix if possible?
|
2022-09-21 00:42:45 -07:00
|
|
|
baseDecimals,
|
2022-07-05 10:31:47 -07:00
|
|
|
maintAssetWeight,
|
|
|
|
initAssetWeight,
|
|
|
|
maintLiabWeight,
|
|
|
|
initLiabWeight,
|
|
|
|
liquidationFee,
|
|
|
|
makerFee,
|
|
|
|
takerFee,
|
|
|
|
minFunding,
|
|
|
|
maxFunding,
|
|
|
|
new BN(impactQuantity),
|
2022-09-12 06:25:50 -07:00
|
|
|
groupInsuranceFund,
|
|
|
|
trustedMarket,
|
2022-09-27 06:13:53 -07:00
|
|
|
feePenalty,
|
2022-09-29 03:59:55 -07:00
|
|
|
settleFeeFlat,
|
|
|
|
settleFeeAmountThreshold,
|
|
|
|
settleFeeFractionLowHealth,
|
2022-07-05 10:31:47 -07:00
|
|
|
)
|
|
|
|
.accounts({
|
|
|
|
group: group.publicKey,
|
|
|
|
admin: (this.program.provider as AnchorProvider).wallet.publicKey,
|
|
|
|
perpMarket: perpMarket.publicKey,
|
|
|
|
})
|
|
|
|
.rpc();
|
|
|
|
}
|
|
|
|
|
2022-06-09 09:27:31 -07:00
|
|
|
async perpCloseMarket(
|
|
|
|
group: Group,
|
2022-09-29 06:51:09 -07:00
|
|
|
perpMarketIndex: PerpMarketIndex,
|
2022-06-09 09:27:31 -07:00
|
|
|
): Promise<TransactionSignature> {
|
2022-09-29 06:51:09 -07:00
|
|
|
const perpMarket = group.getPerpMarketByMarketIndex(perpMarketIndex);
|
2022-06-09 09:27:31 -07:00
|
|
|
|
|
|
|
return await this.program.methods
|
|
|
|
.perpCloseMarket()
|
|
|
|
.accounts({
|
|
|
|
group: group.publicKey,
|
|
|
|
admin: (this.program.provider as AnchorProvider).wallet.publicKey,
|
|
|
|
perpMarket: perpMarket.publicKey,
|
|
|
|
asks: perpMarket.asks,
|
|
|
|
bids: perpMarket.bids,
|
|
|
|
eventQueue: perpMarket.eventQueue,
|
|
|
|
solDestination: (this.program.provider as AnchorProvider).wallet
|
|
|
|
.publicKey,
|
|
|
|
})
|
|
|
|
.rpc();
|
|
|
|
}
|
|
|
|
|
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),
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2022-09-15 00:57:48 -07:00
|
|
|
async perpDeactivatePosition(
|
|
|
|
group: Group,
|
|
|
|
mangoAccount: MangoAccount,
|
2022-09-29 06:51:09 -07:00
|
|
|
perpMarketIndex: PerpMarketIndex,
|
2022-09-15 00:57:48 -07:00
|
|
|
): Promise<TransactionSignature> {
|
2022-09-29 06:51:09 -07:00
|
|
|
const perpMarket = group.getPerpMarketByMarketIndex(perpMarketIndex);
|
2022-09-15 00:57:48 -07:00
|
|
|
const healthRemainingAccounts: PublicKey[] =
|
|
|
|
this.buildHealthRemainingAccounts(
|
|
|
|
AccountRetriever.Fixed,
|
|
|
|
group,
|
|
|
|
[mangoAccount],
|
|
|
|
[],
|
|
|
|
[],
|
|
|
|
);
|
|
|
|
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),
|
|
|
|
),
|
|
|
|
)
|
|
|
|
.rpc();
|
|
|
|
}
|
|
|
|
|
2022-05-11 04:33:01 -07:00
|
|
|
async perpPlaceOrder(
|
|
|
|
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,
|
|
|
|
maxQuoteQuantity: number,
|
2022-05-11 04:33:01 -07:00
|
|
|
clientOrderId: number,
|
2022-09-20 03:57:01 -07:00
|
|
|
orderType: PerpOrderType,
|
2022-05-11 04:33:01 -07:00
|
|
|
expiryTimestamp: number,
|
|
|
|
limit: number,
|
2022-09-20 03:57:01 -07:00
|
|
|
): Promise<TransactionSignature> {
|
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(
|
|
|
|
AccountRetriever.Fixed,
|
|
|
|
group,
|
|
|
|
[mangoAccount],
|
2022-09-21 03:50:10 -07:00
|
|
|
// Settlement token bank, because a position for it may be created
|
2022-09-29 06:51:09 -07:00
|
|
|
[group.getFirstBankByTokenIndex(0 as TokenIndex)],
|
2022-08-31 02:36:44 -07:00
|
|
|
[perpMarket],
|
|
|
|
);
|
2022-09-27 06:13:53 -07:00
|
|
|
const ix = 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-05-11 04:33:01 -07:00
|
|
|
new BN(clientOrderId),
|
|
|
|
orderType,
|
|
|
|
new BN(expiryTimestamp),
|
|
|
|
limit,
|
|
|
|
)
|
|
|
|
.accounts({
|
|
|
|
group: group.publicKey,
|
|
|
|
account: mangoAccount.publicKey,
|
|
|
|
perpMarket: perpMarket.publicKey,
|
|
|
|
asks: perpMarket.asks,
|
|
|
|
bids: perpMarket.bids,
|
|
|
|
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();
|
|
|
|
|
|
|
|
return await sendTransaction(
|
|
|
|
this.program.provider as AnchorProvider,
|
|
|
|
[ix],
|
|
|
|
group.addressLookupTablesList,
|
|
|
|
{
|
|
|
|
postSendTxCallback: this.postSendTxCallback,
|
|
|
|
},
|
|
|
|
);
|
2022-05-11 04:33:01 -07:00
|
|
|
}
|
|
|
|
|
2022-09-20 03:57:01 -07:00
|
|
|
async perpCancelAllOrders(
|
|
|
|
group: Group,
|
|
|
|
mangoAccount: MangoAccount,
|
2022-09-29 06:51:09 -07:00
|
|
|
perpMarketIndex: PerpMarketIndex,
|
2022-09-20 03:57:01 -07:00
|
|
|
limit: number,
|
|
|
|
): Promise<TransactionSignature> {
|
2022-09-29 06:51:09 -07:00
|
|
|
const perpMarket = group.getPerpMarketByMarketIndex(perpMarketIndex);
|
2022-09-27 06:13:53 -07:00
|
|
|
const ix = await this.program.methods
|
2022-09-20 03:57:01 -07:00
|
|
|
.perpCancelAllOrders(limit)
|
|
|
|
.accounts({
|
|
|
|
group: group.publicKey,
|
|
|
|
account: mangoAccount.publicKey,
|
|
|
|
perpMarket: perpMarket.publicKey,
|
|
|
|
asks: perpMarket.asks,
|
|
|
|
bids: perpMarket.bids,
|
|
|
|
owner: (this.program.provider as AnchorProvider).wallet.publicKey,
|
|
|
|
})
|
2022-09-27 06:13:53 -07:00
|
|
|
.instruction();
|
|
|
|
|
|
|
|
return await sendTransaction(
|
|
|
|
this.program.provider as AnchorProvider,
|
|
|
|
[ix],
|
|
|
|
group.addressLookupTablesList,
|
|
|
|
{
|
|
|
|
postSendTxCallback: this.postSendTxCallback,
|
|
|
|
},
|
|
|
|
);
|
2022-09-20 03:57:01 -07:00
|
|
|
}
|
|
|
|
|
2022-09-15 00:57:48 -07:00
|
|
|
async perpConsumeEvents(
|
|
|
|
group: Group,
|
2022-09-29 06:51:09 -07:00
|
|
|
perpMarketIndex: PerpMarketIndex,
|
2022-09-15 00:57:48 -07:00
|
|
|
accounts: PublicKey[],
|
|
|
|
limit: number,
|
|
|
|
): Promise<TransactionSignature> {
|
2022-09-29 06:51:09 -07:00
|
|
|
const perpMarket = group.getPerpMarketByMarketIndex(perpMarketIndex);
|
2022-09-15 00:57:48 -07:00
|
|
|
return await this.program.methods
|
|
|
|
.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),
|
|
|
|
),
|
|
|
|
)
|
|
|
|
.rpc();
|
|
|
|
}
|
|
|
|
|
|
|
|
async perpConsumeAllEvents(
|
|
|
|
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
|
|
|
}
|
|
|
|
}
|
|
|
|
|
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-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-08-17 03:36:55 -07:00
|
|
|
flashLoanType: FlashLoanType;
|
2022-05-24 11:10:01 -07:00
|
|
|
}): Promise<TransactionSignature> {
|
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(
|
|
|
|
AccountRetriever.Fixed,
|
|
|
|
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,
|
|
|
|
mangoAccount.owner,
|
|
|
|
);
|
|
|
|
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(
|
2022-06-29 20:36:57 -07:00
|
|
|
mangoAccount.owner,
|
|
|
|
mangoAccount.owner,
|
|
|
|
inputBank.mint,
|
|
|
|
),
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2022-08-04 10:42:41 -07:00
|
|
|
const outputTokenAccountPk = await getAssociatedTokenAddress(
|
2022-06-29 20:36:57 -07:00
|
|
|
outputBank.mint,
|
|
|
|
mangoAccount.owner,
|
|
|
|
);
|
|
|
|
const outputTokenAccExists =
|
|
|
|
await this.program.provider.connection.getAccountInfo(
|
|
|
|
outputTokenAccountPk,
|
|
|
|
);
|
|
|
|
if (!outputTokenAccExists) {
|
|
|
|
preInstructions.push(
|
2022-08-09 15:27:24 -07:00
|
|
|
await createAssociatedTokenAccountIdempotentInstruction(
|
2022-06-29 20:36:57 -07:00
|
|
|
mangoAccount.owner,
|
|
|
|
mangoAccount.owner,
|
|
|
|
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
|
2022-08-17 03:36:55 -07:00
|
|
|
.flashLoanEnd(flashLoanType)
|
2022-06-29 20:36:57 -07:00
|
|
|
.accounts({
|
|
|
|
account: mangoAccount.publicKey,
|
|
|
|
owner: (this.program.provider as AnchorProvider).wallet.publicKey,
|
|
|
|
})
|
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-07-06 21:45:01 -07:00
|
|
|
toNativeDecimals(amountIn, inputBank.mintDecimals),
|
|
|
|
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-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();
|
|
|
|
|
2022-09-27 06:13:53 -07:00
|
|
|
return await sendTransaction(
|
|
|
|
this.program.provider as AnchorProvider,
|
|
|
|
[
|
|
|
|
...preInstructions,
|
|
|
|
flashLoanBeginIx,
|
|
|
|
...userDefinedInstructions.filter((ix) => ix.keys.length > 2),
|
|
|
|
flashLoanEndIx,
|
|
|
|
],
|
|
|
|
group.addressLookupTablesList,
|
|
|
|
{
|
|
|
|
postSendTxCallback: this.postSendTxCallback,
|
|
|
|
},
|
|
|
|
);
|
2022-07-06 21:45:01 -07:00
|
|
|
}
|
2022-08-03 09:05:16 -07:00
|
|
|
|
2022-09-29 06:51:09 -07:00
|
|
|
async updateIndexAndRate(
|
|
|
|
group: Group,
|
|
|
|
mintPk: PublicKey,
|
|
|
|
): Promise<TransactionSignature> {
|
2022-08-17 23:48:45 -07:00
|
|
|
// TODO: handle updating multiple banks
|
|
|
|
const bank = group.getFirstBankByMint(mintPk);
|
|
|
|
const mintInfo = group.mintInfosMapByMint.get(mintPk.toString())!;
|
2022-08-07 05:16:06 -07:00
|
|
|
|
2022-09-29 06:51:09 -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,
|
|
|
|
])
|
2022-08-07 05:16:06 -07:00
|
|
|
.rpc();
|
2022-08-05 10:11:44 -07:00
|
|
|
}
|
|
|
|
|
2022-08-04 00:07:32 -07:00
|
|
|
/// liquidations
|
|
|
|
|
|
|
|
async liqTokenWithToken(
|
|
|
|
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,
|
2022-09-29 06:51:09 -07:00
|
|
|
): Promise<TransactionSignature> {
|
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(
|
|
|
|
AccountRetriever.Scanning,
|
|
|
|
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();
|
|
|
|
|
|
|
|
return await sendTransaction(
|
|
|
|
this.program.provider as AnchorProvider,
|
|
|
|
[ix],
|
|
|
|
group.addressLookupTablesList,
|
|
|
|
{
|
|
|
|
postSendTxCallback: this.postSendTxCallback,
|
|
|
|
},
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2022-09-29 06:51:09 -07:00
|
|
|
async altSet(
|
|
|
|
group: Group,
|
|
|
|
addressLookupTable: PublicKey,
|
|
|
|
index: number,
|
|
|
|
): Promise<TransactionSignature> {
|
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();
|
|
|
|
|
|
|
|
return await sendTransaction(
|
|
|
|
this.program.provider as AnchorProvider,
|
|
|
|
[ix],
|
|
|
|
group.addressLookupTablesList,
|
|
|
|
{
|
|
|
|
postSendTxCallback: this.postSendTxCallback,
|
|
|
|
},
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
async altExtend(
|
|
|
|
group: Group,
|
|
|
|
addressLookupTable: PublicKey,
|
|
|
|
index: number,
|
|
|
|
pks: PublicKey[],
|
2022-09-29 06:51:09 -07:00
|
|
|
): Promise<TransactionSignature> {
|
2022-09-27 06:13:53 -07:00
|
|
|
return await this.program.methods
|
|
|
|
.altExtend(index, pks)
|
|
|
|
.accounts({
|
|
|
|
group: group.publicKey,
|
|
|
|
admin: (this.program.provider as AnchorProvider).wallet.publicKey,
|
|
|
|
payer: (this.program.provider as AnchorProvider).wallet.publicKey,
|
|
|
|
addressLookupTable,
|
|
|
|
})
|
2022-08-04 00:07:32 -07:00
|
|
|
.rpc();
|
|
|
|
}
|
2022-06-18 07:31:28 -07:00
|
|
|
|
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-08-12 17:15:12 -07:00
|
|
|
opts: any = {},
|
2022-08-17 23:48:45 -07:00
|
|
|
getIdsFromApi: IdsSource = 'api',
|
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-08-17 23:48:45 -07:00
|
|
|
getIdsFromApi,
|
2022-06-21 11:04:21 -07:00
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
static connectForGroupName(
|
|
|
|
provider: Provider,
|
|
|
|
groupName: string,
|
|
|
|
): MangoClient {
|
|
|
|
// TODO: use IDL on chain or in repository? decide...
|
|
|
|
// Alternatively we could fetch IDL from chain.
|
|
|
|
// const idl = await Program.fetchIdl(MANGO_V4_ID, provider);
|
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
|
|
|
|
2022-04-07 09:58:42 -07:00
|
|
|
/// private
|
2022-04-07 08:58:20 -07:00
|
|
|
|
2022-09-29 06:51:09 -07:00
|
|
|
private buildHealthRemainingAccounts(
|
2022-08-03 09:05:16 -07:00
|
|
|
retriever: AccountRetriever,
|
|
|
|
group: Group,
|
|
|
|
mangoAccounts: MangoAccount[],
|
2022-08-31 02:36:44 -07:00
|
|
|
banks: Bank[],
|
|
|
|
perpMarkets: PerpMarket[],
|
2022-08-10 01:15:28 -07:00
|
|
|
): PublicKey[] {
|
2022-08-03 09:05:16 -07:00
|
|
|
if (retriever === AccountRetriever.Fixed) {
|
|
|
|
return this.buildFixedAccountRetrieverHealthAccounts(
|
|
|
|
group,
|
|
|
|
mangoAccounts[0],
|
|
|
|
banks,
|
2022-08-31 02:36:44 -07:00
|
|
|
perpMarkets,
|
2022-08-03 09:05:16 -07:00
|
|
|
);
|
|
|
|
} else {
|
|
|
|
return this.buildScanningAccountRetrieverHealthAccounts(
|
|
|
|
group,
|
|
|
|
mangoAccounts,
|
|
|
|
banks,
|
2022-08-31 02:36:44 -07:00
|
|
|
perpMarkets,
|
2022-08-03 09:05:16 -07:00
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-09-29 06:51:09 -07:00
|
|
|
private buildFixedAccountRetrieverHealthAccounts(
|
2022-04-07 08:58:20 -07:00
|
|
|
group: Group,
|
2022-04-07 09:58:42 -07:00
|
|
|
mangoAccount: MangoAccount,
|
2022-08-31 02:36:44 -07:00
|
|
|
// Banks and perpMarkets for whom positions don't exist on mango account,
|
|
|
|
// but user would potentially open new positions.
|
|
|
|
banks: Bank[],
|
|
|
|
perpMarkets: PerpMarket[],
|
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
|
|
|
|
2022-08-10 01:15:28 -07:00
|
|
|
const allTokenIndices = mangoAccount.tokens.map(
|
|
|
|
(token) => token.tokenIndex,
|
|
|
|
);
|
2022-08-18 23:41:57 -07:00
|
|
|
|
2022-08-10 01:15:28 -07:00
|
|
|
if (banks) {
|
2022-05-31 18:38:47 -07:00
|
|
|
for (const bank of banks) {
|
2022-08-10 01:15:28 -07:00
|
|
|
if (allTokenIndices.indexOf(bank.tokenIndex) < 0) {
|
|
|
|
allTokenIndices[
|
|
|
|
mangoAccount.tokens.findIndex(
|
|
|
|
(token, index) =>
|
|
|
|
!token.isActive() &&
|
|
|
|
allTokenIndices[index] == TokenPosition.TokenIndexUnset,
|
|
|
|
)
|
|
|
|
] = bank.tokenIndex;
|
|
|
|
}
|
2022-05-31 18:38:47 -07:00
|
|
|
}
|
2022-04-07 09:58:42 -07:00
|
|
|
}
|
2022-08-10 01:15:28 -07:00
|
|
|
const mintInfos = allTokenIndices
|
|
|
|
.filter((index) => index != TokenPosition.TokenIndexUnset)
|
2022-08-17 23:48:45 -07:00
|
|
|
.map((tokenIndex) => group.mintInfosMapByTokenIndex.get(tokenIndex)!);
|
2022-04-08 03:30:21 -07:00
|
|
|
|
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
|
|
|
|
2022-09-21 03:50:10 -07:00
|
|
|
const allPerpIndices = mangoAccount.perps.map((perp) => perp.marketIndex);
|
2022-09-21 00:42:45 -07:00
|
|
|
|
2022-09-21 03:50:10 -07:00
|
|
|
// insert any extra perp markets in the free perp position slots
|
|
|
|
if (perpMarkets) {
|
|
|
|
for (const perpMarket of perpMarkets) {
|
|
|
|
if (allPerpIndices.indexOf(perpMarket.perpMarketIndex) < 0) {
|
|
|
|
allPerpIndices[
|
|
|
|
mangoAccount.perps.findIndex(
|
|
|
|
(perp, index) =>
|
|
|
|
!perp.isActive() &&
|
|
|
|
allPerpIndices[index] == PerpPosition.PerpMarketIndexUnset,
|
|
|
|
)
|
|
|
|
] = perpMarket.perpMarketIndex;
|
|
|
|
}
|
2022-08-31 02:36:44 -07:00
|
|
|
}
|
|
|
|
}
|
2022-09-21 03:50:10 -07:00
|
|
|
const allPerpMarkets = allPerpIndices
|
|
|
|
.filter((index) => index != PerpPosition.PerpMarketIndexUnset)
|
|
|
|
.map((index) => group.findPerpMarket(index)!);
|
|
|
|
healthRemainingAccounts.push(
|
|
|
|
...allPerpMarkets.map((perp) => perp.publicKey),
|
|
|
|
);
|
|
|
|
healthRemainingAccounts.push(...allPerpMarkets.map((perp) => perp.oracle));
|
2022-08-31 02:36:44 -07:00
|
|
|
|
|
|
|
healthRemainingAccounts.push(
|
|
|
|
...mangoAccount.serum3
|
|
|
|
.filter((serum3Account) => serum3Account.marketIndex !== 65535)
|
|
|
|
.map((serum3Account) => serum3Account.openOrders),
|
|
|
|
);
|
|
|
|
|
|
|
|
// debugHealthAccounts(group, mangoAccount, healthRemainingAccounts);
|
2022-04-08 03:30:21 -07:00
|
|
|
|
2022-04-07 09:58:42 -07:00
|
|
|
return healthRemainingAccounts;
|
2022-04-07 08:58:20 -07:00
|
|
|
}
|
2022-08-03 09:05:16 -07:00
|
|
|
|
2022-09-29 06:51:09 -07:00
|
|
|
private buildScanningAccountRetrieverHealthAccounts(
|
2022-08-03 09:05:16 -07:00
|
|
|
group: Group,
|
|
|
|
mangoAccounts: MangoAccount[],
|
2022-08-31 02:36:44 -07:00
|
|
|
banks: Bank[],
|
|
|
|
perpMarkets: PerpMarket[],
|
2022-08-10 01:15:28 -07:00
|
|
|
): PublicKey[] {
|
2022-08-03 09:05:16 -07:00
|
|
|
const healthRemainingAccounts: PublicKey[] = [];
|
|
|
|
|
2022-09-29 06:51:09 -07:00
|
|
|
let tokenIndices: TokenIndex[] = [];
|
2022-08-04 10:42:41 -07:00
|
|
|
for (const mangoAccount of mangoAccounts) {
|
2022-08-03 09:05:16 -07:00
|
|
|
tokenIndices.push(
|
|
|
|
...mangoAccount.tokens
|
|
|
|
.filter((token) => token.tokenIndex !== 65535)
|
|
|
|
.map((token) => token.tokenIndex),
|
|
|
|
);
|
|
|
|
}
|
|
|
|
tokenIndices = [...new Set(tokenIndices)];
|
|
|
|
|
|
|
|
if (banks?.length) {
|
|
|
|
for (const bank of banks) {
|
|
|
|
tokenIndices.push(bank.tokenIndex);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
const mintInfos = [...new Set(tokenIndices)].map(
|
2022-08-17 23:48:45 -07:00
|
|
|
(tokenIndex) => group.mintInfosMapByTokenIndex.get(tokenIndex)!,
|
2022-08-03 09:05:16 -07:00
|
|
|
);
|
|
|
|
healthRemainingAccounts.push(
|
|
|
|
...mintInfos.map((mintInfo) => mintInfo.firstBank()),
|
|
|
|
);
|
|
|
|
healthRemainingAccounts.push(
|
|
|
|
...mintInfos.map((mintInfo) => mintInfo.oracle),
|
|
|
|
);
|
2022-08-31 02:36:44 -07:00
|
|
|
|
2022-09-29 06:51:09 -07:00
|
|
|
const perpIndices: PerpMarketIndex[] = [];
|
2022-08-04 10:42:41 -07:00
|
|
|
for (const mangoAccount of mangoAccounts) {
|
2022-09-21 03:50:10 -07:00
|
|
|
perpIndices.push(
|
2022-08-03 09:05:16 -07:00
|
|
|
...mangoAccount.perps
|
|
|
|
.filter((perp) => perp.marketIndex !== 65535)
|
2022-09-21 03:50:10 -07:00
|
|
|
.map((perp) => perp.marketIndex),
|
2022-08-03 09:05:16 -07:00
|
|
|
);
|
|
|
|
}
|
2022-09-21 03:50:10 -07:00
|
|
|
perpIndices.push(...perpMarkets.map((perp) => perp.perpMarketIndex));
|
|
|
|
|
|
|
|
const allPerpMarkets = [...new Set(perpIndices)].map(
|
|
|
|
(marketIndex) => group.findPerpMarket(marketIndex)!,
|
|
|
|
);
|
2022-08-03 09:05:16 -07:00
|
|
|
|
2022-09-21 00:42:45 -07:00
|
|
|
// Add perp accounts
|
2022-09-21 03:50:10 -07:00
|
|
|
healthRemainingAccounts.push(...allPerpMarkets.map((p) => p.publicKey));
|
2022-09-21 00:42:45 -07:00
|
|
|
// Add oracle for each perp
|
2022-09-21 03:50:10 -07:00
|
|
|
healthRemainingAccounts.push(...allPerpMarkets.map((p) => p.oracle));
|
2022-09-21 00:42:45 -07:00
|
|
|
|
|
|
|
for (const mangoAccount of mangoAccounts) {
|
|
|
|
healthRemainingAccounts.push(
|
|
|
|
...mangoAccount.serum3
|
|
|
|
.filter((serum3Account) => serum3Account.marketIndex !== 65535)
|
|
|
|
.map((serum3Account) => serum3Account.openOrders),
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2022-08-03 09:05:16 -07:00
|
|
|
return healthRemainingAccounts;
|
|
|
|
}
|
2022-02-23 02:09:17 -08:00
|
|
|
}
|