Invalid_Nonce authenticating on Crypto.com Google Script

201 Views Asked by At

For private endpoints of Crypto.com, I am getting the error:

{ id: xx,
  method: 'private/get-order-detail',
  code: 10007,
  message: 'INVALID_NONCE' }

for the following code:

function getOrderStatus() {
  var nonce = Math.floor(new Date().setSeconds(new Date().getSeconds() - 10) / 1000);
  nonce += 1; // Increment nonce for each request, is this the increase?
  var payload = {
    "id": orderId,
    "method": "private/get-order-detail",
    "params": {
      "order_id": orderId
    },
    "nonce": nonce
  };
  var payloadString = JSON.stringify(payload);
  var signature = Utilities.computeHmacSha256Signature(payloadString, secretKey);
  var signatureHex = Utilities.base64Encode(signature).toString();
  var headers = {
    "Content-Type": "application/json",
    "API-Key": apiKey,
    "Signature": signatureHex,
    "Timestamp": nonce
  };
  var options = {
    "method": "post",
    "headers": headers,
    "payload": payloadString,
    "muteHttpExceptions": true
  };
  var response = UrlFetchApp.fetch("https://api.crypto.com/v2/private/get-order-detail", options);
  var data = JSON.parse(response.getContentText());
  console.log(data)
  return data;
}

From my understanding, the nonce value needs to be increasing on every request?

1

There are 1 best solutions below

3
On BEST ANSWER

When I saw the official document of Crypto.com Spot Exchange V2.1 API for Exchange reference documentation,

nonce long Y Current timestamp (milliseconds since the Unix epoch)

It seems that the sample value of nonce is 1587846358253.

When I saw your script using new Date('2020-04-26T05:25:58.253Z'), 1587878748 is returned as nonce. And, the document says about code: 10007, as 10007 400 INVALID_NONCE Nonce value differs by more than 30 seconds from server.

If my understanding is correct, I thought that this might be the reason for your current issue. If my understanding is correct, how about the following modification?

From:

var nonce = Math.floor(new Date().setSeconds(new Date().getSeconds() - 10) / 1000);

To:

var nonce = new Date().setSeconds(new Date().getSeconds() - 10);

or

var nonce = new Date().getTime();

or

var nonce = new Date().getTime().toString();

Note:

  • In this answer, it supposes that your other part except for nonce correctly works for using the API you want to use. Please be careful about this.

Reference:

Added:

From your following reply,

with the change it gives a permission error code: 10002, message: 'UNAUTHORIZED' }. I know the API keys are correct.

I could confirm that your issue of nonce in your question was resolved. And also, I confirmed that your other part script except for nonce was not correct, and, this is your new issue. In this case, I think that it is required to modify your request. I think that your issue of nonce of this question can be resolved by my answer. So, how about modifying your request as follows?

Modified script:

The function signRequest is from https://exchange-docs.crypto.com/spot/index.html#request-format.

function myFunction() {
  // Please set your valid values.
  const nonce = new Date().getTime();
  const id = "###"; // Please set your ID.
  const orderId = "###"; // Please set your order ID.
  const apiKey = "###"; // Please set your API key.
  const apiSecret = "###"; // Please set your secret.


  const signRequest = (request_body, api_key, secret) => {
    const { id, method, params, nonce } = request_body;
    function isObject(obj) { return obj !== undefined && obj !== null && obj.constructor == Object; }
    function isArray(obj) { return obj !== undefined && obj !== null && obj.constructor == Array; }
    function arrayToString(obj) { return obj.reduce((a, b) => { return a + (isObject(b) ? objectToString(b) : (isArray(b) ? arrayToString(b) : b)); }, ""); }
    function objectToString(obj) { return (obj == null ? "" : Object.keys(obj).sort().reduce((a, b) => { return a + b + (isArray(obj[b]) ? arrayToString(obj[b]) : (isObject(obj[b]) ? objectToString(obj[b]) : obj[b])); }, "")); }
    const paramsString = objectToString(params);
    console.log(paramsString);
    const sigPayload = method + id + api_key + paramsString + nonce;
    request_body.sig = Utilities.computeHmacSha256Signature(sigPayload, secret).map(byte => ('0' + (byte & 0xFF).toString(16)).slice(-2)).join('');
    return request_body;
  };

  let request = {
    id: id,
    method: "private/get-order-detail",
    api_key: apiKey,
    params: { order_id: orderId },
    nonce: nonce,
  };
  const requestBody = JSON.stringify(signRequest(request, apiKey, apiSecret));
  const options = {
    method: "post",
    contentType: "application/json",
    payload: requestBody,
  }

  var response = UrlFetchApp.fetch("https://api.crypto.com/v2/private/get-order-detail", options);
  var data = JSON.parse(response.getContentText());
  console.log(data)
  return data;
}