@drift-labs/sdk 2.31.0-beta.5 → 2.31.0-beta.7
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 +20 -0
- package/lib/driftClient.js +1 -1
- package/lib/idl/drift.json +1 -1
- package/lib/math/trade.d.ts +9 -0
- package/lib/math/trade.js +59 -1
- package/lib/tx/retryTxSender.d.ts +1 -1
- package/lib/tx/retryTxSender.js +18 -6
- package/lib/tx/types.d.ts +1 -1
- package/lib/user.d.ts +1 -1
- package/lib/user.js +10 -11
- package/package.json +1 -1
- package/src/assert/assert.js +9 -0
- package/src/constants/perpMarkets.ts +20 -0
- package/src/driftClient.ts +2 -1
- package/src/idl/drift.json +1 -1
- package/src/math/trade.ts +88 -0
- package/src/token/index.js +38 -0
- package/src/tx/retryTxSender.ts +19 -9
- package/src/tx/types.ts +2 -1
- package/src/user.ts +17 -15
- package/src/util/computeUnits.js +27 -0
- package/src/util/promiseTimeout.js +14 -0
- package/src/util/tps.js +27 -0
- package/get_events.ts +0 -47
|
@@ -114,6 +114,16 @@ exports.DevnetPerpMarkets = [
|
|
|
114
114
|
launchTs: 1683125906000,
|
|
115
115
|
oracleSource: __1.OracleSource.PYTH_1M,
|
|
116
116
|
},
|
|
117
|
+
{
|
|
118
|
+
fullName: 'OP',
|
|
119
|
+
category: ['L2', 'Infra'],
|
|
120
|
+
symbol: 'OP-PERP',
|
|
121
|
+
baseAssetSymbol: 'OP',
|
|
122
|
+
marketIndex: 11,
|
|
123
|
+
oracle: new web3_js_1.PublicKey('8ctSiDhA7eJoii4TkKV8Rx4KFdz3ycsA1FXy9wq56quG'),
|
|
124
|
+
launchTs: 1683125906000,
|
|
125
|
+
oracleSource: __1.OracleSource.PYTH,
|
|
126
|
+
},
|
|
117
127
|
];
|
|
118
128
|
exports.MainnetPerpMarkets = [
|
|
119
129
|
{
|
|
@@ -226,6 +236,16 @@ exports.MainnetPerpMarkets = [
|
|
|
226
236
|
launchTs: 1683125906000,
|
|
227
237
|
oracleSource: __1.OracleSource.PYTH_1M,
|
|
228
238
|
},
|
|
239
|
+
{
|
|
240
|
+
fullName: 'OP',
|
|
241
|
+
category: ['L2', 'Infra'],
|
|
242
|
+
symbol: 'OP-PERP',
|
|
243
|
+
baseAssetSymbol: 'OP',
|
|
244
|
+
marketIndex: 11,
|
|
245
|
+
oracle: new web3_js_1.PublicKey('4o4CUwzFwLqCvmA5x1G4VzoZkAhAcbiuiYyjWX1CVbY2'),
|
|
246
|
+
launchTs: 1683125906000,
|
|
247
|
+
oracleSource: __1.OracleSource.PYTH,
|
|
248
|
+
},
|
|
229
249
|
];
|
|
230
250
|
exports.PerpMarkets = {
|
|
231
251
|
devnet: exports.DevnetPerpMarkets,
|
package/lib/driftClient.js
CHANGED
|
@@ -3040,7 +3040,7 @@ class DriftClient {
|
|
|
3040
3040
|
return this.txSender.send(tx, additionalSigners, opts, preSigned);
|
|
3041
3041
|
}
|
|
3042
3042
|
else {
|
|
3043
|
-
return this.txSender.sendVersionedTransaction(tx, additionalSigners, opts);
|
|
3043
|
+
return this.txSender.sendVersionedTransaction(tx, additionalSigners, opts, preSigned);
|
|
3044
3044
|
}
|
|
3045
3045
|
}
|
|
3046
3046
|
async buildTransaction(instructions, txParams, txVersion, lookupTables) {
|
package/lib/idl/drift.json
CHANGED
package/lib/math/trade.d.ts
CHANGED
|
@@ -5,6 +5,7 @@ import { OraclePriceData } from '../oracles/types';
|
|
|
5
5
|
import { DLOB } from '../dlob/DLOB';
|
|
6
6
|
import { PublicKey } from '@solana/web3.js';
|
|
7
7
|
import { Orderbook } from '@project-serum/serum';
|
|
8
|
+
import { L2OrderBook } from '../dlob/orderBookLevels';
|
|
8
9
|
export type PriceImpactUnit = 'entryPrice' | 'maxPrice' | 'priceDelta' | 'priceDeltaAsNumber' | 'pctAvg' | 'pctMax' | 'quoteAssetAmount' | 'quoteAssetAmountPeg' | 'acquiredBaseAssetAmount' | 'acquiredQuoteAssetAmount' | 'all';
|
|
9
10
|
/**
|
|
10
11
|
* Calculates avg/max slippage (price impact) for candidate trade
|
|
@@ -104,3 +105,11 @@ export declare function calculateEstimatedSpotEntryPrice(assetType: AssetType, a
|
|
|
104
105
|
baseFilled: BN;
|
|
105
106
|
quoteFilled: BN;
|
|
106
107
|
};
|
|
108
|
+
export declare function calculateEstimatedEntryPriceWithL2(assetType: AssetType, amount: BN, direction: PositionDirection, basePrecision: BN, l2: L2OrderBook): {
|
|
109
|
+
entryPrice: BN;
|
|
110
|
+
priceImpact: BN;
|
|
111
|
+
bestPrice: BN;
|
|
112
|
+
worstPrice: BN;
|
|
113
|
+
baseFilled: BN;
|
|
114
|
+
quoteFilled: BN;
|
|
115
|
+
};
|
package/lib/math/trade.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.calculateEstimatedSpotEntryPrice = exports.calculateEstimatedPerpEntryPrice = exports.calculateTargetPriceTrade = exports.calculateTradeAcquiredAmounts = exports.calculateTradeSlippage = void 0;
|
|
3
|
+
exports.calculateEstimatedEntryPriceWithL2 = exports.calculateEstimatedSpotEntryPrice = exports.calculateEstimatedPerpEntryPrice = exports.calculateTargetPriceTrade = exports.calculateTradeAcquiredAmounts = exports.calculateTradeSlippage = void 0;
|
|
4
4
|
const types_1 = require("../types");
|
|
5
5
|
const anchor_1 = require("@coral-xyz/anchor");
|
|
6
6
|
const assert_1 = require("../assert/assert");
|
|
@@ -571,3 +571,61 @@ function calculateEstimatedSpotEntryPrice(assetType, amount, direction, market,
|
|
|
571
571
|
};
|
|
572
572
|
}
|
|
573
573
|
exports.calculateEstimatedSpotEntryPrice = calculateEstimatedSpotEntryPrice;
|
|
574
|
+
function calculateEstimatedEntryPriceWithL2(assetType, amount, direction, basePrecision, l2) {
|
|
575
|
+
const takerIsLong = (0, types_2.isVariant)(direction, 'long');
|
|
576
|
+
let cumulativeBaseFilled = numericConstants_1.ZERO;
|
|
577
|
+
let cumulativeQuoteFilled = numericConstants_1.ZERO;
|
|
578
|
+
const levels = [...(takerIsLong ? l2.asks : l2.bids)];
|
|
579
|
+
let nextLevel = levels.shift();
|
|
580
|
+
let bestPrice;
|
|
581
|
+
let worstPrice;
|
|
582
|
+
if (nextLevel) {
|
|
583
|
+
bestPrice = nextLevel.price;
|
|
584
|
+
worstPrice = nextLevel.price;
|
|
585
|
+
}
|
|
586
|
+
else {
|
|
587
|
+
bestPrice = takerIsLong ? numericConstants_1.BN_MAX : numericConstants_1.ZERO;
|
|
588
|
+
worstPrice = bestPrice;
|
|
589
|
+
}
|
|
590
|
+
if (assetType === 'base') {
|
|
591
|
+
while (!cumulativeBaseFilled.eq(amount) && nextLevel) {
|
|
592
|
+
const price = nextLevel.price;
|
|
593
|
+
const size = nextLevel.size;
|
|
594
|
+
worstPrice = price;
|
|
595
|
+
const baseFilled = anchor_1.BN.min(size, amount.sub(cumulativeBaseFilled));
|
|
596
|
+
const quoteFilled = baseFilled.mul(price).div(basePrecision);
|
|
597
|
+
cumulativeBaseFilled = cumulativeBaseFilled.add(baseFilled);
|
|
598
|
+
cumulativeQuoteFilled = cumulativeQuoteFilled.add(quoteFilled);
|
|
599
|
+
nextLevel = levels.shift();
|
|
600
|
+
}
|
|
601
|
+
}
|
|
602
|
+
else {
|
|
603
|
+
while (!cumulativeQuoteFilled.eq(amount) && nextLevel) {
|
|
604
|
+
const price = nextLevel.price;
|
|
605
|
+
const size = nextLevel.size;
|
|
606
|
+
worstPrice = price;
|
|
607
|
+
const quoteFilled = anchor_1.BN.min(size.mul(price).div(basePrecision), amount.sub(cumulativeQuoteFilled));
|
|
608
|
+
const baseFilled = quoteFilled.mul(basePrecision).div(price);
|
|
609
|
+
cumulativeBaseFilled = cumulativeBaseFilled.add(baseFilled);
|
|
610
|
+
cumulativeQuoteFilled = cumulativeQuoteFilled.add(quoteFilled);
|
|
611
|
+
nextLevel = levels.shift();
|
|
612
|
+
}
|
|
613
|
+
}
|
|
614
|
+
const entryPrice = cumulativeQuoteFilled
|
|
615
|
+
.mul(basePrecision)
|
|
616
|
+
.div(cumulativeBaseFilled);
|
|
617
|
+
const priceImpact = entryPrice
|
|
618
|
+
.sub(bestPrice)
|
|
619
|
+
.mul(numericConstants_1.PRICE_PRECISION)
|
|
620
|
+
.div(bestPrice)
|
|
621
|
+
.abs();
|
|
622
|
+
return {
|
|
623
|
+
entryPrice,
|
|
624
|
+
priceImpact,
|
|
625
|
+
bestPrice,
|
|
626
|
+
worstPrice,
|
|
627
|
+
baseFilled: cumulativeBaseFilled,
|
|
628
|
+
quoteFilled: cumulativeQuoteFilled,
|
|
629
|
+
};
|
|
630
|
+
}
|
|
631
|
+
exports.calculateEstimatedEntryPriceWithL2 = calculateEstimatedEntryPriceWithL2;
|
|
@@ -14,7 +14,7 @@ export declare class RetryTxSender implements TxSender {
|
|
|
14
14
|
send(tx: Transaction, additionalSigners?: Array<Signer>, opts?: ConfirmOptions, preSigned?: boolean): Promise<TxSigAndSlot>;
|
|
15
15
|
prepareTx(tx: Transaction, additionalSigners: Array<Signer>, opts: ConfirmOptions): Promise<Transaction>;
|
|
16
16
|
getVersionedTransaction(ixs: TransactionInstruction[], lookupTableAccounts: AddressLookupTableAccount[], additionalSigners?: Array<Signer>, opts?: ConfirmOptions): Promise<VersionedTransaction>;
|
|
17
|
-
sendVersionedTransaction(tx: VersionedTransaction, additionalSigners?: Array<Signer>, opts?: ConfirmOptions): Promise<TxSigAndSlot>;
|
|
17
|
+
sendVersionedTransaction(tx: VersionedTransaction, additionalSigners?: Array<Signer>, opts?: ConfirmOptions, preSigned?: boolean): Promise<TxSigAndSlot>;
|
|
18
18
|
sendRawTransaction(rawTransaction: Buffer | Uint8Array, opts: ConfirmOptions): Promise<TxSigAndSlot>;
|
|
19
19
|
confirmTransaction(signature: TransactionSignature, commitment?: Commitment): Promise<RpcResponseAndContext<SignatureResult>>;
|
|
20
20
|
getTimestamp(): number;
|
package/lib/tx/retryTxSender.js
CHANGED
|
@@ -54,12 +54,24 @@ class RetryTxSender {
|
|
|
54
54
|
const tx = new web3_js_1.VersionedTransaction(message);
|
|
55
55
|
return tx;
|
|
56
56
|
}
|
|
57
|
-
async sendVersionedTransaction(tx, additionalSigners, opts) {
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
57
|
+
async sendVersionedTransaction(tx, additionalSigners, opts, preSigned) {
|
|
58
|
+
let signedTx;
|
|
59
|
+
if (preSigned) {
|
|
60
|
+
signedTx = tx;
|
|
61
|
+
// @ts-ignore
|
|
62
|
+
}
|
|
63
|
+
else if (this.provider.wallet.payer) {
|
|
64
|
+
// @ts-ignore
|
|
65
|
+
tx.sign((additionalSigners !== null && additionalSigners !== void 0 ? additionalSigners : []).concat(this.provider.wallet.payer));
|
|
66
|
+
signedTx = tx;
|
|
67
|
+
}
|
|
68
|
+
else {
|
|
69
|
+
additionalSigners === null || additionalSigners === void 0 ? void 0 : additionalSigners.filter((s) => s !== undefined).forEach((kp) => {
|
|
70
|
+
tx.sign([kp]);
|
|
71
|
+
});
|
|
72
|
+
// @ts-ignore
|
|
73
|
+
signedTx = await this.provider.wallet.signTransaction(tx);
|
|
74
|
+
}
|
|
63
75
|
if (opts === undefined) {
|
|
64
76
|
opts = this.provider.opts;
|
|
65
77
|
}
|
package/lib/tx/types.d.ts
CHANGED
|
@@ -8,7 +8,7 @@ export type TxSigAndSlot = {
|
|
|
8
8
|
export interface TxSender {
|
|
9
9
|
provider: Provider;
|
|
10
10
|
send(tx: Transaction, additionalSigners?: Array<Signer>, opts?: ConfirmOptions, preSigned?: boolean): Promise<TxSigAndSlot>;
|
|
11
|
-
sendVersionedTransaction(tx: VersionedTransaction, additionalSigners?: Array<Signer>, opts?: ConfirmOptions): Promise<TxSigAndSlot>;
|
|
11
|
+
sendVersionedTransaction(tx: VersionedTransaction, additionalSigners?: Array<Signer>, opts?: ConfirmOptions, preSigned?: boolean): Promise<TxSigAndSlot>;
|
|
12
12
|
getVersionedTransaction(ixs: TransactionInstruction[], lookupTableAccounts: AddressLookupTableAccount[], additionalSigners?: Array<Signer>, opts?: ConfirmOptions): Promise<VersionedTransaction>;
|
|
13
13
|
sendRawTransaction(rawTransaction: Buffer | Uint8Array, opts: ConfirmOptions): Promise<TxSigAndSlot>;
|
|
14
14
|
}
|
package/lib/user.d.ts
CHANGED
|
@@ -82,7 +82,7 @@ export declare class User {
|
|
|
82
82
|
* @returns : the dust base asset amount (ie, < stepsize)
|
|
83
83
|
* @returns : pnl from settle
|
|
84
84
|
*/
|
|
85
|
-
|
|
85
|
+
getPerpPositionWithLPSettle(marketIndex: number, originalPosition?: PerpPosition): [PerpPosition, BN, BN];
|
|
86
86
|
/**
|
|
87
87
|
* calculates Buying Power = free collateral / initial margin ratio
|
|
88
88
|
* @returns : Precision QUOTE_PRECISION
|
package/lib/user.js
CHANGED
|
@@ -175,12 +175,12 @@ class User {
|
|
|
175
175
|
* @returns : the dust base asset amount (ie, < stepsize)
|
|
176
176
|
* @returns : pnl from settle
|
|
177
177
|
*/
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
return [position, numericConstants_1.ZERO, numericConstants_1.ZERO];
|
|
178
|
+
getPerpPositionWithLPSettle(marketIndex, originalPosition) {
|
|
179
|
+
originalPosition = originalPosition !== null && originalPosition !== void 0 ? originalPosition : this.getPerpPosition(marketIndex);
|
|
180
|
+
if (originalPosition.lpShares.eq(numericConstants_1.ZERO)) {
|
|
181
|
+
return [originalPosition, numericConstants_1.ZERO, numericConstants_1.ZERO];
|
|
183
182
|
}
|
|
183
|
+
const position = this.getClonedPosition(originalPosition);
|
|
184
184
|
const market = this.driftClient.getPerpMarketAccount(position.marketIndex);
|
|
185
185
|
const nShares = position.lpShares;
|
|
186
186
|
const deltaBaa = market.amm.baseAssetAmountPerLp
|
|
@@ -192,11 +192,10 @@ class User {
|
|
|
192
192
|
.mul(nShares)
|
|
193
193
|
.div(numericConstants_1.AMM_RESERVE_PRECISION);
|
|
194
194
|
function sign(v) {
|
|
195
|
-
|
|
196
|
-
return sign;
|
|
195
|
+
return v.isNeg() ? new _1.BN(-1) : new _1.BN(1);
|
|
197
196
|
}
|
|
198
|
-
function standardize(amount,
|
|
199
|
-
const remainder = amount.abs().mod(
|
|
197
|
+
function standardize(amount, stepSize) {
|
|
198
|
+
const remainder = amount.abs().mod(stepSize).mul(sign(amount));
|
|
200
199
|
const standardizedAmount = amount.sub(remainder);
|
|
201
200
|
return [standardizedAmount, remainder];
|
|
202
201
|
}
|
|
@@ -319,7 +318,7 @@ class User {
|
|
|
319
318
|
const quoteSpotMarket = this.driftClient.getSpotMarketAccount(market.quoteSpotMarketIndex);
|
|
320
319
|
const quoteOraclePriceData = this.getOracleDataForSpotMarket(market.quoteSpotMarketIndex);
|
|
321
320
|
if (perpPosition.lpShares.gt(numericConstants_1.ZERO)) {
|
|
322
|
-
perpPosition = this.
|
|
321
|
+
perpPosition = this.getPerpPositionWithLPSettle(perpPosition.marketIndex)[0];
|
|
323
322
|
}
|
|
324
323
|
let positionUnrealizedPnl = (0, _1.calculatePositionPNL)(market, perpPosition, withFunding, oraclePriceData);
|
|
325
324
|
let quotePrice;
|
|
@@ -546,7 +545,7 @@ class User {
|
|
|
546
545
|
// clone so we dont mutate the position
|
|
547
546
|
perpPosition = this.getClonedPosition(perpPosition);
|
|
548
547
|
// settle position
|
|
549
|
-
const [settledPosition, dustBaa, _] = this.
|
|
548
|
+
const [settledPosition, dustBaa, _] = this.getPerpPositionWithLPSettle(market.marketIndex);
|
|
550
549
|
perpPosition.baseAssetAmount =
|
|
551
550
|
settledPosition.baseAssetAmount.add(dustBaa);
|
|
552
551
|
perpPosition.quoteAssetAmount = settledPosition.quoteAssetAmount;
|
package/package.json
CHANGED
|
@@ -124,6 +124,16 @@ export const DevnetPerpMarkets: PerpMarketConfig[] = [
|
|
|
124
124
|
launchTs: 1683125906000,
|
|
125
125
|
oracleSource: OracleSource.PYTH_1M,
|
|
126
126
|
},
|
|
127
|
+
{
|
|
128
|
+
fullName: 'OP',
|
|
129
|
+
category: ['L2', 'Infra'],
|
|
130
|
+
symbol: 'OP-PERP',
|
|
131
|
+
baseAssetSymbol: 'OP',
|
|
132
|
+
marketIndex: 11,
|
|
133
|
+
oracle: new PublicKey('8ctSiDhA7eJoii4TkKV8Rx4KFdz3ycsA1FXy9wq56quG'),
|
|
134
|
+
launchTs: 1683125906000,
|
|
135
|
+
oracleSource: OracleSource.PYTH,
|
|
136
|
+
},
|
|
127
137
|
];
|
|
128
138
|
|
|
129
139
|
export const MainnetPerpMarkets: PerpMarketConfig[] = [
|
|
@@ -237,6 +247,16 @@ export const MainnetPerpMarkets: PerpMarketConfig[] = [
|
|
|
237
247
|
launchTs: 1683125906000,
|
|
238
248
|
oracleSource: OracleSource.PYTH_1M,
|
|
239
249
|
},
|
|
250
|
+
{
|
|
251
|
+
fullName: 'OP',
|
|
252
|
+
category: ['L2', 'Infra'],
|
|
253
|
+
symbol: 'OP-PERP',
|
|
254
|
+
baseAssetSymbol: 'OP',
|
|
255
|
+
marketIndex: 11,
|
|
256
|
+
oracle: new PublicKey('4o4CUwzFwLqCvmA5x1G4VzoZkAhAcbiuiYyjWX1CVbY2'),
|
|
257
|
+
launchTs: 1683125906000,
|
|
258
|
+
oracleSource: OracleSource.PYTH,
|
|
259
|
+
},
|
|
240
260
|
];
|
|
241
261
|
|
|
242
262
|
export const PerpMarkets: { [key in DriftEnv]: PerpMarketConfig[] } = {
|
package/src/driftClient.ts
CHANGED
package/src/idl/drift.json
CHANGED
package/src/math/trade.ts
CHANGED
|
@@ -34,6 +34,7 @@ import { OraclePriceData } from '../oracles/types';
|
|
|
34
34
|
import { DLOB } from '../dlob/DLOB';
|
|
35
35
|
import { PublicKey } from '@solana/web3.js';
|
|
36
36
|
import { Orderbook } from '@project-serum/serum';
|
|
37
|
+
import { L2OrderBook } from '../dlob/orderBookLevels';
|
|
37
38
|
|
|
38
39
|
const MAXPCT = new BN(1000); //percentage units are [0,1000] => [0,1]
|
|
39
40
|
|
|
@@ -884,3 +885,90 @@ export function calculateEstimatedSpotEntryPrice(
|
|
|
884
885
|
quoteFilled: cumulativeQuoteFilled,
|
|
885
886
|
};
|
|
886
887
|
}
|
|
888
|
+
|
|
889
|
+
export function calculateEstimatedEntryPriceWithL2(
|
|
890
|
+
assetType: AssetType,
|
|
891
|
+
amount: BN,
|
|
892
|
+
direction: PositionDirection,
|
|
893
|
+
basePrecision: BN,
|
|
894
|
+
l2: L2OrderBook
|
|
895
|
+
): {
|
|
896
|
+
entryPrice: BN;
|
|
897
|
+
priceImpact: BN;
|
|
898
|
+
bestPrice: BN;
|
|
899
|
+
worstPrice: BN;
|
|
900
|
+
baseFilled: BN;
|
|
901
|
+
quoteFilled: BN;
|
|
902
|
+
} {
|
|
903
|
+
const takerIsLong = isVariant(direction, 'long');
|
|
904
|
+
|
|
905
|
+
let cumulativeBaseFilled = ZERO;
|
|
906
|
+
let cumulativeQuoteFilled = ZERO;
|
|
907
|
+
|
|
908
|
+
const levels = [...(takerIsLong ? l2.asks : l2.bids)];
|
|
909
|
+
let nextLevel = levels.shift();
|
|
910
|
+
|
|
911
|
+
let bestPrice;
|
|
912
|
+
let worstPrice;
|
|
913
|
+
if (nextLevel) {
|
|
914
|
+
bestPrice = nextLevel.price;
|
|
915
|
+
worstPrice = nextLevel.price;
|
|
916
|
+
} else {
|
|
917
|
+
bestPrice = takerIsLong ? BN_MAX : ZERO;
|
|
918
|
+
worstPrice = bestPrice;
|
|
919
|
+
}
|
|
920
|
+
|
|
921
|
+
if (assetType === 'base') {
|
|
922
|
+
while (!cumulativeBaseFilled.eq(amount) && nextLevel) {
|
|
923
|
+
const price = nextLevel.price;
|
|
924
|
+
const size = nextLevel.size;
|
|
925
|
+
|
|
926
|
+
worstPrice = price;
|
|
927
|
+
|
|
928
|
+
const baseFilled = BN.min(size, amount.sub(cumulativeBaseFilled));
|
|
929
|
+
const quoteFilled = baseFilled.mul(price).div(basePrecision);
|
|
930
|
+
|
|
931
|
+
cumulativeBaseFilled = cumulativeBaseFilled.add(baseFilled);
|
|
932
|
+
cumulativeQuoteFilled = cumulativeQuoteFilled.add(quoteFilled);
|
|
933
|
+
|
|
934
|
+
nextLevel = levels.shift();
|
|
935
|
+
}
|
|
936
|
+
} else {
|
|
937
|
+
while (!cumulativeQuoteFilled.eq(amount) && nextLevel) {
|
|
938
|
+
const price = nextLevel.price;
|
|
939
|
+
const size = nextLevel.size;
|
|
940
|
+
|
|
941
|
+
worstPrice = price;
|
|
942
|
+
|
|
943
|
+
const quoteFilled = BN.min(
|
|
944
|
+
size.mul(price).div(basePrecision),
|
|
945
|
+
amount.sub(cumulativeQuoteFilled)
|
|
946
|
+
);
|
|
947
|
+
const baseFilled = quoteFilled.mul(basePrecision).div(price);
|
|
948
|
+
|
|
949
|
+
cumulativeBaseFilled = cumulativeBaseFilled.add(baseFilled);
|
|
950
|
+
cumulativeQuoteFilled = cumulativeQuoteFilled.add(quoteFilled);
|
|
951
|
+
|
|
952
|
+
nextLevel = levels.shift();
|
|
953
|
+
}
|
|
954
|
+
}
|
|
955
|
+
|
|
956
|
+
const entryPrice = cumulativeQuoteFilled
|
|
957
|
+
.mul(basePrecision)
|
|
958
|
+
.div(cumulativeBaseFilled);
|
|
959
|
+
|
|
960
|
+
const priceImpact = entryPrice
|
|
961
|
+
.sub(bestPrice)
|
|
962
|
+
.mul(PRICE_PRECISION)
|
|
963
|
+
.div(bestPrice)
|
|
964
|
+
.abs();
|
|
965
|
+
|
|
966
|
+
return {
|
|
967
|
+
entryPrice,
|
|
968
|
+
priceImpact,
|
|
969
|
+
bestPrice,
|
|
970
|
+
worstPrice,
|
|
971
|
+
baseFilled: cumulativeBaseFilled,
|
|
972
|
+
quoteFilled: cumulativeQuoteFilled,
|
|
973
|
+
};
|
|
974
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.parseTokenAccount = void 0;
|
|
4
|
+
const spl_token_1 = require("@solana/spl-token");
|
|
5
|
+
const web3_js_1 = require("@solana/web3.js");
|
|
6
|
+
function parseTokenAccount(data) {
|
|
7
|
+
const accountInfo = spl_token_1.AccountLayout.decode(data);
|
|
8
|
+
accountInfo.mint = new web3_js_1.PublicKey(accountInfo.mint);
|
|
9
|
+
accountInfo.owner = new web3_js_1.PublicKey(accountInfo.owner);
|
|
10
|
+
accountInfo.amount = spl_token_1.u64.fromBuffer(accountInfo.amount);
|
|
11
|
+
if (accountInfo.delegateOption === 0) {
|
|
12
|
+
accountInfo.delegate = null;
|
|
13
|
+
// eslint-disable-next-line new-cap
|
|
14
|
+
accountInfo.delegatedAmount = new spl_token_1.u64(0);
|
|
15
|
+
}
|
|
16
|
+
else {
|
|
17
|
+
accountInfo.delegate = new web3_js_1.PublicKey(accountInfo.delegate);
|
|
18
|
+
accountInfo.delegatedAmount = spl_token_1.u64.fromBuffer(accountInfo.delegatedAmount);
|
|
19
|
+
}
|
|
20
|
+
accountInfo.isInitialized = accountInfo.state !== 0;
|
|
21
|
+
accountInfo.isFrozen = accountInfo.state === 2;
|
|
22
|
+
if (accountInfo.isNativeOption === 1) {
|
|
23
|
+
accountInfo.rentExemptReserve = spl_token_1.u64.fromBuffer(accountInfo.isNative);
|
|
24
|
+
accountInfo.isNative = true;
|
|
25
|
+
}
|
|
26
|
+
else {
|
|
27
|
+
accountInfo.rentExemptReserve = null;
|
|
28
|
+
accountInfo.isNative = false;
|
|
29
|
+
}
|
|
30
|
+
if (accountInfo.closeAuthorityOption === 0) {
|
|
31
|
+
accountInfo.closeAuthority = null;
|
|
32
|
+
}
|
|
33
|
+
else {
|
|
34
|
+
accountInfo.closeAuthority = new web3_js_1.PublicKey(accountInfo.closeAuthority);
|
|
35
|
+
}
|
|
36
|
+
return accountInfo;
|
|
37
|
+
}
|
|
38
|
+
exports.parseTokenAccount = parseTokenAccount;
|
package/src/tx/retryTxSender.ts
CHANGED
|
@@ -117,16 +117,26 @@ export class RetryTxSender implements TxSender {
|
|
|
117
117
|
async sendVersionedTransaction(
|
|
118
118
|
tx: VersionedTransaction,
|
|
119
119
|
additionalSigners?: Array<Signer>,
|
|
120
|
-
opts?: ConfirmOptions
|
|
120
|
+
opts?: ConfirmOptions,
|
|
121
|
+
preSigned?: boolean
|
|
121
122
|
): Promise<TxSigAndSlot> {
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
123
|
+
let signedTx;
|
|
124
|
+
if (preSigned) {
|
|
125
|
+
signedTx = tx;
|
|
126
|
+
// @ts-ignore
|
|
127
|
+
} else if (this.provider.wallet.payer) {
|
|
128
|
+
// @ts-ignore
|
|
129
|
+
tx.sign((additionalSigners ?? []).concat(this.provider.wallet.payer));
|
|
130
|
+
signedTx = tx;
|
|
131
|
+
} else {
|
|
132
|
+
additionalSigners
|
|
133
|
+
?.filter((s): s is Signer => s !== undefined)
|
|
134
|
+
.forEach((kp) => {
|
|
135
|
+
tx.sign([kp]);
|
|
136
|
+
});
|
|
137
|
+
// @ts-ignore
|
|
138
|
+
signedTx = await this.provider.wallet.signTransaction(tx);
|
|
139
|
+
}
|
|
130
140
|
|
|
131
141
|
if (opts === undefined) {
|
|
132
142
|
opts = this.provider.opts;
|
package/src/tx/types.ts
CHANGED
package/src/user.ts
CHANGED
|
@@ -297,14 +297,18 @@ export class User {
|
|
|
297
297
|
* @returns : the dust base asset amount (ie, < stepsize)
|
|
298
298
|
* @returns : pnl from settle
|
|
299
299
|
*/
|
|
300
|
-
public
|
|
301
|
-
|
|
302
|
-
|
|
300
|
+
public getPerpPositionWithLPSettle(
|
|
301
|
+
marketIndex: number,
|
|
302
|
+
originalPosition?: PerpPosition
|
|
303
|
+
): [PerpPosition, BN, BN] {
|
|
304
|
+
originalPosition = originalPosition ?? this.getPerpPosition(marketIndex);
|
|
303
305
|
|
|
304
|
-
if (
|
|
305
|
-
return [
|
|
306
|
+
if (originalPosition.lpShares.eq(ZERO)) {
|
|
307
|
+
return [originalPosition, ZERO, ZERO];
|
|
306
308
|
}
|
|
307
309
|
|
|
310
|
+
const position = this.getClonedPosition(originalPosition);
|
|
311
|
+
|
|
308
312
|
const market = this.driftClient.getPerpMarketAccount(position.marketIndex);
|
|
309
313
|
const nShares = position.lpShares;
|
|
310
314
|
|
|
@@ -318,14 +322,11 @@ export class User {
|
|
|
318
322
|
.div(AMM_RESERVE_PRECISION);
|
|
319
323
|
|
|
320
324
|
function sign(v: BN) {
|
|
321
|
-
|
|
322
|
-
v.gte(ZERO).toString()
|
|
323
|
-
];
|
|
324
|
-
return sign;
|
|
325
|
+
return v.isNeg() ? new BN(-1) : new BN(1);
|
|
325
326
|
}
|
|
326
327
|
|
|
327
|
-
function standardize(amount: BN,
|
|
328
|
-
const remainder = amount.abs().mod(
|
|
328
|
+
function standardize(amount: BN, stepSize: BN) {
|
|
329
|
+
const remainder = amount.abs().mod(stepSize).mul(sign(amount));
|
|
329
330
|
const standardizedAmount = amount.sub(remainder);
|
|
330
331
|
return [standardizedAmount, remainder];
|
|
331
332
|
}
|
|
@@ -517,7 +518,9 @@ export class User {
|
|
|
517
518
|
);
|
|
518
519
|
|
|
519
520
|
if (perpPosition.lpShares.gt(ZERO)) {
|
|
520
|
-
perpPosition = this.
|
|
521
|
+
perpPosition = this.getPerpPositionWithLPSettle(
|
|
522
|
+
perpPosition.marketIndex
|
|
523
|
+
)[0];
|
|
521
524
|
}
|
|
522
525
|
|
|
523
526
|
let positionUnrealizedPnl = calculatePositionPNL(
|
|
@@ -1022,9 +1025,8 @@ export class User {
|
|
|
1022
1025
|
perpPosition = this.getClonedPosition(perpPosition);
|
|
1023
1026
|
|
|
1024
1027
|
// settle position
|
|
1025
|
-
const [settledPosition, dustBaa, _] =
|
|
1026
|
-
market.marketIndex
|
|
1027
|
-
);
|
|
1028
|
+
const [settledPosition, dustBaa, _] =
|
|
1029
|
+
this.getPerpPositionWithLPSettle(market.marketIndex);
|
|
1028
1030
|
perpPosition.baseAssetAmount =
|
|
1029
1031
|
settledPosition.baseAssetAmount.add(dustBaa);
|
|
1030
1032
|
perpPosition.quoteAssetAmount = settledPosition.quoteAssetAmount;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.findComputeUnitConsumption = void 0;
|
|
13
|
+
function findComputeUnitConsumption(programId, connection, txSignature, commitment = 'confirmed') {
|
|
14
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
15
|
+
const tx = yield connection.getTransaction(txSignature, { commitment });
|
|
16
|
+
const computeUnits = [];
|
|
17
|
+
const regex = new RegExp(`Program ${programId.toString()} consumed ([0-9]{0,6}) of ([0-9]{0,7}) compute units`);
|
|
18
|
+
tx.meta.logMessages.forEach((logMessage) => {
|
|
19
|
+
const match = logMessage.match(regex);
|
|
20
|
+
if (match && match[1]) {
|
|
21
|
+
computeUnits.push(match[1]);
|
|
22
|
+
}
|
|
23
|
+
});
|
|
24
|
+
return computeUnits;
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
exports.findComputeUnitConsumption = findComputeUnitConsumption;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.promiseTimeout = void 0;
|
|
4
|
+
function promiseTimeout(promise, timeoutMs) {
|
|
5
|
+
let timeoutId;
|
|
6
|
+
const timeoutPromise = new Promise((resolve) => {
|
|
7
|
+
timeoutId = setTimeout(() => resolve(null), timeoutMs);
|
|
8
|
+
});
|
|
9
|
+
return Promise.race([promise, timeoutPromise]).then((result) => {
|
|
10
|
+
clearTimeout(timeoutId);
|
|
11
|
+
return result;
|
|
12
|
+
});
|
|
13
|
+
}
|
|
14
|
+
exports.promiseTimeout = promiseTimeout;
|
package/src/util/tps.js
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.estimateTps = void 0;
|
|
13
|
+
function estimateTps(programId, connection, failed) {
|
|
14
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
15
|
+
let signatures = yield connection.getSignaturesForAddress(programId, undefined, 'finalized');
|
|
16
|
+
if (failed) {
|
|
17
|
+
signatures = signatures.filter((signature) => signature.err);
|
|
18
|
+
}
|
|
19
|
+
const numberOfSignatures = signatures.length;
|
|
20
|
+
if (numberOfSignatures === 0) {
|
|
21
|
+
return 0;
|
|
22
|
+
}
|
|
23
|
+
return (numberOfSignatures /
|
|
24
|
+
(signatures[0].blockTime - signatures[numberOfSignatures - 1].blockTime));
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
exports.estimateTps = estimateTps;
|
package/get_events.ts
DELETED
|
@@ -1,47 +0,0 @@
|
|
|
1
|
-
import { Connection, Keypair, PublicKey } from '@solana/web3.js';
|
|
2
|
-
import {
|
|
3
|
-
configs,
|
|
4
|
-
DriftClient,
|
|
5
|
-
Wallet,
|
|
6
|
-
} from "@drift-labs/sdk";
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
async function main() {
|
|
10
|
-
|
|
11
|
-
const driftConfig = configs['mainnet-beta'];
|
|
12
|
-
const connection = new Connection('https://api.mainnet-beta.solana.com');
|
|
13
|
-
|
|
14
|
-
const driftClient = new DriftClient({
|
|
15
|
-
connection: connection,
|
|
16
|
-
wallet: new Wallet(new Keypair()),
|
|
17
|
-
programID: new PublicKey(driftConfig.DRIFT_PROGRAM_ID),
|
|
18
|
-
userStats: true,
|
|
19
|
-
env: 'mainnet-beta',
|
|
20
|
-
});
|
|
21
|
-
console.log(`driftClientSubscribed: ${await driftClient.subscribe()}`);
|
|
22
|
-
|
|
23
|
-
const txHash = "3gvGQufckXGHrFDv4dNWEXuXKRMy3NZkKHMyFrAhLoYScaXXTGCp9vq58kWkfyJ8oDYZrz4bTyGayjUy9PKigeLS";
|
|
24
|
-
|
|
25
|
-
const tx = await driftClient.connection.getParsedTransaction(txHash, {
|
|
26
|
-
commitment: "confirmed",
|
|
27
|
-
maxSupportedTransactionVersion: 0,
|
|
28
|
-
});
|
|
29
|
-
|
|
30
|
-
let logIdx = 0;
|
|
31
|
-
// @ts-ignore
|
|
32
|
-
for (const event of driftClient.program._events._eventParser.parseLogs(tx!.meta!.logMessages)) {
|
|
33
|
-
console.log("----------------------------------------");
|
|
34
|
-
console.log(`Log ${logIdx++}`);
|
|
35
|
-
console.log("----------------------------------------");
|
|
36
|
-
console.log(`${JSON.stringify(event, null, 2)}`);
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
console.log("========================================");
|
|
40
|
-
console.log("Raw transaction logs");
|
|
41
|
-
console.log("========================================");
|
|
42
|
-
console.log(JSON.stringify(tx!.meta!.logMessages, null, 2));
|
|
43
|
-
|
|
44
|
-
process.exit(0);
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
main().catch(console.error);
|