@drift-labs/sdk 2.18.0-beta.0 → 2.18.0-beta.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/constants/perpMarkets.js +10 -0
- package/lib/dlob/DLOB.d.ts +2 -2
- package/lib/dlob/DLOB.js +19 -36
- package/lib/driftClient.js +1 -1
- package/lib/factory/oracleClient.js +4 -0
- package/lib/idl/drift.json +4 -1
- package/lib/math/trade.d.ts +6 -0
- package/lib/math/trade.js +6 -0
- package/lib/oracles/pythClient.d.ts +4 -3
- package/lib/oracles/pythClient.js +8 -7
- package/lib/types.d.ts +3 -0
- package/lib/types.js +1 -0
- package/lib/user.js +7 -5
- package/package.json +1 -1
- package/src/constants/perpMarkets.ts +10 -0
- package/src/dlob/DLOB.ts +26 -60
- package/src/driftClient.ts +1 -1
- package/src/factory/oracleClient.ts +5 -0
- package/src/idl/drift.json +4 -1
- package/src/math/trade.ts +6 -0
- package/src/oracles/pythClient.ts +27 -8
- package/src/types.ts +1 -0
- package/src/user.ts +6 -4
- package/tests/dlob/test.ts +187 -5
|
@@ -44,6 +44,16 @@ exports.DevnetPerpMarkets = [
|
|
|
44
44
|
launchTs: 1675610186000,
|
|
45
45
|
oracleSource: __1.OracleSource.PYTH,
|
|
46
46
|
},
|
|
47
|
+
{
|
|
48
|
+
fullName: 'Bonk',
|
|
49
|
+
category: ['Meme'],
|
|
50
|
+
symbol: 'BONK-PERP',
|
|
51
|
+
baseAssetSymbol: 'BONK',
|
|
52
|
+
marketIndex: 4,
|
|
53
|
+
oracle: new web3_js_1.PublicKey('6bquU99ktV1VRiHDr8gMhDFt3kMfhCQo5nfNrg2Urvsn'),
|
|
54
|
+
launchTs: 1677068931000,
|
|
55
|
+
oracleSource: __1.OracleSource.PYTH_1000,
|
|
56
|
+
},
|
|
47
57
|
];
|
|
48
58
|
exports.MainnetPerpMarkets = [
|
|
49
59
|
{
|
package/lib/dlob/DLOB.d.ts
CHANGED
|
@@ -88,11 +88,11 @@ export declare class DLOB {
|
|
|
88
88
|
getMakerLimitBids(marketIndex: number, slot: number, marketType: MarketType, oraclePriceData: OraclePriceData, fallbackAsk?: BN): Generator<DLOBNode>;
|
|
89
89
|
getAsks(marketIndex: number, fallbackAsk: BN | undefined, slot: number, marketType: MarketType, oraclePriceData: OraclePriceData): Generator<DLOBNode>;
|
|
90
90
|
getBids(marketIndex: number, fallbackBid: BN | undefined, slot: number, marketType: MarketType, oraclePriceData: OraclePriceData): Generator<DLOBNode>;
|
|
91
|
-
findCrossingRestingLimitOrders(marketIndex: number, slot: number, marketType: MarketType, oraclePriceData: OraclePriceData
|
|
91
|
+
findCrossingRestingLimitOrders(marketIndex: number, slot: number, marketType: MarketType, oraclePriceData: OraclePriceData): NodeToFill[];
|
|
92
92
|
determineMakerAndTaker(askNode: DLOBNode, bidNode: DLOBNode): {
|
|
93
93
|
takerNode: DLOBNode;
|
|
94
94
|
makerNode: DLOBNode;
|
|
95
|
-
};
|
|
95
|
+
} | undefined;
|
|
96
96
|
getBestAsk(marketIndex: number, fallbackAsk: BN | undefined, slot: number, marketType: MarketType, oraclePriceData: OraclePriceData): BN;
|
|
97
97
|
getBestBid(marketIndex: number, fallbackBid: BN | undefined, slot: number, marketType: MarketType, oraclePriceData: OraclePriceData): BN;
|
|
98
98
|
findNodesToTrigger(marketIndex: number, slot: number, oraclePrice: BN, marketType: MarketType, stateAccount: StateAccount): NodeToTrigger[];
|
package/lib/dlob/DLOB.js
CHANGED
|
@@ -310,7 +310,7 @@ class DLOB {
|
|
|
310
310
|
}
|
|
311
311
|
findRestingLimitOrderNodesToFill(marketIndex, slot, marketType, oraclePriceData, isAmmPaused, minAuctionDuration, fallbackAsk, fallbackBid) {
|
|
312
312
|
const nodesToFill = new Array();
|
|
313
|
-
const crossingNodes = this.findCrossingRestingLimitOrders(marketIndex, slot, marketType, oraclePriceData
|
|
313
|
+
const crossingNodes = this.findCrossingRestingLimitOrders(marketIndex, slot, marketType, oraclePriceData);
|
|
314
314
|
for (const crossingNode of crossingNodes) {
|
|
315
315
|
nodesToFill.push(crossingNode);
|
|
316
316
|
}
|
|
@@ -711,40 +711,30 @@ class DLOB {
|
|
|
711
711
|
.gt(currentNode.getPrice(oraclePriceData, slot));
|
|
712
712
|
});
|
|
713
713
|
}
|
|
714
|
-
findCrossingRestingLimitOrders(marketIndex, slot, marketType, oraclePriceData
|
|
714
|
+
findCrossingRestingLimitOrders(marketIndex, slot, marketType, oraclePriceData) {
|
|
715
715
|
const nodesToFill = new Array();
|
|
716
716
|
for (const askNode of this.getRestingLimitAsks(marketIndex, slot, marketType, oraclePriceData)) {
|
|
717
|
-
|
|
717
|
+
const bidGenerator = this.getRestingLimitBids(marketIndex, slot, marketType, oraclePriceData);
|
|
718
|
+
for (const bidNode of bidGenerator) {
|
|
718
719
|
const bidPrice = bidNode.getPrice(oraclePriceData, slot);
|
|
719
720
|
const askPrice = askNode.getPrice(oraclePriceData, slot);
|
|
720
|
-
// orders don't cross
|
|
721
|
+
// orders don't cross
|
|
721
722
|
if (bidPrice.lt(askPrice)) {
|
|
722
|
-
|
|
723
|
+
break;
|
|
723
724
|
}
|
|
724
725
|
const bidOrder = bidNode.order;
|
|
725
726
|
const askOrder = askNode.order;
|
|
726
727
|
// Can't match orders from the same user
|
|
727
728
|
const sameUser = bidNode.userAccount.equals(askNode.userAccount);
|
|
728
|
-
if (sameUser
|
|
729
|
+
if (sameUser) {
|
|
729
730
|
continue;
|
|
730
731
|
}
|
|
731
|
-
const
|
|
732
|
-
//
|
|
733
|
-
if (!
|
|
734
|
-
|
|
735
|
-
let askPrice;
|
|
736
|
-
if (__1.isVariant(takerNode.order.direction, 'long')) {
|
|
737
|
-
bidPrice = __1.BN.min(takerNode.getPrice(oraclePriceData, slot), fallbackAsk || __1.BN_MAX);
|
|
738
|
-
askPrice = makerNode.getPrice(oraclePriceData, slot);
|
|
739
|
-
}
|
|
740
|
-
else {
|
|
741
|
-
bidPrice = makerNode.getPrice(oraclePriceData, slot);
|
|
742
|
-
askPrice = __1.BN.max(takerNode.getPrice(oraclePriceData, slot), fallbackBid || __1.ZERO);
|
|
743
|
-
}
|
|
744
|
-
if (bidPrice.lt(askPrice)) {
|
|
745
|
-
continue;
|
|
746
|
-
}
|
|
732
|
+
const makerAndTaker = this.determineMakerAndTaker(askNode, bidNode);
|
|
733
|
+
// unable to match maker and taker due to post only or slot
|
|
734
|
+
if (!makerAndTaker) {
|
|
735
|
+
continue;
|
|
747
736
|
}
|
|
737
|
+
const { takerNode, makerNode } = makerAndTaker;
|
|
748
738
|
const bidBaseRemaining = bidOrder.baseAssetAmount.sub(bidOrder.baseAssetAmountFilled);
|
|
749
739
|
const askBaseRemaining = askOrder.baseAssetAmount.sub(askOrder.baseAssetAmountFilled);
|
|
750
740
|
const baseFilled = __1.BN.min(bidBaseRemaining, askBaseRemaining);
|
|
@@ -769,30 +759,23 @@ class DLOB {
|
|
|
769
759
|
return nodesToFill;
|
|
770
760
|
}
|
|
771
761
|
determineMakerAndTaker(askNode, bidNode) {
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
makerNode: bidNode,
|
|
776
|
-
};
|
|
777
|
-
}
|
|
778
|
-
else if (askNode.order.postOnly) {
|
|
779
|
-
return {
|
|
780
|
-
takerNode: bidNode,
|
|
781
|
-
makerNode: askNode,
|
|
782
|
-
};
|
|
783
|
-
}
|
|
784
|
-
else if (askNode.order.slot.lt(bidNode.order.slot)) {
|
|
762
|
+
const askSlot = askNode.order.slot.add(new __1.BN(askNode.order.auctionDuration));
|
|
763
|
+
const bidSlot = bidNode.order.slot.add(new __1.BN(bidNode.order.auctionDuration));
|
|
764
|
+
if (askSlot.lte(bidSlot) && !bidNode.order.postOnly) {
|
|
785
765
|
return {
|
|
786
766
|
takerNode: bidNode,
|
|
787
767
|
makerNode: askNode,
|
|
788
768
|
};
|
|
789
769
|
}
|
|
790
|
-
else {
|
|
770
|
+
else if (bidSlot.lte(askSlot) && !askNode.order.postOnly) {
|
|
791
771
|
return {
|
|
792
772
|
takerNode: askNode,
|
|
793
773
|
makerNode: bidNode,
|
|
794
774
|
};
|
|
795
775
|
}
|
|
776
|
+
else {
|
|
777
|
+
return undefined;
|
|
778
|
+
}
|
|
796
779
|
}
|
|
797
780
|
getBestAsk(marketIndex, fallbackAsk, slot, marketType, oraclePriceData) {
|
|
798
781
|
return this.getAsks(marketIndex, fallbackAsk, slot, marketType, oraclePriceData)
|
package/lib/driftClient.js
CHANGED
|
@@ -2094,7 +2094,7 @@ class DriftClient {
|
|
|
2094
2094
|
writablePerpMarketIndexes: [marketIndex],
|
|
2095
2095
|
writableSpotMarketIndexes: [numericConstants_1.QUOTE_SPOT_MARKET_INDEX],
|
|
2096
2096
|
});
|
|
2097
|
-
const spotMarket = this.
|
|
2097
|
+
const spotMarket = this.getQuoteSpotMarketAccount();
|
|
2098
2098
|
return await this.program.instruction.resolvePerpBankruptcy(numericConstants_1.QUOTE_SPOT_MARKET_INDEX, marketIndex, {
|
|
2099
2099
|
accounts: {
|
|
2100
2100
|
state: await this.getStatePublicKey(),
|
|
@@ -5,10 +5,14 @@ const types_1 = require("../types");
|
|
|
5
5
|
const pythClient_1 = require("../oracles/pythClient");
|
|
6
6
|
// import { SwitchboardClient } from '../oracles/switchboardClient';
|
|
7
7
|
const quoteAssetOracleClient_1 = require("../oracles/quoteAssetOracleClient");
|
|
8
|
+
const anchor_1 = require("@project-serum/anchor");
|
|
8
9
|
function getOracleClient(oracleSource, connection) {
|
|
9
10
|
if (types_1.isVariant(oracleSource, 'pyth')) {
|
|
10
11
|
return new pythClient_1.PythClient(connection);
|
|
11
12
|
}
|
|
13
|
+
if (types_1.isVariant(oracleSource, 'pyth1000')) {
|
|
14
|
+
return new pythClient_1.PythClient(connection, new anchor_1.BN(1000));
|
|
15
|
+
}
|
|
12
16
|
// if (isVariant(oracleSource, 'switchboard')) {
|
|
13
17
|
// return new SwitchboardClient(connection);
|
|
14
18
|
// }
|
package/lib/idl/drift.json
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"version": "2.18.0-beta.
|
|
2
|
+
"version": "2.18.0-beta.2",
|
|
3
3
|
"name": "drift",
|
|
4
4
|
"instructions": [
|
|
5
5
|
{
|
|
@@ -6237,6 +6237,9 @@
|
|
|
6237
6237
|
{
|
|
6238
6238
|
"name": "Pyth"
|
|
6239
6239
|
},
|
|
6240
|
+
{
|
|
6241
|
+
"name": "Pyth1000"
|
|
6242
|
+
},
|
|
6240
6243
|
{
|
|
6241
6244
|
"name": "Switchboard"
|
|
6242
6245
|
},
|
package/lib/math/trade.d.ts
CHANGED
|
@@ -9,6 +9,9 @@ import { Orderbook } from '@project-serum/serum';
|
|
|
9
9
|
export declare type PriceImpactUnit = 'entryPrice' | 'maxPrice' | 'priceDelta' | 'priceDeltaAsNumber' | 'pctAvg' | 'pctMax' | 'quoteAssetAmount' | 'quoteAssetAmountPeg' | 'acquiredBaseAssetAmount' | 'acquiredQuoteAssetAmount' | 'all';
|
|
10
10
|
/**
|
|
11
11
|
* Calculates avg/max slippage (price impact) for candidate trade
|
|
12
|
+
*
|
|
13
|
+
* @deprecated use calculateEstimatedPerpEntryPrice instead
|
|
14
|
+
*
|
|
12
15
|
* @param direction
|
|
13
16
|
* @param amount
|
|
14
17
|
* @param market
|
|
@@ -40,6 +43,9 @@ export declare function calculateTradeAcquiredAmounts(direction: PositionDirecti
|
|
|
40
43
|
/**
|
|
41
44
|
* calculateTargetPriceTrade
|
|
42
45
|
* simple function for finding arbitraging trades
|
|
46
|
+
*
|
|
47
|
+
* @deprecated
|
|
48
|
+
*
|
|
43
49
|
* @param market
|
|
44
50
|
* @param targetPrice
|
|
45
51
|
* @param pct optional default is 100% gap filling, can set smaller.
|
package/lib/math/trade.js
CHANGED
|
@@ -12,6 +12,9 @@ const types_2 = require("../types");
|
|
|
12
12
|
const MAXPCT = new anchor_1.BN(1000); //percentage units are [0,1000] => [0,1]
|
|
13
13
|
/**
|
|
14
14
|
* Calculates avg/max slippage (price impact) for candidate trade
|
|
15
|
+
*
|
|
16
|
+
* @deprecated use calculateEstimatedPerpEntryPrice instead
|
|
17
|
+
*
|
|
15
18
|
* @param direction
|
|
16
19
|
* @param amount
|
|
17
20
|
* @param market
|
|
@@ -120,6 +123,9 @@ exports.calculateTradeAcquiredAmounts = calculateTradeAcquiredAmounts;
|
|
|
120
123
|
/**
|
|
121
124
|
* calculateTargetPriceTrade
|
|
122
125
|
* simple function for finding arbitraging trades
|
|
126
|
+
*
|
|
127
|
+
* @deprecated
|
|
128
|
+
*
|
|
123
129
|
* @param market
|
|
124
130
|
* @param targetPrice
|
|
125
131
|
* @param pct optional default is 100% gap filling, can set smaller.
|
|
@@ -1,12 +1,13 @@
|
|
|
1
|
-
/// <reference types="node" />
|
|
2
1
|
/// <reference types="bn.js" />
|
|
2
|
+
/// <reference types="node" />
|
|
3
3
|
import { Connection, PublicKey } from '@solana/web3.js';
|
|
4
4
|
import { OracleClient, OraclePriceData } from './types';
|
|
5
5
|
import { BN } from '@project-serum/anchor';
|
|
6
6
|
export declare class PythClient implements OracleClient {
|
|
7
7
|
private connection;
|
|
8
|
-
|
|
8
|
+
private multiple;
|
|
9
|
+
constructor(connection: Connection, multiple?: BN);
|
|
9
10
|
getOraclePriceData(pricePublicKey: PublicKey): Promise<OraclePriceData>;
|
|
10
11
|
getOraclePriceDataFromBuffer(buffer: Buffer): OraclePriceData;
|
|
11
12
|
}
|
|
12
|
-
export declare function convertPythPrice(price: number, exponent: number): BN;
|
|
13
|
+
export declare function convertPythPrice(price: number, exponent: number, multiple: BN): BN;
|
|
@@ -5,8 +5,9 @@ const client_1 = require("@pythnetwork/client");
|
|
|
5
5
|
const anchor_1 = require("@project-serum/anchor");
|
|
6
6
|
const numericConstants_1 = require("../constants/numericConstants");
|
|
7
7
|
class PythClient {
|
|
8
|
-
constructor(connection) {
|
|
8
|
+
constructor(connection, multiple = numericConstants_1.ONE) {
|
|
9
9
|
this.connection = connection;
|
|
10
|
+
this.multiple = multiple;
|
|
10
11
|
}
|
|
11
12
|
async getOraclePriceData(pricePublicKey) {
|
|
12
13
|
const accountInfo = await this.connection.getAccountInfo(pricePublicKey);
|
|
@@ -15,19 +16,19 @@ class PythClient {
|
|
|
15
16
|
getOraclePriceDataFromBuffer(buffer) {
|
|
16
17
|
const priceData = client_1.parsePriceData(buffer);
|
|
17
18
|
return {
|
|
18
|
-
price: convertPythPrice(priceData.aggregate.price, priceData.exponent),
|
|
19
|
+
price: convertPythPrice(priceData.aggregate.price, priceData.exponent, this.multiple),
|
|
19
20
|
slot: new anchor_1.BN(priceData.lastSlot.toString()),
|
|
20
|
-
confidence: convertPythPrice(priceData.confidence, priceData.exponent),
|
|
21
|
-
twap: convertPythPrice(priceData.twap.value, priceData.exponent),
|
|
22
|
-
twapConfidence: convertPythPrice(priceData.twac.value, priceData.exponent),
|
|
21
|
+
confidence: convertPythPrice(priceData.confidence, priceData.exponent, this.multiple),
|
|
22
|
+
twap: convertPythPrice(priceData.twap.value, priceData.exponent, this.multiple),
|
|
23
|
+
twapConfidence: convertPythPrice(priceData.twac.value, priceData.exponent, this.multiple),
|
|
23
24
|
hasSufficientNumberOfDataPoints: true,
|
|
24
25
|
};
|
|
25
26
|
}
|
|
26
27
|
}
|
|
27
28
|
exports.PythClient = PythClient;
|
|
28
|
-
function convertPythPrice(price, exponent) {
|
|
29
|
+
function convertPythPrice(price, exponent, multiple) {
|
|
29
30
|
exponent = Math.abs(exponent);
|
|
30
|
-
const pythPrecision = numericConstants_1.TEN.pow(new anchor_1.BN(exponent).abs());
|
|
31
|
+
const pythPrecision = numericConstants_1.TEN.pow(new anchor_1.BN(exponent).abs()).div(multiple);
|
|
31
32
|
return new anchor_1.BN(price * Math.pow(10, exponent))
|
|
32
33
|
.mul(numericConstants_1.PRICE_PRECISION)
|
|
33
34
|
.div(pythPrecision);
|
package/lib/types.d.ts
CHANGED
package/lib/types.js
CHANGED
|
@@ -78,6 +78,7 @@ class OracleSource {
|
|
|
78
78
|
}
|
|
79
79
|
exports.OracleSource = OracleSource;
|
|
80
80
|
OracleSource.PYTH = { pyth: {} };
|
|
81
|
+
OracleSource.PYTH_1000 = { pyth1000: {} };
|
|
81
82
|
// static readonly SWITCHBOARD = { switchboard: {} };
|
|
82
83
|
OracleSource.QUOTE_ASSET = { quoteAsset: {} };
|
|
83
84
|
class OrderType {
|
package/lib/user.js
CHANGED
|
@@ -400,11 +400,13 @@ class User {
|
|
|
400
400
|
}
|
|
401
401
|
totalLiabilityValue = totalLiabilityValue.add(new _1.BN(spotPosition.openOrders).mul(numericConstants_1.OPEN_ORDER_MARGIN_REQUIREMENT));
|
|
402
402
|
}
|
|
403
|
-
if (
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
403
|
+
if (marketIndex === undefined || marketIndex === numericConstants_1.QUOTE_SPOT_MARKET_INDEX) {
|
|
404
|
+
if (netQuoteValue.gt(numericConstants_1.ZERO)) {
|
|
405
|
+
totalAssetValue = totalAssetValue.add(netQuoteValue);
|
|
406
|
+
}
|
|
407
|
+
else {
|
|
408
|
+
totalLiabilityValue = totalLiabilityValue.add(netQuoteValue.abs());
|
|
409
|
+
}
|
|
408
410
|
}
|
|
409
411
|
return { totalAssetValue, totalLiabilityValue };
|
|
410
412
|
}
|
package/package.json
CHANGED
|
@@ -54,6 +54,16 @@ export const DevnetPerpMarkets: PerpMarketConfig[] = [
|
|
|
54
54
|
launchTs: 1675610186000,
|
|
55
55
|
oracleSource: OracleSource.PYTH,
|
|
56
56
|
},
|
|
57
|
+
{
|
|
58
|
+
fullName: 'Bonk',
|
|
59
|
+
category: ['Meme'],
|
|
60
|
+
symbol: 'BONK-PERP',
|
|
61
|
+
baseAssetSymbol: 'BONK',
|
|
62
|
+
marketIndex: 4,
|
|
63
|
+
oracle: new PublicKey('6bquU99ktV1VRiHDr8gMhDFt3kMfhCQo5nfNrg2Urvsn'),
|
|
64
|
+
launchTs: 1677068931000,
|
|
65
|
+
oracleSource: OracleSource.PYTH_1000,
|
|
66
|
+
},
|
|
57
67
|
];
|
|
58
68
|
|
|
59
69
|
export const MainnetPerpMarkets: PerpMarketConfig[] = [
|
package/src/dlob/DLOB.ts
CHANGED
|
@@ -6,7 +6,6 @@ import {
|
|
|
6
6
|
calculateBidPrice,
|
|
7
7
|
DriftClient,
|
|
8
8
|
convertToNumber,
|
|
9
|
-
isAuctionComplete,
|
|
10
9
|
isOrderExpired,
|
|
11
10
|
isOneOfVariant,
|
|
12
11
|
isVariant,
|
|
@@ -25,8 +24,6 @@ import {
|
|
|
25
24
|
UserMap,
|
|
26
25
|
OrderRecord,
|
|
27
26
|
OrderActionRecord,
|
|
28
|
-
ZERO,
|
|
29
|
-
BN_MAX,
|
|
30
27
|
isRestingLimitOrder,
|
|
31
28
|
isTakingOrder,
|
|
32
29
|
isFallbackAvailableLiquiditySource,
|
|
@@ -536,10 +533,7 @@ export class DLOB {
|
|
|
536
533
|
marketIndex,
|
|
537
534
|
slot,
|
|
538
535
|
marketType,
|
|
539
|
-
oraclePriceData
|
|
540
|
-
minAuctionDuration,
|
|
541
|
-
fallbackAsk,
|
|
542
|
-
fallbackBid
|
|
536
|
+
oraclePriceData
|
|
543
537
|
);
|
|
544
538
|
|
|
545
539
|
for (const crossingNode of crossingNodes) {
|
|
@@ -1295,10 +1289,7 @@ export class DLOB {
|
|
|
1295
1289
|
marketIndex: number,
|
|
1296
1290
|
slot: number,
|
|
1297
1291
|
marketType: MarketType,
|
|
1298
|
-
oraclePriceData: OraclePriceData
|
|
1299
|
-
minAuctionDuration: number,
|
|
1300
|
-
fallbackAsk: BN | undefined,
|
|
1301
|
-
fallbackBid: BN | undefined
|
|
1292
|
+
oraclePriceData: OraclePriceData
|
|
1302
1293
|
): NodeToFill[] {
|
|
1303
1294
|
const nodesToFill = new Array<NodeToFill>();
|
|
1304
1295
|
|
|
@@ -1308,18 +1299,20 @@ export class DLOB {
|
|
|
1308
1299
|
marketType,
|
|
1309
1300
|
oraclePriceData
|
|
1310
1301
|
)) {
|
|
1311
|
-
|
|
1302
|
+
const bidGenerator = this.getRestingLimitBids(
|
|
1312
1303
|
marketIndex,
|
|
1313
1304
|
slot,
|
|
1314
1305
|
marketType,
|
|
1315
1306
|
oraclePriceData
|
|
1316
|
-
)
|
|
1307
|
+
);
|
|
1308
|
+
|
|
1309
|
+
for (const bidNode of bidGenerator) {
|
|
1317
1310
|
const bidPrice = bidNode.getPrice(oraclePriceData, slot);
|
|
1318
1311
|
const askPrice = askNode.getPrice(oraclePriceData, slot);
|
|
1319
1312
|
|
|
1320
|
-
// orders don't cross
|
|
1313
|
+
// orders don't cross
|
|
1321
1314
|
if (bidPrice.lt(askPrice)) {
|
|
1322
|
-
|
|
1315
|
+
break;
|
|
1323
1316
|
}
|
|
1324
1317
|
|
|
1325
1318
|
const bidOrder = bidNode.order;
|
|
@@ -1327,44 +1320,19 @@ export class DLOB {
|
|
|
1327
1320
|
|
|
1328
1321
|
// Can't match orders from the same user
|
|
1329
1322
|
const sameUser = bidNode.userAccount.equals(askNode.userAccount);
|
|
1330
|
-
if (sameUser
|
|
1323
|
+
if (sameUser) {
|
|
1331
1324
|
continue;
|
|
1332
1325
|
}
|
|
1333
1326
|
|
|
1334
|
-
const
|
|
1335
|
-
askNode,
|
|
1336
|
-
bidNode
|
|
1337
|
-
);
|
|
1327
|
+
const makerAndTaker = this.determineMakerAndTaker(askNode, bidNode);
|
|
1338
1328
|
|
|
1339
|
-
//
|
|
1340
|
-
if (
|
|
1341
|
-
|
|
1342
|
-
takerNode.order,
|
|
1343
|
-
minAuctionDuration,
|
|
1344
|
-
slot
|
|
1345
|
-
)
|
|
1346
|
-
) {
|
|
1347
|
-
let bidPrice: BN;
|
|
1348
|
-
let askPrice: BN;
|
|
1349
|
-
if (isVariant(takerNode.order.direction, 'long')) {
|
|
1350
|
-
bidPrice = BN.min(
|
|
1351
|
-
takerNode.getPrice(oraclePriceData, slot),
|
|
1352
|
-
fallbackAsk || BN_MAX
|
|
1353
|
-
);
|
|
1354
|
-
askPrice = makerNode.getPrice(oraclePriceData, slot);
|
|
1355
|
-
} else {
|
|
1356
|
-
bidPrice = makerNode.getPrice(oraclePriceData, slot);
|
|
1357
|
-
askPrice = BN.max(
|
|
1358
|
-
takerNode.getPrice(oraclePriceData, slot),
|
|
1359
|
-
fallbackBid || ZERO
|
|
1360
|
-
);
|
|
1361
|
-
}
|
|
1362
|
-
|
|
1363
|
-
if (bidPrice.lt(askPrice)) {
|
|
1364
|
-
continue;
|
|
1365
|
-
}
|
|
1329
|
+
// unable to match maker and taker due to post only or slot
|
|
1330
|
+
if (!makerAndTaker) {
|
|
1331
|
+
continue;
|
|
1366
1332
|
}
|
|
1367
1333
|
|
|
1334
|
+
const { takerNode, makerNode } = makerAndTaker;
|
|
1335
|
+
|
|
1368
1336
|
const bidBaseRemaining = bidOrder.baseAssetAmount.sub(
|
|
1369
1337
|
bidOrder.baseAssetAmountFilled
|
|
1370
1338
|
);
|
|
@@ -1408,27 +1376,25 @@ export class DLOB {
|
|
|
1408
1376
|
determineMakerAndTaker(
|
|
1409
1377
|
askNode: DLOBNode,
|
|
1410
1378
|
bidNode: DLOBNode
|
|
1411
|
-
): { takerNode: DLOBNode; makerNode: DLOBNode } {
|
|
1412
|
-
|
|
1413
|
-
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
takerNode: bidNode,
|
|
1420
|
-
makerNode: askNode,
|
|
1421
|
-
};
|
|
1422
|
-
} else if (askNode.order.slot.lt(bidNode.order.slot)) {
|
|
1379
|
+
): { takerNode: DLOBNode; makerNode: DLOBNode } | undefined {
|
|
1380
|
+
const askSlot = askNode.order.slot.add(
|
|
1381
|
+
new BN(askNode.order.auctionDuration)
|
|
1382
|
+
);
|
|
1383
|
+
const bidSlot = bidNode.order.slot.add(
|
|
1384
|
+
new BN(bidNode.order.auctionDuration)
|
|
1385
|
+
);
|
|
1386
|
+
if (askSlot.lte(bidSlot) && !bidNode.order.postOnly) {
|
|
1423
1387
|
return {
|
|
1424
1388
|
takerNode: bidNode,
|
|
1425
1389
|
makerNode: askNode,
|
|
1426
1390
|
};
|
|
1427
|
-
} else {
|
|
1391
|
+
} else if (bidSlot.lte(askSlot) && !askNode.order.postOnly) {
|
|
1428
1392
|
return {
|
|
1429
1393
|
takerNode: askNode,
|
|
1430
1394
|
makerNode: bidNode,
|
|
1431
1395
|
};
|
|
1396
|
+
} else {
|
|
1397
|
+
return undefined;
|
|
1432
1398
|
}
|
|
1433
1399
|
}
|
|
1434
1400
|
|
package/src/driftClient.ts
CHANGED
|
@@ -3695,7 +3695,7 @@ export class DriftClient {
|
|
|
3695
3695
|
writableSpotMarketIndexes: [QUOTE_SPOT_MARKET_INDEX],
|
|
3696
3696
|
});
|
|
3697
3697
|
|
|
3698
|
-
const spotMarket = this.
|
|
3698
|
+
const spotMarket = this.getQuoteSpotMarketAccount();
|
|
3699
3699
|
|
|
3700
3700
|
return await this.program.instruction.resolvePerpBankruptcy(
|
|
3701
3701
|
QUOTE_SPOT_MARKET_INDEX,
|
|
@@ -4,6 +4,7 @@ import { OracleClient } from '../oracles/types';
|
|
|
4
4
|
import { PythClient } from '../oracles/pythClient';
|
|
5
5
|
// import { SwitchboardClient } from '../oracles/switchboardClient';
|
|
6
6
|
import { QuoteAssetOracleClient } from '../oracles/quoteAssetOracleClient';
|
|
7
|
+
import { BN } from '@project-serum/anchor';
|
|
7
8
|
|
|
8
9
|
export function getOracleClient(
|
|
9
10
|
oracleSource: OracleSource,
|
|
@@ -13,6 +14,10 @@ export function getOracleClient(
|
|
|
13
14
|
return new PythClient(connection);
|
|
14
15
|
}
|
|
15
16
|
|
|
17
|
+
if (isVariant(oracleSource, 'pyth1000')) {
|
|
18
|
+
return new PythClient(connection, new BN(1000));
|
|
19
|
+
}
|
|
20
|
+
|
|
16
21
|
// if (isVariant(oracleSource, 'switchboard')) {
|
|
17
22
|
// return new SwitchboardClient(connection);
|
|
18
23
|
// }
|
package/src/idl/drift.json
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"version": "2.18.0-beta.
|
|
2
|
+
"version": "2.18.0-beta.2",
|
|
3
3
|
"name": "drift",
|
|
4
4
|
"instructions": [
|
|
5
5
|
{
|
|
@@ -6237,6 +6237,9 @@
|
|
|
6237
6237
|
{
|
|
6238
6238
|
"name": "Pyth"
|
|
6239
6239
|
},
|
|
6240
|
+
{
|
|
6241
|
+
"name": "Pyth1000"
|
|
6242
|
+
},
|
|
6240
6243
|
{
|
|
6241
6244
|
"name": "Switchboard"
|
|
6242
6245
|
},
|
package/src/math/trade.ts
CHANGED
|
@@ -52,6 +52,9 @@ export type PriceImpactUnit =
|
|
|
52
52
|
|
|
53
53
|
/**
|
|
54
54
|
* Calculates avg/max slippage (price impact) for candidate trade
|
|
55
|
+
*
|
|
56
|
+
* @deprecated use calculateEstimatedPerpEntryPrice instead
|
|
57
|
+
*
|
|
55
58
|
* @param direction
|
|
56
59
|
* @param amount
|
|
57
60
|
* @param market
|
|
@@ -200,6 +203,9 @@ export function calculateTradeAcquiredAmounts(
|
|
|
200
203
|
/**
|
|
201
204
|
* calculateTargetPriceTrade
|
|
202
205
|
* simple function for finding arbitraging trades
|
|
206
|
+
*
|
|
207
|
+
* @deprecated
|
|
208
|
+
*
|
|
203
209
|
* @param market
|
|
204
210
|
* @param targetPrice
|
|
205
211
|
* @param pct optional default is 100% gap filling, can set smaller.
|
|
@@ -2,13 +2,15 @@ import { parsePriceData } from '@pythnetwork/client';
|
|
|
2
2
|
import { Connection, PublicKey } from '@solana/web3.js';
|
|
3
3
|
import { OracleClient, OraclePriceData } from './types';
|
|
4
4
|
import { BN } from '@project-serum/anchor';
|
|
5
|
-
import { PRICE_PRECISION, TEN } from '../constants/numericConstants';
|
|
5
|
+
import { ONE, PRICE_PRECISION, TEN } from '../constants/numericConstants';
|
|
6
6
|
|
|
7
7
|
export class PythClient implements OracleClient {
|
|
8
8
|
private connection: Connection;
|
|
9
|
+
private multiple: BN;
|
|
9
10
|
|
|
10
|
-
public constructor(connection: Connection) {
|
|
11
|
+
public constructor(connection: Connection, multiple = ONE) {
|
|
11
12
|
this.connection = connection;
|
|
13
|
+
this.multiple = multiple;
|
|
12
14
|
}
|
|
13
15
|
|
|
14
16
|
public async getOraclePriceData(
|
|
@@ -21,22 +23,39 @@ export class PythClient implements OracleClient {
|
|
|
21
23
|
public getOraclePriceDataFromBuffer(buffer: Buffer): OraclePriceData {
|
|
22
24
|
const priceData = parsePriceData(buffer);
|
|
23
25
|
return {
|
|
24
|
-
price: convertPythPrice(
|
|
26
|
+
price: convertPythPrice(
|
|
27
|
+
priceData.aggregate.price,
|
|
28
|
+
priceData.exponent,
|
|
29
|
+
this.multiple
|
|
30
|
+
),
|
|
25
31
|
slot: new BN(priceData.lastSlot.toString()),
|
|
26
|
-
confidence: convertPythPrice(
|
|
27
|
-
|
|
32
|
+
confidence: convertPythPrice(
|
|
33
|
+
priceData.confidence,
|
|
34
|
+
priceData.exponent,
|
|
35
|
+
this.multiple
|
|
36
|
+
),
|
|
37
|
+
twap: convertPythPrice(
|
|
38
|
+
priceData.twap.value,
|
|
39
|
+
priceData.exponent,
|
|
40
|
+
this.multiple
|
|
41
|
+
),
|
|
28
42
|
twapConfidence: convertPythPrice(
|
|
29
43
|
priceData.twac.value,
|
|
30
|
-
priceData.exponent
|
|
44
|
+
priceData.exponent,
|
|
45
|
+
this.multiple
|
|
31
46
|
),
|
|
32
47
|
hasSufficientNumberOfDataPoints: true,
|
|
33
48
|
};
|
|
34
49
|
}
|
|
35
50
|
}
|
|
36
51
|
|
|
37
|
-
export function convertPythPrice(
|
|
52
|
+
export function convertPythPrice(
|
|
53
|
+
price: number,
|
|
54
|
+
exponent: number,
|
|
55
|
+
multiple: BN
|
|
56
|
+
): BN {
|
|
38
57
|
exponent = Math.abs(exponent);
|
|
39
|
-
const pythPrecision = TEN.pow(new BN(exponent).abs());
|
|
58
|
+
const pythPrecision = TEN.pow(new BN(exponent).abs()).div(multiple);
|
|
40
59
|
return new BN(price * Math.pow(10, exponent))
|
|
41
60
|
.mul(PRICE_PRECISION)
|
|
42
61
|
.div(pythPrecision);
|
package/src/types.ts
CHANGED
|
@@ -76,6 +76,7 @@ export class DepositDirection {
|
|
|
76
76
|
|
|
77
77
|
export class OracleSource {
|
|
78
78
|
static readonly PYTH = { pyth: {} };
|
|
79
|
+
static readonly PYTH_1000 = { pyth1000: {} };
|
|
79
80
|
// static readonly SWITCHBOARD = { switchboard: {} };
|
|
80
81
|
static readonly QUOTE_ASSET = { quoteAsset: {} };
|
|
81
82
|
}
|
package/src/user.ts
CHANGED
|
@@ -697,10 +697,12 @@ export class User {
|
|
|
697
697
|
);
|
|
698
698
|
}
|
|
699
699
|
|
|
700
|
-
if (
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
700
|
+
if (marketIndex === undefined || marketIndex === QUOTE_SPOT_MARKET_INDEX) {
|
|
701
|
+
if (netQuoteValue.gt(ZERO)) {
|
|
702
|
+
totalAssetValue = totalAssetValue.add(netQuoteValue);
|
|
703
|
+
} else {
|
|
704
|
+
totalLiabilityValue = totalLiabilityValue.add(netQuoteValue.abs());
|
|
705
|
+
}
|
|
704
706
|
}
|
|
705
707
|
|
|
706
708
|
return { totalAssetValue, totalLiabilityValue };
|
package/tests/dlob/test.ts
CHANGED
|
@@ -3435,7 +3435,7 @@ describe('DLOB Perp Tests', () => {
|
|
|
3435
3435
|
PositionDirection.LONG,
|
|
3436
3436
|
vBid,
|
|
3437
3437
|
vAsk,
|
|
3438
|
-
new BN(slot
|
|
3438
|
+
new BN(slot + 1), // later order becomes taker
|
|
3439
3439
|
new BN(200),
|
|
3440
3440
|
undefined,
|
|
3441
3441
|
undefined,
|
|
@@ -5109,7 +5109,8 @@ describe('DLOB Spot Tests', () => {
|
|
|
5109
5109
|
BASE_PRECISION, // quantity
|
|
5110
5110
|
PositionDirection.SHORT,
|
|
5111
5111
|
vBid,
|
|
5112
|
-
vAsk
|
|
5112
|
+
vAsk,
|
|
5113
|
+
new BN(1)
|
|
5113
5114
|
);
|
|
5114
5115
|
insertOrderToDLOB(
|
|
5115
5116
|
dlob,
|
|
@@ -5122,7 +5123,8 @@ describe('DLOB Spot Tests', () => {
|
|
|
5122
5123
|
BASE_PRECISION, // quantity
|
|
5123
5124
|
PositionDirection.SHORT,
|
|
5124
5125
|
vBid,
|
|
5125
|
-
vAsk
|
|
5126
|
+
vAsk,
|
|
5127
|
+
new BN(1)
|
|
5126
5128
|
);
|
|
5127
5129
|
|
|
5128
5130
|
// should have no crossing orders
|
|
@@ -5152,7 +5154,7 @@ describe('DLOB Spot Tests', () => {
|
|
|
5152
5154
|
PositionDirection.LONG,
|
|
5153
5155
|
vBid,
|
|
5154
5156
|
vAsk,
|
|
5155
|
-
|
|
5157
|
+
new BN(0),
|
|
5156
5158
|
undefined,
|
|
5157
5159
|
undefined,
|
|
5158
5160
|
true
|
|
@@ -5169,7 +5171,7 @@ describe('DLOB Spot Tests', () => {
|
|
|
5169
5171
|
PositionDirection.LONG,
|
|
5170
5172
|
vBid,
|
|
5171
5173
|
vAsk,
|
|
5172
|
-
|
|
5174
|
+
new BN(0),
|
|
5173
5175
|
undefined,
|
|
5174
5176
|
undefined,
|
|
5175
5177
|
true
|
|
@@ -5205,6 +5207,186 @@ describe('DLOB Spot Tests', () => {
|
|
|
5205
5207
|
expect(nodesToFillAfter[1].makerNode?.order?.orderId).to.equal(3);
|
|
5206
5208
|
});
|
|
5207
5209
|
|
|
5210
|
+
it('Test limit orders skipping more recent post onlys', () => {
|
|
5211
|
+
const vAsk = new BN(15);
|
|
5212
|
+
const vBid = new BN(8);
|
|
5213
|
+
|
|
5214
|
+
const user0 = Keypair.generate();
|
|
5215
|
+
const user1 = Keypair.generate();
|
|
5216
|
+
|
|
5217
|
+
const dlob = new DLOB();
|
|
5218
|
+
const marketIndex = 0;
|
|
5219
|
+
|
|
5220
|
+
const slot = 12;
|
|
5221
|
+
const oracle = {
|
|
5222
|
+
price: vBid.add(vAsk).div(new BN(2)),
|
|
5223
|
+
slot: new BN(slot),
|
|
5224
|
+
confidence: new BN(1),
|
|
5225
|
+
hasSufficientNumberOfDataPoints: true,
|
|
5226
|
+
};
|
|
5227
|
+
|
|
5228
|
+
// insert some limit sells below vAMM ask, above bid
|
|
5229
|
+
insertOrderToDLOB(
|
|
5230
|
+
dlob,
|
|
5231
|
+
user0.publicKey,
|
|
5232
|
+
OrderType.LIMIT,
|
|
5233
|
+
MarketType.PERP,
|
|
5234
|
+
1, // orderId
|
|
5235
|
+
marketIndex,
|
|
5236
|
+
new BN(14), // price
|
|
5237
|
+
BASE_PRECISION, // quantity
|
|
5238
|
+
PositionDirection.SHORT,
|
|
5239
|
+
vBid,
|
|
5240
|
+
vAsk,
|
|
5241
|
+
new BN(1)
|
|
5242
|
+
);
|
|
5243
|
+
insertOrderToDLOB(
|
|
5244
|
+
dlob,
|
|
5245
|
+
user1.publicKey,
|
|
5246
|
+
OrderType.LIMIT,
|
|
5247
|
+
MarketType.PERP,
|
|
5248
|
+
2, // orderId
|
|
5249
|
+
marketIndex,
|
|
5250
|
+
new BN(13), // price
|
|
5251
|
+
BASE_PRECISION, // quantity
|
|
5252
|
+
PositionDirection.SHORT,
|
|
5253
|
+
vBid,
|
|
5254
|
+
vAsk,
|
|
5255
|
+
new BN(1)
|
|
5256
|
+
);
|
|
5257
|
+
|
|
5258
|
+
// should have no crossing orders
|
|
5259
|
+
const nodesToFillBefore = dlob.findNodesToFill(
|
|
5260
|
+
marketIndex,
|
|
5261
|
+
undefined,
|
|
5262
|
+
undefined,
|
|
5263
|
+
12, // auction over
|
|
5264
|
+
Date.now(),
|
|
5265
|
+
MarketType.PERP,
|
|
5266
|
+
oracle,
|
|
5267
|
+
mockStateAccount,
|
|
5268
|
+
mockPerpMarkets[marketIndex]
|
|
5269
|
+
);
|
|
5270
|
+
expect(nodesToFillBefore.length).to.equal(0);
|
|
5271
|
+
|
|
5272
|
+
// add post only orders that are newer than resting limit orders and thus cant match
|
|
5273
|
+
insertOrderToDLOB(
|
|
5274
|
+
dlob,
|
|
5275
|
+
user1.publicKey,
|
|
5276
|
+
OrderType.LIMIT,
|
|
5277
|
+
MarketType.PERP,
|
|
5278
|
+
3, // orderId
|
|
5279
|
+
marketIndex,
|
|
5280
|
+
new BN(15), // price
|
|
5281
|
+
BASE_PRECISION, // quantity
|
|
5282
|
+
PositionDirection.LONG,
|
|
5283
|
+
vBid,
|
|
5284
|
+
vAsk,
|
|
5285
|
+
new BN(2),
|
|
5286
|
+
undefined,
|
|
5287
|
+
undefined,
|
|
5288
|
+
true
|
|
5289
|
+
);
|
|
5290
|
+
insertOrderToDLOB(
|
|
5291
|
+
dlob,
|
|
5292
|
+
user0.publicKey,
|
|
5293
|
+
OrderType.LIMIT,
|
|
5294
|
+
MarketType.PERP,
|
|
5295
|
+
4, // orderId
|
|
5296
|
+
marketIndex,
|
|
5297
|
+
new BN(14), // price
|
|
5298
|
+
BASE_PRECISION, // quantity
|
|
5299
|
+
PositionDirection.LONG,
|
|
5300
|
+
vBid,
|
|
5301
|
+
vAsk,
|
|
5302
|
+
new BN(2),
|
|
5303
|
+
undefined,
|
|
5304
|
+
undefined,
|
|
5305
|
+
true
|
|
5306
|
+
);
|
|
5307
|
+
|
|
5308
|
+
let nodesToFillAfter = dlob.findNodesToFill(
|
|
5309
|
+
marketIndex,
|
|
5310
|
+
undefined,
|
|
5311
|
+
undefined,
|
|
5312
|
+
slot, // auction over
|
|
5313
|
+
Date.now(),
|
|
5314
|
+
MarketType.PERP,
|
|
5315
|
+
oracle,
|
|
5316
|
+
mockStateAccount,
|
|
5317
|
+
mockPerpMarkets[marketIndex]
|
|
5318
|
+
);
|
|
5319
|
+
|
|
5320
|
+
expect(nodesToFillAfter.length).to.equal(0);
|
|
5321
|
+
|
|
5322
|
+
// add post only orders that are older than resting limit orders
|
|
5323
|
+
insertOrderToDLOB(
|
|
5324
|
+
dlob,
|
|
5325
|
+
user1.publicKey,
|
|
5326
|
+
OrderType.LIMIT,
|
|
5327
|
+
MarketType.PERP,
|
|
5328
|
+
5, // orderId
|
|
5329
|
+
marketIndex,
|
|
5330
|
+
new BN(15), // price
|
|
5331
|
+
BASE_PRECISION, // quantity
|
|
5332
|
+
PositionDirection.LONG,
|
|
5333
|
+
vBid,
|
|
5334
|
+
vAsk,
|
|
5335
|
+
new BN(0),
|
|
5336
|
+
undefined,
|
|
5337
|
+
undefined,
|
|
5338
|
+
true
|
|
5339
|
+
);
|
|
5340
|
+
insertOrderToDLOB(
|
|
5341
|
+
dlob,
|
|
5342
|
+
user0.publicKey,
|
|
5343
|
+
OrderType.LIMIT,
|
|
5344
|
+
MarketType.PERP,
|
|
5345
|
+
6, // orderId
|
|
5346
|
+
marketIndex,
|
|
5347
|
+
new BN(14), // price
|
|
5348
|
+
BASE_PRECISION, // quantity
|
|
5349
|
+
PositionDirection.LONG,
|
|
5350
|
+
vBid,
|
|
5351
|
+
vAsk,
|
|
5352
|
+
new BN(0),
|
|
5353
|
+
undefined,
|
|
5354
|
+
undefined,
|
|
5355
|
+
true
|
|
5356
|
+
);
|
|
5357
|
+
|
|
5358
|
+
nodesToFillAfter = dlob.findNodesToFill(
|
|
5359
|
+
marketIndex,
|
|
5360
|
+
undefined,
|
|
5361
|
+
undefined,
|
|
5362
|
+
slot, // auction over
|
|
5363
|
+
Date.now(),
|
|
5364
|
+
MarketType.PERP,
|
|
5365
|
+
oracle,
|
|
5366
|
+
mockStateAccount,
|
|
5367
|
+
mockPerpMarkets[marketIndex]
|
|
5368
|
+
);
|
|
5369
|
+
|
|
5370
|
+
expect(nodesToFillAfter.length).to.equal(2);
|
|
5371
|
+
|
|
5372
|
+
printBookState(dlob, marketIndex, vBid, vAsk, slot, oracle);
|
|
5373
|
+
|
|
5374
|
+
for (const n of nodesToFillAfter) {
|
|
5375
|
+
console.log(
|
|
5376
|
+
`cross found: taker orderId: ${n.node.order?.orderId.toString()}: BAA: ${n.node.order?.baseAssetAmountFilled.toString()}/${n.node.order?.baseAssetAmount.toString()}, maker orderId: ${n.makerNode?.order?.orderId.toString()}: BAA: ${n.makerNode?.order?.baseAssetAmountFilled.toString()}/${n.makerNode?.order?.baseAssetAmount.toString()}`
|
|
5377
|
+
);
|
|
5378
|
+
}
|
|
5379
|
+
expect(nodesToFillAfter.length).to.equal(2);
|
|
5380
|
+
|
|
5381
|
+
// taker should fill completely with best maker
|
|
5382
|
+
expect(nodesToFillAfter[0].node.order?.orderId).to.equal(2);
|
|
5383
|
+
expect(nodesToFillAfter[0].makerNode?.order?.orderId).to.equal(6);
|
|
5384
|
+
|
|
5385
|
+
// taker should fill completely with second best maker
|
|
5386
|
+
expect(nodesToFillAfter[1].node.order?.orderId).to.equal(1);
|
|
5387
|
+
expect(nodesToFillAfter[1].makerNode?.order?.orderId).to.equal(5);
|
|
5388
|
+
});
|
|
5389
|
+
|
|
5208
5390
|
it('Test trigger orders', () => {
|
|
5209
5391
|
const vAsk = new BN(15);
|
|
5210
5392
|
const vBid = new BN(8);
|