ts client changes (#320)
* cleanup + small sync with program Signed-off-by: microwavedcola1 <microwavedcola@gmail.com> * Fixes from review Signed-off-by: microwavedcola1 <microwavedcola@gmail.com> * Update lock file Signed-off-by: microwavedcola1 <microwavedcola@gmail.com> * Fix tsc errors Signed-off-by: microwavedcola1 <microwavedcola@gmail.com> Signed-off-by: microwavedcola1 <microwavedcola@gmail.com>
This commit is contained in:
parent
2a13cf9ac2
commit
7d9c3616af
|
@ -65,7 +65,7 @@ pub fn perp_settle_fees(ctx: Context<PerpSettleFees>, max_settle_amount: u64) ->
|
|||
// Settle funding before settling any PnL
|
||||
perp_position.settle_funding(&perp_market);
|
||||
|
||||
// Calculate PnL for each account
|
||||
// Calculate PnL
|
||||
let pnl = perp_position.pnl_for_price(&perp_market, oracle_price)?;
|
||||
|
||||
// Account perp position must have a loss to be able to settle against the fee account
|
||||
|
|
|
@ -368,6 +368,8 @@ pub fn serum3_place_order(
|
|||
account.check_health_post(&health_cache, pre_health)?;
|
||||
}
|
||||
|
||||
// TODO: enforce min_vault_to_deposits_ratio
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
|
|
@ -376,6 +376,8 @@ impl HealthCache {
|
|||
let entry_index = self.token_info_index(bank.token_index)?;
|
||||
let mut entry = &mut self.token_infos[entry_index];
|
||||
|
||||
// Note: resetting the weights here assumes that the change has been applied to
|
||||
// the passed in bank already
|
||||
entry.init_asset_weight =
|
||||
bank.scaled_init_asset_weight(entry.prices.asset(HealthType::Init));
|
||||
entry.init_liab_weight = bank.scaled_init_liab_weight(entry.prices.liab(HealthType::Init));
|
||||
|
@ -388,16 +390,6 @@ impl HealthCache {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
/// Recomputes the dynamic init weights for the bank's current deposits/borrows.
|
||||
pub fn recompute_token_weights(&mut self, bank: &Bank) -> Result<()> {
|
||||
let entry_index = self.token_info_index(bank.token_index)?;
|
||||
let mut entry = &mut self.token_infos[entry_index];
|
||||
entry.init_asset_weight =
|
||||
bank.scaled_init_asset_weight(entry.prices.asset(HealthType::Init));
|
||||
entry.init_liab_weight = bank.scaled_init_liab_weight(entry.prices.liab(HealthType::Init));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Changes the cached user account token and serum balances.
|
||||
///
|
||||
/// WARNING: You must also call recompute_token_weights() after all bank
|
||||
|
|
|
@ -8,10 +8,14 @@ export const QUOTE_DECIMALS = 6;
|
|||
|
||||
export type TokenIndex = number & As<'token-index'>;
|
||||
|
||||
export type OracleConfig = {
|
||||
export type OracleConfigDto = {
|
||||
confFilter: I80F48Dto;
|
||||
maxStalenessSlots: BN;
|
||||
reserved: number[];
|
||||
};
|
||||
|
||||
export type OracleConfig = {
|
||||
confFilter: I80F48;
|
||||
maxStalenessSlots: BN;
|
||||
};
|
||||
|
||||
export type StablePriceModel = {
|
||||
|
@ -34,10 +38,14 @@ export interface BankForHealth {
|
|||
initLiabWeight: I80F48;
|
||||
price: I80F48;
|
||||
stablePriceModel: StablePriceModel;
|
||||
|
||||
scaledInitAssetWeight(): I80F48;
|
||||
scaledInitLiabWeight(): I80F48;
|
||||
}
|
||||
|
||||
export class Bank implements BankForHealth {
|
||||
public name: string;
|
||||
public oracleConfig: OracleConfig;
|
||||
public depositIndex: I80F48;
|
||||
public borrowIndex: I80F48;
|
||||
public indexedDeposits: I80F48;
|
||||
|
@ -70,7 +78,7 @@ export class Bank implements BankForHealth {
|
|||
mint: PublicKey;
|
||||
vault: PublicKey;
|
||||
oracle: PublicKey;
|
||||
oracleConfig: OracleConfig;
|
||||
oracleConfig: OracleConfigDto;
|
||||
stablePriceModel: StablePriceModel;
|
||||
depositIndex: I80F48Dto;
|
||||
borrowIndex: I80F48Dto;
|
||||
|
@ -161,7 +169,7 @@ export class Bank implements BankForHealth {
|
|||
public mint: PublicKey,
|
||||
public vault: PublicKey,
|
||||
public oracle: PublicKey,
|
||||
oracleConfig: OracleConfig,
|
||||
oracleConfig: OracleConfigDto,
|
||||
public stablePriceModel: StablePriceModel,
|
||||
depositIndex: I80F48Dto,
|
||||
borrowIndex: I80F48Dto,
|
||||
|
@ -195,10 +203,14 @@ export class Bank implements BankForHealth {
|
|||
lastNetBorrowsWindowStartTs: BN,
|
||||
netBorrowLimitPerWindowQuote: BN,
|
||||
netBorrowsInWindow: BN,
|
||||
borrowWeightScaleStartQuote: number,
|
||||
depositWeightScaleStartQuote: number,
|
||||
public borrowWeightScaleStartQuote: number,
|
||||
public depositWeightScaleStartQuote: number,
|
||||
) {
|
||||
this.name = utf8.decode(new Uint8Array(name)).split('\x00')[0];
|
||||
this.oracleConfig = {
|
||||
confFilter: I80F48.from(oracleConfig.confFilter),
|
||||
maxStalenessSlots: oracleConfig.maxStalenessSlots,
|
||||
} as OracleConfig;
|
||||
this.depositIndex = I80F48.from(depositIndex);
|
||||
this.borrowIndex = I80F48.from(borrowIndex);
|
||||
this.indexedDeposits = I80F48.from(indexedDeposits);
|
||||
|
@ -293,6 +305,28 @@ export class Bank implements BankForHealth {
|
|||
);
|
||||
}
|
||||
|
||||
scaledInitAssetWeight(): I80F48 {
|
||||
const depositsQuote = this.nativeDeposits().mul(this.price);
|
||||
if (
|
||||
depositsQuote.lte(I80F48.fromNumber(this.depositWeightScaleStartQuote))
|
||||
) {
|
||||
return this.initAssetWeight;
|
||||
}
|
||||
return this.initAssetWeight.mul(
|
||||
I80F48.fromNumber(this.depositWeightScaleStartQuote).div(depositsQuote),
|
||||
);
|
||||
}
|
||||
|
||||
scaledInitLiabWeight(): I80F48 {
|
||||
const borrowsQuote = this.nativeBorrows().mul(this.price);
|
||||
if (borrowsQuote.lte(I80F48.fromNumber(this.borrowWeightScaleStartQuote))) {
|
||||
return this.initLiabWeight;
|
||||
}
|
||||
return this.initLiabWeight.mul(
|
||||
borrowsQuote.div(I80F48.fromNumber(this.borrowWeightScaleStartQuote)),
|
||||
);
|
||||
}
|
||||
|
||||
get price(): I80F48 {
|
||||
if (!this._price) {
|
||||
throw new Error(
|
||||
|
|
|
@ -14,7 +14,7 @@ import {
|
|||
} from '@solana/web3.js';
|
||||
import BN from 'bn.js';
|
||||
import { MangoClient } from '../client';
|
||||
import { SERUM3_PROGRAM_ID } from '../constants';
|
||||
import { OPENBOOK_PROGRAM_ID } from '../constants';
|
||||
import { Id } from '../ids';
|
||||
import { I80F48, ONE_I80F48 } from '../numbers/I80F48';
|
||||
import { toNative, toNativeI80F48, toUiDecimals } from '../utils';
|
||||
|
@ -225,7 +225,7 @@ export class Group {
|
|||
client.program.provider.connection,
|
||||
serum3Market.serumMarketExternal,
|
||||
{ commitment: client.program.provider.connection.commitment },
|
||||
SERUM3_PROGRAM_ID[client.cluster],
|
||||
OPENBOOK_PROGRAM_ID[client.cluster],
|
||||
),
|
||||
),
|
||||
);
|
||||
|
|
|
@ -23,6 +23,8 @@ function mockBankAndOracle(
|
|||
initLiabWeight: I80F48.fromNumber(1 + initWeight),
|
||||
price: I80F48.fromNumber(price),
|
||||
stablePriceModel: { stablePrice: price } as StablePriceModel,
|
||||
scaledInitAssetWeight: () => I80F48.fromNumber(1 - initWeight),
|
||||
scaledInitLiabWeight: () => I80F48.fromNumber(1 + initWeight),
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -666,6 +666,8 @@ export class HealthCache {
|
|||
function cacheAfterSwap(amount: I80F48): HealthCache {
|
||||
const adjustedCache: HealthCache = _.cloneDeep(healthCacheClone);
|
||||
// adjustedCache.logHealthCache('beforeSwap', adjustedCache);
|
||||
// TODO: make a copy of the bank, apply amount, recompute weights,
|
||||
// and set the new weights on the tokenInfos
|
||||
adjustedCache.tokenInfos[sourceIndex].balanceNative.isub(amount);
|
||||
adjustedCache.tokenInfos[targetIndex].balanceNative.iadd(
|
||||
amount.mul(price),
|
||||
|
@ -1062,9 +1064,9 @@ export class TokenInfo {
|
|||
return new TokenInfo(
|
||||
bank.tokenIndex,
|
||||
bank.maintAssetWeight,
|
||||
bank.initAssetWeight,
|
||||
bank.scaledInitAssetWeight(),
|
||||
bank.maintLiabWeight,
|
||||
bank.initLiabWeight,
|
||||
bank.scaledInitLiabWeight(),
|
||||
new Prices(
|
||||
bank.price,
|
||||
I80F48.fromNumber(bank.stablePriceModel.stablePrice),
|
||||
|
|
|
@ -3,7 +3,7 @@ import { utf8 } from '@project-serum/anchor/dist/cjs/utils/bytes';
|
|||
import { OpenOrders, Order, Orderbook } from '@project-serum/serum/lib/market';
|
||||
import { AccountInfo, PublicKey, TransactionSignature } from '@solana/web3.js';
|
||||
import { MangoClient } from '../client';
|
||||
import { SERUM3_PROGRAM_ID } from '../constants';
|
||||
import { OPENBOOK_PROGRAM_ID } from '../constants';
|
||||
import { I80F48, I80F48Dto, ONE_I80F48, ZERO_I80F48 } from '../numbers/I80F48';
|
||||
import { toNativeI80F48, toUiDecimals, toUiDecimalsForQuote } from '../utils';
|
||||
import { Bank, TokenIndex } from './bank';
|
||||
|
@ -118,7 +118,7 @@ export class MangoAccount {
|
|||
const oo = OpenOrders.fromAccountInfo(
|
||||
serum3Active[i].openOrders,
|
||||
ai,
|
||||
SERUM3_PROGRAM_ID[client.cluster],
|
||||
OPENBOOK_PROGRAM_ID[client.cluster],
|
||||
);
|
||||
return [serum3Active[i].marketIndex, oo];
|
||||
}),
|
||||
|
@ -421,6 +421,8 @@ export class MangoAccount {
|
|||
/**
|
||||
* The amount of given native token you can withdraw including borrows, considering all existing assets as collateral.
|
||||
* @returns amount of given native token you can borrow, considering all existing assets as collateral, in native token
|
||||
*
|
||||
* TODO: take into account net_borrow_limit and min_vault_to_deposits_ratio
|
||||
*/
|
||||
public getMaxWithdrawWithBorrowForToken(
|
||||
group: Group,
|
||||
|
@ -563,7 +565,7 @@ export class MangoAccount {
|
|||
return OpenOrders.fromAccountInfo(
|
||||
this.serum3[index].openOrders,
|
||||
acc,
|
||||
SERUM3_PROGRAM_ID[client.cluster],
|
||||
OPENBOOK_PROGRAM_ID[client.cluster],
|
||||
);
|
||||
});
|
||||
}
|
||||
|
@ -1247,24 +1249,24 @@ export class PerpPosition {
|
|||
);
|
||||
}
|
||||
|
||||
// TODO FUTURE: double check with program side code that this is in sycn with latest changes in program
|
||||
public getEntryPrice(perpMarket: PerpMarket): BN {
|
||||
if (this.basePositionLots.eq(new BN(0))) {
|
||||
return new BN(0);
|
||||
}
|
||||
return this.quoteEntryNative
|
||||
.div(this.basePositionLots.mul(perpMarket.baseLotSize))
|
||||
.abs();
|
||||
public getAverageEntryPriceUi(perpMarket: PerpMarket): number {
|
||||
return perpMarket.priceLotsToUi(
|
||||
new BN(this.avgEntryPricePerBaseLot / perpMarket.baseLotSize.toNumber()),
|
||||
);
|
||||
}
|
||||
|
||||
// TODO FUTURE: double check with program side code that this is in sycn with latest changes in program
|
||||
public getBreakEvenPrice(perpMarket: PerpMarket): BN {
|
||||
public getBreakEvenPriceUi(perpMarket: PerpMarket): number {
|
||||
if (this.basePositionLots.eq(new BN(0))) {
|
||||
return new BN(0);
|
||||
return 0;
|
||||
}
|
||||
return this.quoteRunningNative
|
||||
.div(this.basePositionLots.mul(perpMarket.baseLotSize))
|
||||
.abs();
|
||||
return perpMarket.priceLotsToUi(
|
||||
new BN(
|
||||
this.quoteRunningNative
|
||||
.neg()
|
||||
.div(this.basePositionLots.mul(perpMarket.baseLotSize))
|
||||
.toNumber(),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
public getPnl(perpMarket: PerpMarket): I80F48 {
|
||||
|
|
|
@ -7,6 +7,7 @@ import { I80F48, I80F48Dto, ZERO_I80F48 } from '../numbers/I80F48';
|
|||
import { As, toNative, U64_MAX_BN } from '../utils';
|
||||
import {
|
||||
OracleConfig,
|
||||
OracleConfigDto,
|
||||
QUOTE_DECIMALS,
|
||||
StablePriceModel,
|
||||
TokenIndex,
|
||||
|
@ -18,6 +19,7 @@ export type PerpMarketIndex = number & As<'perp-market-index'>;
|
|||
|
||||
export class PerpMarket {
|
||||
public name: string;
|
||||
public oracleConfig: OracleConfig;
|
||||
public maintAssetWeight: I80F48;
|
||||
public initAssetWeight: I80F48;
|
||||
public maintLiabWeight: I80F48;
|
||||
|
@ -55,7 +57,7 @@ export class PerpMarket {
|
|||
asks: PublicKey;
|
||||
eventQueue: PublicKey;
|
||||
oracle: PublicKey;
|
||||
oracleConfig: OracleConfig;
|
||||
oracleConfig: OracleConfigDto;
|
||||
stablePriceModel: StablePriceModel;
|
||||
quoteLotSize: BN;
|
||||
baseLotSize: BN;
|
||||
|
@ -142,7 +144,7 @@ export class PerpMarket {
|
|||
public asks: PublicKey,
|
||||
public eventQueue: PublicKey,
|
||||
public oracle: PublicKey,
|
||||
oracleConfig: OracleConfig,
|
||||
oracleConfig: OracleConfigDto,
|
||||
public stablePriceModel: StablePriceModel,
|
||||
public quoteLotSize: BN,
|
||||
public baseLotSize: BN,
|
||||
|
@ -172,6 +174,10 @@ export class PerpMarket {
|
|||
settlePnlLimitWindowSizeTs: BN,
|
||||
) {
|
||||
this.name = utf8.decode(new Uint8Array(name)).split('\x00')[0];
|
||||
this.oracleConfig = {
|
||||
confFilter: I80F48.from(oracleConfig.confFilter),
|
||||
maxStalenessSlots: oracleConfig.maxStalenessSlots,
|
||||
} as OracleConfig;
|
||||
this.maintAssetWeight = I80F48.from(maintAssetWeight);
|
||||
this.initAssetWeight = I80F48.from(initAssetWeight);
|
||||
this.maintLiabWeight = I80F48.from(maintLiabWeight);
|
||||
|
@ -703,13 +709,13 @@ export class BookSide {
|
|||
static toInnerNode(client: MangoClient, data: [number]): InnerNode {
|
||||
return (client.program as any)._coder.types.typeLayouts
|
||||
.get('InnerNode')
|
||||
.decode(Buffer.from([BookSide.INNER_NODE_TAG, 0, 0, 0].concat(data)));
|
||||
.decode(Buffer.from([BookSide.INNER_NODE_TAG].concat(data)));
|
||||
}
|
||||
static toLeafNode(client: MangoClient, data: [number]): LeafNode {
|
||||
return LeafNode.from(
|
||||
(client.program as any)._coder.types.typeLayouts
|
||||
.get('LeafNode')
|
||||
.decode(Buffer.from([BookSide.LEAF_NODE_TAG, 0, 0, 0].concat(data))),
|
||||
.decode(Buffer.from([BookSide.LEAF_NODE_TAG].concat(data))),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,7 +3,7 @@ import { Market, Orderbook } from '@project-serum/serum/lib/market';
|
|||
import { Cluster, PublicKey } from '@solana/web3.js';
|
||||
import BN from 'bn.js';
|
||||
import { MangoClient } from '../client';
|
||||
import { SERUM3_PROGRAM_ID } from '../constants';
|
||||
import { OPENBOOK_PROGRAM_ID } from '../constants';
|
||||
import { MAX_I80F48, ONE_I80F48, ZERO_I80F48 } from '../numbers/I80F48';
|
||||
import { As } from '../utils';
|
||||
import { TokenIndex } from './bank';
|
||||
|
@ -163,6 +163,6 @@ export async function generateSerum3MarketExternalVaultSignerAddress(
|
|||
8,
|
||||
),
|
||||
],
|
||||
SERUM3_PROGRAM_ID[cluster],
|
||||
OPENBOOK_PROGRAM_ID[cluster],
|
||||
);
|
||||
}
|
||||
|
|
|
@ -48,7 +48,7 @@ import {
|
|||
Serum3SelfTradeBehavior,
|
||||
Serum3Side,
|
||||
} from './accounts/serum3';
|
||||
import { SERUM3_PROGRAM_ID } from './constants';
|
||||
import { OPENBOOK_PROGRAM_ID } from './constants';
|
||||
import { Id } from './ids';
|
||||
import { IDL, MangoV4 } from './mango_v4';
|
||||
import { I80F48 } from './numbers/I80F48';
|
||||
|
@ -991,7 +991,7 @@ export class MangoClient {
|
|||
.accounts({
|
||||
group: group.publicKey,
|
||||
admin: (this.program.provider as AnchorProvider).wallet.publicKey,
|
||||
serumProgram: SERUM3_PROGRAM_ID[this.cluster],
|
||||
serumProgram: OPENBOOK_PROGRAM_ID[this.cluster],
|
||||
serumMarketExternal: serum3MarketExternalPk,
|
||||
baseBank: baseBank.publicKey,
|
||||
quoteBank: quoteBank.publicKey,
|
||||
|
@ -1203,7 +1203,7 @@ export class MangoClient {
|
|||
openOrders: mangoAccount.getSerum3Account(serum3Market.marketIndex)
|
||||
?.openOrders,
|
||||
serumMarket: serum3Market.publicKey,
|
||||
serumProgram: SERUM3_PROGRAM_ID[this.cluster],
|
||||
serumProgram: OPENBOOK_PROGRAM_ID[this.cluster],
|
||||
serumMarketExternal: serum3Market.serumMarketExternal,
|
||||
marketBids: serum3MarketExternal.bidsAddress,
|
||||
marketAsks: serum3MarketExternal.asksAddress,
|
||||
|
@ -1256,7 +1256,7 @@ export class MangoClient {
|
|||
openOrders: mangoAccount.getSerum3Account(serum3Market.marketIndex)
|
||||
?.openOrders,
|
||||
serumMarket: serum3Market.publicKey,
|
||||
serumProgram: SERUM3_PROGRAM_ID[this.cluster],
|
||||
serumProgram: OPENBOOK_PROGRAM_ID[this.cluster],
|
||||
serumMarketExternal: serum3Market.serumMarketExternal,
|
||||
marketBids: serum3MarketExternal.bidsAddress,
|
||||
marketAsks: serum3MarketExternal.asksAddress,
|
||||
|
@ -1301,7 +1301,7 @@ export class MangoClient {
|
|||
openOrders: mangoAccount.getSerum3Account(serum3Market.marketIndex)
|
||||
?.openOrders,
|
||||
serumMarket: serum3Market.publicKey,
|
||||
serumProgram: SERUM3_PROGRAM_ID[this.cluster],
|
||||
serumProgram: OPENBOOK_PROGRAM_ID[this.cluster],
|
||||
serumMarketExternal: serum3Market.serumMarketExternal,
|
||||
marketBaseVault: serum3MarketExternal.decoded.baseVault,
|
||||
marketQuoteVault: serum3MarketExternal.decoded.quoteVault,
|
||||
|
@ -1350,7 +1350,7 @@ export class MangoClient {
|
|||
openOrders: mangoAccount.getSerum3Account(serum3Market.marketIndex)
|
||||
?.openOrders,
|
||||
serumMarket: serum3Market.publicKey,
|
||||
serumProgram: SERUM3_PROGRAM_ID[this.cluster],
|
||||
serumProgram: OPENBOOK_PROGRAM_ID[this.cluster],
|
||||
serumMarketExternal: serum3Market.serumMarketExternal,
|
||||
marketBids: serum3MarketExternal.bidsAddress,
|
||||
marketAsks: serum3MarketExternal.asksAddress,
|
||||
|
|
|
@ -1,9 +1,8 @@
|
|||
import { PublicKey } from '@solana/web3.js';
|
||||
|
||||
export const SERUM3_PROGRAM_ID = {
|
||||
testnet: new PublicKey('DESVgJVGajEgKGXhb6XmqDHGz3VjdgP7rEVESBgxmroY'),
|
||||
devnet: new PublicKey('DESVgJVGajEgKGXhb6XmqDHGz3VjdgP7rEVESBgxmroY'),
|
||||
'mainnet-beta': new PublicKey('9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin'),
|
||||
export const OPENBOOK_PROGRAM_ID = {
|
||||
devnet: new PublicKey('EoTcMgcDRTJVZDMZWBoU6rhYHZfkNTVEAfz3uUJRcYGj'),
|
||||
'mainnet-beta': new PublicKey('srmqPvymJeFKQ4zGQed1GFppgkRHL9kaELCbyksJtPX'),
|
||||
};
|
||||
|
||||
export const MANGO_V4_ID = {
|
||||
|
|
|
@ -1,295 +0,0 @@
|
|||
import { AnchorProvider, Wallet } from '@project-serum/anchor';
|
||||
import { Connection, Keypair, PublicKey } from '@solana/web3.js';
|
||||
import fs from 'fs';
|
||||
import { MangoClient } from '../client';
|
||||
import { MANGO_V4_ID } from '../constants';
|
||||
|
||||
const GROUP_NUM = Number(process.env.GROUP_NUM || 0);
|
||||
|
||||
// Reference
|
||||
// https://explorer.solana.com/
|
||||
// https://github.com/blockworks-foundation/mango-client-v3/blob/main/src/ids.json
|
||||
const MAINNET_MINTS = new Map([
|
||||
['USDC', 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v'],
|
||||
['USDT', 'Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB'],
|
||||
['BTC', '9n4nbM75f5Ui33ZbPYXn59EwSgE8CGsHtAeTH5YFeJ9E'], // Wrapped Bitcoin (Sollet)
|
||||
['ETH', '7vfCXTUXx5WJV5JADk17DUJ4ksgau7utNKj4b963voxs'], // Ether (Portal), will be treat as ETH due to higher liquidity
|
||||
['soETH', '2FPyTwcZLUg1MDrwsyoP4D6s1tM7hAkHYRjkNb5w6Pxk'], // Wrapped Ethereum (Sollet), will be treated as soETH
|
||||
['SOL', 'So11111111111111111111111111111111111111112'],
|
||||
['mSOL', 'mSoLzYCxHdYgdzU16g5QSh3i5K3z3KZK7ytfqcJm7So'],
|
||||
['MNGO', 'MangoCzJ36AjZyKwVj3VnYU4GTonjfVEnJmvvWaxLac'],
|
||||
]);
|
||||
|
||||
// Reference
|
||||
// https://pyth.network/price-feeds/
|
||||
// https://switchboard.xyz/explorer
|
||||
const MAINNET_ORACLES = new Map([
|
||||
['USDT', '3vxLXJqLqF3JG5TCbYycbKWRBbCJQLxQmBGCkyqEEefL'],
|
||||
['BTC', 'GVXRSBjFk6e6J3NbVPXohDJetcTjaeeuykUpbQF8UoMU'],
|
||||
['ETH', 'JBu1AL4obBcCMqKBBxhpWCNUt136ijcuMZLFvTP7iWdB'],
|
||||
['soETH', 'JBu1AL4obBcCMqKBBxhpWCNUt136ijcuMZLFvTP7iWdB'],
|
||||
['SOL', 'H6ARHf6YXhGYeQfUzQNGk6rDNnLBQKrenN712K4AQJEG'],
|
||||
['mSOL', 'E4v1BBgoso9s64TQvmyownAVJbhbEPGyzA3qn4n46qj9'],
|
||||
['MNGO', '79wm3jjcPr6RaNQ4DGvP5KxG1mNd3gEBsg6FsNVFezK4'],
|
||||
]);
|
||||
|
||||
const MIN_VAULT_TO_DEPOSITS_RATIO = 0.2;
|
||||
const NET_BORROWS_WINDOW_SIZE_TS = 24 * 60 * 60;
|
||||
const NET_BORROWS_LIMIT_NATIVE = 1 * Math.pow(10, 7) * Math.pow(10, 6);
|
||||
|
||||
async function createGroup() {
|
||||
const admin = Keypair.fromSecretKey(
|
||||
Buffer.from(
|
||||
JSON.parse(fs.readFileSync(process.env.MB_PAYER_KEYPAIR!, 'utf-8')),
|
||||
),
|
||||
);
|
||||
|
||||
const options = AnchorProvider.defaultOptions();
|
||||
const connection = new Connection(process.env.MB_CLUSTER_URL!, options);
|
||||
|
||||
const adminWallet = new Wallet(admin);
|
||||
console.log(`Admin ${adminWallet.publicKey.toBase58()}`);
|
||||
const adminProvider = new AnchorProvider(connection, adminWallet, options);
|
||||
const client = await MangoClient.connect(
|
||||
adminProvider,
|
||||
'mainnet-beta',
|
||||
MANGO_V4_ID['mainnet-beta'],
|
||||
{
|
||||
idsSource: 'get-program-accounts',
|
||||
},
|
||||
);
|
||||
|
||||
console.log(`Creating Group...`);
|
||||
const insuranceMint = new PublicKey(MAINNET_MINTS.get('USDC')!);
|
||||
await client.groupCreate(
|
||||
GROUP_NUM,
|
||||
true /* with intention */,
|
||||
0 /* since spot and perp features are not finished */,
|
||||
insuranceMint,
|
||||
);
|
||||
const group = await client.getGroupForCreator(admin.publicKey, GROUP_NUM);
|
||||
console.log(`...registered group ${group.publicKey}`);
|
||||
}
|
||||
|
||||
async function registerTokens() {
|
||||
const admin = Keypair.fromSecretKey(
|
||||
Buffer.from(
|
||||
JSON.parse(fs.readFileSync(process.env.MB_PAYER_KEYPAIR!, 'utf-8')),
|
||||
),
|
||||
);
|
||||
|
||||
const options = AnchorProvider.defaultOptions();
|
||||
const connection = new Connection(process.env.MB_CLUSTER_URL!, options);
|
||||
|
||||
const adminWallet = new Wallet(admin);
|
||||
console.log(`Admin ${adminWallet.publicKey.toBase58()}`);
|
||||
const adminProvider = new AnchorProvider(connection, adminWallet, options);
|
||||
const client = await MangoClient.connect(
|
||||
adminProvider,
|
||||
'mainnet-beta',
|
||||
MANGO_V4_ID['mainnet-beta'],
|
||||
{
|
||||
idsSource: 'get-program-accounts',
|
||||
} /* idsjson service doesn't know about this group yet */,
|
||||
);
|
||||
|
||||
const group = await client.getGroupForCreator(admin.publicKey, GROUP_NUM);
|
||||
|
||||
const defaultOracleConfig = {
|
||||
confFilter: 0.1,
|
||||
maxStalenessSlots: null,
|
||||
};
|
||||
// hoping that dynamic rate parameter adjustment would be enough to tune their rates to the markets needs
|
||||
const defaultInterestRate = {
|
||||
adjustmentFactor: 0.004, // rate parameters are chosen to be the same for all high asset weight tokens,
|
||||
util0: 0.7,
|
||||
rate0: 0.1,
|
||||
util1: 0.85,
|
||||
rate1: 0.2,
|
||||
maxRate: 2.0,
|
||||
};
|
||||
|
||||
console.log(`Creating USDC stub oracle...`);
|
||||
const usdcMainnetMint = new PublicKey(MAINNET_MINTS.get('USDC')!);
|
||||
await client.stubOracleCreate(group, usdcMainnetMint, 1.0);
|
||||
const usdcMainnetOracle = (
|
||||
await client.getStubOracle(group, usdcMainnetMint)
|
||||
)[0];
|
||||
console.log(`...created stub oracle ${usdcMainnetOracle.publicKey}`);
|
||||
|
||||
console.log(`Registering USDC...`);
|
||||
await client.tokenRegister(
|
||||
group,
|
||||
usdcMainnetMint,
|
||||
usdcMainnetOracle.publicKey,
|
||||
defaultOracleConfig,
|
||||
0, // insurance vault token should be the first to be registered
|
||||
'USDC',
|
||||
defaultInterestRate,
|
||||
0.005, // 50 bps
|
||||
0.0005, // 5 bps
|
||||
1,
|
||||
1,
|
||||
1,
|
||||
1,
|
||||
0,
|
||||
MIN_VAULT_TO_DEPOSITS_RATIO,
|
||||
NET_BORROWS_WINDOW_SIZE_TS,
|
||||
NET_BORROWS_LIMIT_NATIVE,
|
||||
);
|
||||
|
||||
console.log(`Registering USDT...`);
|
||||
const usdtMainnetMint = new PublicKey(MAINNET_MINTS.get('USDT')!);
|
||||
const usdtMainnetOracle = new PublicKey(MAINNET_ORACLES.get('USDT')!);
|
||||
await client.tokenRegister(
|
||||
group,
|
||||
usdtMainnetMint,
|
||||
usdtMainnetOracle,
|
||||
defaultOracleConfig,
|
||||
1,
|
||||
'USDT',
|
||||
defaultInterestRate,
|
||||
0.005,
|
||||
0.0005,
|
||||
0.95,
|
||||
0.9,
|
||||
1.05,
|
||||
1.1,
|
||||
0.025, // rule of thumb used - half of maintLiabWeight
|
||||
MIN_VAULT_TO_DEPOSITS_RATIO,
|
||||
NET_BORROWS_WINDOW_SIZE_TS,
|
||||
NET_BORROWS_LIMIT_NATIVE,
|
||||
);
|
||||
|
||||
console.log(`Registering BTC...`);
|
||||
const btcMainnetMint = new PublicKey(MAINNET_MINTS.get('BTC')!);
|
||||
const btcMainnetOracle = new PublicKey(MAINNET_ORACLES.get('BTC')!);
|
||||
await client.tokenRegister(
|
||||
group,
|
||||
btcMainnetMint,
|
||||
btcMainnetOracle,
|
||||
defaultOracleConfig,
|
||||
2,
|
||||
'BTC',
|
||||
defaultInterestRate,
|
||||
0.005,
|
||||
0.0005,
|
||||
0.9,
|
||||
0.8,
|
||||
1.1,
|
||||
1.2,
|
||||
0.05,
|
||||
MIN_VAULT_TO_DEPOSITS_RATIO,
|
||||
NET_BORROWS_WINDOW_SIZE_TS,
|
||||
NET_BORROWS_LIMIT_NATIVE,
|
||||
);
|
||||
|
||||
console.log(`Registering ETH...`);
|
||||
const ethMainnetMint = new PublicKey(MAINNET_MINTS.get('ETH')!);
|
||||
const ethMainnetOracle = new PublicKey(MAINNET_ORACLES.get('ETH')!);
|
||||
await client.tokenRegister(
|
||||
group,
|
||||
ethMainnetMint,
|
||||
ethMainnetOracle,
|
||||
defaultOracleConfig,
|
||||
3,
|
||||
'ETH',
|
||||
defaultInterestRate,
|
||||
0.005,
|
||||
0.0005,
|
||||
0.9,
|
||||
0.8,
|
||||
1.1,
|
||||
1.2,
|
||||
0.05,
|
||||
MIN_VAULT_TO_DEPOSITS_RATIO,
|
||||
NET_BORROWS_WINDOW_SIZE_TS,
|
||||
NET_BORROWS_LIMIT_NATIVE,
|
||||
);
|
||||
|
||||
console.log(`Registering soETH...`);
|
||||
const soEthMainnetMint = new PublicKey(MAINNET_MINTS.get('soETH')!);
|
||||
const soEthMainnetOracle = new PublicKey(MAINNET_ORACLES.get('soETH')!);
|
||||
await client.tokenRegister(
|
||||
group,
|
||||
soEthMainnetMint,
|
||||
soEthMainnetOracle,
|
||||
defaultOracleConfig,
|
||||
4,
|
||||
'soETH',
|
||||
defaultInterestRate,
|
||||
0.005,
|
||||
0.0005,
|
||||
0.9,
|
||||
0.8,
|
||||
1.1,
|
||||
1.2,
|
||||
0.05,
|
||||
MIN_VAULT_TO_DEPOSITS_RATIO,
|
||||
NET_BORROWS_WINDOW_SIZE_TS,
|
||||
NET_BORROWS_LIMIT_NATIVE,
|
||||
);
|
||||
|
||||
console.log(`Registering SOL...`);
|
||||
const solMainnetMint = new PublicKey(MAINNET_MINTS.get('SOL')!);
|
||||
const solMainnetOracle = new PublicKey(MAINNET_ORACLES.get('SOL')!);
|
||||
await client.tokenRegister(
|
||||
group,
|
||||
solMainnetMint,
|
||||
solMainnetOracle,
|
||||
defaultOracleConfig,
|
||||
5,
|
||||
'SOL',
|
||||
defaultInterestRate,
|
||||
0.005,
|
||||
0.0005,
|
||||
0.9,
|
||||
0.8,
|
||||
1.1,
|
||||
1.2,
|
||||
0.05,
|
||||
MIN_VAULT_TO_DEPOSITS_RATIO,
|
||||
NET_BORROWS_WINDOW_SIZE_TS,
|
||||
NET_BORROWS_LIMIT_NATIVE,
|
||||
);
|
||||
|
||||
console.log(`Registering mSOL...`);
|
||||
const msolMainnetMint = new PublicKey(MAINNET_MINTS.get('mSOL')!);
|
||||
const msolMainnetOracle = new PublicKey(MAINNET_ORACLES.get('mSOL')!);
|
||||
await client.tokenRegister(
|
||||
group,
|
||||
msolMainnetMint,
|
||||
msolMainnetOracle,
|
||||
defaultOracleConfig,
|
||||
6,
|
||||
'mSOL',
|
||||
defaultInterestRate,
|
||||
0.005,
|
||||
0.0005,
|
||||
0.9,
|
||||
0.8,
|
||||
1.1,
|
||||
1.2,
|
||||
0.05,
|
||||
MIN_VAULT_TO_DEPOSITS_RATIO,
|
||||
NET_BORROWS_WINDOW_SIZE_TS,
|
||||
NET_BORROWS_LIMIT_NATIVE,
|
||||
);
|
||||
|
||||
// log tokens/banks
|
||||
await group.reloadAll(client);
|
||||
for (const [bank] of await group.banksMapByMint.values()) {
|
||||
console.log(`${bank.toString()}`);
|
||||
}
|
||||
}
|
||||
|
||||
async function main() {
|
||||
createGroup();
|
||||
registerTokens();
|
||||
}
|
||||
|
||||
try {
|
||||
main();
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
|
@ -6,6 +6,7 @@ import {
|
|||
PublicKey,
|
||||
} from '@solana/web3.js';
|
||||
import fs from 'fs';
|
||||
import { PerpMarketIndex } from '../accounts/perp';
|
||||
import { MangoClient } from '../client';
|
||||
import { MANGO_V4_ID } from '../constants';
|
||||
import { buildVersionedTx } from '../utils';
|
||||
|
@ -20,29 +21,20 @@ import { buildVersionedTx } from '../utils';
|
|||
// * solana airdrop 1 -k ~/.config/solana/admin.json
|
||||
//
|
||||
|
||||
// TODO: switch out with devnet openbook markets
|
||||
// https://github.com/blockworks-foundation/mango-client-v3/blob/main/src/serum.json#L70
|
||||
const DEVNET_SERUM3_MARKETS = new Map([
|
||||
['BTC/USDC', 'DW83EpHFywBxCHmyARxwj3nzxJd7MUdSeznmrdzZKNZB'],
|
||||
['SOL/USDC', '5xWpt56U1NCuHoAEtpLeUrQcxDkEpNfScjfLFaRzLPgR'],
|
||||
['ETH/USDC', 'BkAraCyL9TTLbeMY3L1VWrPcv32DvSi5QDDQjik1J6Ac'],
|
||||
['SRM/USDC', '249LDNPLLL29nRq8kjBTg9hKdXMcZf4vK2UvxszZYcuZ'],
|
||||
['SOL/USDC', '82iPEvGiTceyxYpeLK3DhSwga3R5m4Yfyoydd13CukQ9'],
|
||||
]);
|
||||
const DEVNET_MINTS = new Map([
|
||||
['USDC', '8FRFC6MoGGkMFQwngccyu69VnYbzykGeez7ignHVAFSN'], // use devnet usdc
|
||||
['BTC', '3UNBZ6o52WTWwjac2kPUb4FyodhU1vFkRJheu1Sh2TvU'],
|
||||
['SOL', 'So11111111111111111111111111111111111111112'],
|
||||
['ORCA', 'orcarKHSqC5CDDsGbho8GKvwExejWHxTqGzXgcewB9L'],
|
||||
['MNGO', 'Bb9bsTQa1bGEtQ5KagGkvSHyuLqDWumFUcRqFusFNJWC'],
|
||||
['ETH', 'Cu84KB3tDL6SbFgToHMLYVDJJXdJjenNzSKikeAvzmkA'],
|
||||
['SRM', 'AvtB6w9xboLwA145E221vhof5TddhqsChYcx7Fy3xVMH'],
|
||||
]);
|
||||
const DEVNET_ORACLES = new Map([
|
||||
['BTC', 'HovQMDrbAgAYPCmHVSrezcSmkMtXSSUsLDFANExrZh2J'],
|
||||
['SOL', 'J83w4HKfqxwcq3BEMMkPFSppX3gqekLyLJBexebFVkix'],
|
||||
['ORCA', 'A1WttWF7X3Rg6ZRpB2YQUFHCRh1kiXV8sKKLV3S9neJV'],
|
||||
['MNGO', '8k7F9Xb36oFJsjpCKpsXvg4cgBRoZtwNTc3EzG5Ttd2o'],
|
||||
['BTC', 'HovQMDrbAgAYPCmHVSrezcSmkMtXSSUsLDFANExrZh2J'],
|
||||
['ETH', 'EdVCmQ9FSPcVe5YySXDPCRmc8aDQLKJ9xvYBMZPie1Vw'],
|
||||
['SRM', '992moaMQKs32GKZ9dxi8keyM2bUmbrwBZpK4p2K6X5Vs'],
|
||||
]);
|
||||
|
||||
// TODO: should these constants be baked right into client.ts or even program?
|
||||
|
@ -53,6 +45,8 @@ const NET_BORROWS_LIMIT_NATIVE = 1 * Math.pow(10, 7) * Math.pow(10, 6);
|
|||
const GROUP_NUM = Number(process.env.GROUP_NUM || 0);
|
||||
|
||||
async function main() {
|
||||
let sig;
|
||||
|
||||
const options = AnchorProvider.defaultOptions();
|
||||
const connection = new Connection(
|
||||
'https://mango.devnet.rpcpool.com',
|
||||
|
@ -100,20 +94,19 @@ async function main() {
|
|||
maxRate: 2.0,
|
||||
};
|
||||
|
||||
// stub oracle + register token 0
|
||||
// stub usdc oracle + register token 0
|
||||
console.log(`Registering USDC...`);
|
||||
const usdcDevnetMint = new PublicKey(DEVNET_MINTS.get('USDC')!);
|
||||
try {
|
||||
await client.stubOracleCreate(group, usdcDevnetMint, 1.0);
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
const usdcDevnetOracle = (
|
||||
await client.getStubOracle(group, usdcDevnetMint)
|
||||
)[0];
|
||||
console.log(`...created stub oracle ${usdcDevnetOracle.publicKey}`);
|
||||
try {
|
||||
await client.tokenRegister(
|
||||
sig = await client.stubOracleCreate(group, usdcDevnetMint, 1.0);
|
||||
const usdcDevnetOracle = (
|
||||
await client.getStubOracle(group, usdcDevnetMint)
|
||||
)[0];
|
||||
console.log(
|
||||
`...registered stub oracle ${usdcDevnetOracle}, https://explorer.solana.com/tx/${sig}?cluster=devnet`,
|
||||
);
|
||||
|
||||
sig = await client.tokenRegister(
|
||||
group,
|
||||
usdcDevnetMint,
|
||||
usdcDevnetOracle.publicKey,
|
||||
|
@ -133,48 +126,24 @@ async function main() {
|
|||
NET_BORROWS_LIMIT_NATIVE,
|
||||
);
|
||||
await group.reloadAll(client);
|
||||
const bank = group.getFirstBankByMint(usdcDevnetMint);
|
||||
console.log(
|
||||
`...registered token bank ${bank.publicKey}, https://explorer.solana.com/tx/${sig}?cluster=devnet`,
|
||||
);
|
||||
await group.reloadAll(client);
|
||||
} catch (error) {}
|
||||
|
||||
// register token 1
|
||||
console.log(`Registering BTC...`);
|
||||
const btcDevnetMint = new PublicKey(DEVNET_MINTS.get('BTC')!);
|
||||
const btcDevnetOracle = new PublicKey(DEVNET_ORACLES.get('BTC')!);
|
||||
try {
|
||||
await client.tokenRegister(
|
||||
group,
|
||||
btcDevnetMint,
|
||||
btcDevnetOracle,
|
||||
defaultOracleConfig,
|
||||
1, // tokenIndex
|
||||
'BTC',
|
||||
defaultInterestRate,
|
||||
0.005,
|
||||
0.0005,
|
||||
0.9,
|
||||
0.8,
|
||||
1.1,
|
||||
1.2,
|
||||
0.05,
|
||||
MIN_VAULT_TO_DEPOSITS_RATIO,
|
||||
NET_BORROWS_WINDOW_SIZE_TS,
|
||||
NET_BORROWS_LIMIT_NATIVE,
|
||||
);
|
||||
await group.reloadAll(client);
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
|
||||
// register token 2
|
||||
console.log(`Registering SOL...`);
|
||||
const solDevnetMint = new PublicKey(DEVNET_MINTS.get('SOL')!);
|
||||
const solDevnetOracle = new PublicKey(DEVNET_ORACLES.get('SOL')!);
|
||||
try {
|
||||
await client.tokenRegister(
|
||||
sig = await client.tokenRegister(
|
||||
group,
|
||||
solDevnetMint,
|
||||
solDevnetOracle,
|
||||
defaultOracleConfig,
|
||||
2, // tokenIndex
|
||||
1, // tokenIndex
|
||||
'SOL',
|
||||
defaultInterestRate,
|
||||
0.005,
|
||||
|
@ -189,100 +158,10 @@ async function main() {
|
|||
NET_BORROWS_LIMIT_NATIVE,
|
||||
);
|
||||
await group.reloadAll(client);
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
|
||||
// register token 3
|
||||
console.log(`Registering ORCA...`);
|
||||
const orcaDevnetMint = new PublicKey(DEVNET_MINTS.get('ORCA')!);
|
||||
const orcaDevnetOracle = new PublicKey(DEVNET_ORACLES.get('ORCA')!);
|
||||
try {
|
||||
await client.tokenRegister(
|
||||
group,
|
||||
orcaDevnetMint,
|
||||
orcaDevnetOracle,
|
||||
defaultOracleConfig,
|
||||
3, // tokenIndex
|
||||
'ORCA',
|
||||
{
|
||||
adjustmentFactor: 0.01,
|
||||
util0: 0.4,
|
||||
rate0: 0.07,
|
||||
util1: 0.8,
|
||||
rate1: 0.9,
|
||||
maxRate: 0.63, // weird?
|
||||
},
|
||||
0.0005,
|
||||
0.0005,
|
||||
0.8,
|
||||
0.6,
|
||||
1.2,
|
||||
1.4,
|
||||
0.02,
|
||||
MIN_VAULT_TO_DEPOSITS_RATIO,
|
||||
NET_BORROWS_WINDOW_SIZE_TS,
|
||||
NET_BORROWS_LIMIT_NATIVE,
|
||||
const bank = group.getFirstBankByMint(solDevnetMint);
|
||||
console.log(
|
||||
`...registered token bank ${bank.publicKey}, https://explorer.solana.com/tx/${sig}?cluster=devnet`,
|
||||
);
|
||||
await group.reloadAll(client);
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
|
||||
// register token 7
|
||||
console.log(`Registering ETH...`);
|
||||
const ethDevnetMint = new PublicKey(DEVNET_MINTS.get('ETH')!);
|
||||
const ethDevnetOracle = new PublicKey(DEVNET_ORACLES.get('ETH')!);
|
||||
try {
|
||||
await client.tokenRegister(
|
||||
group,
|
||||
ethDevnetMint,
|
||||
ethDevnetOracle,
|
||||
defaultOracleConfig,
|
||||
7, // tokenIndex
|
||||
'ETH',
|
||||
defaultInterestRate,
|
||||
0.005,
|
||||
0.0005,
|
||||
0.9,
|
||||
0.8,
|
||||
1.1,
|
||||
1.2,
|
||||
0.05,
|
||||
MIN_VAULT_TO_DEPOSITS_RATIO,
|
||||
NET_BORROWS_WINDOW_SIZE_TS,
|
||||
NET_BORROWS_LIMIT_NATIVE,
|
||||
);
|
||||
await group.reloadAll(client);
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
|
||||
// register token 5
|
||||
console.log(`Registering SRM...`);
|
||||
const srmDevnetMint = new PublicKey(DEVNET_MINTS.get('SRM')!);
|
||||
const srmDevnetOracle = new PublicKey(DEVNET_ORACLES.get('SRM')!);
|
||||
try {
|
||||
await client.tokenRegister(
|
||||
group,
|
||||
srmDevnetMint,
|
||||
srmDevnetOracle,
|
||||
defaultOracleConfig,
|
||||
5, // tokenIndex
|
||||
'SRM',
|
||||
defaultInterestRate,
|
||||
0.005,
|
||||
0.0005,
|
||||
0.9,
|
||||
0.8,
|
||||
1.1,
|
||||
1.2,
|
||||
0.05,
|
||||
MIN_VAULT_TO_DEPOSITS_RATIO,
|
||||
NET_BORROWS_WINDOW_SIZE_TS,
|
||||
NET_BORROWS_LIMIT_NATIVE,
|
||||
);
|
||||
await group.reloadAll(client);
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
|
@ -290,91 +169,70 @@ async function main() {
|
|||
console.log(
|
||||
`Editing group, setting existing admin as fastListingAdmin to be able to add MNGO truslessly...`,
|
||||
);
|
||||
let sig = await client.groupEdit(
|
||||
sig = await client.groupEdit(
|
||||
group,
|
||||
group.admin,
|
||||
group.admin,
|
||||
undefined,
|
||||
undefined,
|
||||
);
|
||||
console.log(`sig https://explorer.solana.com/tx/${sig}?cluster=devnet`);
|
||||
console.log(
|
||||
`...edited group, https://explorer.solana.com/tx/${sig}?cluster=devnet`,
|
||||
);
|
||||
console.log(`Registering MNGO...`);
|
||||
const mngoDevnetMint = new PublicKey(DEVNET_MINTS.get('MNGO')!);
|
||||
const mngoDevnetOracle = new PublicKey(DEVNET_ORACLES.get('MNGO')!);
|
||||
try {
|
||||
await client.tokenRegisterTrustless(
|
||||
sig = await client.tokenRegisterTrustless(
|
||||
group,
|
||||
mngoDevnetMint,
|
||||
mngoDevnetOracle,
|
||||
4,
|
||||
2,
|
||||
'MNGO',
|
||||
);
|
||||
await group.reloadAll(client);
|
||||
const bank = group.getFirstBankByMint(mngoDevnetMint);
|
||||
console.log(
|
||||
`...registered token bank ${bank.publicKey}, https://explorer.solana.com/tx/${sig}?cluster=devnet`,
|
||||
);
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
|
||||
// DEBUGGING
|
||||
// log tokens/banks
|
||||
group.consoleLogBanks();
|
||||
// group.consoleLogBanks();
|
||||
|
||||
// register serum market
|
||||
console.log(`Registering serum3 market...`);
|
||||
let serumMarketExternalPk = new PublicKey(
|
||||
DEVNET_SERUM3_MARKETS.get('BTC/USDC')!,
|
||||
);
|
||||
try {
|
||||
await client.serum3RegisterMarket(
|
||||
group,
|
||||
serumMarketExternalPk,
|
||||
group.getFirstBankByMint(btcDevnetMint),
|
||||
group.getFirstBankByMint(usdcDevnetMint),
|
||||
0,
|
||||
'BTC/USDC',
|
||||
);
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
const markets = await client.serum3GetMarkets(
|
||||
group,
|
||||
group.getFirstBankByMint(btcDevnetMint).tokenIndex,
|
||||
group.getFirstBankByMint(usdcDevnetMint).tokenIndex,
|
||||
);
|
||||
console.log(`...registered serum3 market ${markets[0].publicKey}`);
|
||||
|
||||
serumMarketExternalPk = new PublicKey(DEVNET_SERUM3_MARKETS.get('ETH/USDC')!);
|
||||
try {
|
||||
await client.serum3RegisterMarket(
|
||||
group,
|
||||
serumMarketExternalPk,
|
||||
group.getFirstBankByMint(ethDevnetMint),
|
||||
group.getFirstBankByMint(usdcDevnetMint),
|
||||
1,
|
||||
'ETH/USDC',
|
||||
);
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
|
||||
serumMarketExternalPk = new PublicKey(DEVNET_SERUM3_MARKETS.get('SRM/USDC')!);
|
||||
try {
|
||||
await client.serum3RegisterMarket(
|
||||
group,
|
||||
serumMarketExternalPk,
|
||||
group.getFirstBankByMint(srmDevnetMint),
|
||||
group.getFirstBankByMint(usdcDevnetMint),
|
||||
2,
|
||||
'SRM/USDC',
|
||||
);
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
// // register serum market
|
||||
// const serumMarketExternalPk = new PublicKey(
|
||||
// DEVNET_SERUM3_MARKETS.get('SOL/USDC')!,
|
||||
// );
|
||||
// try {
|
||||
// sig = await client.serum3RegisterMarket(
|
||||
// group,
|
||||
// serumMarketExternalPk,
|
||||
// group.getFirstBankByMint(solDevnetMint),
|
||||
// group.getFirstBankByMint(usdcDevnetMint),
|
||||
// 0,
|
||||
// 'SOL/USDC',
|
||||
// );
|
||||
// await group.reloadAll(client);
|
||||
// const serum3Market = group.getSerum3MarketByExternalMarket(
|
||||
// serumMarketExternalPk,
|
||||
// );
|
||||
// console.log(
|
||||
// `...registered serum market ${serum3Market.publicKey}, https://explorer.solana.com/tx/${sig}?cluster=devnet`,
|
||||
// );
|
||||
// } catch (error) {
|
||||
// console.log(error);
|
||||
// }
|
||||
|
||||
// register perp market
|
||||
console.log(`Registering perp market...`);
|
||||
try {
|
||||
await client.perpCreateMarket(
|
||||
sig = await client.perpCreateMarket(
|
||||
group,
|
||||
btcDevnetOracle,
|
||||
new PublicKey(DEVNET_ORACLES.get('BTC')!),
|
||||
0,
|
||||
'BTC-PERP',
|
||||
defaultOracleConfig,
|
||||
|
@ -401,164 +259,20 @@ async function main() {
|
|||
1.0,
|
||||
2 * 60 * 60,
|
||||
);
|
||||
console.log('done');
|
||||
await group.reloadAll(client);
|
||||
const perpMarket = group.getPerpMarketByMarketIndex(0 as PerpMarketIndex);
|
||||
console.log(
|
||||
`...registered perp market ${perpMarket.publicKey}, https://explorer.solana.com/tx/${sig}?cluster=devnet`,
|
||||
);
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
const perpMarkets = await client.perpGetMarkets(group);
|
||||
console.log(`...created perp market ${perpMarkets[0].publicKey}`);
|
||||
|
||||
//
|
||||
// edit
|
||||
//
|
||||
|
||||
if (true) {
|
||||
console.log(`Editing USDC...`);
|
||||
if (group.addressLookupTables[0].equals(PublicKey.default)) {
|
||||
try {
|
||||
let sig = await client.tokenEdit(
|
||||
group,
|
||||
usdcDevnetMint,
|
||||
usdcDevnetOracle.publicKey,
|
||||
defaultOracleConfig,
|
||||
null,
|
||||
defaultInterestRate,
|
||||
0.005,
|
||||
0.0005,
|
||||
1,
|
||||
1,
|
||||
1,
|
||||
1,
|
||||
0,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
MIN_VAULT_TO_DEPOSITS_RATIO,
|
||||
NET_BORROWS_WINDOW_SIZE_TS,
|
||||
NET_BORROWS_LIMIT_NATIVE,
|
||||
null,
|
||||
null,
|
||||
false,
|
||||
false,
|
||||
);
|
||||
console.log(`https://explorer.solana.com/tx/${sig}?cluster=devnet`);
|
||||
await group.reloadAll(client);
|
||||
console.log(group.getFirstBankByMint(btcDevnetMint).toString());
|
||||
} catch (error) {
|
||||
throw error;
|
||||
}
|
||||
|
||||
console.log(`Editing BTC...`);
|
||||
try {
|
||||
let sig = await client.tokenEdit(
|
||||
group,
|
||||
usdcDevnetMint,
|
||||
usdcDevnetOracle.publicKey,
|
||||
defaultOracleConfig,
|
||||
null,
|
||||
defaultInterestRate,
|
||||
0.005,
|
||||
0.0005,
|
||||
0.9,
|
||||
0.8,
|
||||
1.1,
|
||||
1.2,
|
||||
0.05,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
MIN_VAULT_TO_DEPOSITS_RATIO,
|
||||
NET_BORROWS_WINDOW_SIZE_TS,
|
||||
NET_BORROWS_LIMIT_NATIVE,
|
||||
null,
|
||||
null,
|
||||
false,
|
||||
false,
|
||||
);
|
||||
console.log(`https://explorer.solana.com/tx/${sig}?cluster=devnet`);
|
||||
await group.reloadAll(client);
|
||||
console.log(group.getFirstBankByMint(btcDevnetMint).toString());
|
||||
} catch (error) {
|
||||
throw error;
|
||||
}
|
||||
|
||||
console.log(`Editing SOL...`);
|
||||
try {
|
||||
let sig = await client.tokenEdit(
|
||||
group,
|
||||
usdcDevnetMint,
|
||||
usdcDevnetOracle.publicKey,
|
||||
defaultOracleConfig,
|
||||
null,
|
||||
defaultInterestRate,
|
||||
0.005,
|
||||
0.0005,
|
||||
0.9,
|
||||
0.8,
|
||||
1.1,
|
||||
1.2,
|
||||
0.05,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
MIN_VAULT_TO_DEPOSITS_RATIO,
|
||||
NET_BORROWS_WINDOW_SIZE_TS,
|
||||
NET_BORROWS_LIMIT_NATIVE,
|
||||
null,
|
||||
null,
|
||||
false,
|
||||
false,
|
||||
);
|
||||
console.log(`https://explorer.solana.com/tx/${sig}?cluster=devnet`);
|
||||
await group.reloadAll(client);
|
||||
console.log(group.getFirstBankByMint(btcDevnetMint).toString());
|
||||
} catch (error) {
|
||||
throw error;
|
||||
}
|
||||
|
||||
console.log(`Editing BTC-PERP...`);
|
||||
try {
|
||||
let sig = await client.perpEditMarket(
|
||||
group,
|
||||
group.getPerpMarketByName('BTC-PERP').perpMarketIndex,
|
||||
btcDevnetOracle,
|
||||
defaultOracleConfig,
|
||||
6,
|
||||
0.975,
|
||||
0.95,
|
||||
1.025,
|
||||
1.05,
|
||||
0.012,
|
||||
0.0002,
|
||||
0.0,
|
||||
0,
|
||||
0.05,
|
||||
0.05,
|
||||
100,
|
||||
true,
|
||||
true,
|
||||
1000,
|
||||
1000000,
|
||||
0.05,
|
||||
MIN_VAULT_TO_DEPOSITS_RATIO,
|
||||
NET_BORROWS_WINDOW_SIZE_TS,
|
||||
NET_BORROWS_LIMIT_NATIVE,
|
||||
1.0,
|
||||
2 * 60 * 60,
|
||||
);
|
||||
console.log(`https://explorer.solana.com/tx/${sig}?cluster=devnet`);
|
||||
await group.reloadAll(client);
|
||||
console.log(group.getFirstBankByMint(btcDevnetMint).toString());
|
||||
} catch (error) {
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
if (
|
||||
// true
|
||||
group.addressLookupTables[0].equals(PublicKey.default)
|
||||
) {
|
||||
try {
|
||||
console.log(`ALT: Creating`);
|
||||
console.log(`ALT...`);
|
||||
const createIx = AddressLookupTableProgram.createLookupTable({
|
||||
authority: admin.publicKey,
|
||||
payer: admin.publicKey,
|
||||
|
@ -568,37 +282,20 @@ async function main() {
|
|||
client.program.provider as AnchorProvider,
|
||||
[createIx[0]],
|
||||
);
|
||||
let sig = await connection.sendTransaction(createTx);
|
||||
sig = await connection.sendTransaction(createTx);
|
||||
console.log(
|
||||
`...created ALT ${createIx[1]} https://explorer.solana.com/tx/${sig}?cluster=devnet`,
|
||||
);
|
||||
|
||||
console.log(`ALT: set at index 0 for group...`);
|
||||
sig = await client.altSet(
|
||||
group,
|
||||
new PublicKey('EmN5RjHUFsoag7tZ2AyBL2N8JrhV7nLMKgNbpCfzC81D'),
|
||||
0,
|
||||
);
|
||||
console.log(`...https://explorer.solana.com/tx/${sig}?cluster=devnet`);
|
||||
|
||||
// Extend using a mango v4 program ix
|
||||
// Throws > Instruction references an unknown account 11111111111111111111111111111111 atm
|
||||
//
|
||||
console.log(
|
||||
`ALT: extending using mango v4 program with bank publick keys and oracles`,
|
||||
`...set at index 0 for group https://explorer.solana.com/tx/${sig}?cluster=devnet`,
|
||||
);
|
||||
// let sig = await client.altExtend(
|
||||
// group,
|
||||
// new PublicKey('EmN5RjHUFsoag7tZ2AyBL2N8JrhV7nLMKgNbpCfzC81D'),
|
||||
// 0,
|
||||
// Array.from(group.banksMapByMint.values())
|
||||
// .flat()
|
||||
// .map((bank) => [bank.publicKey, bank.oracle])
|
||||
// .flat(),
|
||||
// );
|
||||
// console.log(`https://explorer.solana.com/tx/${sig}?cluster=devnet`);
|
||||
|
||||
console.log(`ALT: extending manually with bank publick keys and oracles`);
|
||||
const extendIx = AddressLookupTableProgram.extendLookupTable({
|
||||
lookupTable: createIx[1],
|
||||
payer: admin.publicKey,
|
||||
|
@ -613,7 +310,9 @@ async function main() {
|
|||
[extendIx],
|
||||
);
|
||||
sig = await client.program.provider.connection.sendTransaction(extendTx);
|
||||
console.log(`https://explorer.solana.com/tx/${sig}?cluster=devnet`);
|
||||
console.log(
|
||||
`...extended ALT with pks, https://explorer.solana.com/tx/${sig}?cluster=devnet`,
|
||||
);
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
import * as dotenv from 'dotenv';
|
||||
dotenv.config();
|
||||
import { AnchorProvider, Wallet } from '@project-serum/anchor';
|
||||
import { Connection, Keypair } from '@solana/web3.js';
|
||||
import * as dotenv from 'dotenv';
|
||||
import fs from 'fs';
|
||||
import { PerpMarket } from '../accounts/perp';
|
||||
import { MangoClient } from '../client';
|
||||
import { MANGO_V4_ID } from '../constants';
|
||||
dotenv.config();
|
||||
|
||||
//
|
||||
// (untested?) script which closes a mango account cleanly, first closes all positions, withdraws all tokens and then closes it
|
||||
|
@ -32,13 +33,16 @@ async function editPerpMarket(perpMarketName: string) {
|
|||
const group = await client.getGroupForCreator(admin.publicKey, 2);
|
||||
console.log(`Found group ${group.publicKey.toBase58()}`);
|
||||
|
||||
const pm = group.getPerpMarketByName(perpMarketName);
|
||||
const pm: PerpMarket = group.getPerpMarketByName(perpMarketName);
|
||||
|
||||
const signature = await client.perpEditMarket(
|
||||
group,
|
||||
pm.perpMarketIndex,
|
||||
pm.oracle,
|
||||
pm.confFilter.toNumber(),
|
||||
{
|
||||
confFilter: pm.oracleConfig.confFilter.toNumber(),
|
||||
maxStalenessSlots: null,
|
||||
},
|
||||
pm.baseDecimals,
|
||||
pm.maintAssetWeight.toNumber(),
|
||||
pm.initAssetWeight.toNumber(),
|
||||
|
@ -57,6 +61,11 @@ async function editPerpMarket(perpMarketName: string) {
|
|||
pm.settleFeeFlat,
|
||||
pm.settleFeeAmountThreshold,
|
||||
pm.settleFeeFractionLowHealth,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
);
|
||||
|
||||
console.log('Tx Successful:', signature);
|
||||
|
|
|
@ -20,9 +20,7 @@ import { buildVersionedTx } from '../utils';
|
|||
const MAINNET_MINTS = new Map([
|
||||
['USDC', 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v'],
|
||||
['USDT', 'Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB'],
|
||||
['BTC', '9n4nbM75f5Ui33ZbPYXn59EwSgE8CGsHtAeTH5YFeJ9E'], // Wrapped Bitcoin (Sollet)
|
||||
['ETH', '7vfCXTUXx5WJV5JADk17DUJ4ksgau7utNKj4b963voxs'], // Ether (Portal)
|
||||
['soETH', '2FPyTwcZLUg1MDrwsyoP4D6s1tM7hAkHYRjkNb5w6Pxk'], // Wrapped Ethereum (Sollet)
|
||||
['SOL', 'So11111111111111111111111111111111111111112'], // Wrapped SOL
|
||||
['MSOL', 'mSoLzYCxHdYgdzU16g5QSh3i5K3z3KZK7ytfqcJm7So'],
|
||||
['MNGO', 'MangoCzJ36AjZyKwVj3VnYU4GTonjfVEnJmvvWaxLac'],
|
||||
|
@ -33,7 +31,6 @@ const MAINNET_ORACLES = new Map([
|
|||
['USDT', '3vxLXJqLqF3JG5TCbYycbKWRBbCJQLxQmBGCkyqEEefL'],
|
||||
['BTC', 'GVXRSBjFk6e6J3NbVPXohDJetcTjaeeuykUpbQF8UoMU'],
|
||||
['ETH', 'JBu1AL4obBcCMqKBBxhpWCNUt136ijcuMZLFvTP7iWdB'],
|
||||
['soETH', 'JBu1AL4obBcCMqKBBxhpWCNUt136ijcuMZLFvTP7iWdB'],
|
||||
['SOL', 'H6ARHf6YXhGYeQfUzQNGk6rDNnLBQKrenN712K4AQJEG'],
|
||||
['MSOL', 'E4v1BBgoso9s64TQvmyownAVJbhbEPGyzA3qn4n46qj9'],
|
||||
['MNGO', '79wm3jjcPr6RaNQ4DGvP5KxG1mNd3gEBsg6FsNVFezK4'],
|
||||
|
@ -41,14 +38,9 @@ const MAINNET_ORACLES = new Map([
|
|||
['DUST', 'C5tuUPi7xJHBHZGZX6wWYf1Svm6jtTVwYrYrBCiEVejK'],
|
||||
]);
|
||||
|
||||
// External markets are matched with those in https://github.com/blockworks-foundation/mango-client-v3/blob/main/src/ids.json
|
||||
// and verified to have best liquidity for pair on https://openserum.io/
|
||||
// TODO: replace with markets from https://github.com/openbook-dex/resources/blob/main/markets.json
|
||||
// External markets are matched with those in https://github.com/openbook-dex/openbook-ts/blob/master/packages/serum/src/markets.json
|
||||
const MAINNET_SERUM3_MARKETS = new Map([
|
||||
['BTC/USDC', 'A8YFbxQYFVqKZaoYJLLUVcQiWP7G2MeEgW5wsAQgMvFw'],
|
||||
['SOL/USDC', '9wFFyRfZBsuAha4YcuxcXLKwMxJR43S7fPfQLusDBzvT'],
|
||||
['RAY/SOL', 'C6tp2RVZnxBPFbnAsfTjis8BN9tycESAT4SgDQgbbrsA'],
|
||||
['DUST/SOL', '8WCzJpSNcLUYXPYeUDAXpH4hgqxFJpkYkVT6GJDSpcGx'],
|
||||
]);
|
||||
|
||||
const MIN_VAULT_TO_DEPOSITS_RATIO = 0.2;
|
||||
|
@ -193,29 +185,6 @@ async function registerTokens() {
|
|||
NET_BORROWS_LIMIT_NATIVE,
|
||||
);
|
||||
|
||||
console.log(`Registering BTC...`);
|
||||
const btcMainnetMint = new PublicKey(MAINNET_MINTS.get('BTC')!);
|
||||
const btcMainnetOracle = new PublicKey(MAINNET_ORACLES.get('BTC')!);
|
||||
await client.tokenRegister(
|
||||
group,
|
||||
btcMainnetMint,
|
||||
btcMainnetOracle,
|
||||
defaultOracleConfig,
|
||||
2,
|
||||
'BTC',
|
||||
defaultInterestRate,
|
||||
0.005,
|
||||
0.0005,
|
||||
0.9,
|
||||
0.8,
|
||||
1.1,
|
||||
1.2,
|
||||
0.05,
|
||||
MIN_VAULT_TO_DEPOSITS_RATIO,
|
||||
NET_BORROWS_WINDOW_SIZE_TS,
|
||||
NET_BORROWS_LIMIT_NATIVE,
|
||||
);
|
||||
|
||||
console.log(`Registering ETH...`);
|
||||
const ethMainnetMint = new PublicKey(MAINNET_MINTS.get('ETH')!);
|
||||
const ethMainnetOracle = new PublicKey(MAINNET_ORACLES.get('ETH')!);
|
||||
|
@ -239,29 +208,6 @@ async function registerTokens() {
|
|||
NET_BORROWS_LIMIT_NATIVE,
|
||||
);
|
||||
|
||||
console.log(`Registering soETH...`);
|
||||
const soEthMainnetMint = new PublicKey(MAINNET_MINTS.get('soETH')!);
|
||||
const soEthMainnetOracle = new PublicKey(MAINNET_ORACLES.get('soETH')!);
|
||||
await client.tokenRegister(
|
||||
group,
|
||||
soEthMainnetMint,
|
||||
soEthMainnetOracle,
|
||||
defaultOracleConfig,
|
||||
4,
|
||||
'soETH',
|
||||
defaultInterestRate,
|
||||
0.005,
|
||||
0.0005,
|
||||
0.9,
|
||||
0.8,
|
||||
1.1,
|
||||
1.2,
|
||||
0.05,
|
||||
MIN_VAULT_TO_DEPOSITS_RATIO,
|
||||
NET_BORROWS_WINDOW_SIZE_TS,
|
||||
NET_BORROWS_LIMIT_NATIVE,
|
||||
);
|
||||
|
||||
console.log(`Registering SOL...`);
|
||||
const solMainnetMint = new PublicKey(MAINNET_MINTS.get('SOL')!);
|
||||
const solMainnetOracle = new PublicKey(MAINNET_ORACLES.get('SOL')!);
|
||||
|
@ -404,15 +350,8 @@ async function registerSerum3Markets() {
|
|||
1,
|
||||
);
|
||||
|
||||
// Register BTC and SOL markets
|
||||
await client.serum3RegisterMarket(
|
||||
group,
|
||||
new PublicKey(MAINNET_SERUM3_MARKETS.get('BTC/USDC')!),
|
||||
group.getFirstBankByMint(new PublicKey(MAINNET_MINTS.get('BTC')!)),
|
||||
group.getFirstBankByMint(new PublicKey(MAINNET_MINTS.get('USDC')!)),
|
||||
0,
|
||||
'BTC/USDC',
|
||||
);
|
||||
// Register SOL serum market
|
||||
|
||||
await client.serum3RegisterMarket(
|
||||
group,
|
||||
new PublicKey(MAINNET_SERUM3_MARKETS.get('SOL/USDC')!),
|
||||
|
@ -421,24 +360,6 @@ async function registerSerum3Markets() {
|
|||
1,
|
||||
'SOL/USDC',
|
||||
);
|
||||
|
||||
// Register RAY and DUST markets
|
||||
await client.serum3RegisterMarket(
|
||||
group,
|
||||
new PublicKey(MAINNET_SERUM3_MARKETS.get('RAY/SOL')!),
|
||||
group.getFirstBankByMint(new PublicKey(MAINNET_MINTS.get('RAY')!)),
|
||||
group.getFirstBankByMint(new PublicKey(MAINNET_MINTS.get('SOL')!)),
|
||||
2,
|
||||
'RAY/SOL',
|
||||
);
|
||||
await client.serum3RegisterMarket(
|
||||
group,
|
||||
new PublicKey(MAINNET_SERUM3_MARKETS.get('DUST/SOL')!),
|
||||
group.getFirstBankByMint(new PublicKey(MAINNET_MINTS.get('DUST')!)),
|
||||
group.getFirstBankByMint(new PublicKey(MAINNET_MINTS.get('SOL')!)),
|
||||
3,
|
||||
'DUST/SOL',
|
||||
);
|
||||
}
|
||||
|
||||
async function unregisterSerum3Markets() {
|
||||
|
|
|
@ -114,8 +114,8 @@ async function refreshState(
|
|||
mc.perpMarket = group.getPerpMarketByMarketIndex(
|
||||
perpMarket.perpMarketIndex,
|
||||
);
|
||||
mc.bids = await perpMarket.loadBids(client);
|
||||
mc.asks = await perpMarket.loadAsks(client);
|
||||
mc.bids = await perpMarket.loadBids(client, true);
|
||||
mc.asks = await perpMarket.loadAsks(client, true);
|
||||
mc.lastBookUpdate = ts;
|
||||
|
||||
mc.binanceAsk = parseFloat((result[i + 2] as any).asks[0].price);
|
||||
|
@ -448,6 +448,7 @@ async function makeMarketUpdateInstructions(
|
|||
const expiryTimestamp =
|
||||
params.tif !== undefined ? Date.now() / 1000 + params.tif : 0;
|
||||
|
||||
// TODO: oracle pegged runs out of free perp open order slots on mango account
|
||||
if (params.oraclePegged) {
|
||||
const uiOPegBidOffset = fairValue * (-charge + lean + bias + pfQuoteLean);
|
||||
const uiOPegAskOffset = fairValue * (charge + lean + bias + pfQuoteLean);
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"interval": 1000,
|
||||
"oraclePegged": true,
|
||||
"oraclePegged": false,
|
||||
"batch": 1,
|
||||
"assets": {
|
||||
"BTC": {
|
||||
|
|
|
@ -7,7 +7,7 @@ import { PerpMarket, PerpOrderSide, PerpOrderType } from '../../accounts/perp';
|
|||
import { MangoClient } from '../../client';
|
||||
import { MANGO_V4_ID } from '../../constants';
|
||||
import { ZERO_I80F48 } from '../../numbers/I80F48';
|
||||
import { toUiDecimalsForQuote } from '../../utils';
|
||||
import { toNativeI80F48, toUiDecimalsForQuote } from '../../utils';
|
||||
|
||||
// For easy switching between mainnet and devnet, default is mainnet
|
||||
const CLUSTER: Cluster =
|
||||
|
@ -33,13 +33,35 @@ async function settlePnl(
|
|||
.find((pp) => pp.marketIndex === perpMarket.perpMarketIndex)!;
|
||||
const pnl = pp.getPnl(perpMarket);
|
||||
|
||||
console.log(
|
||||
`Avg entry price - ${pp.getAverageEntryPriceUi(
|
||||
perpMarket,
|
||||
)}, Breakeven price - ${pp.getBreakEvenPriceUi(perpMarket)}`,
|
||||
);
|
||||
|
||||
let profitableAccount, unprofitableAccount;
|
||||
|
||||
if (pnl.abs().gt(toNativeI80F48(1, 6))) {
|
||||
console.log(`- Settling pnl ${toUiDecimalsForQuote(pnl)} ...`);
|
||||
} else {
|
||||
console.log(
|
||||
`- Skipping Settling pnl ${toUiDecimalsForQuote(pnl)}, too small`,
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
if (pnl.gt(ZERO_I80F48())) {
|
||||
console.log(`- Settling profit pnl...`);
|
||||
profitableAccount = mangoAccount;
|
||||
unprofitableAccount = (
|
||||
await perpMarket.getSettlePnlCandidates(client, group, 'negative')
|
||||
)[0].account;
|
||||
const candidates = await perpMarket.getSettlePnlCandidates(
|
||||
client,
|
||||
group,
|
||||
'negative',
|
||||
);
|
||||
if (candidates.length === 0) {
|
||||
return;
|
||||
}
|
||||
unprofitableAccount = candidates[0].account;
|
||||
const sig = await client.perpSettlePnl(
|
||||
group,
|
||||
profitableAccount,
|
||||
|
@ -48,16 +70,23 @@ async function settlePnl(
|
|||
perpMarket.perpMarketIndex,
|
||||
);
|
||||
console.log(
|
||||
`Settled pnl, sig https://explorer.solana.com/tx/${sig}?cluster=${
|
||||
`- Settled pnl, sig https://explorer.solana.com/tx/${sig}?cluster=${
|
||||
CLUSTER == 'devnet' ? 'devnet' : ''
|
||||
}`,
|
||||
);
|
||||
} else if (pnl.lt(ZERO_I80F48())) {
|
||||
unprofitableAccount = mangoAccount;
|
||||
profitableAccount = (
|
||||
await perpMarket.getSettlePnlCandidates(client, group, 'positive')
|
||||
)[0].account;
|
||||
const sig = await client.perpSettlePnl(
|
||||
const candidates = await perpMarket.getSettlePnlCandidates(
|
||||
client,
|
||||
group,
|
||||
'positive',
|
||||
);
|
||||
if (candidates.length === 0) {
|
||||
return;
|
||||
}
|
||||
profitableAccount = candidates[0].account;
|
||||
console.log(`- Settling loss pnl...`);
|
||||
let sig = await client.perpSettlePnl(
|
||||
group,
|
||||
profitableAccount,
|
||||
unprofitableAccount,
|
||||
|
@ -65,7 +94,7 @@ async function settlePnl(
|
|||
perpMarket.perpMarketIndex,
|
||||
);
|
||||
console.log(
|
||||
`Settled pnl, sig https://explorer.solana.com/tx/${sig}?cluster=${
|
||||
`- Settled pnl, sig https://explorer.solana.com/tx/${sig}?cluster=${
|
||||
CLUSTER == 'devnet' ? 'devnet' : ''
|
||||
}`,
|
||||
);
|
||||
|
@ -87,7 +116,7 @@ async function takeOrder(
|
|||
? perpMarket.uiPrice * 1.01
|
||||
: perpMarket.uiPrice * 0.99;
|
||||
console.log(
|
||||
`${perpMarket.name} taking with a ${
|
||||
`- ${perpMarket.name} taking with a ${
|
||||
side === PerpOrderSide.bid ? 'bid' : 'ask'
|
||||
} at price ${price.toFixed(4)} and size ${size.toFixed(6)}`,
|
||||
);
|
||||
|
@ -95,7 +124,7 @@ async function takeOrder(
|
|||
const oldPosition = mangoAccount.getPerpPosition(perpMarket.perpMarketIndex);
|
||||
if (oldPosition) {
|
||||
console.log(
|
||||
`- before base: ${perpMarket.baseLotsToUi(
|
||||
`-- before base: ${perpMarket.baseLotsToUi(
|
||||
oldPosition.basePositionLots,
|
||||
)}, quote: ${toUiDecimalsForQuote(oldPosition.quotePositionNative)}`,
|
||||
);
|
||||
|
@ -122,7 +151,7 @@ async function takeOrder(
|
|||
const newPosition = mangoAccount.getPerpPosition(perpMarket.perpMarketIndex);
|
||||
if (newPosition) {
|
||||
console.log(
|
||||
`- after base: ${perpMarket.baseLotsToUi(
|
||||
`-- after base: ${perpMarket.baseLotsToUi(
|
||||
newPosition.basePositionLots,
|
||||
)}, quote: ${toUiDecimalsForQuote(newPosition.quotePositionNative)}`,
|
||||
);
|
||||
|
|
Loading…
Reference in New Issue