@drift-labs/sdk 2.0.15 → 2.0.17

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.
@@ -0,0 +1,245 @@
1
+ {
2
+ "version": "2.0.0",
3
+ "name": "dlob",
4
+ "instructions": [],
5
+ "accounts": [],
6
+ "types": [
7
+ {
8
+ "name": "DLOBOrders",
9
+ "type": {
10
+ "vec": {
11
+ "defined": "DLOBOrder"
12
+ }
13
+ }
14
+ },
15
+ {
16
+ "name": "DLOBOrder",
17
+ "type": {
18
+ "kind": "struct",
19
+ "fields": [
20
+ {
21
+ "name": "user",
22
+ "type": "publicKey"
23
+ },
24
+ {
25
+ "name": "order",
26
+ "type": {
27
+ "defined": "Order"
28
+ }
29
+ }
30
+ ]
31
+ }
32
+ },
33
+ {
34
+ "name": "Order",
35
+ "type": {
36
+ "kind": "struct",
37
+ "fields": [
38
+ {
39
+ "name": "slot",
40
+ "type": "u64"
41
+ },
42
+ {
43
+ "name": "price",
44
+ "type": "u64"
45
+ },
46
+ {
47
+ "name": "baseAssetAmount",
48
+ "type": "u64"
49
+ },
50
+ {
51
+ "name": "baseAssetAmountFilled",
52
+ "type": "u64"
53
+ },
54
+ {
55
+ "name": "quoteAssetAmountFilled",
56
+ "type": "u64"
57
+ },
58
+ {
59
+ "name": "triggerPrice",
60
+ "type": "u64"
61
+ },
62
+ {
63
+ "name": "auctionStartPrice",
64
+ "type": "u64"
65
+ },
66
+ {
67
+ "name": "auctionEndPrice",
68
+ "type": "u64"
69
+ },
70
+ {
71
+ "name": "maxTs",
72
+ "type": "i64"
73
+ },
74
+ {
75
+ "name": "oraclePriceOffset",
76
+ "type": "i32"
77
+ },
78
+ {
79
+ "name": "orderId",
80
+ "type": "u32"
81
+ },
82
+ {
83
+ "name": "marketIndex",
84
+ "type": "u16"
85
+ },
86
+ {
87
+ "name": "status",
88
+ "type": {
89
+ "defined": "OrderStatus"
90
+ }
91
+ },
92
+ {
93
+ "name": "orderType",
94
+ "type": {
95
+ "defined": "OrderType"
96
+ }
97
+ },
98
+ {
99
+ "name": "marketType",
100
+ "type": {
101
+ "defined": "MarketType"
102
+ }
103
+ },
104
+ {
105
+ "name": "userOrderId",
106
+ "type": "u8"
107
+ },
108
+ {
109
+ "name": "existingPositionDirection",
110
+ "type": {
111
+ "defined": "PositionDirection"
112
+ }
113
+ },
114
+ {
115
+ "name": "direction",
116
+ "type": {
117
+ "defined": "PositionDirection"
118
+ }
119
+ },
120
+ {
121
+ "name": "reduceOnly",
122
+ "type": "bool"
123
+ },
124
+ {
125
+ "name": "postOnly",
126
+ "type": "bool"
127
+ },
128
+ {
129
+ "name": "immediateOrCancel",
130
+ "type": "bool"
131
+ },
132
+ {
133
+ "name": "triggerCondition",
134
+ "type": {
135
+ "defined": "OrderTriggerCondition"
136
+ }
137
+ },
138
+ {
139
+ "name": "auctionDuration",
140
+ "type": "u8"
141
+ },
142
+ {
143
+ "name": "padding",
144
+ "type": {
145
+ "array": [
146
+ "u8",
147
+ 3
148
+ ]
149
+ }
150
+ }
151
+ ]
152
+ }
153
+ },
154
+ {
155
+ "name": "OrderStatus",
156
+ "type": {
157
+ "kind": "enum",
158
+ "variants": [
159
+ {
160
+ "name": "Init"
161
+ },
162
+ {
163
+ "name": "Open"
164
+ },
165
+ {
166
+ "name": "Filled"
167
+ },
168
+ {
169
+ "name": "Canceled"
170
+ }
171
+ ]
172
+ }
173
+ },
174
+ {
175
+ "name": "OrderType",
176
+ "type": {
177
+ "kind": "enum",
178
+ "variants": [
179
+ {
180
+ "name": "Market"
181
+ },
182
+ {
183
+ "name": "Limit"
184
+ },
185
+ {
186
+ "name": "TriggerMarket"
187
+ },
188
+ {
189
+ "name": "TriggerLimit"
190
+ }
191
+ ]
192
+ }
193
+ },
194
+ {
195
+ "name": "OrderTriggerCondition",
196
+ "type": {
197
+ "kind": "enum",
198
+ "variants": [
199
+ {
200
+ "name": "Above"
201
+ },
202
+ {
203
+ "name": "Below"
204
+ },
205
+ {
206
+ "name": "TriggeredAbove"
207
+ },
208
+ {
209
+ "name": "TriggeredBelow"
210
+ }
211
+ ]
212
+ }
213
+ },
214
+ {
215
+ "name": "MarketType",
216
+ "type": {
217
+ "kind": "enum",
218
+ "variants": [
219
+ {
220
+ "name": "Spot"
221
+ },
222
+ {
223
+ "name": "Perp"
224
+ }
225
+ ]
226
+ }
227
+ },
228
+ {
229
+ "name": "PositionDirection",
230
+ "type": {
231
+ "kind": "enum",
232
+ "variants": [
233
+ {
234
+ "name": "Long"
235
+ },
236
+ {
237
+ "name": "Short"
238
+ }
239
+ ]
240
+ }
241
+ }
242
+ ],
243
+ "events": [],
244
+ "errors": []
245
+ }
@@ -8519,6 +8519,11 @@
8519
8519
  "code": 6221,
