fix(#187): signature fails sometimes for spot v3 with param GET requests. add example for query spot tpsl orders

This commit is contained in:
tiagosiebler
2022-10-24 19:48:57 +01:00
parent b0608dacc8
commit bdd1d760f5
4 changed files with 71 additions and 8 deletions

View File

@@ -0,0 +1,42 @@
import { SpotClientV3 } from '../src/index';
// or
// import { SpotClientV3 } from 'bybit-api';
const symbol = 'BTCUSDT';
const key = process.env.API_KEY_COM;
const secret = process.env.API_SECRET_COM;
const client = new SpotClientV3({
key,
secret,
strict_param_validation: true,
});
(async () => {
try {
const orderId = undefined;
const ordersPerPage = undefined;
const orders = await client.getOpenOrders(symbol);
console.log('orders 1:', orders);
const normalOrders = await client.getOpenOrders(
symbol,
orderId,
ordersPerPage,
0
);
console.log('normal orders:', normalOrders);
const tpSlOrders = await client.getOpenOrders(
symbol,
orderId,
ordersPerPage,
1
);
console.log('tpSlOrders:', tpSlOrders);
} catch (e) {
console.error('request failed: ', e);
}
})();

View File

@@ -17,6 +17,7 @@ export const API_ERROR_CODE = {
/** This could mean bad request, incorrect value types or even incorrect/missing values */ /** This could mean bad request, incorrect value types or even incorrect/missing values */
PARAMS_MISSING_OR_WRONG: 10001, PARAMS_MISSING_OR_WRONG: 10001,
INVALID_API_KEY_OR_PERMISSIONS: 10003, INVALID_API_KEY_OR_PERMISSIONS: 10003,
SIGNATURE_NOT_VALID: 10004,
INCORRECT_API_KEY_PERMISSIONS: 10005, INCORRECT_API_KEY_PERMISSIONS: 10005,
INCORRECT_PRIVATE_OPERATIONS: 3303001, INCORRECT_PRIVATE_OPERATIONS: 3303001,
/** Account not unified margin, update required */ /** Account not unified margin, update required */

View File

@@ -108,7 +108,7 @@ export default abstract class BaseRestClient {
} }
} }
private isSpotClient() { private isSpotV1Client() {
return this.clientType === REST_CLIENT_TYPE_ENUM.spot; return this.clientType === REST_CLIENT_TYPE_ENUM.spot;
} }
@@ -233,7 +233,7 @@ export default abstract class BaseRestClient {
isPublicApi isPublicApi
); );
if (method === 'GET' || this.isSpotClient()) { if (method === 'GET' || this.isSpotV1Client()) {
return { return {
...options, ...options,
params: signResult.paramsWithSign, params: signResult.paramsWithSign,
@@ -343,13 +343,20 @@ export default abstract class BaseRestClient {
// usdc is different for some reason // usdc is different for some reason
if (signMethod === 'usdc') { if (signMethod === 'usdc') {
const sortProperties = false;
const signRequestParams = const signRequestParams =
method === 'GET' method === 'GET'
? serializeParams(res.originalParams, strictParamValidation) ? serializeParams(
res.originalParams,
strictParamValidation,
sortProperties
)
: JSON.stringify(res.originalParams); : JSON.stringify(res.originalParams);
const paramsStr = timestamp + key + recvWindow + signRequestParams; const paramsStr = timestamp + key + recvWindow + signRequestParams;
res.sign = await signMessage(paramsStr, this.secret); res.sign = await signMessage(paramsStr, this.secret);
// console.log('sign req: ', paramsStr);
return res; return res;
} }
@@ -360,16 +367,18 @@ export default abstract class BaseRestClient {
// Optional, set to 5000 by default. Increase if timestamp/recv_window errors are seen. // Optional, set to 5000 by default. Increase if timestamp/recv_window errors are seen.
if (recvWindow) { if (recvWindow) {
if (this.isSpotClient()) { if (this.isSpotV1Client()) {
res.originalParams.recvWindow = recvWindow; res.originalParams.recvWindow = recvWindow;
} else { } else {
res.originalParams.recv_window = recvWindow; res.originalParams.recv_window = recvWindow;
} }
} }
const sortProperties = true;
res.serializedParams = serializeParams( res.serializedParams = serializeParams(
res.originalParams, res.originalParams,
strictParamValidation strictParamValidation,
sortProperties
); );
res.sign = await signMessage(res.serializedParams, this.secret); res.sign = await signMessage(res.serializedParams, this.secret);
res.paramsWithSign = { res.paramsWithSign = {

View File

@@ -30,12 +30,23 @@ export interface RestClientOptions {
parse_exceptions?: boolean; parse_exceptions?: boolean;
} }
/**
* Serialise a (flat) object into a query string
* @param params the object to serialise
* @param strict_validation throw if any properties are undefined
* @param sortProperties sort properties alphabetically before building a query string
* @returns the params object as a serialised string key1=value1&key2=value2&etc
*/
export function serializeParams( export function serializeParams(
params: object = {}, params: object = {},
strict_validation = false strict_validation = false,
sortProperties = true
): string { ): string {
return Object.keys(params) const properties = sortProperties
.sort() ? Object.keys(params).sort()
: Object.keys(params);
return properties
.map((key) => { .map((key) => {
const value = params[key]; const value = params[key];
if (strict_validation === true && typeof value === 'undefined') { if (strict_validation === true && typeof value === 'undefined') {