@velocity-exchange/sdk 0.2.4 → 0.3.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/CHANGELOG.md +60 -4
- package/README.md +8 -8
- package/lib/browser/accounts/grpcMultiAccountSubscriber.d.ts +0 -1
- package/lib/browser/accounts/grpcMultiAccountSubscriber.js +2 -7
- package/lib/browser/accounts/grpcMultiUserAccountSubscriber.js +3 -0
- package/lib/browser/accounts/webSocketAccountSubscriberV2.js +1 -2
- package/lib/browser/accounts/websocketProgramUserAccountSubscriber.js +3 -0
- package/lib/browser/adminClient.d.ts +3 -1
- package/lib/browser/adminClient.js +16 -0
- package/lib/browser/idl/velocity.d.ts +50 -1
- package/lib/browser/idl/velocity.json +50 -1
- package/lib/browser/math/exchangeStatus.d.ts +1 -0
- package/lib/browser/math/exchangeStatus.js +8 -1
- package/lib/browser/math/orders.d.ts +3 -0
- package/lib/browser/math/orders.js +6 -2
- package/lib/browser/math/state.js +1 -1
- package/lib/browser/memcmp.js +26 -5
- package/lib/browser/orderSubscriber/OrderSubscriber.js +11 -2
- package/lib/browser/swift/swiftOrderSubscriber.js +2 -2
- package/lib/browser/tokenFaucet.d.ts +2 -2
- package/lib/browser/tokenFaucet.js +11 -4
- package/lib/browser/types.d.ts +5 -0
- package/lib/browser/types.js +9 -2
- package/lib/browser/user.d.ts +22 -6
- package/lib/browser/user.js +24 -8
- package/lib/browser/velocityClient.d.ts +1 -3
- package/lib/browser/velocityClient.js +16 -22
- package/lib/node/accounts/grpcMultiAccountSubscriber.d.ts +0 -1
- package/lib/node/accounts/grpcMultiAccountSubscriber.d.ts.map +1 -1
- package/lib/node/accounts/grpcMultiAccountSubscriber.js +2 -7
- package/lib/node/accounts/grpcMultiUserAccountSubscriber.d.ts.map +1 -1
- package/lib/node/accounts/grpcMultiUserAccountSubscriber.js +3 -0
- package/lib/node/accounts/webSocketAccountSubscriberV2.d.ts.map +1 -1
- package/lib/node/accounts/webSocketAccountSubscriberV2.js +1 -2
- package/lib/node/accounts/websocketProgramUserAccountSubscriber.d.ts.map +1 -1
- package/lib/node/accounts/websocketProgramUserAccountSubscriber.js +3 -0
- package/lib/node/adminClient.d.ts +3 -1
- package/lib/node/adminClient.d.ts.map +1 -1
- package/lib/node/adminClient.js +16 -0
- package/lib/node/idl/velocity.d.ts +50 -1
- package/lib/node/idl/velocity.d.ts.map +1 -1
- package/lib/node/idl/velocity.json +50 -1
- package/lib/node/math/exchangeStatus.d.ts +1 -0
- package/lib/node/math/exchangeStatus.d.ts.map +1 -1
- package/lib/node/math/exchangeStatus.js +8 -1
- package/lib/node/math/orders.d.ts +3 -0
- package/lib/node/math/orders.d.ts.map +1 -1
- package/lib/node/math/orders.js +6 -2
- package/lib/node/math/state.js +1 -1
- package/lib/node/memcmp.d.ts.map +1 -1
- package/lib/node/memcmp.js +26 -5
- package/lib/node/orderSubscriber/OrderSubscriber.d.ts.map +1 -1
- package/lib/node/orderSubscriber/OrderSubscriber.js +11 -2
- package/lib/node/swift/swiftOrderSubscriber.js +2 -2
- package/lib/node/tokenFaucet.d.ts +2 -2
- package/lib/node/tokenFaucet.d.ts.map +1 -1
- package/lib/node/tokenFaucet.js +11 -4
- package/lib/node/types.d.ts +5 -0
- package/lib/node/types.d.ts.map +1 -1
- package/lib/node/types.js +9 -2
- package/lib/node/user.d.ts +22 -6
- package/lib/node/user.d.ts.map +1 -1
- package/lib/node/user.js +24 -8
- package/lib/node/velocityClient.d.ts +1 -3
- package/lib/node/velocityClient.d.ts.map +1 -1
- package/lib/node/velocityClient.js +16 -22
- package/package.json +2 -2
- package/src/accounts/grpcMultiAccountSubscriber.ts +2 -10
- package/src/accounts/grpcMultiUserAccountSubscriber.ts +5 -0
- package/src/accounts/webSocketAccountSubscriberV2.ts +1 -5
- package/src/accounts/websocketProgramUserAccountSubscriber.ts +5 -0
- package/src/adminClient.ts +28 -0
- package/src/idl/velocity.json +50 -1
- package/src/idl/velocity.ts +50 -1
- package/src/math/exchangeStatus.ts +10 -0
- package/src/math/orders.ts +6 -2
- package/src/math/state.ts +1 -1
- package/src/memcmp.ts +27 -5
- package/src/orderSubscriber/OrderSubscriber.ts +18 -2
- package/src/swift/swiftOrderSubscriber.ts +2 -2
- package/src/tokenFaucet.ts +10 -7
- package/src/types.ts +8 -0
- package/src/user.ts +24 -8
- package/src/velocityClient.ts +17 -36
- package/tests/dlob/helpers.ts +1 -0
package/src/adminClient.ts
CHANGED
|
@@ -22,6 +22,7 @@ import {
|
|
|
22
22
|
OracleGuardRails,
|
|
23
23
|
OracleSource,
|
|
24
24
|
ExchangeStatus,
|
|
25
|
+
SolvencyStatus,
|
|
25
26
|
MarketStatus,
|
|
26
27
|
ContractTier,
|
|
27
28
|
AssetTier,
|
|
@@ -3223,6 +3224,33 @@ export class AdminClient extends VelocityClient {
|
|
|
3223
3224
|
});
|
|
3224
3225
|
}
|
|
3225
3226
|
|
|
3227
|
+
public async updateSolvencyStatus(
|
|
3228
|
+
solvencyStatus: SolvencyStatus
|
|
3229
|
+
): Promise<TransactionSignature> {
|
|
3230
|
+
const updateSolvencyStatusIx = await this.getUpdateSolvencyStatusIx(
|
|
3231
|
+
solvencyStatus
|
|
3232
|
+
);
|
|
3233
|
+
|
|
3234
|
+
const tx = await this.buildTransaction(updateSolvencyStatusIx);
|
|
3235
|
+
|
|
3236
|
+
const { txSig } = await this.sendTransaction(tx, [], this.opts);
|
|
3237
|
+
|
|
3238
|
+
return txSig;
|
|
3239
|
+
}
|
|
3240
|
+
|
|
3241
|
+
public async getUpdateSolvencyStatusIx(
|
|
3242
|
+
solvencyStatus: SolvencyStatus
|
|
3243
|
+
): Promise<TransactionInstruction> {
|
|
3244
|
+
return await this.program.instruction.updateSolvencyStatus(solvencyStatus, {
|
|
3245
|
+
accounts: {
|
|
3246
|
+
admin: this.isSubscribed
|
|
3247
|
+
? this.getStateAccount().coldAdmin
|
|
3248
|
+
: this.wallet.publicKey,
|
|
3249
|
+
state: await this.getStatePublicKey(),
|
|
3250
|
+
},
|
|
3251
|
+
});
|
|
3252
|
+
}
|
|
3253
|
+
|
|
3226
3254
|
public async updatePerpAuctionDuration(
|
|
3227
3255
|
minDuration: BN | number
|
|
3228
3256
|
): Promise<TransactionSignature> {
|
package/src/idl/velocity.json
CHANGED
|
@@ -11068,6 +11068,35 @@
|
|
|
11068
11068
|
}
|
|
11069
11069
|
]
|
|
11070
11070
|
},
|
|
11071
|
+
{
|
|
11072
|
+
"name": "update_solvency_status",
|
|
11073
|
+
"discriminator": [
|
|
11074
|
+
81,
|
|
11075
|
+
136,
|
|
11076
|
+
15,
|
|
11077
|
+
6,
|
|
11078
|
+
24,
|
|
11079
|
+
165,
|
|
11080
|
+
44,
|
|
11081
|
+
133
|
|
11082
|
+
],
|
|
11083
|
+
"accounts": [
|
|
11084
|
+
{
|
|
11085
|
+
"name": "admin",
|
|
11086
|
+
"signer": true
|
|
11087
|
+
},
|
|
11088
|
+
{
|
|
11089
|
+
"name": "state",
|
|
11090
|
+
"writable": true
|
|
11091
|
+
}
|
|
11092
|
+
],
|
|
11093
|
+
"args": [
|
|
11094
|
+
{
|
|
11095
|
+
"name": "solvency_status",
|
|
11096
|
+
"type": "u8"
|
|
11097
|
+
}
|
|
11098
|
+
]
|
|
11099
|
+
},
|
|
11071
11100
|
{
|
|
11072
11101
|
"name": "update_special_user_status",
|
|
11073
11102
|
"discriminator": [
|
|
@@ -15972,6 +16001,16 @@
|
|
|
15972
16001
|
"code": 6354,
|
|
15973
16002
|
"name": "InsufficientProtocolFees",
|
|
15974
16003
|
"msg": "Insufficient protocol fees available to withdraw"
|
|
16004
|
+
},
|
|
16005
|
+
{
|
|
16006
|
+
"code": 6355,
|
|
16007
|
+
"name": "InvalidNativeStateAccount",
|
|
16008
|
+
"msg": "Native dispatch: supplied state account is not the canonical Velocity state PDA"
|
|
16009
|
+
},
|
|
16010
|
+
{
|
|
16011
|
+
"code": 6356,
|
|
16012
|
+
"name": "InvalidNativePerpMarketAccount",
|
|
16013
|
+
"msg": "Native dispatch: supplied market account is not a Velocity perp market"
|
|
15975
16014
|
}
|
|
15976
16015
|
],
|
|
15977
16016
|
"types": [
|
|
@@ -23207,6 +23246,16 @@
|
|
|
23207
23246
|
"name": "lp_pool_feature_bit_flags",
|
|
23208
23247
|
"type": "u8"
|
|
23209
23248
|
},
|
|
23249
|
+
{
|
|
23250
|
+
"name": "solvency_status",
|
|
23251
|
+
"docs": [
|
|
23252
|
+
"Bitmask of `SolvencyStatus` flags. Gates internal solvency-repair flows",
|
|
23253
|
+
"(bankruptcy / pnl-deficit resolution) independently of `WithdrawPaused`,",
|
|
23254
|
+
"so user withdrawals can be halted while repair keeps running, or repair",
|
|
23255
|
+
"can be frozen on its own when an oracle is suspect. `0` = repair allowed."
|
|
23256
|
+
],
|
|
23257
|
+
"type": "u8"
|
|
23258
|
+
},
|
|
23210
23259
|
{
|
|
23211
23260
|
"name": "protocol_fee_recipient_perp",
|
|
23212
23261
|
"docs": [
|
|
@@ -23241,7 +23290,7 @@
|
|
|
23241
23290
|
"type": {
|
|
23242
23291
|
"array": [
|
|
23243
23292
|
"u8",
|
|
23244
|
-
|
|
23293
|
+
271
|
|
23245
23294
|
]
|
|
23246
23295
|
}
|
|
23247
23296
|
}
|
package/src/idl/velocity.ts
CHANGED
|
@@ -11074,6 +11074,35 @@ export type Velocity = {
|
|
|
11074
11074
|
}
|
|
11075
11075
|
]
|
|
11076
11076
|
},
|
|
11077
|
+
{
|
|
11078
|
+
"name": "updateSolvencyStatus",
|
|
11079
|
+
"discriminator": [
|
|
11080
|
+
81,
|
|
11081
|
+
136,
|
|
11082
|
+
15,
|
|
11083
|
+
6,
|
|
11084
|
+
24,
|
|
11085
|
+
165,
|
|
11086
|
+
44,
|
|
11087
|
+
133
|
|
11088
|
+
],
|
|
11089
|
+
"accounts": [
|
|
11090
|
+
{
|
|
11091
|
+
"name": "admin",
|
|
11092
|
+
"signer": true
|
|
11093
|
+
},
|
|
11094
|
+
{
|
|
11095
|
+
"name": "state",
|
|
11096
|
+
"writable": true
|
|
11097
|
+
}
|
|
11098
|
+
],
|
|
11099
|
+
"args": [
|
|
11100
|
+
{
|
|
11101
|
+
"name": "solvencyStatus",
|
|
11102
|
+
"type": "u8"
|
|
11103
|
+
}
|
|
11104
|
+
]
|
|
11105
|
+
},
|
|
11077
11106
|
{
|
|
11078
11107
|
"name": "updateSpecialUserStatus",
|
|
11079
11108
|
"discriminator": [
|
|
@@ -15978,6 +16007,16 @@ export type Velocity = {
|
|
|
15978
16007
|
"code": 6354,
|
|
15979
16008
|
"name": "insufficientProtocolFees",
|
|
15980
16009
|
"msg": "Insufficient protocol fees available to withdraw"
|
|
16010
|
+
},
|
|
16011
|
+
{
|
|
16012
|
+
"code": 6355,
|
|
16013
|
+
"name": "invalidNativeStateAccount",
|
|
16014
|
+
"msg": "Native dispatch: supplied state account is not the canonical Velocity state PDA"
|
|
16015
|
+
},
|
|
16016
|
+
{
|
|
16017
|
+
"code": 6356,
|
|
16018
|
+
"name": "invalidNativePerpMarketAccount",
|
|
16019
|
+
"msg": "Native dispatch: supplied market account is not a Velocity perp market"
|
|
15981
16020
|
}
|
|
15982
16021
|
],
|
|
15983
16022
|
"types": [
|
|
@@ -23213,6 +23252,16 @@ export type Velocity = {
|
|
|
23213
23252
|
"name": "lpPoolFeatureBitFlags",
|
|
23214
23253
|
"type": "u8"
|
|
23215
23254
|
},
|
|
23255
|
+
{
|
|
23256
|
+
"name": "solvencyStatus",
|
|
23257
|
+
"docs": [
|
|
23258
|
+
"Bitmask of `SolvencyStatus` flags. Gates internal solvency-repair flows",
|
|
23259
|
+
"(bankruptcy / pnl-deficit resolution) independently of `WithdrawPaused`,",
|
|
23260
|
+
"so user withdrawals can be halted while repair keeps running, or repair",
|
|
23261
|
+
"can be frozen on its own when an oracle is suspect. `0` = repair allowed."
|
|
23262
|
+
],
|
|
23263
|
+
"type": "u8"
|
|
23264
|
+
},
|
|
23216
23265
|
{
|
|
23217
23266
|
"name": "protocolFeeRecipientPerp",
|
|
23218
23267
|
"docs": [
|
|
@@ -23247,7 +23296,7 @@ export type Velocity = {
|
|
|
23247
23296
|
"type": {
|
|
23248
23297
|
"array": [
|
|
23249
23298
|
"u8",
|
|
23250
|
-
|
|
23299
|
+
271
|
|
23251
23300
|
]
|
|
23252
23301
|
}
|
|
23253
23302
|
}
|
|
@@ -7,6 +7,7 @@ import {
|
|
|
7
7
|
ExchangeStatus,
|
|
8
8
|
PerpMarketAccount,
|
|
9
9
|
PerpOperation,
|
|
10
|
+
SolvencyStatus,
|
|
10
11
|
SpotMarketAccount,
|
|
11
12
|
SpotOperation,
|
|
12
13
|
StateAccount,
|
|
@@ -20,6 +21,15 @@ export function exchangePaused(state: StateAccount): boolean {
|
|
|
20
21
|
return state.exchangeStatus !== ExchangeStatus.ACTIVE;
|
|
21
22
|
}
|
|
22
23
|
|
|
24
|
+
// Mirror of the program's `State::solvency_repair_paused`. Gates the resolve
|
|
25
|
+
// bankruptcy / pnl-deficit instructions, independent of WITHDRAW_PAUSED.
|
|
26
|
+
export function solvencyRepairPaused(state: StateAccount): boolean {
|
|
27
|
+
return (
|
|
28
|
+
(state.solvencyStatus & SolvencyStatus.SOLVENCY_REPAIR_PAUSED) ===
|
|
29
|
+
SolvencyStatus.SOLVENCY_REPAIR_PAUSED
|
|
30
|
+
);
|
|
31
|
+
}
|
|
32
|
+
|
|
23
33
|
export function fillPaused(
|
|
24
34
|
state: StateAccount,
|
|
25
35
|
market: PerpMarketAccount | SpotMarketAccount
|
package/src/math/orders.ts
CHANGED
|
@@ -312,6 +312,9 @@ export function calculateOrderBaseAssetAmount(
|
|
|
312
312
|
* Returns:
|
|
313
313
|
* - BN size (>=0) if bounded
|
|
314
314
|
* - null if impossible (target < liabilityWeight) OR imfFactor == 0 (unbounded)
|
|
315
|
+
*
|
|
316
|
+
* Note: a market.maxOpenInterest of 0 means "no configured cap" and is treated
|
|
317
|
+
* as unlimited rather than a hard cap of 0.
|
|
315
318
|
*/
|
|
316
319
|
export function maxSizeForTargetLiabilityWeightBN(
|
|
317
320
|
target: BN,
|
|
@@ -364,9 +367,10 @@ export function maxSizeForTargetLiabilityWeightBN(
|
|
|
364
367
|
}
|
|
365
368
|
}
|
|
366
369
|
|
|
367
|
-
// cap at max OI
|
|
370
|
+
// cap at max OI. A maxOpenInterest of 0 means no configured cap (unlimited),
|
|
371
|
+
// matching the on-chain convention — do not treat it as a hard cap of 0.
|
|
368
372
|
const maxOpenInterest = market.maxOpenInterest;
|
|
369
|
-
if (lo.gt(maxOpenInterest)) {
|
|
373
|
+
if (!maxOpenInterest.isZero() && lo.gt(maxOpenInterest)) {
|
|
370
374
|
return maxOpenInterest;
|
|
371
375
|
}
|
|
372
376
|
|
package/src/math/state.ts
CHANGED
|
@@ -15,7 +15,7 @@ export function calculateInitUserFee(stateAccount: StateAccount): BN {
|
|
|
15
15
|
const accountSpaceUtilization = stateAccount.numberOfSubAccounts
|
|
16
16
|
.addn(1)
|
|
17
17
|
.mul(PERCENTAGE_PRECISION)
|
|
18
|
-
.div(getMaxNumberOfSubAccounts(stateAccount));
|
|
18
|
+
.div(BN.max(getMaxNumberOfSubAccounts(stateAccount), new BN(1)));
|
|
19
19
|
|
|
20
20
|
if (accountSpaceUtilization.gt(targetUtilization)) {
|
|
21
21
|
return maxInitFee
|
package/src/memcmp.ts
CHANGED
|
@@ -12,10 +12,32 @@ export function getUserFilter(): MemcmpFilter {
|
|
|
12
12
|
};
|
|
13
13
|
}
|
|
14
14
|
|
|
15
|
+
/*
|
|
16
|
+
* Byte offsets of the trailing scalar flags in the `User` account.
|
|
17
|
+
*
|
|
18
|
+
* These MUST match the on-chain `User` layout decoded in `decode/user.ts`. The
|
|
19
|
+
* current Velocity layout is 4496 bytes, with the tail block laid out as
|
|
20
|
+
* consecutive single bytes:
|
|
21
|
+
* status(4468) isMarginTradingEnabled(4469) idle(4470) openOrders(4471)
|
|
22
|
+
* hasOpenOrder(4472) openAuctions(4473) hasOpenAuction(4474) poolId(4475)
|
|
23
|
+
* specialUserStatus(4476)
|
|
24
|
+
*
|
|
25
|
+
* NOTE: these were previously hardcoded to the older (4376-byte) layout
|
|
26
|
+
* (idle@4350, hasOpenOrder@4352, ...). After Velocity added fields to
|
|
27
|
+
* `PerpPosition`, the account grew by 120 bytes and these flags shifted, but
|
|
28
|
+
* the filters were not updated — so `getUserWithOrderFilter()` matched zero
|
|
29
|
+
* accounts and the DLOB order book never populated. Keep these in sync with
|
|
30
|
+
* `decode/user.ts` if the `User` layout changes again.
|
|
31
|
+
*/
|
|
32
|
+
const USER_IDLE_OFFSET = 4470;
|
|
33
|
+
const USER_HAS_OPEN_ORDER_OFFSET = 4472;
|
|
34
|
+
const USER_HAS_OPEN_AUCTION_OFFSET = 4474;
|
|
35
|
+
const USER_POOL_ID_OFFSET = 4475;
|
|
36
|
+
|
|
15
37
|
export function getNonIdleUserFilter(): MemcmpFilter {
|
|
16
38
|
return {
|
|
17
39
|
memcmp: {
|
|
18
|
-
offset:
|
|
40
|
+
offset: USER_IDLE_OFFSET,
|
|
19
41
|
bytes: bs58.encode(Uint8Array.from([0])),
|
|
20
42
|
},
|
|
21
43
|
};
|
|
@@ -24,7 +46,7 @@ export function getNonIdleUserFilter(): MemcmpFilter {
|
|
|
24
46
|
export function getUserWithOrderFilter(): MemcmpFilter {
|
|
25
47
|
return {
|
|
26
48
|
memcmp: {
|
|
27
|
-
offset:
|
|
49
|
+
offset: USER_HAS_OPEN_ORDER_OFFSET,
|
|
28
50
|
bytes: bs58.encode(Uint8Array.from([1])),
|
|
29
51
|
},
|
|
30
52
|
};
|
|
@@ -33,7 +55,7 @@ export function getUserWithOrderFilter(): MemcmpFilter {
|
|
|
33
55
|
export function getUserWithoutOrderFilter(): MemcmpFilter {
|
|
34
56
|
return {
|
|
35
57
|
memcmp: {
|
|
36
|
-
offset:
|
|
58
|
+
offset: USER_HAS_OPEN_ORDER_OFFSET,
|
|
37
59
|
bytes: bs58.encode(Uint8Array.from([0])),
|
|
38
60
|
},
|
|
39
61
|
};
|
|
@@ -42,7 +64,7 @@ export function getUserWithoutOrderFilter(): MemcmpFilter {
|
|
|
42
64
|
export function getUserWithAuctionFilter(): MemcmpFilter {
|
|
43
65
|
return {
|
|
44
66
|
memcmp: {
|
|
45
|
-
offset:
|
|
67
|
+
offset: USER_HAS_OPEN_AUCTION_OFFSET,
|
|
46
68
|
bytes: bs58.encode(Uint8Array.from([1])),
|
|
47
69
|
},
|
|
48
70
|
};
|
|
@@ -60,7 +82,7 @@ export function getUserWithName(name: string): MemcmpFilter {
|
|
|
60
82
|
export function getUsersWithPoolId(poolId: number): MemcmpFilter {
|
|
61
83
|
return {
|
|
62
84
|
memcmp: {
|
|
63
|
-
offset:
|
|
85
|
+
offset: USER_POOL_ID_OFFSET,
|
|
64
86
|
bytes: bs58.encode(Uint8Array.from([poolId])),
|
|
65
87
|
},
|
|
66
88
|
};
|
|
@@ -19,6 +19,16 @@ import { grpcSubscription } from './grpcSubscription';
|
|
|
19
19
|
import { calculateOrderBaseAssetAmount } from '../math/orders';
|
|
20
20
|
import { ZERO } from '../constants/numericConstants';
|
|
21
21
|
|
|
22
|
+
/*
|
|
23
|
+
* Byte offset of `lastActiveSlot` (u64) in the `User` account, used here to
|
|
24
|
+
* cheaply detect stale updates without fully decoding the buffer. Must match
|
|
25
|
+
* the on-chain `User` layout (see `decode/user.ts`). The previous value (4328)
|
|
26
|
+
* was for the older 4376-byte layout; the current Velocity layout is 4496
|
|
27
|
+
* bytes, shifting this field +120 bytes. With the wrong offset this read 8
|
|
28
|
+
* zero-padding bytes, so the staleness guard rejected every post-load update.
|
|
29
|
+
*/
|
|
30
|
+
const USER_LAST_ACTIVE_SLOT_OFFSET = 4448;
|
|
31
|
+
|
|
22
32
|
export class OrderSubscriber {
|
|
23
33
|
velocityClient: VelocityClient;
|
|
24
34
|
usersAccounts = new Map<string, { slot: number; userAccount: UserAccount }>();
|
|
@@ -176,7 +186,10 @@ export class OrderSubscriber {
|
|
|
176
186
|
const buffer = Buffer.from(data[0], data[1]);
|
|
177
187
|
|
|
178
188
|
const newLastActiveSlot = new BN(
|
|
179
|
-
buffer.subarray(
|
|
189
|
+
buffer.subarray(
|
|
190
|
+
USER_LAST_ACTIVE_SLOT_OFFSET,
|
|
191
|
+
USER_LAST_ACTIVE_SLOT_OFFSET + 8
|
|
192
|
+
),
|
|
180
193
|
undefined,
|
|
181
194
|
'le'
|
|
182
195
|
);
|
|
@@ -191,7 +204,10 @@ export class OrderSubscriber {
|
|
|
191
204
|
} else if (dataType === 'buffer') {
|
|
192
205
|
const buffer: Buffer = data as Buffer;
|
|
193
206
|
const newLastActiveSlot = new BN(
|
|
194
|
-
buffer.subarray(
|
|
207
|
+
buffer.subarray(
|
|
208
|
+
USER_LAST_ACTIVE_SLOT_OFFSET,
|
|
209
|
+
USER_LAST_ACTIVE_SLOT_OFFSET + 8
|
|
210
|
+
),
|
|
195
211
|
undefined,
|
|
196
212
|
'le'
|
|
197
213
|
);
|
|
@@ -161,8 +161,8 @@ export class SwiftOrderSubscriber {
|
|
|
161
161
|
const endpoint =
|
|
162
162
|
this.config.endpoint ??
|
|
163
163
|
(env === 'devnet'
|
|
164
|
-
? 'wss://master.
|
|
165
|
-
: 'wss://swift.
|
|
164
|
+
? 'wss://swift.master.velocity.exchange/ws'
|
|
165
|
+
: 'wss://swift.velocity.exchange/ws');
|
|
166
166
|
const ws = new WebSocket(
|
|
167
167
|
endpoint + '?pubkey=' + this.config.keypair.publicKey.toBase58()
|
|
168
168
|
);
|
package/src/tokenFaucet.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import * as anchor from './isomorphic/
|
|
2
|
-
import { AnchorProvider, Idl, Program } from './isomorphic/
|
|
1
|
+
import * as anchor from './isomorphic/anchor';
|
|
2
|
+
import { AnchorProvider, Idl, Program } from './isomorphic/anchor';
|
|
3
3
|
import {
|
|
4
4
|
TOKEN_PROGRAM_ID,
|
|
5
5
|
Account,
|
|
@@ -51,11 +51,14 @@ export class TokenFaucet {
|
|
|
51
51
|
this.opts
|
|
52
52
|
);
|
|
53
53
|
this.provider = provider;
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
54
|
+
// Anchor (>= 0.30) reads the program id from `idl.address` rather than a
|
|
55
|
+
// constructor argument. Override it with the caller-provided `programId`
|
|
56
|
+
// so PDAs and instructions target the intended program.
|
|
57
|
+
const idl = {
|
|
58
|
+
...(tokenFaucet as unknown as Idl),
|
|
59
|
+
address: programId.toBase58(),
|
|
60
|
+
} as Idl;
|
|
61
|
+
this.program = new Program(idl, provider);
|
|
59
62
|
this.mint = mint;
|
|
60
63
|
}
|
|
61
64
|
|
package/src/types.ts
CHANGED
|
@@ -39,6 +39,13 @@ export enum ExchangeStatus {
|
|
|
39
39
|
PAUSED = 255,
|
|
40
40
|
}
|
|
41
41
|
|
|
42
|
+
// Mirror of the Rust `SolvencyStatus` bitflag (State.solvencyStatus). Gates
|
|
43
|
+
// internal solvency-repair flows independently of ExchangeStatus.WITHDRAW_PAUSED.
|
|
44
|
+
export enum SolvencyStatus {
|
|
45
|
+
ACTIVE = 0,
|
|
46
|
+
SOLVENCY_REPAIR_PAUSED = 1,
|
|
47
|
+
}
|
|
48
|
+
|
|
42
49
|
export enum FeatureBitFlags {
|
|
43
50
|
MM_ORACLE_UPDATE = 1,
|
|
44
51
|
MEDIAN_TRIGGER_PRICE = 2,
|
|
@@ -771,6 +778,7 @@ export type StateAccount = {
|
|
|
771
778
|
maxInitializeUserFee: number;
|
|
772
779
|
featureBitFlags: number;
|
|
773
780
|
lpPoolFeatureBitFlags: number;
|
|
781
|
+
solvencyStatus: number;
|
|
774
782
|
};
|
|
775
783
|
|
|
776
784
|
export type PerpMarketAccount = {
|
package/src/user.ts
CHANGED
|
@@ -225,20 +225,35 @@ export class User {
|
|
|
225
225
|
this.isSubscribed = false;
|
|
226
226
|
}
|
|
227
227
|
|
|
228
|
+
/**
|
|
229
|
+
* Returns the cached user account.
|
|
230
|
+
*
|
|
231
|
+
* - **Throws** `NotSubscribedError` if the subscriber has not been subscribed
|
|
232
|
+
* yet — reading the account before {@link subscribe} resolves is a
|
|
233
|
+
* programming error, not a missing-account condition.
|
|
234
|
+
* - Returns `undefined` when subscribed but no account was found on chain.
|
|
235
|
+
* Because `subscribe()` awaits the initial fetch, an `undefined` here means
|
|
236
|
+
* the account does not exist (or has not yet been observed), not that data
|
|
237
|
+
* is "still loading".
|
|
238
|
+
*/
|
|
228
239
|
public getUserAccount(): UserAccount | undefined {
|
|
229
240
|
return this.accountSubscriber.getUserAccountAndSlot()?.data;
|
|
230
241
|
}
|
|
231
242
|
|
|
232
243
|
/**
|
|
233
|
-
* Like {@link getUserAccount} but throws
|
|
234
|
-
*
|
|
235
|
-
*
|
|
244
|
+
* Like {@link getUserAccount} but throws instead of returning `undefined`
|
|
245
|
+
* when the account was not found. Use at call sites that structurally
|
|
246
|
+
* require the account to exist. (Still propagates `NotSubscribedError` when
|
|
247
|
+
* called before subscribing.)
|
|
248
|
+
*
|
|
249
|
+
* Delegates to {@link getUserAccount} (rather than the subscriber directly)
|
|
250
|
+
* so callers that override `getUserAccount` see the override here too.
|
|
236
251
|
*/
|
|
237
252
|
public getUserAccountOrThrow(): UserAccount {
|
|
238
253
|
const userAccount = this.getUserAccount();
|
|
239
254
|
if (!userAccount) {
|
|
240
255
|
throw new Error(
|
|
241
|
-
`User account not
|
|
256
|
+
`User account not found: ${this.getUserAccountPublicKey().toString()}`
|
|
242
257
|
);
|
|
243
258
|
}
|
|
244
259
|
return userAccount;
|
|
@@ -255,14 +270,15 @@ export class User {
|
|
|
255
270
|
}
|
|
256
271
|
|
|
257
272
|
/**
|
|
258
|
-
* Like {@link getUserAccountAndSlot} but throws
|
|
259
|
-
*
|
|
260
|
-
*
|
|
273
|
+
* Like {@link getUserAccountAndSlot} but throws instead of returning
|
|
274
|
+
* `undefined` when the account was not found. Use at call sites that
|
|
275
|
+
* structurally require the account to exist. (Still propagates
|
|
276
|
+
* `NotSubscribedError` when called before subscribing.)
|
|
261
277
|
*/
|
|
262
278
|
public getUserAccountAndSlotOrThrow(): DataAndSlot<UserAccount> {
|
|
263
279
|
return assertDataAndSlot(
|
|
264
280
|
this.accountSubscriber.getUserAccountAndSlot(),
|
|
265
|
-
`User account not
|
|
281
|
+
`User account not found: ${this.getUserAccountPublicKey().toString()}`
|
|
266
282
|
);
|
|
267
283
|
}
|
|
268
284
|
|
package/src/velocityClient.ts
CHANGED
|
@@ -1297,37 +1297,6 @@ export class VelocityClient {
|
|
|
1297
1297
|
});
|
|
1298
1298
|
}
|
|
1299
1299
|
|
|
1300
|
-
public async migrateReferrer(
|
|
1301
|
-
authority: PublicKey,
|
|
1302
|
-
txParams?: TxParams
|
|
1303
|
-
): Promise<TransactionSignature> {
|
|
1304
|
-
const ix = await this.getMigrateReferrerIx(authority);
|
|
1305
|
-
const tx = await this.buildTransaction([ix], txParams);
|
|
1306
|
-
const { txSig } = await this.sendTransaction(tx, [], this.opts);
|
|
1307
|
-
return txSig;
|
|
1308
|
-
}
|
|
1309
|
-
|
|
1310
|
-
public async getMigrateReferrerIx(
|
|
1311
|
-
authority: PublicKey
|
|
1312
|
-
): Promise<TransactionInstruction> {
|
|
1313
|
-
const escrow = getRevenueShareEscrowAccountPublicKey(
|
|
1314
|
-
this.program.programId,
|
|
1315
|
-
authority
|
|
1316
|
-
);
|
|
1317
|
-
return (this.program.instruction as any).migrateReferrer({
|
|
1318
|
-
accounts: {
|
|
1319
|
-
escrow,
|
|
1320
|
-
authority,
|
|
1321
|
-
userStats: getUserStatsAccountPublicKey(
|
|
1322
|
-
this.program.programId,
|
|
1323
|
-
authority
|
|
1324
|
-
),
|
|
1325
|
-
state: await this.getStatePublicKey(),
|
|
1326
|
-
payer: this.wallet.publicKey,
|
|
1327
|
-
},
|
|
1328
|
-
});
|
|
1329
|
-
}
|
|
1330
|
-
|
|
1331
1300
|
public async resizeRevenueShareEscrowOrders(
|
|
1332
1301
|
authority: PublicKey,
|
|
1333
1302
|
numOrders: number,
|
|
@@ -2335,7 +2304,7 @@ export class VelocityClient {
|
|
|
2335
2304
|
subAccountId = subAccountId ?? this.activeSubAccountId;
|
|
2336
2305
|
authority = authority ?? this.authority;
|
|
2337
2306
|
if (subAccountId === undefined || authority === undefined) {
|
|
2338
|
-
|
|
2307
|
+
return false;
|
|
2339
2308
|
}
|
|
2340
2309
|
const userMapKey = this.getUserMapKey(subAccountId, authority);
|
|
2341
2310
|
|
|
@@ -10360,7 +10329,11 @@ export class VelocityClient {
|
|
|
10360
10329
|
);
|
|
10361
10330
|
|
|
10362
10331
|
const tx = await this.buildTransaction(updateMmOracleIx, {
|
|
10363
|
-
|
|
10332
|
+
// Headroom for the native handler's owner + discriminator validation
|
|
10333
|
+
// of the state + perp-market accounts (was 1000 when it bytemuck-cast
|
|
10334
|
+
// the market without any checks). Measured ~1.3k CU; 2000 leaves
|
|
10335
|
+
// margin for the production-only signer check.
|
|
10336
|
+
computeUnits: 2000,
|
|
10364
10337
|
computeUnitsPrice: 0,
|
|
10365
10338
|
});
|
|
10366
10339
|
const { txSig } = await this.sendTransaction(tx, [], this.opts);
|
|
@@ -10368,16 +10341,19 @@ export class VelocityClient {
|
|
|
10368
10341
|
return txSig;
|
|
10369
10342
|
}
|
|
10370
10343
|
|
|
10371
|
-
public getUpdateAmmSpreadAdjustmentNativeIx(
|
|
10344
|
+
public async getUpdateAmmSpreadAdjustmentNativeIx(
|
|
10372
10345
|
marketIndex: number,
|
|
10373
10346
|
ammSpreadAdjustment: number // i8
|
|
10374
|
-
): TransactionInstruction {
|
|
10347
|
+
): Promise<TransactionInstruction> {
|
|
10375
10348
|
const discriminatorBuffer = createNativeInstructionDiscriminatorBuffer(1);
|
|
10376
10349
|
const data = Buffer.alloc(discriminatorBuffer.length + 4);
|
|
10377
10350
|
data.set(discriminatorBuffer, 0);
|
|
10378
10351
|
data.writeInt8(ammSpreadAdjustment, 5); // next byte
|
|
10379
10352
|
|
|
10380
|
-
// Build the instruction manually
|
|
10353
|
+
// Build the instruction manually. The native handler re-establishes the
|
|
10354
|
+
// account guarantees Anchor would normally provide: it loads `state` as
|
|
10355
|
+
// the program-owned State account and authenticates the signer against
|
|
10356
|
+
// `state.hotAmmSpreadAdjust`, so the state account is required at index 2.
|
|
10381
10357
|
return new TransactionInstruction({
|
|
10382
10358
|
programId: this.program.programId,
|
|
10383
10359
|
keys: [
|
|
@@ -10391,6 +10367,11 @@ export class VelocityClient {
|
|
|
10391
10367
|
isWritable: false,
|
|
10392
10368
|
isSigner: true,
|
|
10393
10369
|
},
|
|
10370
|
+
{
|
|
10371
|
+
pubkey: await this.getStatePublicKey(),
|
|
10372
|
+
isWritable: false,
|
|
10373
|
+
isSigner: false,
|
|
10374
|
+
},
|
|
10394
10375
|
],
|
|
10395
10376
|
data,
|
|
10396
10377
|
});
|
package/tests/dlob/helpers.ts
CHANGED
|
@@ -560,6 +560,7 @@ export const mockStateAccount: StateAccount = {
|
|
|
560
560
|
protocolFeeRecipientSpot: PublicKey.default,
|
|
561
561
|
featureBitFlags: 0,
|
|
562
562
|
lpPoolFeatureBitFlags: 0,
|
|
563
|
+
solvencyStatus: 0,
|
|
563
564
|
defaultMarketOrderTimeInForce: 0,
|
|
564
565
|
defaultSpotAuctionDuration: 0,
|
|
565
566
|
discountMint: PublicKey.default,
|