@drift-labs/sdk 0.1.36-master.7 → 0.2.0-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 +6 -6
- package/lib/accounts/bulkAccountLoader.js +81 -95
- package/lib/accounts/bulkUserSubscription.js +13 -57
- package/lib/accounts/fetch.d.ts +4 -0
- package/lib/accounts/fetch.js +18 -0
- package/lib/accounts/pollingClearingHouseAccountSubscriber.d.ts +34 -38
- package/lib/accounts/pollingClearingHouseAccountSubscriber.js +224 -224
- package/lib/accounts/pollingOracleSubscriber.d.ts +3 -3
- package/lib/accounts/pollingOracleSubscriber.js +37 -49
- package/lib/accounts/pollingTokenAccountSubscriber.d.ts +3 -3
- package/lib/accounts/pollingTokenAccountSubscriber.js +35 -50
- package/lib/accounts/pollingUserAccountSubscriber.d.ts +7 -13
- package/lib/accounts/pollingUserAccountSubscriber.js +71 -134
- package/lib/accounts/types.d.ts +34 -41
- package/lib/accounts/webSocketAccountSubscriber.d.ts +6 -4
- package/lib/accounts/webSocketAccountSubscriber.js +39 -35
- package/lib/accounts/webSocketClearingHouseAccountSubscriber.d.ts +33 -28
- package/lib/accounts/webSocketClearingHouseAccountSubscriber.js +153 -185
- package/lib/accounts/webSocketUserAccountSubscriber.d.ts +5 -11
- package/lib/accounts/webSocketUserAccountSubscriber.js +22 -67
- package/lib/addresses/marketAddresses.d.ts +4 -0
- package/lib/addresses/marketAddresses.js +15 -0
- package/lib/addresses/pda.d.ts +12 -0
- package/lib/addresses/pda.js +83 -0
- package/lib/admin.d.ts +8 -17
- package/lib/admin.js +366 -558
- package/lib/clearingHouse.d.ts +84 -109
- package/lib/clearingHouse.js +778 -899
- package/lib/clearingHouseConfig.d.ts +34 -0
- package/lib/clearingHouseConfig.js +2 -0
- package/lib/clearingHouseUser.d.ts +19 -22
- package/lib/clearingHouseUser.js +155 -141
- package/lib/clearingHouseUserConfig.d.ts +14 -0
- package/lib/clearingHouseUserConfig.js +2 -0
- package/lib/config.d.ts +12 -0
- package/lib/config.js +35 -4
- package/lib/constants/banks.d.ts +16 -0
- package/lib/constants/banks.js +34 -0
- package/lib/constants/markets.d.ts +8 -3
- package/lib/constants/markets.js +13 -206
- package/lib/constants/numericConstants.d.ts +16 -0
- package/lib/constants/numericConstants.js +22 -6
- package/lib/events/eventList.d.ts +22 -0
- package/lib/events/eventList.js +77 -0
- package/lib/events/eventSubscriber.d.ts +34 -0
- package/lib/events/eventSubscriber.js +126 -0
- package/lib/events/fetchLogs.d.ts +13 -0
- package/lib/events/fetchLogs.js +39 -0
- package/lib/events/pollingLogProvider.d.ts +15 -0
- package/lib/events/pollingLogProvider.js +53 -0
- package/lib/events/sort.d.ts +2 -0
- package/lib/events/sort.js +44 -0
- package/lib/events/txEventCache.d.ts +24 -0
- package/lib/events/txEventCache.js +71 -0
- package/lib/events/types.d.ts +49 -0
- package/lib/events/types.js +20 -0
- package/lib/events/webSocketLogProvider.d.ts +12 -0
- package/lib/events/webSocketLogProvider.js +30 -0
- package/lib/examples/makeTradeExample.js +26 -27
- package/lib/factory/bigNum.d.ts +112 -0
- package/lib/factory/bigNum.js +356 -0
- package/lib/factory/oracleClient.d.ts +1 -2
- package/lib/factory/oracleClient.js +6 -2
- package/lib/idl/clearing_house.json +2213 -2951
- package/lib/index.d.ts +12 -4
- package/lib/index.js +12 -4
- package/lib/math/amm.d.ts +19 -29
- package/lib/math/amm.js +129 -179
- package/lib/math/auction.d.ts +5 -0
- package/lib/math/auction.js +39 -0
- package/lib/math/bankBalance.d.ts +9 -0
- package/lib/math/bankBalance.js +75 -0
- package/lib/math/conversion.d.ts +0 -1
- package/lib/math/conversion.js +1 -5
- package/lib/math/funding.d.ts +6 -6
- package/lib/math/funding.js +158 -175
- package/lib/math/market.d.ts +6 -6
- package/lib/math/market.js +10 -9
- package/lib/math/orders.d.ts +5 -0
- package/lib/math/orders.js +31 -1
- package/lib/math/position.d.ts +7 -5
- package/lib/math/position.js +27 -27
- package/lib/math/repeg.d.ts +22 -0
- package/lib/math/repeg.js +128 -0
- package/lib/math/trade.d.ts +5 -4
- package/lib/math/trade.js +29 -21
- package/lib/mockUSDCFaucet.js +87 -116
- package/lib/oracles/oracleClientCache.d.ts +8 -0
- package/lib/oracles/oracleClientCache.js +19 -0
- package/lib/oracles/pythClient.d.ts +3 -5
- package/lib/oracles/pythClient.js +12 -31
- package/lib/oracles/quoteAssetOracleClient.d.ts +9 -0
- package/lib/oracles/quoteAssetOracleClient.js +21 -0
- package/lib/oracles/switchboardClient.d.ts +3 -5
- package/lib/oracles/switchboardClient.js +29 -50
- package/lib/oracles/types.d.ts +6 -1
- package/lib/orders.d.ts +6 -6
- package/lib/orders.js +10 -9
- package/lib/slot/SlotSubscriber.d.ts +12 -0
- package/lib/slot/SlotSubscriber.js +23 -0
- package/lib/tx/retryTxSender.d.ts +2 -2
- package/lib/tx/retryTxSender.js +108 -123
- package/lib/tx/types.d.ts +5 -1
- package/lib/tx/utils.d.ts +1 -1
- package/lib/tx/utils.js +11 -2
- package/lib/types.d.ts +105 -109
- package/lib/types.js +13 -1
- package/lib/userName.d.ts +4 -0
- package/lib/userName.js +20 -0
- package/lib/util/computeUnits.js +10 -21
- package/lib/util/tps.js +11 -22
- package/lib/wallet.js +7 -20
- package/package.json +10 -3
- package/src/accounts/bulkAccountLoader.ts +21 -15
- package/src/accounts/bulkUserSubscription.ts +1 -45
- package/src/accounts/fetch.ts +33 -0
- package/src/accounts/pollingClearingHouseAccountSubscriber.ts +249 -214
- package/src/accounts/pollingOracleSubscriber.ts +16 -8
- package/src/accounts/pollingTokenAccountSubscriber.ts +11 -8
- package/src/accounts/pollingUserAccountSubscriber.ts +21 -86
- package/src/accounts/types.ts +41 -70
- package/src/accounts/webSocketAccountSubscriber.ts +33 -16
- package/src/accounts/webSocketClearingHouseAccountSubscriber.ts +190 -240
- package/src/accounts/webSocketUserAccountSubscriber.ts +11 -71
- package/src/addresses/marketAddresses.ts +18 -0
- package/src/addresses/pda.ts +118 -0
- package/src/admin.ts +205 -346
- package/src/clearingHouse.ts +918 -961
- package/src/clearingHouseConfig.ts +37 -0
- package/src/clearingHouseUser.ts +275 -185
- package/src/clearingHouseUserConfig.ts +18 -0
- package/src/config.ts +54 -1
- package/src/constants/banks.ts +43 -0
- package/src/constants/markets.ts +16 -207
- package/src/constants/numericConstants.ts +33 -5
- package/src/events/eventList.ts +94 -0
- package/src/events/eventSubscriber.ts +194 -0
- package/src/events/fetchLogs.ts +80 -0
- package/src/events/pollingLogProvider.ts +79 -0
- package/src/events/sort.ts +65 -0
- package/src/events/txEventCache.ts +74 -0
- package/src/events/types.ts +98 -0
- package/src/events/webSocketLogProvider.ts +38 -0
- package/src/examples/makeTradeExample.ts +20 -11
- package/src/factory/bigNum.ts +507 -0
- package/src/factory/oracleClient.ts +7 -4
- package/src/idl/clearing_house.json +2213 -2951
- package/src/index.ts +12 -4
- package/src/math/amm.ts +229 -245
- package/src/math/auction.ts +39 -0
- package/src/math/bankBalance.ts +112 -0
- package/src/math/conversion.ts +1 -11
- package/src/math/funding.ts +12 -9
- package/src/math/market.ts +37 -30
- package/src/math/orders.ts +38 -0
- package/src/math/position.ts +48 -35
- package/src/math/repeg.ts +175 -0
- package/src/math/trade.ts +45 -35
- package/src/math/utils.js +27 -0
- package/src/math/utils.js.map +1 -0
- package/src/oracles/oracleClientCache.ts +20 -0
- package/src/oracles/pythClient.ts +4 -11
- package/src/oracles/quoteAssetOracleClient.ts +25 -0
- package/src/oracles/switchboardClient.ts +11 -24
- package/src/oracles/types.ts +7 -1
- package/src/orders.ts +35 -20
- package/src/slot/SlotSubscriber.ts +32 -0
- package/src/tx/retryTxSender.ts +6 -4
- package/src/tx/types.ts +6 -1
- package/src/tx/utils.ts +22 -3
- package/src/types.ts +108 -122
- package/src/userName.ts +20 -0
- package/src/util/computeUnits.js +17 -0
- package/src/util/computeUnits.js.map +1 -0
- package/tests/bn/test.ts +255 -0
- package/tsconfig.json +12 -12
- package/lib/addresses.d.ts +0 -10
- package/lib/addresses.js +0 -93
- package/lib/constants/accounts.d.ts +0 -15
- package/lib/constants/accounts.js +0 -18
- package/lib/factory/clearingHouse.d.ts +0 -35
- package/lib/factory/clearingHouse.js +0 -81
- package/lib/factory/clearingHouseUser.d.ts +0 -19
- package/lib/factory/clearingHouseUser.js +0 -34
- package/lib/math/insuranceFund.d.ts +0 -15
- package/lib/math/insuranceFund.js +0 -33
- package/lib/settlement.d.ts +0 -4
- package/lib/settlement.js +0 -10
- package/lib/tx/defaultTxSender.d.ts +0 -8
- package/lib/tx/defaultTxSender.js +0 -12
- package/src/addresses.ts +0 -82
- package/src/constants/accounts.ts +0 -26
- package/src/factory/clearingHouse.ts +0 -173
- package/src/factory/clearingHouseUser.ts +0 -73
- package/src/math/insuranceFund.ts +0 -29
- package/src/settlement.ts +0 -9
- package/src/tx/defaultTxSender.ts +0 -24
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import { BankAccount, BankBalanceType, isVariant } from '../types';
|
|
2
|
+
import { BN } from '@project-serum/anchor';
|
|
3
|
+
import {
|
|
4
|
+
BANK_UTILIZATION_PRECISION,
|
|
5
|
+
ONE,
|
|
6
|
+
TEN,
|
|
7
|
+
ZERO,
|
|
8
|
+
BANK_INTEREST_PRECISION,
|
|
9
|
+
ONE_YEAR,
|
|
10
|
+
} from '../constants/numericConstants';
|
|
11
|
+
|
|
12
|
+
export function getBalance(
|
|
13
|
+
tokenAmount: BN,
|
|
14
|
+
bank: BankAccount,
|
|
15
|
+
balanceType: BankBalanceType
|
|
16
|
+
): BN {
|
|
17
|
+
const precisionIncrease = TEN.pow(new BN(16 - bank.decimals));
|
|
18
|
+
|
|
19
|
+
const cumulativeInterest = isVariant(balanceType, 'deposit')
|
|
20
|
+
? bank.cumulativeDepositInterest
|
|
21
|
+
: bank.cumulativeBorrowInterest;
|
|
22
|
+
|
|
23
|
+
let balance = tokenAmount.mul(precisionIncrease).div(cumulativeInterest);
|
|
24
|
+
|
|
25
|
+
if (!balance.eq(ZERO) && isVariant(balanceType, 'borrow')) {
|
|
26
|
+
balance = balance.add(ONE);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
return balance;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export function getTokenAmount(
|
|
33
|
+
balanceAmount: BN,
|
|
34
|
+
bank: BankAccount,
|
|
35
|
+
balanceType: BankBalanceType
|
|
36
|
+
): BN {
|
|
37
|
+
const precisionDecrease = TEN.pow(new BN(16 - bank.decimals));
|
|
38
|
+
|
|
39
|
+
const cumulativeInterest = isVariant(balanceType, 'deposit')
|
|
40
|
+
? bank.cumulativeDepositInterest
|
|
41
|
+
: bank.cumulativeBorrowInterest;
|
|
42
|
+
|
|
43
|
+
return balanceAmount.mul(cumulativeInterest).div(precisionDecrease);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export function calculateInterestAccumulated(
|
|
47
|
+
bank: BankAccount,
|
|
48
|
+
now: BN
|
|
49
|
+
): { borrowInterest: BN; depositInterest: BN } {
|
|
50
|
+
const token_deposit_amount = getTokenAmount(
|
|
51
|
+
bank.depositBalance,
|
|
52
|
+
bank,
|
|
53
|
+
BankBalanceType.DEPOSIT
|
|
54
|
+
);
|
|
55
|
+
const token_borrow_amount = getTokenAmount(
|
|
56
|
+
bank.borrowBalance,
|
|
57
|
+
bank,
|
|
58
|
+
BankBalanceType.BORROW
|
|
59
|
+
);
|
|
60
|
+
|
|
61
|
+
let utilization: BN;
|
|
62
|
+
if (token_borrow_amount.eq(ZERO) && token_deposit_amount.eq(ZERO)) {
|
|
63
|
+
utilization = ZERO;
|
|
64
|
+
} else if (token_deposit_amount.eq(ZERO)) {
|
|
65
|
+
utilization = BANK_UTILIZATION_PRECISION;
|
|
66
|
+
} else {
|
|
67
|
+
utilization = token_borrow_amount
|
|
68
|
+
.mul(BANK_UTILIZATION_PRECISION)
|
|
69
|
+
.div(token_deposit_amount);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
let interest_rate: BN;
|
|
73
|
+
if (utilization.gt(bank.optimalUtilization)) {
|
|
74
|
+
const surplusUtilization = utilization.sub(bank.optimalUtilization);
|
|
75
|
+
const borrowRateSlope = bank.maxBorrowRate
|
|
76
|
+
.sub(bank.optimalBorrowRate)
|
|
77
|
+
.mul(BANK_UTILIZATION_PRECISION)
|
|
78
|
+
.div(BANK_UTILIZATION_PRECISION.sub(bank.optimalUtilization));
|
|
79
|
+
|
|
80
|
+
interest_rate = bank.optimalBorrowRate.add(
|
|
81
|
+
surplusUtilization.mul(borrowRateSlope).div(BANK_UTILIZATION_PRECISION)
|
|
82
|
+
);
|
|
83
|
+
} else {
|
|
84
|
+
const borrowRateSlope = bank.optimalBorrowRate
|
|
85
|
+
.mul(BANK_UTILIZATION_PRECISION)
|
|
86
|
+
.div(BANK_UTILIZATION_PRECISION.sub(bank.optimalUtilization));
|
|
87
|
+
|
|
88
|
+
interest_rate = utilization
|
|
89
|
+
.mul(borrowRateSlope)
|
|
90
|
+
.div(BANK_UTILIZATION_PRECISION);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
const timeSinceLastUpdate = now.sub(bank.lastUpdated);
|
|
94
|
+
|
|
95
|
+
const modifiedBorrowRate = interest_rate.mul(timeSinceLastUpdate);
|
|
96
|
+
|
|
97
|
+
const modifiedDepositRate = modifiedBorrowRate
|
|
98
|
+
.mul(utilization)
|
|
99
|
+
.div(BANK_UTILIZATION_PRECISION);
|
|
100
|
+
|
|
101
|
+
const borrowInterest = bank.cumulativeBorrowInterest
|
|
102
|
+
.mul(modifiedBorrowRate)
|
|
103
|
+
.div(ONE_YEAR)
|
|
104
|
+
.div(BANK_INTEREST_PRECISION)
|
|
105
|
+
.add(ONE);
|
|
106
|
+
const depositInterest = bank.cumulativeDepositInterest
|
|
107
|
+
.mul(modifiedDepositRate)
|
|
108
|
+
.div(ONE_YEAR)
|
|
109
|
+
.div(BANK_INTEREST_PRECISION);
|
|
110
|
+
|
|
111
|
+
return { borrowInterest, depositInterest };
|
|
112
|
+
}
|
package/src/math/conversion.ts
CHANGED
|
@@ -1,8 +1,5 @@
|
|
|
1
1
|
import { BN } from '../';
|
|
2
|
-
import {
|
|
3
|
-
MARK_PRICE_PRECISION,
|
|
4
|
-
PEG_PRECISION,
|
|
5
|
-
} from '../constants/numericConstants';
|
|
2
|
+
import { MARK_PRICE_PRECISION } from '../constants/numericConstants';
|
|
6
3
|
|
|
7
4
|
export const convertToNumber = (
|
|
8
5
|
bigNumber: BN,
|
|
@@ -14,10 +11,3 @@ export const convertToNumber = (
|
|
|
14
11
|
bigNumber.mod(precision).toNumber() / precision.toNumber()
|
|
15
12
|
);
|
|
16
13
|
};
|
|
17
|
-
|
|
18
|
-
export const convertBaseAssetAmountToNumber = (baseAssetAmount: BN) => {
|
|
19
|
-
return convertToNumber(
|
|
20
|
-
baseAssetAmount,
|
|
21
|
-
MARK_PRICE_PRECISION.mul(PEG_PRECISION)
|
|
22
|
-
);
|
|
23
|
-
};
|
package/src/math/funding.ts
CHANGED
|
@@ -5,7 +5,7 @@ import {
|
|
|
5
5
|
QUOTE_PRECISION,
|
|
6
6
|
ZERO,
|
|
7
7
|
} from '../constants/numericConstants';
|
|
8
|
-
import {
|
|
8
|
+
import { MarketAccount } from '../types';
|
|
9
9
|
import { calculateMarkPrice } from './market';
|
|
10
10
|
import { OraclePriceData } from '../oracles/types';
|
|
11
11
|
|
|
@@ -17,7 +17,7 @@ import { OraclePriceData } from '../oracles/types';
|
|
|
17
17
|
* @returns Estimated funding rate. : Precision //TODO-PRECISION
|
|
18
18
|
*/
|
|
19
19
|
export async function calculateAllEstimatedFundingRate(
|
|
20
|
-
market:
|
|
20
|
+
market: MarketAccount,
|
|
21
21
|
oraclePriceData?: OraclePriceData,
|
|
22
22
|
periodAdjustment: BN = new BN(1)
|
|
23
23
|
): Promise<[BN, BN, BN, BN, BN]> {
|
|
@@ -48,7 +48,10 @@ export async function calculateAllEstimatedFundingRate(
|
|
|
48
48
|
secondsInHour,
|
|
49
49
|
BN.max(ZERO, secondsInHour.sub(timeSinceLastMarkChange))
|
|
50
50
|
);
|
|
51
|
-
const baseAssetPriceWithMantissa = calculateMarkPrice(
|
|
51
|
+
const baseAssetPriceWithMantissa = calculateMarkPrice(
|
|
52
|
+
market,
|
|
53
|
+
oraclePriceData
|
|
54
|
+
);
|
|
52
55
|
|
|
53
56
|
const markTwapWithMantissa = markTwapTimeSinceLastUpdate
|
|
54
57
|
.mul(lastMarkTwapWithMantissa)
|
|
@@ -205,7 +208,7 @@ export async function calculateAllEstimatedFundingRate(
|
|
|
205
208
|
* @returns Estimated funding rate. : Precision //TODO-PRECISION
|
|
206
209
|
*/
|
|
207
210
|
export async function calculateEstimatedFundingRate(
|
|
208
|
-
market:
|
|
211
|
+
market: MarketAccount,
|
|
209
212
|
oraclePriceData?: OraclePriceData,
|
|
210
213
|
periodAdjustment: BN = new BN(1),
|
|
211
214
|
estimationMethod?: 'interpolated' | 'lowerbound' | 'capped'
|
|
@@ -235,7 +238,7 @@ export async function calculateEstimatedFundingRate(
|
|
|
235
238
|
* @returns Estimated funding rate. : Precision //TODO-PRECISION
|
|
236
239
|
*/
|
|
237
240
|
export async function calculateLongShortFundingRate(
|
|
238
|
-
market:
|
|
241
|
+
market: MarketAccount,
|
|
239
242
|
oraclePriceData?: OraclePriceData,
|
|
240
243
|
periodAdjustment: BN = new BN(1)
|
|
241
244
|
): Promise<[BN, BN]> {
|
|
@@ -263,7 +266,7 @@ export async function calculateLongShortFundingRate(
|
|
|
263
266
|
* @returns Estimated funding rate. : Precision //TODO-PRECISION
|
|
264
267
|
*/
|
|
265
268
|
export async function calculateLongShortFundingRateAndLiveTwaps(
|
|
266
|
-
market:
|
|
269
|
+
market: MarketAccount,
|
|
267
270
|
oraclePriceData?: OraclePriceData,
|
|
268
271
|
periodAdjustment: BN = new BN(1)
|
|
269
272
|
): Promise<[BN, BN, BN, BN]> {
|
|
@@ -288,14 +291,14 @@ export async function calculateLongShortFundingRateAndLiveTwaps(
|
|
|
288
291
|
* @param market
|
|
289
292
|
* @returns Estimated fee pool size
|
|
290
293
|
*/
|
|
291
|
-
export function calculateFundingPool(market:
|
|
294
|
+
export function calculateFundingPool(market: MarketAccount): BN {
|
|
292
295
|
// todo
|
|
293
|
-
const totalFeeLB = market.amm.
|
|
296
|
+
const totalFeeLB = market.amm.totalExchangeFee.div(new BN(2));
|
|
294
297
|
const feePool = BN.max(
|
|
295
298
|
ZERO,
|
|
296
299
|
market.amm.totalFeeMinusDistributions
|
|
297
300
|
.sub(totalFeeLB)
|
|
298
|
-
.mul(new BN(
|
|
301
|
+
.mul(new BN(1))
|
|
299
302
|
.div(new BN(3))
|
|
300
303
|
);
|
|
301
304
|
return feePool;
|
package/src/math/market.ts
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import { BN } from '@project-serum/anchor';
|
|
2
|
-
import {
|
|
2
|
+
import { MarketAccount, PositionDirection } from '../types';
|
|
3
3
|
import {
|
|
4
4
|
calculateAmmReservesAfterSwap,
|
|
5
5
|
calculatePrice,
|
|
6
|
-
|
|
6
|
+
calculateUpdatedAMMSpreadReserves,
|
|
7
7
|
getSwapDirection,
|
|
8
|
+
calculateUpdatedAMM,
|
|
8
9
|
} from './amm';
|
|
9
10
|
import { OraclePriceData } from '../oracles/types';
|
|
10
11
|
|
|
@@ -14,11 +15,15 @@ import { OraclePriceData } from '../oracles/types';
|
|
|
14
15
|
* @param market
|
|
15
16
|
* @return markPrice : Precision MARK_PRICE_PRECISION
|
|
16
17
|
*/
|
|
17
|
-
export function calculateMarkPrice(
|
|
18
|
+
export function calculateMarkPrice(
|
|
19
|
+
market: MarketAccount,
|
|
20
|
+
oraclePriceData: OraclePriceData
|
|
21
|
+
): BN {
|
|
22
|
+
const newAmm = calculateUpdatedAMM(market.amm, oraclePriceData);
|
|
18
23
|
return calculatePrice(
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
24
|
+
newAmm.baseAssetReserve,
|
|
25
|
+
newAmm.quoteAssetReserve,
|
|
26
|
+
newAmm.pegMultiplier
|
|
22
27
|
);
|
|
23
28
|
}
|
|
24
29
|
|
|
@@ -28,17 +33,18 @@ export function calculateMarkPrice(market: Market): BN {
|
|
|
28
33
|
* @param market
|
|
29
34
|
* @return bidPrice : Precision MARK_PRICE_PRECISION
|
|
30
35
|
*/
|
|
31
|
-
export function calculateBidPrice(
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
+
export function calculateBidPrice(
|
|
37
|
+
market: MarketAccount,
|
|
38
|
+
oraclePriceData: OraclePriceData
|
|
39
|
+
): BN {
|
|
40
|
+
const { baseAssetReserve, quoteAssetReserve, newPeg } =
|
|
41
|
+
calculateUpdatedAMMSpreadReserves(
|
|
42
|
+
market.amm,
|
|
43
|
+
PositionDirection.SHORT,
|
|
44
|
+
oraclePriceData
|
|
45
|
+
);
|
|
36
46
|
|
|
37
|
-
return calculatePrice(
|
|
38
|
-
baseAssetReserve,
|
|
39
|
-
quoteAssetReserve,
|
|
40
|
-
market.amm.pegMultiplier
|
|
41
|
-
);
|
|
47
|
+
return calculatePrice(baseAssetReserve, quoteAssetReserve, newPeg);
|
|
42
48
|
}
|
|
43
49
|
|
|
44
50
|
/**
|
|
@@ -47,24 +53,25 @@ export function calculateBidPrice(market: Market): BN {
|
|
|
47
53
|
* @param market
|
|
48
54
|
* @return bidPrice : Precision MARK_PRICE_PRECISION
|
|
49
55
|
*/
|
|
50
|
-
export function calculateAskPrice(
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
56
|
+
export function calculateAskPrice(
|
|
57
|
+
market: MarketAccount,
|
|
58
|
+
oraclePriceData: OraclePriceData
|
|
59
|
+
): BN {
|
|
60
|
+
const { baseAssetReserve, quoteAssetReserve, newPeg } =
|
|
61
|
+
calculateUpdatedAMMSpreadReserves(
|
|
62
|
+
market.amm,
|
|
63
|
+
PositionDirection.LONG,
|
|
64
|
+
oraclePriceData
|
|
65
|
+
);
|
|
55
66
|
|
|
56
|
-
return calculatePrice(
|
|
57
|
-
baseAssetReserve,
|
|
58
|
-
quoteAssetReserve,
|
|
59
|
-
market.amm.pegMultiplier
|
|
60
|
-
);
|
|
67
|
+
return calculatePrice(baseAssetReserve, quoteAssetReserve, newPeg);
|
|
61
68
|
}
|
|
62
69
|
|
|
63
70
|
export function calculateNewMarketAfterTrade(
|
|
64
71
|
baseAssetAmount: BN,
|
|
65
72
|
direction: PositionDirection,
|
|
66
|
-
market:
|
|
67
|
-
):
|
|
73
|
+
market: MarketAccount
|
|
74
|
+
): MarketAccount {
|
|
68
75
|
const [newQuoteAssetReserve, newBaseAssetReserve] =
|
|
69
76
|
calculateAmmReservesAfterSwap(
|
|
70
77
|
market.amm,
|
|
@@ -83,10 +90,10 @@ export function calculateNewMarketAfterTrade(
|
|
|
83
90
|
}
|
|
84
91
|
|
|
85
92
|
export function calculateMarkOracleSpread(
|
|
86
|
-
market:
|
|
93
|
+
market: MarketAccount,
|
|
87
94
|
oraclePriceData: OraclePriceData
|
|
88
95
|
): BN {
|
|
89
|
-
const markPrice = calculateMarkPrice(market);
|
|
96
|
+
const markPrice = calculateMarkPrice(market, oraclePriceData);
|
|
90
97
|
return calculateOracleSpread(markPrice, oraclePriceData);
|
|
91
98
|
}
|
|
92
99
|
|
package/src/math/orders.ts
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import { ClearingHouseUser } from '../clearingHouseUser';
|
|
2
2
|
import { isVariant, Order } from '../types';
|
|
3
3
|
import { ZERO, TWO } from '../constants/numericConstants';
|
|
4
|
+
import { BN } from '@project-serum/anchor';
|
|
5
|
+
import { OraclePriceData } from '../oracles/types';
|
|
6
|
+
import { getAuctionPrice } from './auction';
|
|
4
7
|
|
|
5
8
|
export function isOrderRiskIncreasing(
|
|
6
9
|
user: ClearingHouseUser,
|
|
@@ -106,3 +109,38 @@ export function isOrderReduceOnly(
|
|
|
106
109
|
|
|
107
110
|
return true;
|
|
108
111
|
}
|
|
112
|
+
|
|
113
|
+
export function standardizeBaseAssetAmount(
|
|
114
|
+
baseAssetAmount: BN,
|
|
115
|
+
stepSize: BN
|
|
116
|
+
): BN {
|
|
117
|
+
const remainder = baseAssetAmount.mod(stepSize);
|
|
118
|
+
return baseAssetAmount.sub(remainder);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
export function getLimitPrice(
|
|
122
|
+
order: Order,
|
|
123
|
+
oraclePriceData: OraclePriceData,
|
|
124
|
+
slot: number
|
|
125
|
+
): BN {
|
|
126
|
+
let limitPrice;
|
|
127
|
+
if (!order.oraclePriceOffset.eq(ZERO)) {
|
|
128
|
+
const floatingPrice = oraclePriceData.price.add(order.oraclePriceOffset);
|
|
129
|
+
if (order.postOnly) {
|
|
130
|
+
limitPrice = isVariant(order.direction, 'long')
|
|
131
|
+
? BN.min(order.price, floatingPrice)
|
|
132
|
+
: BN.max(order.price, floatingPrice);
|
|
133
|
+
} else {
|
|
134
|
+
limitPrice = floatingPrice;
|
|
135
|
+
}
|
|
136
|
+
} else if (
|
|
137
|
+
isVariant(order.orderType, 'market') ||
|
|
138
|
+
isVariant(order.orderType, 'triggerMarket')
|
|
139
|
+
) {
|
|
140
|
+
limitPrice = getAuctionPrice(order, slot);
|
|
141
|
+
} else {
|
|
142
|
+
limitPrice = order.price;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
return limitPrice;
|
|
146
|
+
}
|
package/src/math/position.ts
CHANGED
|
@@ -9,29 +9,54 @@ import {
|
|
|
9
9
|
PRICE_TO_QUOTE_PRECISION,
|
|
10
10
|
ZERO,
|
|
11
11
|
} from '../constants/numericConstants';
|
|
12
|
-
import {
|
|
13
|
-
import {
|
|
14
|
-
import {
|
|
12
|
+
import { OraclePriceData } from '../oracles/types';
|
|
13
|
+
import { MarketAccount, PositionDirection, UserPosition } from '../types';
|
|
14
|
+
import {
|
|
15
|
+
calculateUpdatedAMM,
|
|
16
|
+
calculateUpdatedAMMSpreadReserves,
|
|
17
|
+
calculateAmmReservesAfterSwap,
|
|
18
|
+
getSwapDirection,
|
|
19
|
+
} from './amm';
|
|
15
20
|
|
|
16
21
|
/**
|
|
17
22
|
* calculateBaseAssetValue
|
|
18
23
|
* = market value of closing entire position
|
|
19
24
|
* @param market
|
|
20
25
|
* @param userPosition
|
|
26
|
+
* @param oraclePriceData
|
|
21
27
|
* @returns Base Asset Value. : Precision QUOTE_PRECISION
|
|
22
28
|
*/
|
|
23
29
|
export function calculateBaseAssetValue(
|
|
24
|
-
market:
|
|
25
|
-
userPosition: UserPosition
|
|
30
|
+
market: MarketAccount,
|
|
31
|
+
userPosition: UserPosition,
|
|
32
|
+
oraclePriceData: OraclePriceData
|
|
26
33
|
): BN {
|
|
27
34
|
if (userPosition.baseAssetAmount.eq(ZERO)) {
|
|
28
35
|
return ZERO;
|
|
29
36
|
}
|
|
30
37
|
|
|
31
38
|
const directionToClose = findDirectionToClose(userPosition);
|
|
39
|
+
let prepegAmm: Parameters<typeof calculateAmmReservesAfterSwap>[0];
|
|
40
|
+
|
|
41
|
+
if (market.amm.baseSpread > 0) {
|
|
42
|
+
const { baseAssetReserve, quoteAssetReserve, sqrtK, newPeg } =
|
|
43
|
+
calculateUpdatedAMMSpreadReserves(
|
|
44
|
+
market.amm,
|
|
45
|
+
directionToClose,
|
|
46
|
+
oraclePriceData
|
|
47
|
+
);
|
|
48
|
+
prepegAmm = {
|
|
49
|
+
baseAssetReserve,
|
|
50
|
+
quoteAssetReserve,
|
|
51
|
+
sqrtK: sqrtK,
|
|
52
|
+
pegMultiplier: newPeg,
|
|
53
|
+
};
|
|
54
|
+
} else {
|
|
55
|
+
prepegAmm = calculateUpdatedAMM(market.amm, oraclePriceData);
|
|
56
|
+
}
|
|
32
57
|
|
|
33
58
|
const [newQuoteAssetReserve, _] = calculateAmmReservesAfterSwap(
|
|
34
|
-
|
|
59
|
+
prepegAmm,
|
|
35
60
|
'base',
|
|
36
61
|
userPosition.baseAssetAmount.abs(),
|
|
37
62
|
getSwapDirection('base', directionToClose)
|
|
@@ -39,15 +64,15 @@ export function calculateBaseAssetValue(
|
|
|
39
64
|
|
|
40
65
|
switch (directionToClose) {
|
|
41
66
|
case PositionDirection.SHORT:
|
|
42
|
-
return
|
|
67
|
+
return prepegAmm.quoteAssetReserve
|
|
43
68
|
.sub(newQuoteAssetReserve)
|
|
44
|
-
.mul(
|
|
69
|
+
.mul(prepegAmm.pegMultiplier)
|
|
45
70
|
.div(AMM_TIMES_PEG_TO_QUOTE_PRECISION_RATIO);
|
|
46
71
|
|
|
47
72
|
case PositionDirection.LONG:
|
|
48
73
|
return newQuoteAssetReserve
|
|
49
|
-
.sub(
|
|
50
|
-
.mul(
|
|
74
|
+
.sub(prepegAmm.quoteAssetReserve)
|
|
75
|
+
.mul(prepegAmm.pegMultiplier)
|
|
51
76
|
.div(AMM_TIMES_PEG_TO_QUOTE_PRECISION_RATIO)
|
|
52
77
|
.add(ONE);
|
|
53
78
|
}
|
|
@@ -62,15 +87,20 @@ export function calculateBaseAssetValue(
|
|
|
62
87
|
* @returns BaseAssetAmount : Precision QUOTE_PRECISION
|
|
63
88
|
*/
|
|
64
89
|
export function calculatePositionPNL(
|
|
65
|
-
market:
|
|
90
|
+
market: MarketAccount,
|
|
66
91
|
marketPosition: UserPosition,
|
|
67
|
-
withFunding = false
|
|
92
|
+
withFunding = false,
|
|
93
|
+
oraclePriceData: OraclePriceData
|
|
68
94
|
): BN {
|
|
69
95
|
if (marketPosition.baseAssetAmount.eq(ZERO)) {
|
|
70
96
|
return ZERO;
|
|
71
97
|
}
|
|
72
98
|
|
|
73
|
-
const baseAssetValue = calculateBaseAssetValue(
|
|
99
|
+
const baseAssetValue = calculateBaseAssetValue(
|
|
100
|
+
market,
|
|
101
|
+
marketPosition,
|
|
102
|
+
oraclePriceData
|
|
103
|
+
);
|
|
74
104
|
|
|
75
105
|
let pnl;
|
|
76
106
|
if (marketPosition.baseAssetAmount.gt(ZERO)) {
|
|
@@ -91,27 +121,6 @@ export function calculatePositionPNL(
|
|
|
91
121
|
return pnl;
|
|
92
122
|
}
|
|
93
123
|
|
|
94
|
-
export function calculateSettledPositionPNL(
|
|
95
|
-
market: Market,
|
|
96
|
-
marketPosition: UserPosition
|
|
97
|
-
): BN {
|
|
98
|
-
let pnl = calculatePositionPNL(market, marketPosition);
|
|
99
|
-
|
|
100
|
-
if (pnl.gt(ZERO)) {
|
|
101
|
-
try {
|
|
102
|
-
pnl = pnl
|
|
103
|
-
.mul(new BN(SETTLEMENT_RATIOS[marketPosition.marketIndex.toNumber()]))
|
|
104
|
-
.div(SETTLEMENT_RATIO_PRECISION);
|
|
105
|
-
} catch (e) {
|
|
106
|
-
console.log(pnl.toString());
|
|
107
|
-
console.log(marketPosition.marketIndex.toNumber());
|
|
108
|
-
throw e;
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
return pnl;
|
|
113
|
-
}
|
|
114
|
-
|
|
115
124
|
/**
|
|
116
125
|
*
|
|
117
126
|
* @param market
|
|
@@ -119,7 +128,7 @@ export function calculateSettledPositionPNL(
|
|
|
119
128
|
* @returns // TODO-PRECISION
|
|
120
129
|
*/
|
|
121
130
|
export function calculatePositionFundingPNL(
|
|
122
|
-
market:
|
|
131
|
+
market: MarketAccount,
|
|
123
132
|
marketPosition: UserPosition
|
|
124
133
|
): BN {
|
|
125
134
|
if (marketPosition.baseAssetAmount.eq(ZERO)) {
|
|
@@ -143,6 +152,10 @@ export function calculatePositionFundingPNL(
|
|
|
143
152
|
return perPositionFundingRate;
|
|
144
153
|
}
|
|
145
154
|
|
|
155
|
+
export function positionIsAvailable(position: UserPosition): boolean {
|
|
156
|
+
return position.baseAssetAmount.eq(ZERO) && position.openOrders.eq(ZERO);
|
|
157
|
+
}
|
|
158
|
+
|
|
146
159
|
/**
|
|
147
160
|
*
|
|
148
161
|
* @param userPosition
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
import { BN } from '@project-serum/anchor';
|
|
2
|
+
import { assert } from '../assert/assert';
|
|
3
|
+
import {
|
|
4
|
+
MARK_PRICE_PRECISION,
|
|
5
|
+
AMM_RESERVE_PRECISION,
|
|
6
|
+
PEG_PRECISION,
|
|
7
|
+
AMM_TO_QUOTE_PRECISION_RATIO,
|
|
8
|
+
QUOTE_PRECISION,
|
|
9
|
+
ZERO,
|
|
10
|
+
} from '../constants/numericConstants';
|
|
11
|
+
import { AMM } from '../types';
|
|
12
|
+
/**
|
|
13
|
+
* Helper function calculating adjust k cost
|
|
14
|
+
* @param amm
|
|
15
|
+
* @param numerator
|
|
16
|
+
* @param denomenator
|
|
17
|
+
* @returns cost : Precision QUOTE_ASSET_PRECISION
|
|
18
|
+
*/
|
|
19
|
+
export function calculateAdjustKCost(
|
|
20
|
+
amm: AMM,
|
|
21
|
+
numerator: BN,
|
|
22
|
+
denomenator: BN
|
|
23
|
+
): BN {
|
|
24
|
+
// const k = market.amm.sqrtK.mul(market.amm.sqrtK);
|
|
25
|
+
const x = amm.baseAssetReserve;
|
|
26
|
+
const y = amm.quoteAssetReserve;
|
|
27
|
+
|
|
28
|
+
const d = amm.netBaseAssetAmount;
|
|
29
|
+
const Q = amm.pegMultiplier;
|
|
30
|
+
|
|
31
|
+
const quoteScale = y.mul(d).mul(Q); //.div(AMM_RESERVE_PRECISION);
|
|
32
|
+
|
|
33
|
+
const p = numerator.mul(MARK_PRICE_PRECISION).div(denomenator);
|
|
34
|
+
|
|
35
|
+
const cost = quoteScale
|
|
36
|
+
.div(x.add(d))
|
|
37
|
+
.sub(
|
|
38
|
+
quoteScale
|
|
39
|
+
.mul(p)
|
|
40
|
+
.div(MARK_PRICE_PRECISION)
|
|
41
|
+
.div(x.mul(p).div(MARK_PRICE_PRECISION).add(d))
|
|
42
|
+
)
|
|
43
|
+
.div(AMM_TO_QUOTE_PRECISION_RATIO)
|
|
44
|
+
.div(PEG_PRECISION);
|
|
45
|
+
|
|
46
|
+
return cost.mul(new BN(-1));
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Helper function calculating adjust pegMultiplier (repeg) cost
|
|
51
|
+
*
|
|
52
|
+
* @param amm
|
|
53
|
+
* @param newPeg
|
|
54
|
+
* @returns cost : Precision QUOTE_ASSET_PRECISION
|
|
55
|
+
*/
|
|
56
|
+
export function calculateRepegCost(amm: AMM, newPeg: BN): BN {
|
|
57
|
+
const dqar = amm.quoteAssetReserve.sub(amm.terminalQuoteAssetReserve);
|
|
58
|
+
const cost = dqar
|
|
59
|
+
.mul(newPeg.sub(amm.pegMultiplier))
|
|
60
|
+
.div(AMM_TO_QUOTE_PRECISION_RATIO)
|
|
61
|
+
.div(PEG_PRECISION);
|
|
62
|
+
return cost;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export function calculateBudgetedKBN(
|
|
66
|
+
x: BN,
|
|
67
|
+
y: BN,
|
|
68
|
+
budget: BN,
|
|
69
|
+
Q: BN,
|
|
70
|
+
d: BN
|
|
71
|
+
): [BN, BN] {
|
|
72
|
+
assert(Q.gt(new BN(0)));
|
|
73
|
+
const C = budget.mul(new BN(-1));
|
|
74
|
+
|
|
75
|
+
let dSign = new BN(1);
|
|
76
|
+
if (d.lt(new BN(0))) {
|
|
77
|
+
dSign = new BN(-1);
|
|
78
|
+
}
|
|
79
|
+
const pegged_y_d_d = y
|
|
80
|
+
.mul(d)
|
|
81
|
+
.mul(d)
|
|
82
|
+
.mul(Q)
|
|
83
|
+
.div(AMM_RESERVE_PRECISION)
|
|
84
|
+
.div(AMM_RESERVE_PRECISION)
|
|
85
|
+
.div(PEG_PRECISION);
|
|
86
|
+
|
|
87
|
+
const numer1 = pegged_y_d_d;
|
|
88
|
+
const numer2 = C.mul(d)
|
|
89
|
+
.div(QUOTE_PRECISION)
|
|
90
|
+
.mul(x.add(d))
|
|
91
|
+
.div(AMM_RESERVE_PRECISION)
|
|
92
|
+
.mul(dSign);
|
|
93
|
+
|
|
94
|
+
const denom1 = C.mul(x)
|
|
95
|
+
.mul(x.add(d))
|
|
96
|
+
.div(AMM_RESERVE_PRECISION)
|
|
97
|
+
.div(QUOTE_PRECISION);
|
|
98
|
+
const denom2 = pegged_y_d_d;
|
|
99
|
+
|
|
100
|
+
const numerator = numer1.sub(numer2).div(AMM_TO_QUOTE_PRECISION_RATIO);
|
|
101
|
+
const denominator = denom1.add(denom2).div(AMM_TO_QUOTE_PRECISION_RATIO);
|
|
102
|
+
|
|
103
|
+
return [numerator, denominator];
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
export function calculateBudgetedK(amm: AMM, cost: BN): [BN, BN] {
|
|
107
|
+
// wolframalpha.com
|
|
108
|
+
// (1/(x+d) - p/(x*p+d))*y*d*Q = C solve for p
|
|
109
|
+
// p = (d(y*d*Q - C(x+d))) / (C*x(x+d) + y*d*d*Q)
|
|
110
|
+
|
|
111
|
+
// numer
|
|
112
|
+
// = y*d*d*Q - Cxd - Cdd
|
|
113
|
+
// = y/x*Q*d*d - Cd - Cd/x
|
|
114
|
+
// = mark - C/d - C/(x)
|
|
115
|
+
// = mark/C - 1/d - 1/x
|
|
116
|
+
|
|
117
|
+
// denom
|
|
118
|
+
// = C*x*x + C*x*d + y*d*d*Q
|
|
119
|
+
// = x/d**2 + 1 / d + mark/C
|
|
120
|
+
|
|
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
|
+
|
|
124
|
+
const x = amm.baseAssetReserve;
|
|
125
|
+
const y = amm.quoteAssetReserve;
|
|
126
|
+
|
|
127
|
+
const d = amm.netBaseAssetAmount;
|
|
128
|
+
const Q = amm.pegMultiplier;
|
|
129
|
+
|
|
130
|
+
const [numerator, denominator] = calculateBudgetedKBN(x, y, cost, Q, d);
|
|
131
|
+
|
|
132
|
+
return [numerator, denominator];
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
export function calculateBudgetedPeg(amm: AMM, cost: BN, targetPrice: BN): BN {
|
|
136
|
+
// wolframalpha.com
|
|
137
|
+
// (1/(x+d) - p/(x*p+d))*y*d*Q = C solve for p
|
|
138
|
+
// p = (d(y*d*Q - C(x+d))) / (C*x(x+d) + y*y*d*Q)
|
|
139
|
+
|
|
140
|
+
// todo: assumes k = x * y
|
|
141
|
+
// otherwise use: (y(1-p) + (kp^2/(x*p+d)) - k/(x+d)) * Q = C solve for p
|
|
142
|
+
const targetPeg = targetPrice
|
|
143
|
+
.mul(amm.baseAssetReserve)
|
|
144
|
+
.div(amm.quoteAssetReserve)
|
|
145
|
+
.div(MARK_PRICE_PRECISION.div(PEG_PRECISION));
|
|
146
|
+
|
|
147
|
+
const k = amm.sqrtK.mul(amm.sqrtK);
|
|
148
|
+
const x = amm.baseAssetReserve;
|
|
149
|
+
const y = amm.quoteAssetReserve;
|
|
150
|
+
|
|
151
|
+
const d = amm.netBaseAssetAmount;
|
|
152
|
+
const Q = amm.pegMultiplier;
|
|
153
|
+
|
|
154
|
+
const C = cost.mul(new BN(-1));
|
|
155
|
+
|
|
156
|
+
const deltaQuoteAssetReserves = y.sub(k.div(x.add(d)));
|
|
157
|
+
const pegChangeDirection = targetPeg.sub(Q);
|
|
158
|
+
|
|
159
|
+
const useTargetPeg =
|
|
160
|
+
(deltaQuoteAssetReserves.lt(ZERO) && pegChangeDirection.gt(ZERO)) ||
|
|
161
|
+
(deltaQuoteAssetReserves.gt(ZERO) && pegChangeDirection.lt(ZERO));
|
|
162
|
+
|
|
163
|
+
if (deltaQuoteAssetReserves.eq(ZERO) || useTargetPeg) {
|
|
164
|
+
return targetPeg;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
const deltaPegMultiplier = C.mul(MARK_PRICE_PRECISION).div(
|
|
168
|
+
deltaQuoteAssetReserves.div(AMM_TO_QUOTE_PRECISION_RATIO)
|
|
169
|
+
);
|
|
170
|
+
const newPeg = Q.sub(
|
|
171
|
+
deltaPegMultiplier.mul(PEG_PRECISION).div(MARK_PRICE_PRECISION)
|
|
172
|
+
);
|
|
173
|
+
|
|
174
|
+
return newPeg;
|
|
175
|
+
}
|