From 7b10ae08a20f9d7080bf891c6c73e9523029b694 Mon Sep 17 00:00:00 2001 From: tiagosiebler Date: Tue, 15 Nov 2022 16:22:04 +0000 Subject: [PATCH] v3.2.1: fix sign error when using cursor containing percent symbols. URI encode request parameters by default when serialising during sign. --- src/util/BaseRestClient.ts | 9 +++++++-- src/util/requestUtils.ts | 16 ++++++++++++++-- 2 files changed, 21 insertions(+), 4 deletions(-) diff --git a/src/util/BaseRestClient.ts b/src/util/BaseRestClient.ts index 248fe33..a83d687 100644 --- a/src/util/BaseRestClient.ts +++ b/src/util/BaseRestClient.ts @@ -79,6 +79,8 @@ export default abstract class BaseRestClient { enable_time_sync: false, /** How often to sync time drift with bybit servers (if time sync is enabled) */ sync_interval_ms: 3600000, + /** Request parameter values are now URI encoded by default during signing. Set to false to override this behaviour. */ + encodeSerialisedValues: true, ...restOptions, }; @@ -337,6 +339,7 @@ export default abstract class BaseRestClient { const recvWindow = res.originalParams.recv_window || this.options.recv_window || 5000; const strictParamValidation = this.options.strict_param_validation; + const encodeSerialisedValues = this.options.encodeSerialisedValues; // In case the parent function needs it (e.g. USDC uses a header) res.recvWindow = recvWindow; @@ -349,7 +352,8 @@ export default abstract class BaseRestClient { ? serializeParams( res.originalParams, strictParamValidation, - sortProperties + sortProperties, + encodeSerialisedValues ) : JSON.stringify(res.originalParams); @@ -378,7 +382,8 @@ export default abstract class BaseRestClient { res.serializedParams = serializeParams( res.originalParams, strictParamValidation, - sortProperties + sortProperties, + encodeSerialisedValues ); res.sign = await signMessage(res.serializedParams, this.secret); res.paramsWithSign = { diff --git a/src/util/requestUtils.ts b/src/util/requestUtils.ts index bf5ca66..7c60b01 100644 --- a/src/util/requestUtils.ts +++ b/src/util/requestUtils.ts @@ -20,6 +20,13 @@ export interface RestClientOptions { /** Default: false. If true, we'll throw errors if any params are undefined */ strict_param_validation?: boolean; + /** + * Default: true. + * If true, request parameters will be URI encoded during the signing process. + * New behaviour introduced in v3.2.1 to fix rare parameter-driven sign errors with unified margin cursors containing "%". + */ + encodeSerialisedValues?: boolean; + /** * Optionally override API protocol + domain * e.g baseUrl: 'https://api.bytick.com' @@ -35,12 +42,14 @@ export interface RestClientOptions { * @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 + * @param encodeSerialisedValues URL encode value before serialising * @returns the params object as a serialised string key1=value1&key2=value2&etc */ export function serializeParams( params: object = {}, strict_validation = false, - sortProperties = true + sortProperties = true, + encodeSerialisedValues = true ): string { const properties = sortProperties ? Object.keys(params).sort() @@ -48,7 +57,10 @@ export function serializeParams( return properties .map((key) => { - const value = params[key]; + const value = encodeSerialisedValues + ? encodeURI(params[key]) + : params[key]; + if (strict_validation === true && typeof value === 'undefined') { throw new Error( 'Failed to sign API request due to undefined parameter'