@drift-labs/sdk 2.60.0-beta.1 → 2.60.0-beta.10
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/VERSION +1 -1
- package/lib/constants/perpMarkets.js +10 -0
- package/lib/constants/spotMarkets.d.ts +1 -0
- package/lib/constants/spotMarkets.js +13 -0
- package/lib/driftClient.js +13 -4
- package/lib/index.d.ts +1 -0
- package/lib/index.js +1 -0
- package/lib/math/spotMarket.js +2 -1
- package/lib/math/superStake.d.ts +12 -16
- package/lib/math/superStake.js +29 -38
- package/lib/math/utils.d.ts +7 -0
- package/lib/math/utils.js +26 -1
- package/lib/user.d.ts +3 -2
- package/lib/user.js +50 -6
- package/package.json +1 -1
- package/src/constants/perpMarkets.ts +10 -0
- package/src/constants/spotMarkets.ts +20 -0
- package/src/driftClient.ts +11 -4
- package/src/index.ts +1 -0
- package/src/math/spotMarket.ts +2 -1
- package/src/math/superStake.ts +51 -61
- package/src/math/utils.ts +23 -0
- package/src/user.ts +105 -8
- package/tests/amm/test.ts +6 -1
- package/tests/bn/test.ts +15 -1
- package/examples/phoenix.ts +0 -66
- package/lib/examples/loadDlob.d.ts +0 -1
- package/lib/examples/loadDlob.js +0 -59
- package/lib/examples/makeTradeExample.d.ts +0 -2
- package/lib/examples/makeTradeExample.js +0 -83
- package/src/examples/loadDlob.ts +0 -86
- package/src/examples/makeTradeExample.ts +0 -162
package/src/math/superStake.ts
CHANGED
|
@@ -267,66 +267,59 @@ export async function findBestLstSuperStakeIxs({
|
|
|
267
267
|
}
|
|
268
268
|
|
|
269
269
|
export type JITO_SOL_METRICS_ENDPOINT_RESPONSE = {
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
date: string;
|
|
285
|
-
}[];
|
|
286
|
-
};
|
|
287
|
-
};
|
|
270
|
+
tvl: {
|
|
271
|
+
// TVL in SOL, BN
|
|
272
|
+
data: number;
|
|
273
|
+
date: string;
|
|
274
|
+
}[];
|
|
275
|
+
supply: {
|
|
276
|
+
// jitoSOL supply
|
|
277
|
+
data: number;
|
|
278
|
+
date: string;
|
|
279
|
+
}[];
|
|
280
|
+
apy: {
|
|
281
|
+
data: number;
|
|
282
|
+
date: string;
|
|
283
|
+
}[];
|
|
288
284
|
};
|
|
289
285
|
|
|
290
|
-
|
|
286
|
+
/**
|
|
287
|
+
* Removes hours, minutes, seconds from a date, and returns the ISO string value (with milliseconds trimmed from the output (required by Jito API))
|
|
288
|
+
* @param inDate
|
|
289
|
+
* @returns
|
|
290
|
+
*/
|
|
291
|
+
const getNormalizedDateString = (inDate: Date) => {
|
|
292
|
+
const date = new Date(inDate.getTime());
|
|
293
|
+
date.setUTCHours(0, 0, 0, 0);
|
|
294
|
+
return date.toISOString().slice(0, 19) + 'Z';
|
|
295
|
+
};
|
|
296
|
+
|
|
297
|
+
const get30DAgo = () => {
|
|
298
|
+
const date = new Date(Date.now() - 30 * 24 * 60 * 60 * 1000);
|
|
299
|
+
return date;
|
|
300
|
+
};
|
|
291
301
|
|
|
292
302
|
export async function fetchJitoSolMetrics() {
|
|
293
|
-
const res = await fetch(
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
bucketType: 'DAILY',
|
|
299
|
-
rangeFilter: {
|
|
300
|
-
start: JITO_SOL_START_DATE,
|
|
301
|
-
end: new Date().toISOString(),
|
|
302
|
-
},
|
|
303
|
-
sortBy: {
|
|
304
|
-
order: 'ASC',
|
|
305
|
-
field: 'BLOCK_TIME',
|
|
306
|
-
},
|
|
307
|
-
},
|
|
303
|
+
const res = await fetch(
|
|
304
|
+
'https://kobe.mainnet.jito.network/api/v1/stake_pool_stats',
|
|
305
|
+
{
|
|
306
|
+
headers: {
|
|
307
|
+
'Content-Type': 'application/json',
|
|
308
308
|
},
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
}
|
|
324
|
-
}
|
|
325
|
-
}
|
|
326
|
-
`,
|
|
327
|
-
}),
|
|
328
|
-
method: 'POST',
|
|
329
|
-
});
|
|
309
|
+
body: JSON.stringify({
|
|
310
|
+
bucket_type: 'Daily',
|
|
311
|
+
range_filter: {
|
|
312
|
+
start: getNormalizedDateString(get30DAgo()),
|
|
313
|
+
end: getNormalizedDateString(new Date()),
|
|
314
|
+
},
|
|
315
|
+
sort_by: {
|
|
316
|
+
order: 'Asc',
|
|
317
|
+
field: 'BlockTime',
|
|
318
|
+
},
|
|
319
|
+
}),
|
|
320
|
+
method: 'POST',
|
|
321
|
+
}
|
|
322
|
+
);
|
|
330
323
|
|
|
331
324
|
const data: JITO_SOL_METRICS_ENDPOINT_RESPONSE = await res.json();
|
|
332
325
|
|
|
@@ -396,14 +389,11 @@ const getJitoSolHistoricalPriceMap = async (timestamps: number[]) => {
|
|
|
396
389
|
const jitoSolHistoricalPriceMap = new Map<number, number>();
|
|
397
390
|
const jitoSolHistoricalPriceInSol = [];
|
|
398
391
|
|
|
399
|
-
for (let i = 0; i < data.
|
|
400
|
-
const priceInSol =
|
|
401
|
-
data.data.getStakePoolStats.tvl[i].data /
|
|
402
|
-
10 ** 9 /
|
|
403
|
-
data.data.getStakePoolStats.supply[i].data;
|
|
392
|
+
for (let i = 0; i < data.supply.length; i++) {
|
|
393
|
+
const priceInSol = data.tvl[i].data / 10 ** 9 / data.supply[i].data;
|
|
404
394
|
jitoSolHistoricalPriceInSol.push({
|
|
405
395
|
price: priceInSol,
|
|
406
|
-
ts: data.
|
|
396
|
+
ts: data.tvl[i].date,
|
|
407
397
|
});
|
|
408
398
|
}
|
|
409
399
|
|
package/src/math/utils.ts
CHANGED
|
@@ -95,3 +95,26 @@ export const checkSameDate = (dateString1: string, dateString2: string) => {
|
|
|
95
95
|
|
|
96
96
|
return isSameDate;
|
|
97
97
|
};
|
|
98
|
+
|
|
99
|
+
export function isBNSafe(number: number): boolean {
|
|
100
|
+
return number <= 0x1fffffffffffff;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Converts a number to BN makes sure the number is safe to convert to BN (that it does not overflow number after multiplying by precision)
|
|
105
|
+
* @param number the number to convert to BN
|
|
106
|
+
* @param precision the BN precision to use (i.e. QUOTE_PRECISION and BASE_PRECISION from drift sdk)
|
|
107
|
+
*/
|
|
108
|
+
export function numberToSafeBN(number: number, precision: BN): BN {
|
|
109
|
+
// check if number has decimals
|
|
110
|
+
const candidate = number * precision.toNumber();
|
|
111
|
+
if (isBNSafe(candidate)) {
|
|
112
|
+
return new BN(candidate);
|
|
113
|
+
} else {
|
|
114
|
+
if (number % 1 === 0) {
|
|
115
|
+
return new BN(number.toString()).mul(precision);
|
|
116
|
+
} else {
|
|
117
|
+
return new BN(number).mul(precision);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
}
|
package/src/user.ts
CHANGED
|
@@ -60,6 +60,7 @@ import {
|
|
|
60
60
|
sigNum,
|
|
61
61
|
SpotBalanceType,
|
|
62
62
|
SpotMarketAccount,
|
|
63
|
+
standardizeBaseAssetAmount,
|
|
63
64
|
} from '.';
|
|
64
65
|
import {
|
|
65
66
|
calculateAssetWeight,
|
|
@@ -1973,20 +1974,43 @@ export class User {
|
|
|
1973
1974
|
*/
|
|
1974
1975
|
public liquidationPrice(
|
|
1975
1976
|
marketIndex: number,
|
|
1976
|
-
positionBaseSizeChange: BN = ZERO
|
|
1977
|
+
positionBaseSizeChange: BN = ZERO,
|
|
1978
|
+
estimatedEntryPrice: BN = ZERO
|
|
1977
1979
|
): BN {
|
|
1978
1980
|
const totalCollateral = this.getTotalCollateral('Maintenance');
|
|
1979
1981
|
const maintenanceMarginRequirement = this.getMaintenanceMarginRequirement();
|
|
1980
|
-
|
|
1982
|
+
let freeCollateral = BN.max(
|
|
1981
1983
|
ZERO,
|
|
1982
1984
|
totalCollateral.sub(maintenanceMarginRequirement)
|
|
1983
1985
|
);
|
|
1984
1986
|
|
|
1987
|
+
const oracle =
|
|
1988
|
+
this.driftClient.getPerpMarketAccount(marketIndex).amm.oracle;
|
|
1989
|
+
|
|
1990
|
+
const oraclePrice =
|
|
1991
|
+
this.driftClient.getOracleDataForPerpMarket(marketIndex).price;
|
|
1992
|
+
|
|
1985
1993
|
const market = this.driftClient.getPerpMarketAccount(marketIndex);
|
|
1986
1994
|
const currentPerpPosition =
|
|
1987
1995
|
this.getPerpPositionWithLPSettle(marketIndex, undefined, true)[0] ||
|
|
1988
1996
|
this.getEmptyPosition(marketIndex);
|
|
1989
1997
|
|
|
1998
|
+
positionBaseSizeChange = standardizeBaseAssetAmount(
|
|
1999
|
+
positionBaseSizeChange,
|
|
2000
|
+
market.amm.orderStepSize
|
|
2001
|
+
);
|
|
2002
|
+
|
|
2003
|
+
const freeCollateralChangeFromNewPosition =
|
|
2004
|
+
this.calculateEntriesEffectOnFreeCollateral(
|
|
2005
|
+
market,
|
|
2006
|
+
oraclePrice,
|
|
2007
|
+
currentPerpPosition,
|
|
2008
|
+
positionBaseSizeChange,
|
|
2009
|
+
estimatedEntryPrice
|
|
2010
|
+
);
|
|
2011
|
+
|
|
2012
|
+
freeCollateral = freeCollateral.add(freeCollateralChangeFromNewPosition);
|
|
2013
|
+
|
|
1990
2014
|
let freeCollateralDelta = this.calculateFreeCollateralDeltaForPerp(
|
|
1991
2015
|
market,
|
|
1992
2016
|
currentPerpPosition,
|
|
@@ -1997,8 +2021,6 @@ export class User {
|
|
|
1997
2021
|
return new BN(-1);
|
|
1998
2022
|
}
|
|
1999
2023
|
|
|
2000
|
-
const oracle =
|
|
2001
|
-
this.driftClient.getPerpMarketAccount(marketIndex).amm.oracle;
|
|
2002
2024
|
const spotMarketWithSameOracle = this.driftClient
|
|
2003
2025
|
.getSpotMarketAccounts()
|
|
2004
2026
|
.find((market) => market.oracle.equals(oracle));
|
|
@@ -2031,8 +2053,6 @@ export class User {
|
|
|
2031
2053
|
return new BN(-1);
|
|
2032
2054
|
}
|
|
2033
2055
|
|
|
2034
|
-
const oraclePrice =
|
|
2035
|
-
this.driftClient.getOracleDataForPerpMarket(marketIndex).price;
|
|
2036
2056
|
const liqPriceDelta = freeCollateral
|
|
2037
2057
|
.mul(QUOTE_PRECISION)
|
|
2038
2058
|
.div(freeCollateralDelta);
|
|
@@ -2046,6 +2066,78 @@ export class User {
|
|
|
2046
2066
|
return liqPrice;
|
|
2047
2067
|
}
|
|
2048
2068
|
|
|
2069
|
+
calculateEntriesEffectOnFreeCollateral(
|
|
2070
|
+
market: PerpMarketAccount,
|
|
2071
|
+
oraclePrice: BN,
|
|
2072
|
+
perpPosition: PerpPosition,
|
|
2073
|
+
positionBaseSizeChange: BN,
|
|
2074
|
+
estimatedEntryPrice: BN
|
|
2075
|
+
): BN {
|
|
2076
|
+
let freeCollateralChange = ZERO;
|
|
2077
|
+
|
|
2078
|
+
// update free collateral to account for change in pnl from new position
|
|
2079
|
+
if (!estimatedEntryPrice.eq(ZERO) && !positionBaseSizeChange.eq(ZERO)) {
|
|
2080
|
+
const costBasis = oraclePrice
|
|
2081
|
+
.mul(positionBaseSizeChange.abs())
|
|
2082
|
+
.div(BASE_PRECISION);
|
|
2083
|
+
const newPositionValue = estimatedEntryPrice
|
|
2084
|
+
.mul(positionBaseSizeChange.abs())
|
|
2085
|
+
.div(BASE_PRECISION);
|
|
2086
|
+
if (positionBaseSizeChange.gt(ZERO)) {
|
|
2087
|
+
freeCollateralChange = costBasis.sub(newPositionValue);
|
|
2088
|
+
} else {
|
|
2089
|
+
freeCollateralChange = newPositionValue.sub(costBasis);
|
|
2090
|
+
}
|
|
2091
|
+
|
|
2092
|
+
// assume worst fee tier
|
|
2093
|
+
const takerFeeTier =
|
|
2094
|
+
this.driftClient.getStateAccount().perpFeeStructure.feeTiers[0];
|
|
2095
|
+
const takerFee = newPositionValue
|
|
2096
|
+
.muln(takerFeeTier.feeNumerator)
|
|
2097
|
+
.divn(takerFeeTier.feeDenominator);
|
|
2098
|
+
freeCollateralChange = freeCollateralChange.sub(takerFee);
|
|
2099
|
+
}
|
|
2100
|
+
|
|
2101
|
+
const worstCaseBaseAssetAmount =
|
|
2102
|
+
calculateWorstCaseBaseAssetAmount(perpPosition);
|
|
2103
|
+
|
|
2104
|
+
const marginRatioBefore = calculateMarketMarginRatio(
|
|
2105
|
+
market,
|
|
2106
|
+
worstCaseBaseAssetAmount.abs(),
|
|
2107
|
+
'Maintenance'
|
|
2108
|
+
);
|
|
2109
|
+
|
|
2110
|
+
const newWorstCaseBaseAssetAmount = worstCaseBaseAssetAmount.add(
|
|
2111
|
+
positionBaseSizeChange
|
|
2112
|
+
);
|
|
2113
|
+
|
|
2114
|
+
const newMarginRatio = calculateMarketMarginRatio(
|
|
2115
|
+
market,
|
|
2116
|
+
newWorstCaseBaseAssetAmount.abs(),
|
|
2117
|
+
'Maintenance'
|
|
2118
|
+
);
|
|
2119
|
+
|
|
2120
|
+
// update free collateral to account for change in margin ratio from position change
|
|
2121
|
+
freeCollateralChange = freeCollateralChange.sub(
|
|
2122
|
+
worstCaseBaseAssetAmount
|
|
2123
|
+
.mul(oraclePrice)
|
|
2124
|
+
.div(BASE_PRECISION)
|
|
2125
|
+
.mul(new BN(newMarginRatio - marginRatioBefore))
|
|
2126
|
+
.div(MARGIN_PRECISION)
|
|
2127
|
+
);
|
|
2128
|
+
|
|
2129
|
+
// update free collateral to account for new margin requirement from position change
|
|
2130
|
+
freeCollateralChange = freeCollateralChange.sub(
|
|
2131
|
+
positionBaseSizeChange
|
|
2132
|
+
.mul(oraclePrice)
|
|
2133
|
+
.div(BASE_PRECISION)
|
|
2134
|
+
.mul(new BN(newMarginRatio))
|
|
2135
|
+
.div(MARGIN_PRECISION)
|
|
2136
|
+
);
|
|
2137
|
+
|
|
2138
|
+
return freeCollateralChange;
|
|
2139
|
+
}
|
|
2140
|
+
|
|
2049
2141
|
calculateFreeCollateralDeltaForPerp(
|
|
2050
2142
|
market: PerpMarketAccount,
|
|
2051
2143
|
perpPosition: PerpPosition,
|
|
@@ -2142,7 +2234,8 @@ export class User {
|
|
|
2142
2234
|
*/
|
|
2143
2235
|
public liquidationPriceAfterClose(
|
|
2144
2236
|
positionMarketIndex: number,
|
|
2145
|
-
closeQuoteAmount: BN
|
|
2237
|
+
closeQuoteAmount: BN,
|
|
2238
|
+
estimatedEntryPrice: BN = ZERO
|
|
2146
2239
|
): BN {
|
|
2147
2240
|
const currentPosition =
|
|
2148
2241
|
this.getPerpPositionWithLPSettle(
|
|
@@ -2161,7 +2254,11 @@ export class User {
|
|
|
2161
2254
|
)
|
|
2162
2255
|
.neg();
|
|
2163
2256
|
|
|
2164
|
-
return this.liquidationPrice(
|
|
2257
|
+
return this.liquidationPrice(
|
|
2258
|
+
positionMarketIndex,
|
|
2259
|
+
closeBaseAmount,
|
|
2260
|
+
estimatedEntryPrice
|
|
2261
|
+
);
|
|
2165
2262
|
}
|
|
2166
2263
|
|
|
2167
2264
|
/**
|
package/tests/amm/test.ts
CHANGED
|
@@ -1140,7 +1140,12 @@ describe('AMM Tests', () => {
|
|
|
1140
1140
|
|
|
1141
1141
|
mockAmm.lastOracleConfPct = new BN(150000);
|
|
1142
1142
|
const reservePrice = new BN(13.553 * PRICE_PRECISION.toNumber());
|
|
1143
|
-
const newConfPct = getNewOracleConfPct(
|
|
1143
|
+
const newConfPct = getNewOracleConfPct(
|
|
1144
|
+
mockAmm,
|
|
1145
|
+
oraclePriceData,
|
|
1146
|
+
reservePrice,
|
|
1147
|
+
now
|
|
1148
|
+
);
|
|
1144
1149
|
console.log('newConfPct:', newConfPct.toString());
|
|
1145
1150
|
|
|
1146
1151
|
assert(
|
package/tests/bn/test.ts
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
import { BN } from '../../src/index';
|
|
1
|
+
import { BN, numberToSafeBN } from '../../src/index';
|
|
2
2
|
import { expect } from 'chai';
|
|
3
3
|
import { BigNum } from '../../src/factory/bigNum';
|
|
4
4
|
import {
|
|
5
5
|
AMM_RESERVE_PRECISION_EXP,
|
|
6
|
+
BASE_PRECISION,
|
|
6
7
|
BASE_PRECISION_EXP,
|
|
7
8
|
TEN_THOUSAND,
|
|
8
9
|
} from '../../src/constants/numericConstants';
|
|
@@ -324,4 +325,17 @@ describe('BigNum Tests', () => {
|
|
|
324
325
|
const val6 = BigNum.from('0', 5);
|
|
325
326
|
expect(val6.toRounded(3).print()).to.equal('0.00000');
|
|
326
327
|
});
|
|
328
|
+
|
|
329
|
+
it('test numberToSafeBN', async () => {
|
|
330
|
+
expect(
|
|
331
|
+
numberToSafeBN(32445073.479281776, BASE_PRECISION).toString()
|
|
332
|
+
).to.equal(new BN('32445073000000000').toString());
|
|
333
|
+
expect(
|
|
334
|
+
// eslint-disable-next-line @typescript-eslint/no-loss-of-precision
|
|
335
|
+
numberToSafeBN(9999999999111111111, BASE_PRECISION).toString()
|
|
336
|
+
).to.equal(new BN('9999999999111110000000000000').toString());
|
|
337
|
+
expect(numberToSafeBN(123, BASE_PRECISION).toString()).to.equal(
|
|
338
|
+
new BN('123000000000').toString()
|
|
339
|
+
);
|
|
340
|
+
});
|
|
327
341
|
});
|
package/examples/phoenix.ts
DELETED
|
@@ -1,66 +0,0 @@
|
|
|
1
|
-
import { Connection, PublicKey } from '@solana/web3.js';
|
|
2
|
-
import {
|
|
3
|
-
BASE_PRECISION,
|
|
4
|
-
L2Level,
|
|
5
|
-
PRICE_PRECISION,
|
|
6
|
-
PhoenixSubscriber,
|
|
7
|
-
} from '../src';
|
|
8
|
-
import { PROGRAM_ID } from '@ellipsis-labs/phoenix-sdk';
|
|
9
|
-
|
|
10
|
-
export async function listenToBook(): Promise<void> {
|
|
11
|
-
const connection = new Connection('https://api.mainnet-beta.solana.com');
|
|
12
|
-
|
|
13
|
-
for (const market of [
|
|
14
|
-
'4DoNfFBfF7UokCC2FQzriy7yHK6DY6NVdYpuekQ5pRgg', // SOL/USDC
|
|
15
|
-
'Ew3vFDdtdGrknJAVVfraxCA37uNJtimXYPY4QjnfhFHH', // ETH/USDC
|
|
16
|
-
'2sTMN9A1D1qeZLF95XQgJCUPiKe5DiV52jLfZGqMP46m', // PYTH/USDC
|
|
17
|
-
'BRLLmdtPGuuFn3BU6orYw4KHaohAEptBToi3dwRUnHQZ', // JTO/USDC
|
|
18
|
-
]) {
|
|
19
|
-
const phoenixSubscriber = new PhoenixSubscriber({
|
|
20
|
-
connection,
|
|
21
|
-
programId: PROGRAM_ID,
|
|
22
|
-
marketAddress: new PublicKey(market),
|
|
23
|
-
accountSubscription: {
|
|
24
|
-
type: 'websocket',
|
|
25
|
-
},
|
|
26
|
-
});
|
|
27
|
-
|
|
28
|
-
await phoenixSubscriber.subscribe();
|
|
29
|
-
|
|
30
|
-
const bids = phoenixSubscriber.getL2Levels('bids');
|
|
31
|
-
const asks = phoenixSubscriber.getL2Levels('asks');
|
|
32
|
-
let bid: L2Level | null = null;
|
|
33
|
-
for (const b of bids) {
|
|
34
|
-
bid = b;
|
|
35
|
-
break;
|
|
36
|
-
}
|
|
37
|
-
let ask: L2Level | null = null;
|
|
38
|
-
for (const a of asks) {
|
|
39
|
-
ask = a;
|
|
40
|
-
break;
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
console.log('market', market);
|
|
44
|
-
console.log(
|
|
45
|
-
(bid?.size.toNumber() || 0) / BASE_PRECISION.toNumber(),
|
|
46
|
-
(bid?.price.toNumber() || 0) / PRICE_PRECISION.toNumber(),
|
|
47
|
-
'@',
|
|
48
|
-
(ask?.price.toNumber() || (1 << 53) - 1) / PRICE_PRECISION.toNumber(),
|
|
49
|
-
(ask?.size.toNumber() || 0) / BASE_PRECISION.toNumber()
|
|
50
|
-
);
|
|
51
|
-
console.log();
|
|
52
|
-
|
|
53
|
-
await phoenixSubscriber.unsubscribe();
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
(async function () {
|
|
58
|
-
try {
|
|
59
|
-
await listenToBook();
|
|
60
|
-
} catch (err) {
|
|
61
|
-
console.log('Error: ', err);
|
|
62
|
-
process.exit(1);
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
process.exit(0);
|
|
66
|
-
})();
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
package/lib/examples/loadDlob.js
DELETED
|
@@ -1,59 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
const anchor_1 = require("@coral-xyz/anchor");
|
|
4
|
-
const __1 = require("..");
|
|
5
|
-
const web3_js_1 = require("@solana/web3.js");
|
|
6
|
-
const __2 = require("..");
|
|
7
|
-
const env = 'mainnet-beta';
|
|
8
|
-
const main = async () => {
|
|
9
|
-
// Initialize Drift SDK
|
|
10
|
-
const sdkConfig = (0, __2.initialize)({ env });
|
|
11
|
-
// Set up the Wallet and Provider
|
|
12
|
-
const privateKey = process.env.BOT_PRIVATE_KEY; // stored as an array string
|
|
13
|
-
const keypair = web3_js_1.Keypair.fromSecretKey(Uint8Array.from(JSON.parse(privateKey)));
|
|
14
|
-
const wallet = new __1.Wallet(keypair);
|
|
15
|
-
// Set up the Connection
|
|
16
|
-
const rpcAddress = process.env.RPC_ADDRESS; // can use: https://api.devnet.solana.com for devnet; https://api.mainnet-beta.solana.com for mainnet;
|
|
17
|
-
const connection = new web3_js_1.Connection(rpcAddress);
|
|
18
|
-
// Set up the Provider
|
|
19
|
-
const provider = new anchor_1.AnchorProvider(connection,
|
|
20
|
-
// @ts-ignore
|
|
21
|
-
wallet, anchor_1.AnchorProvider.defaultOptions());
|
|
22
|
-
// Set up the Drift Clearing House
|
|
23
|
-
const driftPublicKey = new web3_js_1.PublicKey(sdkConfig.DRIFT_PROGRAM_ID);
|
|
24
|
-
const bulkAccountLoader = new __2.BulkAccountLoader(connection, 'confirmed', 1000);
|
|
25
|
-
const driftClient = new __2.DriftClient({
|
|
26
|
-
connection,
|
|
27
|
-
wallet: provider.wallet,
|
|
28
|
-
programID: driftPublicKey,
|
|
29
|
-
...(0, __2.getMarketsAndOraclesForSubscription)(env),
|
|
30
|
-
accountSubscription: {
|
|
31
|
-
type: 'polling',
|
|
32
|
-
accountLoader: bulkAccountLoader,
|
|
33
|
-
},
|
|
34
|
-
});
|
|
35
|
-
console.log('Subscribing drift client...');
|
|
36
|
-
await driftClient.subscribe();
|
|
37
|
-
console.log('Loading user map...');
|
|
38
|
-
const userMap = new __1.UserMap({
|
|
39
|
-
driftClient,
|
|
40
|
-
subscriptionConfig: {
|
|
41
|
-
type: 'websocket',
|
|
42
|
-
commitment: 'processed',
|
|
43
|
-
},
|
|
44
|
-
skipInitialLoad: false,
|
|
45
|
-
includeIdle: false,
|
|
46
|
-
});
|
|
47
|
-
// fetches all users and subscribes for updates
|
|
48
|
-
await userMap.subscribe();
|
|
49
|
-
console.log('Loading dlob from user map...');
|
|
50
|
-
const slot = await driftClient.connection.getSlot();
|
|
51
|
-
const dlob = await userMap.getDLOB(slot);
|
|
52
|
-
console.log('number of orders', dlob.getDLOBOrders().length);
|
|
53
|
-
dlob.clear();
|
|
54
|
-
console.log('Unsubscribing users...');
|
|
55
|
-
await userMap.unsubscribe();
|
|
56
|
-
console.log('Unsubscribing drift client...');
|
|
57
|
-
await driftClient.unsubscribe();
|
|
58
|
-
};
|
|
59
|
-
main();
|
|
@@ -1,83 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.getTokenAddress = void 0;
|
|
4
|
-
const anchor_1 = require("@coral-xyz/anchor");
|
|
5
|
-
const __1 = require("..");
|
|
6
|
-
const spl_token_1 = require("@solana/spl-token");
|
|
7
|
-
const web3_js_1 = require("@solana/web3.js");
|
|
8
|
-
const __2 = require("..");
|
|
9
|
-
const spotMarkets_1 = require("../constants/spotMarkets");
|
|
10
|
-
const getTokenAddress = (mintAddress, userPubKey) => {
|
|
11
|
-
return (0, spl_token_1.getAssociatedTokenAddress)(new web3_js_1.PublicKey(mintAddress), new web3_js_1.PublicKey(userPubKey));
|
|
12
|
-
};
|
|
13
|
-
exports.getTokenAddress = getTokenAddress;
|
|
14
|
-
const env = 'devnet';
|
|
15
|
-
const main = async () => {
|
|
16
|
-
// Initialize Drift SDK
|
|
17
|
-
const sdkConfig = (0, __2.initialize)({ env });
|
|
18
|
-
// Set up the Wallet and Provider
|
|
19
|
-
const privateKey = process.env.BOT_PRIVATE_KEY; // stored as an array string
|
|
20
|
-
const keypair = web3_js_1.Keypair.fromSecretKey(Uint8Array.from(JSON.parse(privateKey)));
|
|
21
|
-
const wallet = new __1.Wallet(keypair);
|
|
22
|
-
// Set up the Connection
|
|
23
|
-
const rpcAddress = process.env.RPC_ADDRESS; // can use: https://api.devnet.solana.com for devnet; https://api.mainnet-beta.solana.com for mainnet;
|
|
24
|
-
const connection = new web3_js_1.Connection(rpcAddress);
|
|
25
|
-
// Set up the Provider
|
|
26
|
-
const provider = new anchor_1.AnchorProvider(connection,
|
|
27
|
-
// @ts-ignore
|
|
28
|
-
wallet, anchor_1.AnchorProvider.defaultOptions());
|
|
29
|
-
// Check SOL Balance
|
|
30
|
-
const lamportsBalance = await connection.getBalance(wallet.publicKey);
|
|
31
|
-
console.log('SOL balance:', lamportsBalance / 10 ** 9);
|
|
32
|
-
// Misc. other things to set up
|
|
33
|
-
const usdcTokenAddress = await (0, exports.getTokenAddress)(sdkConfig.USDC_MINT_ADDRESS, wallet.publicKey.toString());
|
|
34
|
-
// Set up the Drift Clearing House
|
|
35
|
-
const driftPublicKey = new web3_js_1.PublicKey(sdkConfig.DRIFT_PROGRAM_ID);
|
|
36
|
-
const bulkAccountLoader = new __2.BulkAccountLoader(connection, 'confirmed', 1000);
|
|
37
|
-
const driftClient = new __2.DriftClient({
|
|
38
|
-
connection,
|
|
39
|
-
wallet: provider.wallet,
|
|
40
|
-
programID: driftPublicKey,
|
|
41
|
-
...(0, __2.getMarketsAndOraclesForSubscription)(env),
|
|
42
|
-
accountSubscription: {
|
|
43
|
-
type: 'polling',
|
|
44
|
-
accountLoader: bulkAccountLoader,
|
|
45
|
-
},
|
|
46
|
-
});
|
|
47
|
-
await driftClient.subscribe();
|
|
48
|
-
// Set up user client
|
|
49
|
-
const user = new __2.User({
|
|
50
|
-
driftClient: driftClient,
|
|
51
|
-
userAccountPublicKey: await driftClient.getUserAccountPublicKey(),
|
|
52
|
-
accountSubscription: {
|
|
53
|
-
type: 'polling',
|
|
54
|
-
accountLoader: bulkAccountLoader,
|
|
55
|
-
},
|
|
56
|
-
});
|
|
57
|
-
//// Check if user account exists for the current wallet
|
|
58
|
-
const userAccountExists = await user.exists();
|
|
59
|
-
if (!userAccountExists) {
|
|
60
|
-
//// Create a Clearing House account by Depositing some USDC ($10,000 in this case)
|
|
61
|
-
const depositAmount = new anchor_1.BN(10000).mul(__2.QUOTE_PRECISION);
|
|
62
|
-
await driftClient.initializeUserAccountAndDepositCollateral(depositAmount, await (0, exports.getTokenAddress)(usdcTokenAddress.toString(), wallet.publicKey.toString()), spotMarkets_1.SpotMarkets['devnet'][0].marketIndex);
|
|
63
|
-
}
|
|
64
|
-
await user.subscribe();
|
|
65
|
-
// Get current price
|
|
66
|
-
const solMarketInfo = sdkConfig.PERP_MARKETS.find((market) => market.baseAssetSymbol === 'SOL');
|
|
67
|
-
const marketIndex = solMarketInfo.marketIndex;
|
|
68
|
-
const [bid, ask] = (0, __1.calculateBidAskPrice)(driftClient.getPerpMarketAccount(marketIndex).amm, driftClient.getOracleDataForPerpMarket(marketIndex));
|
|
69
|
-
const formattedBidPrice = (0, __2.convertToNumber)(bid, __2.PRICE_PRECISION);
|
|
70
|
-
const formattedAskPrice = (0, __2.convertToNumber)(ask, __2.PRICE_PRECISION);
|
|
71
|
-
console.log(`Current amm bid and ask price are $${formattedBidPrice} and $${formattedAskPrice}`);
|
|
72
|
-
// Estimate the slippage for a $5000 LONG trade
|
|
73
|
-
const solMarketAccount = driftClient.getPerpMarketAccount(solMarketInfo.marketIndex);
|
|
74
|
-
const slippage = (0, __2.convertToNumber)((0, __2.calculateTradeSlippage)(__2.PositionDirection.LONG, new anchor_1.BN(1).mul(__1.BASE_PRECISION), solMarketAccount, 'base', driftClient.getOracleDataForPerpMarket(solMarketInfo.marketIndex))[0], __2.PRICE_PRECISION);
|
|
75
|
-
console.log(`Slippage for a 1 SOL-PERP would be $${slippage}`);
|
|
76
|
-
await driftClient.placePerpOrder((0, __1.getMarketOrderParams)({
|
|
77
|
-
baseAssetAmount: new anchor_1.BN(1).mul(__1.BASE_PRECISION),
|
|
78
|
-
direction: __2.PositionDirection.LONG,
|
|
79
|
-
marketIndex: solMarketAccount.marketIndex,
|
|
80
|
-
}));
|
|
81
|
-
console.log(`Placed a 1 SOL-PERP LONG order`);
|
|
82
|
-
};
|
|
83
|
-
main();
|
package/src/examples/loadDlob.ts
DELETED
|
@@ -1,86 +0,0 @@
|
|
|
1
|
-
import { AnchorProvider } from '@coral-xyz/anchor';
|
|
2
|
-
import { UserMap, Wallet } from '..';
|
|
3
|
-
import { Connection, Keypair, PublicKey } from '@solana/web3.js';
|
|
4
|
-
import {
|
|
5
|
-
DriftClient,
|
|
6
|
-
initialize,
|
|
7
|
-
BulkAccountLoader,
|
|
8
|
-
getMarketsAndOraclesForSubscription,
|
|
9
|
-
} from '..';
|
|
10
|
-
|
|
11
|
-
const env = 'mainnet-beta';
|
|
12
|
-
|
|
13
|
-
const main = async () => {
|
|
14
|
-
// Initialize Drift SDK
|
|
15
|
-
const sdkConfig = initialize({ env });
|
|
16
|
-
|
|
17
|
-
// Set up the Wallet and Provider
|
|
18
|
-
const privateKey = process.env.BOT_PRIVATE_KEY; // stored as an array string
|
|
19
|
-
const keypair = Keypair.fromSecretKey(
|
|
20
|
-
Uint8Array.from(JSON.parse(privateKey))
|
|
21
|
-
);
|
|
22
|
-
const wallet = new Wallet(keypair);
|
|
23
|
-
|
|
24
|
-
// Set up the Connection
|
|
25
|
-
const rpcAddress = process.env.RPC_ADDRESS; // can use: https://api.devnet.solana.com for devnet; https://api.mainnet-beta.solana.com for mainnet;
|
|
26
|
-
const connection = new Connection(rpcAddress);
|
|
27
|
-
|
|
28
|
-
// Set up the Provider
|
|
29
|
-
const provider = new AnchorProvider(
|
|
30
|
-
connection,
|
|
31
|
-
// @ts-ignore
|
|
32
|
-
wallet,
|
|
33
|
-
AnchorProvider.defaultOptions()
|
|
34
|
-
);
|
|
35
|
-
|
|
36
|
-
// Set up the Drift Clearing House
|
|
37
|
-
const driftPublicKey = new PublicKey(sdkConfig.DRIFT_PROGRAM_ID);
|
|
38
|
-
const bulkAccountLoader = new BulkAccountLoader(
|
|
39
|
-
connection,
|
|
40
|
-
'confirmed',
|
|
41
|
-
1000
|
|
42
|
-
);
|
|
43
|
-
const driftClient = new DriftClient({
|
|
44
|
-
connection,
|
|
45
|
-
wallet: provider.wallet,
|
|
46
|
-
programID: driftPublicKey,
|
|
47
|
-
...getMarketsAndOraclesForSubscription(env),
|
|
48
|
-
accountSubscription: {
|
|
49
|
-
type: 'polling',
|
|
50
|
-
accountLoader: bulkAccountLoader,
|
|
51
|
-
},
|
|
52
|
-
});
|
|
53
|
-
|
|
54
|
-
console.log('Subscribing drift client...');
|
|
55
|
-
await driftClient.subscribe();
|
|
56
|
-
|
|
57
|
-
console.log('Loading user map...');
|
|
58
|
-
const userMap = new UserMap({
|
|
59
|
-
driftClient,
|
|
60
|
-
subscriptionConfig: {
|
|
61
|
-
type: 'websocket',
|
|
62
|
-
commitment: 'processed',
|
|
63
|
-
},
|
|
64
|
-
skipInitialLoad: false,
|
|
65
|
-
includeIdle: false,
|
|
66
|
-
});
|
|
67
|
-
|
|
68
|
-
// fetches all users and subscribes for updates
|
|
69
|
-
await userMap.subscribe();
|
|
70
|
-
|
|
71
|
-
console.log('Loading dlob from user map...');
|
|
72
|
-
const slot = await driftClient.connection.getSlot();
|
|
73
|
-
const dlob = await userMap.getDLOB(slot);
|
|
74
|
-
|
|
75
|
-
console.log('number of orders', dlob.getDLOBOrders().length);
|
|
76
|
-
|
|
77
|
-
dlob.clear();
|
|
78
|
-
|
|
79
|
-
console.log('Unsubscribing users...');
|
|
80
|
-
await userMap.unsubscribe();
|
|
81
|
-
|
|
82
|
-
console.log('Unsubscribing drift client...');
|
|
83
|
-
await driftClient.unsubscribe();
|
|
84
|
-
};
|
|
85
|
-
|
|
86
|
-
main();
|