8520
8520
  "name": "SpotFulfillmentConfigDisabled",
8521
8521
  "msg": "Spot Fulfullment Config Disabled"
8522
+ },
8523
+ {
8524
+ "code": 6222,
8525
+ "name": "InvalidMaker",
8526
+ "msg": "Invalid Maker"
8522
8527
  }
8523
8528
  ]
8524
8529
  }
package/lib/math/amm.d.ts CHANGED
@@ -38,12 +38,12 @@ export declare function calculateInventoryScale(baseAssetAmountWithAmm: BN, base
38
38
  export declare function calculateEffectiveLeverage(baseSpread: number, quoteAssetReserve: BN, terminalQuoteAssetReserve: BN, pegMultiplier: BN, netBaseAssetAmount: BN, reservePrice: BN, totalFeeMinusDistributions: BN): number;
39
39
  export declare function calculateMaxSpread(marginRatioInitial: number): number;
40
40
  export declare function calculateVolSpreadBN(lastOracleConfPct: BN, reservePrice: BN, markStd: BN, oracleStd: BN, longIntensity: BN, shortIntensity: BN, volume24H: BN): [BN, BN];
41
- export declare function calculateSpreadBN(baseSpread: number, lastOracleReservePriceSpreadPct: BN, lastOracleConfPct: BN, maxSpread: number, quoteAssetReserve: BN, terminalQuoteAssetReserve: BN, pegMultiplier: BN, baseAssetAmountWithAmm: BN, reservePrice: BN, totalFeeMinusDistributions: BN, baseAssetReserve: BN, minBaseAssetReserve: BN, maxBaseAssetReserve: BN, markStd: BN, oracleStd: BN, longIntensity: BN, shortIntensity: BN, volume24H: BN): [number, number];
42
- export declare function calculateSpread(amm: AMM, direction: PositionDirection, oraclePriceData: OraclePriceData): number;
43
- export declare function calculateSpreadReserves(amm: AMM, direction: PositionDirection, oraclePriceData: OraclePriceData): {
44
- baseAssetReserve: BN;
45
- quoteAssetReserve: BN;
46
- };
41
+ export declare function calculateSpreadBN(baseSpread: number, lastOracleReservePriceSpreadPct: BN, lastOracleConfPct: BN, maxSpread: number, quoteAssetReserve: BN, terminalQuoteAssetReserve: BN, pegMultiplier: BN, baseAssetAmountWithAmm: BN, reservePrice: BN, totalFeeMinusDistributions: BN, netRevenueSinceLastFunding: BN, baseAssetReserve: BN, minBaseAssetReserve: BN, maxBaseAssetReserve: BN, markStd: BN, oracleStd: BN, longIntensity: BN, shortIntensity: BN, volume24H: BN): [number, number];
42
+ export declare function calculateSpread(amm: AMM, oraclePriceData: OraclePriceData): [number, number];
43
+ export declare function calculateSpreadReserves(amm: AMM, oraclePriceData: OraclePriceData): {
44
+ baseAssetReserve: any;
45
+ quoteAssetReserve: any;
46
+ }[];
47
47
  /**
48
48
  * Helper function calculating constant product curve output. Agnostic to whether input asset is quote or base
49
49
  *
package/lib/math/amm.js CHANGED
@@ -100,7 +100,10 @@ function calculateUpdatedAMM(amm, oraclePriceData) {
100
100
  exports.calculateUpdatedAMM = calculateUpdatedAMM;
101
101
  function calculateUpdatedAMMSpreadReserves(amm, direction, oraclePriceData) {
102
102
  const newAmm = calculateUpdatedAMM(amm, oraclePriceData);
103
- const dirReserves = calculateSpreadReserves(newAmm, direction, oraclePriceData);
103
+ const [shortReserves, longReserves] = calculateSpreadReserves(newAmm, oraclePriceData);
104
+ const dirReserves = (0, types_1.isVariant)(direction, 'long')
105
+ ? longReserves
106
+ : shortReserves;
104
107
  const result = {
105
108
  baseAssetReserve: dirReserves.baseAssetReserve,
106
109
  quoteAssetReserve: dirReserves.quoteAssetReserve,
@@ -118,8 +121,7 @@ function calculateBidAskPrice(amm, oraclePriceData, withUpdate = true) {
118
121
  else {
119
122
  newAmm = amm;
120
123
  }
121
- const askReserves = calculateSpreadReserves(newAmm, types_1.PositionDirection.LONG, oraclePriceData);
122
- const bidReserves = calculateSpreadReserves(newAmm, types_1.PositionDirection.SHORT, oraclePriceData);
124
+ const [bidReserves, askReserves] = calculateSpreadReserves(newAmm, oraclePriceData);
123
125
  const askPrice = calculatePrice(askReserves.baseAssetReserve, askReserves.quoteAssetReserve, newAmm.pegMultiplier);
124
126
  const bidPrice = calculatePrice(bidReserves.baseAssetReserve, bidReserves.quoteAssetReserve, newAmm.pegMultiplier);
125
127
  return [bidPrice, askPrice];
@@ -236,10 +238,11 @@ function calculateVolSpreadBN(lastOracleConfPct, reservePrice, markStd, oracleSt
236
238
  const marketAvgStdPct = markStd
237
239
  .add(oracleStd)
238
240
  .mul(numericConstants_1.PERCENTAGE_PRECISION)
239
- .div(reservePrice.mul(new anchor_1.BN(2)));
241
+ .div(reservePrice)
242
+ .div(new anchor_1.BN(2));
240
243
  const volSpread = anchor_1.BN.max(lastOracleConfPct, marketAvgStdPct.div(new anchor_1.BN(2)));
244
+ const clampMin = numericConstants_1.PERCENTAGE_PRECISION.div(new anchor_1.BN(100));
241
245
  const clampMax = numericConstants_1.PERCENTAGE_PRECISION.mul(new anchor_1.BN(16)).div(new anchor_1.BN(10));
242
- const clampMin = numericConstants_1.PERCENTAGE_PRECISION.div(new anchor_1.BN(10));
243
246
  const longVolSpreadFactor = (0, __1.clampBN)(longIntensity.mul(numericConstants_1.PERCENTAGE_PRECISION).div(anchor_1.BN.max(numericConstants_1.ONE, volume24H)), clampMin, clampMax);
244
247
  const shortVolSpreadFactor = (0, __1.clampBN)(shortIntensity.mul(numericConstants_1.PERCENTAGE_PRECISION).div(anchor_1.BN.max(numericConstants_1.ONE, volume24H)), clampMin, clampMax);
245
248
  const longVolSpread = anchor_1.BN.max(lastOracleConfPct, volSpread.mul(longVolSpreadFactor).div(numericConstants_1.PERCENTAGE_PRECISION));
@@ -247,7 +250,7 @@ function calculateVolSpreadBN(lastOracleConfPct, reservePrice, markStd, oracleSt
247
250
  return [longVolSpread, shortVolSpread];
248
251
  }
249
252
  exports.calculateVolSpreadBN = calculateVolSpreadBN;
250
- function calculateSpreadBN(baseSpread, lastOracleReservePriceSpreadPct, lastOracleConfPct, maxSpread, quoteAssetReserve, terminalQuoteAssetReserve, pegMultiplier, baseAssetAmountWithAmm, reservePrice, totalFeeMinusDistributions, baseAssetReserve, minBaseAssetReserve, maxBaseAssetReserve, markStd, oracleStd, longIntensity, shortIntensity, volume24H) {
253
+ function calculateSpreadBN(baseSpread, lastOracleReservePriceSpreadPct, lastOracleConfPct, maxSpread, quoteAssetReserve, terminalQuoteAssetReserve, pegMultiplier, baseAssetAmountWithAmm, reservePrice, totalFeeMinusDistributions, netRevenueSinceLastFunding, baseAssetReserve, minBaseAssetReserve, maxBaseAssetReserve, markStd, oracleStd, longIntensity, shortIntensity, volume24H) {
251
254
  const [longVolSpread, shortVolSpread] = calculateVolSpreadBN(lastOracleConfPct, reservePrice, markStd, oracleStd, longIntensity, shortIntensity, volume24H);
252
255
  let longSpread = Math.max(baseSpread / 2, longVolSpread.toNumber());
253
256
  let shortSpread = Math.max(baseSpread / 2, shortVolSpread.toNumber());
@@ -267,9 +270,9 @@ function calculateSpreadBN(baseSpread, lastOracleReservePriceSpreadPct, lastOrac
267
270
  else if (baseAssetAmountWithAmm.lt(numericConstants_1.ZERO)) {
268
271
  shortSpread *= inventorySpreadScale;
269
272
  }
270
- const effectiveLeverage = calculateEffectiveLeverage(baseSpread, quoteAssetReserve, terminalQuoteAssetReserve, pegMultiplier, baseAssetAmountWithAmm, reservePrice, totalFeeMinusDistributions);
271
273
  const MAX_SPREAD_SCALE = 10;
272
274
  if (totalFeeMinusDistributions.gt(numericConstants_1.ZERO)) {
275
+ const effectiveLeverage = calculateEffectiveLeverage(baseSpread, quoteAssetReserve, terminalQuoteAssetReserve, pegMultiplier, baseAssetAmountWithAmm, reservePrice, totalFeeMinusDistributions);
273
276
  const spreadScale = Math.min(MAX_SPREAD_SCALE, 1 + effectiveLeverage);
274
277
  if (baseAssetAmountWithAmm.gt(numericConstants_1.ZERO)) {
275
278
  longSpread *= spreadScale;
@@ -282,23 +285,40 @@ function calculateSpreadBN(baseSpread, lastOracleReservePriceSpreadPct, lastOrac
282
285
  longSpread *= MAX_SPREAD_SCALE;
283
286
  shortSpread *= MAX_SPREAD_SCALE;
284
287
  }
288
+ if (netRevenueSinceLastFunding.lt(numericConstants_1.DEFAULT_REVENUE_SINCE_LAST_FUNDING_SPREAD_RETREAT)) {
289
+ const retreatAmount = Math.min(maxTargetSpread / 10, Math.floor((baseSpread * netRevenueSinceLastFunding.abs().toNumber()) /
290
+ numericConstants_1.DEFAULT_REVENUE_SINCE_LAST_FUNDING_SPREAD_RETREAT.toNumber()));
291
+ const halfRetreatAmount = Math.floor(retreatAmount / 2);
292
+ if (baseAssetAmountWithAmm.gt(numericConstants_1.ZERO)) {
293
+ longSpread += retreatAmount;
294
+ shortSpread += halfRetreatAmount;
295
+ }
296
+ else if (baseAssetAmountWithAmm.lt(numericConstants_1.ZERO)) {
297
+ longSpread += halfRetreatAmount;
298
+ shortSpread += retreatAmount;
299
+ }
300
+ else {
301
+ longSpread += halfRetreatAmount;
302
+ shortSpread += halfRetreatAmount;
303
+ }
304
+ }
285
305
  const totalSpread = longSpread + shortSpread;
286
306
  if (totalSpread > maxTargetSpread) {
287
307
  if (longSpread > shortSpread) {
288
- longSpread = Math.min(longSpread, maxTargetSpread);
308
+ longSpread = Math.ceil((longSpread * maxTargetSpread) / totalSpread);
289
309
  shortSpread = maxTargetSpread - longSpread;
290
310
  }
291
311
  else {
292
- shortSpread = Math.min(shortSpread, maxTargetSpread);
312
+ shortSpread = Math.ceil((shortSpread * maxTargetSpread) / totalSpread);
293
313
  longSpread = maxTargetSpread - shortSpread;
294
314
  }
295
315
  }
296
316
  return [longSpread, shortSpread];
297
317
  }
298
318
  exports.calculateSpreadBN = calculateSpreadBN;
299
- function calculateSpread(amm, direction, oraclePriceData) {
319
+ function calculateSpread(amm, oraclePriceData) {
300
320
  if (amm.baseSpread == 0 || amm.curveUpdateIntensity == 0) {
301
- return amm.baseSpread / 2;
321
+ return [amm.baseSpread / 2, amm.baseSpread / 2];
302
322
  }
303
323
  const reservePrice = calculatePrice(amm.baseAssetReserve, amm.quoteAssetReserve, amm.pegMultiplier);
304
324
  const targetPrice = (oraclePriceData === null || oraclePriceData === void 0 ? void 0 : oraclePriceData.price) || reservePrice;
@@ -312,38 +332,36 @@ function calculateSpread(amm, direction, oraclePriceData) {
312
332
  .div(reservePrice);
313
333
  const now = new anchor_1.BN(new Date().getTime() / 1000); //todo
314
334
  const liveOracleStd = (0, oracles_1.calculateLiveOracleStd)(amm, oraclePriceData, now);
315
- const [longSpread, shortSpread] = calculateSpreadBN(amm.baseSpread, targetMarkSpreadPct, confIntervalPct, amm.maxSpread, amm.quoteAssetReserve, amm.terminalQuoteAssetReserve, amm.pegMultiplier, amm.baseAssetAmountWithAmm, reservePrice, amm.totalFeeMinusDistributions, amm.baseAssetReserve, amm.minBaseAssetReserve, amm.maxBaseAssetReserve, amm.markStd, liveOracleStd, amm.longIntensityVolume, amm.shortIntensityVolume, amm.volume24H);
316
- let spread;
317
- if ((0, types_1.isVariant)(direction, 'long')) {
318
- spread = longSpread;
319
- }
320
- else {
321
- spread = shortSpread;
322
- }
323
- return spread;
335
+ const [longSpread, shortSpread] = calculateSpreadBN(amm.baseSpread, targetMarkSpreadPct, confIntervalPct, amm.maxSpread, amm.quoteAssetReserve, amm.terminalQuoteAssetReserve, amm.pegMultiplier, amm.baseAssetAmountWithAmm, reservePrice, amm.totalFeeMinusDistributions, amm.netRevenueSinceLastFunding, amm.baseAssetReserve, amm.minBaseAssetReserve, amm.maxBaseAssetReserve, amm.markStd, liveOracleStd, amm.longIntensityVolume, amm.shortIntensityVolume, amm.volume24H);
336
+ return [longSpread, shortSpread];
324
337
  }
325
338
  exports.calculateSpread = calculateSpread;
326
- function calculateSpreadReserves(amm, direction, oraclePriceData) {
327
- const spread = calculateSpread(amm, direction, oraclePriceData);
328
- if (spread === 0) {
339
+ function calculateSpreadReserves(amm, oraclePriceData) {
340
+ function calculateSpreadReserve(spread, direction, amm) {
341
+ if (spread === 0) {
342
+ return {
343
+ baseAssetReserve: amm.baseAssetReserve,
344
+ quoteAssetReserve: amm.quoteAssetReserve,
345
+ };
346
+ }
347
+ const quoteAssetReserveDelta = amm.quoteAssetReserve.div(numericConstants_1.BID_ASK_SPREAD_PRECISION.div(new anchor_1.BN(spread / 2)));
348
+ let quoteAssetReserve;
349
+ if ((0, types_1.isVariant)(direction, 'long')) {
350
+ quoteAssetReserve = amm.quoteAssetReserve.add(quoteAssetReserveDelta);
351
+ }
352
+ else {
353
+ quoteAssetReserve = amm.quoteAssetReserve.sub(quoteAssetReserveDelta);
354
+ }
355
+ const baseAssetReserve = amm.sqrtK.mul(amm.sqrtK).div(quoteAssetReserve);
329
356
  return {
330
- baseAssetReserve: amm.baseAssetReserve,
331
- quoteAssetReserve: amm.quoteAssetReserve,
357
+ baseAssetReserve,
358
+ quoteAssetReserve,
332
359
  };
333
360
  }
334
- const quoteAsserReserveDelta = amm.quoteAssetReserve.div(numericConstants_1.BID_ASK_SPREAD_PRECISION.div(new anchor_1.BN(spread / 2)));
335
- let quoteAssetReserve;
336
- if ((0, types_1.isVariant)(direction, 'long')) {
337
- quoteAssetReserve = amm.quoteAssetReserve.add(quoteAsserReserveDelta);
338
- }
339
- else {
340
- quoteAssetReserve = amm.quoteAssetReserve.sub(quoteAsserReserveDelta);
341
- }
342
- const baseAssetReserve = amm.sqrtK.mul(amm.sqrtK).div(quoteAssetReserve);
343
- return {
344
- baseAssetReserve,
345
- quoteAssetReserve,
346
- };
361
+ const [longSpread, shortSpread] = calculateSpread(amm, oraclePriceData);
362
+ const askReserves = calculateSpreadReserve(longSpread, types_1.PositionDirection.LONG, amm);
363
+ const bidReserves = calculateSpreadReserve(shortSpread, types_1.PositionDirection.SHORT, amm);
364
+ return [bidReserves, askReserves];
347
365
  }
348
366
  exports.calculateSpreadReserves = calculateSpreadReserves;
349
367
  /**
@@ -410,7 +428,10 @@ function calculateMaxBaseAssetAmountToTrade(amm, limit_price, direction, oracleP
410
428
  .div(limit_price)
411
429
  .div(numericConstants_1.PEG_PRECISION);
412
430
  const newBaseAssetReserve = (0, __1.squareRootBN)(newBaseAssetReserveSquared);
413
- const baseAssetReserveBefore = calculateSpreadReserves(amm, direction, oraclePriceData).baseAssetReserve;
431
+ const [shortSpreadReserves, longSpreadReserves] = calculateSpreadReserves(amm, oraclePriceData);
432
+ const baseAssetReserveBefore = (0, types_1.isVariant)(direction, 'long')
433
+ ? longSpreadReserves.baseAssetReserve
434
+ : shortSpreadReserves.baseAssetReserve;
414
435
  if (newBaseAssetReserve.gt(baseAssetReserveBefore)) {
415
436
  return [
416
437
  newBaseAssetReserve.sub(baseAssetReserveBefore),
@@ -1,4 +1,4 @@
1
1
  /// <reference types="bn.js" />
2
2
  import { BN } from '../';
3
3
  export declare function clampBN(x: BN, min: BN, max: BN): BN;
4
- export declare const squareRootBN: (n: any, closeness?: BN) => any;
4
+ export declare const squareRootBN: (n: any, closeness?: BN) => BN;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@drift-labs/sdk",
3
- "version": "2.0.15",
3
+ "version": "2.0.17",
4
4
  "main": "lib/index.js",
5
5
  "types": "lib/index.d.ts",
6
6
  "author": "crispheaney",
@@ -91,3 +91,7 @@ export const LAMPORTS_PRECISION = new BN(LAMPORTS_PER_SOL);
91
91
  export const LAMPORTS_EXP = new BN(Math.log10(LAMPORTS_PER_SOL));
92
92
 
93
93
  export const OPEN_ORDER_MARGIN_REQUIREMENT = QUOTE_PRECISION.div(new BN(100));
94
+
95
+ export const DEFAULT_REVENUE_SINCE_LAST_FUNDING_SPREAD_RETREAT = new BN(
96
+ -25
97
+ ).mul(QUOTE_PRECISION);