@drift-labs/sdk 0.2.0-master.3 → 0.2.0-master.31
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/README.md +13 -13
- package/lib/accounts/bulkUserStatsSubscription.d.ts +7 -0
- package/lib/accounts/bulkUserStatsSubscription.js +21 -0
- package/lib/accounts/bulkUserSubscription.js +0 -1
- package/lib/accounts/fetch.d.ts +2 -1
- package/lib/accounts/fetch.js +9 -1
- package/lib/accounts/pollingClearingHouseAccountSubscriber.d.ts +16 -16
- package/lib/accounts/pollingClearingHouseAccountSubscriber.js +31 -28
- package/lib/accounts/pollingUserStatsAccountSubscriber.d.ts +27 -0
- package/lib/accounts/pollingUserStatsAccountSubscriber.js +113 -0
- package/lib/accounts/types.d.ts +22 -11
- package/lib/accounts/webSocketClearingHouseAccountSubscriber.d.ts +17 -17
- package/lib/accounts/webSocketClearingHouseAccountSubscriber.js +37 -35
- package/lib/accounts/webSocketUserStatsAccountSubsriber.d.ts +20 -0
- package/lib/accounts/webSocketUserStatsAccountSubsriber.js +47 -0
- package/lib/addresses/marketAddresses.d.ts +1 -3
- package/lib/addresses/pda.d.ts +10 -4
- package/lib/addresses/pda.js +51 -14
- package/lib/admin.d.ts +42 -26
- package/lib/admin.js +228 -81
- package/lib/clearingHouse.d.ts +130 -49
- package/lib/clearingHouse.js +1256 -367
- package/lib/clearingHouseConfig.d.ts +4 -4
- package/lib/clearingHouseUser.d.ts +51 -39
- package/lib/clearingHouseUser.js +408 -191
- package/lib/clearingHouseUserStats.d.ts +18 -0
- package/lib/clearingHouseUserStats.js +49 -0
- package/lib/clearingHouseUserStatsConfig.d.ts +14 -0
- package/lib/clearingHouseUserStatsConfig.js +2 -0
- package/lib/config.d.ts +7 -9
- package/lib/config.js +21 -21
- package/lib/constants/numericConstants.d.ts +25 -12
- package/lib/constants/numericConstants.js +35 -21
- package/lib/constants/perpMarkets.d.ts +18 -0
- package/lib/constants/{markets.js → perpMarkets.js} +7 -7
- package/lib/constants/spotMarkets.d.ts +19 -0
- package/lib/constants/spotMarkets.js +53 -0
- package/lib/dlob/DLOB.d.ts +74 -0
- package/lib/dlob/DLOB.js +595 -0
- package/lib/dlob/DLOBNode.d.ts +54 -0
- package/lib/dlob/DLOBNode.js +85 -0
- package/lib/dlob/NodeList.d.ts +26 -0
- package/lib/dlob/NodeList.js +139 -0
- package/lib/events/eventList.js +3 -0
- package/lib/events/eventSubscriber.d.ts +4 -2
- package/lib/events/eventSubscriber.js +16 -9
- package/lib/events/fetchLogs.d.ts +10 -1
- package/lib/events/fetchLogs.js +27 -7
- package/lib/events/pollingLogProvider.d.ts +2 -1
- package/lib/events/pollingLogProvider.js +6 -2
- package/lib/events/sort.js +8 -11
- package/lib/events/types.d.ts +8 -2
- package/lib/events/types.js +6 -0
- package/lib/examples/makeTradeExample.js +20 -8
- package/lib/factory/bigNum.d.ts +2 -0
- package/lib/factory/bigNum.js +48 -10
- package/lib/idl/clearing_house.json +4889 -1529
- package/lib/idl/{mock_usdc_faucet.json → token_faucet.json} +46 -23
- package/lib/index.d.ts +21 -6
- package/lib/index.js +25 -6
- package/lib/math/amm.d.ts +9 -6
- package/lib/math/amm.js +91 -66
- package/lib/math/auction.js +4 -1
- package/lib/math/conversion.js +1 -1
- package/lib/math/funding.d.ts +6 -6
- package/lib/math/funding.js +11 -10
- package/lib/math/insurance.d.ts +4 -0
- package/lib/math/insurance.js +27 -0
- package/lib/math/margin.d.ts +11 -0
- package/lib/math/margin.js +77 -0
- package/lib/math/market.d.ts +14 -9
- package/lib/math/market.js +72 -10
- package/lib/math/oracles.d.ts +4 -0
- package/lib/math/oracles.js +36 -8
- package/lib/math/orders.d.ts +6 -2
- package/lib/math/orders.js +78 -3
- package/lib/math/position.d.ts +21 -13
- package/lib/math/position.js +76 -36
- package/lib/math/repeg.js +14 -5
- package/lib/math/spotBalance.d.ts +22 -0
- package/lib/math/spotBalance.js +192 -0
- package/lib/math/spotMarket.d.ts +4 -0
- package/lib/math/spotMarket.js +8 -0
- package/lib/math/spotPosition.d.ts +6 -0
- package/lib/math/spotPosition.js +23 -0
- package/lib/math/trade.d.ts +10 -10
- package/lib/math/trade.js +32 -39
- package/lib/oracles/pythClient.js +1 -1
- package/lib/oracles/quoteAssetOracleClient.js +1 -1
- package/lib/oracles/switchboardClient.js +1 -1
- package/lib/orderParams.d.ts +14 -5
- package/lib/orderParams.js +12 -92
- package/lib/serum/serumSubscriber.d.ts +23 -0
- package/lib/serum/serumSubscriber.js +41 -0
- package/lib/serum/types.d.ts +11 -0
- package/lib/serum/types.js +2 -0
- package/lib/slot/SlotSubscriber.d.ts +7 -0
- package/lib/slot/SlotSubscriber.js +3 -0
- package/lib/{mockUSDCFaucet.d.ts → tokenFaucet.d.ts} +8 -5
- package/lib/{mockUSDCFaucet.js → tokenFaucet.js} +63 -51
- package/lib/tx/retryTxSender.d.ts +1 -1
- package/lib/tx/retryTxSender.js +13 -4
- package/lib/tx/types.d.ts +1 -1
- package/lib/tx/utils.js +1 -1
- package/lib/types.d.ts +566 -138
- package/lib/types.js +129 -5
- package/lib/userMap/userMap.d.ts +25 -0
- package/lib/userMap/userMap.js +73 -0
- package/lib/userMap/userStatsMap.d.ts +19 -0
- package/lib/userMap/userStatsMap.js +68 -0
- package/lib/util/computeUnits.js +1 -1
- package/lib/util/getTokenAddress.d.ts +2 -0
- package/lib/util/getTokenAddress.js +9 -0
- package/package.json +12 -6
- package/src/accounts/bulkUserStatsSubscription.ts +33 -0
- package/src/accounts/bulkUserSubscription.ts +0 -1
- package/src/accounts/fetch.ts +27 -2
- package/src/accounts/pollingClearingHouseAccountSubscriber.ts +46 -42
- package/src/accounts/pollingUserStatsAccountSubscriber.ts +172 -0
- package/src/accounts/types.ts +31 -11
- package/src/accounts/webSocketClearingHouseAccountSubscriber.ts +64 -59
- package/src/accounts/webSocketUserStatsAccountSubsriber.ts +80 -0
- package/src/addresses/marketAddresses.ts +1 -2
- package/src/addresses/pda.ts +88 -14
- package/src/admin.ts +452 -147
- package/src/assert/assert.js +9 -0
- package/src/clearingHouse.ts +2066 -467
- package/src/clearingHouseConfig.ts +4 -3
- package/src/clearingHouseUser.ts +747 -294
- package/src/clearingHouseUserStats.ts +75 -0
- package/src/clearingHouseUserStatsConfig.ts +18 -0
- package/src/config.ts +30 -31
- package/src/constants/numericConstants.ts +48 -25
- package/src/constants/{markets.ts → perpMarkets.ts} +10 -10
- package/src/constants/spotMarkets.ts +73 -0
- package/src/dlob/DLOB.ts +953 -0
- package/src/dlob/DLOBNode.ts +167 -0
- package/src/dlob/NodeList.ts +189 -0
- package/src/events/eventList.js +77 -0
- package/src/events/eventList.ts +3 -0
- package/src/events/eventSubscriber.ts +20 -12
- package/src/events/fetchLogs.ts +35 -8
- package/src/events/pollingLogProvider.ts +10 -2
- package/src/events/sort.ts +11 -15
- package/src/events/types.ts +19 -1
- package/src/examples/makeTradeExample.js +157 -0
- package/src/examples/makeTradeExample.ts +32 -14
- package/src/factory/bigNum.ts +65 -13
- package/src/idl/clearing_house.json +4889 -1529
- package/src/idl/{mock_usdc_faucet.json → token_faucet.json} +46 -23
- package/src/index.ts +21 -6
- package/src/math/amm.ts +171 -88
- package/src/math/auction.ts +5 -1
- package/src/math/conversion.ts +2 -2
- package/src/math/funding.ts +20 -18
- package/src/math/insurance.ts +35 -0
- package/src/math/margin.ts +127 -0
- package/src/math/market.ts +145 -14
- package/src/math/oracles.ts +63 -9
- package/src/math/orders.ts +138 -4
- package/src/math/position.ts +119 -58
- package/src/math/repeg.ts +16 -6
- package/src/math/spotBalance.ts +319 -0
- package/src/math/spotMarket.ts +9 -0
- package/src/math/spotPosition.ts +47 -0
- package/src/math/trade.ts +53 -59
- package/src/oracles/pythClient.ts +2 -2
- package/src/oracles/quoteAssetOracleClient.ts +2 -2
- package/src/oracles/switchboardClient.ts +2 -2
- package/src/orderParams.ts +24 -137
- package/src/serum/serumSubscriber.ts +80 -0
- package/src/serum/types.ts +13 -0
- package/src/slot/SlotSubscriber.ts +11 -1
- package/src/token/index.js +38 -0
- package/src/{mockUSDCFaucet.ts → tokenFaucet.ts} +82 -70
- package/src/tx/retryTxSender.ts +16 -5
- package/src/tx/types.js +2 -0
- package/src/tx/types.ts +2 -1
- package/src/tx/utils.js +17 -0
- package/src/tx/utils.ts +1 -1
- package/src/types.ts +533 -140
- package/src/userMap/userMap.ts +100 -0
- package/src/userMap/userStatsMap.ts +110 -0
- package/src/util/computeUnits.js +21 -11
- package/src/util/computeUnits.ts +1 -1
- package/src/util/getTokenAddress.js +9 -0
- package/src/util/getTokenAddress.ts +18 -0
- package/src/util/promiseTimeout.js +14 -0
- package/src/util/tps.js +27 -0
- package/tests/bn/test.ts +24 -10
- package/tests/dlob/helpers.ts +397 -0
- package/tests/dlob/test.ts +3688 -0
- package/lib/constants/banks.d.ts +0 -16
- package/lib/constants/banks.js +0 -34
- package/lib/constants/markets.d.ts +0 -19
- package/lib/math/bankBalance.d.ts +0 -9
- package/lib/math/bankBalance.js +0 -75
- package/lib/math/state.d.ts +0 -8
- package/lib/math/state.js +0 -15
- package/lib/orders.d.ts +0 -8
- package/lib/orders.js +0 -134
- package/src/constants/banks.ts +0 -43
- package/src/math/bankBalance.ts +0 -112
- package/src/math/state.ts +0 -14
- package/src/math/utils.js +0 -27
- package/src/math/utils.js.map +0 -1
- package/src/orders.ts +0 -244
- package/src/util/computeUnits.js.map +0 -1
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createNode = exports.TriggerOrderNode = exports.MarketOrderNode = exports.FloatingLimitOrderNode = exports.LimitOrderNode = exports.OrderNode = void 0;
|
|
4
|
+
const __1 = require("..");
|
|
5
|
+
const NodeList_1 = require("./NodeList");
|
|
6
|
+
class OrderNode {
|
|
7
|
+
constructor(order, market, userAccount) {
|
|
8
|
+
this.haveFilled = false;
|
|
9
|
+
this.haveTrigger = false;
|
|
10
|
+
this.order = order;
|
|
11
|
+
this.market = market;
|
|
12
|
+
this.userAccount = userAccount;
|
|
13
|
+
this.sortValue = this.getSortValue(order);
|
|
14
|
+
}
|
|
15
|
+
getLabel() {
|
|
16
|
+
let msg = `Order ${(0, NodeList_1.getOrderSignature)(this.order.orderId, this.userAccount)}`;
|
|
17
|
+
msg += ` ${(0, __1.isVariant)(this.order.direction, 'long') ? 'LONG' : 'SHORT'} `;
|
|
18
|
+
msg += `${(0, __1.convertToNumber)(this.order.baseAssetAmount, __1.AMM_RESERVE_PRECISION).toFixed(3)}`;
|
|
19
|
+
if (this.order.price.gt(__1.ZERO)) {
|
|
20
|
+
msg += ` @ ${(0, __1.convertToNumber)(this.order.price, __1.PRICE_PRECISION).toFixed(3)}`;
|
|
21
|
+
}
|
|
22
|
+
if (this.order.triggerPrice.gt(__1.ZERO)) {
|
|
23
|
+
msg += ` ${(0, __1.isVariant)(this.order.triggerCondition, 'below') ? 'BELOW' : 'ABOVE'}`;
|
|
24
|
+
msg += ` ${(0, __1.convertToNumber)(this.order.triggerPrice, __1.PRICE_PRECISION).toFixed(3)}`;
|
|
25
|
+
}
|
|
26
|
+
return msg;
|
|
27
|
+
}
|
|
28
|
+
getPrice(oraclePriceData, slot) {
|
|
29
|
+
if ((0, __1.isOneOfVariant)(this.order.marketType, ['spot'])) {
|
|
30
|
+
return (0, __1.getLimitPrice)(this.order, oraclePriceData, slot);
|
|
31
|
+
}
|
|
32
|
+
else if ((0, __1.isOneOfVariant)(this.order.marketType, ['perp'])) {
|
|
33
|
+
return (0, __1.getLimitPrice)(this.order, oraclePriceData, slot, this.market);
|
|
34
|
+
}
|
|
35
|
+
else {
|
|
36
|
+
console.error(`Unknown market type: ${this.order.marketType}`);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
isBaseFilled() {
|
|
40
|
+
return this.order.baseAssetAmountFilled.eq(this.order.baseAssetAmount);
|
|
41
|
+
}
|
|
42
|
+
isVammNode() {
|
|
43
|
+
return false;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
exports.OrderNode = OrderNode;
|
|
47
|
+
class LimitOrderNode extends OrderNode {
|
|
48
|
+
getSortValue(order) {
|
|
49
|
+
return order.price;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
exports.LimitOrderNode = LimitOrderNode;
|
|
53
|
+
class FloatingLimitOrderNode extends OrderNode {
|
|
54
|
+
getSortValue(order) {
|
|
55
|
+
return order.oraclePriceOffset;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
exports.FloatingLimitOrderNode = FloatingLimitOrderNode;
|
|
59
|
+
class MarketOrderNode extends OrderNode {
|
|
60
|
+
getSortValue(order) {
|
|
61
|
+
return order.slot;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
exports.MarketOrderNode = MarketOrderNode;
|
|
65
|
+
class TriggerOrderNode extends OrderNode {
|
|
66
|
+
getSortValue(order) {
|
|
67
|
+
return order.triggerPrice;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
exports.TriggerOrderNode = TriggerOrderNode;
|
|
71
|
+
function createNode(nodeType, order, market, userAccount) {
|
|
72
|
+
switch (nodeType) {
|
|
73
|
+
case 'floatingLimit':
|
|
74
|
+
return new FloatingLimitOrderNode(order, market, userAccount);
|
|
75
|
+
case 'limit':
|
|
76
|
+
return new LimitOrderNode(order, market, userAccount);
|
|
77
|
+
case 'market':
|
|
78
|
+
return new MarketOrderNode(order, market, userAccount);
|
|
79
|
+
case 'trigger':
|
|
80
|
+
return new TriggerOrderNode(order, market, userAccount);
|
|
81
|
+
default:
|
|
82
|
+
throw Error(`Unknown DLOBNode type ${nodeType}`);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
exports.createNode = createNode;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/// <reference types="bn.js" />
|
|
2
|
+
import { BN, MarketTypeStr, Order, PerpMarketAccount, SpotMarketAccount } from '..';
|
|
3
|
+
import { PublicKey } from '@solana/web3.js';
|
|
4
|
+
import { DLOBNode, DLOBNodeMap } from './DLOBNode';
|
|
5
|
+
export declare type SortDirection = 'asc' | 'desc';
|
|
6
|
+
export declare function getOrderSignature(orderId: number, userAccount: PublicKey): string;
|
|
7
|
+
export interface DLOBNodeGenerator {
|
|
8
|
+
getGenerator(): Generator<DLOBNode>;
|
|
9
|
+
}
|
|
10
|
+
export declare class NodeList<NodeType extends keyof DLOBNodeMap> implements DLOBNodeGenerator {
|
|
11
|
+
private nodeType;
|
|
12
|
+
private sortDirection;
|
|
13
|
+
head?: DLOBNodeMap[NodeType];
|
|
14
|
+
length: number;
|
|
15
|
+
nodeMap: Map<string, DLOBNodeMap[NodeType]>;
|
|
16
|
+
constructor(nodeType: NodeType, sortDirection: SortDirection);
|
|
17
|
+
insert(order: Order, marketType: MarketTypeStr, market: PerpMarketAccount | SpotMarketAccount, userAccount: PublicKey): void;
|
|
18
|
+
prependNode(currentNode: DLOBNodeMap[NodeType], newNode: DLOBNodeMap[NodeType]): boolean;
|
|
19
|
+
update(order: Order, userAccount: PublicKey): void;
|
|
20
|
+
remove(order: Order, userAccount: PublicKey): void;
|
|
21
|
+
getGenerator(): Generator<DLOBNode>;
|
|
22
|
+
has(order: Order, userAccount: PublicKey): boolean;
|
|
23
|
+
print(): void;
|
|
24
|
+
printTop(): void;
|
|
25
|
+
}
|
|
26
|
+
export declare function getVammNodeGenerator(price: BN | undefined): Generator<DLOBNode>;
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.getVammNodeGenerator = exports.NodeList = exports.getOrderSignature = void 0;
|
|
4
|
+
const __1 = require("..");
|
|
5
|
+
const DLOBNode_1 = require("./DLOBNode");
|
|
6
|
+
function getOrderSignature(orderId, userAccount) {
|
|
7
|
+
return `${userAccount.toString()}-${orderId.toString()}`;
|
|
8
|
+
}
|
|
9
|
+
exports.getOrderSignature = getOrderSignature;
|
|
10
|
+
class NodeList {
|
|
11
|
+
constructor(nodeType, sortDirection) {
|
|
12
|
+
this.nodeType = nodeType;
|
|
13
|
+
this.sortDirection = sortDirection;
|
|
14
|
+
this.length = 0;
|
|
15
|
+
this.nodeMap = new Map();
|
|
16
|
+
}
|
|
17
|
+
insert(order, marketType, market, userAccount) {
|
|
18
|
+
if ((0, __1.isVariant)(order.status, 'init')) {
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
if (marketType === 'spot') {
|
|
22
|
+
market = market;
|
|
23
|
+
}
|
|
24
|
+
else if (marketType === 'perp') {
|
|
25
|
+
market = market;
|
|
26
|
+
}
|
|
27
|
+
const newNode = (0, DLOBNode_1.createNode)(this.nodeType, order, market, userAccount);
|
|
28
|
+
const orderSignature = getOrderSignature(order.orderId, userAccount);
|
|
29
|
+
if (this.nodeMap.has(orderSignature)) {
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
this.nodeMap.set(orderSignature, newNode);
|
|
33
|
+
this.length += 1;
|
|
34
|
+
if (this.head === undefined) {
|
|
35
|
+
this.head = newNode;
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
if (this.prependNode(this.head, newNode)) {
|
|
39
|
+
this.head.previous = newNode;
|
|
40
|
+
newNode.next = this.head;
|
|
41
|
+
this.head = newNode;
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
let currentNode = this.head;
|
|
45
|
+
while (currentNode.next !== undefined &&
|
|
46
|
+
!this.prependNode(currentNode.next, newNode)) {
|
|
47
|
+
currentNode = currentNode.next;
|
|
48
|
+
}
|
|
49
|
+
newNode.next = currentNode.next;
|
|
50
|
+
if (currentNode.next !== undefined) {
|
|
51
|
+
newNode.next.previous = newNode;
|
|
52
|
+
}
|
|
53
|
+
currentNode.next = newNode;
|
|
54
|
+
newNode.previous = currentNode;
|
|
55
|
+
}
|
|
56
|
+
prependNode(currentNode, newNode) {
|
|
57
|
+
const currentOrder = currentNode.order;
|
|
58
|
+
const newOrder = newNode.order;
|
|
59
|
+
const currentOrderSortPrice = currentNode.sortValue;
|
|
60
|
+
const newOrderSortPrice = newNode.sortValue;
|
|
61
|
+
if (newOrderSortPrice.eq(currentOrderSortPrice)) {
|
|
62
|
+
return newOrder.ts.lt(currentOrder.ts);
|
|
63
|
+
}
|
|
64
|
+
if (this.sortDirection === 'asc') {
|
|
65
|
+
return newOrderSortPrice.lt(currentOrderSortPrice);
|
|
66
|
+
}
|
|
67
|
+
else {
|
|
68
|
+
return newOrderSortPrice.gt(currentOrderSortPrice);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
update(order, userAccount) {
|
|
72
|
+
const orderId = getOrderSignature(order.orderId, userAccount);
|
|
73
|
+
if (this.nodeMap.has(orderId)) {
|
|
74
|
+
const node = this.nodeMap.get(orderId);
|
|
75
|
+
Object.assign(node.order, order);
|
|
76
|
+
node.haveFilled = false;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
remove(order, userAccount) {
|
|
80
|
+
const orderId = getOrderSignature(order.orderId, userAccount);
|
|
81
|
+
if (this.nodeMap.has(orderId)) {
|
|
82
|
+
const node = this.nodeMap.get(orderId);
|
|
83
|
+
if (node.next) {
|
|
84
|
+
node.next.previous = node.previous;
|
|
85
|
+
}
|
|
86
|
+
if (node.previous) {
|
|
87
|
+
node.previous.next = node.next;
|
|
88
|
+
}
|
|
89
|
+
if (this.head && node.order.orderId === this.head.order.orderId) {
|
|
90
|
+
this.head = node.next;
|
|
91
|
+
}
|
|
92
|
+
node.previous = undefined;
|
|
93
|
+
node.next = undefined;
|
|
94
|
+
this.nodeMap.delete(orderId);
|
|
95
|
+
this.length--;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
*getGenerator() {
|
|
99
|
+
let node = this.head;
|
|
100
|
+
while (node !== undefined) {
|
|
101
|
+
yield node;
|
|
102
|
+
node = node.next;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
has(order, userAccount) {
|
|
106
|
+
return this.nodeMap.has(getOrderSignature(order.orderId, userAccount));
|
|
107
|
+
}
|
|
108
|
+
print() {
|
|
109
|
+
let currentNode = this.head;
|
|
110
|
+
while (currentNode !== undefined) {
|
|
111
|
+
console.log(currentNode.getLabel());
|
|
112
|
+
currentNode = currentNode.next;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
printTop() {
|
|
116
|
+
if (this.head) {
|
|
117
|
+
console.log(this.sortDirection.toUpperCase(), this.head.getLabel());
|
|
118
|
+
}
|
|
119
|
+
else {
|
|
120
|
+
console.log('---');
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
exports.NodeList = NodeList;
|
|
125
|
+
function* getVammNodeGenerator(price) {
|
|
126
|
+
if (!price) {
|
|
127
|
+
return;
|
|
128
|
+
}
|
|
129
|
+
yield {
|
|
130
|
+
getPrice: () => price,
|
|
131
|
+
isVammNode: () => true,
|
|
132
|
+
order: undefined,
|
|
133
|
+
market: undefined,
|
|
134
|
+
userAccount: undefined,
|
|
135
|
+
isBaseFilled: () => false,
|
|
136
|
+
haveFilled: false,
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
exports.getVammNodeGenerator = getVammNodeGenerator;
|
package/lib/events/eventList.js
CHANGED
|
@@ -15,10 +15,12 @@ export declare class EventSubscriber {
|
|
|
15
15
|
private awaitTxResolver;
|
|
16
16
|
private logProvider;
|
|
17
17
|
eventEmitter: StrictEventEmitter<EventEmitter, EventSubscriberEvents>;
|
|
18
|
+
private lastSeenSlot;
|
|
19
|
+
lastSeenTxSig: string;
|
|
18
20
|
constructor(connection: Connection, program: Program, options?: EventSubscriptionOptions);
|
|
19
|
-
subscribe(): boolean
|
|
21
|
+
subscribe(): Promise<boolean>;
|
|
20
22
|
private handleTxLogs;
|
|
21
|
-
|
|
23
|
+
fetchPreviousTx(fetchMax?: boolean): Promise<void>;
|
|
22
24
|
unsubscribe(): Promise<boolean>;
|
|
23
25
|
private parseEventsFromLogs;
|
|
24
26
|
awaitTx(txSig: TransactionSignature): Promise<void>;
|
|
@@ -30,17 +30,21 @@ class EventSubscriber {
|
|
|
30
30
|
this.logProvider = new pollingLogProvider_1.PollingLogProvider(this.connection, this.program.programId, options.commitment, this.options.logProviderConfig.frequency);
|
|
31
31
|
}
|
|
32
32
|
}
|
|
33
|
-
subscribe() {
|
|
34
|
-
|
|
33
|
+
async subscribe() {
|
|
34
|
+
try {
|
|
35
|
+
if (this.logProvider.isSubscribed()) {
|
|
36
|
+
return true;
|
|
37
|
+
}
|
|
38
|
+
this.logProvider.subscribe((txSig, slot, logs) => {
|
|
39
|
+
this.handleTxLogs(txSig, slot, logs);
|
|
40
|
+
}, true);
|
|
35
41
|
return true;
|
|
36
42
|
}
|
|
37
|
-
|
|
43
|
+
catch (e) {
|
|
38
44
|
console.error('Error fetching previous txs in event subscriber');
|
|
39
45
|
console.error(e);
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
this.handleTxLogs(txSig, slot, logs);
|
|
43
|
-
});
|
|
46
|
+
return false;
|
|
47
|
+
}
|
|
44
48
|
}
|
|
45
49
|
handleTxLogs(txSig, slot, logs) {
|
|
46
50
|
if (this.txEventCache.has(txSig)) {
|
|
@@ -56,10 +60,13 @@ class EventSubscriber {
|
|
|
56
60
|
this.awaitTxResolver.get(txSig)();
|
|
57
61
|
this.awaitTxResolver.delete(txSig);
|
|
58
62
|
}
|
|
63
|
+
if (slot > this.lastSeenSlot) {
|
|
64
|
+
this.lastSeenTxSig = txSig;
|
|
65
|
+
}
|
|
59
66
|
this.txEventCache.add(txSig, wrappedEvents);
|
|
60
67
|
}
|
|
61
|
-
async fetchPreviousTx() {
|
|
62
|
-
if (!this.options.untilTx) {
|
|
68
|
+
async fetchPreviousTx(fetchMax) {
|
|
69
|
+
if (!this.options.untilTx && !fetchMax) {
|
|
63
70
|
return;
|
|
64
71
|
}
|
|
65
72
|
let txFetched = 0;
|
|
@@ -1,4 +1,6 @@
|
|
|
1
|
+
import { Program } from '@project-serum/anchor';
|
|
1
2
|
import { Connection, Finality, PublicKey, TransactionSignature } from '@solana/web3.js';
|
|
3
|
+
import { WrappedEvents } from './types';
|
|
2
4
|
declare type Log = {
|
|
3
5
|
txSig: TransactionSignature;
|
|
4
6
|
slot: number;
|
|
@@ -7,7 +9,14 @@ declare type Log = {
|
|
|
7
9
|
declare type FetchLogsResponse = {
|
|
8
10
|
earliestTx: string;
|
|
9
11
|
mostRecentTx: string;
|
|
12
|
+
earliestSlot: number;
|
|
13
|
+
mostRecentSlot: number;
|
|
10
14
|
transactionLogs: Log[];
|
|
11
15
|
};
|
|
12
|
-
export declare function fetchLogs(connection: Connection, programId: PublicKey, finality: Finality, beforeTx?: TransactionSignature, untilTx?: TransactionSignature): Promise<FetchLogsResponse
|
|
16
|
+
export declare function fetchLogs(connection: Connection, programId: PublicKey, finality: Finality, beforeTx?: TransactionSignature, untilTx?: TransactionSignature, limit?: number): Promise<FetchLogsResponse>;
|
|
17
|
+
export declare class LogParser {
|
|
18
|
+
private program;
|
|
19
|
+
constructor(program: Program);
|
|
20
|
+
parseEventsFromLogs(event: Log): WrappedEvents;
|
|
21
|
+
}
|
|
13
22
|
export {};
|
package/lib/events/fetchLogs.js
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.fetchLogs = void 0;
|
|
4
|
-
async function fetchLogs(connection, programId, finality, beforeTx, untilTx) {
|
|
3
|
+
exports.LogParser = exports.fetchLogs = void 0;
|
|
4
|
+
async function fetchLogs(connection, programId, finality, beforeTx, untilTx, limit) {
|
|
5
5
|
const signatures = await connection.getSignaturesForAddress(programId, {
|
|
6
6
|
before: beforeTx,
|
|
7
7
|
until: untilTx,
|
|
8
|
+
limit,
|
|
8
9
|
}, finality);
|
|
9
|
-
const sortedSignatures = signatures.sort((a, b) => a.slot < b.slot ? -1 : 1);
|
|
10
|
+
const sortedSignatures = signatures.sort((a, b) => a.slot === b.slot ? 0 : a.slot < b.slot ? -1 : 1);
|
|
10
11
|
const filteredSignatures = sortedSignatures.filter((signature) => !signature.err);
|
|
11
12
|
if (filteredSignatures.length === 0) {
|
|
12
13
|
return undefined;
|
|
@@ -22,12 +23,14 @@ async function fetchLogs(connection, programId, finality, beforeTx, untilTx) {
|
|
|
22
23
|
};
|
|
23
24
|
});
|
|
24
25
|
}))).flat();
|
|
25
|
-
const
|
|
26
|
-
const
|
|
26
|
+
const earliest = filteredSignatures[0];
|
|
27
|
+
const mostRecent = filteredSignatures[filteredSignatures.length - 1];
|
|
27
28
|
return {
|
|
28
29
|
transactionLogs: transactionLogs,
|
|
29
|
-
earliestTx:
|
|
30
|
-
mostRecentTx:
|
|
30
|
+
earliestTx: earliest.signature,
|
|
31
|
+
mostRecentTx: mostRecent.signature,
|
|
32
|
+
earliestSlot: earliest.slot,
|
|
33
|
+
mostRecentSlot: mostRecent.slot,
|
|
31
34
|
};
|
|
32
35
|
}
|
|
33
36
|
exports.fetchLogs = fetchLogs;
|
|
@@ -37,3 +40,20 @@ function chunk(array, size) {
|
|
|
37
40
|
.map((_, index) => index * size)
|
|
38
41
|
.map((begin) => array.slice(begin, begin + size));
|
|
39
42
|
}
|
|
43
|
+
class LogParser {
|
|
44
|
+
constructor(program) {
|
|
45
|
+
this.program = program;
|
|
46
|
+
}
|
|
47
|
+
parseEventsFromLogs(event) {
|
|
48
|
+
const records = [];
|
|
49
|
+
// @ts-ignore
|
|
50
|
+
this.program._events._eventParser.parseLogs(event.logs, (eventLog) => {
|
|
51
|
+
eventLog.data.txSig = event.txSig;
|
|
52
|
+
eventLog.data.slot = event.slot;
|
|
53
|
+
eventLog.data.eventType = eventLog.name;
|
|
54
|
+
records.push(eventLog.data);
|
|
55
|
+
});
|
|
56
|
+
return records;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
exports.LogParser = LogParser;
|
|
@@ -8,8 +8,9 @@ export declare class PollingLogProvider implements LogProvider {
|
|
|
8
8
|
private intervalId;
|
|
9
9
|
private mostRecentSeenTx?;
|
|
10
10
|
private mutex;
|
|
11
|
+
private firstFetch;
|
|
11
12
|
constructor(connection: Connection, programId: PublicKey, commitment: Commitment, frequency?: number);
|
|
12
|
-
subscribe(callback: logProviderCallback): boolean;
|
|
13
|
+
subscribe(callback: logProviderCallback, skipHistory?: boolean): boolean;
|
|
13
14
|
isSubscribed(): boolean;
|
|
14
15
|
unsubscribe(): Promise<boolean>;
|
|
15
16
|
}
|
|
@@ -7,9 +7,10 @@ class PollingLogProvider {
|
|
|
7
7
|
this.connection = connection;
|
|
8
8
|
this.programId = programId;
|
|
9
9
|
this.frequency = frequency;
|
|
10
|
+
this.firstFetch = true;
|
|
10
11
|
this.finality = commitment === 'finalized' ? 'finalized' : 'confirmed';
|
|
11
12
|
}
|
|
12
|
-
subscribe(callback) {
|
|
13
|
+
subscribe(callback, skipHistory) {
|
|
13
14
|
if (this.intervalId) {
|
|
14
15
|
return true;
|
|
15
16
|
}
|
|
@@ -19,7 +20,10 @@ class PollingLogProvider {
|
|
|
19
20
|
}
|
|
20
21
|
this.mutex = 1;
|
|
21
22
|
try {
|
|
22
|
-
const response = await (0, fetchLogs_1.fetchLogs)(this.connection, this.programId, this.finality, undefined, this.mostRecentSeenTx
|
|
23
|
+
const response = await (0, fetchLogs_1.fetchLogs)(this.connection, this.programId, this.finality, undefined, this.mostRecentSeenTx,
|
|
24
|
+
// If skipping history, only fetch one log back, not the maximum amount available
|
|
25
|
+
skipHistory && this.firstFetch ? 1 : undefined);
|
|
26
|
+
this.firstFetch = false;
|
|
23
27
|
if (response === undefined) {
|
|
24
28
|
return;
|
|
25
29
|
}
|
package/lib/events/sort.js
CHANGED
|
@@ -11,17 +11,14 @@ function clientSortDescFn() {
|
|
|
11
11
|
function defaultBlockchainSortFn(currentEvent, newEvent) {
|
|
12
12
|
return currentEvent.slot <= newEvent.slot ? 'less than' : 'greater than';
|
|
13
13
|
}
|
|
14
|
-
function
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
? newEvent.makerOrder.marketIndex
|
|
20
|
-
: newEvent.takerOrder.marketIndex;
|
|
21
|
-
if (!currentEventMarketIndex.eq(newEventMarketIndex)) {
|
|
14
|
+
function orderActionRecordSortFn(currentEvent, newEvent) {
|
|
15
|
+
var _a, _b;
|
|
16
|
+
const currentEventMarketIndex = currentEvent.marketIndex;
|
|
17
|
+
const newEventMarketIndex = newEvent.marketIndex;
|
|
18
|
+
if (currentEventMarketIndex !== newEventMarketIndex) {
|
|
22
19
|
return currentEvent.ts.lte(newEvent.ts) ? 'less than' : 'greater than';
|
|
23
20
|
}
|
|
24
|
-
if (currentEvent.fillRecordId.gt(index_1.ZERO) && newEvent.fillRecordId.gt(index_1.ZERO)) {
|
|
21
|
+
if (((_a = currentEvent.fillRecordId) === null || _a === void 0 ? void 0 : _a.gt(index_1.ZERO)) && ((_b = newEvent.fillRecordId) === null || _b === void 0 ? void 0 : _b.gt(index_1.ZERO))) {
|
|
25
22
|
return currentEvent.fillRecordId.lte(newEvent.fillRecordId)
|
|
26
23
|
? 'less than'
|
|
27
24
|
: 'greater than';
|
|
@@ -35,8 +32,8 @@ function getSortFn(orderBy, orderDir, eventType) {
|
|
|
35
32
|
return orderDir === 'asc' ? clientSortAscFn : clientSortDescFn;
|
|
36
33
|
}
|
|
37
34
|
switch (eventType) {
|
|
38
|
-
case '
|
|
39
|
-
return
|
|
35
|
+
case 'OrderActionRecord':
|
|
36
|
+
return orderActionRecordSortFn;
|
|
40
37
|
default:
|
|
41
38
|
return defaultBlockchainSortFn;
|
|
42
39
|
}
|
package/lib/events/types.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Commitment, TransactionSignature } from '@solana/web3.js';
|
|
2
|
-
import { DepositRecord, FundingPaymentRecord, FundingRateRecord, LiquidationRecord, OrderRecord } from '../index';
|
|
2
|
+
import { DepositRecord, FundingPaymentRecord, FundingRateRecord, LiquidationRecord, NewUserRecord, OrderActionRecord, OrderRecord, SettlePnlRecord, LPRecord, InsuranceFundRecord, SpotInterestRecord } from '../index';
|
|
3
3
|
export declare type EventSubscriptionOptions = {
|
|
4
4
|
eventTypes?: EventType[];
|
|
5
5
|
maxEventsPerType?: number;
|
|
@@ -27,6 +27,12 @@ export declare type EventMap = {
|
|
|
27
27
|
LiquidationRecord: Event<LiquidationRecord>;
|
|
28
28
|
FundingRateRecord: Event<FundingRateRecord>;
|
|
29
29
|
OrderRecord: Event<OrderRecord>;
|
|
30
|
+
OrderActionRecord: Event<OrderActionRecord>;
|
|
31
|
+
SettlePnlRecord: Event<SettlePnlRecord>;
|
|
32
|
+
NewUserRecord: Event<NewUserRecord>;
|
|
33
|
+
LPRecord: Event<LPRecord>;
|
|
34
|
+
InsuranceFundRecord: Event<InsuranceFundRecord>;
|
|
35
|
+
SpotInterestRecord: Event<SpotInterestRecord>;
|
|
30
36
|
};
|
|
31
37
|
export declare type EventType = keyof EventMap;
|
|
32
38
|
export interface EventSubscriberEvents {
|
|
@@ -36,7 +42,7 @@ export declare type SortFn = (currentRecord: EventMap[EventType], newRecord: Eve
|
|
|
36
42
|
export declare type logProviderCallback = (txSig: TransactionSignature, slot: number, logs: string[]) => void;
|
|
37
43
|
export interface LogProvider {
|
|
38
44
|
isSubscribed(): boolean;
|
|
39
|
-
subscribe(callback: logProviderCallback): boolean;
|
|
45
|
+
subscribe(callback: logProviderCallback, skipHistory?: boolean): boolean;
|
|
40
46
|
unsubscribe(): Promise<boolean>;
|
|
41
47
|
}
|
|
42
48
|
export declare type WebSocketLogProviderConfig = {
|
package/lib/events/types.js
CHANGED
|
@@ -7,7 +7,13 @@ exports.DefaultEventSubscriptionOptions = {
|
|
|
7
7
|
'FundingPaymentRecord',
|
|
8
8
|
'LiquidationRecord',
|
|
9
9
|
'OrderRecord',
|
|
10
|
+
'OrderActionRecord',
|
|
10
11
|
'FundingRateRecord',
|
|
12
|
+
'NewUserRecord',
|
|
13
|
+
'SettlePnlRecord',
|
|
14
|
+
'LPRecord',
|
|
15
|
+
'InsuranceFundRecord',
|
|
16
|
+
'SpotInterestRecord',
|
|
11
17
|
],
|
|
12
18
|
maxEventsPerType: 4096,
|
|
13
19
|
orderBy: 'blockchain',
|
|
@@ -6,14 +6,15 @@ const __1 = require("..");
|
|
|
6
6
|
const spl_token_1 = require("@solana/spl-token");
|
|
7
7
|
const web3_js_1 = require("@solana/web3.js");
|
|
8
8
|
const __2 = require("..");
|
|
9
|
-
const
|
|
9
|
+
const spotMarkets_1 = require("../constants/spotMarkets");
|
|
10
10
|
const getTokenAddress = (mintAddress, userPubKey) => {
|
|
11
11
|
return spl_token_1.Token.getAssociatedTokenAddress(new web3_js_1.PublicKey(`ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL`), spl_token_1.TOKEN_PROGRAM_ID, new web3_js_1.PublicKey(mintAddress), new web3_js_1.PublicKey(userPubKey));
|
|
12
12
|
};
|
|
13
13
|
exports.getTokenAddress = getTokenAddress;
|
|
14
|
+
const cluster = 'devnet';
|
|
14
15
|
const main = async () => {
|
|
15
16
|
// Initialize Drift SDK
|
|
16
|
-
const sdkConfig = (0, __2.initialize)({ env:
|
|
17
|
+
const sdkConfig = (0, __2.initialize)({ env: cluster });
|
|
17
18
|
// Set up the Wallet and Provider
|
|
18
19
|
const privateKey = process.env.BOT_PRIVATE_KEY; // stored as an array string
|
|
19
20
|
const keypair = web3_js_1.Keypair.fromSecretKey(Uint8Array.from(JSON.parse(privateKey)));
|
|
@@ -30,34 +31,45 @@ const main = async () => {
|
|
|
30
31
|
const usdcTokenAddress = await (0, exports.getTokenAddress)(sdkConfig.USDC_MINT_ADDRESS, wallet.publicKey.toString());
|
|
31
32
|
// Set up the Drift Clearing House
|
|
32
33
|
const clearingHousePublicKey = new web3_js_1.PublicKey(sdkConfig.CLEARING_HOUSE_PROGRAM_ID);
|
|
34
|
+
const bulkAccountLoader = new __2.BulkAccountLoader(connection, 'confirmed', 1000);
|
|
33
35
|
const clearingHouse = new __2.ClearingHouse({
|
|
34
36
|
connection,
|
|
35
37
|
wallet: provider.wallet,
|
|
36
38
|
programID: clearingHousePublicKey,
|
|
39
|
+
perpMarketIndexes: __2.PerpMarkets[cluster].map((market) => market.marketIndex),
|
|
40
|
+
spotMarketIndexes: spotMarkets_1.SpotMarkets[cluster].map((spotMarket) => spotMarket.marketIndex),
|
|
41
|
+
accountSubscription: {
|
|
42
|
+
type: 'polling',
|
|
43
|
+
accountLoader: bulkAccountLoader,
|
|
44
|
+
},
|
|
37
45
|
});
|
|
38
46
|
await clearingHouse.subscribe();
|
|
39
47
|
// Set up Clearing House user client
|
|
40
48
|
const user = new __2.ClearingHouseUser({
|
|
41
49
|
clearingHouse,
|
|
42
50
|
userAccountPublicKey: await clearingHouse.getUserAccountPublicKey(),
|
|
51
|
+
accountSubscription: {
|
|
52
|
+
type: 'polling',
|
|
53
|
+
accountLoader: bulkAccountLoader,
|
|
54
|
+
},
|
|
43
55
|
});
|
|
44
56
|
//// Check if clearing house account exists for the current wallet
|
|
45
57
|
const userAccountExists = await user.exists();
|
|
46
58
|
if (!userAccountExists) {
|
|
47
59
|
//// Create a Clearing House account by Depositing some USDC ($10,000 in this case)
|
|
48
60
|
const depositAmount = new anchor_1.BN(10000).mul(__2.QUOTE_PRECISION);
|
|
49
|
-
await clearingHouse.initializeUserAccountAndDepositCollateral(depositAmount, await (0, exports.getTokenAddress)(usdcTokenAddress.toString(), wallet.publicKey.toString()),
|
|
61
|
+
await clearingHouse.initializeUserAccountAndDepositCollateral(depositAmount, await (0, exports.getTokenAddress)(usdcTokenAddress.toString(), wallet.publicKey.toString()), spotMarkets_1.SpotMarkets['devnet'][0].marketIndex);
|
|
50
62
|
}
|
|
51
63
|
await user.subscribe();
|
|
52
64
|
// Get current price
|
|
53
|
-
const solMarketInfo = sdkConfig.
|
|
54
|
-
const currentMarketPrice = (0, __2.
|
|
55
|
-
const formattedPrice = (0, __2.convertToNumber)(currentMarketPrice, __2.
|
|
65
|
+
const solMarketInfo = sdkConfig.PERP_MARKETS.find((market) => market.baseAssetSymbol === 'SOL');
|
|
66
|
+
const currentMarketPrice = (0, __2.calculateReservePrice)(clearingHouse.getPerpMarketAccount(solMarketInfo.marketIndex), undefined);
|
|
67
|
+
const formattedPrice = (0, __2.convertToNumber)(currentMarketPrice, __2.PRICE_PRECISION);
|
|
56
68
|
console.log(`Current Market Price is $${formattedPrice}`);
|
|
57
69
|
// Estimate the slippage for a $5000 LONG trade
|
|
58
|
-
const solMarketAccount = clearingHouse.
|
|
70
|
+
const solMarketAccount = clearingHouse.getPerpMarketAccount(solMarketInfo.marketIndex);
|
|
59
71
|
const longAmount = new anchor_1.BN(5000).mul(__2.QUOTE_PRECISION);
|
|
60
|
-
const slippage = (0, __2.convertToNumber)((0, __2.calculateTradeSlippage)(__2.PositionDirection.LONG, longAmount, solMarketAccount, 'quote', undefined)[0], __2.
|
|
72
|
+
const slippage = (0, __2.convertToNumber)((0, __2.calculateTradeSlippage)(__2.PositionDirection.LONG, longAmount, solMarketAccount, 'quote', undefined)[0], __2.PRICE_PRECISION);
|
|
61
73
|
console.log(`Slippage for a $5000 LONG on the SOL market would be $${slippage}`);
|
|
62
74
|
// Make a $5000 LONG trade
|
|
63
75
|
await clearingHouse.openPosition(__2.PositionDirection.LONG, longAmount, solMarketInfo.marketIndex);
|
package/lib/factory/bigNum.d.ts
CHANGED
|
@@ -6,6 +6,7 @@ export declare class BigNum {
|
|
|
6
6
|
static delim: string;
|
|
7
7
|
static spacer: string;
|
|
8
8
|
constructor(val: BN | number | string, precisionVal?: BN | number | string);
|
|
9
|
+
private bigNumFromParam;
|
|
9
10
|
add(bn: BigNum): BigNum;
|
|
10
11
|
sub(bn: BigNum): BigNum;
|
|
11
12
|
mul(bn: BigNum | BN): BigNum;
|
|
@@ -68,6 +69,7 @@ export declare class BigNum {
|
|
|
68
69
|
* @returns
|
|
69
70
|
*/
|
|
70
71
|
toFixed(fixedPrecision: number): string;
|
|
72
|
+
private getZeroes;
|
|
71
73
|
/**
|
|
72
74
|
* Pretty print to the specified number of significant figures
|
|
73
75
|
* @param fixedPrecision
|