adding CancelAllSpotOrders instruction into the lib (#79)
* adding CancelAllSpotOrders instruction into the lib * adding test to test cancelallspotorders * correcting tests for cancelallspotorders * adding new yarn script to launch cancelallspotorders test * cancelallspotorders test changes after max's review. * moving pyth-client from dependencies to dev-dependecies
This commit is contained in:
parent
ac2a042efc
commit
8951e86b46
|
@ -37,6 +37,7 @@
|
|||
"test-stoploss": "ts-node test/stoploss.test.ts",
|
||||
"test-closeaccount": "ts-node test/closeaccount.test.ts",
|
||||
"test-cancelside": "ts-node test/cancelside.test.ts",
|
||||
"test-cancelallspotorders": "ts-node test/cancelallspotorders.test.ts",
|
||||
"mint-devnet": "ts-node src/mintDevnet.ts",
|
||||
"test": "mocha -r ts-node/register test/**/*.test.ts --timeout 0",
|
||||
"test:build": "yarn build && yarn",
|
||||
|
@ -62,7 +63,8 @@
|
|||
"prettier": "^2.0.5",
|
||||
"ts-node": "^9.1.1",
|
||||
"typedoc": "^0.22.5",
|
||||
"typescript": "^4.6.3"
|
||||
"typescript": "^4.6.3",
|
||||
"@pythnetwork/client": "^2.7.0"
|
||||
},
|
||||
"files": [
|
||||
"lib"
|
||||
|
|
|
@ -116,6 +116,7 @@ import {
|
|||
makeUpgradeMangoAccountV0V1Instruction,
|
||||
makeWithdrawInstruction,
|
||||
makeWithdrawMsrmInstruction,
|
||||
makeCancelAllSpotOrdersInstruction,
|
||||
} from './instruction';
|
||||
import {
|
||||
getFeeRates,
|
||||
|
@ -5296,4 +5297,64 @@ export class MangoClient {
|
|||
|
||||
return referrerIds;
|
||||
}
|
||||
}
|
||||
|
||||
async cancelAllSpotOrders(
|
||||
mangoGroup: MangoGroup,
|
||||
mangoAccount: MangoAccount,
|
||||
spotMarket: Market,
|
||||
owner: Payer,
|
||||
limit: number,
|
||||
) {
|
||||
if(!owner.publicKey)
|
||||
return;
|
||||
const marketIndex = mangoGroup.getSpotMarketIndex(spotMarket.address);
|
||||
const baseRootBank = mangoGroup.rootBankAccounts[marketIndex];
|
||||
const quoteRootBank = mangoGroup.rootBankAccounts[QUOTE_INDEX];
|
||||
if(baseRootBank == null || quoteRootBank == null)
|
||||
{
|
||||
console.log("A root bank is null")
|
||||
return;
|
||||
}
|
||||
const baseNodeBanks = await baseRootBank.loadNodeBanks(this.connection);
|
||||
const quoteNodeBanks = await quoteRootBank.loadNodeBanks(this.connection);
|
||||
const spotMarketIndex = mangoGroup.getSpotMarketIndex(spotMarket.publicKey);
|
||||
|
||||
const dexSigner = await PublicKey.createProgramAddress(
|
||||
[
|
||||
spotMarket.publicKey.toBuffer(),
|
||||
spotMarket['_decoded'].vaultSignerNonce.toArrayLike(Buffer, 'le', 8),
|
||||
],
|
||||
spotMarket.programId,
|
||||
);
|
||||
|
||||
const instruction = makeCancelAllSpotOrdersInstruction(
|
||||
this.programId,
|
||||
mangoGroup.publicKey,
|
||||
mangoGroup.mangoCache,
|
||||
mangoAccount.publicKey,
|
||||
owner.publicKey,
|
||||
baseRootBank.publicKey,
|
||||
baseNodeBanks[0].publicKey,
|
||||
baseNodeBanks[0].vault,
|
||||
quoteRootBank.publicKey,
|
||||
quoteNodeBanks[0].publicKey,
|
||||
quoteNodeBanks[0].vault,
|
||||
spotMarket.publicKey,
|
||||
spotMarket.bidsAddress,
|
||||
spotMarket.asksAddress,
|
||||
mangoAccount.spotOpenOrders[spotMarketIndex],
|
||||
mangoGroup.signerKey,
|
||||
spotMarket['_decoded'].eventQueue,
|
||||
spotMarket['_decoded'].baseVault,
|
||||
spotMarket['_decoded'].quoteVault,
|
||||
dexSigner,
|
||||
mangoGroup.dexProgramId,
|
||||
new BN(limit),
|
||||
);
|
||||
|
||||
const transaction = new Transaction();
|
||||
transaction.add(instruction);
|
||||
|
||||
return await this.sendTransaction(transaction, owner, []);
|
||||
}
|
||||
}
|
|
@ -2326,3 +2326,63 @@ export function makeRegisterReferrerIdInstruction(
|
|||
programId,
|
||||
});
|
||||
}
|
||||
|
||||
export function makeCancelAllSpotOrdersInstruction(
|
||||
programId: PublicKey,
|
||||
mangoGroupPk: PublicKey,
|
||||
mangoCachePk: PublicKey,
|
||||
mangoAccountPk: PublicKey,
|
||||
owner: PublicKey,
|
||||
baseRootBankPk: PublicKey,
|
||||
baseNodeBankPk: PublicKey,
|
||||
baseVaultPk: PublicKey,
|
||||
quoteRootBankPk: PublicKey,
|
||||
quoteNodeBankPk: PublicKey,
|
||||
quoteVaultPk: PublicKey,
|
||||
spotMarketPk: PublicKey,
|
||||
bidsPk: PublicKey,
|
||||
asksPk: PublicKey,
|
||||
openOrders: PublicKey,
|
||||
signerPk: PublicKey,
|
||||
dexEventQueuePk: PublicKey,
|
||||
dexBasePk: PublicKey,
|
||||
dexQuotePk: PublicKey,
|
||||
dexSignerPk: PublicKey,
|
||||
dexProgramPk: PublicKey,
|
||||
limit: BN,
|
||||
): TransactionInstruction {
|
||||
const keys = [
|
||||
{ isSigner: false, isWritable: false, pubkey: mangoGroupPk },
|
||||
{ isSigner: false, isWritable: false, pubkey: mangoCachePk },
|
||||
{ isSigner: false, isWritable: true, pubkey: mangoAccountPk },
|
||||
{ isSigner: true, isWritable: false, pubkey: owner },
|
||||
{ isSigner: false, isWritable: false, pubkey: baseRootBankPk },
|
||||
{ isSigner: false, isWritable: true, pubkey: baseNodeBankPk },
|
||||
{ isSigner: false, isWritable: true, pubkey: baseVaultPk },
|
||||
{ isSigner: false, isWritable: false, pubkey: quoteRootBankPk },
|
||||
{ isSigner: false, isWritable: true, pubkey: quoteNodeBankPk },
|
||||
{ isSigner: false, isWritable: true, pubkey: quoteVaultPk },
|
||||
{ isSigner: false, isWritable: true, pubkey: spotMarketPk },
|
||||
{ isSigner: false, isWritable: true, pubkey: bidsPk },
|
||||
{ isSigner: false, isWritable: true, pubkey: asksPk },
|
||||
{ isSigner: false, isWritable: true, pubkey: openOrders },
|
||||
{ isSigner: false, isWritable: false, pubkey: signerPk },
|
||||
{ isSigner: false, isWritable: true, pubkey: dexEventQueuePk },
|
||||
{ isSigner: false, isWritable: true, pubkey: dexBasePk },
|
||||
{ isSigner: false, isWritable: true, pubkey: dexQuotePk },
|
||||
{ isSigner: false, isWritable: false, pubkey: dexSignerPk },
|
||||
{ isSigner: false, isWritable: false, pubkey: dexProgramPk },
|
||||
{ isSigner: false, isWritable: false, pubkey: TOKEN_PROGRAM_ID },
|
||||
];
|
||||
|
||||
const data = encodeMangoInstruction({
|
||||
CancelAllSpotOrders: {
|
||||
limit,
|
||||
},
|
||||
});
|
||||
return new TransactionInstruction({
|
||||
keys,
|
||||
data,
|
||||
programId,
|
||||
});
|
||||
}
|
||||
|
|
|
@ -611,6 +611,14 @@ MangoInstructionLayout.addVariant(
|
|||
'PlacePerpOrder2',
|
||||
);
|
||||
|
||||
MangoInstructionLayout.addVariant(
|
||||
65,
|
||||
struct([
|
||||
u8('limit'),
|
||||
]),
|
||||
'CancelAllSpotOrders',
|
||||
);
|
||||
|
||||
const instructionMaxSpan = Math.max(
|
||||
// @ts-ignore
|
||||
...Object.values(MangoInstructionLayout.registry).map((r) => r.span),
|
||||
|
|
|
@ -0,0 +1,129 @@
|
|||
import fs from 'fs';
|
||||
import os from 'os';
|
||||
import { Cluster, Config, MangoClient, QUOTE_INDEX, sleep } from '../src';
|
||||
import configFile from '../src/ids.json';
|
||||
import { Commitment, Connection, Keypair, PublicKey, Transaction } from '@solana/web3.js';
|
||||
import { Token, TOKEN_PROGRAM_ID } from '@solana/spl-token';
|
||||
import TestGroup from './TestGroup';
|
||||
import * as serum from '@project-serum/serum';
|
||||
import * as pyth from "@pythnetwork/client";
|
||||
import { expect } from 'chai';
|
||||
|
||||
async function testCancelAllSpotOrders() {
|
||||
const cluster = (process.env.CLUSTER || 'devnet') as Cluster;
|
||||
const sleepTime = 2000;
|
||||
const config = new Config(configFile);
|
||||
const groupConfig = config.getGroup(cluster, 'devnet.2')!;
|
||||
const mangoProgramId = groupConfig.mangoProgramId;
|
||||
const mangoGroupKey = groupConfig.publicKey;
|
||||
const payer = Keypair.fromSecretKey(
|
||||
new Uint8Array(
|
||||
JSON.parse(
|
||||
process.env.KEYPAIR ||
|
||||
fs.readFileSync(os.homedir() + '/.config/solana/devnet.json', 'utf-8'),
|
||||
),
|
||||
)
|
||||
);
|
||||
const connection = new Connection(
|
||||
config.cluster_urls[cluster],
|
||||
'processed' as Commitment,
|
||||
);
|
||||
// init
|
||||
//const testGroup = new TestGroup(connection, payer, mangoProgramId);
|
||||
const client = new MangoClient(connection, mangoProgramId);
|
||||
const mangoGroup = await client.getMangoGroup(mangoGroupKey);
|
||||
|
||||
const cache = await mangoGroup.loadCache(connection);
|
||||
const rootBanks = await mangoGroup.loadRootBanks(connection);
|
||||
const quoteRootBank = rootBanks[QUOTE_INDEX];
|
||||
if (!quoteRootBank) {
|
||||
throw new Error('Quote Rootbank Not Found');
|
||||
}
|
||||
const quoteNodeBanks = await quoteRootBank.loadNodeBanks(connection);
|
||||
|
||||
const accountPk: PublicKey = (await client.createMangoAccount(
|
||||
mangoGroup,
|
||||
payer,
|
||||
1,
|
||||
))!;
|
||||
console.log('Created Account:', accountPk.toBase58());
|
||||
|
||||
await sleep(sleepTime);
|
||||
const mangoAccount = await client.getMangoAccount(
|
||||
accountPk,
|
||||
mangoGroup.dexProgramId,
|
||||
);
|
||||
|
||||
const quoteTokenInfo = mangoGroup.tokens[QUOTE_INDEX];
|
||||
const quoteToken = new Token(
|
||||
connection,
|
||||
quoteTokenInfo.mint,
|
||||
TOKEN_PROGRAM_ID,
|
||||
payer,
|
||||
);
|
||||
const quoteWallet = await quoteToken.getOrCreateAssociatedAccountInfo(
|
||||
payer.publicKey,
|
||||
);
|
||||
|
||||
await client.deposit(
|
||||
mangoGroup,
|
||||
mangoAccount,
|
||||
payer,
|
||||
quoteRootBank.publicKey,
|
||||
quoteNodeBanks[0].publicKey,
|
||||
quoteNodeBanks[0].vault,
|
||||
quoteWallet.address,
|
||||
10000,
|
||||
);
|
||||
|
||||
await sleep(sleepTime);
|
||||
|
||||
const marketPk = mangoGroup.spotMarkets[3].spotMarket;
|
||||
const market = await serum.Market.load(connection, marketPk, undefined, groupConfig.serumProgramId);
|
||||
const oracle = mangoGroup.oracles[3];
|
||||
|
||||
await mangoAccount.reload(connection);
|
||||
const oracleData = await connection.getAccountInfo(oracle);
|
||||
if(oracleData == null)
|
||||
return;
|
||||
// determine asset price
|
||||
const price = pyth.parsePriceData(oracleData?.data);
|
||||
const assetPrice = price!.price;
|
||||
console.log('asset price is ' + assetPrice)
|
||||
|
||||
// Buy some spot to create sell instructions later
|
||||
{
|
||||
await client.placeSpotOrder(mangoGroup, mangoAccount, mangoGroup.mangoCache, market, payer, "buy", assetPrice ?? 0 * 1.05, 1, 'limit');
|
||||
const consumeItx = market.makeConsumeEventsInstruction(mangoAccount.spotOpenOrders, 10);
|
||||
const trx = new Transaction();
|
||||
trx.add(consumeItx);
|
||||
await client.sendTransaction(trx, payer, []);
|
||||
await mangoAccount.reload(connection);
|
||||
}
|
||||
|
||||
// placing orders
|
||||
console.log('place order 1')
|
||||
await client.placeSpotOrder(mangoGroup, mangoAccount, mangoGroup.mangoCache, market, payer, "buy", assetPrice ?? 0 * 0.99, 1, 'limit');
|
||||
await mangoAccount.reload(connection);
|
||||
console.log('place order 2')
|
||||
await client.placeSpotOrder(mangoGroup, mangoAccount, mangoGroup.mangoCache, market, payer, "sell", assetPrice ?? 0 * 1.02, 1, 'limit');
|
||||
// checking open orders length
|
||||
{
|
||||
const orders = await mangoAccount.loadSpotOrdersForMarket(connection, market, 3)
|
||||
expect( orders.length === 2 );
|
||||
console.log("Number of orders placed are : " + orders.length)
|
||||
}
|
||||
// canceling all spot orders for a market
|
||||
console.log("Cancel All Spot Orders");
|
||||
const signature = await client.cancelAllSpotOrders(mangoGroup, mangoAccount, market, payer, 255);
|
||||
console.log("cancel all spot orders signature " + signature)
|
||||
|
||||
await sleep(sleepTime);
|
||||
{
|
||||
const orders = await mangoAccount.loadSpotOrdersForMarket(connection, market, 3)
|
||||
expect( orders.length === 0 );
|
||||
console.log("Number of orders placed are : " + orders.length)
|
||||
}
|
||||
}
|
||||
|
||||
testCancelAllSpotOrders()
|
Loading…
Reference in New Issue