@drift-labs/sdk 0.1.29-master.0 → 0.1.30-master.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.
Files changed (68) hide show
  1. package/lib/accounts/bulkAccountLoader.d.ts +1 -0
  2. package/lib/accounts/bulkAccountLoader.js +33 -13
  3. package/lib/clearingHouse.d.ts +4 -1
  4. package/lib/clearingHouse.js +49 -0
  5. package/lib/constants/markets.js +11 -0
  6. package/lib/idl/clearing_house.json +63 -2
  7. package/lib/index.d.ts +1 -0
  8. package/lib/index.js +1 -0
  9. package/lib/math/amm.d.ts +0 -20
  10. package/lib/math/amm.js +1 -151
  11. package/lib/math/repeg.d.ts +32 -0
  12. package/lib/math/repeg.js +178 -0
  13. package/lib/oracles/pythClient.js +1 -1
  14. package/lib/orderParams.d.ts +1 -1
  15. package/lib/orderParams.js +2 -2
  16. package/lib/tx/retryTxSender.d.ts +5 -2
  17. package/lib/tx/retryTxSender.js +14 -1
  18. package/package.json +1 -1
  19. package/src/accounts/bulkAccountLoader.ts +40 -15
  20. package/src/clearingHouse.ts +71 -0
  21. package/src/constants/markets.ts +11 -0
  22. package/src/idl/clearing_house.json +63 -2
  23. package/src/index.ts +1 -0
  24. package/src/math/amm.ts +1 -212
  25. package/src/math/repeg.ts +253 -0
  26. package/src/oracles/pythClient.ts +1 -1
  27. package/src/orderParams.ts +3 -2
  28. package/src/tx/retryTxSender.ts +19 -1
  29. package/src/accounts/bulkUserSubscription.js +0 -56
  30. package/src/accounts/bulkUserSubscription.js.map +0 -1
  31. package/src/accounts/pollingUserAccountSubscriber.js +0 -139
  32. package/src/accounts/pollingUserAccountSubscriber.js.map +0 -1
  33. package/src/accounts/types.js +0 -11
  34. package/src/accounts/types.js.map +0 -1
  35. package/src/accounts/webSocketUserAccountSubscriber.js +0 -78
  36. package/src/accounts/webSocketUserAccountSubscriber.js.map +0 -1
  37. package/src/addresses.js +0 -59
  38. package/src/addresses.js.map +0 -1
  39. package/src/admin.js +0 -443
  40. package/src/admin.js.map +0 -1
  41. package/src/clearingHouseUser.js +0 -581
  42. package/src/clearingHouseUser.js.map +0 -1
  43. package/src/config.js +0 -37
  44. package/src/config.js.map +0 -1
  45. package/src/factory/clearingHouse.js +0 -65
  46. package/src/factory/clearingHouse.js.map +0 -1
  47. package/src/factory/clearingHouseUser.js +0 -35
  48. package/src/factory/clearingHouseUser.js.map +0 -1
  49. package/src/factory/oracleClient.js +0 -17
  50. package/src/factory/oracleClient.js.map +0 -1
  51. package/src/index.js +0 -56
  52. package/src/index.js.map +0 -1
  53. package/src/math/amm.js +0 -285
  54. package/src/math/amm.js.map +0 -1
  55. package/src/mockUSDCFaucet.js +0 -143
  56. package/src/mockUSDCFaucet.js.map +0 -1
  57. package/src/oracles/pythClient.js +0 -39
  58. package/src/oracles/pythClient.js.map +0 -1
  59. package/src/orderParams.js +0 -109
  60. package/src/orderParams.js.map +0 -1
  61. package/src/orders.js +0 -172
  62. package/src/orders.js.map +0 -1
  63. package/src/tx/retryTxSender.js +0 -137
  64. package/src/tx/retryTxSender.js.map +0 -1
  65. package/src/types.js +0 -61
  66. package/src/types.js.map +0 -1
  67. package/src/wallet.js +0 -23
  68. package/src/wallet.js.map +0 -1
