From 336fa0ee3d5d2ec7b6005fc5cbff15bf9b44544b Mon Sep 17 00:00:00 2001 From: wphan Date: Wed, 30 Jul 2025 10:38:39 -0700 Subject: [PATCH 1/2] sdk: handle unfillable reduce only orders --- sdk/src/dlob/DLOB.ts | 62 +++++++++++++++++++++++++++++++++++++++++++- sdk/src/types.ts | 1 + 2 files changed, 62 insertions(+), 1 deletion(-) diff --git a/sdk/src/dlob/DLOB.ts b/sdk/src/dlob/DLOB.ts index 92fb572c2..17676e282 100644 --- a/sdk/src/dlob/DLOB.ts +++ b/sdk/src/dlob/DLOB.ts @@ -504,10 +504,23 @@ export class DLOB { new BN(slot) ); + const stepSize = isVariant(marketType, 'perp') + ? (marketAccount as PerpMarketAccount).amm.orderStepSize + : (marketAccount as SpotMarketAccount).orderStepSize; + + const cancelReduceOnlyNodesToFill = + this.findUnfillableReduceOnlyOrdersToCancel( + marketIndex, + marketType, + stepSize + ); + return this.mergeNodesToFill( restingLimitOrderNodesToFill, takingOrderNodesToFill - ).concat(expiredNodesToFill); + ) + .concat(expiredNodesToFill) + .concat(cancelReduceOnlyNodesToFill); } getMakerRebate( @@ -997,6 +1010,53 @@ export class DLOB { return nodesToFill; } + public findUnfillableReduceOnlyOrdersToCancel( + marketIndex: number, + marketType: MarketType, + stepSize: BN + ): NodeToFill[] { + const nodesToFill = new Array(); + + const marketTypeStr = getVariant(marketType) as MarketTypeStr; + const nodeLists = this.orderLists.get(marketTypeStr).get(marketIndex); + + if (!nodeLists) { + return nodesToFill; + } + + const generators = [ + nodeLists.takingLimit.bid.getGenerator(), + nodeLists.restingLimit.bid.getGenerator(), + nodeLists.floatingLimit.bid.getGenerator(), + nodeLists.market.bid.getGenerator(), + nodeLists.signedMsg.bid.getGenerator(), + nodeLists.takingLimit.ask.getGenerator(), + nodeLists.restingLimit.ask.getGenerator(), + nodeLists.floatingLimit.ask.getGenerator(), + nodeLists.market.ask.getGenerator(), + nodeLists.signedMsg.ask.getGenerator(), + nodeLists.trigger.above.getGenerator(), + nodeLists.trigger.below.getGenerator(), + ]; + + for (const generator of generators) { + for (const node of generator) { + if (!node.order.reduceOnly) { + continue; + } + + if (node.baseAssetAmount.lt(stepSize)) { + nodesToFill.push({ + node, + makerNodes: [], + }); + } + } + } + + return nodesToFill; + } + *getTakingBids( marketIndex: number, marketType: MarketType, diff --git a/sdk/src/types.ts b/sdk/src/types.ts index 06a174f42..2d6a34d11 100644 --- a/sdk/src/types.ts +++ b/sdk/src/types.ts @@ -196,6 +196,7 @@ export class OrderBitFlag { static readonly SignedMessage = 1; static readonly OracleTriggerMarket = 2; static readonly SafeTriggerOrder = 4; + static readonly NewTriggerReduceOnly = 8; } export class OrderAction { From d21ebc793ef8cbfbb1ecc276e9385feb06877c89 Mon Sep 17 00:00:00 2001 From: wphan Date: Wed, 30 Jul 2025 13:09:57 -0700 Subject: [PATCH 2/2] fix dlob tests build errors --- sdk/package.json | 1 + sdk/tests/amm/test.ts | 11 ++++++++++- sdk/tests/dlob/helpers.ts | 14 ++++++++++---- sdk/tests/dlob/test.ts | 6 ++++-- 4 files changed, 25 insertions(+), 7 deletions(-) diff --git a/sdk/package.json b/sdk/package.json index 3beb3fd95..50f6671f3 100644 --- a/sdk/package.json +++ b/sdk/package.json @@ -19,6 +19,7 @@ "test:inspect": "mocha --inspect-brk -r ts-node/register tests/**/*.ts", "test:bignum": "mocha -r ts-node/register tests/bn/**/*.ts", "test:ci": "mocha -r ts-node/register tests/ci/**/*.ts", + "test:dlob": "mocha -r ts-node/register tests/dlob/**/*.ts", "patch-and-pub": "npm version patch --force && npm publish", "prettify": "prettier --check './src/***/*.ts'", "prettify:fix": "prettier --write './{src,tests}/***/*.ts'", diff --git a/sdk/tests/amm/test.ts b/sdk/tests/amm/test.ts index fc8821c1a..143a66673 100644 --- a/sdk/tests/amm/test.ts +++ b/sdk/tests/amm/test.ts @@ -278,7 +278,8 @@ describe('AMM Tests', () => { oracleStd, longIntensity, shortIntensity, - volume24H + volume24H, + 0, ); const l1 = spreads[0]; const s1 = spreads[1]; @@ -305,6 +306,7 @@ describe('AMM Tests', () => { longIntensity, shortIntensity, volume24H, + 0, true ); // console.log(terms1); @@ -337,6 +339,7 @@ describe('AMM Tests', () => { new BN(12358265776), new BN(72230366233), new BN(432067603632), + 0, true ); @@ -369,6 +372,7 @@ describe('AMM Tests', () => { new BN(12358265776), new BN(72230366233), new BN(432067603632), + 0, true ); @@ -402,6 +406,7 @@ describe('AMM Tests', () => { new BN(12358265776), new BN(72230366233), new BN(432067603632), + 0, true ); @@ -436,6 +441,7 @@ describe('AMM Tests', () => { new BN(768323534), new BN(243875031), new BN(130017761029), + 0, true ); @@ -608,6 +614,7 @@ describe('AMM Tests', () => { new BN(suiExample.amm.longIntensityVolume), new BN(suiExample.amm.shortIntensityVolume), new BN(suiExample.amm.volume24H), + 0, true ); @@ -648,6 +655,7 @@ describe('AMM Tests', () => { new BN(suiExample.amm.longIntensityVolume), new BN(suiExample.amm.shortIntensityVolume), new BN(suiExample.amm.volume24H), + 0, true ); console.log(termsSuiExampleMod1); @@ -676,6 +684,7 @@ describe('AMM Tests', () => { new BN(suiExample.amm.longIntensityVolume), new BN(suiExample.amm.shortIntensityVolume), new BN(suiExample.amm.volume24H), + 0, true ); diff --git a/sdk/tests/dlob/helpers.ts b/sdk/tests/dlob/helpers.ts index 78ab90387..d1b68abe8 100644 --- a/sdk/tests/dlob/helpers.ts +++ b/sdk/tests/dlob/helpers.ts @@ -26,6 +26,7 @@ import { PRICE_PRECISION, DataAndSlot, } from '../../src'; +import { EventEmitter } from 'events'; export const mockPerpPosition: PerpPosition = { baseAssetAmount: new BN(0), @@ -62,7 +63,6 @@ export const mockAMM: AMM = { lastMarkPriceTwap: new BN(0), lastMarkPriceTwap5Min: new BN(0), lastMarkPriceTwapTs: new BN(0), - totalFeeEarnedPerLp: new BN(0), historicalOracleData: { lastOraclePrice: new BN(0), lastOracleConf: new BN(0), @@ -130,13 +130,10 @@ export const mockAMM: AMM = { markStd: new BN(0), oracleStd: new BN(0), - longIntensityCount: 0, longIntensityVolume: new BN(0), - shortIntensityCount: 0, shortIntensityVolume: new BN(0), volume24H: new BN(0), minOrderSize: new BN(0), - maxPositionSize: new BN(0), bidBaseAssetReserve: new BN(0), bidQuoteAssetReserve: new BN(0), @@ -150,11 +147,16 @@ export const mockAMM: AMM = { takerSpeedBumpOverride: 0, ammSpreadAdjustment: 0, ammInventorySpreadAdjustment: 0, + mmOracleSequenceId: new BN(0), + mmOraclePrice: new BN(0), + mmOracleSlot: new BN(0), + lastFundingOracleTwap: new BN(0), }; export const mockPerpMarkets: Array = [ { status: MarketStatus.INITIALIZED, + lastFillPrice: new BN(0), name: [], contractType: ContractType.PERPETUAL, contractTier: ContractTier.A, @@ -201,6 +203,7 @@ export const mockPerpMarkets: Array = [ }, { status: MarketStatus.INITIALIZED, + lastFillPrice: new BN(0), contractTier: ContractTier.A, nextFundingRateRecordId: new BN(0), nextCurveRecordId: new BN(0), @@ -247,6 +250,7 @@ export const mockPerpMarkets: Array = [ }, { status: MarketStatus.INITIALIZED, + lastFillPrice: new BN(0), contractTier: ContractTier.A, nextFundingRateRecordId: new BN(0), nextCurveRecordId: new BN(0), @@ -574,6 +578,7 @@ export const mockSpotMarkets: Array = [ export const mockStateAccount: StateAccount = { admin: PublicKey.default, + featureBitFlags: 0, defaultMarketOrderTimeInForce: 0, defaultSpotAuctionDuration: 0, discountMint: PublicKey.default, @@ -651,6 +656,7 @@ export const mockStateAccount: StateAccount = { }; export class MockUserMap implements UserMapInterface { + eventEmitter: EventEmitter = new EventEmitter(); private userMap = new Map(); private userAccountToAuthority = new Map(); private driftClient: DriftClient; diff --git a/sdk/tests/dlob/test.ts b/sdk/tests/dlob/test.ts index 75d50db1c..eea4a13b5 100644 --- a/sdk/tests/dlob/test.ts +++ b/sdk/tests/dlob/test.ts @@ -99,7 +99,8 @@ function insertOrderToDLOB( }, userAccount.toString(), slot.toNumber(), - false + false, + baseAssetAmount ); } @@ -153,7 +154,8 @@ function insertTriggerOrderToDLOB( }, userAccount.toString(), slot.toNumber(), - false + false, + baseAssetAmount ); }