From e7c2ae83800456ff5bdd5f818eb19140bc718397 Mon Sep 17 00:00:00 2001 From: Tyler Shipe Date: Mon, 22 Feb 2021 17:08:07 -0500 Subject: [PATCH] Revert "prettier" This reverts commit 460eae585807f89c33ad91e1e072cf9c237cd5db. --- package.json | 3 +- src/client.ts | 711 ++++++++++++++++++++++++++------------------------ src/layout.ts | 99 ++++--- 3 files changed, 436 insertions(+), 377 deletions(-) diff --git a/package.json b/package.json index 5e3a217..e50372b 100644 --- a/package.json +++ b/package.json @@ -52,8 +52,7 @@ ], "prettier": { "singleQuote": true, - "trailingComma": "all", - "printWidth": 120 + "trailingComma": "all" }, "dependencies": { "@project-serum/serum": "^0.13.20", diff --git a/src/client.ts b/src/client.ts index f919785..ab595d8 100644 --- a/src/client.ts +++ b/src/client.ts @@ -33,13 +33,14 @@ import { Order } from '@project-serum/serum/lib/market'; import Wallet from '@project-serum/sol-wallet-adapter'; import { makeCancelOrderInstruction, makeSettleFundsInstruction } from './instruction'; + export class MangoGroup { publicKey: PublicKey; accountFlags!: WideBits; tokens!: PublicKey[]; vaults!: PublicKey[]; - indexes!: { lastUpdate: BN; borrow: number; deposit: number }; + indexes!: { lastUpdate: BN, borrow: number, deposit: number }; spotMarkets!: PublicKey[]; oracles!: PublicKey[]; signerNonce!: BN; @@ -58,47 +59,49 @@ export class MangoGroup { Object.assign(this, decoded); } - async getPrices(connection: Connection): Promise { + async getPrices( + connection: Connection, + ): Promise { const oracleAccs = await getMultipleAccounts(connection, this.oracles); - return oracleAccs.map((oa) => decodeAggregatorInfo(oa.accountInfo).submissionValue).concat(1.0); + return oracleAccs.map((oa) => decodeAggregatorInfo(oa.accountInfo).submissionValue).concat(1.0) } getMarketIndex(spotMarket: Market): number { for (let i = 0; i < this.spotMarkets.length; i++) { if (this.spotMarkets[i].equals(spotMarket.publicKey)) { - return i; + return i } } - throw new Error('This Market does not belong to this MangoGroup'); + throw new Error("This Market does not belong to this MangoGroup") } getTokenIndex(token: PublicKey): number { for (let i = 0; i < this.tokens.length; i++) { if (this.tokens[i].equals(token)) { - return i; + return i } } - throw new Error('This token does not belong in this MangoGroup'); + throw new Error("This token does not belong in this MangoGroup") } getBorrowRate(tokenIndex: number): number { - return 0.0; // TODO + return 0.0 // TODO } getDepositRate(tokenIndex: number): number { - return 0.0; // TODO + return 0.0 // TODO } getUiTotalDeposit(tokenIndex: number): number { - return nativeToUi(this.totalDeposits[tokenIndex] * this.indexes[tokenIndex].deposit, this.mintDecimals[tokenIndex]); + return nativeToUi(this.totalDeposits[tokenIndex] * this.indexes[tokenIndex].deposit, this.mintDecimals[tokenIndex]) } getUiTotalBorrow(tokenIndex: number): number { - return nativeToUi(this.totalBorrows[tokenIndex] * this.indexes[tokenIndex].borrow, this.mintDecimals[tokenIndex]); + return nativeToUi(this.totalBorrows[tokenIndex] * this.indexes[tokenIndex].borrow, this.mintDecimals[tokenIndex]) } } export class MarginAccount { publicKey: PublicKey; - createTime: number; // used to determine when to update + createTime: number; // used to determine when to update // TODO maybe this is obviated by websocket feed onUpdate accountFlags!: WideBits; @@ -108,144 +111,151 @@ export class MarginAccount { borrows!: number[]; openOrders!: PublicKey[]; srmBalance!: number; - openOrdersAccounts: (OpenOrders | undefined)[]; // undefined if an openOrdersAccount not yet initialized and has zeroKey + openOrdersAccounts: (OpenOrders | undefined)[] // undefined if an openOrdersAccount not yet initialized and has zeroKey // TODO keep updated with websocket constructor(publicKey: PublicKey, decoded: any) { - this.publicKey = publicKey; - this.createTime = getUnixTs(); - this.openOrdersAccounts = new Array(NUM_MARKETS).fill(undefined); - Object.assign(this, decoded); + this.publicKey = publicKey + this.createTime = getUnixTs() + this.openOrdersAccounts = new Array(NUM_MARKETS).fill(undefined) + Object.assign(this, decoded) } - getNativeDeposit(mangoGroup: MangoGroup, tokenIndex: number): number { - // insufficient precision - return Math.round(mangoGroup.indexes[tokenIndex].deposit * this.deposits[tokenIndex]); + getNativeDeposit(mangoGroup: MangoGroup, tokenIndex: number): number { // insufficient precision + return Math.round(mangoGroup.indexes[tokenIndex].deposit * this.deposits[tokenIndex]) } - getNativeBorrow(mangoGroup: MangoGroup, tokenIndex: number): number { - // insufficient precision - return Math.round(mangoGroup.indexes[tokenIndex].borrow * this.borrows[tokenIndex]); + getNativeBorrow(mangoGroup: MangoGroup, tokenIndex: number): number { // insufficient precision + return Math.round(mangoGroup.indexes[tokenIndex].borrow * this.borrows[tokenIndex]) } - getUiDeposit(mangoGroup: MangoGroup, tokenIndex: number): number { - // insufficient precision - return nativeToUi(this.getNativeDeposit(mangoGroup, tokenIndex), mangoGroup.mintDecimals[tokenIndex]); + getUiDeposit(mangoGroup: MangoGroup, tokenIndex: number): number { // insufficient precision + return nativeToUi(this.getNativeDeposit(mangoGroup, tokenIndex), mangoGroup.mintDecimals[tokenIndex]) } - getUiBorrow(mangoGroup: MangoGroup, tokenIndex: number): number { - // insufficient precision - return nativeToUi(this.getNativeBorrow(mangoGroup, tokenIndex), mangoGroup.mintDecimals[tokenIndex]); + getUiBorrow(mangoGroup: MangoGroup, tokenIndex: number): number { // insufficient precision + return nativeToUi(this.getNativeBorrow(mangoGroup, tokenIndex), mangoGroup.mintDecimals[tokenIndex]) } getUiSrmBalance() { - return nativeToUi(this.srmBalance, SRM_DECIMALS); + return nativeToUi(this.srmBalance, SRM_DECIMALS) } - async loadOpenOrders(connection: Connection, dexProgramId: PublicKey): Promise<(OpenOrders | undefined)[]> { - const promises: Promise[] = []; + async loadOpenOrders( + connection: Connection, + dexProgramId: PublicKey + ): Promise<(OpenOrders | undefined)[]> { + const promises: Promise[] = [] for (let i = 0; i < this.openOrders.length; i++) { if (this.openOrders[i].equals(zeroKey)) { - promises.push(promiseUndef()); + promises.push(promiseUndef()) } else { - promises.push(OpenOrders.load(connection, this.openOrders[i], dexProgramId)); + promises.push(OpenOrders.load(connection, this.openOrders[i], dexProgramId)) } } - this.openOrdersAccounts = await Promise.all(promises); - return this.openOrdersAccounts; + this.openOrdersAccounts = await Promise.all(promises) + return this.openOrdersAccounts } - toPrettyString(mangoGroup: MangoGroup): string { - const lines = [`MarginAccount: ${this.publicKey.toBase58()}`, `Asset Deposits Borrows`]; + toPrettyString( + mangoGroup: MangoGroup + ): string { + const lines = [ + `MarginAccount: ${this.publicKey.toBase58()}`, + `Asset Deposits Borrows`, + ] - const tokenNames = ['BTC', 'ETH', 'USDC']; // TODO pull this from somewhere + const tokenNames = ["BTC", "ETH", "USDC"] // TODO pull this from somewhere for (let i = 0; i < mangoGroup.tokens.length; i++) { - lines.push(`${tokenNames[i]} ${this.getUiDeposit(mangoGroup, i)} ${this.getUiBorrow(mangoGroup, i)}`); + lines.push( + `${tokenNames[i]} ${this.getUiDeposit(mangoGroup, i)} ${this.getUiBorrow(mangoGroup, i)}` + ) } - return lines.join('\n'); + return lines.join('\n') } - async getValue(connection: Connection, mangoGroup: MangoGroup): Promise { - const prices = await mangoGroup.getPrices(connection); + async getValue( + connection: Connection, + mangoGroup: MangoGroup + ): Promise { + const prices = await mangoGroup.getPrices(connection) - let value = 0; + let value = 0 for (let i = 0; i < this.deposits.length; i++) { - value += (this.getUiDeposit(mangoGroup, i) - this.getUiBorrow(mangoGroup, i)) * prices[i]; + value += (this.getUiDeposit(mangoGroup, i) - this.getUiBorrow(mangoGroup, i)) * prices[i] } for (let i = 0; i < this.openOrdersAccounts.length; i++) { - const oos = this.openOrdersAccounts[i]; + const oos = this.openOrdersAccounts[i] if (oos != undefined) { - value += nativeToUi(oos.baseTokenTotal.toNumber(), mangoGroup.mintDecimals[i]) * prices[i]; - value += nativeToUi(oos.quoteTokenTotal.toNumber(), mangoGroup.mintDecimals[NUM_TOKENS - 1]); + value += nativeToUi(oos.baseTokenTotal.toNumber(), mangoGroup.mintDecimals[i]) * prices[i] + value += nativeToUi(oos.quoteTokenTotal.toNumber(), mangoGroup.mintDecimals[NUM_TOKENS-1]) } } - return value; + return value } getAssets(mangoGroup: MangoGroup): number[] { - const assets = new Array(NUM_TOKENS); + const assets = new Array(NUM_TOKENS) for (let i = 0; i < NUM_TOKENS; i++) { - assets[i] = this.getUiDeposit(mangoGroup, i); + assets[i] = this.getUiDeposit(mangoGroup, i) } for (let i = 0; i < NUM_MARKETS; i++) { - const openOrdersAccount = this.openOrdersAccounts[i]; + const openOrdersAccount = this.openOrdersAccounts[i] if (openOrdersAccount == undefined) { - continue; + continue } - assets[i] += nativeToUi(openOrdersAccount.baseTokenTotal.toNumber(), mangoGroup.mintDecimals[i]); - assets[NUM_TOKENS - 1] += nativeToUi( - openOrdersAccount.quoteTokenTotal.toNumber(), - mangoGroup.mintDecimals[NUM_TOKENS - 1], - ); + assets[i] += nativeToUi(openOrdersAccount.baseTokenTotal.toNumber(), mangoGroup.mintDecimals[i]) + assets[NUM_TOKENS-1] += nativeToUi(openOrdersAccount.quoteTokenTotal.toNumber(), mangoGroup.mintDecimals[NUM_TOKENS-1]) } - return assets; + + return assets } getLiabs(mangoGroup: MangoGroup): number[] { - const liabs = new Array(NUM_TOKENS); + const liabs = new Array(NUM_TOKENS) for (let i = 0; i < NUM_TOKENS; i++) { - liabs[i] = this.getUiBorrow(mangoGroup, i); + liabs[i] = this.getUiBorrow(mangoGroup, i) } - return liabs; + return liabs } getAssetsVal(mangoGroup: MangoGroup, prices: number[]): number { - let assetsVal = 0; + let assetsVal = 0 for (let i = 0; i < NUM_TOKENS; i++) { - assetsVal += this.getUiDeposit(mangoGroup, i) * prices[i]; + assetsVal += this.getUiDeposit(mangoGroup, i) * prices[i] } for (let i = 0; i < NUM_MARKETS; i++) { - const openOrdersAccount = this.openOrdersAccounts[i]; + const openOrdersAccount = this.openOrdersAccounts[i] if (openOrdersAccount == undefined) { - continue; + continue } - assetsVal += nativeToUi(openOrdersAccount.baseTokenTotal.toNumber(), mangoGroup.mintDecimals[i]) * prices[i]; - assetsVal += nativeToUi(openOrdersAccount.quoteTokenTotal.toNumber(), mangoGroup.mintDecimals[NUM_TOKENS - 1]); + assetsVal += nativeToUi(openOrdersAccount.baseTokenTotal.toNumber(), mangoGroup.mintDecimals[i]) * prices[i] + assetsVal += nativeToUi(openOrdersAccount.quoteTokenTotal.toNumber(), mangoGroup.mintDecimals[NUM_TOKENS-1]) } - return assetsVal; + return assetsVal } getLiabsVal(mangoGroup: MangoGroup, prices: number[]) { - let liabsVal = 0; + let liabsVal = 0 for (let i = 0; i < NUM_TOKENS; i++) { - liabsVal += this.getUiBorrow(mangoGroup, i) * prices[i]; + liabsVal += this.getUiBorrow(mangoGroup, i) * prices[i] } - return liabsVal; + return liabsVal } getCollateralRatio(mangoGroup: MangoGroup, prices: number[]): number { - const assetsVal = this.getAssetsVal(mangoGroup, prices); - const liabsVal = this.getLiabsVal(mangoGroup, prices); + const assetsVal = this.getAssetsVal(mangoGroup, prices) + const liabsVal = this.getLiabsVal(mangoGroup, prices) - return assetsVal / liabsVal; + return assetsVal / liabsVal } async cancelAllOrdersByMarket( @@ -256,25 +266,29 @@ export class MarginAccount { market: Market, bids: Orderbook, asks: Orderbook, - owner: Account, + owner: Account ): Promise { - const marketIndex = mangoGroup.getMarketIndex(market); - const openOrdersAccount = this.openOrdersAccounts[marketIndex]; - if (openOrdersAccount == undefined) { - // no open orders for this market - return []; + + const marketIndex = mangoGroup.getMarketIndex(market) + const openOrdersAccount = this.openOrdersAccounts[marketIndex] + if (openOrdersAccount == undefined) { // no open orders for this market + return [] } - const orders = market.filterForOpenOrders(bids, asks, [openOrdersAccount]); - return await Promise.all( - orders.map((order) => client.cancelOrder(connection, programId, mangoGroup, this, owner, market, order)), - ); + const orders = market.filterForOpenOrders(bids, asks, [openOrdersAccount]) + return await Promise.all(orders.map( + (order) => ( + client.cancelOrder(connection, programId, mangoGroup, this, owner, market, order) + ) + )) + } + } export class MangoClient { async initMangoGroup() { - throw new Error('Not Implemented'); + throw new Error("Not Implemented"); } async sendTransaction( @@ -282,50 +296,54 @@ export class MangoClient { transaction: Transaction, payer: Account, additionalSigners: Account[], - ): Promise { +): Promise { // TODO test on mainnet - transaction.recentBlockhash = (await connection.getRecentBlockhash('singleGossip')).blockhash; - transaction.setSigners(payer.publicKey, ...additionalSigners.map((a) => a.publicKey)); + transaction.recentBlockhash = (await connection.getRecentBlockhash('singleGossip')).blockhash + transaction.setSigners(payer.publicKey, ...additionalSigners.map( a => a.publicKey )) + + const signers = [payer].concat(additionalSigners) + transaction.sign(...signers) + const rawTransaction = transaction.serialize() + return await sendAndConfirmRawTransaction(connection, rawTransaction, {skipPreflight: true}) - const signers = [payer].concat(additionalSigners); - transaction.sign(...signers); - const rawTransaction = transaction.serialize(); - return await sendAndConfirmRawTransaction(connection, rawTransaction, { skipPreflight: true }); } async initMarginAccount( connection: Connection, programId: PublicKey, mangoGroup: MangoGroup, - owner: Account, // assumed to be same as payer for now + owner: Account, // assumed to be same as payer for now ): Promise { // Create a Solana account for the MarginAccount and allocate space - const accInstr = await createAccountInstruction(connection, owner.publicKey, MarginAccountLayout.span, programId); + const accInstr = await createAccountInstruction(connection, + owner.publicKey, MarginAccountLayout.span, programId) // Specify the accounts this instruction takes in (see program/src/instruction.rs) const keys = [ { isSigner: false, isWritable: false, pubkey: mangoGroup.publicKey }, - { isSigner: false, isWritable: true, pubkey: accInstr.account.publicKey }, - { isSigner: true, isWritable: false, pubkey: owner.publicKey }, - { isSigner: false, isWritable: false, pubkey: SYSVAR_RENT_PUBKEY }, - ]; + { isSigner: false, isWritable: true, pubkey: accInstr.account.publicKey }, + { isSigner: true, isWritable: false, pubkey: owner.publicKey }, + { isSigner: false, isWritable: false, pubkey: SYSVAR_RENT_PUBKEY } + ] // Encode and create instruction for actual initMarginAccount instruction - const data = encodeMangoInstruction({ InitMarginAccount: {} }); - const initMarginAccountInstruction = new TransactionInstruction({ keys, data, programId }); + const data = encodeMangoInstruction({ InitMarginAccount: {} }) + const initMarginAccountInstruction = new TransactionInstruction( { keys, data, programId }) // Add all instructions to one atomic transaction - const transaction = new Transaction(); - transaction.add(accInstr.instruction); - transaction.add(initMarginAccountInstruction); + const transaction = new Transaction() + transaction.add(accInstr.instruction) + transaction.add(initMarginAccountInstruction) // Specify signers in addition to the wallet - const additionalSigners = [accInstr.account]; + const additionalSigners = [ + accInstr.account, + ] // sign, send and confirm transaction - await this.sendTransaction(connection, transaction, owner, additionalSigners); + await this.sendTransaction(connection, transaction, owner, additionalSigners) - return accInstr.account.publicKey; + return accInstr.account.publicKey } async deposit( @@ -337,29 +355,30 @@ export class MangoClient { token: PublicKey, tokenAcc: PublicKey, - quantity: number, + quantity: number ): Promise { - const tokenIndex = mangoGroup.getTokenIndex(token); - const nativeQuantity = uiToNative(quantity, mangoGroup.mintDecimals[tokenIndex]); + const tokenIndex = mangoGroup.getTokenIndex(token) + const nativeQuantity = uiToNative(quantity, mangoGroup.mintDecimals[tokenIndex]) const keys = [ - { isSigner: false, isWritable: true, pubkey: mangoGroup.publicKey }, - { isSigner: false, isWritable: true, pubkey: marginAccount.publicKey }, + { isSigner: false, isWritable: true, pubkey: mangoGroup.publicKey}, + { isSigner: false, isWritable: true, pubkey: marginAccount.publicKey }, { isSigner: true, isWritable: false, pubkey: owner.publicKey }, - { isSigner: false, isWritable: true, pubkey: tokenAcc }, - { isSigner: false, isWritable: true, pubkey: mangoGroup.vaults[tokenIndex] }, + { isSigner: false, isWritable: true, pubkey: tokenAcc }, + { isSigner: false, isWritable: true, pubkey: mangoGroup.vaults[tokenIndex] }, { isSigner: false, isWritable: false, pubkey: TOKEN_PROGRAM_ID }, - { isSigner: false, isWritable: false, pubkey: SYSVAR_CLOCK_PUBKEY }, - ]; - const data = encodeMangoInstruction({ Deposit: { quantity: nativeQuantity } }); + { isSigner: false, isWritable: false, pubkey: SYSVAR_CLOCK_PUBKEY } + ] + const data = encodeMangoInstruction({Deposit: {quantity: nativeQuantity}}) - const instruction = new TransactionInstruction({ keys, data, programId }); - const transaction = new Transaction(); - transaction.add(instruction); - const additionalSigners = []; + const instruction = new TransactionInstruction( { keys, data, programId }) - return await this.sendTransaction(connection, transaction, owner, additionalSigners); + const transaction = new Transaction() + transaction.add(instruction) + const additionalSigners = [] + + return await this.sendTransaction(connection, transaction, owner, additionalSigners) } async withdraw( @@ -371,32 +390,33 @@ export class MangoClient { token: PublicKey, tokenAcc: PublicKey, - quantity: number, + quantity: number ): Promise { - const tokenIndex = mangoGroup.getTokenIndex(token); - const nativeQuantity = uiToNative(quantity, mangoGroup.mintDecimals[tokenIndex]); + const tokenIndex = mangoGroup.getTokenIndex(token) + const nativeQuantity = uiToNative(quantity, mangoGroup.mintDecimals[tokenIndex]) const keys = [ - { isSigner: false, isWritable: true, pubkey: mangoGroup.publicKey }, - { isSigner: false, isWritable: true, pubkey: marginAccount.publicKey }, + { isSigner: false, isWritable: true, pubkey: mangoGroup.publicKey}, + { isSigner: false, isWritable: true, pubkey: marginAccount.publicKey }, { isSigner: true, isWritable: false, pubkey: owner.publicKey }, - { isSigner: false, isWritable: true, pubkey: tokenAcc }, - { isSigner: false, isWritable: true, pubkey: mangoGroup.vaults[tokenIndex] }, - { isSigner: false, isWritable: false, pubkey: mangoGroup.signerKey }, + { isSigner: false, isWritable: true, pubkey: tokenAcc }, + { isSigner: false, isWritable: true, pubkey: mangoGroup.vaults[tokenIndex] }, + { isSigner: false, isWritable: false, pubkey: mangoGroup.signerKey }, { isSigner: false, isWritable: false, pubkey: TOKEN_PROGRAM_ID }, { isSigner: false, isWritable: false, pubkey: SYSVAR_CLOCK_PUBKEY }, - ...marginAccount.openOrders.map((pubkey) => ({ isSigner: false, isWritable: false, pubkey })), - ...mangoGroup.oracles.map((pubkey) => ({ isSigner: false, isWritable: false, pubkey })), - ]; - const data = encodeMangoInstruction({ Withdraw: { quantity: nativeQuantity } }); + ...marginAccount.openOrders.map( (pubkey) => ( { isSigner: false, isWritable: false, pubkey })), + ...mangoGroup.oracles.map( (pubkey) => ( { isSigner: false, isWritable: false, pubkey })) + ] + const data = encodeMangoInstruction({Withdraw: {quantity: nativeQuantity}}) - const instruction = new TransactionInstruction({ keys, data, programId }); - const transaction = new Transaction(); - transaction.add(instruction); - const additionalSigners = []; + const instruction = new TransactionInstruction( { keys, data, programId }) - return await this.sendTransaction(connection, transaction, owner, additionalSigners); + const transaction = new Transaction() + transaction.add(instruction) + const additionalSigners = [] + + return await this.sendTransaction(connection, transaction, owner, additionalSigners) } async borrow( @@ -407,28 +427,29 @@ export class MangoClient { owner: Account, token: PublicKey, - quantity: number, + quantity: number ): Promise { - const tokenIndex = mangoGroup.getTokenIndex(token); - const nativeQuantity = uiToNative(quantity, mangoGroup.mintDecimals[tokenIndex]); + const tokenIndex = mangoGroup.getTokenIndex(token) + const nativeQuantity = uiToNative(quantity, mangoGroup.mintDecimals[tokenIndex]) const keys = [ - { isSigner: false, isWritable: true, pubkey: mangoGroup.publicKey }, - { isSigner: false, isWritable: true, pubkey: marginAccount.publicKey }, + { isSigner: false, isWritable: true, pubkey: mangoGroup.publicKey}, + { isSigner: false, isWritable: true, pubkey: marginAccount.publicKey }, { isSigner: true, isWritable: false, pubkey: owner.publicKey }, { isSigner: false, isWritable: false, pubkey: SYSVAR_CLOCK_PUBKEY }, - ...marginAccount.openOrders.map((pubkey) => ({ isSigner: false, isWritable: false, pubkey })), - ...mangoGroup.oracles.map((pubkey) => ({ isSigner: false, isWritable: false, pubkey })), - ]; - const data = encodeMangoInstruction({ Borrow: { tokenIndex: new BN(tokenIndex), quantity: nativeQuantity } }); + ...marginAccount.openOrders.map( (pubkey) => ( { isSigner: false, isWritable: false, pubkey })), + ...mangoGroup.oracles.map( (pubkey) => ( { isSigner: false, isWritable: false, pubkey })), + ] + const data = encodeMangoInstruction({Borrow: {tokenIndex: new BN(tokenIndex), quantity: nativeQuantity}}) - const instruction = new TransactionInstruction({ keys, data, programId }); - const transaction = new Transaction(); - transaction.add(instruction); - const additionalSigners = []; + const instruction = new TransactionInstruction( { keys, data, programId }) - return await this.sendTransaction(connection, transaction, owner, additionalSigners); + const transaction = new Transaction() + transaction.add(instruction) + const additionalSigners = [] + + return await this.sendTransaction(connection, transaction, owner, additionalSigners) } async settleBorrow( @@ -439,25 +460,26 @@ export class MangoClient { owner: Account, token: PublicKey, - quantity: number, + quantity: number ): Promise { - const tokenIndex = mangoGroup.getTokenIndex(token); - const nativeQuantity = uiToNative(quantity, mangoGroup.mintDecimals[tokenIndex]); + + const tokenIndex = mangoGroup.getTokenIndex(token) + const nativeQuantity = uiToNative(quantity, mangoGroup.mintDecimals[tokenIndex]) const keys = [ - { isSigner: false, isWritable: true, pubkey: mangoGroup.publicKey }, - { isSigner: false, isWritable: true, pubkey: marginAccount.publicKey }, - { isSigner: true, isWritable: false, pubkey: owner.publicKey }, - { isSigner: false, isWritable: false, pubkey: SYSVAR_CLOCK_PUBKEY }, - ]; - const data = encodeMangoInstruction({ SettleBorrow: { tokenIndex: new BN(tokenIndex), quantity: nativeQuantity } }); + { isSigner: false, isWritable: true, pubkey: mangoGroup.publicKey}, + { isSigner: false, isWritable: true, pubkey: marginAccount.publicKey }, + { isSigner: true, isWritable: false, pubkey: owner.publicKey }, + { isSigner: false, isWritable: false, pubkey: SYSVAR_CLOCK_PUBKEY } + ] + const data = encodeMangoInstruction({SettleBorrow: {tokenIndex: new BN(tokenIndex), quantity: nativeQuantity}}) - const instruction = new TransactionInstruction({ keys, data, programId }); - const transaction = new Transaction(); - transaction.add(instruction); - const additionalSigners = []; + const instruction = new TransactionInstruction( { keys, data, programId }) + const transaction = new Transaction() + transaction.add(instruction) + const additionalSigners = [] - return await this.sendTransaction(connection, transaction, owner, additionalSigners); + return await this.sendTransaction(connection, transaction, owner, additionalSigners) } /** @@ -475,23 +497,27 @@ export class MangoClient { mangoGroup: MangoGroup, marginAccount: MarginAccount, markets: Market[], - owner: Account, + owner: Account ): Promise { - const transaction = new Transaction(); + + const transaction = new Transaction() for (let i = 0; i < NUM_MARKETS; i++) { if (marginAccount.openOrdersAccounts[i] == undefined) { - continue; + continue } - const spotMarket = markets[i]; + const spotMarket = markets[i] const dexSigner = await PublicKey.createProgramAddress( - [spotMarket.publicKey.toBuffer(), spotMarket['_decoded'].vaultSignerNonce.toArrayLike(Buffer, 'le', 8)], - spotMarket.programId, - ); + [ + spotMarket.publicKey.toBuffer(), + spotMarket['_decoded'].vaultSignerNonce.toArrayLike(Buffer, 'le', 8) + ], + spotMarket.programId + ) const keys = [ - { isSigner: false, isWritable: true, pubkey: mangoGroup.publicKey }, - { isSigner: true, isWritable: false, pubkey: owner.publicKey }, - { isSigner: false, isWritable: true, pubkey: marginAccount.publicKey }, + { isSigner: false, isWritable: true, pubkey: mangoGroup.publicKey}, + { isSigner: true, isWritable: false, pubkey: owner.publicKey }, + { isSigner: false, isWritable: true, pubkey: marginAccount.publicKey }, { isSigner: false, isWritable: false, pubkey: SYSVAR_CLOCK_PUBKEY }, { isSigner: false, isWritable: false, pubkey: spotMarket.programId }, { isSigner: false, isWritable: true, pubkey: spotMarket.publicKey }, @@ -503,70 +529,69 @@ export class MangoClient { { isSigner: false, isWritable: true, pubkey: mangoGroup.vaults[mangoGroup.vaults.length - 1] }, { isSigner: false, isWritable: false, pubkey: dexSigner }, { isSigner: false, isWritable: false, pubkey: TOKEN_PROGRAM_ID }, - ]; - const data = encodeMangoInstruction({ SettleFunds: {} }); + ] + const data = encodeMangoInstruction( {SettleFunds: {}} ) - const instruction = new TransactionInstruction({ keys, data, programId }); - transaction.add(instruction); + const instruction = new TransactionInstruction( { keys, data, programId }) + transaction.add(instruction) } - const assets = marginAccount.getAssets(mangoGroup); - const liabs = marginAccount.getLiabs(mangoGroup); + const assets = marginAccount.getAssets(mangoGroup) + const liabs = marginAccount.getLiabs(mangoGroup) - for (let i = 0; i < NUM_TOKENS; i++) { - // TODO test this. maybe it hits transaction size limit + for (let i = 0; i < NUM_TOKENS; i++) { // TODO test this. maybe it hits transaction size limit const keys = [ - { isSigner: false, isWritable: true, pubkey: mangoGroup.publicKey }, - { isSigner: false, isWritable: true, pubkey: marginAccount.publicKey }, - { isSigner: true, isWritable: false, pubkey: owner.publicKey }, - { isSigner: false, isWritable: false, pubkey: SYSVAR_CLOCK_PUBKEY }, - ]; - const data = encodeMangoInstruction({ - SettleBorrow: { tokenIndex: new BN(i), quantity: uiToNative(liabs[i] * 2, mangoGroup.mintDecimals[i]) }, - }); + { isSigner: false, isWritable: true, pubkey: mangoGroup.publicKey}, + { isSigner: false, isWritable: true, pubkey: marginAccount.publicKey }, + { isSigner: true, isWritable: false, pubkey: owner.publicKey }, + { isSigner: false, isWritable: false, pubkey: SYSVAR_CLOCK_PUBKEY } + ] + const data = encodeMangoInstruction({SettleBorrow: {tokenIndex: new BN(i), quantity: uiToNative(liabs[i] * 2, mangoGroup.mintDecimals[i])}}) - const instruction = new TransactionInstruction({ keys, data, programId }); - transaction.add(instruction); + const instruction = new TransactionInstruction( { keys, data, programId }) + transaction.add(instruction) } - const additionalSigners = []; - return await this.sendTransaction(connection, transaction, owner, additionalSigners); + const additionalSigners = [] + return await this.sendTransaction(connection, transaction, owner, additionalSigners) } async liquidate( connection: Connection, programId: PublicKey, mangoGroup: MangoGroup, - liqeeMarginAccount: MarginAccount, // liquidatee marginAccount - liqor: Account, // liquidator + liqeeMarginAccount: MarginAccount, // liquidatee marginAccount + liqor: Account, // liquidator tokenAccs: PublicKey[], - depositQuantities: number[], + depositQuantities: number[] ): Promise { - const depositsBN: BN[] = []; + + const depositsBN: BN[] = [] for (let i = 0; i < mangoGroup.tokens.length; i++) { - depositsBN[i] = uiToNative(depositQuantities[i], mangoGroup.mintDecimals[i]); + depositsBN[i] = uiToNative(depositQuantities[i], mangoGroup.mintDecimals[i]) } const keys = [ - { isSigner: false, isWritable: true, pubkey: mangoGroup.publicKey }, + { isSigner: false, isWritable: true, pubkey: mangoGroup.publicKey}, { isSigner: true, isWritable: false, pubkey: liqor.publicKey }, - { isSigner: false, isWritable: true, pubkey: liqeeMarginAccount.publicKey }, + { isSigner: false, isWritable: true, pubkey: liqeeMarginAccount.publicKey }, { isSigner: false, isWritable: false, pubkey: TOKEN_PROGRAM_ID }, { isSigner: false, isWritable: false, pubkey: SYSVAR_CLOCK_PUBKEY }, - ...liqeeMarginAccount.openOrders.map((pubkey) => ({ isSigner: false, isWritable: false, pubkey })), - ...mangoGroup.oracles.map((pubkey) => ({ isSigner: false, isWritable: false, pubkey })), - ...mangoGroup.vaults.map((pubkey) => ({ isSigner: false, isWritable: true, pubkey })), - ...tokenAccs.map((pubkey) => ({ isSigner: false, isWritable: true, pubkey })), - ]; - const data = encodeMangoInstruction({ Liquidate: { depositQuantities: depositsBN } }); + ...liqeeMarginAccount.openOrders.map( (pubkey) => ( { isSigner: false, isWritable: false, pubkey })), + ...mangoGroup.oracles.map( (pubkey) => ( { isSigner: false, isWritable: false, pubkey })), + ...mangoGroup.vaults.map( (pubkey) => ( { isSigner: false, isWritable: true, pubkey })), + ...tokenAccs.map( (pubkey) => ( { isSigner: false, isWritable: true, pubkey })), + ] + const data = encodeMangoInstruction({Liquidate: {depositQuantities: depositsBN}}) - const instruction = new TransactionInstruction({ keys, data, programId }); - const transaction = new Transaction(); - transaction.add(instruction); - const additionalSigners = []; + const instruction = new TransactionInstruction( { keys, data, programId }) - return await this.sendTransaction(connection, transaction, liqor, additionalSigners); + const transaction = new Transaction() + transaction.add(instruction) + const additionalSigners = [] + + return await this.sendTransaction(connection, transaction, liqor, additionalSigners) } async depositSrm( @@ -577,28 +602,28 @@ export class MangoClient { owner: Account, srmAccount: PublicKey, - quantity: number, + quantity: number ): Promise { - const nativeQuantity = uiToNative(quantity, SRM_DECIMALS); + const nativeQuantity = uiToNative(quantity, SRM_DECIMALS) const keys = [ { isSigner: false, isWritable: true, pubkey: mangoGroup.publicKey }, - { isSigner: false, isWritable: true, pubkey: marginAccount.publicKey }, + { isSigner: false, isWritable: true, pubkey: marginAccount.publicKey }, { isSigner: true, isWritable: false, pubkey: owner.publicKey }, - { isSigner: false, isWritable: true, pubkey: srmAccount }, - { isSigner: false, isWritable: true, pubkey: mangoGroup.srmVault }, + { isSigner: false, isWritable: true, pubkey: srmAccount }, + { isSigner: false, isWritable: true, pubkey: mangoGroup.srmVault }, { isSigner: false, isWritable: false, pubkey: TOKEN_PROGRAM_ID }, - { isSigner: false, isWritable: false, pubkey: SYSVAR_CLOCK_PUBKEY }, - ]; - const data = encodeMangoInstruction({ DepositSrm: { quantity: nativeQuantity } }); + { isSigner: false, isWritable: false, pubkey: SYSVAR_CLOCK_PUBKEY } + ] + const data = encodeMangoInstruction({DepositSrm: {quantity: nativeQuantity}}) - const instruction = new TransactionInstruction({ keys, data, programId }); + const instruction = new TransactionInstruction( { keys, data, programId }) - const transaction = new Transaction(); - transaction.add(instruction); - const additionalSigners = []; + const transaction = new Transaction() + transaction.add(instruction) + const additionalSigners = [] - return await this.sendTransaction(connection, transaction, owner, additionalSigners); + return await this.sendTransaction(connection, transaction, owner, additionalSigners) } async withdrawSrm( @@ -609,29 +634,29 @@ export class MangoClient { owner: Account, srmAccount: PublicKey, - quantity: number, + quantity: number ): Promise { - const nativeQuantity = uiToNative(quantity, SRM_DECIMALS); + const nativeQuantity = uiToNative(quantity, SRM_DECIMALS) const keys = [ { isSigner: false, isWritable: true, pubkey: mangoGroup.publicKey }, - { isSigner: false, isWritable: true, pubkey: marginAccount.publicKey }, + { isSigner: false, isWritable: true, pubkey: marginAccount.publicKey }, { isSigner: true, isWritable: false, pubkey: owner.publicKey }, - { isSigner: false, isWritable: true, pubkey: srmAccount }, - { isSigner: false, isWritable: true, pubkey: mangoGroup.srmVault }, - { isSigner: false, isWritable: false, pubkey: mangoGroup.signerKey }, + { isSigner: false, isWritable: true, pubkey: srmAccount }, + { isSigner: false, isWritable: true, pubkey: mangoGroup.srmVault }, + { isSigner: false, isWritable: false, pubkey: mangoGroup.signerKey }, { isSigner: false, isWritable: false, pubkey: TOKEN_PROGRAM_ID }, - { isSigner: false, isWritable: false, pubkey: SYSVAR_CLOCK_PUBKEY }, - ]; - const data = encodeMangoInstruction({ WithdrawSrm: { quantity: nativeQuantity } }); + { isSigner: false, isWritable: false, pubkey: SYSVAR_CLOCK_PUBKEY } + ] + const data = encodeMangoInstruction({WithdrawSrm: {quantity: nativeQuantity}}) - const instruction = new TransactionInstruction({ keys, data, programId }); + const instruction = new TransactionInstruction( { keys, data, programId }) - const transaction = new Transaction(); - transaction.add(instruction); - const additionalSigners = []; + const transaction = new Transaction() + transaction.add(instruction) + const additionalSigners = [] - return await this.sendTransaction(connection, transaction, owner, additionalSigners); + return await this.sendTransaction(connection, transaction, owner, additionalSigners) } async placeOrder( @@ -647,62 +672,59 @@ export class MangoClient { size: number, orderType?: 'limit' | 'ioc' | 'postOnly', clientId?: BN, + ): Promise { // TODO allow wrapped SOL wallets // TODO allow fee discounts - orderType = orderType == undefined ? 'limit' : orderType; + orderType = orderType == undefined ? 'limit' : orderType // orderType = orderType ?? 'limit' - const limitPrice = spotMarket.priceNumberToLots(price); - const maxBaseQuantity = spotMarket.baseSizeNumberToLots(size); + const limitPrice = spotMarket.priceNumberToLots(price) + const maxBaseQuantity = spotMarket.baseSizeNumberToLots(size) // TODO verify if multiplying by highest fee tier is appropriate const maxQuoteQuantity = new BN(spotMarket['_decoded'].quoteLotSize.toNumber()).mul( maxBaseQuantity.mul(limitPrice), - ); + ) if (maxBaseQuantity.lte(new BN(0))) { - throw new Error('size too small'); + throw new Error('size too small') } if (limitPrice.lte(new BN(0))) { - throw new Error('invalid price'); + throw new Error('invalid price') } - const selfTradeBehavior = 'decrementTake'; - const marketIndex = mangoGroup.getMarketIndex(spotMarket); - const vaultIndex = side === 'buy' ? mangoGroup.vaults.length - 1 : marketIndex; + const selfTradeBehavior = 'decrementTake' + const marketIndex = mangoGroup.getMarketIndex(spotMarket) + const vaultIndex = (side === 'buy') ? mangoGroup.vaults.length - 1 : marketIndex // Add all instructions to one atomic transaction - const transaction = new Transaction(); + const transaction = new Transaction() // Specify signers in addition to the wallet - const additionalSigners: Account[] = []; + const additionalSigners: Account[] = [] // Create a Solana account for the open orders account if it's missing const openOrdersKeys: PublicKey[] = []; for (let i = 0; i < marginAccount.openOrders.length; i++) { if (i === marketIndex && marginAccount.openOrders[marketIndex].equals(zeroKey)) { // open orders missing for this market; create a new one now - const openOrdersSpace = OpenOrders.getLayout(mangoGroup.dexProgramId).span; - const openOrdersLamports = await connection.getMinimumBalanceForRentExemption(openOrdersSpace, 'singleGossip'); + const openOrdersSpace = OpenOrders.getLayout(mangoGroup.dexProgramId).span + const openOrdersLamports = await connection.getMinimumBalanceForRentExemption(openOrdersSpace, 'singleGossip') const accInstr = await createAccountInstruction( - connection, - owner.publicKey, - openOrdersSpace, - mangoGroup.dexProgramId, - openOrdersLamports, - ); + connection, owner.publicKey, openOrdersSpace, mangoGroup.dexProgramId, openOrdersLamports + ) - transaction.add(accInstr.instruction); - additionalSigners.push(accInstr.account); - openOrdersKeys.push(accInstr.account.publicKey); + transaction.add(accInstr.instruction) + additionalSigners.push(accInstr.account) + openOrdersKeys.push(accInstr.account.publicKey) } else { - openOrdersKeys.push(marginAccount.openOrders[i]); + openOrdersKeys.push(marginAccount.openOrders[i]) } } const keys = [ - { isSigner: false, isWritable: true, pubkey: mangoGroup.publicKey }, - { isSigner: true, isWritable: false, pubkey: owner.publicKey }, + { isSigner: false, isWritable: true, pubkey: mangoGroup.publicKey}, + { isSigner: true, isWritable: false, pubkey: owner.publicKey }, { isSigner: false, isWritable: true, pubkey: marginAccount.publicKey }, { isSigner: false, isWritable: false, pubkey: SYSVAR_CLOCK_PUBKEY }, { isSigner: false, isWritable: false, pubkey: spotMarket.programId }, @@ -718,21 +740,24 @@ export class MangoClient { { isSigner: false, isWritable: false, pubkey: TOKEN_PROGRAM_ID }, { isSigner: false, isWritable: false, pubkey: SYSVAR_RENT_PUBKEY }, { isSigner: false, isWritable: true, pubkey: mangoGroup.srmVault }, - ...openOrdersKeys.map((pubkey) => ({ isSigner: false, isWritable: true, pubkey })), - ...mangoGroup.oracles.map((pubkey) => ({ isSigner: false, isWritable: false, pubkey })), - ]; + ...openOrdersKeys.map( (pubkey) => ( { isSigner: false, isWritable: true, pubkey })), + ...mangoGroup.oracles.map( (pubkey) => ( { isSigner: false, isWritable: false, pubkey })), + ] - const data = encodeMangoInstruction({ - PlaceOrder: clientId - ? { side, limitPrice, maxBaseQuantity, maxQuoteQuantity, selfTradeBehavior, orderType, clientId, limit: 65535 } - : { side, limitPrice, maxBaseQuantity, maxQuoteQuantity, selfTradeBehavior, orderType, limit: 65535 }, - }); + const data = encodeMangoInstruction( + { + PlaceOrder: + clientId + ? { side, limitPrice, maxBaseQuantity, maxQuoteQuantity, selfTradeBehavior, orderType, clientId, limit: 65535} + : { side, limitPrice, maxBaseQuantity, maxQuoteQuantity, selfTradeBehavior, orderType, limit: 65535} + } + ) - const placeOrderInstruction = new TransactionInstruction({ keys, data, programId }); - transaction.add(placeOrderInstruction); + const placeOrderInstruction = new TransactionInstruction( { keys, data, programId }) + transaction.add(placeOrderInstruction) // sign, send and confirm transaction - return await this.sendTransaction(connection, transaction, owner, additionalSigners); + return await this.sendTransaction(connection, transaction, owner, additionalSigners) } async settleFunds( connection: Connection, @@ -741,12 +766,17 @@ export class MangoClient { marginAccount: MarginAccount, owner: Account, spotMarket: Market, + ): Promise { - const marketIndex = mangoGroup.getMarketIndex(spotMarket); + + const marketIndex = mangoGroup.getMarketIndex(spotMarket) const dexSigner = await PublicKey.createProgramAddress( - [spotMarket.publicKey.toBuffer(), spotMarket['_decoded'].vaultSignerNonce.toArrayLike(Buffer, 'le', 8)], - spotMarket.programId, - ); + [ + spotMarket.publicKey.toBuffer(), + spotMarket['_decoded'].vaultSignerNonce.toArrayLike(Buffer, 'le', 8) + ], + spotMarket.programId + ) const instruction = makeSettleFundsInstruction( programId, @@ -761,19 +791,20 @@ export class MangoClient { spotMarket['_decoded'].quoteVault, mangoGroup.vaults[marketIndex], mangoGroup.vaults[mangoGroup.vaults.length - 1], - dexSigner, - ); + dexSigner + ) - const transaction = new Transaction(); - transaction.add(instruction); + const transaction = new Transaction() + transaction.add(instruction) // Specify signers in addition to the owner account - const additionalSigners = []; + const additionalSigners = [] // sign, send and confirm transaction - return await this.sendTransaction(connection, transaction, owner, additionalSigners); + return await this.sendTransaction(connection, transaction, owner, additionalSigners) } + async cancelOrder( connection: Connection, programId: PublicKey, @@ -795,16 +826,19 @@ export class MangoClient { order.openOrdersAddress, mangoGroup.signerKey, spotMarket['_decoded'].eventQueue, - order, - ); - const transaction = new Transaction(); - transaction.add(instruction); - const additionalSigners = []; + order + ) + const transaction = new Transaction() + transaction.add(instruction) + const additionalSigners = [] - return await this.sendTransaction(connection, transaction, owner, additionalSigners); + return await this.sendTransaction(connection, transaction, owner, additionalSigners) } - async getMangoGroup(connection: Connection, mangoGroupPk: PublicKey): Promise { + async getMangoGroup( + connection: Connection, + mangoGroupPk: PublicKey + ): Promise { const acc = await connection.getAccountInfo(mangoGroupPk); const decoded = MangoGroupLayout.decode(acc == null ? undefined : acc.data); return new MangoGroup(mangoGroupPk, decoded); @@ -813,25 +847,25 @@ export class MangoClient { async getMarginAccount( connection: Connection, marginAccountPk: PublicKey, - dexProgramId: PublicKey, + dexProgramId: PublicKey ): Promise { - const acc = await connection.getAccountInfo(marginAccountPk, 'singleGossip'); - const ma = new MarginAccount(marginAccountPk, MarginAccountLayout.decode(acc == null ? undefined : acc.data)); - await ma.loadOpenOrders(connection, dexProgramId); - return ma; + const acc = await connection.getAccountInfo(marginAccountPk, 'singleGossip') + const ma = new MarginAccount(marginAccountPk, MarginAccountLayout.decode(acc == null ? undefined : acc.data)) + await ma.loadOpenOrders(connection, dexProgramId) + return ma } async getAllMarginAccounts( connection: Connection, programId: PublicKey, - mangoGroup: MangoGroup, - ): Promise { + mangoGroup: MangoGroup + ): Promise{ const filters = [ { memcmp: { offset: MarginAccountLayout.offsetOf('mangoGroup'), bytes: mangoGroup.publicKey.toBase58(), - }, + } }, { @@ -842,19 +876,21 @@ export class MangoClient { const accounts = await getFilteredProgramAccounts(connection, programId, filters); const marginAccounts = accounts.map( ({ publicKey, accountInfo }) => - new MarginAccount(publicKey, MarginAccountLayout.decode(accountInfo == null ? undefined : accountInfo.data)), - ); + new MarginAccount(publicKey, MarginAccountLayout.decode(accountInfo == null ? undefined : accountInfo.data)) + ) + + await Promise.all(marginAccounts.map((ma) => ma.loadOpenOrders(connection, mangoGroup.dexProgramId))) + return marginAccounts - await Promise.all(marginAccounts.map((ma) => ma.loadOpenOrders(connection, mangoGroup.dexProgramId))); - return marginAccounts; } async getMarginAccountsForOwner( connection: Connection, programId: PublicKey, mangoGroup: MangoGroup, - owner: Account | Wallet, + owner: Account | Wallet ): Promise { + const filters = [ { memcmp: { @@ -866,7 +902,7 @@ export class MangoClient { memcmp: { offset: MarginAccountLayout.offsetOf('owner'), bytes: owner.publicKey.toBase58(), - }, + } }, { @@ -877,33 +913,37 @@ export class MangoClient { const accounts = await getFilteredProgramAccounts(connection, programId, filters); const marginAccounts = accounts.map( ({ publicKey, accountInfo }) => - new MarginAccount(publicKey, MarginAccountLayout.decode(accountInfo == null ? undefined : accountInfo.data)), - ); - await Promise.all(marginAccounts.map((ma) => ma.loadOpenOrders(connection, mangoGroup.dexProgramId))); - return marginAccounts; + new MarginAccount(publicKey, MarginAccountLayout.decode(accountInfo == null ? undefined : accountInfo.data)) + ) + await Promise.all(marginAccounts.map((ma) => ma.loadOpenOrders(connection, mangoGroup.dexProgramId))) + return marginAccounts } + } async function getMultipleAccounts( connection: Connection, - publicKeys: PublicKey[], + publicKeys: PublicKey[] + ): Promise<{ publicKey: PublicKey; accountInfo: AccountInfo }[]> { - const publickKeyStrs = publicKeys.map((pk) => pk.toBase58()); + const publickKeyStrs = publicKeys.map((pk) => (pk.toBase58())); // @ts-ignore const resp = await connection._rpcRequest('getMultipleAccounts', [publickKeyStrs]); if (resp.error) { throw new Error(resp.error.message); } - return resp.result.value.map(({ data, executable, lamports, owner }, i) => ({ - publicKey: publicKeys[i], - accountInfo: { - data: Buffer.from(data[0], 'base64'), - executable, - owner: new PublicKey(owner), - lamports, - }, - })); + return resp.result.value.map( + ({ data, executable, lamports, owner } , i) => ({ + publicKey: publicKeys[i], + accountInfo: { + data: Buffer.from(data[0], 'base64'), + executable, + owner: new PublicKey(owner), + lamports, + }, + }), + ); } async function getFilteredProgramAccounts( @@ -923,19 +963,22 @@ async function getFilteredProgramAccounts( if (resp.error) { throw new Error(resp.error.message); } - return resp.result.map(({ pubkey, account: { data, executable, owner, lamports } }) => ({ - publicKey: new PublicKey(pubkey), - accountInfo: { - data: Buffer.from(data[0], 'base64'), - executable, - owner: new PublicKey(owner), - lamports, - }, - })); + return resp.result.map( + ({ pubkey, account: { data, executable, owner, lamports } }) => ({ + publicKey: new PublicKey(pubkey), + accountInfo: { + data: Buffer.from(data[0], 'base64'), + executable, + owner: new PublicKey(owner), + lamports, + }, + }), + ); } + async function promiseUndef(): Promise { - return undefined; + return undefined } export const getUnixTs = () => { diff --git a/src/layout.ts b/src/layout.ts index cb368aa..b7ccd09 100644 --- a/src/layout.ts +++ b/src/layout.ts @@ -4,7 +4,7 @@ import BN from 'bn.js'; export const NUM_TOKENS = 3; export const NUM_MARKETS = NUM_TOKENS - 1; -export const MANGO_GROUP_PADDING = 8 - ((NUM_TOKENS + NUM_MARKETS) % 8); +export const MANGO_GROUP_PADDING = 8 - (NUM_TOKENS + NUM_MARKETS) % 8; class PublicKeyLayout extends Blob { constructor(property) { @@ -20,7 +20,7 @@ class PublicKeyLayout extends Blob { } } -export function publicKeyLayout(property = '') { +export function publicKeyLayout(property = "") { return new PublicKeyLayout(property); } @@ -28,7 +28,7 @@ class BNLayout extends Blob { constructor(number: number, property) { super(number, property); // restore prototype chain - Object.setPrototypeOf(this, new.target.prototype); + Object.setPrototypeOf(this, new.target.prototype) } decode(b, offset) { @@ -40,14 +40,15 @@ class BNLayout extends Blob { } } -export function u64(property = '') { +export function u64(property = "") { return new BNLayout(8, property); } -export function u128(property = '') { +export function u128(property = "") { return new BNLayout(16, property); } + class U64F64Layout extends Blob { constructor(property: string) { super(16, property); @@ -65,8 +66,8 @@ class U64F64Layout extends Blob { } } -export function U64F64(property = '') { - return new U64F64Layout(property); +export function U64F64(property = "") { + return new U64F64Layout(property) } export class WideBits extends Layout { @@ -97,7 +98,10 @@ export class WideBits extends Layout { return super.replicate(property); } encode(src, b, offset = 0) { - return this._lower.encode(src, b, offset) + this._upper.encode(src, b, offset + this._lower.span); + return ( + this._lower.encode(src, b, offset) + + this._upper.encode(src, b, offset + this._lower.span) + ); } } const ACCOUNT_FLAGS_LAYOUT = new WideBits(undefined); @@ -106,13 +110,13 @@ ACCOUNT_FLAGS_LAYOUT.addBoolean('MangoGroup'); ACCOUNT_FLAGS_LAYOUT.addBoolean('MarginAccount'); export function accountFlagsLayout(property = 'accountFlags') { - return ACCOUNT_FLAGS_LAYOUT.replicate(property); // TODO: when ts check is on, replicate throws error, doesn't compile + return ACCOUNT_FLAGS_LAYOUT.replicate(property); // TODO: when ts check is on, replicate throws error, doesn't compile } export const MangoIndexLayout = struct([ u64('lastUpdate'), U64F64('borrow'), // U64F64 - U64F64('deposit'), // U64F64 + U64F64('deposit') // U64F64 ]); export const MangoGroupLayout = struct([ @@ -133,9 +137,10 @@ export const MangoGroupLayout = struct([ publicKeyLayout('srmVault'), seq(u8(), NUM_TOKENS, 'mintDecimals'), seq(u8(), NUM_MARKETS, 'oracleDecimals'), - seq(u8(), MANGO_GROUP_PADDING, 'padding'), + seq(u8(), MANGO_GROUP_PADDING, 'padding') ]); + export const MarginAccountLayout = struct([ accountFlagsLayout('accountFlags'), publicKeyLayout('mangoGroup'), @@ -144,14 +149,15 @@ export const MarginAccountLayout = struct([ seq(U64F64(), NUM_TOKENS, 'deposits'), seq(U64F64(), NUM_TOKENS, 'borrows'), seq(publicKeyLayout(), NUM_MARKETS, 'openOrders'), - u64('srmBalance'), + u64('srmBalance') ]); + class EnumLayout extends UInt { values: any; constructor(values, span, property) { super(span, property); - this.values = values; + this.values = values } encode(src, b, offset) { if (this.values[src] !== undefined) { @@ -162,7 +168,9 @@ class EnumLayout extends UInt { decode(b, offset) { const decodedValue = super.decode(b, offset); - const entry = Object.entries(this.values).find(([, value]) => value === decodedValue); + const entry = Object.entries(this.values).find( + ([, value]) => value === decodedValue, + ); if (entry) { return entry[0]; } @@ -182,37 +190,46 @@ export function selfTradeBehaviorLayout(property) { return new EnumLayout({ decrementTake: 0, cancelProvide: 1, abortTransaction: 2 }, 4, property); } -export const MangoInstructionLayout = union(u32('instruction')); +export const MangoInstructionLayout = union(u32('instruction')) -MangoInstructionLayout.addVariant(0, struct([]), 'InitMangoGroup'); -MangoInstructionLayout.addVariant(1, struct([]), 'InitMarginAccount'); -MangoInstructionLayout.addVariant(2, struct([u64('quantity')]), 'Deposit'); -MangoInstructionLayout.addVariant(3, struct([u64('quantity')]), 'Withdraw'); -MangoInstructionLayout.addVariant(4, struct([u64('tokenIndex'), u64('quantity')]), 'Borrow'); -MangoInstructionLayout.addVariant(5, struct([u64('tokenIndex'), u64('quantity')]), 'SettleBorrow'); -MangoInstructionLayout.addVariant(6, struct([seq(u64(), NUM_TOKENS, 'depositQuantities')]), 'Liquidate'); -MangoInstructionLayout.addVariant(7, struct([u64('quantity')]), 'DepositSrm'); -MangoInstructionLayout.addVariant(8, struct([u64('quantity')]), 'WithdrawSrm'); +MangoInstructionLayout.addVariant(0, struct([]), 'InitMangoGroup') +MangoInstructionLayout.addVariant(1, struct([]), 'InitMarginAccount') +MangoInstructionLayout.addVariant(2, struct([u64('quantity')]), 'Deposit') +MangoInstructionLayout.addVariant(3, struct([u64('quantity')]), 'Withdraw') +MangoInstructionLayout.addVariant(4, struct([u64('tokenIndex'), u64('quantity')]), 'Borrow') +MangoInstructionLayout.addVariant(5, struct([u64('tokenIndex'), u64('quantity')]), 'SettleBorrow') +MangoInstructionLayout.addVariant(6, struct([seq(u64(), NUM_TOKENS, 'depositQuantities')]), 'Liquidate') +MangoInstructionLayout.addVariant(7, struct([u64('quantity')]), 'DepositSrm') +MangoInstructionLayout.addVariant(8, struct([u64('quantity')]), 'WithdrawSrm') -MangoInstructionLayout.addVariant( - 9, - struct([ - sideLayout('side'), - u64('limitPrice'), - u64('maxBaseQuantity'), - u64('maxQuoteQuantity'), - selfTradeBehaviorLayout('selfTradeBehavior'), - orderTypeLayout('orderType'), - u64('clientId'), - u16('limit'), - ]), - 'PlaceOrder', -); +MangoInstructionLayout.addVariant(9, + struct( + [ + sideLayout('side'), + u64('limitPrice'), + u64('maxBaseQuantity'), + u64('maxQuoteQuantity'), + selfTradeBehaviorLayout('selfTradeBehavior'), + orderTypeLayout('orderType'), + u64('clientId'), + u16('limit'), + ] + ), + 'PlaceOrder' +) -MangoInstructionLayout.addVariant(10, struct([]), 'SettleFunds'); -MangoInstructionLayout.addVariant(11, struct([sideLayout('side'), u128('orderId')]), 'CancelOrder'); +MangoInstructionLayout.addVariant(10, struct([]), 'SettleFunds') +MangoInstructionLayout.addVariant(11, + struct( + [ + sideLayout('side'), + u128('orderId') + ] + ), + 'CancelOrder' +) -MangoInstructionLayout.addVariant(12, struct([u64('clientId')]), 'CancelOrderByClientId'); +MangoInstructionLayout.addVariant(12, struct([u64('clientId')]), 'CancelOrderByClientId') // @ts-ignore const instructionMaxSpan = Math.max(...Object.values(MangoInstructionLayout.registry).map((r) => r.span));