@drift-labs/sdk 2.60.0-beta.4 → 2.60.0-beta.6
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/user.d.ts +1 -1
- package/lib/user.js +19 -4
- package/package.json +1 -1
- package/src/user.ts +24 -6
- 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/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
2.60.0-beta.
|
|
1
|
+
2.60.0-beta.6
|
package/lib/user.d.ts
CHANGED
|
@@ -248,7 +248,7 @@ export declare class User {
|
|
|
248
248
|
* @param positionBaseSizeChange // change in position size to calculate liquidation price for : Precision 10^13
|
|
249
249
|
* @returns Precision : PRICE_PRECISION
|
|
250
250
|
*/
|
|
251
|
-
liquidationPrice(marketIndex: number, positionBaseSizeChange?: BN): BN;
|
|
251
|
+
liquidationPrice(marketIndex: number, positionBaseSizeChange?: BN, estimatedEntryPrice?: BN): BN;
|
|
252
252
|
calculateFreeCollateralDeltaForPerp(market: PerpMarketAccount, perpPosition: PerpPosition, positionBaseSizeChange: BN): BN | undefined;
|
|
253
253
|
calculateFreeCollateralDeltaForSpot(market: SpotMarketAccount, signedTokenAmount: BN): BN;
|
|
254
254
|
/**
|
package/lib/user.js
CHANGED
|
@@ -1082,10 +1082,27 @@ class User {
|
|
|
1082
1082
|
* @param positionBaseSizeChange // change in position size to calculate liquidation price for : Precision 10^13
|
|
1083
1083
|
* @returns Precision : PRICE_PRECISION
|
|
1084
1084
|
*/
|
|
1085
|
-
liquidationPrice(marketIndex, positionBaseSizeChange = numericConstants_1.ZERO) {
|
|
1085
|
+
liquidationPrice(marketIndex, positionBaseSizeChange = numericConstants_1.ZERO, estimatedEntryPrice = numericConstants_1.ZERO) {
|
|
1086
1086
|
const totalCollateral = this.getTotalCollateral('Maintenance');
|
|
1087
1087
|
const maintenanceMarginRequirement = this.getMaintenanceMarginRequirement();
|
|
1088
|
-
|
|
1088
|
+
let freeCollateral = _1.BN.max(numericConstants_1.ZERO, totalCollateral.sub(maintenanceMarginRequirement));
|
|
1089
|
+
const oracle = this.driftClient.getPerpMarketAccount(marketIndex).amm.oracle;
|
|
1090
|
+
const oraclePrice = this.driftClient.getOracleDataForPerpMarket(marketIndex).price;
|
|
1091
|
+
// update free collateral to accoutn from pnl based on entry price
|
|
1092
|
+
if (!estimatedEntryPrice.eq(numericConstants_1.ZERO) && !positionBaseSizeChange.eq(numericConstants_1.ZERO)) {
|
|
1093
|
+
const costBasis = oraclePrice
|
|
1094
|
+
.mul(positionBaseSizeChange.abs())
|
|
1095
|
+
.div(numericConstants_1.BASE_PRECISION);
|
|
1096
|
+
const newPositionValue = estimatedEntryPrice
|
|
1097
|
+
.mul(positionBaseSizeChange.abs())
|
|
1098
|
+
.div(numericConstants_1.BASE_PRECISION);
|
|
1099
|
+
if (positionBaseSizeChange.gt(numericConstants_1.ZERO)) {
|
|
1100
|
+
freeCollateral = freeCollateral.add(costBasis.sub(newPositionValue));
|
|
1101
|
+
}
|
|
1102
|
+
else {
|
|
1103
|
+
freeCollateral = freeCollateral.add(newPositionValue.sub(costBasis));
|
|
1104
|
+
}
|
|
1105
|
+
}
|
|
1089
1106
|
const market = this.driftClient.getPerpMarketAccount(marketIndex);
|
|
1090
1107
|
const currentPerpPosition = this.getPerpPositionWithLPSettle(marketIndex, undefined, true)[0] ||
|
|
1091
1108
|
this.getEmptyPosition(marketIndex);
|
|
@@ -1093,7 +1110,6 @@ class User {
|
|
|
1093
1110
|
if (!freeCollateralDelta) {
|
|
1094
1111
|
return new _1.BN(-1);
|
|
1095
1112
|
}
|
|
1096
|
-
const oracle = this.driftClient.getPerpMarketAccount(marketIndex).amm.oracle;
|
|
1097
1113
|
const spotMarketWithSameOracle = this.driftClient
|
|
1098
1114
|
.getSpotMarketAccounts()
|
|
1099
1115
|
.find((market) => market.oracle.equals(oracle));
|
|
@@ -1108,7 +1124,6 @@ class User {
|
|
|
1108
1124
|
if (freeCollateralDelta.eq(numericConstants_1.ZERO)) {
|
|
1109
1125
|
return new _1.BN(-1);
|
|
1110
1126
|
}
|
|
1111
|
-
const oraclePrice = this.driftClient.getOracleDataForPerpMarket(marketIndex).price;
|
|
1112
1127
|
const liqPriceDelta = freeCollateral
|
|
1113
1128
|
.mul(numericConstants_1.QUOTE_PRECISION)
|
|
1114
1129
|
.div(freeCollateralDelta);
|
package/package.json
CHANGED
package/src/user.ts
CHANGED
|
@@ -1973,15 +1973,37 @@ export class User {
|
|
|
1973
1973
|
*/
|
|
1974
1974
|
public liquidationPrice(
|
|
1975
1975
|
marketIndex: number,
|
|
1976
|
-
positionBaseSizeChange: BN = ZERO
|
|
1976
|
+
positionBaseSizeChange: BN = ZERO,
|
|
1977
|
+
estimatedEntryPrice: BN = ZERO
|
|
1977
1978
|
): BN {
|
|
1978
1979
|
const totalCollateral = this.getTotalCollateral('Maintenance');
|
|
1979
1980
|
const maintenanceMarginRequirement = this.getMaintenanceMarginRequirement();
|
|
1980
|
-
|
|
1981
|
+
let freeCollateral = BN.max(
|
|
1981
1982
|
ZERO,
|
|
1982
1983
|
totalCollateral.sub(maintenanceMarginRequirement)
|
|
1983
1984
|
);
|
|
1984
1985
|
|
|
1986
|
+
const oracle =
|
|
1987
|
+
this.driftClient.getPerpMarketAccount(marketIndex).amm.oracle;
|
|
1988
|
+
|
|
1989
|
+
const oraclePrice =
|
|
1990
|
+
this.driftClient.getOracleDataForPerpMarket(marketIndex).price;
|
|
1991
|
+
|
|
1992
|
+
// update free collateral to accoutn from pnl based on entry price
|
|
1993
|
+
if (!estimatedEntryPrice.eq(ZERO) && !positionBaseSizeChange.eq(ZERO)) {
|
|
1994
|
+
const costBasis = oraclePrice
|
|
1995
|
+
.mul(positionBaseSizeChange.abs())
|
|
1996
|
+
.div(BASE_PRECISION);
|
|
1997
|
+
const newPositionValue = estimatedEntryPrice
|
|
1998
|
+
.mul(positionBaseSizeChange.abs())
|
|
1999
|
+
.div(BASE_PRECISION);
|
|
2000
|
+
if (positionBaseSizeChange.gt(ZERO)) {
|
|
2001
|
+
freeCollateral = freeCollateral.add(costBasis.sub(newPositionValue));
|
|
2002
|
+
} else {
|
|
2003
|
+
freeCollateral = freeCollateral.add(newPositionValue.sub(costBasis));
|
|
2004
|
+
}
|
|
2005
|
+
}
|
|
2006
|
+
|
|
1985
2007
|
const market = this.driftClient.getPerpMarketAccount(marketIndex);
|
|
1986
2008
|
const currentPerpPosition =
|
|
1987
2009
|
this.getPerpPositionWithLPSettle(marketIndex, undefined, true)[0] ||
|
|
@@ -1997,8 +2019,6 @@ export class User {
|
|
|
1997
2019
|
return new BN(-1);
|
|
1998
2020
|
}
|
|
1999
2021
|
|
|
2000
|
-
const oracle =
|
|
2001
|
-
this.driftClient.getPerpMarketAccount(marketIndex).amm.oracle;
|
|
2002
2022
|
const spotMarketWithSameOracle = this.driftClient
|
|
2003
2023
|
.getSpotMarketAccounts()
|
|
2004
2024
|
.find((market) => market.oracle.equals(oracle));
|
|
@@ -2031,8 +2051,6 @@ export class User {
|
|
|
2031
2051
|
return new BN(-1);
|
|
2032
2052
|
}
|
|
2033
2053
|
|
|
2034
|
-
const oraclePrice =
|
|
2035
|
-
this.driftClient.getOracleDataForPerpMarket(marketIndex).price;
|
|
2036
2054
|
const liqPriceDelta = freeCollateral
|
|
2037
2055
|
.mul(QUOTE_PRECISION)
|
|
2038
2056
|
.div(freeCollateralDelta);
|
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();
|
|
@@ -1,162 +0,0 @@
|
|
|
1
|
-
import { AnchorProvider, BN } from '@coral-xyz/anchor';
|
|
2
|
-
import {
|
|
3
|
-
BASE_PRECISION,
|
|
4
|
-
calculateBidAskPrice,
|
|
5
|
-
getMarketOrderParams,
|
|
6
|
-
Wallet,
|
|
7
|
-
} from '..';
|
|
8
|
-
import { getAssociatedTokenAddress } from '@solana/spl-token';
|
|
9
|
-
import { Connection, Keypair, PublicKey } from '@solana/web3.js';
|
|
10
|
-
import {
|
|
11
|
-
DriftClient,
|
|
12
|
-
User,
|
|
13
|
-
initialize,
|
|
14
|
-
PositionDirection,
|
|
15
|
-
convertToNumber,
|
|
16
|
-
calculateTradeSlippage,
|
|
17
|
-
BulkAccountLoader,
|
|
18
|
-
getMarketsAndOraclesForSubscription,
|
|
19
|
-
PRICE_PRECISION,
|
|
20
|
-
QUOTE_PRECISION,
|
|
21
|
-
} from '..';
|
|
22
|
-
import { SpotMarkets } from '../constants/spotMarkets';
|
|
23
|
-
|
|
24
|
-
export const getTokenAddress = (
|
|
25
|
-
mintAddress: string,
|
|
26
|
-
userPubKey: string
|
|
27
|
-
): Promise<PublicKey> => {
|
|
28
|
-
return getAssociatedTokenAddress(
|
|
29
|
-
new PublicKey(mintAddress),
|
|
30
|
-
new PublicKey(userPubKey)
|
|
31
|
-
);
|
|
32
|
-
};
|
|
33
|
-
|
|
34
|
-
const env = 'devnet';
|
|
35
|
-
|
|
36
|
-
const main = async () => {
|
|
37
|
-
// Initialize Drift SDK
|
|
38
|
-
const sdkConfig = initialize({ env });
|
|
39
|
-
|
|
40
|
-
// Set up the Wallet and Provider
|
|
41
|
-
const privateKey = process.env.BOT_PRIVATE_KEY; // stored as an array string
|
|
42
|
-
const keypair = Keypair.fromSecretKey(
|
|
43
|
-
Uint8Array.from(JSON.parse(privateKey))
|
|
44
|
-
);
|
|
45
|
-
const wallet = new Wallet(keypair);
|
|
46
|
-
|
|
47
|
-
// Set up the Connection
|
|
48
|
-
const rpcAddress = process.env.RPC_ADDRESS; // can use: https://api.devnet.solana.com for devnet; https://api.mainnet-beta.solana.com for mainnet;
|
|
49
|
-
const connection = new Connection(rpcAddress);
|
|
50
|
-
|
|
51
|
-
// Set up the Provider
|
|
52
|
-
const provider = new AnchorProvider(
|
|
53
|
-
connection,
|
|
54
|
-
// @ts-ignore
|
|
55
|
-
wallet,
|
|
56
|
-
AnchorProvider.defaultOptions()
|
|
57
|
-
);
|
|
58
|
-
|
|
59
|
-
// Check SOL Balance
|
|
60
|
-
const lamportsBalance = await connection.getBalance(wallet.publicKey);
|
|
61
|
-
console.log('SOL balance:', lamportsBalance / 10 ** 9);
|
|
62
|
-
|
|
63
|
-
// Misc. other things to set up
|
|
64
|
-
const usdcTokenAddress = await getTokenAddress(
|
|
65
|
-
sdkConfig.USDC_MINT_ADDRESS,
|
|
66
|
-
wallet.publicKey.toString()
|
|
67
|
-
);
|
|
68
|
-
|
|
69
|
-
// Set up the Drift Clearing House
|
|
70
|
-
const driftPublicKey = new PublicKey(sdkConfig.DRIFT_PROGRAM_ID);
|
|
71
|
-
const bulkAccountLoader = new BulkAccountLoader(
|
|
72
|
-
connection,
|
|
73
|
-
'confirmed',
|
|
74
|
-
1000
|
|
75
|
-
);
|
|
76
|
-
const driftClient = new DriftClient({
|
|
77
|
-
connection,
|
|
78
|
-
wallet: provider.wallet,
|
|
79
|
-
programID: driftPublicKey,
|
|
80
|
-
...getMarketsAndOraclesForSubscription(env),
|
|
81
|
-
accountSubscription: {
|
|
82
|
-
type: 'polling',
|
|
83
|
-
accountLoader: bulkAccountLoader,
|
|
84
|
-
},
|
|
85
|
-
});
|
|
86
|
-
await driftClient.subscribe();
|
|
87
|
-
|
|
88
|
-
// Set up user client
|
|
89
|
-
const user = new User({
|
|
90
|
-
driftClient: driftClient,
|
|
91
|
-
userAccountPublicKey: await driftClient.getUserAccountPublicKey(),
|
|
92
|
-
accountSubscription: {
|
|
93
|
-
type: 'polling',
|
|
94
|
-
accountLoader: bulkAccountLoader,
|
|
95
|
-
},
|
|
96
|
-
});
|
|
97
|
-
|
|
98
|
-
//// Check if user account exists for the current wallet
|
|
99
|
-
const userAccountExists = await user.exists();
|
|
100
|
-
|
|
101
|
-
if (!userAccountExists) {
|
|
102
|
-
//// Create a Clearing House account by Depositing some USDC ($10,000 in this case)
|
|
103
|
-
const depositAmount = new BN(10000).mul(QUOTE_PRECISION);
|
|
104
|
-
await driftClient.initializeUserAccountAndDepositCollateral(
|
|
105
|
-
depositAmount,
|
|
106
|
-
await getTokenAddress(
|
|
107
|
-
usdcTokenAddress.toString(),
|
|
108
|
-
wallet.publicKey.toString()
|
|
109
|
-
),
|
|
110
|
-
SpotMarkets['devnet'][0].marketIndex
|
|
111
|
-
);
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
await user.subscribe();
|
|
115
|
-
|
|
116
|
-
// Get current price
|
|
117
|
-
const solMarketInfo = sdkConfig.PERP_MARKETS.find(
|
|
118
|
-
(market) => market.baseAssetSymbol === 'SOL'
|
|
119
|
-
);
|
|
120
|
-
|
|
121
|
-
const marketIndex = solMarketInfo.marketIndex;
|
|
122
|
-
const [bid, ask] = calculateBidAskPrice(
|
|
123
|
-
driftClient.getPerpMarketAccount(marketIndex).amm,
|
|
124
|
-
driftClient.getOracleDataForPerpMarket(marketIndex)
|
|
125
|
-
);
|
|
126
|
-
|
|
127
|
-
const formattedBidPrice = convertToNumber(bid, PRICE_PRECISION);
|
|
128
|
-
const formattedAskPrice = convertToNumber(ask, PRICE_PRECISION);
|
|
129
|
-
|
|
130
|
-
console.log(
|
|
131
|
-
`Current amm bid and ask price are $${formattedBidPrice} and $${formattedAskPrice}`
|
|
132
|
-
);
|
|
133
|
-
|
|
134
|
-
// Estimate the slippage for a $5000 LONG trade
|
|
135
|
-
const solMarketAccount = driftClient.getPerpMarketAccount(
|
|
136
|
-
solMarketInfo.marketIndex
|
|
137
|
-
);
|
|
138
|
-
|
|
139
|
-
const slippage = convertToNumber(
|
|
140
|
-
calculateTradeSlippage(
|
|
141
|
-
PositionDirection.LONG,
|
|
142
|
-
new BN(1).mul(BASE_PRECISION),
|
|
143
|
-
solMarketAccount,
|
|
144
|
-
'base',
|
|
145
|
-
driftClient.getOracleDataForPerpMarket(solMarketInfo.marketIndex)
|
|
146
|
-
)[0],
|
|
147
|
-
PRICE_PRECISION
|
|
148
|
-
);
|
|
149
|
-
|
|
150
|
-
console.log(`Slippage for a 1 SOL-PERP would be $${slippage}`);
|
|
151
|
-
|
|
152
|
-
await driftClient.placePerpOrder(
|
|
153
|
-
getMarketOrderParams({
|
|
154
|
-
baseAssetAmount: new BN(1).mul(BASE_PRECISION),
|
|
155
|
-
direction: PositionDirection.LONG,
|
|
156
|
-
marketIndex: solMarketAccount.marketIndex,
|
|
157
|
-
})
|
|
158
|
-
);
|
|
159
|
-
console.log(`Placed a 1 SOL-PERP LONG order`);
|
|
160
|
-
};
|
|
161
|
-
|
|
162
|
-
main();
|