2022-04-12 07:19:58 -07:00
|
|
|
import { utf8 } from '@project-serum/anchor/dist/cjs/utils/bytes';
|
2022-08-31 02:36:44 -07:00
|
|
|
import { Market, Orderbook } from '@project-serum/serum/lib/market';
|
|
|
|
import { Cluster, PublicKey } from '@solana/web3.js';
|
2022-08-01 09:46:45 -07:00
|
|
|
import BN from 'bn.js';
|
2022-08-31 02:36:44 -07:00
|
|
|
import { MangoClient } from '../client';
|
2022-12-08 01:16:06 -08:00
|
|
|
import { OPENBOOK_PROGRAM_ID } from '../constants';
|
2022-10-11 00:34:02 -07:00
|
|
|
import { MAX_I80F48, ONE_I80F48, ZERO_I80F48 } from '../numbers/I80F48';
|
2022-09-29 06:51:09 -07:00
|
|
|
import { As } from '../utils';
|
|
|
|
import { TokenIndex } from './bank';
|
2022-08-31 02:36:44 -07:00
|
|
|
import { Group } from './group';
|
2022-04-02 23:57:45 -07:00
|
|
|
|
2022-09-29 06:51:09 -07:00
|
|
|
export type MarketIndex = number & As<'market-index'>;
|
|
|
|
|
2022-04-02 23:57:45 -07:00
|
|
|
export class Serum3Market {
|
2022-04-12 07:19:58 -07:00
|
|
|
public name: string;
|
2022-04-02 23:57:45 -07:00
|
|
|
static from(
|
|
|
|
publicKey: PublicKey,
|
|
|
|
obj: {
|
|
|
|
group: PublicKey;
|
2022-08-04 01:41:54 -07:00
|
|
|
baseTokenIndex: number;
|
|
|
|
quoteTokenIndex: number;
|
|
|
|
name: number[];
|
2022-04-02 23:57:45 -07:00
|
|
|
serumProgram: PublicKey;
|
|
|
|
serumMarketExternal: PublicKey;
|
|
|
|
marketIndex: number;
|
2022-08-01 09:46:45 -07:00
|
|
|
registrationTime: BN;
|
2022-04-02 23:57:45 -07:00
|
|
|
},
|
|
|
|
): Serum3Market {
|
|
|
|
return new Serum3Market(
|
|
|
|
publicKey,
|
|
|
|
obj.group,
|
2022-09-29 06:51:09 -07:00
|
|
|
obj.baseTokenIndex as TokenIndex,
|
|
|
|
obj.quoteTokenIndex as TokenIndex,
|
2022-08-04 01:41:54 -07:00
|
|
|
obj.name,
|
2022-04-02 23:57:45 -07:00
|
|
|
obj.serumProgram,
|
|
|
|
obj.serumMarketExternal,
|
2022-09-29 06:51:09 -07:00
|
|
|
obj.marketIndex as MarketIndex,
|
2022-08-01 09:46:45 -07:00
|
|
|
obj.registrationTime,
|
2022-04-02 23:57:45 -07:00
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
constructor(
|
|
|
|
public publicKey: PublicKey,
|
|
|
|
public group: PublicKey,
|
2022-09-29 06:51:09 -07:00
|
|
|
public baseTokenIndex: TokenIndex,
|
|
|
|
public quoteTokenIndex: TokenIndex,
|
2022-08-04 01:41:54 -07:00
|
|
|
name: number[],
|
2022-04-02 23:57:45 -07:00
|
|
|
public serumProgram: PublicKey,
|
|
|
|
public serumMarketExternal: PublicKey,
|
2022-09-29 06:51:09 -07:00
|
|
|
public marketIndex: MarketIndex,
|
2022-08-01 09:46:45 -07:00
|
|
|
public registrationTime: BN,
|
2022-04-12 07:19:58 -07:00
|
|
|
) {
|
|
|
|
this.name = utf8.decode(new Uint8Array(name)).split('\x00')[0];
|
|
|
|
}
|
2022-08-31 02:36:44 -07:00
|
|
|
|
2022-08-31 05:37:45 -07:00
|
|
|
/**
|
|
|
|
*
|
|
|
|
* @param group
|
|
|
|
* @returns maximum leverage one can bid on this market, this is only for display purposes,
|
|
|
|
* also see getMaxQuoteForSerum3BidUi and getMaxBaseForSerum3AskUi
|
|
|
|
*/
|
|
|
|
maxBidLeverage(group: Group): number {
|
|
|
|
const baseBank = group.getFirstBankByTokenIndex(this.baseTokenIndex);
|
|
|
|
const quoteBank = group.getFirstBankByTokenIndex(this.quoteTokenIndex);
|
|
|
|
if (
|
2022-09-01 00:48:23 -07:00
|
|
|
quoteBank.initLiabWeight.sub(baseBank.initAssetWeight).lte(ZERO_I80F48())
|
2022-08-31 05:37:45 -07:00
|
|
|
) {
|
2022-09-01 00:48:23 -07:00
|
|
|
return MAX_I80F48().toNumber();
|
2022-08-31 05:37:45 -07:00
|
|
|
}
|
|
|
|
|
2022-09-01 00:48:23 -07:00
|
|
|
return ONE_I80F48()
|
|
|
|
.div(quoteBank.initLiabWeight.sub(baseBank.initAssetWeight))
|
|
|
|
.toNumber();
|
2022-08-31 05:37:45 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
*
|
|
|
|
* @param group
|
|
|
|
* @returns maximum leverage one can ask on this market, this is only for display purposes,
|
|
|
|
* also see getMaxQuoteForSerum3BidUi and getMaxBaseForSerum3AskUi
|
|
|
|
*/
|
|
|
|
maxAskLeverage(group: Group): number {
|
|
|
|
const baseBank = group.getFirstBankByTokenIndex(this.baseTokenIndex);
|
|
|
|
const quoteBank = group.getFirstBankByTokenIndex(this.quoteTokenIndex);
|
|
|
|
|
|
|
|
if (
|
2022-09-01 00:48:23 -07:00
|
|
|
baseBank.initLiabWeight.sub(quoteBank.initAssetWeight).lte(ZERO_I80F48())
|
2022-08-31 05:37:45 -07:00
|
|
|
) {
|
2022-09-01 00:48:23 -07:00
|
|
|
return MAX_I80F48().toNumber();
|
2022-08-31 05:37:45 -07:00
|
|
|
}
|
|
|
|
|
2022-09-01 00:48:23 -07:00
|
|
|
return ONE_I80F48()
|
|
|
|
.div(baseBank.initLiabWeight.sub(quoteBank.initAssetWeight))
|
|
|
|
.toNumber();
|
2022-08-31 05:37:45 -07:00
|
|
|
}
|
|
|
|
|
2022-08-31 02:55:54 -07:00
|
|
|
public async loadBids(client: MangoClient, group: Group): Promise<Orderbook> {
|
2022-09-29 06:51:09 -07:00
|
|
|
const serum3MarketExternal = group.getSerum3ExternalMarket(
|
|
|
|
this.serumMarketExternal,
|
2022-08-31 02:36:44 -07:00
|
|
|
);
|
|
|
|
return await serum3MarketExternal.loadBids(
|
|
|
|
client.program.provider.connection,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2022-08-31 02:55:54 -07:00
|
|
|
public async loadAsks(client: MangoClient, group: Group): Promise<Orderbook> {
|
2022-09-29 06:51:09 -07:00
|
|
|
const serum3MarketExternal = group.getSerum3ExternalMarket(
|
|
|
|
this.serumMarketExternal,
|
2022-08-31 02:36:44 -07:00
|
|
|
);
|
|
|
|
return await serum3MarketExternal.loadAsks(
|
|
|
|
client.program.provider.connection,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2022-08-31 02:55:54 -07:00
|
|
|
public async logOb(client: MangoClient, group: Group): Promise<string> {
|
2022-08-31 02:36:44 -07:00
|
|
|
let res = ``;
|
|
|
|
res += ` ${this.name} OrderBook`;
|
|
|
|
let orders = await this?.loadAsks(client, group);
|
|
|
|
for (const order of orders!.items(true)) {
|
|
|
|
res += `\n ${order.price.toString().padStart(10)}, ${order.size
|
|
|
|
.toString()
|
|
|
|
.padStart(10)}`;
|
|
|
|
}
|
|
|
|
res += `\n --------------------------`;
|
|
|
|
orders = await this?.loadBids(client, group);
|
|
|
|
for (const order of orders!.items(true)) {
|
|
|
|
res += `\n ${order.price.toString().padStart(10)}, ${order.size
|
|
|
|
.toString()
|
|
|
|
.padStart(10)}`;
|
|
|
|
}
|
|
|
|
return res;
|
|
|
|
}
|
2022-04-02 23:57:45 -07:00
|
|
|
}
|
|
|
|
|
2022-04-03 22:29:22 -07:00
|
|
|
export class Serum3SelfTradeBehavior {
|
|
|
|
static decrementTake = { decrementTake: {} };
|
|
|
|
static cancelProvide = { cancelProvide: {} };
|
|
|
|
static abortTransaction = { abortTransaction: {} };
|
|
|
|
}
|
|
|
|
|
|
|
|
export class Serum3OrderType {
|
|
|
|
static limit = { limit: {} };
|
|
|
|
static immediateOrCancel = { immediateOrCancel: {} };
|
|
|
|
static postOnly = { postOnly: {} };
|
|
|
|
}
|
|
|
|
|
|
|
|
export class Serum3Side {
|
|
|
|
static bid = { bid: {} };
|
|
|
|
static ask = { ask: {} };
|
|
|
|
}
|
2022-08-31 02:36:44 -07:00
|
|
|
|
|
|
|
export async function generateSerum3MarketExternalVaultSignerAddress(
|
|
|
|
cluster: Cluster,
|
|
|
|
serum3Market: Serum3Market,
|
|
|
|
serum3MarketExternal: Market,
|
|
|
|
): Promise<PublicKey> {
|
|
|
|
return await PublicKey.createProgramAddress(
|
|
|
|
[
|
|
|
|
serum3Market.serumMarketExternal.toBuffer(),
|
|
|
|
serum3MarketExternal.decoded.vaultSignerNonce.toArrayLike(
|
|
|
|
Buffer,
|
|
|
|
'le',
|
|
|
|
8,
|
|
|
|
),
|
|
|
|
],
|
2022-12-08 01:16:06 -08:00
|
|
|
OPENBOOK_PROGRAM_ID[cluster],
|
2022-08-31 02:36:44 -07:00
|
|
|
);
|
|
|
|
}
|