@@ -0,0 +1,178 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.calculateBudgetedPeg = exports.calculateBudgetedK = exports.calculateReserveRebalanceCost = exports.calculateRepegCost = exports.calculateAdjustKCost = void 0;
4
+ const anchor_1 = require("@project-serum/anchor");
5
+ const numericConstants_1 = require("../constants/numericConstants");
6
+ const position_1 = require("./position");
7
+ const amm_1 = require("./amm");
8
+ const __1 = require("..");
9
+ /**
10
+ * Helper function calculating adjust k cost
11
+ * @param market
12
+ * @param marketIndex
13
+ * @param numerator
14
+ * @param denomenator
15
+ * @returns cost : Precision QUOTE_ASSET_PRECISION
16
+ */
17
+ function calculateAdjustKCost(market, marketIndex, numerator, denomenator) {
18
+ const netUserPosition = {
19
+ baseAssetAmount: market.baseAssetAmount,
20
+ lastCumulativeFundingRate: market.amm.cumulativeFundingRate,
21
+ marketIndex: new anchor_1.BN(marketIndex),
22
+ quoteAssetAmount: numericConstants_1.ZERO,
23
+ openOrders: numericConstants_1.ZERO,
24
+ };
25
+ const currentValue = (0, position_1.calculateBaseAssetValue)(market, netUserPosition);
26
+ const marketNewK = Object.assign({}, market);
27
+ marketNewK.amm = Object.assign({}, market.amm);
28
+ marketNewK.amm.baseAssetReserve = market.amm.baseAssetReserve
29
+ .mul(numerator)
30
+ .div(denomenator);
31
+ marketNewK.amm.quoteAssetReserve = market.amm.quoteAssetReserve
32
+ .mul(numerator)
33
+ .div(denomenator);
34
+ marketNewK.amm.sqrtK = market.amm.sqrtK.mul(numerator).div(denomenator);
35
+ netUserPosition.quoteAssetAmount = currentValue;
36
+ const cost = (0, __1.calculatePositionPNL)(marketNewK, netUserPosition);
37
+ return cost;
38
+ }
39
+ exports.calculateAdjustKCost = calculateAdjustKCost;
40
+ /**
41
+ * Helper function calculating adjust pegMultiplier (repeg) cost
42
+ *
43
+ * @param market
44
+ * @param marketIndex
45
+ * @param newPeg
46
+ * @returns cost : Precision QUOTE_ASSET_PRECISION
47
+ */
48
+ function calculateRepegCost(market, marketIndex, newPeg) {
49
+ const netUserPosition = {
50
+ baseAssetAmount: market.baseAssetAmount,
51
+ lastCumulativeFundingRate: market.amm.cumulativeFundingRate,
52
+ marketIndex: new anchor_1.BN(marketIndex),
53
+ quoteAssetAmount: new anchor_1.BN(0),
54
+ openOrders: numericConstants_1.ZERO,
55
+ };
56
+ const currentValue = (0, position_1.calculateBaseAssetValue)(market, netUserPosition);
57
+ netUserPosition.quoteAssetAmount = currentValue;
58
+ const prevMarketPrice = (0, __1.calculateMarkPrice)(market);
59
+ const marketNewPeg = Object.assign({}, market);
60
+ marketNewPeg.amm = Object.assign({}, market.amm);
61
+ // const marketNewPeg = JSON.parse(JSON.stringify(market));
62
+ marketNewPeg.amm.pegMultiplier = newPeg;
63
+ console.log('Price moves from', (0, __1.convertToNumber)(prevMarketPrice), 'to', (0, __1.convertToNumber)((0, __1.calculateMarkPrice)(marketNewPeg)));
64
+ const cost = (0, __1.calculatePositionPNL)(marketNewPeg, netUserPosition);
65
+ return cost;
66
+ }
67
+ exports.calculateRepegCost = calculateRepegCost;
68
+ /**
69
+ * Helper function calculating adjust pegMultiplier (repeg) cost
70
+ *
71
+ * @param market
72
+ * @param marketIndex
73
+ * @param newPeg
74
+ * @returns cost : Precision QUOTE_ASSET_PRECISION
75
+ */
76
+ function calculateReserveRebalanceCost(market, marketIndex) {
77
+ const netUserPosition = {
78
+ baseAssetAmount: market.baseAssetAmount,
79
+ lastCumulativeFundingRate: market.amm.cumulativeFundingRate,
80
+ marketIndex: new anchor_1.BN(marketIndex),
81
+ quoteAssetAmount: new anchor_1.BN(0),
82
+ openOrders: numericConstants_1.ZERO,
83
+ };
84
+ const currentValue = (0, position_1.calculateBaseAssetValue)(market, netUserPosition);
85
+ netUserPosition.quoteAssetAmount = currentValue;
86
+ const prevMarketPrice = (0, __1.calculateMarkPrice)(market);
87
+ const marketNewPeg = Object.assign({}, market);
88
+ marketNewPeg.amm = Object.assign({}, market.amm);
89
+ // const marketNewPeg = JSON.parse(JSON.stringify(market));
90
+ const newPeg = (0, amm_1.calculateTerminalPrice)(market)
91
+ .mul(numericConstants_1.PEG_PRECISION)
92
+ .div(numericConstants_1.MARK_PRICE_PRECISION);
93
+ // const newPeg = prevMarketPrice.mul(PEG_PRECISION).div(MARK_PRICE_PRECISION);
94
+ const newBaseReserve = market.amm.baseAssetReserve.add(market.baseAssetAmount);
95
+ const newQuoteReserve = market.amm.sqrtK
96
+ .mul(market.amm.sqrtK)
97
+ .div(newBaseReserve);
98
+ console.log('current reserves on close, quote:', (0, __1.convertToNumber)(newQuoteReserve, numericConstants_1.AMM_RESERVE_PRECISION), 'base:', (0, __1.convertToNumber)(newBaseReserve, numericConstants_1.AMM_RESERVE_PRECISION));
99
+ let newSqrtK;
100
+ if (newPeg.lt(market.amm.pegMultiplier)) {
101
+ newSqrtK = newBaseReserve;
102
+ }
103
+ else {
104
+ newSqrtK = newQuoteReserve;
105
+ }
106
+ marketNewPeg.amm.baseAssetReserve = newSqrtK.sub(market.baseAssetAmount); // newSqrtK.sub(market.baseAssetAmount);
107
+ marketNewPeg.amm.quoteAssetReserve = newSqrtK
108
+ .mul(newSqrtK)
109
+ .div(marketNewPeg.amm.baseAssetReserve);
110
+ marketNewPeg.amm.sqrtK = newSqrtK;
111
+ marketNewPeg.amm.pegMultiplier = newPeg;
112
+ console.log('Price moves from', (0, __1.convertToNumber)(prevMarketPrice), 'to', (0, __1.convertToNumber)((0, __1.calculateMarkPrice)(marketNewPeg)));
113
+ const cost = (0, __1.calculatePositionPNL)(marketNewPeg, netUserPosition);
114
+ return cost;
115
+ }
116
+ exports.calculateReserveRebalanceCost = calculateReserveRebalanceCost;
117
+ function calculateBudgetedK(market, cost) {
118
+ // wolframalpha.com
119
+ // (1/(x+d) - p/(x*p+d))*y*d*Q = C solve for p
120
+ // p = (d(y*d*Q - C(x+d))) / (C*x(x+d) + y*y*d*Q)
121
+ // todo: assumes k = x * y
122
+ // otherwise use: (y(1-p) + (kp^2/(x*p+d)) - k/(x+d)) * Q = C solve for p
123
+ // const k = market.amm.sqrtK.mul(market.amm.sqrtK);
124
+ const x = market.amm.baseAssetReserve;
125
+ const y = market.amm.quoteAssetReserve;
126
+ const d = market.baseAssetAmount;
127
+ const Q = market.amm.pegMultiplier;
128
+ const C = cost.mul(new anchor_1.BN(-1));
129
+ const numer1 = y.mul(d).mul(Q).div(numericConstants_1.AMM_RESERVE_PRECISION).div(numericConstants_1.PEG_PRECISION);
130
+ const numer2 = C.mul(x.add(d)).div(numericConstants_1.QUOTE_PRECISION);
131
+ const denom1 = C.mul(x)
132
+ .mul(x.add(d))
133
+ .div(numericConstants_1.AMM_RESERVE_PRECISION)
134
+ .div(numericConstants_1.QUOTE_PRECISION);
135
+ const denom2 = y
136
+ .mul(d)
137
+ .mul(d)
138
+ .mul(Q)
139
+ .div(numericConstants_1.AMM_RESERVE_PRECISION)
140
+ .div(numericConstants_1.AMM_RESERVE_PRECISION)
141
+ .div(numericConstants_1.PEG_PRECISION);
142
+ const numerator = d
143
+ .mul(numer1.add(numer2))
144
+ .div(numericConstants_1.AMM_RESERVE_PRECISION)
145
+ .div(numericConstants_1.AMM_RESERVE_PRECISION)
146
+ .div(numericConstants_1.AMM_TO_QUOTE_PRECISION_RATIO);
147
+ const denominator = denom1
148
+ .add(denom2)
149
+ .div(numericConstants_1.AMM_RESERVE_PRECISION)
150
+ .div(numericConstants_1.AMM_TO_QUOTE_PRECISION_RATIO);
151
+ console.log(numerator, denominator);
152
+ // const p = (numerator).div(denominator);
153
+ // const formulaCost = (numer21.sub(numer20).sub(numer1)).mul(market.amm.pegMultiplier).div(AMM_TIMES_PEG_TO_QUOTE_PRECISION_RATIO)
154
+ // console.log(convertToNumber(formulaCost, QUOTE_PRECISION))
155
+ return [numerator, denominator];
156
+ }
157
+ exports.calculateBudgetedK = calculateBudgetedK;
158
+ function calculateBudgetedPeg(market, cost) {
159
+ // wolframalpha.com
160
+ // (1/(x+d) - p/(x*p+d))*y*d*Q = C solve for p
161
+ // p = (d(y*d*Q - C(x+d))) / (C*x(x+d) + y*y*d*Q)
162
+ // todo: assumes k = x * y
163
+ // otherwise use: (y(1-p) + (kp^2/(x*p+d)) - k/(x+d)) * Q = C solve for p
164
+ const k = market.amm.sqrtK.mul(market.amm.sqrtK);
165
+ const x = market.amm.baseAssetReserve;
166
+ const y = market.amm.quoteAssetReserve;
167
+ const d = market.baseAssetAmount;
168
+ const Q = market.amm.pegMultiplier;
169
+ const C = cost.mul(new anchor_1.BN(-1));
170
+ const deltaQuoteAssetReserves = y.sub(k.div(x.add(d)));
171
+ const deltaPegMultiplier = C.mul(numericConstants_1.MARK_PRICE_PRECISION).div(deltaQuoteAssetReserves.div(numericConstants_1.AMM_TO_QUOTE_PRECISION_RATIO));
172
+ // .mul(PEG_PRECISION)
173
+ // .div(QUOTE_PRECISION);
174
+ console.log(Q.toNumber(), 'change by', deltaPegMultiplier.toNumber() / numericConstants_1.MARK_PRICE_PRECISION.toNumber());
175
+ const newPeg = Q.sub(deltaPegMultiplier.mul(numericConstants_1.PEG_PRECISION).div(numericConstants_1.MARK_PRICE_PRECISION));
176
+ return newPeg;
177
+ }
178
+ exports.calculateBudgetedPeg = calculateBudgetedPeg;
@@ -33,7 +33,7 @@ class PythClient {
33
33
  return __awaiter(this, void 0, void 0, function* () {
34
34
  const priceData = (0, client_1.parsePriceData)(buffer);
35
35
  return {
36
- price: convertPythPrice(priceData.price, priceData.exponent),
36
+ price: convertPythPrice(priceData.aggregate.price, priceData.exponent),
37
37
  slot: new anchor_1.BN(priceData.lastSlot.toString()),
38
38
  confidence: convertPythPrice(priceData.confidence, priceData.exponent),
39
39
  twap: convertPythPrice(priceData.twap.value, priceData.exponent),
@@ -1,7 +1,7 @@
1
1
  /// <reference types="bn.js" />
2
2
  import { OrderParams, OrderTriggerCondition, PositionDirection } from './types';
3
3
  import { BN } from '@project-serum/anchor';
4
- export declare function getLimitOrderParams(marketIndex: BN, direction: PositionDirection, baseAssetAmount: BN, price: BN, reduceOnly: boolean, discountToken?: boolean, referrer?: boolean, userOrderId?: number, postOnly?: boolean, oraclePriceOffset?: BN): OrderParams;
4
+ export declare function getLimitOrderParams(marketIndex: BN, direction: PositionDirection, baseAssetAmount: BN, price: BN, reduceOnly: boolean, discountToken?: boolean, referrer?: boolean, userOrderId?: number, postOnly?: boolean, oraclePriceOffset?: BN, immediateOrCancel?: boolean): OrderParams;
5
5
  export declare function getTriggerMarketOrderParams(marketIndex: BN, direction: PositionDirection, baseAssetAmount: BN, triggerPrice: BN, triggerCondition: OrderTriggerCondition, reduceOnly: boolean, discountToken?: boolean, referrer?: boolean, userOrderId?: number): OrderParams;
6
6
  export declare function getTriggerLimitOrderParams(marketIndex: BN, direction: PositionDirection, baseAssetAmount: BN, price: BN, triggerPrice: BN, triggerCondition: OrderTriggerCondition, reduceOnly: boolean, discountToken?: boolean, referrer?: boolean, userOrderId?: number): OrderParams;
7
7
  export declare function getMarketOrderParams(marketIndex: BN, direction: PositionDirection, quoteAssetAmount: BN, baseAssetAmount: BN, reduceOnly: boolean, price?: BN, discountToken?: boolean, referrer?: boolean): OrderParams;
@@ -3,7 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.getMarketOrderParams = exports.getTriggerLimitOrderParams = exports.getTriggerMarketOrderParams = exports.getLimitOrderParams = void 0;
4
4
  const types_1 = require("./types");
5
5
  const numericConstants_1 = require("./constants/numericConstants");
6
- function getLimitOrderParams(marketIndex, direction, baseAssetAmount, price, reduceOnly, discountToken = false, referrer = false, userOrderId = 0, postOnly = false, oraclePriceOffset = numericConstants_1.ZERO) {
6
+ function getLimitOrderParams(marketIndex, direction, baseAssetAmount, price, reduceOnly, discountToken = false, referrer = false, userOrderId = 0, postOnly = false, oraclePriceOffset = numericConstants_1.ZERO, immediateOrCancel = false) {
7
7
  return {
8
8
  orderType: types_1.OrderType.LIMIT,
9
9
  userOrderId,
@@ -14,7 +14,7 @@ function getLimitOrderParams(marketIndex, direction, baseAssetAmount, price, red
14
14
  price,
15
15
  reduceOnly,
16
16
  postOnly,
17
- immediateOrCancel: false,
17
+ immediateOrCancel,
18
18
  positionLimit: numericConstants_1.ZERO,
19
19
  padding0: true,
20
20
  padding1: numericConstants_1.ZERO,
@@ -1,5 +1,6 @@
1
+ /// <reference types="node" />
1
2
  import { TxSender } from './types';
2
- import { Commitment, ConfirmOptions, RpcResponseAndContext, Signer, SignatureResult, Transaction, TransactionSignature } from '@solana/web3.js';
3
+ import { Commitment, ConfirmOptions, RpcResponseAndContext, Signer, SignatureResult, Transaction, TransactionSignature, Connection } from '@solana/web3.js';
3
4
  import { Provider } from '@project-serum/anchor';
4
5
  declare type ResolveReference = {
5
6
  resolve?: () => void;
@@ -8,12 +9,14 @@ export declare class RetryTxSender implements TxSender {
8
9
  provider: Provider;
9
10
  timeout: number;
10
11
  retrySleep: number;
11
- constructor(provider: Provider, timeout?: number, retrySleep?: number);
12
+ additionalConnections: Connection[];
13
+ constructor(provider: Provider, timeout?: number, retrySleep?: number, additionalConnections?: Connection[]);
12
14
  send(tx: Transaction, additionalSigners?: Array<Signer>, opts?: ConfirmOptions): Promise<TransactionSignature>;
13
15
  prepareTx(tx: Transaction, additionalSigners: Array<Signer>, opts: ConfirmOptions): Promise<Transaction>;
14
16
  confirmTransaction(signature: TransactionSignature, commitment?: Commitment): Promise<RpcResponseAndContext<SignatureResult>>;
15
17
  getTimestamp(): number;
16
18
  sleep(reference: ResolveReference): Promise<void>;
17
19
  promiseTimeout<T>(promise: Promise<T>, timeoutMs: number): Promise<T | null>;
20
+ sendToAdditionalConnections(rawTx: Buffer, opts: ConfirmOptions): void;
18
21
  }
19
22
  export {};
@@ -18,10 +18,11 @@ const bs58_1 = __importDefault(require("bs58"));
18
18
  const DEFAULT_TIMEOUT = 35000;
19
19
  const DEFAULT_RETRY = 8000;
20
20
  class RetryTxSender {
21
- constructor(provider, timeout, retrySleep) {
21
+ constructor(provider, timeout, retrySleep, additionalConnections = new Array()) {
22
22
  this.provider = provider;
23
23
  this.timeout = timeout !== null && timeout !== void 0 ? timeout : DEFAULT_TIMEOUT;
24
24
  this.retrySleep = retrySleep !== null && retrySleep !== void 0 ? retrySleep : DEFAULT_RETRY;
25
+ this.additionalConnections = additionalConnections;
25
26
  }
26
27
  send(tx, additionalSigners, opts) {
27
28
  return __awaiter(this, void 0, void 0, function* () {
@@ -35,6 +36,7 @@ class RetryTxSender {
35
36
  const rawTransaction = tx.serialize();
36
37
  const startTime = this.getTimestamp();
37
38
  const txid = yield this.provider.connection.sendRawTransaction(rawTransaction, opts);
39
+ this.sendToAdditionalConnections(rawTransaction, opts);
38
40
  let done = false;
39
41
  const resolveReference = {
40
42
  resolve: undefined,
@@ -55,6 +57,7 @@ class RetryTxSender {
55
57
  console.error(e);
56
58
  stopWaiting();
57
59
  });
60
+ this.sendToAdditionalConnections(rawTransaction, opts);
58
61
  }
59
62
  }
60
63
  }))();
@@ -149,5 +152,15 @@ class RetryTxSender {
149
152
  return result;
150
153
  });
151
154
  }
155
+ sendToAdditionalConnections(rawTx, opts) {
156
+ this.additionalConnections.map((connection) => {
157
+ connection.sendRawTransaction(rawTx, opts).catch((e) => {
158
+ console.error(
159
+ // @ts-ignore
160
+ `error sending tx to additional connection ${connection._rpcEndpoint}`);
161
+ console.error(e);
162
+ });
163
+ });
164
+ }
152
165
  }
153
166
  exports.RetryTxSender = RetryTxSender;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@drift-labs/sdk",
3
- "version": "0.1.29-master.0",
3
+ "version": "0.1.30-master.0",
4
4
  "main": "lib/index.js",
5
5
  "types": "lib/index.d.ts",
6
6
  "author": "crispheaney",
@@ -43,10 +43,15 @@ export class BulkAccountLoader {
43
43
  const existingSize = this.accountsToLoad.size;
44
44
 
45
45
  const callbackId = uuidv4();
46
+ this.log(
47
+ `Adding account ${publicKey.toString()} callback id ${callbackId}`
48
+ );
46
49
  const existingAccountToLoad = this.accountsToLoad.get(publicKey.toString());
47
50
  if (existingAccountToLoad) {
51
+ this.log(`account already exists`);
48
52
  existingAccountToLoad.callbacks.set(callbackId, callback);
49
53
  } else {
54
+ this.log(`account doesn't already exist. creating new callback map`);
50
55
  const callbacks = new Map<string, (buffer: Buffer) => void>();
51
56
  callbacks.set(callbackId, callback);
52
57
  const newAccountToLoad = {
@@ -67,6 +72,9 @@ export class BulkAccountLoader {
67
72
  }
68
73
 
69
74
  public removeAccount(publicKey: PublicKey, callbackId: string): void {
75
+ this.log(
76
+ `Removing account ${publicKey.toString()} callback id ${callbackId}`
77
+ );
70
78
  const existingAccountToLoad = this.accountsToLoad.get(publicKey.toString());
71
79
  if (existingAccountToLoad) {
72
80
  existingAccountToLoad.callbacks.delete(callbackId);
@@ -99,17 +107,21 @@ export class BulkAccountLoader {
99
107
 
100
108
  public async load(): Promise<void> {
101
109
  if (this.loadPromise) {
110
+ this.log(`Load promise exists. Returning early`);
102
111
  return this.loadPromise;
103
112
  }
104
113
  this.loadPromise = new Promise((resolver) => {
105
114
  this.loadPromiseResolver = resolver;
106
115
  });
107
116
 
117
+ this.log(`Loading`);
118
+
108
119
  try {
109
120
  const chunks = this.chunks(
110
121
  Array.from(this.accountsToLoad.values()),
111
122
  GET_MULTIPLE_ACCOUNTS_CHUNK_SIZE
112
123
  );
124
+ this.log(`${chunks.length} chunks`);
113
125
 
114
126
  await Promise.all(
115
127
  chunks.map((chunk) => {
@@ -122,17 +134,17 @@ export class BulkAccountLoader {
122
134
  for (const [_, callback] of this.errorCallbacks) {
123
135
  callback(e);
124
136
  }
137
+ this.log('finished error callbacks');
125
138
  } finally {
139
+ this.log(`resetting load promise`);
126
140
  this.loadPromiseResolver();
127
141
  this.loadPromise = undefined;
128
142
 
129
143
  const now = Date.now();
130
144
  if (now - this.lastUpdate > fiveMinutes) {
131
- if (this.loggingEnabled) {
132
- console.log(
133
- "Haven't seen updated account in five minutes. Bulk account loader creating new Connection Object"
134
- );
135
- }
145
+ this.log(
146
+ "Haven't seen updated account in five minutes. Bulk account loader creating new Connection Object"
147
+ );
136
148
  this.connection = new Connection(
137
149
  // @ts-ignore
138
150
  this.connection._rpcEndpoint,
@@ -144,6 +156,7 @@ export class BulkAccountLoader {
144
156
 
145
157
  async loadChunk(accountsToLoad: AccountToLoad[]): Promise<void> {
146
158
  if (accountsToLoad.length === 0) {
159
+ this.log(`no accounts in chunk`);
147
160
  return;
148
161
  }
149
162
 
@@ -161,8 +174,8 @@ export class BulkAccountLoader {
161
174
  );
162
175
 
163
176
  const oneMinuteSinceLastUpdate = Date.now() - this.lastUpdate > oneMinute;
164
- if (this.loggingEnabled && oneMinuteSinceLastUpdate) {
165
- console.log('rpcResponse', JSON.stringify(rpcResponse));
177
+ if (oneMinuteSinceLastUpdate) {
178
+ this.log('rpcResponse ' + JSON.stringify(rpcResponse));
166
179
  }
167
180
 
168
181
  const newSlot = rpcResponse.result.context.slot;
@@ -179,11 +192,12 @@ export class BulkAccountLoader {
179
192
  newBuffer = Buffer.from(raw, dataType);
180
193
  }
181
194
 
182
- if (this.loggingEnabled && oneMinuteSinceLastUpdate) {
183
- console.log('oldRPCResponse', oldRPCResponse);
195
+ if (oneMinuteSinceLastUpdate) {
196
+ this.log('oldRPCResponse' + oldRPCResponse);
184
197
  }
185
198
 
186
199
  if (!oldRPCResponse) {
200
+ this.log('No old rpc response, updating account data');
187
201
  this.accountData.set(key, {
188
202
  slot: newSlot,
189
203
  buffer: newBuffer,
@@ -194,25 +208,34 @@ export class BulkAccountLoader {
194
208
  }
195
209
 
196
210
  if (newSlot <= oldRPCResponse.slot) {
211
+ this.log(`new slot ${newSlot} old slot ${oldRPCResponse.slot}`);
197
212
  continue;
198
213
  }
199
214
 
200
215
  const oldBuffer = oldRPCResponse.buffer;
201
216
  if (newBuffer && (!oldBuffer || !newBuffer.equals(oldBuffer))) {
217
+ this.log('new buffer, updating account data');
202
218
  this.accountData.set(key, {
203
219
  slot: newSlot,
204
220
  buffer: newBuffer,
205
221
  });
206
222
  this.handleAccountCallbacks(accountToLoad, newBuffer);
207
223
  this.lastUpdate = Date.now();
224
+ } else {
225
+ this.log('unable to update account for newest slot');
226
+ this.log('oldBuffer ' + oldBuffer);
227
+ this.log('newBuffer ' + newBuffer);
228
+ this.log('buffers equal ' + newBuffer.equals(oldBuffer));
208
229
  }
209
230
  }
210
231
  }
211
232
 
212
233
  handleAccountCallbacks(accountToLoad: AccountToLoad, buffer: Buffer): void {
234
+ this.log('handling account callbacks');
213
235
  for (const [_, callback] of accountToLoad.callbacks) {
214
236
  callback(buffer);
215
237
  }
238
+ this.log('finished account callbacks');
216
239
  }
217
240
 
218
241
  public getAccountData(publicKey: PublicKey): Buffer | undefined {
@@ -225,9 +248,7 @@ export class BulkAccountLoader {
225
248
  return;
226
249
  }
227
250
 
228
- if (this.loggingEnabled) {
229
- console.log(`startPolling`);
230
- }
251
+ this.log('startPolling');
231
252
 
232
253
  this.intervalId = setInterval(this.load.bind(this), this.pollingFrequency);
233
254
  }
@@ -237,9 +258,13 @@ export class BulkAccountLoader {
237
258
  clearInterval(this.intervalId);
238
259
  this.intervalId = undefined;
239
260
 
240
- if (this.loggingEnabled) {
241
- console.log(`stopPolling`);
242
- }
261
+ this.log('stopPolling');
262
+ }
263
+ }
264
+
265
+ public log(msg: string): void {
266
+ if (this.loggingEnabled) {
267
+ console.log(msg);
243
268
  }
244
269
  }
245
270
  }
@@ -21,6 +21,7 @@ import {
21
21
  OrderParams,
22
22
  Order,
23
23
  ExtendedCurveHistoryAccount,
24
+ UserPositionsAccount,
24
25
  } from './types';
25
26
  import * as anchor from '@project-serum/anchor';
26
27
  import clearingHouseIDL from './idl/clearing_house.json';
@@ -922,6 +923,51 @@ export class ClearingHouse {
922
923
  });
923
924
  }
924
925
 
926
+ public async cancelAllOrders(
927
+ oracles?: PublicKey[]
928
+ ): Promise<TransactionSignature> {
929
+ return await this.txSender.send(
930
+ wrapInTx(await this.getCancelAllOrdersIx(oracles)),
931
+ [],
932
+ this.opts
933
+ );
934
+ }
935
+
936
+ public async getCancelAllOrdersIx(
937
+ oracles: PublicKey[]
938
+ ): Promise<TransactionInstruction> {
939
+ const userAccountPublicKey = await this.getUserAccountPublicKey();
940
+ const userAccount = await this.getUserAccount();
941
+
942
+ const state = this.getStateAccount();
943
+ const orderState = this.getOrderStateAccount();
944
+
945
+ const remainingAccounts = [];
946
+ for (const oracle of oracles) {
947
+ remainingAccounts.push({
948
+ pubkey: oracle,
949
+ isWritable: false,
950
+ isSigner: false,
951
+ });
952
+ }
953
+
954
+ return await this.program.instruction.cancelAllOrders({
955
+ accounts: {
956
+ state: await this.getStatePublicKey(),
957
+ user: userAccountPublicKey,
958
+ authority: this.wallet.publicKey,
959
+ markets: state.markets,
960
+ userOrders: await this.getUserOrdersAccountPublicKey(),
961
+ userPositions: userAccount.positions,
962
+ fundingPaymentHistory: state.fundingPaymentHistory,
963
+ fundingRateHistory: state.fundingRateHistory,
964
+ orderState: await this.getOrderStatePublicKey(),
965
+ orderHistory: orderState.orderHistory,
966
+ },
967
+ remainingAccounts,
968
+ });
969
+ }
970
+
925
971
  public async fillOrder(
926
972
  userAccountPublicKey: PublicKey,
927
973
  userOrdersAccountPublicKey: PublicKey,
@@ -1160,6 +1206,31 @@ export class ClearingHouse {
1160
1206
  );
1161
1207
  }
1162
1208
 
1209
+ public async closeAllPositions(
1210
+ userPositionsAccount: UserPositionsAccount,
1211
+ discountToken?: PublicKey,
1212
+ referrer?: PublicKey
1213
+ ): Promise<TransactionSignature> {
1214
+ const ixs: TransactionInstruction[] = [];
1215
+ for (const userPosition of userPositionsAccount.positions) {
1216
+ if (userPosition.baseAssetAmount.eq(ZERO)) {
1217
+ continue;
1218
+ }
1219
+
1220
+ ixs.push(
1221
+ await this.getClosePositionIx(
1222
+ userPosition.marketIndex,
1223
+ discountToken,
1224
+ referrer
1225
+ )
1226
+ );
1227
+ }
1228
+
1229
+ const tx = new Transaction().add(...ixs);
1230
+
1231
+ return this.txSender.send(tx, [], this.opts);
1232
+ }
1233
+
1163
1234
  public async liquidate(
1164
1235
  liquidateeUserAccountPublicKey: PublicKey
1165
1236
  ): Promise<TransactionSignature> {
@@ -187,6 +187,17 @@ export const Markets: MarketConfig[] = [
187
187
  launchTs: 1648607439000,
188
188
  oracleSource: OracleSource.PYTH,
189
189
  },
190
+ {
191
+ fullName: 'Near',
192
+ category: ['L1', 'Infra'],
193
+ symbol: 'NEAR-PERP',
194
+ baseAssetSymbol: 'NEAR',
195
+ marketIndex: new BN(16),
196
+ devnetPublicKey: '3gnSbT7bhoTdGkFVZc1dW1PvjreWzpUNUD5ppXwv1N59',
197
+ mainnetPublicKey: 'ECSFWQ1bnnpqPVvoy9237t2wddZAaHisW88mYxuEHKWf',
198
+ launchTs: 1649105516000,
199
+ oracleSource: OracleSource.PYTH,
200
+ },
190
201
  // {
191
202
  // symbol: 'mSOL-PERP',
192
203
  // baseAssetSymbol: 'mSOL',
@@ -677,6 +677,57 @@
677
677
  }
678
678
  ]
679
679
  },
680
+ {
681
+ "name": "cancelAllOrders",
682
+ "accounts": [
683
+ {
684
+ "name": "state",
685
+ "isMut": false,
686
+ "isSigner": false
687
+ },
688
+ {
689
+ "name": "orderState",
690
+ "isMut": false,
691
+ "isSigner": false
692
+ },
693
+ {
694
+ "name": "user",
695
+ "isMut": false,
696
+ "isSigner": false
697
+ },
698
+ {
699
+ "name": "authority",
700
+ "isMut": false,
701
+ "isSigner": true
702
+ },
703
+ {
704
+ "name": "markets",
705
+ "isMut": false,
706
+ "isSigner": false
707
+ },
708
+ {
709
+ "name": "userPositions",
710
+ "isMut": true,
711
+ "isSigner": false
712
+ },
713
+ {
714
+ "name": "userOrders",
715
+ "isMut": true,
716
+ "isSigner": false
717
+ },
718
+ {
719
+ "name": "fundingPaymentHistory",
720
+ "isMut": true,
721
+ "isSigner": false
722
+ },
723
+ {
724
+ "name": "orderHistory",
725
+ "isMut": true,
726
+ "isSigner": false
727
+ }
728
+ ],
729
+ "args": []
730
+ },
680
731
  {
681
732
  "name": "expireOrders",
682
733
  "accounts": [
@@ -1444,6 +1495,11 @@
1444
1495
  "isMut": true,
1445
1496
  "isSigner": false
1446
1497
  },
1498
+ {
1499
+ "name": "userOrders",
1500
+ "isMut": true,
1501
+ "isSigner": false
1502
+ },
1447
1503
  {
1448
1504
  "name": "authority",
1449
1505
  "isMut": false,
@@ -3236,8 +3292,8 @@
3236
3292
  "type": "u128"
3237
3293
  },
3238
3294
  {
3239
- "name": "padding1",
3240
- "type": "u64"
3295
+ "name": "netRevenueSinceLastFunding",
3296
+ "type": "i64"
3241
3297
  },
3242
3298
  {
3243
3299
  "name": "padding2",
@@ -4244,6 +4300,11 @@
4244
4300
  "code": 6060,
4245
4301
  "name": "CantExpireOrders",
4246
4302
  "msg": "CantExpireOrders"
4303
+ },
4304
+ {
4305
+ "code": 6061,
4306
+ "name": "InvalidRepegPriceImpact",
4307
+ "msg": "AMM repeg mark price impact vs oracle too large"
4247
4308
  }
4248
4309
  ]
4249
4310
  }
package/src/index.ts CHANGED
@@ -29,6 +29,7 @@ export * from './math/position';
29
29
  export * from './math/amm';
30
30
  export * from './math/trade';
31
31
  export * from './math/orders';
32
+ export * from './math/repeg';
32
33
  export * from './orders';
33
34
  export * from './orderParams';
34
35
  export * from './wallet';