@velocity-exchange/sdk 0.4.0 → 0.6.1
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 +3 -3
- package/lib/browser/adminClient.d.ts +52 -0
- package/lib/browser/adminClient.js +97 -0
- package/lib/browser/config.js +6 -7
- package/lib/browser/constants/numericConstants.d.ts +1 -1
- package/lib/browser/constants/numericConstants.js +1 -1
- package/lib/browser/decode/user.js +5 -1
- package/lib/browser/idl/velocity.d.ts +191 -15
- package/lib/browser/idl/velocity.json +192 -16
- package/lib/browser/orderSubscriber/OrderSubscriber.d.ts +1 -0
- package/lib/browser/orderSubscriber/OrderSubscriber.js +10 -4
- package/lib/browser/pyth/pythLazerSubscriber.js +37 -27
- package/lib/browser/types.d.ts +6 -0
- package/lib/browser/user.d.ts +20 -3
- package/lib/browser/user.js +52 -4
- package/lib/browser/velocityClient.d.ts +46 -10
- package/lib/browser/velocityClient.js +107 -35
- package/lib/node/adminClient.d.ts +52 -0
- package/lib/node/adminClient.d.ts.map +1 -1
- package/lib/node/adminClient.js +97 -0
- package/lib/node/config.d.ts.map +1 -1
- package/lib/node/config.js +6 -7
- package/lib/node/constants/numericConstants.d.ts +1 -1
- package/lib/node/constants/numericConstants.d.ts.map +1 -1
- package/lib/node/constants/numericConstants.js +1 -1
- package/lib/node/decode/user.d.ts.map +1 -1
- package/lib/node/decode/user.js +5 -1
- package/lib/node/idl/velocity.d.ts +191 -15
- package/lib/node/idl/velocity.d.ts.map +1 -1
- package/lib/node/idl/velocity.json +192 -16
- package/lib/node/orderSubscriber/OrderSubscriber.d.ts +1 -0
- package/lib/node/orderSubscriber/OrderSubscriber.d.ts.map +1 -1
- package/lib/node/orderSubscriber/OrderSubscriber.js +10 -4
- package/lib/node/pyth/pythLazerSubscriber.d.ts.map +1 -1
- package/lib/node/pyth/pythLazerSubscriber.js +37 -27
- package/lib/node/types.d.ts +6 -0
- package/lib/node/types.d.ts.map +1 -1
- package/lib/node/user.d.ts +20 -3
- package/lib/node/user.d.ts.map +1 -1
- package/lib/node/user.js +52 -4
- package/lib/node/velocityClient.d.ts +46 -10
- package/lib/node/velocityClient.d.ts.map +1 -1
- package/lib/node/velocityClient.js +107 -35
- package/package.json +7 -3
- package/.prettierignore +0 -1
- package/CHANGELOG.md +0 -132
- package/build-browser.js +0 -58
- package/bunfig.toml +0 -3
- package/esbuild-shims.js +0 -12
- package/scripts/deposit-isolated-positions.ts +0 -110
- package/scripts/find-flagged-users.ts +0 -213
- package/scripts/grpc-client-test-comparison.ts +0 -372
- package/scripts/grpc-multiuser-client-test-comparison.ts +0 -158
- package/scripts/postbuild.js +0 -95
- package/scripts/single-grpc-client-test.ts +0 -284
- package/scripts/withdraw-isolated-positions.ts +0 -174
- package/src/accounts/README_WebSocketAccountSubscriberV2.md +0 -95
- package/src/accounts/README_WebSocketProgramAccountSubscriberV2.md +0 -135
- package/src/accounts/basicUserAccountSubscriber.ts +0 -79
- package/src/accounts/basicUserStatsAccountSubscriber.ts +0 -87
- package/src/accounts/bulkAccountLoader.ts +0 -358
- package/src/accounts/bulkUserStatsSubscription.ts +0 -40
- package/src/accounts/bulkUserSubscription.ts +0 -39
- package/src/accounts/customizedCadenceBulkAccountLoader.ts +0 -250
- package/src/accounts/fetch.ts +0 -200
- package/src/accounts/grpcAccountSubscriber.ts +0 -225
- package/src/accounts/grpcInsuranceFundStakeAccountSubscriber.ts +0 -73
- package/src/accounts/grpcMultiAccountSubscriber.ts +0 -566
- package/src/accounts/grpcMultiUserAccountSubscriber.ts +0 -328
- package/src/accounts/grpcProgramAccountSubscriber.ts +0 -264
- package/src/accounts/grpcUserAccountSubscriber.ts +0 -63
- package/src/accounts/grpcUserStatsAccountSubscriber.ts +0 -65
- package/src/accounts/grpcVelocityClientAccountSubscriber.ts +0 -257
- package/src/accounts/grpcVelocityClientAccountSubscriberV2.ts +0 -941
- package/src/accounts/laserProgramAccountSubscriber.ts +0 -266
- package/src/accounts/oneShotUserAccountSubscriber.ts +0 -88
- package/src/accounts/oneShotUserStatsAccountSubscriber.ts +0 -94
- package/src/accounts/pollingInsuranceFundStakeAccountSubscriber.ts +0 -223
- package/src/accounts/pollingOracleAccountSubscriber.ts +0 -151
- package/src/accounts/pollingTokenAccountSubscriber.ts +0 -147
- package/src/accounts/pollingUserAccountSubscriber.ts +0 -198
- package/src/accounts/pollingUserStatsAccountSubscriber.ts +0 -180
- package/src/accounts/pollingVelocityClientAccountSubscriber.ts +0 -774
- package/src/accounts/testBulkAccountLoader.ts +0 -59
- package/src/accounts/types.ts +0 -428
- package/src/accounts/utils.ts +0 -90
- package/src/accounts/webSocketAccountSubscriber.ts +0 -304
- package/src/accounts/webSocketAccountSubscriberV2.ts +0 -536
- package/src/accounts/webSocketInsuranceFundStakeAccountSubscriber.ts +0 -171
- package/src/accounts/webSocketProgramAccountSubscriber.ts +0 -244
- package/src/accounts/webSocketProgramAccountSubscriberV2.ts +0 -1048
- package/src/accounts/webSocketProgramAccountsSubscriberV2.ts +0 -1042
- package/src/accounts/webSocketUserAccountSubscriber.ts +0 -139
- package/src/accounts/webSocketUserStatsAccountSubsriber.ts +0 -131
- package/src/accounts/webSocketVelocityClientAccountSubscriber.ts +0 -865
- package/src/accounts/webSocketVelocityClientAccountSubscriberV2.ts +0 -897
- package/src/accounts/websocketProgramUserAccountSubscriber.ts +0 -127
- package/src/addresses/marketAddresses.ts +0 -28
- package/src/addresses/pda.ts +0 -620
- package/src/adminClient.ts +0 -8136
- package/src/assert/assert.ts +0 -5
- package/src/auctionSubscriber/auctionSubscriber.ts +0 -86
- package/src/auctionSubscriber/auctionSubscriberGrpc.ts +0 -99
- package/src/auctionSubscriber/index.ts +0 -9
- package/src/auctionSubscriber/types.ts +0 -30
- package/src/bankrun/bankrunConnection.ts +0 -630
- package/src/blockhashSubscriber/BlockhashSubscriber.ts +0 -160
- package/src/blockhashSubscriber/index.ts +0 -6
- package/src/blockhashSubscriber/types.ts +0 -13
- package/src/clock/clockSubscriber.ts +0 -146
- package/src/config.ts +0 -312
- package/src/constants/index.ts +0 -9
- package/src/constants/numericConstants.ts +0 -194
- package/src/constants/perpMarkets.ts +0 -127
- package/src/constants/spotMarkets.ts +0 -104
- package/src/constants/txConstants.ts +0 -2
- package/src/constituentMap/constituentMap.ts +0 -305
- package/src/constituentMap/pollingConstituentAccountSubscriber.ts +0 -99
- package/src/constituentMap/webSocketConstituentAccountSubscriber.ts +0 -121
- package/src/core/VelocityCore.ts +0 -606
- package/src/core/index.ts +0 -12
- package/src/core/instructions/deposit.ts +0 -64
- package/src/core/instructions/fill.ts +0 -51
- package/src/core/instructions/funding.ts +0 -33
- package/src/core/instructions/liquidation.ts +0 -55
- package/src/core/instructions/orders.ts +0 -84
- package/src/core/instructions/perpOrders.ts +0 -312
- package/src/core/instructions/settlement.ts +0 -40
- package/src/core/instructions/trigger.ts +0 -41
- package/src/core/instructions/withdraw.ts +0 -65
- package/src/core/remainingAccounts.ts +0 -320
- package/src/core/signedMsg.ts +0 -109
- package/src/decode/customCoder.ts +0 -148
- package/src/decode/user.ts +0 -401
- package/src/dlob/DLOB.ts +0 -2793
- package/src/dlob/DLOBNode.ts +0 -305
- package/src/dlob/DLOBSubscriber.ts +0 -269
- package/src/dlob/NodeList.ts +0 -244
- package/src/dlob/orderBookLevels.ts +0 -695
- package/src/dlob/types.ts +0 -37
- package/src/events/eventList.ts +0 -114
- package/src/events/eventSubscriber.ts +0 -521
- package/src/events/eventsServerLogProvider.ts +0 -189
- package/src/events/fetchLogs.ts +0 -219
- package/src/events/parse.ts +0 -271
- package/src/events/pollingLogProvider.ts +0 -113
- package/src/events/sort.ts +0 -51
- package/src/events/txEventCache.ts +0 -92
- package/src/events/types.ts +0 -337
- package/src/events/webSocketLogProvider.ts +0 -152
- package/src/factory/bigNum.ts +0 -709
- package/src/factory/oracleClient.ts +0 -73
- package/src/idl/pyth.json +0 -142
- package/src/idl/pyth.ts +0 -97
- package/src/idl/pyth_solana_receiver.json +0 -628
- package/src/idl/token_faucet.json +0 -229
- package/src/idl/token_faucet.ts +0 -197
- package/src/idl/velocity.json +0 -23974
- package/src/idl/velocity.ts +0 -23980
- package/src/index.ts +0 -150
- package/src/indicative-quotes/indicativeQuotesSender.ts +0 -233
- package/src/isomorphic/README.md +0 -19
- package/src/isomorphic/anchor.browser.ts +0 -44
- package/src/isomorphic/anchor.node.ts +0 -1
- package/src/isomorphic/anchor.ts +0 -1
- package/src/isomorphic/anchor29.browser.ts +0 -24
- package/src/isomorphic/anchor29.node.ts +0 -1
- package/src/isomorphic/anchor29.ts +0 -1
- package/src/isomorphic/grpc.browser.ts +0 -4
- package/src/isomorphic/grpc.node.ts +0 -130
- package/src/isomorphic/grpc.ts +0 -1
- package/src/jupiter/jupiterClient.ts +0 -502
- package/src/keypair.ts +0 -32
- package/src/margin/README.md +0 -138
- package/src/marginCalculation.ts +0 -407
- package/src/marinade/idl/idl.json +0 -1962
- package/src/marinade/index.ts +0 -73
- package/src/marinade/types.ts +0 -3925
- package/src/math/amm.ts +0 -1758
- package/src/math/auction.ts +0 -480
- package/src/math/bankruptcy.ts +0 -138
- package/src/math/builder.ts +0 -130
- package/src/math/conversion.ts +0 -45
- package/src/math/exchangeStatus.ts +0 -261
- package/src/math/funding.ts +0 -498
- package/src/math/insurance.ts +0 -171
- package/src/math/liquidation.ts +0 -433
- package/src/math/margin.ts +0 -327
- package/src/math/market.ts +0 -487
- package/src/math/oracles.ts +0 -477
- package/src/math/orders.ts +0 -500
- package/src/math/position.ts +0 -381
- package/src/math/repeg.ts +0 -223
- package/src/math/spotBalance.ts +0 -996
- package/src/math/spotMarket.ts +0 -115
- package/src/math/spotPosition.ts +0 -263
- package/src/math/state.ts +0 -71
- package/src/math/superStake.ts +0 -602
- package/src/math/tiers.ts +0 -73
- package/src/math/trade.ts +0 -879
- package/src/math/utils.ts +0 -183
- package/src/memcmp.ts +0 -279
- package/src/oracles/oracleClientCache.ts +0 -41
- package/src/oracles/oracleId.ts +0 -99
- package/src/oracles/prelaunchOracleClient.ts +0 -63
- package/src/oracles/pythClient.ts +0 -125
- package/src/oracles/pythLazerClient.ts +0 -141
- package/src/oracles/quoteAssetOracleClient.ts +0 -43
- package/src/oracles/strictOraclePrice.ts +0 -40
- package/src/oracles/types.ts +0 -82
- package/src/oracles/utils.ts +0 -45
- package/src/orderParams.ts +0 -117
- package/src/orderSubscriber/OrderSubscriber.ts +0 -378
- package/src/orderSubscriber/PollingSubscription.ts +0 -50
- package/src/orderSubscriber/WebsocketSubscription.ts +0 -137
- package/src/orderSubscriber/grpcSubscription.ts +0 -155
- package/src/orderSubscriber/index.ts +0 -7
- package/src/orderSubscriber/types.ts +0 -64
- package/src/priorityFee/averageOverSlotsStrategy.ts +0 -17
- package/src/priorityFee/averageStrategy.ts +0 -13
- package/src/priorityFee/ewmaStrategy.ts +0 -51
- package/src/priorityFee/heliusPriorityFeeMethod.ts +0 -68
- package/src/priorityFee/index.ts +0 -16
- package/src/priorityFee/maxOverSlotsStrategy.ts +0 -18
- package/src/priorityFee/maxStrategy.ts +0 -8
- package/src/priorityFee/priorityFeeSubscriber.ts +0 -328
- package/src/priorityFee/priorityFeeSubscriberMap.ts +0 -134
- package/src/priorityFee/solanaPriorityFeeMethod.ts +0 -46
- package/src/priorityFee/types.ts +0 -82
- package/src/priorityFee/velocityPriorityFeeMethod.ts +0 -53
- package/src/pyth/constants.ts +0 -9
- package/src/pyth/index.ts +0 -15
- package/src/pyth/pythLazerSubscriber.ts +0 -365
- package/src/pyth/types.ts +0 -4451
- package/src/pyth/utils.ts +0 -13
- package/src/slot/SlotSubscriber.ts +0 -126
- package/src/slot/SlothashSubscriber.ts +0 -163
- package/src/swap/UnifiedSwapClient.ts +0 -315
- package/src/swift/grpcSignedMsgUserAccountSubscriber.ts +0 -81
- package/src/swift/index.ts +0 -10
- package/src/swift/signedMsgUserAccountSubscriber.ts +0 -251
- package/src/swift/swiftOrderSubscriber.ts +0 -351
- package/src/testClient.ts +0 -42
- package/src/titan/titanClient.ts +0 -438
- package/src/token/index.ts +0 -13
- package/src/tokenFaucet.ts +0 -296
- package/src/tx/baseTxSender.ts +0 -651
- package/src/tx/blockhashFetcher/baseBlockhashFetcher.ts +0 -31
- package/src/tx/blockhashFetcher/cachedBlockhashFetcher.ts +0 -105
- package/src/tx/blockhashFetcher/types.ts +0 -9
- package/src/tx/fastSingleTxSender.ts +0 -200
- package/src/tx/forwardOnlyTxSender.ts +0 -193
- package/src/tx/priorityFeeCalculator.ts +0 -117
- package/src/tx/reportTransactionError.ts +0 -176
- package/src/tx/retryTxSender.ts +0 -177
- package/src/tx/txHandler.ts +0 -1009
- package/src/tx/txParamProcessor.ts +0 -225
- package/src/tx/types.ts +0 -117
- package/src/tx/utils.ts +0 -133
- package/src/tx/whileValidTxSender.ts +0 -377
- package/src/types.ts +0 -2575
- package/src/user.ts +0 -5316
- package/src/userConfig.ts +0 -38
- package/src/userMap/PollingSubscription.ts +0 -61
- package/src/userMap/WebsocketSubscription.ts +0 -93
- package/src/userMap/grpcSubscription.ts +0 -93
- package/src/userMap/referrerMap.ts +0 -360
- package/src/userMap/revenueShareEscrowMap.ts +0 -342
- package/src/userMap/userMap.ts +0 -784
- package/src/userMap/userMapConfig.ts +0 -82
- package/src/userMap/userStatsMap.ts +0 -393
- package/src/userName.ts +0 -37
- package/src/userStats.ts +0 -159
- package/src/userStatsConfig.ts +0 -35
- package/src/util/TransactionConfirmationManager.ts +0 -333
- package/src/util/chainClock.ts +0 -65
- package/src/util/computeUnits.ts +0 -101
- package/src/util/digest.ts +0 -33
- package/src/util/ed25519Utils.ts +0 -95
- package/src/util/promiseTimeout.ts +0 -23
- package/src/velocityClient.ts +0 -14802
- package/src/velocityClientConfig.ts +0 -119
- package/src/wallet.ts +0 -91
- package/tests/VelocityCore/builder_escrow.test.ts +0 -121
- package/tests/VelocityCore/decode.test.ts +0 -16
- package/tests/VelocityCore/fill_trigger.test.ts +0 -73
- package/tests/VelocityCore/instructions.test.ts +0 -46
- package/tests/VelocityCore/pdas.test.ts +0 -30
- package/tests/VelocityCore/perp_orders.test.ts +0 -205
- package/tests/VelocityCore/remainingAccounts.test.ts +0 -72
- package/tests/VelocityCore/settlement_liquidation.test.ts +0 -69
- package/tests/accounts/customizedCadenceBulkAccountLoader.test.ts +0 -211
- package/tests/amm/test.ts +0 -2402
- package/tests/auctions/test.ts +0 -81
- package/tests/bn/test.ts +0 -355
- package/tests/builder/builderFee.test.ts +0 -42
- package/tests/ci/verifyConstants.ts +0 -393
- package/tests/decode/test.ts +0 -262
- package/tests/decode/userAccountBufferStrings.ts +0 -102
- package/tests/dlob/helpers.ts +0 -748
- package/tests/dlob/test.ts +0 -6969
- package/tests/dlob/tickSizeStandardization.ts +0 -545
- package/tests/events/parseLogsForCuUsage.ts +0 -139
- package/tests/exchangeStatus/test.ts +0 -45
- package/tests/insurance/test.ts +0 -40
- package/tests/liquidation/test.ts +0 -125
- package/tests/oracles/mmOracleGate.test.ts +0 -379
- package/tests/oracles/pythPegSnap.test.ts +0 -76
- package/tests/sdkParity/enumParity.test.ts +0 -84
- package/tests/sdkParity/marginCategoryFill.test.ts +0 -143
- package/tests/sdkParity/memcmpOffsets.test.ts +0 -139
- package/tests/spot/test.ts +0 -281
- package/tests/tx/TransactionConfirmationManager.test.ts +0 -312
- package/tests/tx/cachedBlockhashFetcher.test.ts +0 -96
- package/tests/tx/priorityFeeCalculator.ts +0 -77
- package/tests/tx/priorityFeeStrategy.ts +0 -95
- package/tests/user/bankruptcy.ts +0 -165
- package/tests/user/feeAndWithdrawLimits.ts +0 -284
- package/tests/user/getMarginCalculation.ts +0 -586
- package/tests/user/helpers.ts +0 -184
- package/tests/user/liquidations.ts +0 -129
- package/tests/user/marginCalculations.test.ts +0 -321
- package/tests/user/test.ts +0 -833
- package/tsconfig.browser.json +0 -18
- package/tsconfig.json +0 -36
|
@@ -1,586 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
BN,
|
|
3
|
-
ZERO,
|
|
4
|
-
User,
|
|
5
|
-
PublicKey,
|
|
6
|
-
BASE_PRECISION,
|
|
7
|
-
QUOTE_PRECISION,
|
|
8
|
-
PRICE_PRECISION,
|
|
9
|
-
MARGIN_PRECISION,
|
|
10
|
-
SPOT_MARKET_BALANCE_PRECISION,
|
|
11
|
-
SpotBalanceType,
|
|
12
|
-
OPEN_ORDER_MARGIN_REQUIREMENT,
|
|
13
|
-
SPOT_MARKET_WEIGHT_PRECISION,
|
|
14
|
-
MAX_POSITIVE_UPNL_FOR_INITIAL_MARGIN,
|
|
15
|
-
PositionFlag,
|
|
16
|
-
ContractTier,
|
|
17
|
-
UserStatus,
|
|
18
|
-
} from '../../src';
|
|
19
|
-
import { mockPerpMarkets, mockSpotMarkets } from '../dlob/helpers';
|
|
20
|
-
import { assert } from '../../src/assert/assert';
|
|
21
|
-
import {
|
|
22
|
-
mockUserAccount as baseMockUserAccount,
|
|
23
|
-
makeMockUser,
|
|
24
|
-
} from './helpers';
|
|
25
|
-
import * as _ from 'lodash';
|
|
26
|
-
|
|
27
|
-
describe('getMarginCalculation snapshot', () => {
|
|
28
|
-
it('empty account returns zeroed snapshot', async () => {
|
|
29
|
-
const myMockPerpMarkets = _.cloneDeep(mockPerpMarkets);
|
|
30
|
-
const myMockSpotMarkets = _.cloneDeep(mockSpotMarkets);
|
|
31
|
-
const myMockUserAccount = _.cloneDeep(baseMockUserAccount);
|
|
32
|
-
|
|
33
|
-
const user: User = await makeMockUser(
|
|
34
|
-
myMockPerpMarkets,
|
|
35
|
-
myMockSpotMarkets,
|
|
36
|
-
myMockUserAccount,
|
|
37
|
-
[1, 1, 1, 1, 1, 1, 1, 1],
|
|
38
|
-
[1, 1, 1, 1, 1, 1, 1, 1]
|
|
39
|
-
);
|
|
40
|
-
|
|
41
|
-
const calc = user.getMarginCalculation('Initial');
|
|
42
|
-
assert(calc.totalCollateral.eq(ZERO));
|
|
43
|
-
assert(calc.marginRequirement.eq(ZERO));
|
|
44
|
-
});
|
|
45
|
-
|
|
46
|
-
it('quote deposit increases totalCollateral, no requirement', async () => {
|
|
47
|
-
const myMockPerpMarkets = _.cloneDeep(mockPerpMarkets);
|
|
48
|
-
const myMockSpotMarkets = _.cloneDeep(mockSpotMarkets);
|
|
49
|
-
const myMockUserAccount = _.cloneDeep(baseMockUserAccount);
|
|
50
|
-
|
|
51
|
-
myMockUserAccount.spotPositions[0].balanceType = SpotBalanceType.DEPOSIT;
|
|
52
|
-
myMockUserAccount.spotPositions[0].scaledBalance = new BN(
|
|
53
|
-
10000 * SPOT_MARKET_BALANCE_PRECISION.toNumber()
|
|
54
|
-
);
|
|
55
|
-
|
|
56
|
-
const user: User = await makeMockUser(
|
|
57
|
-
myMockPerpMarkets,
|
|
58
|
-
myMockSpotMarkets,
|
|
59
|
-
myMockUserAccount,
|
|
60
|
-
[1, 1, 1, 1, 1, 1, 1, 1],
|
|
61
|
-
[1, 1, 1, 1, 1, 1, 1, 1]
|
|
62
|
-
);
|
|
63
|
-
|
|
64
|
-
const calc = user.getMarginCalculation('Initial');
|
|
65
|
-
const expected = new BN('10000000000'); // $10k
|
|
66
|
-
assert(calc.totalCollateral.eq(expected));
|
|
67
|
-
assert(calc.marginRequirement.eq(ZERO));
|
|
68
|
-
});
|
|
69
|
-
|
|
70
|
-
it('quote borrow increases requirement and buffer applies', async () => {
|
|
71
|
-
const myMockPerpMarkets = _.cloneDeep(mockPerpMarkets);
|
|
72
|
-
const myMockSpotMarkets = _.cloneDeep(mockSpotMarkets);
|
|
73
|
-
const myMockUserAccount = _.cloneDeep(baseMockUserAccount);
|
|
74
|
-
|
|
75
|
-
// Borrow 100 quote
|
|
76
|
-
myMockUserAccount.spotPositions[0].balanceType = SpotBalanceType.BORROW;
|
|
77
|
-
myMockUserAccount.spotPositions[0].scaledBalance = new BN(
|
|
78
|
-
100 * SPOT_MARKET_BALANCE_PRECISION.toNumber()
|
|
79
|
-
);
|
|
80
|
-
|
|
81
|
-
const user: User = await makeMockUser(
|
|
82
|
-
myMockPerpMarkets,
|
|
83
|
-
myMockSpotMarkets,
|
|
84
|
-
myMockUserAccount,
|
|
85
|
-
[1, 1, 1, 1, 1, 1, 1, 1],
|
|
86
|
-
[1, 1, 1, 1, 1, 1, 1, 1]
|
|
87
|
-
);
|
|
88
|
-
|
|
89
|
-
const tenPercent = new BN(1000);
|
|
90
|
-
const calc = user.getMarginCalculation('Initial', {
|
|
91
|
-
liquidationBufferMap: new Map([['cross', tenPercent]]),
|
|
92
|
-
});
|
|
93
|
-
// mirrors margin.rs: a quote borrow enters the requirement at its raw strict
|
|
94
|
-
// token value; the cross buffer only appears in marginRequirementPlusBuffer
|
|
95
|
-
const liability = new BN(100).mul(QUOTE_PRECISION); // $100
|
|
96
|
-
assert(calc.totalCollateral.eq(ZERO));
|
|
97
|
-
assert(
|
|
98
|
-
calc.marginRequirement.eq(liability),
|
|
99
|
-
`margin requirement does not equal liability: ${calc.marginRequirement.toString()} != ${liability.toString()}`
|
|
100
|
-
);
|
|
101
|
-
assert(
|
|
102
|
-
calc.marginRequirementPlusBuffer.eq(
|
|
103
|
-
liability.div(new BN(10)).add(calc.marginRequirement) // 10% of liability + margin requirement
|
|
104
|
-
),
|
|
105
|
-
`margin requirement plus buffer does not equal 10% of liability + margin requirement: ${calc.marginRequirementPlusBuffer.toString()} != ${liability
|
|
106
|
-
.div(new BN(10))
|
|
107
|
-
.add(calc.marginRequirement)
|
|
108
|
-
.toString()}`
|
|
109
|
-
);
|
|
110
|
-
});
|
|
111
|
-
|
|
112
|
-
it('non-quote spot open orders add IM', async () => {
|
|
113
|
-
const myMockPerpMarkets = _.cloneDeep(mockPerpMarkets);
|
|
114
|
-
const myMockSpotMarkets = _.cloneDeep(mockSpotMarkets);
|
|
115
|
-
const myMockUserAccount = _.cloneDeep(baseMockUserAccount);
|
|
116
|
-
|
|
117
|
-
// Market 1 (e.g., SOL) with 2 open orders
|
|
118
|
-
myMockUserAccount.spotPositions[1].marketIndex = 1;
|
|
119
|
-
myMockUserAccount.spotPositions[1].openOrders = 2;
|
|
120
|
-
|
|
121
|
-
const user: User = await makeMockUser(
|
|
122
|
-
myMockPerpMarkets,
|
|
123
|
-
myMockSpotMarkets,
|
|
124
|
-
myMockUserAccount,
|
|
125
|
-
[1, 1, 1, 1, 1, 1, 1, 1],
|
|
126
|
-
[1, 1, 1, 1, 1, 1, 1, 1]
|
|
127
|
-
);
|
|
128
|
-
|
|
129
|
-
const calc = user.getMarginCalculation('Initial');
|
|
130
|
-
const expectedIM = new BN(2).mul(OPEN_ORDER_MARGIN_REQUIREMENT);
|
|
131
|
-
assert(calc.marginRequirement.eq(expectedIM));
|
|
132
|
-
});
|
|
133
|
-
|
|
134
|
-
it('perp long liability reflects maintenance requirement', async () => {
|
|
135
|
-
const myMockPerpMarkets = _.cloneDeep(mockPerpMarkets);
|
|
136
|
-
const myMockSpotMarkets = _.cloneDeep(mockSpotMarkets);
|
|
137
|
-
const myMockUserAccount = _.cloneDeep(baseMockUserAccount);
|
|
138
|
-
|
|
139
|
-
// 20 base long, -$10 quote (liability)
|
|
140
|
-
myMockUserAccount.perpPositions[0].baseAssetAmount = new BN(20).mul(
|
|
141
|
-
BASE_PRECISION
|
|
142
|
-
);
|
|
143
|
-
|
|
144
|
-
const user: User = await makeMockUser(
|
|
145
|
-
myMockPerpMarkets,
|
|
146
|
-
myMockSpotMarkets,
|
|
147
|
-
myMockUserAccount,
|
|
148
|
-
[1, 1, 1, 1, 1, 1, 1, 1],
|
|
149
|
-
[1, 1, 1, 1, 1, 1, 1, 1]
|
|
150
|
-
);
|
|
151
|
-
|
|
152
|
-
const calc = user.getMarginCalculation('Maintenance');
|
|
153
|
-
// From existing liquidation test expectations: 2_000_000
|
|
154
|
-
assert(calc.marginRequirement.eq(new BN('2000000')));
|
|
155
|
-
});
|
|
156
|
-
|
|
157
|
-
it('collateral equals maintenance requirement', async () => {
|
|
158
|
-
const myMockPerpMarkets = _.cloneDeep(mockPerpMarkets);
|
|
159
|
-
const myMockSpotMarkets = _.cloneDeep(mockSpotMarkets);
|
|
160
|
-
const myMockUserAccount = _.cloneDeep(baseMockUserAccount);
|
|
161
|
-
|
|
162
|
-
myMockUserAccount.perpPositions[0].baseAssetAmount = new BN(200000000).mul(
|
|
163
|
-
BASE_PRECISION
|
|
164
|
-
);
|
|
165
|
-
|
|
166
|
-
myMockUserAccount.spotPositions[0].balanceType = SpotBalanceType.DEPOSIT;
|
|
167
|
-
myMockUserAccount.spotPositions[0].scaledBalance = new BN(20000000).mul(
|
|
168
|
-
SPOT_MARKET_BALANCE_PRECISION
|
|
169
|
-
);
|
|
170
|
-
|
|
171
|
-
const user: User = await makeMockUser(
|
|
172
|
-
myMockPerpMarkets,
|
|
173
|
-
myMockSpotMarkets,
|
|
174
|
-
myMockUserAccount,
|
|
175
|
-
[1, 1, 1, 1, 1, 1, 1, 1],
|
|
176
|
-
[1, 1, 1, 1, 1, 1, 1, 1]
|
|
177
|
-
);
|
|
178
|
-
|
|
179
|
-
const calc = user.getMarginCalculation('Maintenance');
|
|
180
|
-
assert(
|
|
181
|
-
calc.marginRequirement.eq(calc.totalCollateral),
|
|
182
|
-
`margin requirement does not equal total collateral: ${calc.marginRequirement.toString()} != ${calc.totalCollateral.toString()}`
|
|
183
|
-
);
|
|
184
|
-
});
|
|
185
|
-
|
|
186
|
-
it('maker reducing after simulated fill: collateral equals maintenance requirement', async () => {
|
|
187
|
-
const myMockPerpMarkets = _.cloneDeep(mockPerpMarkets);
|
|
188
|
-
const myMockSpotMarkets = _.cloneDeep(mockSpotMarkets);
|
|
189
|
-
|
|
190
|
-
// Build maker and taker accounts
|
|
191
|
-
const makerAccount = _.cloneDeep(baseMockUserAccount);
|
|
192
|
-
const takerAccount = _.cloneDeep(baseMockUserAccount);
|
|
193
|
-
|
|
194
|
-
// Oracle price = 1 for perp and spot
|
|
195
|
-
const perpOracles = [1, 1, 1, 1, 1, 1, 1, 1];
|
|
196
|
-
const spotOracles = [1, 1, 1, 1, 1, 1, 1, 1];
|
|
197
|
-
|
|
198
|
-
// Pre-fill: maker has 21 base long at entry 1 ($21 notional), taker flat
|
|
199
|
-
makerAccount.perpPositions[0].baseAssetAmount = new BN(21).mul(
|
|
200
|
-
BASE_PRECISION
|
|
201
|
-
);
|
|
202
|
-
makerAccount.perpPositions[0].quoteEntryAmount = new BN(-21).mul(
|
|
203
|
-
QUOTE_PRECISION
|
|
204
|
-
);
|
|
205
|
-
makerAccount.perpPositions[0].quoteBreakEvenAmount = new BN(-21).mul(
|
|
206
|
-
QUOTE_PRECISION
|
|
207
|
-
);
|
|
208
|
-
// Provide exactly $2 in quote collateral to equal 10% maintenance of 20 notional post-fill
|
|
209
|
-
makerAccount.spotPositions[0].balanceType = SpotBalanceType.DEPOSIT;
|
|
210
|
-
makerAccount.spotPositions[0].scaledBalance = new BN(2).mul(
|
|
211
|
-
SPOT_MARKET_BALANCE_PRECISION
|
|
212
|
-
);
|
|
213
|
-
|
|
214
|
-
// Simulate fill: maker sells 1 base to taker at price = oracle = 1
|
|
215
|
-
// Post-fill maker position: 20 base long with zero unrealized PnL
|
|
216
|
-
const maker: User = await makeMockUser(
|
|
217
|
-
myMockPerpMarkets,
|
|
218
|
-
myMockSpotMarkets,
|
|
219
|
-
makerAccount,
|
|
220
|
-
perpOracles,
|
|
221
|
-
spotOracles
|
|
222
|
-
);
|
|
223
|
-
const taker: User = await makeMockUser(
|
|
224
|
-
myMockPerpMarkets,
|
|
225
|
-
myMockSpotMarkets,
|
|
226
|
-
takerAccount,
|
|
227
|
-
perpOracles,
|
|
228
|
-
spotOracles
|
|
229
|
-
);
|
|
230
|
-
|
|
231
|
-
// Apply synthetic trade deltas to both user accounts
|
|
232
|
-
// Maker: base 21 -> 20; taker: base 0 -> 1. Use quote deltas consistent with price 1, fee 0
|
|
233
|
-
maker.getUserAccount().perpPositions[0].baseAssetAmount = new BN(20).mul(
|
|
234
|
-
BASE_PRECISION
|
|
235
|
-
);
|
|
236
|
-
maker.getUserAccount().perpPositions[0].quoteEntryAmount = new BN(-20).mul(
|
|
237
|
-
QUOTE_PRECISION
|
|
238
|
-
);
|
|
239
|
-
maker.getUserAccount().perpPositions[0].quoteBreakEvenAmount = new BN(
|
|
240
|
-
-20
|
|
241
|
-
).mul(QUOTE_PRECISION);
|
|
242
|
-
// Align quoteAssetAmount with base value so unrealized PnL = 0 at price 1
|
|
243
|
-
maker.getUserAccount().perpPositions[0].quoteAssetAmount = new BN(-20).mul(
|
|
244
|
-
QUOTE_PRECISION
|
|
245
|
-
);
|
|
246
|
-
|
|
247
|
-
taker.getUserAccount().perpPositions[0].baseAssetAmount = new BN(1).mul(
|
|
248
|
-
BASE_PRECISION
|
|
249
|
-
);
|
|
250
|
-
taker.getUserAccount().perpPositions[0].quoteEntryAmount = new BN(-1).mul(
|
|
251
|
-
QUOTE_PRECISION
|
|
252
|
-
);
|
|
253
|
-
taker.getUserAccount().perpPositions[0].quoteBreakEvenAmount = new BN(
|
|
254
|
-
-1
|
|
255
|
-
).mul(QUOTE_PRECISION);
|
|
256
|
-
// Also set taker's quoteAssetAmount consistently
|
|
257
|
-
taker.getUserAccount().perpPositions[0].quoteAssetAmount = new BN(-1).mul(
|
|
258
|
-
QUOTE_PRECISION
|
|
259
|
-
);
|
|
260
|
-
|
|
261
|
-
const makerCalc = maker.getMarginCalculation('Maintenance');
|
|
262
|
-
assert(makerCalc.marginRequirement.eq(makerCalc.totalCollateral));
|
|
263
|
-
assert(makerCalc.marginRequirement.gt(ZERO));
|
|
264
|
-
});
|
|
265
|
-
|
|
266
|
-
it('isolated position margin requirement (SDK parity)', async () => {
|
|
267
|
-
const myMockPerpMarkets = _.cloneDeep(mockPerpMarkets);
|
|
268
|
-
const myMockSpotMarkets = _.cloneDeep(mockSpotMarkets);
|
|
269
|
-
myMockSpotMarkets[0].oracle = new PublicKey(2);
|
|
270
|
-
myMockSpotMarkets[1].oracle = new PublicKey(5);
|
|
271
|
-
myMockPerpMarkets[0].oracle = new PublicKey(5);
|
|
272
|
-
|
|
273
|
-
// Configure perp market 0 ratios to match on-chain test
|
|
274
|
-
myMockPerpMarkets[0].marginRatioInitial = 1000; // 10%
|
|
275
|
-
myMockPerpMarkets[0].marginRatioMaintenance = 500; // 5%
|
|
276
|
-
|
|
277
|
-
// Configure spot market 1 (e.g., SOL) weights to match on-chain test
|
|
278
|
-
myMockSpotMarkets[1].initialAssetWeight =
|
|
279
|
-
(SPOT_MARKET_WEIGHT_PRECISION.toNumber() * 8) / 10; // 0.8
|
|
280
|
-
myMockSpotMarkets[1].maintenanceAssetWeight =
|
|
281
|
-
(SPOT_MARKET_WEIGHT_PRECISION.toNumber() * 9) / 10; // 0.9
|
|
282
|
-
myMockSpotMarkets[1].initialLiabilityWeight =
|
|
283
|
-
(SPOT_MARKET_WEIGHT_PRECISION.toNumber() * 12) / 10; // 1.2
|
|
284
|
-
myMockSpotMarkets[1].maintenanceLiabilityWeight =
|
|
285
|
-
(SPOT_MARKET_WEIGHT_PRECISION.toNumber() * 11) / 10; // 1.1
|
|
286
|
-
|
|
287
|
-
// ---------- Cross margin only (spot positions) ----------
|
|
288
|
-
const crossAccount = _.cloneDeep(baseMockUserAccount);
|
|
289
|
-
// USDC deposit: $20,000
|
|
290
|
-
crossAccount.spotPositions[0].marketIndex = 0;
|
|
291
|
-
crossAccount.spotPositions[0].balanceType = SpotBalanceType.DEPOSIT;
|
|
292
|
-
crossAccount.spotPositions[0].scaledBalance = new BN(20000).mul(
|
|
293
|
-
SPOT_MARKET_BALANCE_PRECISION
|
|
294
|
-
);
|
|
295
|
-
// SOL borrow: 100 units
|
|
296
|
-
crossAccount.spotPositions[1].marketIndex = 1;
|
|
297
|
-
crossAccount.spotPositions[1].balanceType = SpotBalanceType.BORROW;
|
|
298
|
-
crossAccount.spotPositions[1].scaledBalance = new BN(100).mul(
|
|
299
|
-
SPOT_MARKET_BALANCE_PRECISION
|
|
300
|
-
);
|
|
301
|
-
// No perp exposure in cross calc
|
|
302
|
-
crossAccount.perpPositions[0].baseAssetAmount = new BN(
|
|
303
|
-
100 * BASE_PRECISION.toNumber()
|
|
304
|
-
);
|
|
305
|
-
crossAccount.perpPositions[0].quoteAssetAmount = new BN(
|
|
306
|
-
-11000 * QUOTE_PRECISION.toNumber()
|
|
307
|
-
);
|
|
308
|
-
crossAccount.perpPositions[0].positionFlag = PositionFlag.IsolatedPosition;
|
|
309
|
-
crossAccount.perpPositions[0].isolatedPositionScaledBalance = new BN(
|
|
310
|
-
100
|
|
311
|
-
).mul(SPOT_MARKET_BALANCE_PRECISION);
|
|
312
|
-
|
|
313
|
-
const userCross: User = await makeMockUser(
|
|
314
|
-
myMockPerpMarkets,
|
|
315
|
-
myMockSpotMarkets,
|
|
316
|
-
crossAccount,
|
|
317
|
-
[100, 1, 1, 1, 1, 1, 1, 1], // perp oracle for market 0 = 100
|
|
318
|
-
[1, 100, 1, 1, 1, 1, 1, 1] // spot oracle: usdc=1, sol=100
|
|
319
|
-
);
|
|
320
|
-
|
|
321
|
-
const crossCalc = userCross.getMarginCalculation('Initial');
|
|
322
|
-
const isolatedMarginCalc = crossCalc.isolatedMarginCalculations.get(0);
|
|
323
|
-
// Expect: cross MR from SOL borrow: 100 * $100 = $10,000 * 1.2 = $12,000
|
|
324
|
-
assert(crossCalc.marginRequirement.eq(new BN('12000000000')));
|
|
325
|
-
// Expect: cross total collateral from USDC deposit only = $20,000
|
|
326
|
-
assert(crossCalc.totalCollateral.eq(new BN('20000000000')));
|
|
327
|
-
// Meets cross margin requirement
|
|
328
|
-
assert(crossCalc.marginRequirement.lte(crossCalc.totalCollateral));
|
|
329
|
-
|
|
330
|
-
assert(isolatedMarginCalc?.marginRequirement.eq(new BN('1000000000')));
|
|
331
|
-
assert(isolatedMarginCalc?.totalCollateral.eq(new BN('-900000000')));
|
|
332
|
-
// With 10% buffer
|
|
333
|
-
const tenPct = new BN(1000);
|
|
334
|
-
const crossCalcBuf = userCross.getMarginCalculation('Initial', {
|
|
335
|
-
liquidationBufferMap: new Map<number | 'cross', BN>([
|
|
336
|
-
['cross', tenPct],
|
|
337
|
-
[0, new BN(100)],
|
|
338
|
-
]),
|
|
339
|
-
});
|
|
340
|
-
assert(
|
|
341
|
-
crossCalcBuf.marginRequirementPlusBuffer.eq(new BN('14300000000')),
|
|
342
|
-
`margin requirement plus buffer does not equal 110% of liability + margin requirement: ${crossCalcBuf.marginRequirementPlusBuffer.toString()} != ${new BN(
|
|
343
|
-
'14300000000'
|
|
344
|
-
).toString()}`
|
|
345
|
-
); // replicate 10% buffer
|
|
346
|
-
const crossTotalPlusBuffer = crossCalcBuf.totalCollateral.add(
|
|
347
|
-
crossCalcBuf.totalCollateralBuffer
|
|
348
|
-
);
|
|
349
|
-
assert(crossTotalPlusBuffer.eq(new BN('20000000000')));
|
|
350
|
-
|
|
351
|
-
const isoPositionBuf = crossCalcBuf.isolatedMarginCalculations.get(0);
|
|
352
|
-
assert(
|
|
353
|
-
isoPositionBuf?.marginRequirementPlusBuffer.eq(new BN('1100000000')),
|
|
354
|
-
`margin requirement plus buffer does not equal 10% of liability + margin requirement: ${isoPositionBuf?.marginRequirementPlusBuffer.toString()} != ${new BN(
|
|
355
|
-
'1100000000'
|
|
356
|
-
).toString()}`
|
|
357
|
-
);
|
|
358
|
-
assert(isoPositionBuf?.marginRequirement.eq(new BN('1000000000')));
|
|
359
|
-
assert(
|
|
360
|
-
isoPositionBuf?.totalCollateralBuffer
|
|
361
|
-
.add(isoPositionBuf?.totalCollateral)
|
|
362
|
-
.eq(new BN('-910000000')),
|
|
363
|
-
`total collateral buffer plus total collateral does not equal -$9100: ${isoPositionBuf?.totalCollateralBuffer
|
|
364
|
-
.add(isoPositionBuf?.totalCollateral)
|
|
365
|
-
.toString()} != ${new BN('-900000000').toString()}`
|
|
366
|
-
);
|
|
367
|
-
});
|
|
368
|
-
|
|
369
|
-
it('positive unrealized pnl above $100 is capped under Initial but not Maintenance', async () => {
|
|
370
|
-
const myMockPerpMarkets = _.cloneDeep(mockPerpMarkets);
|
|
371
|
-
const myMockSpotMarkets = _.cloneDeep(mockSpotMarkets);
|
|
372
|
-
const myMockUserAccount = _.cloneDeep(baseMockUserAccount);
|
|
373
|
-
|
|
374
|
-
// distinct oracle per market: all mock markets otherwise share the
|
|
375
|
-
// default pubkey, which would collapse their prices onto one entry
|
|
376
|
-
myMockPerpMarkets[0].oracle = new PublicKey(7);
|
|
377
|
-
|
|
378
|
-
// weight uPnL at 100% for both categories so only the Initial-margin
|
|
379
|
-
// $100 cap (not the market's asset-weight config) drives the difference
|
|
380
|
-
myMockPerpMarkets[0].unrealizedPnlInitialAssetWeight =
|
|
381
|
-
SPOT_MARKET_WEIGHT_PRECISION.toNumber();
|
|
382
|
-
myMockPerpMarkets[0].unrealizedPnlMaintenanceAssetWeight =
|
|
383
|
-
SPOT_MARKET_WEIGHT_PRECISION.toNumber();
|
|
384
|
-
|
|
385
|
-
// 10 base long @ $100 oracle = $1000 notional, entered at $750 -> $250 uPnL
|
|
386
|
-
myMockUserAccount.perpPositions[0].baseAssetAmount = new BN(10).mul(
|
|
387
|
-
BASE_PRECISION
|
|
388
|
-
);
|
|
389
|
-
myMockUserAccount.perpPositions[0].quoteAssetAmount = new BN(750)
|
|
390
|
-
.neg()
|
|
391
|
-
.mul(QUOTE_PRECISION);
|
|
392
|
-
|
|
393
|
-
const user: User = await makeMockUser(
|
|
394
|
-
myMockPerpMarkets,
|
|
395
|
-
myMockSpotMarkets,
|
|
396
|
-
myMockUserAccount,
|
|
397
|
-
[100, 1, 1, 1, 1, 1, 1, 1],
|
|
398
|
-
[1, 1, 1, 1, 1, 1, 1, 1]
|
|
399
|
-
);
|
|
400
|
-
|
|
401
|
-
const initialCalc = user.getMarginCalculation('Initial');
|
|
402
|
-
assert(
|
|
403
|
-
initialCalc.totalCollateral.eq(MAX_POSITIVE_UPNL_FOR_INITIAL_MARGIN),
|
|
404
|
-
`initial total collateral not capped at $100: ${initialCalc.totalCollateral.toString()}`
|
|
405
|
-
);
|
|
406
|
-
|
|
407
|
-
const maintenanceCalc = user.getMarginCalculation('Maintenance');
|
|
408
|
-
assert(
|
|
409
|
-
maintenanceCalc.totalCollateral.eq(new BN(250).mul(QUOTE_PRECISION)),
|
|
410
|
-
`maintenance total collateral should be the full $250 uPnL: ${maintenanceCalc.totalCollateral.toString()}`
|
|
411
|
-
);
|
|
412
|
-
});
|
|
413
|
-
|
|
414
|
-
it('strict quote price (non-1.0) scales isolated worst-case liability buffer', async () => {
|
|
415
|
-
const myMockPerpMarkets = _.cloneDeep(mockPerpMarkets);
|
|
416
|
-
const myMockSpotMarkets = _.cloneDeep(mockSpotMarkets);
|
|
417
|
-
const myMockUserAccount = _.cloneDeep(baseMockUserAccount);
|
|
418
|
-
|
|
419
|
-
// distinct oracle per market: all mock markets otherwise share the
|
|
420
|
-
// default pubkey, which would collapse their prices onto one entry
|
|
421
|
-
myMockPerpMarkets[0].oracle = new PublicKey(7);
|
|
422
|
-
|
|
423
|
-
// quote market trades at $1 currently but its 5min twap is $1.10; as a
|
|
424
|
-
// liability, worst-case value must use the larger of the two
|
|
425
|
-
myMockSpotMarkets[0].historicalOracleData.lastOraclePriceTwap5Min = new BN(
|
|
426
|
-
1.1 * PRICE_PRECISION.toNumber()
|
|
427
|
-
);
|
|
428
|
-
|
|
429
|
-
// isolated short of 10 base @ $100 oracle = $1000 worst-case liability,
|
|
430
|
-
// entered flat (zero uPnL) so only the liability-side conversion matters
|
|
431
|
-
myMockUserAccount.perpPositions[0].positionFlag =
|
|
432
|
-
PositionFlag.IsolatedPosition;
|
|
433
|
-
myMockUserAccount.perpPositions[0].baseAssetAmount = new BN(10)
|
|
434
|
-
.mul(BASE_PRECISION)
|
|
435
|
-
.neg();
|
|
436
|
-
myMockUserAccount.perpPositions[0].quoteAssetAmount = new BN(1000).mul(
|
|
437
|
-
QUOTE_PRECISION
|
|
438
|
-
);
|
|
439
|
-
|
|
440
|
-
const user: User = await makeMockUser(
|
|
441
|
-
myMockPerpMarkets,
|
|
442
|
-
myMockSpotMarkets,
|
|
443
|
-
myMockUserAccount,
|
|
444
|
-
[100, 1, 1, 1, 1, 1, 1, 1],
|
|
445
|
-
[1, 1, 1, 1, 1, 1, 1, 1]
|
|
446
|
-
);
|
|
447
|
-
|
|
448
|
-
const tenPct = new BN(1000);
|
|
449
|
-
const calc = user.getMarginCalculation('Initial', {
|
|
450
|
-
strict: true,
|
|
451
|
-
liquidationBufferMap: new Map<number | 'cross', BN>([[0, tenPct]]),
|
|
452
|
-
});
|
|
453
|
-
const isolatedCalc = calc.isolatedMarginCalculations.get(0);
|
|
454
|
-
|
|
455
|
-
// marginRequirement = $1000 * 1.10 (quote-converted liability) * 20% initial margin ratio = $220
|
|
456
|
-
const expectedMarginRequirement = new BN(220).mul(QUOTE_PRECISION);
|
|
457
|
-
assert(
|
|
458
|
-
isolatedCalc?.marginRequirement.eq(expectedMarginRequirement),
|
|
459
|
-
`isolated margin requirement mismatch: ${isolatedCalc?.marginRequirement.toString()} != ${expectedMarginRequirement.toString()}`
|
|
460
|
-
);
|
|
461
|
-
|
|
462
|
-
// marginRequirementPlusBuffer adds 10% of the quote-converted ($1100) liability, not the raw ($1000) one
|
|
463
|
-
const expectedBuffer = new BN(1100)
|
|
464
|
-
.mul(QUOTE_PRECISION)
|
|
465
|
-
.mul(tenPct)
|
|
466
|
-
.div(MARGIN_PRECISION);
|
|
467
|
-
const expectedMarginRequirementPlusBuffer =
|
|
468
|
-
expectedMarginRequirement.add(expectedBuffer);
|
|
469
|
-
assert(
|
|
470
|
-
isolatedCalc?.marginRequirementPlusBuffer.eq(
|
|
471
|
-
expectedMarginRequirementPlusBuffer
|
|
472
|
-
),
|
|
473
|
-
`isolated margin requirement plus buffer not quote-converted: ${isolatedCalc?.marginRequirementPlusBuffer.toString()} != ${expectedMarginRequirementPlusBuffer.toString()}`
|
|
474
|
-
);
|
|
475
|
-
});
|
|
476
|
-
|
|
477
|
-
it('pool-1 user skips quote deposit value carve-out without throwing', async () => {
|
|
478
|
-
const myMockPerpMarkets = _.cloneDeep(mockPerpMarkets);
|
|
479
|
-
const myMockSpotMarkets = _.cloneDeep(mockSpotMarkets);
|
|
480
|
-
const myMockUserAccount = _.cloneDeep(baseMockUserAccount);
|
|
481
|
-
|
|
482
|
-
myMockUserAccount.poolId = 1;
|
|
483
|
-
myMockUserAccount.spotPositions[0].balanceType = SpotBalanceType.DEPOSIT;
|
|
484
|
-
myMockUserAccount.spotPositions[0].scaledBalance = new BN(5000).mul(
|
|
485
|
-
SPOT_MARKET_BALANCE_PRECISION
|
|
486
|
-
);
|
|
487
|
-
|
|
488
|
-
const user: User = await makeMockUser(
|
|
489
|
-
myMockPerpMarkets,
|
|
490
|
-
myMockSpotMarkets,
|
|
491
|
-
myMockUserAccount,
|
|
492
|
-
[1, 1, 1, 1, 1, 1, 1, 1],
|
|
493
|
-
[1, 1, 1, 1, 1, 1, 1, 1]
|
|
494
|
-
);
|
|
495
|
-
|
|
496
|
-
const calc = user.getMarginCalculation('Initial');
|
|
497
|
-
assert(
|
|
498
|
-
calc.totalCollateral.eq(ZERO),
|
|
499
|
-
`pool-1 quote deposit should be excluded from collateral: ${calc.totalCollateral.toString()}`
|
|
500
|
-
);
|
|
501
|
-
});
|
|
502
|
-
|
|
503
|
-
it('mismatched pool ids outside the pool-1 quote carve-out throw', async () => {
|
|
504
|
-
const myMockPerpMarkets = _.cloneDeep(mockPerpMarkets);
|
|
505
|
-
const myMockSpotMarkets = _.cloneDeep(mockSpotMarkets);
|
|
506
|
-
const myMockUserAccount = _.cloneDeep(baseMockUserAccount);
|
|
507
|
-
|
|
508
|
-
myMockUserAccount.poolId = 1;
|
|
509
|
-
myMockUserAccount.spotPositions[1].marketIndex = 1;
|
|
510
|
-
myMockUserAccount.spotPositions[1].balanceType = SpotBalanceType.DEPOSIT;
|
|
511
|
-
myMockUserAccount.spotPositions[1].scaledBalance = new BN(100).mul(
|
|
512
|
-
SPOT_MARKET_BALANCE_PRECISION
|
|
513
|
-
);
|
|
514
|
-
// myMockSpotMarkets[1].poolId stays 0, mismatched with user pool id 1
|
|
515
|
-
|
|
516
|
-
const user: User = await makeMockUser(
|
|
517
|
-
myMockPerpMarkets,
|
|
518
|
-
myMockSpotMarkets,
|
|
519
|
-
myMockUserAccount,
|
|
520
|
-
[1, 1, 1, 1, 1, 1, 1, 1],
|
|
521
|
-
[1, 1, 1, 1, 1, 1, 1, 1]
|
|
522
|
-
);
|
|
523
|
-
|
|
524
|
-
let threw = false;
|
|
525
|
-
try {
|
|
526
|
-
user.getMarginCalculation('Initial');
|
|
527
|
-
} catch (e) {
|
|
528
|
-
threw = true;
|
|
529
|
-
}
|
|
530
|
-
assert(threw, 'expected mismatched pool ids to throw InvalidPoolId');
|
|
531
|
-
});
|
|
532
|
-
|
|
533
|
-
it('validateAnyIsolatedTierRequirements rejects a second perp liability alongside an isolated-tier one', async () => {
|
|
534
|
-
const myMockPerpMarkets = _.cloneDeep(mockPerpMarkets);
|
|
535
|
-
const myMockSpotMarkets = _.cloneDeep(mockSpotMarkets);
|
|
536
|
-
const myMockUserAccount = _.cloneDeep(baseMockUserAccount);
|
|
537
|
-
|
|
538
|
-
myMockPerpMarkets[0].oracle = new PublicKey(7);
|
|
539
|
-
myMockPerpMarkets[0].contractTier = ContractTier.ISOLATED;
|
|
540
|
-
myMockPerpMarkets[1].oracle = new PublicKey(9);
|
|
541
|
-
|
|
542
|
-
// market 0: isolated-tier liability
|
|
543
|
-
myMockUserAccount.perpPositions[0].positionFlag =
|
|
544
|
-
PositionFlag.IsolatedPosition;
|
|
545
|
-
myMockUserAccount.perpPositions[0].baseAssetAmount = BASE_PRECISION;
|
|
546
|
-
myMockUserAccount.perpPositions[0].isolatedPositionScaledBalance = new BN(
|
|
547
|
-
10
|
|
548
|
-
).mul(SPOT_MARKET_BALANCE_PRECISION);
|
|
549
|
-
|
|
550
|
-
// market 1: a second, unrelated perp liability
|
|
551
|
-
myMockUserAccount.perpPositions[1].marketIndex = 1;
|
|
552
|
-
myMockUserAccount.perpPositions[1].baseAssetAmount = BASE_PRECISION;
|
|
553
|
-
|
|
554
|
-
const user: User = await makeMockUser(
|
|
555
|
-
myMockPerpMarkets,
|
|
556
|
-
myMockSpotMarkets,
|
|
557
|
-
myMockUserAccount,
|
|
558
|
-
[1, 1, 1, 1, 1, 1, 1, 1],
|
|
559
|
-
[1, 1, 1, 1, 1, 1, 1, 1]
|
|
560
|
-
);
|
|
561
|
-
|
|
562
|
-
const calc = user.getMarginCalculation('Initial');
|
|
563
|
-
assert(
|
|
564
|
-
calc.withPerpIsolatedLiability,
|
|
565
|
-
'expected withPerpIsolatedLiability to be set'
|
|
566
|
-
);
|
|
567
|
-
assert(
|
|
568
|
-
calc.numPerpLiabilities === 2,
|
|
569
|
-
`expected 2 perp liabilities, got ${calc.numPerpLiabilities}`
|
|
570
|
-
);
|
|
571
|
-
|
|
572
|
-
const result = user.validateAnyIsolatedTierRequirements(calc);
|
|
573
|
-
assert(
|
|
574
|
-
!result.valid,
|
|
575
|
-
'expected isolated tier violation for a second perp liability'
|
|
576
|
-
);
|
|
577
|
-
|
|
578
|
-
// reduce-only users are exempt from the isolated-tier restriction
|
|
579
|
-
user.getUserAccountOrThrow().status |= UserStatus.REDUCE_ONLY;
|
|
580
|
-
const reduceOnlyResult = user.validateAnyIsolatedTierRequirements(calc);
|
|
581
|
-
assert(
|
|
582
|
-
reduceOnlyResult.valid,
|
|
583
|
-
'expected reduce-only user to bypass the isolated tier violation'
|
|
584
|
-
);
|
|
585
|
-
});
|
|
586
|
-
});
|