@drift-labs/sdk 0.2.0-master.10 → 0.2.0-master.13
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/admin.d.ts +3 -3
- package/lib/admin.js +6 -6
- package/lib/clearingHouse.d.ts +22 -6
- package/lib/clearingHouse.js +357 -74
- package/lib/clearingHouseUser.d.ts +12 -17
- package/lib/clearingHouseUser.js +97 -88
- package/lib/config.js +1 -1
- package/lib/constants/banks.d.ts +2 -2
- package/lib/constants/banks.js +5 -4
- package/lib/constants/numericConstants.d.ts +3 -0
- package/lib/constants/numericConstants.js +4 -1
- package/lib/events/eventList.js +3 -0
- package/lib/events/types.d.ts +2 -1
- package/lib/factory/bigNum.d.ts +1 -0
- package/lib/factory/bigNum.js +37 -11
- package/lib/idl/clearing_house.json +611 -146
- package/lib/idl/{mock_usdc_faucet.json → token_faucet.json} +46 -23
- package/lib/index.d.ts +2 -1
- package/lib/index.js +2 -1
- package/lib/math/amm.js +2 -2
- package/lib/math/bankBalance.d.ts +3 -1
- package/lib/math/bankBalance.js +54 -1
- package/lib/math/margin.d.ts +11 -0
- package/lib/math/margin.js +72 -0
- package/lib/math/market.d.ts +4 -1
- package/lib/math/market.js +35 -1
- package/lib/math/position.d.ts +8 -0
- package/lib/math/position.js +42 -12
- package/lib/orders.d.ts +1 -2
- package/lib/orders.js +2 -77
- package/lib/{mockUSDCFaucet.d.ts → tokenFaucet.d.ts} +8 -5
- package/lib/{mockUSDCFaucet.js → tokenFaucet.js} +63 -51
- package/lib/tx/retryTxSender.js +9 -2
- package/lib/types.d.ts +86 -16
- package/lib/types.js +18 -1
- 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 +1 -1
- package/src/admin.ts +7 -7
- package/src/clearingHouse.ts +636 -94
- package/src/clearingHouseConfig.js +2 -0
- package/src/clearingHouseUser.ts +219 -121
- package/src/clearingHouseUserConfig.js +2 -0
- package/src/config.ts +1 -1
- package/src/constants/banks.js +42 -0
- package/src/constants/banks.ts +7 -4
- package/src/constants/markets.js +42 -0
- package/src/constants/numericConstants.js +41 -0
- package/src/constants/numericConstants.ts +4 -0
- package/src/events/eventList.ts +3 -0
- package/src/events/types.ts +2 -0
- package/src/factory/bigNum.js +37 -11
- package/src/factory/bigNum.ts +43 -13
- package/src/idl/clearing_house.json +611 -146
- package/src/idl/{mock_usdc_faucet.json → token_faucet.json} +46 -23
- package/src/index.js +1 -1
- package/src/index.ts +2 -1
- package/src/math/amm.ts +8 -5
- package/src/math/bankBalance.ts +98 -1
- package/src/math/margin.ts +124 -0
- package/src/math/market.ts +66 -1
- package/src/math/position.ts +59 -9
- package/src/mockUSDCFaucet.js +276 -167
- package/src/orders.ts +4 -157
- package/src/tokenFaucet.js +189 -0
- package/src/{mockUSDCFaucet.ts → tokenFaucet.ts} +82 -70
- package/src/tx/retryTxSender.ts +11 -3
- package/src/types.js +12 -1
- package/src/types.ts +88 -16
- package/src/{accounts/fetch.js → util/computeUnits.js} +11 -13
- package/src/util/computeUnits.ts +1 -1
- package/src/util/getTokenAddress.js +9 -0
- package/src/util/getTokenAddress.ts +18 -0
- package/tests/bn/test.ts +2 -0
- package/src/addresses/pda.js +0 -104
- package/src/math/bankBalance.js +0 -75
- package/src/math/market.js +0 -57
- package/src/math/orders.js +0 -110
- package/src/math/position.js +0 -140
- package/src/orders.js +0 -134
- package/src/tx/retryTxSender.js +0 -188
|
@@ -1,23 +1,23 @@
|
|
|
1
1
|
{
|
|
2
|
-
"version": "0.
|
|
3
|
-
"name": "
|
|
2
|
+
"version": "0.1.0",
|
|
3
|
+
"name": "token_faucet",
|
|
4
4
|
"instructions": [
|
|
5
5
|
{
|
|
6
6
|
"name": "initialize",
|
|
7
7
|
"accounts": [
|
|
8
8
|
{
|
|
9
|
-
"name": "
|
|
9
|
+
"name": "faucetConfig",
|
|
10
10
|
"isMut": true,
|
|
11
11
|
"isSigner": false
|
|
12
12
|
},
|
|
13
13
|
{
|
|
14
14
|
"name": "admin",
|
|
15
|
-
"isMut":
|
|
15
|
+
"isMut": true,
|
|
16
16
|
"isSigner": true
|
|
17
17
|
},
|
|
18
18
|
{
|
|
19
19
|
"name": "mintAccount",
|
|
20
|
-
"isMut":
|
|
20
|
+
"isMut": true,
|
|
21
21
|
"isSigner": false
|
|
22
22
|
},
|
|
23
23
|
{
|
|
@@ -29,20 +29,20 @@
|
|
|
29
29
|
"name": "systemProgram",
|
|
30
30
|
"isMut": false,
|
|
31
31
|
"isSigner": false
|
|
32
|
-
}
|
|
33
|
-
],
|
|
34
|
-
"args": [
|
|
32
|
+
},
|
|
35
33
|
{
|
|
36
|
-
"name": "
|
|
37
|
-
"
|
|
34
|
+
"name": "tokenProgram",
|
|
35
|
+
"isMut": false,
|
|
36
|
+
"isSigner": false
|
|
38
37
|
}
|
|
39
|
-
]
|
|
38
|
+
],
|
|
39
|
+
"args": []
|
|
40
40
|
},
|
|
41
41
|
{
|
|
42
42
|
"name": "mintToUser",
|
|
43
43
|
"accounts": [
|
|
44
44
|
{
|
|
45
|
-
"name": "
|
|
45
|
+
"name": "faucetConfig",
|
|
46
46
|
"isMut": false,
|
|
47
47
|
"isSigner": false
|
|
48
48
|
},
|
|
@@ -73,11 +73,42 @@
|
|
|
73
73
|
"type": "u64"
|
|
74
74
|
}
|
|
75
75
|
]
|
|
76
|
+
},
|
|
77
|
+
{
|
|
78
|
+
"name": "transferMintAuthority",
|
|
79
|
+
"accounts": [
|
|
80
|
+
{
|
|
81
|
+
"name": "faucetConfig",
|
|
82
|
+
"isMut": false,
|
|
83
|
+
"isSigner": false
|
|
84
|
+
},
|
|
85
|
+
{
|
|
86
|
+
"name": "admin",
|
|
87
|
+
"isMut": true,
|
|
88
|
+
"isSigner": true
|
|
89
|
+
},
|
|
90
|
+
{
|
|
91
|
+
"name": "mintAccount",
|
|
92
|
+
"isMut": true,
|
|
93
|
+
"isSigner": false
|
|
94
|
+
},
|
|
95
|
+
{
|
|
96
|
+
"name": "mintAuthority",
|
|
97
|
+
"isMut": false,
|
|
98
|
+
"isSigner": false
|
|
99
|
+
},
|
|
100
|
+
{
|
|
101
|
+
"name": "tokenProgram",
|
|
102
|
+
"isMut": false,
|
|
103
|
+
"isSigner": false
|
|
104
|
+
}
|
|
105
|
+
],
|
|
106
|
+
"args": []
|
|
76
107
|
}
|
|
77
108
|
],
|
|
78
109
|
"accounts": [
|
|
79
110
|
{
|
|
80
|
-
"name": "
|
|
111
|
+
"name": "FaucetConfig",
|
|
81
112
|
"type": {
|
|
82
113
|
"kind": "struct",
|
|
83
114
|
"fields": [
|
|
@@ -103,17 +134,9 @@
|
|
|
103
134
|
],
|
|
104
135
|
"errors": [
|
|
105
136
|
{
|
|
106
|
-
"code":
|
|
137
|
+
"code": 6000,
|
|
107
138
|
"name": "InvalidMintAccountAuthority",
|
|
108
139
|
"msg": "Program not mint authority"
|
|
109
|
-
},
|
|
110
|
-
{
|
|
111
|
-
"code": 301,
|
|
112
|
-
"name": "Unauthorized",
|
|
113
|
-
"msg": "Signer must be MockUSDCFaucet admin"
|
|
114
140
|
}
|
|
115
|
-
]
|
|
116
|
-
"metadata": {
|
|
117
|
-
"address": "2z2DLVD3tBWc86pbvvy5qN31v1NXprM6zA5MDr2FMx64"
|
|
118
|
-
}
|
|
141
|
+
]
|
|
119
142
|
}
|
package/src/index.js
CHANGED
|
@@ -20,7 +20,7 @@ const web3_js_1 = require("@solana/web3.js");
|
|
|
20
20
|
Object.defineProperty(exports, "PublicKey", { enumerable: true, get: function () { return web3_js_1.PublicKey; } });
|
|
21
21
|
const client_1 = __importDefault(require("@pythnetwork/client"));
|
|
22
22
|
exports.pyth = client_1.default;
|
|
23
|
-
__exportStar(require("./
|
|
23
|
+
__exportStar(require("./tokenFaucet"), exports);
|
|
24
24
|
__exportStar(require("./oracles/types"), exports);
|
|
25
25
|
__exportStar(require("./oracles/pythClient"), exports);
|
|
26
26
|
__exportStar(require("./oracles/switchboardClient"), exports);
|
package/src/index.ts
CHANGED
|
@@ -2,7 +2,7 @@ import { BN } from '@project-serum/anchor';
|
|
|
2
2
|
import { PublicKey } from '@solana/web3.js';
|
|
3
3
|
import pyth from '@pythnetwork/client';
|
|
4
4
|
|
|
5
|
-
export * from './
|
|
5
|
+
export * from './tokenFaucet';
|
|
6
6
|
export * from './oracles/types';
|
|
7
7
|
export * from './oracles/pythClient';
|
|
8
8
|
export * from './oracles/switchboardClient';
|
|
@@ -35,6 +35,7 @@ export * from './math/amm';
|
|
|
35
35
|
export * from './math/trade';
|
|
36
36
|
export * from './math/orders';
|
|
37
37
|
export * from './math/repeg';
|
|
38
|
+
export * from './math/margin';
|
|
38
39
|
export * from './orders';
|
|
39
40
|
export * from './orderParams';
|
|
40
41
|
export * from './slot/SlotSubscriber';
|
package/src/math/amm.ts
CHANGED
|
@@ -33,11 +33,14 @@ export function calculatePegFromTargetPrice(
|
|
|
33
33
|
baseAssetReserve: BN,
|
|
34
34
|
quoteAssetReserve: BN
|
|
35
35
|
): BN {
|
|
36
|
-
return
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
36
|
+
return BN.max(
|
|
37
|
+
targetPrice
|
|
38
|
+
.mul(baseAssetReserve)
|
|
39
|
+
.div(quoteAssetReserve)
|
|
40
|
+
.add(PRICE_DIV_PEG.div(new BN(2)))
|
|
41
|
+
.div(PRICE_DIV_PEG),
|
|
42
|
+
ONE
|
|
43
|
+
);
|
|
41
44
|
}
|
|
42
45
|
|
|
43
46
|
export function calculateOptimalPegAndBudget(
|
package/src/math/bankBalance.ts
CHANGED
|
@@ -1,4 +1,9 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
BankAccount,
|
|
3
|
+
BankBalanceType,
|
|
4
|
+
isVariant,
|
|
5
|
+
MarginCategory,
|
|
6
|
+
} from '../types';
|
|
2
7
|
import { BN } from '@project-serum/anchor';
|
|
3
8
|
import {
|
|
4
9
|
BANK_UTILIZATION_PRECISION,
|
|
@@ -6,8 +11,14 @@ import {
|
|
|
6
11
|
TEN,
|
|
7
12
|
ZERO,
|
|
8
13
|
BANK_INTEREST_PRECISION,
|
|
14
|
+
BANK_WEIGHT_PRECISION,
|
|
9
15
|
ONE_YEAR,
|
|
16
|
+
AMM_RESERVE_PRECISION,
|
|
10
17
|
} from '../constants/numericConstants';
|
|
18
|
+
import {
|
|
19
|
+
calculateSizeDiscountAssetWeight,
|
|
20
|
+
calculateSizePremiumLiabilityWeight,
|
|
21
|
+
} from './margin';
|
|
11
22
|
|
|
12
23
|
export function getBalance(
|
|
13
24
|
tokenAmount: BN,
|
|
@@ -43,6 +54,92 @@ export function getTokenAmount(
|
|
|
43
54
|
return balanceAmount.mul(cumulativeInterest).div(precisionDecrease);
|
|
44
55
|
}
|
|
45
56
|
|
|
57
|
+
export function calculateAssetWeight(
|
|
58
|
+
balanceAmount: BN,
|
|
59
|
+
bank: BankAccount,
|
|
60
|
+
marginCategory: MarginCategory
|
|
61
|
+
): BN {
|
|
62
|
+
const sizePrecision = TEN.pow(new BN(bank.decimals));
|
|
63
|
+
let sizeInAmmReservePrecision;
|
|
64
|
+
if (sizePrecision.gt(AMM_RESERVE_PRECISION)) {
|
|
65
|
+
sizeInAmmReservePrecision = balanceAmount.div(
|
|
66
|
+
sizePrecision.div(AMM_RESERVE_PRECISION)
|
|
67
|
+
);
|
|
68
|
+
} else {
|
|
69
|
+
sizeInAmmReservePrecision = balanceAmount
|
|
70
|
+
.mul(AMM_RESERVE_PRECISION)
|
|
71
|
+
.div(sizePrecision);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
let assetWeight;
|
|
75
|
+
|
|
76
|
+
switch (marginCategory) {
|
|
77
|
+
case 'Initial':
|
|
78
|
+
assetWeight = calculateSizeDiscountAssetWeight(
|
|
79
|
+
sizeInAmmReservePrecision,
|
|
80
|
+
bank.imfFactor,
|
|
81
|
+
bank.initialAssetWeight
|
|
82
|
+
);
|
|
83
|
+
break;
|
|
84
|
+
case 'Maintenance':
|
|
85
|
+
assetWeight = calculateSizeDiscountAssetWeight(
|
|
86
|
+
sizeInAmmReservePrecision,
|
|
87
|
+
bank.imfFactor,
|
|
88
|
+
bank.maintenanceAssetWeight
|
|
89
|
+
);
|
|
90
|
+
break;
|
|
91
|
+
default:
|
|
92
|
+
assetWeight = bank.initialAssetWeight;
|
|
93
|
+
break;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
return assetWeight;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
export function calculateLiabilityWeight(
|
|
100
|
+
balanceAmount: BN,
|
|
101
|
+
bank: BankAccount,
|
|
102
|
+
marginCategory: MarginCategory
|
|
103
|
+
): BN {
|
|
104
|
+
const sizePrecision = TEN.pow(new BN(bank.decimals));
|
|
105
|
+
let sizeInAmmReservePrecision;
|
|
106
|
+
if (sizePrecision.gt(AMM_RESERVE_PRECISION)) {
|
|
107
|
+
sizeInAmmReservePrecision = balanceAmount.div(
|
|
108
|
+
sizePrecision.div(AMM_RESERVE_PRECISION)
|
|
109
|
+
);
|
|
110
|
+
} else {
|
|
111
|
+
sizeInAmmReservePrecision = balanceAmount
|
|
112
|
+
.mul(AMM_RESERVE_PRECISION)
|
|
113
|
+
.div(sizePrecision);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
let assetWeight;
|
|
117
|
+
|
|
118
|
+
switch (marginCategory) {
|
|
119
|
+
case 'Initial':
|
|
120
|
+
assetWeight = calculateSizePremiumLiabilityWeight(
|
|
121
|
+
sizeInAmmReservePrecision,
|
|
122
|
+
bank.imfFactor,
|
|
123
|
+
bank.initialLiabilityWeight,
|
|
124
|
+
BANK_WEIGHT_PRECISION
|
|
125
|
+
);
|
|
126
|
+
break;
|
|
127
|
+
case 'Maintenance':
|
|
128
|
+
assetWeight = calculateSizePremiumLiabilityWeight(
|
|
129
|
+
sizeInAmmReservePrecision,
|
|
130
|
+
bank.imfFactor,
|
|
131
|
+
bank.maintenanceLiabilityWeight,
|
|
132
|
+
BANK_WEIGHT_PRECISION
|
|
133
|
+
);
|
|
134
|
+
break;
|
|
135
|
+
default:
|
|
136
|
+
assetWeight = bank.initialLiabilityWeight;
|
|
137
|
+
break;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
return assetWeight;
|
|
141
|
+
}
|
|
142
|
+
|
|
46
143
|
export function calculateInterestAccumulated(
|
|
47
144
|
bank: BankAccount,
|
|
48
145
|
now: BN
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import { squareRootBN } from './utils';
|
|
2
|
+
import {
|
|
3
|
+
BANK_WEIGHT_PRECISION,
|
|
4
|
+
BANK_IMF_PRECISION,
|
|
5
|
+
ZERO,
|
|
6
|
+
BID_ASK_SPREAD_PRECISION,
|
|
7
|
+
AMM_TO_QUOTE_PRECISION_RATIO,
|
|
8
|
+
MARK_PRICE_PRECISION,
|
|
9
|
+
} from '../constants/numericConstants';
|
|
10
|
+
import { BN } from '@project-serum/anchor';
|
|
11
|
+
import { OraclePriceData } from '../oracles/types';
|
|
12
|
+
import { MarketAccount, UserPosition } from '..';
|
|
13
|
+
|
|
14
|
+
export function calculateSizePremiumLiabilityWeight(
|
|
15
|
+
size: BN, // AMM_RESERVE_PRECISION
|
|
16
|
+
imfFactor: BN,
|
|
17
|
+
liabilityWeight: BN,
|
|
18
|
+
precision: BN
|
|
19
|
+
): BN {
|
|
20
|
+
if (imfFactor.eq(ZERO)) {
|
|
21
|
+
return liabilityWeight;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const sizeSqrt = squareRootBN(size.div(new BN(1000)).add(new BN(1))); //1e13 -> 1e10 -> 1e5
|
|
25
|
+
const liabilityWeightNumerator = liabilityWeight.sub(
|
|
26
|
+
liabilityWeight.div(BN.max(new BN(1), BANK_IMF_PRECISION.div(imfFactor)))
|
|
27
|
+
);
|
|
28
|
+
|
|
29
|
+
const sizePremiumLiabilityWeight = liabilityWeightNumerator.add(
|
|
30
|
+
sizeSqrt // 1e5
|
|
31
|
+
.mul(imfFactor)
|
|
32
|
+
.div(new BN(100_000).mul(BANK_IMF_PRECISION).div(precision)) // 1e5
|
|
33
|
+
);
|
|
34
|
+
|
|
35
|
+
const maxLiabilityWeight = BN.max(
|
|
36
|
+
liabilityWeight,
|
|
37
|
+
sizePremiumLiabilityWeight
|
|
38
|
+
);
|
|
39
|
+
return maxLiabilityWeight;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export function calculateSizeDiscountAssetWeight(
|
|
43
|
+
size: BN, // AMM_RESERVE_PRECISION
|
|
44
|
+
imfFactor: BN,
|
|
45
|
+
assetWeight: BN
|
|
46
|
+
): BN {
|
|
47
|
+
if (imfFactor.eq(ZERO)) {
|
|
48
|
+
return assetWeight;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
const sizeSqrt = squareRootBN(size.div(new BN(1000)).add(new BN(1))); //1e13 -> 1e10 -> 1e5
|
|
52
|
+
const imfNumerator = BANK_IMF_PRECISION.add(
|
|
53
|
+
BANK_IMF_PRECISION.div(new BN(10))
|
|
54
|
+
);
|
|
55
|
+
|
|
56
|
+
const sizeDiscountAssetWeight = imfNumerator.mul(BANK_WEIGHT_PRECISION).div(
|
|
57
|
+
BANK_IMF_PRECISION.add(
|
|
58
|
+
sizeSqrt // 1e5
|
|
59
|
+
.mul(imfFactor)
|
|
60
|
+
.div(new BN(100_000)) // 1e5
|
|
61
|
+
)
|
|
62
|
+
);
|
|
63
|
+
|
|
64
|
+
const minAssetWeight = BN.min(assetWeight, sizeDiscountAssetWeight);
|
|
65
|
+
|
|
66
|
+
return minAssetWeight;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
export function calculateOraclePriceForPerpMargin(
|
|
70
|
+
marketPosition: UserPosition,
|
|
71
|
+
market: MarketAccount,
|
|
72
|
+
oraclePriceData: OraclePriceData
|
|
73
|
+
): BN {
|
|
74
|
+
const oraclePriceOffset = BN.min(
|
|
75
|
+
new BN(market.amm.maxSpread)
|
|
76
|
+
.mul(oraclePriceData.price)
|
|
77
|
+
.div(BID_ASK_SPREAD_PRECISION),
|
|
78
|
+
oraclePriceData.confidence.add(
|
|
79
|
+
new BN(market.amm.baseSpread)
|
|
80
|
+
.mul(oraclePriceData.price)
|
|
81
|
+
.div(BID_ASK_SPREAD_PRECISION)
|
|
82
|
+
)
|
|
83
|
+
);
|
|
84
|
+
|
|
85
|
+
let marginPrice: BN;
|
|
86
|
+
if (marketPosition.baseAssetAmount.gt(ZERO)) {
|
|
87
|
+
marginPrice = oraclePriceData.price.sub(oraclePriceOffset);
|
|
88
|
+
} else {
|
|
89
|
+
marginPrice = oraclePriceData.price.add(oraclePriceOffset);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
return marginPrice;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
export function calculateMarginBaseAssetValue(
|
|
96
|
+
market: MarketAccount,
|
|
97
|
+
marketPosition: UserPosition,
|
|
98
|
+
oraclePriceData: OraclePriceData
|
|
99
|
+
): BN {
|
|
100
|
+
const marginPrice = calculateOraclePriceForPerpMargin(
|
|
101
|
+
marketPosition,
|
|
102
|
+
market,
|
|
103
|
+
oraclePriceData
|
|
104
|
+
);
|
|
105
|
+
const baseAssetValue = marketPosition.baseAssetAmount
|
|
106
|
+
.abs()
|
|
107
|
+
.mul(marginPrice)
|
|
108
|
+
.div(AMM_TO_QUOTE_PRECISION_RATIO.mul(MARK_PRICE_PRECISION));
|
|
109
|
+
|
|
110
|
+
return baseAssetValue;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
export function calculateWorstCaseBaseAssetAmount(
|
|
114
|
+
marketPosition: UserPosition
|
|
115
|
+
): BN {
|
|
116
|
+
const allBids = marketPosition.baseAssetAmount.add(marketPosition.openBids);
|
|
117
|
+
const allAsks = marketPosition.baseAssetAmount.add(marketPosition.openAsks);
|
|
118
|
+
|
|
119
|
+
if (allBids.abs().gt(allAsks.abs())) {
|
|
120
|
+
return allBids;
|
|
121
|
+
} else {
|
|
122
|
+
return allAsks;
|
|
123
|
+
}
|
|
124
|
+
}
|
package/src/math/market.ts
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
import { BN } from '@project-serum/anchor';
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
MarketAccount,
|
|
4
|
+
PositionDirection,
|
|
5
|
+
MarginCategory,
|
|
6
|
+
BankAccount,
|
|
7
|
+
BankBalanceType,
|
|
8
|
+
} from '../types';
|
|
3
9
|
import {
|
|
4
10
|
calculateAmmReservesAfterSwap,
|
|
5
11
|
calculatePrice,
|
|
@@ -7,7 +13,13 @@ import {
|
|
|
7
13
|
getSwapDirection,
|
|
8
14
|
calculateUpdatedAMM,
|
|
9
15
|
} from './amm';
|
|
16
|
+
import {
|
|
17
|
+
calculateSizeDiscountAssetWeight,
|
|
18
|
+
calculateSizePremiumLiabilityWeight,
|
|
19
|
+
} from './margin';
|
|
10
20
|
import { OraclePriceData } from '../oracles/types';
|
|
21
|
+
import { MARGIN_PRECISION } from '../constants/numericConstants';
|
|
22
|
+
import { getTokenAmount } from './bankBalance';
|
|
11
23
|
|
|
12
24
|
/**
|
|
13
25
|
* Calculates market mark price
|
|
@@ -103,3 +115,56 @@ export function calculateOracleSpread(
|
|
|
103
115
|
): BN {
|
|
104
116
|
return price.sub(oraclePriceData.price);
|
|
105
117
|
}
|
|
118
|
+
|
|
119
|
+
export function calculateMarketMarginRatio(
|
|
120
|
+
market: MarketAccount,
|
|
121
|
+
size: BN,
|
|
122
|
+
marginCategory: MarginCategory
|
|
123
|
+
): number {
|
|
124
|
+
let marginRatio;
|
|
125
|
+
switch (marginCategory) {
|
|
126
|
+
case 'Initial':
|
|
127
|
+
marginRatio = calculateSizePremiumLiabilityWeight(
|
|
128
|
+
size,
|
|
129
|
+
market.imfFactor,
|
|
130
|
+
new BN(market.marginRatioInitial),
|
|
131
|
+
MARGIN_PRECISION
|
|
132
|
+
).toNumber();
|
|
133
|
+
break;
|
|
134
|
+
case 'Maintenance':
|
|
135
|
+
marginRatio = market.marginRatioMaintenance;
|
|
136
|
+
break;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
return marginRatio;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
export function calculateUnsettledAssetWeight(
|
|
143
|
+
market: MarketAccount,
|
|
144
|
+
unsettledPnl: BN,
|
|
145
|
+
marginCategory: MarginCategory
|
|
146
|
+
): BN {
|
|
147
|
+
let assetWeight: BN;
|
|
148
|
+
|
|
149
|
+
switch (marginCategory) {
|
|
150
|
+
case 'Initial':
|
|
151
|
+
assetWeight = calculateSizeDiscountAssetWeight(
|
|
152
|
+
unsettledPnl,
|
|
153
|
+
market.unsettledImfFactor,
|
|
154
|
+
new BN(market.unsettledInitialAssetWeight)
|
|
155
|
+
);
|
|
156
|
+
break;
|
|
157
|
+
case 'Maintenance':
|
|
158
|
+
assetWeight = new BN(market.unsettledMaintenanceAssetWeight);
|
|
159
|
+
break;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
return assetWeight;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
export function calculateMarketAvailablePNL(
|
|
166
|
+
market: MarketAccount,
|
|
167
|
+
bank: BankAccount
|
|
168
|
+
): BN {
|
|
169
|
+
return getTokenAmount(market.pnlPool.balance, bank, BankBalanceType.DEPOSIT);
|
|
170
|
+
}
|
package/src/math/position.ts
CHANGED
|
@@ -18,6 +18,8 @@ import {
|
|
|
18
18
|
getSwapDirection,
|
|
19
19
|
} from './amm';
|
|
20
20
|
|
|
21
|
+
import { calculateMarginBaseAssetValue } from './margin';
|
|
22
|
+
|
|
21
23
|
/**
|
|
22
24
|
* calculateBaseAssetValue
|
|
23
25
|
* = market value of closing entire position
|
|
@@ -84,6 +86,7 @@ export function calculateBaseAssetValue(
|
|
|
84
86
|
* @param market
|
|
85
87
|
* @param marketPosition
|
|
86
88
|
* @param withFunding (adds unrealized funding payment pnl to result)
|
|
89
|
+
* @param oraclePriceData
|
|
87
90
|
* @returns BaseAssetAmount : Precision QUOTE_PRECISION
|
|
88
91
|
*/
|
|
89
92
|
export function calculatePositionPNL(
|
|
@@ -93,21 +96,21 @@ export function calculatePositionPNL(
|
|
|
93
96
|
oraclePriceData: OraclePriceData
|
|
94
97
|
): BN {
|
|
95
98
|
if (marketPosition.baseAssetAmount.eq(ZERO)) {
|
|
96
|
-
return
|
|
99
|
+
return marketPosition.quoteAssetAmount;
|
|
97
100
|
}
|
|
98
101
|
|
|
99
|
-
const baseAssetValue =
|
|
102
|
+
const baseAssetValue = calculateMarginBaseAssetValue(
|
|
100
103
|
market,
|
|
101
104
|
marketPosition,
|
|
102
105
|
oraclePriceData
|
|
103
106
|
);
|
|
104
107
|
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
108
|
+
const baseAssetValueSign = marketPosition.baseAssetAmount.isNeg()
|
|
109
|
+
? new BN(-1)
|
|
110
|
+
: new BN(1);
|
|
111
|
+
let pnl = baseAssetValue
|
|
112
|
+
.mul(baseAssetValueSign)
|
|
113
|
+
.add(marketPosition.quoteAssetAmount);
|
|
111
114
|
|
|
112
115
|
if (withFunding) {
|
|
113
116
|
const fundingRatePnL = calculatePositionFundingPNL(
|
|
@@ -121,6 +124,36 @@ export function calculatePositionPNL(
|
|
|
121
124
|
return pnl;
|
|
122
125
|
}
|
|
123
126
|
|
|
127
|
+
export function calculateUnsettledPnl(
|
|
128
|
+
market: MarketAccount,
|
|
129
|
+
marketPosition: UserPosition,
|
|
130
|
+
oraclePriceData: OraclePriceData
|
|
131
|
+
): BN {
|
|
132
|
+
const unrealizedPnl = calculatePositionPNL(
|
|
133
|
+
market,
|
|
134
|
+
marketPosition,
|
|
135
|
+
true,
|
|
136
|
+
oraclePriceData
|
|
137
|
+
);
|
|
138
|
+
|
|
139
|
+
let unsettledPnl = unrealizedPnl;
|
|
140
|
+
if (unrealizedPnl.gt(ZERO)) {
|
|
141
|
+
const fundingPnL = calculatePositionFundingPNL(market, marketPosition).div(
|
|
142
|
+
PRICE_TO_QUOTE_PRECISION
|
|
143
|
+
);
|
|
144
|
+
|
|
145
|
+
const maxPositivePnl = BN.max(
|
|
146
|
+
marketPosition.quoteAssetAmount
|
|
147
|
+
.add(marketPosition.quoteEntryAmount)
|
|
148
|
+
.add(fundingPnL),
|
|
149
|
+
ZERO
|
|
150
|
+
);
|
|
151
|
+
|
|
152
|
+
unsettledPnl = BN.min(maxPositivePnl, unrealizedPnl);
|
|
153
|
+
}
|
|
154
|
+
return unsettledPnl;
|
|
155
|
+
}
|
|
156
|
+
|
|
124
157
|
/**
|
|
125
158
|
*
|
|
126
159
|
* @param market
|
|
@@ -156,7 +189,7 @@ export function positionIsAvailable(position: UserPosition): boolean {
|
|
|
156
189
|
return (
|
|
157
190
|
position.baseAssetAmount.eq(ZERO) &&
|
|
158
191
|
position.openOrders.eq(ZERO) &&
|
|
159
|
-
position.
|
|
192
|
+
position.quoteAssetAmount.eq(ZERO)
|
|
160
193
|
);
|
|
161
194
|
}
|
|
162
195
|
|
|
@@ -170,6 +203,23 @@ export function calculateEntryPrice(userPosition: UserPosition): BN {
|
|
|
170
203
|
return ZERO;
|
|
171
204
|
}
|
|
172
205
|
|
|
206
|
+
return userPosition.quoteEntryAmount
|
|
207
|
+
.mul(MARK_PRICE_PRECISION)
|
|
208
|
+
.mul(AMM_TO_QUOTE_PRECISION_RATIO)
|
|
209
|
+
.div(userPosition.baseAssetAmount)
|
|
210
|
+
.abs();
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
/**
|
|
214
|
+
*
|
|
215
|
+
* @param userPosition
|
|
216
|
+
* @returns Precision: MARK_PRICE_PRECISION (10^10)
|
|
217
|
+
*/
|
|
218
|
+
export function calculateCostBasis(userPosition: UserPosition): BN {
|
|
219
|
+
if (userPosition.baseAssetAmount.eq(ZERO)) {
|
|
220
|
+
return ZERO;
|
|
221
|
+
}
|
|
222
|
+
|
|
173
223
|
return userPosition.quoteAssetAmount
|
|
174
224
|
.mul(MARK_PRICE_PRECISION)
|
|
175
225
|
.mul(AMM_TO_QUOTE_PRECISION_RATIO)
|