@drift-labs/sdk 2.18.0 → 2.19.0
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 +13 -3
- package/lib/dlob/DLOB.js +19 -6
- package/lib/dlob/NodeList.d.ts +1 -1
- package/lib/dlob/NodeList.js +2 -2
- package/lib/factory/oracleClient.js +4 -1
- package/lib/idl/drift.json +7 -4
- package/lib/math/amm.js +10 -15
- package/lib/math/trade.js +1 -1
- package/lib/serum/serumSubscriber.d.ts +4 -3
- package/lib/serum/serumSubscriber.js +40 -11
- package/lib/serum/types.d.ts +2 -0
- package/lib/types.d.ts +5 -2
- package/lib/types.js +2 -1
- package/package.json +1 -1
- package/src/constants/perpMarkets.ts +13 -3
- package/src/dlob/DLOB.ts +17 -5
- package/src/dlob/NodeList.ts +2 -5
- package/src/factory/oracleClient.ts +5 -1
- package/src/idl/drift.json +7 -4
- package/src/math/amm.ts +22 -23
- package/src/math/trade.ts +1 -1
- package/src/serum/serumSubscriber.ts +62 -20
- package/src/serum/types.ts +9 -5
- package/src/types.ts +2 -1
- package/tests/amm/test.ts +177 -5
- package/tests/dlob/test.ts +2 -1
|
@@ -47,12 +47,12 @@ exports.DevnetPerpMarkets = [
|
|
|
47
47
|
{
|
|
48
48
|
fullName: 'Bonk',
|
|
49
49
|
category: ['Meme'],
|
|
50
|
-
symbol: '
|
|
51
|
-
baseAssetSymbol: '
|
|
50
|
+
symbol: '1MBONK-PERP',
|
|
51
|
+
baseAssetSymbol: '1MBONK',
|
|
52
52
|
marketIndex: 4,
|
|
53
53
|
oracle: new web3_js_1.PublicKey('6bquU99ktV1VRiHDr8gMhDFt3kMfhCQo5nfNrg2Urvsn'),
|
|
54
54
|
launchTs: 1677068931000,
|
|
55
|
-
oracleSource: __1.OracleSource.
|
|
55
|
+
oracleSource: __1.OracleSource.PYTH_1M,
|
|
56
56
|
},
|
|
57
57
|
];
|
|
58
58
|
exports.MainnetPerpMarkets = [
|
|
@@ -96,6 +96,16 @@ exports.MainnetPerpMarkets = [
|
|
|
96
96
|
launchTs: 1675802661000,
|
|
97
97
|
oracleSource: __1.OracleSource.PYTH,
|
|
98
98
|
},
|
|
99
|
+
{
|
|
100
|
+
fullName: 'Bonk',
|
|
101
|
+
category: ['Meme'],
|
|
102
|
+
symbol: '1MBONK-PERP',
|
|
103
|
+
baseAssetSymbol: '1MBONK',
|
|
104
|
+
marketIndex: 4,
|
|
105
|
+
oracle: new web3_js_1.PublicKey('8ihFLu5FimgTQ1Unh4dVyEHUGodJ5gJQCrQf4KUVB9bN'),
|
|
106
|
+
launchTs: 1677690149000,
|
|
107
|
+
oracleSource: __1.OracleSource.PYTH_1M,
|
|
108
|
+
},
|
|
99
109
|
];
|
|
100
110
|
exports.PerpMarkets = {
|
|
101
111
|
devnet: exports.DevnetPerpMarkets,
|
package/lib/dlob/DLOB.js
CHANGED
|
@@ -286,8 +286,9 @@ class DLOB {
|
|
|
286
286
|
}
|
|
287
287
|
}
|
|
288
288
|
getOrder(orderId, userAccount) {
|
|
289
|
+
const orderSignature = NodeList_1.getOrderSignature(orderId, userAccount);
|
|
289
290
|
for (const nodeList of this.getNodeLists()) {
|
|
290
|
-
const node = nodeList.get(
|
|
291
|
+
const node = nodeList.get(orderSignature);
|
|
291
292
|
if (node) {
|
|
292
293
|
return node.order;
|
|
293
294
|
}
|
|
@@ -761,20 +762,32 @@ class DLOB {
|
|
|
761
762
|
determineMakerAndTaker(askNode, bidNode) {
|
|
762
763
|
const askSlot = askNode.order.slot.add(new __1.BN(askNode.order.auctionDuration));
|
|
763
764
|
const bidSlot = bidNode.order.slot.add(new __1.BN(bidNode.order.auctionDuration));
|
|
764
|
-
if (
|
|
765
|
+
if (bidNode.order.postOnly && askNode.order.postOnly) {
|
|
766
|
+
return undefined;
|
|
767
|
+
}
|
|
768
|
+
else if (bidNode.order.postOnly) {
|
|
769
|
+
return {
|
|
770
|
+
takerNode: askNode,
|
|
771
|
+
makerNode: bidNode,
|
|
772
|
+
};
|
|
773
|
+
}
|
|
774
|
+
else if (askNode.order.postOnly) {
|
|
765
775
|
return {
|
|
766
776
|
takerNode: bidNode,
|
|
767
777
|
makerNode: askNode,
|
|
768
778
|
};
|
|
769
779
|
}
|
|
770
|
-
else if (
|
|
780
|
+
else if (askSlot.lte(bidSlot)) {
|
|
771
781
|
return {
|
|
772
|
-
takerNode:
|
|
773
|
-
makerNode:
|
|
782
|
+
takerNode: bidNode,
|
|
783
|
+
makerNode: askNode,
|
|
774
784
|
};
|
|
775
785
|
}
|
|
776
786
|
else {
|
|
777
|
-
return
|
|
787
|
+
return {
|
|
788
|
+
takerNode: askNode,
|
|
789
|
+
makerNode: bidNode,
|
|
790
|
+
};
|
|
778
791
|
}
|
|
779
792
|
}
|
|
780
793
|
getBestAsk(marketIndex, fallbackAsk, slot, marketType, oraclePriceData) {
|
package/lib/dlob/NodeList.d.ts
CHANGED
|
@@ -21,7 +21,7 @@ export declare class NodeList<NodeType extends keyof DLOBNodeMap> implements DLO
|
|
|
21
21
|
remove(order: Order, userAccount: PublicKey): void;
|
|
22
22
|
getGenerator(): Generator<DLOBNode>;
|
|
23
23
|
has(order: Order, userAccount: PublicKey): boolean;
|
|
24
|
-
get(
|
|
24
|
+
get(orderSignature: string): DLOBNodeMap[NodeType] | undefined;
|
|
25
25
|
print(): void;
|
|
26
26
|
printTop(): void;
|
|
27
27
|
}
|
package/lib/dlob/NodeList.js
CHANGED
|
@@ -104,8 +104,8 @@ class NodeList {
|
|
|
104
104
|
has(order, userAccount) {
|
|
105
105
|
return this.nodeMap.has(getOrderSignature(order.orderId, userAccount));
|
|
106
106
|
}
|
|
107
|
-
get(
|
|
108
|
-
return this.nodeMap.get(
|
|
107
|
+
get(orderSignature) {
|
|
108
|
+
return this.nodeMap.get(orderSignature);
|
|
109
109
|
}
|
|
110
110
|
print() {
|
|
111
111
|
let currentNode = this.head;
|
|
@@ -10,9 +10,12 @@ function getOracleClient(oracleSource, connection) {
|
|
|
10
10
|
if (types_1.isVariant(oracleSource, 'pyth')) {
|
|
11
11
|
return new pythClient_1.PythClient(connection);
|
|
12
12
|
}
|
|
13
|
-
if (types_1.isVariant(oracleSource, '
|
|
13
|
+
if (types_1.isVariant(oracleSource, 'pyth1K')) {
|
|
14
14
|
return new pythClient_1.PythClient(connection, new anchor_1.BN(1000));
|
|
15
15
|
}
|
|
16
|
+
if (types_1.isVariant(oracleSource, 'pyth1M')) {
|
|
17
|
+
return new pythClient_1.PythClient(connection, new anchor_1.BN(1000000));
|
|
18
|
+
}
|
|
16
19
|
// if (isVariant(oracleSource, 'switchboard')) {
|
|
17
20
|
// return new SwitchboardClient(connection);
|
|
18
21
|
// }
|
package/lib/idl/drift.json
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"version": "2.
|
|
2
|
+
"version": "2.19.0",
|
|
3
3
|
"name": "drift",
|
|
4
4
|
"instructions": [
|
|
5
5
|
{
|
|
@@ -6237,14 +6237,17 @@
|
|
|
6237
6237
|
{
|
|
6238
6238
|
"name": "Pyth"
|
|
6239
6239
|
},
|
|
6240
|
-
{
|
|
6241
|
-
"name": "Pyth1000"
|
|
6242
|
-
},
|
|
6243
6240
|
{
|
|
6244
6241
|
"name": "Switchboard"
|
|
6245
6242
|
},
|
|
6246
6243
|
{
|
|
6247
6244
|
"name": "QuoteAsset"
|
|
6245
|
+
},
|
|
6246
|
+
{
|
|
6247
|
+
"name": "Pyth1K"
|
|
6248
|
+
},
|
|
6249
|
+
{
|
|
6250
|
+
"name": "Pyth1M"
|
|
6248
6251
|
}
|
|
6249
6252
|
]
|
|
6250
6253
|
}
|
package/lib/math/amm.js
CHANGED
|
@@ -203,26 +203,21 @@ function calculateMarketOpenBidAsk(baseAssetReserve, minBaseAssetReserve, maxBas
|
|
|
203
203
|
exports.calculateMarketOpenBidAsk = calculateMarketOpenBidAsk;
|
|
204
204
|
function calculateInventoryScale(baseAssetAmountWithAmm, baseAssetReserve, minBaseAssetReserve, maxBaseAssetReserve, directionalSpread, maxSpread) {
|
|
205
205
|
if (baseAssetAmountWithAmm.eq(numericConstants_1.ZERO)) {
|
|
206
|
-
return
|
|
206
|
+
return 1;
|
|
207
207
|
}
|
|
208
|
-
const
|
|
208
|
+
const MAX_BID_ASK_INVENTORY_SKEW_FACTOR = numericConstants_1.BID_ASK_SPREAD_PRECISION.mul(new anchor_1.BN(10));
|
|
209
209
|
// inventory skew
|
|
210
210
|
const [openBids, openAsks] = calculateMarketOpenBidAsk(baseAssetReserve, minBaseAssetReserve, maxBaseAssetReserve);
|
|
211
|
-
const minSideLiquidity = anchor_1.BN.
|
|
212
|
-
const
|
|
211
|
+
const minSideLiquidity = anchor_1.BN.min(openBids.abs(), openAsks.abs());
|
|
212
|
+
const inventoryScaleBN = anchor_1.BN.min(baseAssetAmountWithAmm
|
|
213
|
+
.mul(numericConstants_1.PERCENTAGE_PRECISION)
|
|
214
|
+
.div(anchor_1.BN.max(minSideLiquidity, numericConstants_1.ONE))
|
|
215
|
+
.abs(), numericConstants_1.PERCENTAGE_PRECISION);
|
|
216
|
+
const inventoryScaleMaxBN = anchor_1.BN.max(MAX_BID_ASK_INVENTORY_SKEW_FACTOR, new anchor_1.BN(maxSpread)
|
|
213
217
|
.mul(numericConstants_1.BID_ASK_SPREAD_PRECISION)
|
|
214
218
|
.div(new anchor_1.BN(Math.max(directionalSpread, 1))));
|
|
215
|
-
const
|
|
216
|
-
|
|
217
|
-
.div(numericConstants_1.BASE_PRECISION)
|
|
218
|
-
.mul(defaultLargeBidAskFactor)
|
|
219
|
-
.div(minSideLiquidity)
|
|
220
|
-
.abs();
|
|
221
|
-
const inventoryScale = anchor_1.BN.min(inventoryScaleMaxBN, inventoryScaleBN).toNumber() /
|
|
222
|
-
numericConstants_1.BID_ASK_SPREAD_PRECISION.toNumber();
|
|
223
|
-
const inventoryScaleMax = inventoryScaleMaxBN.toNumber() / numericConstants_1.BID_ASK_SPREAD_PRECISION.toNumber();
|
|
224
|
-
const inventorySpreadScale = Math.min(inventoryScaleMax, 1 + inventoryScale);
|
|
225
|
-
return inventorySpreadScale;
|
|
219
|
+
const inventoryScaleCapped = anchor_1.BN.min(inventoryScaleMaxBN, numericConstants_1.BID_ASK_SPREAD_PRECISION.add(inventoryScaleMaxBN.mul(inventoryScaleBN).div(numericConstants_1.PERCENTAGE_PRECISION))).toNumber() / numericConstants_1.BID_ASK_SPREAD_PRECISION.toNumber();
|
|
220
|
+
return inventoryScaleCapped;
|
|
226
221
|
}
|
|
227
222
|
exports.calculateInventoryScale = calculateInventoryScale;
|
|
228
223
|
function calculateEffectiveLeverage(baseSpread, quoteAssetReserve, terminalQuoteAssetReserve, pegMultiplier, netBaseAssetAmount, reservePrice, totalFeeMinusDistributions) {
|
package/lib/math/trade.js
CHANGED
|
@@ -499,7 +499,7 @@ function calculateEstimatedSpotEntryPrice(assetType, amount, direction, market,
|
|
|
499
499
|
.div(basePrecision);
|
|
500
500
|
cumulativeBaseFilled = cumulativeBaseFilled.add(baseFilled);
|
|
501
501
|
cumulativeQuoteFilled = cumulativeQuoteFilled.add(quoteFilled);
|
|
502
|
-
worstPrice =
|
|
502
|
+
worstPrice = dlobLimitOrderPrice;
|
|
503
503
|
dlobLimitOrder = dlobLimitOrders.next().value;
|
|
504
504
|
}
|
|
505
505
|
else {
|
|
@@ -8,16 +8,17 @@ export declare class SerumSubscriber {
|
|
|
8
8
|
connection: Connection;
|
|
9
9
|
programId: PublicKey;
|
|
10
10
|
marketAddress: PublicKey;
|
|
11
|
-
|
|
11
|
+
subscriptionType: 'polling' | 'websocket';
|
|
12
|
+
accountLoader: BulkAccountLoader | undefined;
|
|
12
13
|
market: Market;
|
|
13
14
|
subscribed: boolean;
|
|
14
15
|
asksAddress: PublicKey;
|
|
15
16
|
asks: Orderbook;
|
|
16
|
-
asksCallbackId: string;
|
|
17
|
+
asksCallbackId: string | number;
|
|
17
18
|
lastAsksSlot: number;
|
|
18
19
|
bidsAddress: PublicKey;
|
|
19
20
|
bids: Orderbook;
|
|
20
|
-
bidsCallbackId: string;
|
|
21
|
+
bidsCallbackId: string | number;
|
|
21
22
|
lastBidsSlot: number;
|
|
22
23
|
constructor(config: SerumMarketSubscriberConfig);
|
|
23
24
|
subscribe(): Promise<void>;
|
|
@@ -9,7 +9,13 @@ class SerumSubscriber {
|
|
|
9
9
|
this.connection = config.connection;
|
|
10
10
|
this.programId = config.programId;
|
|
11
11
|
this.marketAddress = config.marketAddress;
|
|
12
|
-
|
|
12
|
+
if (config.accountSubscription.type === 'polling') {
|
|
13
|
+
this.subscriptionType = 'polling';
|
|
14
|
+
this.accountLoader = config.accountSubscription.accountLoader;
|
|
15
|
+
}
|
|
16
|
+
else {
|
|
17
|
+
this.subscriptionType = 'websocket';
|
|
18
|
+
}
|
|
13
19
|
}
|
|
14
20
|
async subscribe() {
|
|
15
21
|
if (this.subscribed) {
|
|
@@ -18,16 +24,32 @@ class SerumSubscriber {
|
|
|
18
24
|
this.market = await serum_1.Market.load(this.connection, this.marketAddress, undefined, this.programId);
|
|
19
25
|
this.asksAddress = this.market.asksAddress;
|
|
20
26
|
this.asks = await this.market.loadAsks(this.connection);
|
|
21
|
-
|
|
22
|
-
this.
|
|
23
|
-
|
|
24
|
-
|
|
27
|
+
if (this.subscriptionType === 'websocket') {
|
|
28
|
+
this.asksCallbackId = this.connection.onAccountChange(this.asksAddress, (accountInfo, ctx) => {
|
|
29
|
+
this.lastAsksSlot = ctx.slot;
|
|
30
|
+
this.asks = serum_1.Orderbook.decode(this.market, accountInfo.data);
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
else {
|
|
34
|
+
this.asksCallbackId = await this.accountLoader.addAccount(this.asksAddress, (buffer, slot) => {
|
|
35
|
+
this.lastAsksSlot = slot;
|
|
36
|
+
this.asks = serum_1.Orderbook.decode(this.market, buffer);
|
|
37
|
+
});
|
|
38
|
+
}
|
|
25
39
|
this.bidsAddress = this.market.bidsAddress;
|
|
26
40
|
this.bids = await this.market.loadBids(this.connection);
|
|
27
|
-
|
|
28
|
-
this.
|
|
29
|
-
|
|
30
|
-
|
|
41
|
+
if (this.subscriptionType === 'websocket') {
|
|
42
|
+
this.bidsCallbackId = this.connection.onAccountChange(this.bidsAddress, (accountInfo, ctx) => {
|
|
43
|
+
this.lastBidsSlot = ctx.slot;
|
|
44
|
+
this.bids = serum_1.Orderbook.decode(this.market, accountInfo.data);
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
else {
|
|
48
|
+
this.bidsCallbackId = await this.accountLoader.addAccount(this.bidsAddress, (buffer, slot) => {
|
|
49
|
+
this.lastBidsSlot = slot;
|
|
50
|
+
this.bids = serum_1.Orderbook.decode(this.market, buffer);
|
|
51
|
+
});
|
|
52
|
+
}
|
|
31
53
|
this.subscribed = true;
|
|
32
54
|
}
|
|
33
55
|
getBestBid() {
|
|
@@ -48,8 +70,15 @@ class SerumSubscriber {
|
|
|
48
70
|
if (!this.subscribed) {
|
|
49
71
|
return;
|
|
50
72
|
}
|
|
51
|
-
|
|
52
|
-
|
|
73
|
+
// remove listeners
|
|
74
|
+
if (this.subscriptionType === 'websocket') {
|
|
75
|
+
await this.connection.removeAccountChangeListener(this.asksCallbackId);
|
|
76
|
+
await this.connection.removeAccountChangeListener(this.bidsCallbackId);
|
|
77
|
+
}
|
|
78
|
+
else {
|
|
79
|
+
this.accountLoader.removeAccount(this.asksAddress, this.asksCallbackId);
|
|
80
|
+
this.accountLoader.removeAccount(this.bidsAddress, this.bidsCallbackId);
|
|
81
|
+
}
|
|
53
82
|
this.subscribed = false;
|
|
54
83
|
}
|
|
55
84
|
}
|
package/lib/serum/types.d.ts
CHANGED
package/lib/types.d.ts
CHANGED
|
@@ -130,8 +130,11 @@ export declare class OracleSource {
|
|
|
130
130
|
static readonly PYTH: {
|
|
131
131
|
pyth: {};
|
|
132
132
|
};
|
|
133
|
-
static readonly
|
|
134
|
-
|
|
133
|
+
static readonly PYTH_1K: {
|
|
134
|
+
pyth1K: {};
|
|
135
|
+
};
|
|
136
|
+
static readonly PYTH_1M: {
|
|
137
|
+
pyth1M: {};
|
|
135
138
|
};
|
|
136
139
|
static readonly QUOTE_ASSET: {
|
|
137
140
|
quoteAsset: {};
|
package/lib/types.js
CHANGED
|
@@ -78,7 +78,8 @@ class OracleSource {
|
|
|
78
78
|
}
|
|
79
79
|
exports.OracleSource = OracleSource;
|
|
80
80
|
OracleSource.PYTH = { pyth: {} };
|
|
81
|
-
OracleSource.
|
|
81
|
+
OracleSource.PYTH_1K = { pyth1K: {} };
|
|
82
|
+
OracleSource.PYTH_1M = { pyth1M: {} };
|
|
82
83
|
// static readonly SWITCHBOARD = { switchboard: {} };
|
|
83
84
|
OracleSource.QUOTE_ASSET = { quoteAsset: {} };
|
|
84
85
|
class OrderType {
|
package/package.json
CHANGED
|
@@ -57,12 +57,12 @@ export const DevnetPerpMarkets: PerpMarketConfig[] = [
|
|
|
57
57
|
{
|
|
58
58
|
fullName: 'Bonk',
|
|
59
59
|
category: ['Meme'],
|
|
60
|
-
symbol: '
|
|
61
|
-
baseAssetSymbol: '
|
|
60
|
+
symbol: '1MBONK-PERP',
|
|
61
|
+
baseAssetSymbol: '1MBONK',
|
|
62
62
|
marketIndex: 4,
|
|
63
63
|
oracle: new PublicKey('6bquU99ktV1VRiHDr8gMhDFt3kMfhCQo5nfNrg2Urvsn'),
|
|
64
64
|
launchTs: 1677068931000,
|
|
65
|
-
oracleSource: OracleSource.
|
|
65
|
+
oracleSource: OracleSource.PYTH_1M,
|
|
66
66
|
},
|
|
67
67
|
];
|
|
68
68
|
|
|
@@ -107,6 +107,16 @@ export const MainnetPerpMarkets: PerpMarketConfig[] = [
|
|
|
107
107
|
launchTs: 1675802661000,
|
|
108
108
|
oracleSource: OracleSource.PYTH,
|
|
109
109
|
},
|
|
110
|
+
{
|
|
111
|
+
fullName: 'Bonk',
|
|
112
|
+
category: ['Meme'],
|
|
113
|
+
symbol: '1MBONK-PERP',
|
|
114
|
+
baseAssetSymbol: '1MBONK',
|
|
115
|
+
marketIndex: 4,
|
|
116
|
+
oracle: new PublicKey('8ihFLu5FimgTQ1Unh4dVyEHUGodJ5gJQCrQf4KUVB9bN'),
|
|
117
|
+
launchTs: 1677690149000,
|
|
118
|
+
oracleSource: OracleSource.PYTH_1M,
|
|
119
|
+
},
|
|
110
120
|
];
|
|
111
121
|
|
|
112
122
|
export const PerpMarkets: { [key in DriftEnv]: PerpMarketConfig[] } = {
|
package/src/dlob/DLOB.ts
CHANGED
|
@@ -450,8 +450,9 @@ export class DLOB {
|
|
|
450
450
|
}
|
|
451
451
|
|
|
452
452
|
public getOrder(orderId: number, userAccount: PublicKey): Order | undefined {
|
|
453
|
+
const orderSignature = getOrderSignature(orderId, userAccount);
|
|
453
454
|
for (const nodeList of this.getNodeLists()) {
|
|
454
|
-
const node = nodeList.get(
|
|
455
|
+
const node = nodeList.get(orderSignature);
|
|
455
456
|
if (node) {
|
|
456
457
|
return node.order;
|
|
457
458
|
}
|
|
@@ -1383,18 +1384,29 @@ export class DLOB {
|
|
|
1383
1384
|
const bidSlot = bidNode.order.slot.add(
|
|
1384
1385
|
new BN(bidNode.order.auctionDuration)
|
|
1385
1386
|
);
|
|
1386
|
-
|
|
1387
|
+
|
|
1388
|
+
if (bidNode.order.postOnly && askNode.order.postOnly) {
|
|
1389
|
+
return undefined;
|
|
1390
|
+
} else if (bidNode.order.postOnly) {
|
|
1391
|
+
return {
|
|
1392
|
+
takerNode: askNode,
|
|
1393
|
+
makerNode: bidNode,
|
|
1394
|
+
};
|
|
1395
|
+
} else if (askNode.order.postOnly) {
|
|
1387
1396
|
return {
|
|
1388
1397
|
takerNode: bidNode,
|
|
1389
1398
|
makerNode: askNode,
|
|
1390
1399
|
};
|
|
1391
|
-
} else if (
|
|
1400
|
+
} else if (askSlot.lte(bidSlot)) {
|
|
1401
|
+
return {
|
|
1402
|
+
takerNode: bidNode,
|
|
1403
|
+
makerNode: askNode,
|
|
1404
|
+
};
|
|
1405
|
+
} else {
|
|
1392
1406
|
return {
|
|
1393
1407
|
takerNode: askNode,
|
|
1394
1408
|
makerNode: bidNode,
|
|
1395
1409
|
};
|
|
1396
|
-
} else {
|
|
1397
|
-
return undefined;
|
|
1398
1410
|
}
|
|
1399
1411
|
}
|
|
1400
1412
|
|
package/src/dlob/NodeList.ts
CHANGED
|
@@ -146,11 +146,8 @@ export class NodeList<NodeType extends keyof DLOBNodeMap>
|
|
|
146
146
|
return this.nodeMap.has(getOrderSignature(order.orderId, userAccount));
|
|
147
147
|
}
|
|
148
148
|
|
|
149
|
-
public get(
|
|
150
|
-
|
|
151
|
-
userAccount: PublicKey
|
|
152
|
-
): DLOBNodeMap[NodeType] | undefined {
|
|
153
|
-
return this.nodeMap.get(getOrderSignature(orderId, userAccount));
|
|
149
|
+
public get(orderSignature: string): DLOBNodeMap[NodeType] | undefined {
|
|
150
|
+
return this.nodeMap.get(orderSignature);
|
|
154
151
|
}
|
|
155
152
|
|
|
156
153
|
public print(): void {
|
|
@@ -14,10 +14,14 @@ export function getOracleClient(
|
|
|
14
14
|
return new PythClient(connection);
|
|
15
15
|
}
|
|
16
16
|
|
|
17
|
-
if (isVariant(oracleSource, '
|
|
17
|
+
if (isVariant(oracleSource, 'pyth1K')) {
|
|
18
18
|
return new PythClient(connection, new BN(1000));
|
|
19
19
|
}
|
|
20
20
|
|
|
21
|
+
if (isVariant(oracleSource, 'pyth1M')) {
|
|
22
|
+
return new PythClient(connection, new BN(1000000));
|
|
23
|
+
}
|
|
24
|
+
|
|
21
25
|
// if (isVariant(oracleSource, 'switchboard')) {
|
|
22
26
|
// return new SwitchboardClient(connection);
|
|
23
27
|
// }
|
package/src/idl/drift.json
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"version": "2.
|
|
2
|
+
"version": "2.19.0",
|
|
3
3
|
"name": "drift",
|
|
4
4
|
"instructions": [
|
|
5
5
|
{
|
|
@@ -6237,14 +6237,17 @@
|
|
|
6237
6237
|
{
|
|
6238
6238
|
"name": "Pyth"
|
|
6239
6239
|
},
|
|
6240
|
-
{
|
|
6241
|
-
"name": "Pyth1000"
|
|
6242
|
-
},
|
|
6243
6240
|
{
|
|
6244
6241
|
"name": "Switchboard"
|
|
6245
6242
|
},
|
|
6246
6243
|
{
|
|
6247
6244
|
"name": "QuoteAsset"
|
|
6245
|
+
},
|
|
6246
|
+
{
|
|
6247
|
+
"name": "Pyth1K"
|
|
6248
|
+
},
|
|
6249
|
+
{
|
|
6250
|
+
"name": "Pyth1M"
|
|
6248
6251
|
}
|
|
6249
6252
|
]
|
|
6250
6253
|
}
|
package/src/math/amm.ts
CHANGED
|
@@ -11,7 +11,6 @@ import {
|
|
|
11
11
|
MARGIN_PRECISION,
|
|
12
12
|
PRICE_DIV_PEG,
|
|
13
13
|
PERCENTAGE_PRECISION,
|
|
14
|
-
BASE_PRECISION,
|
|
15
14
|
DEFAULT_REVENUE_SINCE_LAST_FUNDING_SPREAD_RETREAT,
|
|
16
15
|
TWO,
|
|
17
16
|
} from '../constants/numericConstants';
|
|
@@ -362,10 +361,12 @@ export function calculateInventoryScale(
|
|
|
362
361
|
maxSpread: number
|
|
363
362
|
): number {
|
|
364
363
|
if (baseAssetAmountWithAmm.eq(ZERO)) {
|
|
365
|
-
return
|
|
364
|
+
return 1;
|
|
366
365
|
}
|
|
367
366
|
|
|
368
|
-
const
|
|
367
|
+
const MAX_BID_ASK_INVENTORY_SKEW_FACTOR = BID_ASK_SPREAD_PRECISION.mul(
|
|
368
|
+
new BN(10)
|
|
369
|
+
);
|
|
369
370
|
// inventory skew
|
|
370
371
|
const [openBids, openAsks] = calculateMarketOpenBidAsk(
|
|
371
372
|
baseAssetReserve,
|
|
@@ -373,34 +374,32 @@ export function calculateInventoryScale(
|
|
|
373
374
|
maxBaseAssetReserve
|
|
374
375
|
);
|
|
375
376
|
|
|
376
|
-
const minSideLiquidity = BN.
|
|
377
|
-
|
|
378
|
-
|
|
377
|
+
const minSideLiquidity = BN.min(openBids.abs(), openAsks.abs());
|
|
378
|
+
|
|
379
|
+
const inventoryScaleBN = BN.min(
|
|
380
|
+
baseAssetAmountWithAmm
|
|
381
|
+
.mul(PERCENTAGE_PRECISION)
|
|
382
|
+
.div(BN.max(minSideLiquidity, ONE))
|
|
383
|
+
.abs(),
|
|
384
|
+
PERCENTAGE_PRECISION
|
|
379
385
|
);
|
|
380
386
|
|
|
381
387
|
const inventoryScaleMaxBN = BN.max(
|
|
382
|
-
|
|
383
|
-
new BN(maxSpread
|
|
388
|
+
MAX_BID_ASK_INVENTORY_SKEW_FACTOR,
|
|
389
|
+
new BN(maxSpread)
|
|
384
390
|
.mul(BID_ASK_SPREAD_PRECISION)
|
|
385
391
|
.div(new BN(Math.max(directionalSpread, 1)))
|
|
386
392
|
);
|
|
387
393
|
|
|
388
|
-
const
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
const inventoryScale =
|
|
396
|
-
BN.min(inventoryScaleMaxBN, inventoryScaleBN).toNumber() /
|
|
397
|
-
BID_ASK_SPREAD_PRECISION.toNumber();
|
|
398
|
-
|
|
399
|
-
const inventoryScaleMax =
|
|
400
|
-
inventoryScaleMaxBN.toNumber() / BID_ASK_SPREAD_PRECISION.toNumber();
|
|
401
|
-
const inventorySpreadScale = Math.min(inventoryScaleMax, 1 + inventoryScale);
|
|
394
|
+
const inventoryScaleCapped =
|
|
395
|
+
BN.min(
|
|
396
|
+
inventoryScaleMaxBN,
|
|
397
|
+
BID_ASK_SPREAD_PRECISION.add(
|
|
398
|
+
inventoryScaleMaxBN.mul(inventoryScaleBN).div(PERCENTAGE_PRECISION)
|
|
399
|
+
)
|
|
400
|
+
).toNumber() / BID_ASK_SPREAD_PRECISION.toNumber();
|
|
402
401
|
|
|
403
|
-
return
|
|
402
|
+
return inventoryScaleCapped;
|
|
404
403
|
}
|
|
405
404
|
|
|
406
405
|
export function calculateEffectiveLeverage(
|
package/src/math/trade.ts
CHANGED
|
@@ -782,7 +782,7 @@ export function calculateEstimatedSpotEntryPrice(
|
|
|
782
782
|
cumulativeBaseFilled = cumulativeBaseFilled.add(baseFilled);
|
|
783
783
|
cumulativeQuoteFilled = cumulativeQuoteFilled.add(quoteFilled);
|
|
784
784
|
|
|
785
|
-
worstPrice =
|
|
785
|
+
worstPrice = dlobLimitOrderPrice;
|
|
786
786
|
|
|
787
787
|
dlobLimitOrder = dlobLimitOrders.next().value;
|
|
788
788
|
} else {
|
|
@@ -9,26 +9,32 @@ export class SerumSubscriber {
|
|
|
9
9
|
connection: Connection;
|
|
10
10
|
programId: PublicKey;
|
|
11
11
|
marketAddress: PublicKey;
|
|
12
|
-
|
|
12
|
+
subscriptionType: 'polling' | 'websocket';
|
|
13
|
+
accountLoader: BulkAccountLoader | undefined;
|
|
13
14
|
market: Market;
|
|
14
15
|
|
|
15
16
|
subscribed: boolean;
|
|
16
17
|
|
|
17
18
|
asksAddress: PublicKey;
|
|
18
19
|
asks: Orderbook;
|
|
19
|
-
asksCallbackId: string;
|
|
20
|
+
asksCallbackId: string | number;
|
|
20
21
|
lastAsksSlot: number;
|
|
21
22
|
|
|
22
23
|
bidsAddress: PublicKey;
|
|
23
24
|
bids: Orderbook;
|
|
24
|
-
bidsCallbackId: string;
|
|
25
|
+
bidsCallbackId: string | number;
|
|
25
26
|
lastBidsSlot: number;
|
|
26
27
|
|
|
27
28
|
public constructor(config: SerumMarketSubscriberConfig) {
|
|
28
29
|
this.connection = config.connection;
|
|
29
30
|
this.programId = config.programId;
|
|
30
31
|
this.marketAddress = config.marketAddress;
|
|
31
|
-
|
|
32
|
+
if (config.accountSubscription.type === 'polling') {
|
|
33
|
+
this.subscriptionType = 'polling';
|
|
34
|
+
this.accountLoader = config.accountSubscription.accountLoader;
|
|
35
|
+
} else {
|
|
36
|
+
this.subscriptionType = 'websocket';
|
|
37
|
+
}
|
|
32
38
|
}
|
|
33
39
|
|
|
34
40
|
public async subscribe(): Promise<void> {
|
|
@@ -46,24 +52,44 @@ export class SerumSubscriber {
|
|
|
46
52
|
this.asksAddress = this.market.asksAddress;
|
|
47
53
|
this.asks = await this.market.loadAsks(this.connection);
|
|
48
54
|
|
|
49
|
-
this.
|
|
50
|
-
this.
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
55
|
+
if (this.subscriptionType === 'websocket') {
|
|
56
|
+
this.asksCallbackId = this.connection.onAccountChange(
|
|
57
|
+
this.asksAddress,
|
|
58
|
+
(accountInfo, ctx) => {
|
|
59
|
+
this.lastAsksSlot = ctx.slot;
|
|
60
|
+
this.asks = Orderbook.decode(this.market, accountInfo.data);
|
|
61
|
+
}
|
|
62
|
+
);
|
|
63
|
+
} else {
|
|
64
|
+
this.asksCallbackId = await this.accountLoader.addAccount(
|
|
65
|
+
this.asksAddress,
|
|
66
|
+
(buffer, slot) => {
|
|
67
|
+
this.lastAsksSlot = slot;
|
|
68
|
+
this.asks = Orderbook.decode(this.market, buffer);
|
|
69
|
+
}
|
|
70
|
+
);
|
|
71
|
+
}
|
|
56
72
|
|
|
57
73
|
this.bidsAddress = this.market.bidsAddress;
|
|
58
74
|
this.bids = await this.market.loadBids(this.connection);
|
|
59
75
|
|
|
60
|
-
this.
|
|
61
|
-
this.
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
76
|
+
if (this.subscriptionType === 'websocket') {
|
|
77
|
+
this.bidsCallbackId = this.connection.onAccountChange(
|
|
78
|
+
this.bidsAddress,
|
|
79
|
+
(accountInfo, ctx) => {
|
|
80
|
+
this.lastBidsSlot = ctx.slot;
|
|
81
|
+
this.bids = Orderbook.decode(this.market, accountInfo.data);
|
|
82
|
+
}
|
|
83
|
+
);
|
|
84
|
+
} else {
|
|
85
|
+
this.bidsCallbackId = await this.accountLoader.addAccount(
|
|
86
|
+
this.bidsAddress,
|
|
87
|
+
(buffer, slot) => {
|
|
88
|
+
this.lastBidsSlot = slot;
|
|
89
|
+
this.bids = Orderbook.decode(this.market, buffer);
|
|
90
|
+
}
|
|
91
|
+
);
|
|
92
|
+
}
|
|
67
93
|
|
|
68
94
|
this.subscribed = true;
|
|
69
95
|
}
|
|
@@ -91,8 +117,24 @@ export class SerumSubscriber {
|
|
|
91
117
|
return;
|
|
92
118
|
}
|
|
93
119
|
|
|
94
|
-
|
|
95
|
-
|
|
120
|
+
// remove listeners
|
|
121
|
+
if (this.subscriptionType === 'websocket') {
|
|
122
|
+
await this.connection.removeAccountChangeListener(
|
|
123
|
+
this.asksCallbackId as number
|
|
124
|
+
);
|
|
125
|
+
await this.connection.removeAccountChangeListener(
|
|
126
|
+
this.bidsCallbackId as number
|
|
127
|
+
);
|
|
128
|
+
} else {
|
|
129
|
+
this.accountLoader.removeAccount(
|
|
130
|
+
this.asksAddress,
|
|
131
|
+
this.asksCallbackId as string
|
|
132
|
+
);
|
|
133
|
+
this.accountLoader.removeAccount(
|
|
134
|
+
this.bidsAddress,
|
|
135
|
+
this.bidsCallbackId as string
|
|
136
|
+
);
|
|
137
|
+
}
|
|
96
138
|
|
|
97
139
|
this.subscribed = false;
|
|
98
140
|
}
|
package/src/serum/types.ts
CHANGED
|
@@ -5,9 +5,13 @@ export type SerumMarketSubscriberConfig = {
|
|
|
5
5
|
connection: Connection;
|
|
6
6
|
programId: PublicKey;
|
|
7
7
|
marketAddress: PublicKey;
|
|
8
|
-
accountSubscription:
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
8
|
+
accountSubscription:
|
|
9
|
+
| {
|
|
10
|
+
// enables use to add web sockets in the future
|
|
11
|
+
type: 'polling';
|
|
12
|
+
accountLoader: BulkAccountLoader;
|
|
13
|
+
}
|
|
14
|
+
| {
|
|
15
|
+
type: 'websocket';
|
|
16
|
+
};
|
|
13
17
|
};
|
package/src/types.ts
CHANGED
|
@@ -76,7 +76,8 @@ export class DepositDirection {
|
|
|
76
76
|
|
|
77
77
|
export class OracleSource {
|
|
78
78
|
static readonly PYTH = { pyth: {} };
|
|
79
|
-
static readonly
|
|
79
|
+
static readonly PYTH_1K = { pyth1K: {} };
|
|
80
|
+
static readonly PYTH_1M = { pyth1M: {} };
|
|
80
81
|
// static readonly SWITCHBOARD = { switchboard: {} };
|
|
81
82
|
static readonly QUOTE_ASSET = { quoteAsset: {} };
|
|
82
83
|
}
|
package/tests/amm/test.ts
CHANGED
|
@@ -6,8 +6,10 @@ import {
|
|
|
6
6
|
QUOTE_PRECISION,
|
|
7
7
|
calculateSpreadBN,
|
|
8
8
|
ZERO,
|
|
9
|
+
ONE,
|
|
9
10
|
calculateLiveOracleStd,
|
|
10
11
|
calculateLiveOracleTwap,
|
|
12
|
+
calculateInventoryScale,
|
|
11
13
|
} from '../../src';
|
|
12
14
|
import { mockPerpMarkets } from '../dlob/helpers';
|
|
13
15
|
|
|
@@ -36,6 +38,176 @@ class AMMSpreadTerms {
|
|
|
36
38
|
}
|
|
37
39
|
|
|
38
40
|
describe('AMM Tests', () => {
|
|
41
|
+
it('Spread Maths', () => {
|
|
42
|
+
let iscale = calculateInventoryScale(
|
|
43
|
+
ZERO,
|
|
44
|
+
AMM_RESERVE_PRECISION,
|
|
45
|
+
AMM_RESERVE_PRECISION.div(new BN(2)),
|
|
46
|
+
AMM_RESERVE_PRECISION.mul(new BN(3)).div(new BN(2)),
|
|
47
|
+
250,
|
|
48
|
+
30000,
|
|
49
|
+
);
|
|
50
|
+
assert(iscale == 1);
|
|
51
|
+
|
|
52
|
+
iscale = calculateInventoryScale(
|
|
53
|
+
ONE,
|
|
54
|
+
AMM_RESERVE_PRECISION,
|
|
55
|
+
AMM_RESERVE_PRECISION.div(new BN(2)),
|
|
56
|
+
AMM_RESERVE_PRECISION.mul(new BN(3)).div(new BN(2)),
|
|
57
|
+
250,
|
|
58
|
+
30000,
|
|
59
|
+
);
|
|
60
|
+
assert(iscale == 1);
|
|
61
|
+
|
|
62
|
+
let baa = new BN(1000);
|
|
63
|
+
iscale = calculateInventoryScale(
|
|
64
|
+
baa,
|
|
65
|
+
AMM_RESERVE_PRECISION.add(baa),
|
|
66
|
+
AMM_RESERVE_PRECISION.div(new BN(2)),
|
|
67
|
+
AMM_RESERVE_PRECISION.mul(new BN(3)).div(new BN(2)),
|
|
68
|
+
250,
|
|
69
|
+
30000,
|
|
70
|
+
);
|
|
71
|
+
console.log(iscale);
|
|
72
|
+
assert(iscale == 1.00024);
|
|
73
|
+
|
|
74
|
+
baa = new BN(100000);
|
|
75
|
+
iscale = calculateInventoryScale(
|
|
76
|
+
baa,
|
|
77
|
+
AMM_RESERVE_PRECISION.add(baa),
|
|
78
|
+
AMM_RESERVE_PRECISION.div(new BN(2)),
|
|
79
|
+
AMM_RESERVE_PRECISION.mul(new BN(3)).div(new BN(2)),
|
|
80
|
+
250,
|
|
81
|
+
30000,
|
|
82
|
+
);
|
|
83
|
+
console.log(iscale);
|
|
84
|
+
assert(iscale == 1.024);
|
|
85
|
+
|
|
86
|
+
baa = new BN(1000000);
|
|
87
|
+
iscale = calculateInventoryScale(
|
|
88
|
+
baa,
|
|
89
|
+
AMM_RESERVE_PRECISION.add(baa),
|
|
90
|
+
AMM_RESERVE_PRECISION.div(new BN(2)),
|
|
91
|
+
AMM_RESERVE_PRECISION.mul(new BN(3)).div(new BN(2)),
|
|
92
|
+
250,
|
|
93
|
+
30000,
|
|
94
|
+
);
|
|
95
|
+
console.log(iscale);
|
|
96
|
+
assert(iscale == 1.24048);
|
|
97
|
+
|
|
98
|
+
baa = new BN(10000000); // 2%
|
|
99
|
+
iscale = calculateInventoryScale(
|
|
100
|
+
baa,
|
|
101
|
+
AMM_RESERVE_PRECISION.add(baa),
|
|
102
|
+
AMM_RESERVE_PRECISION.div(new BN(2)),
|
|
103
|
+
AMM_RESERVE_PRECISION.mul(new BN(3)).div(new BN(2)),
|
|
104
|
+
250,
|
|
105
|
+
30000,
|
|
106
|
+
);
|
|
107
|
+
console.log(iscale);
|
|
108
|
+
assert(iscale == 3.44896);
|
|
109
|
+
|
|
110
|
+
baa = new BN(50000000); // 10%
|
|
111
|
+
iscale = calculateInventoryScale(
|
|
112
|
+
baa,
|
|
113
|
+
AMM_RESERVE_PRECISION.add(baa),
|
|
114
|
+
AMM_RESERVE_PRECISION.div(new BN(2)),
|
|
115
|
+
AMM_RESERVE_PRECISION.mul(new BN(3)).div(new BN(2)),
|
|
116
|
+
250,
|
|
117
|
+
30000,
|
|
118
|
+
);
|
|
119
|
+
console.log(iscale);
|
|
120
|
+
assert(iscale == 14.33332);
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
baa = AMM_RESERVE_PRECISION.div(new BN(4)); // 50%
|
|
124
|
+
iscale = calculateInventoryScale(
|
|
125
|
+
baa,
|
|
126
|
+
AMM_RESERVE_PRECISION.add(baa),
|
|
127
|
+
AMM_RESERVE_PRECISION.div(new BN(2)),
|
|
128
|
+
AMM_RESERVE_PRECISION.mul(new BN(3)).div(new BN(2)),
|
|
129
|
+
250,
|
|
130
|
+
30000,
|
|
131
|
+
);
|
|
132
|
+
console.log(iscale);
|
|
133
|
+
assert(iscale == 120); //100%
|
|
134
|
+
|
|
135
|
+
baa = AMM_RESERVE_PRECISION.div(new BN(4)); // 50%
|
|
136
|
+
iscale = calculateInventoryScale(
|
|
137
|
+
baa,
|
|
138
|
+
AMM_RESERVE_PRECISION.add(baa),
|
|
139
|
+
AMM_RESERVE_PRECISION.div(new BN(2)),
|
|
140
|
+
AMM_RESERVE_PRECISION.mul(new BN(3)).div(new BN(2)),
|
|
141
|
+
250,
|
|
142
|
+
30000 * 2,
|
|
143
|
+
);
|
|
144
|
+
console.log(iscale);
|
|
145
|
+
assert(iscale == 120 * 2); //100%
|
|
146
|
+
|
|
147
|
+
baa = AMM_RESERVE_PRECISION.div(new BN(5)); // <50%
|
|
148
|
+
iscale = calculateInventoryScale(
|
|
149
|
+
baa,
|
|
150
|
+
AMM_RESERVE_PRECISION.add(baa),
|
|
151
|
+
AMM_RESERVE_PRECISION.div(new BN(2)),
|
|
152
|
+
AMM_RESERVE_PRECISION.mul(new BN(3)).div(new BN(2)),
|
|
153
|
+
250,
|
|
154
|
+
30000 * 2,
|
|
155
|
+
);
|
|
156
|
+
assert(iscale == 160.99984);
|
|
157
|
+
|
|
158
|
+
baa = new BN(855329058);
|
|
159
|
+
iscale = calculateInventoryScale(
|
|
160
|
+
baa,
|
|
161
|
+
AMM_RESERVE_PRECISION.add(baa),
|
|
162
|
+
AMM_RESERVE_PRECISION.div(new BN(2)),
|
|
163
|
+
AMM_RESERVE_PRECISION,
|
|
164
|
+
250,
|
|
165
|
+
30000,
|
|
166
|
+
); // >100%
|
|
167
|
+
assert(iscale == 120);
|
|
168
|
+
assert(250*iscale == 30000);
|
|
169
|
+
|
|
170
|
+
iscale = calculateInventoryScale(
|
|
171
|
+
baa,
|
|
172
|
+
AMM_RESERVE_PRECISION.add(baa), // ~85%
|
|
173
|
+
AMM_RESERVE_PRECISION.div(new BN(2)),
|
|
174
|
+
AMM_RESERVE_PRECISION.mul(new BN(3)).div(new BN(2)),
|
|
175
|
+
250,
|
|
176
|
+
30000,
|
|
177
|
+
);
|
|
178
|
+
assert(iscale == 120);
|
|
179
|
+
assert(250*iscale == 30000);
|
|
180
|
+
|
|
181
|
+
baa = new BN(-855329058); // ~85%
|
|
182
|
+
iscale = calculateInventoryScale(
|
|
183
|
+
baa,
|
|
184
|
+
AMM_RESERVE_PRECISION.add(baa),
|
|
185
|
+
AMM_RESERVE_PRECISION.div(new BN(2)),
|
|
186
|
+
AMM_RESERVE_PRECISION.mul(new BN(3)).div(new BN(2)),
|
|
187
|
+
250,
|
|
188
|
+
30000,
|
|
189
|
+
);
|
|
190
|
+
assert(iscale == 120);
|
|
191
|
+
assert(250*iscale == 30000);
|
|
192
|
+
|
|
193
|
+
// 'bonk' scale
|
|
194
|
+
iscale = calculateInventoryScale(
|
|
195
|
+
new BN('30228000000000000'),
|
|
196
|
+
new BN('2496788386034912600'),
|
|
197
|
+
new BN('2443167585342470000'),
|
|
198
|
+
new BN('2545411471321696000'),
|
|
199
|
+
3500,
|
|
200
|
+
100000,
|
|
201
|
+
);
|
|
202
|
+
console.log(iscale);
|
|
203
|
+
console.log(3500*iscale/1e6);
|
|
204
|
+
assert(iscale == 18.762285);
|
|
205
|
+
assert(3500*iscale/1e6 == 0.06566799749999999); //6.5%
|
|
206
|
+
|
|
207
|
+
|
|
208
|
+
|
|
209
|
+
});
|
|
210
|
+
|
|
39
211
|
it('Various Spreads', () => {
|
|
40
212
|
const baseSpread: number = 0.025 * 1e6;
|
|
41
213
|
const lastOracleReservePriceSpreadPct: BN = ZERO;
|
|
@@ -150,9 +322,9 @@ describe('AMM Tests', () => {
|
|
|
150
322
|
|
|
151
323
|
console.log(terms2);
|
|
152
324
|
assert(terms2.effectiveLeverageCapped >= 1.0002);
|
|
153
|
-
assert(terms2.inventorySpreadScale ==
|
|
154
|
-
assert(terms2.longSpread ==
|
|
155
|
-
assert(terms2.shortSpread ==
|
|
325
|
+
assert(terms2.inventorySpreadScale == 1.73492);
|
|
326
|
+
assert(terms2.longSpread == 4262);
|
|
327
|
+
assert(terms2.shortSpread == 43238);
|
|
156
328
|
});
|
|
157
329
|
|
|
158
330
|
it('Corner Case Spreads', () => {
|
|
@@ -183,8 +355,8 @@ describe('AMM Tests', () => {
|
|
|
183
355
|
|
|
184
356
|
console.log(terms2);
|
|
185
357
|
assert(terms2.effectiveLeverageCapped <= 1.000001);
|
|
186
|
-
assert(terms2.inventorySpreadScale == 1.
|
|
187
|
-
assert(terms2.longSpread ==
|
|
358
|
+
assert(terms2.inventorySpreadScale == 1.013527);
|
|
359
|
+
assert(terms2.longSpread == 1146);
|
|
188
360
|
assert(terms2.shortSpread == 6686);
|
|
189
361
|
});
|
|
190
362
|
|
package/tests/dlob/test.ts
CHANGED
|
@@ -5207,7 +5207,8 @@ describe('DLOB Spot Tests', () => {
|
|
|
5207
5207
|
expect(nodesToFillAfter[1].makerNode?.order?.orderId).to.equal(3);
|
|
5208
5208
|
});
|
|
5209
5209
|
|
|
5210
|
-
|
|
5210
|
+
// add back if dlob checks limit order age again
|
|
5211
|
+
it.skip('Test limit orders skipping more recent post onlys', () => {
|
|
5211
5212
|
const vAsk = new BN(15);
|
|
5212
5213
|
const vBid = new BN(8);
|
|
5213
5214
|
|