@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.
- package/lib/accounts/bulkAccountLoader.d.ts +1 -0
- package/lib/accounts/bulkAccountLoader.js +33 -13
- package/lib/clearingHouse.d.ts +4 -1
- package/lib/clearingHouse.js +49 -0
- package/lib/constants/markets.js +11 -0
- package/lib/idl/clearing_house.json +63 -2
- package/lib/index.d.ts +1 -0
- package/lib/index.js +1 -0
- package/lib/math/amm.d.ts +0 -20
- package/lib/math/amm.js +1 -151
- package/lib/math/repeg.d.ts +32 -0
- package/lib/math/repeg.js +178 -0
- package/lib/oracles/pythClient.js +1 -1
- package/lib/orderParams.d.ts +1 -1
- package/lib/orderParams.js +2 -2
- package/lib/tx/retryTxSender.d.ts +5 -2
- package/lib/tx/retryTxSender.js +14 -1
- package/package.json +1 -1
- package/src/accounts/bulkAccountLoader.ts +40 -15
- package/src/clearingHouse.ts +71 -0
- package/src/constants/markets.ts +11 -0
- package/src/idl/clearing_house.json +63 -2
- package/src/index.ts +1 -0
- package/src/math/amm.ts +1 -212
- package/src/math/repeg.ts +253 -0
- package/src/oracles/pythClient.ts +1 -1
- package/src/orderParams.ts +3 -2
- package/src/tx/retryTxSender.ts +19 -1
- package/src/accounts/bulkUserSubscription.js +0 -56
- package/src/accounts/bulkUserSubscription.js.map +0 -1
- package/src/accounts/pollingUserAccountSubscriber.js +0 -139
- package/src/accounts/pollingUserAccountSubscriber.js.map +0 -1
- package/src/accounts/types.js +0 -11
- package/src/accounts/types.js.map +0 -1
- package/src/accounts/webSocketUserAccountSubscriber.js +0 -78
- package/src/accounts/webSocketUserAccountSubscriber.js.map +0 -1
- package/src/addresses.js +0 -59
- package/src/addresses.js.map +0 -1
- package/src/admin.js +0 -443
- package/src/admin.js.map +0 -1
- package/src/clearingHouseUser.js +0 -581
- package/src/clearingHouseUser.js.map +0 -1
- package/src/config.js +0 -37
- package/src/config.js.map +0 -1
- package/src/factory/clearingHouse.js +0 -65
- package/src/factory/clearingHouse.js.map +0 -1
- package/src/factory/clearingHouseUser.js +0 -35
- package/src/factory/clearingHouseUser.js.map +0 -1
- package/src/factory/oracleClient.js +0 -17
- package/src/factory/oracleClient.js.map +0 -1
- package/src/index.js +0 -56
- package/src/index.js.map +0 -1
- package/src/math/amm.js +0 -285
- package/src/math/amm.js.map +0 -1
- package/src/mockUSDCFaucet.js +0 -143
- package/src/mockUSDCFaucet.js.map +0 -1
- package/src/oracles/pythClient.js +0 -39
- package/src/oracles/pythClient.js.map +0 -1
- package/src/orderParams.js +0 -109
- package/src/orderParams.js.map +0 -1
- package/src/orders.js +0 -172
- package/src/orders.js.map +0 -1
- package/src/tx/retryTxSender.js +0 -137
- package/src/tx/retryTxSender.js.map +0 -1
- package/src/types.js +0 -61
- package/src/types.js.map +0 -1
- package/src/wallet.js +0 -23
- 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),
|
package/lib/orderParams.d.ts
CHANGED
|
@@ -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;
|
package/lib/orderParams.js
CHANGED
|
@@ -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
|
|
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
|
-
|
|
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 {};
|
package/lib/tx/retryTxSender.js
CHANGED
|
@@ -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
|
@@ -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
|
-
|
|
132
|
-
|
|
133
|
-
|
|
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 (
|
|
165
|
-
|
|
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 (
|
|
183
|
-
|
|
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
|
-
|
|
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
|
-
|
|
241
|
-
|
|
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
|
}
|
package/src/clearingHouse.ts
CHANGED
|
@@ -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> {
|
package/src/constants/markets.ts
CHANGED
|
@@ -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": "
|
|
3240
|
-
"type": "
|
|
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