yhtx
Version:
HTX API
158 lines (144 loc) • 5.7 kB
JavaScript
const crypto = require("crypto");
const axios = require("axios");
function getSign(queryString, secret, method, path) {
let signString = [
method,
path.includes("linear-swap-api") ? "api.hbdm.com" : "api.huobi.pro",
path,
queryString || undefined,
]
.filter(Boolean)
.join("\n");
return crypto.createHmac("sha256", secret).update(signString).digest("base64");
}
async function call(path, { apiKey, secret, data, method, recvWindow } = {}) {
apiKey ||= "";
secret ||= "";
method ||= "GET";
recvWindow ??= 30000;
const origin = path.includes("linear-swap-api")
? "https://api.hbdm.com" //UM //for debig:https:api.btcgateway.pro, aws:https://api.hbdm.vn
: "https://api.huobi.pro"; //spot //https:api-aws.huobi.pro
data ||= {};
let timestamp = Date.now();
let url;
let sign;
timestamp = new Date(timestamp).toISOString().slice(0, 19);
let preBody = {
AccessKeyId: apiKey,
SignatureMethod: "HmacSHA256", //Ed25519
SignatureVersion: 2,
Timestamp: timestamp,
};
body = {
...preBody,
...data,
};
let pars = [];
for (let k in method == "GET" ? body : preBody)
pars.push(k + "=" + encodeURIComponent(body[k]));
let queryString = pars.sort().join("&");
if (method === "POST") {
url = origin + path + "?" + queryString;
sign = getSign(queryString, secret, method, path);
url += `&Signature=${sign}`;
} /*GET*/ else {
url = origin + path + "?" + queryString;
sign = getSign(queryString, secret, method, path);
url += `&Signature=${sign}`;
}
let headers = { "Content-Type": "application/json" };
let config = {
method,
url,
headers,
...(method == "POST" && { data }), //must be "data" //if GET, don't send
};
// let r = await axios(config)
// .then((r) => {
// if (!(r.data?.code == 200 /*success*/ || r.data?.status == "ok"))
// console.log(r.data); //if not code:200 or status:ok, then log
// let rs = r.data.data;
// return rs;
// })
// .catch(function (e) {
// console.log(e.response.data);
// }); //old
let r = await axios(config)
.then((r) => {
let dt = r.data;
let rs = r.data.data;
if (dt?.code == 403 && msg == "Verification failure [校验失败]") {
console.log("api bug: null"); //{code:403,msg:'Verification failure [校验失败]',data:null,ts:1758849372250}
} else if (dt?.status == "error") {
if (dt?.["err-code"] == "api-signature-not-valid") {
console.log("api bug2: null"); //{status: 'error','err-code': 'api-signature-not-valid','err-msg': 'Signature not valid: Verification failure [校验失败]',data:null}
} else if (dt?.err_code == 403) {
console.log("api bug3: undefined"); //{status:"error",err_code:403,err_msg:"Verification failure [校验失败]",ts:1758854139970};
} else if (dt?.["err-msg"] == "Format Error: account-id.") {
console.log("api bug(accId): null"); //{status: 'error','err-code': 'validation-format-error','err-msg': 'Format Error: account-id.',data:null}
} else {
console.log(dt);
rs = dt; //rs={status:'error',}
}
} else if (dt?.message == "Verification failure [校验失败]" && dt?.code == 1003) {
console.log("api bug4: undefined"); //{ message: 'Verification failure [校验失败]', code: 1003, success: false }
} else if (dt?.message == "Verification failure" && dt?.code == 12008) {
console.log("api bug5: null"); //{ code: 12008, message: "Verification failure", data: null };
} else if (!(r.data?.code == 200 /*success*/ || r.data?.status == "ok")) {
console.log(r.data); //if not code:200 or status:ok, then log //
} //eg{message:'The account API interface queried is empty',code:40237,success:false}
else if (rs == undefined) {
console.log(dt);
rs = dt; //eg rs={message:'The account API interface queried is empty',code:40237,success:false}
} // rs=DATA(if ok)|{status:'error',}|null(api fail)|undefined(api fail)
else if (!rs) console.log(dt);
// let rs = r.data?.data;
// if (
// rs == null &&
// dt?.status == "error" &&
// dt?.err_code != 403 &&
// dt?.["err-code"] != "api-signature-not-valid"
// ) {
// if (dt?.["err-msg"] != "Format Error: account-id.") {
// console.log(dt);
// rs = r.data; //eg rs={status:"error","err-code":"dw-withdraw-precision-limit","err-msg":"withdraw amount precision cannot be greater than 6",data:null}
// }
// } else if (rs == undefined) {
// if (![dt?.err_msg, dt?.message].includes("Verification failure [校验失败]")) {
// console.log(dt);
// rs = r.data; //eg rs={message:'The account API interface queried is empty',code:40237,success:false}
// } // if (dt?.success == false && dt?.code != 1003 && /*bug3*/ dt?.err_code != 403) {
// }
return rs; //rs=DATA | {status:'error','err=code','err-msg',data:null} | null(if api fail) | undefined(if apiFail)
})
.catch(function (e) {
console.log(e.response?.data);
});
return r;
}
class api {
constructor(apiKey = "", secret = "") {
this.apiKey = apiKey;
this.secret = secret;
}
async get(path, pr = {}) {
let data = {
apiKey: this.apiKey,
secret: this.secret,
data: pr,
};
return call(path, data);
}
async post(path, pr = {}) {
let data = {
apiKey: this.apiKey,
secret: this.secret,
method: "POST",
data: pr,
};
return call(path, data);
}
}
module.exports = api;
module.exports.call = call;