Skip to content

Commit

Permalink
chore(): deprecate pre-V5 authentication workflows
Browse files Browse the repository at this point in the history
  • Loading branch information
tiagosiebler committed Jan 24, 2025
1 parent e4957b0 commit 03169b3
Show file tree
Hide file tree
Showing 7 changed files with 50 additions and 81 deletions.
2 changes: 1 addition & 1 deletion src/rest-client-v5.ts
Original file line number Diff line number Diff line change
Expand Up @@ -272,7 +272,7 @@ export class RestClientV5 extends BaseRestClient {
*/

getClientType() {
return REST_CLIENT_TYPE_ENUM.v3;
return REST_CLIENT_TYPE_ENUM.v5;
}

async fetchServerTime(): Promise<number> {
Expand Down
4 changes: 2 additions & 2 deletions src/spot-client-v3.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ import BaseRestClient from './util/BaseRestClient';
*/
export class SpotClientV3 extends BaseRestClient {
getClientType() {
// Follows the same authentication mechanism as other v3 APIs (e.g. USDC)
return REST_CLIENT_TYPE_ENUM.v3;
// Doesn't really matter here, since the only remaining endpoint does not require auth.
return REST_CLIENT_TYPE_ENUM.v5;
}

async fetchServerTime(): Promise<number> {
Expand Down
62 changes: 16 additions & 46 deletions src/util/BaseRestClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -164,10 +164,6 @@ export default abstract class BaseRestClient {
}
}

private isSpotV1Client() {
return this.clientType === REST_CLIENT_TYPE_ENUM.spot;
}

get(endpoint: string, params?: any) {
return this._call('GET', endpoint, params, true);
}
Expand Down Expand Up @@ -263,56 +259,34 @@ export default abstract class BaseRestClient {
};
}

// USDC endpoints, unified margin and a few others use a different way of authenticating requests (headers instead of params)
if (this.clientType === REST_CLIENT_TYPE_ENUM.v3) {
const signResult = await this.prepareSignParams(
method,
'v5auth',
params,
isPublicApi,
);

const headers: AxiosRequestConfig['headers'] = {
'X-BAPI-SIGN-TYPE': 2,
'X-BAPI-API-KEY': this.key,
'X-BAPI-TIMESTAMP': signResult.timestamp,
'X-BAPI-SIGN': signResult.sign,
'X-BAPI-RECV-WINDOW': signResult.recvWindow,
...options.headers,
};

if (method === 'GET') {
return {
...options,
headers,
params: signResult.originalParams,
};
}

return {
...options,
headers,
data: signResult.originalParams,
};
}

const signResult = await this.prepareSignParams(
method,
'v2auth',
'v5auth',
params,
isPublicApi,
);

if (method === 'GET' || this.isSpotV1Client()) {
const headers: AxiosRequestConfig['headers'] = {
'X-BAPI-SIGN-TYPE': 2,
'X-BAPI-API-KEY': this.key,
'X-BAPI-TIMESTAMP': signResult.timestamp,
'X-BAPI-SIGN': signResult.sign,
'X-BAPI-RECV-WINDOW': signResult.recvWindow,
...options.headers,
};

if (method === 'GET') {
return {
...options,
params: signResult.paramsWithSign,
headers,
params: signResult.originalParams,
};
}

return {
...options,
data: signResult.paramsWithSign,
headers,
data: signResult.originalParams,
};
}

Expand Down Expand Up @@ -476,11 +450,7 @@ export default abstract class BaseRestClient {

// Optional, set to 5000 by default. Increase if timestamp/recv_window errors are seen.
if (recvWindow) {
if (this.isSpotV1Client()) {
res.originalParams.recvWindow = recvWindow;
} else {
res.originalParams.recv_window = recvWindow;
}
res.originalParams.recv_window = recvWindow;
}
const sortProperties = true;
const encodeValues = false;
Expand Down
28 changes: 1 addition & 27 deletions src/util/requestUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -207,39 +207,13 @@ export function isTopicSubscriptionConfirmation(
return true;
}

export function isWSAPIResponse(
msg: unknown,
): msg is Omit<WSAPIResponse, 'wsKey'> {
if (typeof msg !== 'object' || !msg) {
return false;
}

if (typeof msg['op'] !== 'string') {
return false;
}

return (WS_API_Operations as string[]).includes(msg['op']);
}

export function isTopicSubscriptionSuccess(
msg: unknown,
): msg is WebsocketSucceededTopicSubscriptionConfirmationEvent {
if (!isTopicSubscriptionConfirmation(msg)) return false;
return msg.success === true;
}

export const APIID = 'bybitapinode';

/**
* Used to switch how authentication/requests work under the hood (primarily for SPOT since it's different there)
*/
export const REST_CLIENT_TYPE_ENUM = {
accountAsset: 'accountAsset',
inverse: 'inverse',
inverseFutures: 'inverseFutures',
linear: 'linear',
spot: 'spot',
v3: 'v3',
v5: 'v5',
} as const;

export type RestClientType =
Expand Down
28 changes: 28 additions & 0 deletions src/util/typeGuards.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,15 @@
* Use type guards to narrow down types with minimal efforts.
*/

import { WebsocketSucceededTopicSubscriptionConfirmationEvent } from '../types';
import { WSAPIResponse, WS_API_Operations } from '../types/websockets/ws-api';
import {
WSAccountOrderEventV5,
WSExecutionEventV5,
WSOrderbookEventV5,
WSPositionEventV5,
} from '../types/websockets/ws-events';
import { isTopicSubscriptionConfirmation } from './requestUtils';

/**
* Type guard to detect a V5 orderbook event (delta & snapshots)
Expand Down Expand Up @@ -92,3 +95,28 @@ export function isWsExecutionEventV5(

return event['topic'] === 'execution';
}

export function neverGuard(x: never, msg: string): Error {
return new Error(`Unhandled value exception "${x}", ${msg}`);
}

export function isWSAPIResponse(
msg: unknown,
): msg is Omit<WSAPIResponse, 'wsKey'> {
if (typeof msg !== 'object' || !msg) {
return false;
}

if (typeof msg['op'] !== 'string') {
return false;
}

return (WS_API_Operations as string[]).includes(msg['op']);
}

export function isTopicSubscriptionSuccess(
msg: unknown,
): msg is WebsocketSucceededTopicSubscriptionConfirmationEvent {
if (!isTopicSubscriptionConfirmation(msg)) return false;
return msg.success === true;
}
2 changes: 1 addition & 1 deletion src/util/webCryptoAPI.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { neverGuard } from './websockets';
import { neverGuard } from './typeGuards';

function bufferToB64(buffer: ArrayBuffer): string {
let binary = '';
Expand Down
5 changes: 1 addition & 4 deletions src/util/websockets/websocket-util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import {

import { DefaultLogger } from '../logger';
import { WSAPIRequest } from '../../types/websockets/ws-api';
import { neverGuard } from '../typeGuards';

export const WS_LOGGER_CATEGORY = { category: 'bybit-ws' };

Expand Down Expand Up @@ -301,10 +302,6 @@ export const WS_ERROR_ENUM = {
USDC_OPTION_AUTH_FAILED: '3303006',
};

export function neverGuard(x: never, msg: string): Error {
return new Error(`Unhandled value exception "${x}", ${msg}`);
}

/**
* #305: ws.terminate() is undefined in browsers.
* This only works in node.js, not in browsers.
Expand Down

0 comments on commit 03169b3

Please sign in to comment.