From 35d39a9be5c4dbb6694607c489d557133479a923 Mon Sep 17 00:00:00 2001 From: jhlx Date: Tue, 5 Apr 2022 12:45:03 -0400 Subject: [PATCH] Update serum-ts for bulk cancel and max_ts --- .gitignore | 1 + packages/serum/src/instructions.js | 53 +++++++++++++++++++++++++++ packages/serum/src/layout.js | 4 ++ packages/serum/src/market.ts | 59 +++++++++++++++++++++++++++--- 4 files changed, 111 insertions(+), 6 deletions(-) diff --git a/.gitignore b/.gitignore index 74b6e524..4bec3c88 100644 --- a/.gitignore +++ b/.gitignore @@ -10,3 +10,4 @@ docs/lockup-ui/ npm-debug.log* yarn-debug.log* yarn-error.log* +private/ \ No newline at end of file diff --git a/packages/serum/src/instructions.js b/packages/serum/src/instructions.js index 41f3be5f..015b00fd 100644 --- a/packages/serum/src/instructions.js +++ b/packages/serum/src/instructions.js @@ -6,6 +6,7 @@ import { sideLayout, u128, u64, + i64, VersionedLayout, } from './layout'; import { @@ -14,6 +15,7 @@ import { PublicKey, } from '@solana/web3.js'; import { TOKEN_PROGRAM_ID } from './token-instructions'; +import BN from 'bn.js'; // NOTE: Update these if the position of arguments for the settleFunds instruction changes export const SETTLE_FUNDS_BASE_WALLET_INDEX = 5; @@ -82,6 +84,7 @@ INSTRUCTION_LAYOUT.inner.addVariant( orderTypeLayout('orderType'), u64('clientId'), u16('limit'), + i64('maxTs'), ]), 'newOrderV3', ); @@ -99,6 +102,20 @@ INSTRUCTION_LAYOUT.inner.addVariant(14, struct([]), 'closeOpenOrders'); INSTRUCTION_LAYOUT.inner.addVariant(15, struct([]), 'initOpenOrders'); INSTRUCTION_LAYOUT.inner.addVariant(16, struct([u16('limit')]), 'prune'); INSTRUCTION_LAYOUT.inner.addVariant(17, struct([u16('limit')]), 'consumeEventsPermissioned'); +INSTRUCTION_LAYOUT.inner.addVariant( + 18, + struct([ + u64('clientId0'), + u64('clientId1'), + u64('clientId2'), + u64('clientId3'), + u64('clientId4'), + u64('clientId5'), + u64('clientId6'), + u64('clientId7') + ]), + 'cancelOrdersByClientIds', +); export function encodeInstruction(instruction) { const b = Buffer.alloc(100); @@ -244,6 +261,7 @@ export class DexInstructions { programId, selfTradeBehavior, feeDiscountPubkey = null, + maxTs = null, }) { const keys = [ { pubkey: market, isSigner: false, isWritable: true }, @@ -279,6 +297,7 @@ export class DexInstructions { orderType, clientId, limit: 65535, + maxTs: new BN(maxTs ?? '9223372036854775807'), }, }), }); @@ -460,6 +479,40 @@ export class DexInstructions { }); } + static cancelOrdersByClientIds({ + market, + openOrders, + owner, + bids, + asks, + eventQueue, + clientIds, + programId, + }) { + if (clientIds.length > 8) { + throw new Error("Number of client ids cannot exceed 8!"); + } + + while (clientIds.length < 8) { + clientIds.push(new BN(0)); + } + + return new TransactionInstruction({ + keys: [ + { pubkey: market, isSigner: false, isWritable: false }, + { pubkey: bids, isSigner: false, isWritable: true }, + { pubkey: asks, isSigner: false, isWritable: true }, + { pubkey: openOrders, isSigner: false, isWritable: true }, + { pubkey: owner, isSigner: true, isWritable: false }, + { pubkey: eventQueue, isSigner: false, isWritable: true }, + ], + programId, + data: encodeInstruction({ + cancelOrdersByClientIds: Object.fromEntries(clientIds.map((clientId, i) => [`clientId${i}`, clientId])), + }), + }); + } + static settleFunds({ market, openOrders, diff --git a/packages/serum/src/layout.js b/packages/serum/src/layout.js index d152e499..2b615c0c 100644 --- a/packages/serum/src/layout.js +++ b/packages/serum/src/layout.js @@ -50,6 +50,10 @@ export function u64(property) { return new BNLayout(8, property); } +export function i64(property) { + return new BNLayout(8, property); +} + export function u128(property) { return new BNLayout(16, property); } diff --git a/packages/serum/src/market.ts b/packages/serum/src/market.ts index 07ee1f53..6f2fea8f 100644 --- a/packages/serum/src/market.ts +++ b/packages/serum/src/market.ts @@ -431,6 +431,7 @@ export class Market { openOrdersAddressKey, openOrdersAccount, feeDiscountPubkey, + maxTs, }: OrderParams, ) { const { transaction, signers } = await this.makePlaceOrderTransaction< @@ -446,6 +447,7 @@ export class Market { openOrdersAddressKey, openOrdersAccount, feeDiscountPubkey, + maxTs, }); return await this._sendTransaction(connection, transaction, [ owner, @@ -599,6 +601,7 @@ export class Market { openOrdersAccount, feeDiscountPubkey = undefined, selfTradeBehavior = 'decrementTake', + maxTs, }: OrderParams, cacheDurationMs = 0, feeDiscountPubkeyCacheDurationMs = 0, @@ -714,6 +717,7 @@ export class Market { openOrdersAddressKey: openOrdersAddress, feeDiscountPubkey: useFeeDiscountPubkey, selfTradeBehavior, + maxTs, }); transaction.add(placeOrderInstruction); @@ -745,6 +749,7 @@ export class Market { openOrdersAddressKey, openOrdersAccount, feeDiscountPubkey = null, + maxTs, } = params; // @ts-ignore const ownerAddress: PublicKey = owner.publicKey ?? owner; @@ -796,6 +801,7 @@ export class Market { feeDiscountPubkey = null, selfTradeBehavior = 'decrementTake', programId, + maxTs, } = params; // @ts-ignore const ownerAddress: PublicKey = owner.publicKey ?? owner; @@ -822,9 +828,12 @@ export class Market { clientId, programId: programId ?? this._programId, selfTradeBehavior, + // @ts-ignore feeDiscountPubkey: this.supportsSrmFeeDiscounts ? feeDiscountPubkey : null, + // @ts-ignore + maxTs, }); } @@ -861,6 +870,21 @@ export class Market { return await this._sendTransaction(connection, transaction, [owner]); } + async cancelOrdersByClientIds( + connection: Connection, + owner: Account, + openOrders: PublicKey, + clientIds: BN[], + ) { + const transaction = await this.makeCancelOrdersByClientIdsTransaction( + connection, + owner.publicKey, + openOrders, + clientIds, + ); + return await this._sendTransaction(connection, transaction, [owner]); + } + async makeCancelOrderByClientIdTransaction( connection: Connection, owner: PublicKey, @@ -896,6 +920,28 @@ export class Market { return transaction; } + async makeCancelOrdersByClientIdsTransaction( + connection: Connection, + owner: PublicKey, + openOrders: PublicKey, + clientIds: BN[], + ) { + const transaction = new Transaction(); + transaction.add( + DexInstructions.cancelOrdersByClientIds({ + market: this.address, + openOrders, + owner, + bids: this._decoded.bids, + asks: this._decoded.asks, + eventQueue: this._decoded.eventQueue, + clientIds, + programId: this._programId, + }), + ); + return transaction; + } + async cancelOrder(connection: Connection, owner: Account, order: Order) { const transaction = await this.makeCancelOrderTransaction( connection, @@ -1194,8 +1240,8 @@ export class Market { (price * Math.pow(10, this._quoteSplTokenDecimals) * this._decoded.baseLotSize.toNumber()) / - (Math.pow(10, this._baseSplTokenDecimals) * - this._decoded.quoteLotSize.toNumber()), + (Math.pow(10, this._baseSplTokenDecimals) * + this._decoded.quoteLotSize.toNumber()), ), ); } @@ -1264,11 +1310,12 @@ export interface OrderParams { openOrdersAccount?: Account; feeDiscountPubkey?: PublicKey | null; selfTradeBehavior?: - | 'decrementTake' - | 'cancelProvide' - | 'abortTransaction' - | undefined; + | 'decrementTake' + | 'cancelProvide' + | 'abortTransaction' + | undefined; programId?: PublicKey; + maxTs?: number | null; } export const _OPEN_ORDERS_LAYOUT_V1 = struct([