@riocrypto/common-server 1.0.2747 → 1.0.2749
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -18,6 +18,7 @@ function buildAxiosWithLogging() {
|
|
|
18
18
|
"private",
|
|
19
19
|
"credential",
|
|
20
20
|
"passphrase",
|
|
21
|
+
"signature",
|
|
21
22
|
"csrf",
|
|
22
23
|
];
|
|
23
24
|
function maskHeaderValue(value) {
|
|
@@ -34,6 +35,25 @@ function buildAxiosWithLogging() {
|
|
|
34
35
|
});
|
|
35
36
|
return maskedHeaders;
|
|
36
37
|
}
|
|
38
|
+
function maskUrl(url) {
|
|
39
|
+
if (!url)
|
|
40
|
+
return "unknown";
|
|
41
|
+
try {
|
|
42
|
+
const parsed = new URL(url);
|
|
43
|
+
const params = new URLSearchParams(parsed.search);
|
|
44
|
+
params.forEach((value, key) => {
|
|
45
|
+
const lower = key.toLowerCase();
|
|
46
|
+
if (sensitiveSubstrings.some((sub) => lower.includes(sub))) {
|
|
47
|
+
params.set(key, maskHeaderValue(value));
|
|
48
|
+
}
|
|
49
|
+
});
|
|
50
|
+
parsed.search = params.toString();
|
|
51
|
+
return parsed.toString();
|
|
52
|
+
}
|
|
53
|
+
catch (_a) {
|
|
54
|
+
return url;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
37
57
|
// Request Interceptor
|
|
38
58
|
axiosWithLogging.interceptors.request.use((config) => {
|
|
39
59
|
var _a;
|
|
@@ -43,7 +63,7 @@ function buildAxiosWithLogging() {
|
|
|
43
63
|
// Mask sensitive headers in the configuration
|
|
44
64
|
const maskedHeaders = maskHeaders(customConfig.headers);
|
|
45
65
|
// Combine and log the full request configuration with masked headers
|
|
46
|
-
const logMessage = `Request: method=${customConfig.method}, url=${customConfig.url}, headers=${JSON.stringify(maskedHeaders)}, data=${JSON.stringify(customConfig.data)}`;
|
|
66
|
+
const logMessage = `Request: method=${customConfig.method}, url=${maskUrl(customConfig.url)}, headers=${JSON.stringify(maskedHeaders)}, data=${JSON.stringify(customConfig.data)}`;
|
|
47
67
|
((_a = logger_1.default.getLogger()) === null || _a === void 0 ? void 0 : _a.info(logMessage)) || console.log(logMessage);
|
|
48
68
|
}
|
|
49
69
|
return config;
|
|
@@ -61,21 +81,21 @@ function buildAxiosWithLogging() {
|
|
|
61
81
|
// Check if logging is disabled for this request
|
|
62
82
|
if (!customConfig.skipLogging) {
|
|
63
83
|
// Combine and log the full response details
|
|
64
|
-
const logMessage = `Response: url=${customConfig.url}, status=${response.status}, data=${JSON.stringify(response.data)}`;
|
|
84
|
+
const logMessage = `Response: url=${maskUrl(customConfig.url)}, status=${response.status}, data=${JSON.stringify(response.data)}`;
|
|
65
85
|
((_a = logger_1.default.getLogger()) === null || _a === void 0 ? void 0 : _a.info(logMessage)) || console.log(logMessage);
|
|
66
86
|
}
|
|
67
87
|
return response;
|
|
68
88
|
}, (error) => {
|
|
69
|
-
var _a, _b;
|
|
89
|
+
var _a, _b, _c;
|
|
70
90
|
// Combine and log the response error details without headers
|
|
71
|
-
let logMessage = `Response Error: url=${error.config ?
|
|
91
|
+
let logMessage = `Response Error: url=${maskUrl((_a = error.config) === null || _a === void 0 ? void 0 : _a.url)}, message=${error.message}`;
|
|
72
92
|
if (error.response) {
|
|
73
93
|
logMessage += `, status=${error.response.status}, data=${JSON.stringify(error.response.data)}`;
|
|
74
94
|
}
|
|
75
|
-
((
|
|
95
|
+
((_b = logger_1.default.getLogger()) === null || _b === void 0 ? void 0 : _b.info(logMessage)) || console.log(logMessage);
|
|
76
96
|
return Promise.reject({
|
|
77
97
|
message: logMessage,
|
|
78
|
-
status: (
|
|
98
|
+
status: (_c = error.response) === null || _c === void 0 ? void 0 : _c.status,
|
|
79
99
|
});
|
|
80
100
|
});
|
|
81
101
|
return axiosWithLogging;
|
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
import { Crypto } from "@riocrypto/common";
|
|
2
|
+
export interface BinanceBalance {
|
|
3
|
+
asset: string;
|
|
4
|
+
free: string;
|
|
5
|
+
locked: string;
|
|
6
|
+
}
|
|
7
|
+
export interface BinanceAccountInfo {
|
|
8
|
+
balances: BinanceBalance[];
|
|
9
|
+
}
|
|
10
|
+
export interface BinanceDepositAddress {
|
|
11
|
+
address: string;
|
|
12
|
+
coin: string;
|
|
13
|
+
tag: string;
|
|
14
|
+
url: string;
|
|
15
|
+
}
|
|
16
|
+
export interface BinanceOrderResponse {
|
|
17
|
+
symbol: string;
|
|
18
|
+
orderId: number;
|
|
19
|
+
orderListId: number;
|
|
20
|
+
clientOrderId: string;
|
|
21
|
+
transactTime?: number;
|
|
22
|
+
price: string;
|
|
23
|
+
origQty: string;
|
|
24
|
+
executedQty: string;
|
|
25
|
+
cummulativeQuoteQty: string;
|
|
26
|
+
status: string;
|
|
27
|
+
timeInForce: string;
|
|
28
|
+
type: string;
|
|
29
|
+
side: string;
|
|
30
|
+
fills?: Array<{
|
|
31
|
+
price: string;
|
|
32
|
+
qty: string;
|
|
33
|
+
commission: string;
|
|
34
|
+
commissionAsset: string;
|
|
35
|
+
}>;
|
|
36
|
+
}
|
|
37
|
+
export interface BinanceWithdrawHistoryItem {
|
|
38
|
+
id: string;
|
|
39
|
+
amount: string;
|
|
40
|
+
transactionFee: string;
|
|
41
|
+
coin: string;
|
|
42
|
+
status: number;
|
|
43
|
+
address: string;
|
|
44
|
+
txId: string;
|
|
45
|
+
applyTime: string;
|
|
46
|
+
network: string;
|
|
47
|
+
transferType: number;
|
|
48
|
+
withdrawOrderId?: string;
|
|
49
|
+
info: string;
|
|
50
|
+
confirmNo: number;
|
|
51
|
+
}
|
|
52
|
+
export interface BinanceDepositHistoryItem {
|
|
53
|
+
id: string;
|
|
54
|
+
amount: string;
|
|
55
|
+
coin: string;
|
|
56
|
+
network: string;
|
|
57
|
+
status: number;
|
|
58
|
+
address: string;
|
|
59
|
+
addressTag: string;
|
|
60
|
+
txId: string;
|
|
61
|
+
insertTime: number;
|
|
62
|
+
transferType: number;
|
|
63
|
+
confirmTimes: string;
|
|
64
|
+
unlockConfirm: number;
|
|
65
|
+
walletType: number;
|
|
66
|
+
}
|
|
67
|
+
export interface BinanceTradeItem {
|
|
68
|
+
id: number;
|
|
69
|
+
price: string;
|
|
70
|
+
qty: string;
|
|
71
|
+
quoteQty: string;
|
|
72
|
+
time: number;
|
|
73
|
+
isBuyerMaker: boolean;
|
|
74
|
+
isBestMatch: boolean;
|
|
75
|
+
}
|
|
76
|
+
export interface BinanceOrderBook {
|
|
77
|
+
lastUpdateId: number;
|
|
78
|
+
bids: [string, string][];
|
|
79
|
+
asks: [string, string][];
|
|
80
|
+
}
|
|
81
|
+
export interface BinanceExchangeInfo {
|
|
82
|
+
timezone: string;
|
|
83
|
+
serverTime: number;
|
|
84
|
+
symbols: any[];
|
|
85
|
+
}
|
|
86
|
+
export interface BinanceFiatWithdrawResponse {
|
|
87
|
+
code: string;
|
|
88
|
+
message: string;
|
|
89
|
+
data: {
|
|
90
|
+
orderId: string;
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
export interface BinanceFiatOrderDetail {
|
|
94
|
+
code: string;
|
|
95
|
+
message: string;
|
|
96
|
+
data: {
|
|
97
|
+
orderId: string;
|
|
98
|
+
orderStatus: string;
|
|
99
|
+
amount: string;
|
|
100
|
+
fee: string;
|
|
101
|
+
fiatCurrency: string;
|
|
102
|
+
errorCode: string;
|
|
103
|
+
errorMessage: string;
|
|
104
|
+
ext: Record<string, any>;
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
export declare enum BinanceOrderStatus {
|
|
108
|
+
NEW = "NEW",
|
|
109
|
+
PARTIALLY_FILLED = "PARTIALLY_FILLED",
|
|
110
|
+
FILLED = "FILLED",
|
|
111
|
+
CANCELED = "CANCELED",
|
|
112
|
+
PENDING_CANCEL = "PENDING_CANCEL",
|
|
113
|
+
REJECTED = "REJECTED",
|
|
114
|
+
EXPIRED = "EXPIRED",
|
|
115
|
+
EXPIRED_IN_MATCH = "EXPIRED_IN_MATCH"
|
|
116
|
+
}
|
|
117
|
+
declare class BinanceClient {
|
|
118
|
+
private apiKey;
|
|
119
|
+
private apiSecret;
|
|
120
|
+
private baseUrl;
|
|
121
|
+
private axiosClient;
|
|
122
|
+
constructor(apiKey: string, apiSecret: string, env: "Production" | "Staging");
|
|
123
|
+
private buildQueryString;
|
|
124
|
+
private sign;
|
|
125
|
+
private signedGet;
|
|
126
|
+
private signedPost;
|
|
127
|
+
private signedPostWithBody;
|
|
128
|
+
private signedDelete;
|
|
129
|
+
private publicGet;
|
|
130
|
+
getAccountInformation(skipLogging?: boolean): Promise<BinanceAccountInfo>;
|
|
131
|
+
getBalance(asset: string): Promise<number>;
|
|
132
|
+
getAllBalances(assets?: string[]): Promise<Record<string, number>>;
|
|
133
|
+
newOrder(params: {
|
|
134
|
+
symbol: string;
|
|
135
|
+
side: string;
|
|
136
|
+
type: string;
|
|
137
|
+
timeInForce?: string;
|
|
138
|
+
quantity?: number;
|
|
139
|
+
quoteOrderQty?: number;
|
|
140
|
+
price?: string | number;
|
|
141
|
+
}): Promise<BinanceOrderResponse>;
|
|
142
|
+
getOrder(symbol: string, orderId: number): Promise<BinanceOrderResponse>;
|
|
143
|
+
cancelOrder(symbol: string, orderId: number): Promise<any>;
|
|
144
|
+
getOpenOrders(symbol: string): Promise<BinanceOrderResponse[]>;
|
|
145
|
+
getAllOrders(symbol: string): Promise<BinanceOrderResponse[]>;
|
|
146
|
+
getMyTrades(symbol: string, orderId?: number): Promise<any[]>;
|
|
147
|
+
getRecentTrades(symbol: string, limit?: number): Promise<BinanceTradeItem[]>;
|
|
148
|
+
getExchangeInfo(): Promise<BinanceExchangeInfo>;
|
|
149
|
+
getOrderBook(symbol: string, limit?: number): Promise<BinanceOrderBook>;
|
|
150
|
+
getDepositAddress(coin: string, network?: string): Promise<BinanceDepositAddress>;
|
|
151
|
+
withdraw(params: {
|
|
152
|
+
coin: string;
|
|
153
|
+
address: string;
|
|
154
|
+
amount: number;
|
|
155
|
+
network?: string;
|
|
156
|
+
withdrawOrderId?: string;
|
|
157
|
+
addressTag?: string;
|
|
158
|
+
}): Promise<{
|
|
159
|
+
id: string;
|
|
160
|
+
}>;
|
|
161
|
+
getWithdrawHistory(params?: {
|
|
162
|
+
coin?: string;
|
|
163
|
+
withdrawOrderId?: string;
|
|
164
|
+
status?: number;
|
|
165
|
+
offset?: number;
|
|
166
|
+
limit?: number;
|
|
167
|
+
startTime?: number;
|
|
168
|
+
endTime?: number;
|
|
169
|
+
}): Promise<BinanceWithdrawHistoryItem[]>;
|
|
170
|
+
getDepositHistory(params?: {
|
|
171
|
+
coin?: string;
|
|
172
|
+
status?: number;
|
|
173
|
+
startTime?: number;
|
|
174
|
+
endTime?: number;
|
|
175
|
+
offset?: number;
|
|
176
|
+
limit?: number;
|
|
177
|
+
txId?: string;
|
|
178
|
+
}): Promise<BinanceDepositHistoryItem[]>;
|
|
179
|
+
withdrawFiat(params: {
|
|
180
|
+
currency: string;
|
|
181
|
+
apiPaymentMethod: string;
|
|
182
|
+
amount: number;
|
|
183
|
+
accountInfo: {
|
|
184
|
+
accountNumber: string;
|
|
185
|
+
[key: string]: any;
|
|
186
|
+
};
|
|
187
|
+
ext?: Record<string, any>;
|
|
188
|
+
}): Promise<BinanceFiatWithdrawResponse>;
|
|
189
|
+
getFiatOrderDetail(orderNo: string): Promise<BinanceFiatOrderDetail>;
|
|
190
|
+
private convertCryptoToBinanceDescriptor;
|
|
191
|
+
getDepositAddressForCrypto(cryptoAsset: Crypto): Promise<{
|
|
192
|
+
address: string;
|
|
193
|
+
memo?: string;
|
|
194
|
+
}>;
|
|
195
|
+
withdrawCrypto(cryptoAsset: Crypto, amount: number, address: string, memo?: string): Promise<string>;
|
|
196
|
+
withdrawMXN(amount: number, clabe: string): Promise<string>;
|
|
197
|
+
getWithdrawalHistoryByOrderId(withdrawalId: string): Promise<BinanceWithdrawHistoryItem[]>;
|
|
198
|
+
getDepositByTxHash(hash: string): Promise<BinanceDepositHistoryItem | undefined>;
|
|
199
|
+
createMarketOrder(symbol: string, amount: number, side: "BUY" | "SELL"): Promise<BinanceOrderResponse>;
|
|
200
|
+
createLimitOrder(symbol: string, side: "BUY" | "SELL", quantity: number, price: string | number, timeInForce?: string): Promise<BinanceOrderResponse>;
|
|
201
|
+
getLatestTradedPrice(symbol: string): Promise<number>;
|
|
202
|
+
getLowestAsk(symbol: string, limit?: number): Promise<number>;
|
|
203
|
+
getHighestBid(symbol: string, limit?: number): Promise<number>;
|
|
204
|
+
}
|
|
205
|
+
export declare const buildBinanceClient: () => Promise<BinanceClient>;
|
|
206
|
+
export {};
|
|
@@ -0,0 +1,398 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
12
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
13
|
+
};
|
|
14
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
+
exports.buildBinanceClient = exports.BinanceOrderStatus = void 0;
|
|
16
|
+
const crypto_1 = __importDefault(require("crypto"));
|
|
17
|
+
const common_1 = require("@riocrypto/common");
|
|
18
|
+
const axios_with_logging_1 = require("./axios-with-logging");
|
|
19
|
+
const secret_manager_client_1 = require("./secret-manager-client");
|
|
20
|
+
const mongoose_1 = __importDefault(require("mongoose"));
|
|
21
|
+
var BinanceOrderStatus;
|
|
22
|
+
(function (BinanceOrderStatus) {
|
|
23
|
+
BinanceOrderStatus["NEW"] = "NEW";
|
|
24
|
+
BinanceOrderStatus["PARTIALLY_FILLED"] = "PARTIALLY_FILLED";
|
|
25
|
+
BinanceOrderStatus["FILLED"] = "FILLED";
|
|
26
|
+
BinanceOrderStatus["CANCELED"] = "CANCELED";
|
|
27
|
+
BinanceOrderStatus["PENDING_CANCEL"] = "PENDING_CANCEL";
|
|
28
|
+
BinanceOrderStatus["REJECTED"] = "REJECTED";
|
|
29
|
+
BinanceOrderStatus["EXPIRED"] = "EXPIRED";
|
|
30
|
+
BinanceOrderStatus["EXPIRED_IN_MATCH"] = "EXPIRED_IN_MATCH";
|
|
31
|
+
})(BinanceOrderStatus = exports.BinanceOrderStatus || (exports.BinanceOrderStatus = {}));
|
|
32
|
+
class BinanceClient {
|
|
33
|
+
constructor(apiKey, apiSecret, env) {
|
|
34
|
+
this.apiKey = apiKey;
|
|
35
|
+
this.apiSecret = apiSecret;
|
|
36
|
+
this.baseUrl =
|
|
37
|
+
env === "Production"
|
|
38
|
+
? "https://api.binance.com"
|
|
39
|
+
: "https://testnet.binance.vision";
|
|
40
|
+
this.axiosClient = (0, axios_with_logging_1.buildAxiosWithLogging)();
|
|
41
|
+
}
|
|
42
|
+
buildQueryString(params) {
|
|
43
|
+
const filtered = {};
|
|
44
|
+
for (const [key, value] of Object.entries(params)) {
|
|
45
|
+
if (value !== undefined && value !== null) {
|
|
46
|
+
filtered[key] = String(value);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
return new URLSearchParams(filtered).toString();
|
|
50
|
+
}
|
|
51
|
+
sign(queryString) {
|
|
52
|
+
return crypto_1.default
|
|
53
|
+
.createHmac("sha256", this.apiSecret)
|
|
54
|
+
.update(queryString)
|
|
55
|
+
.digest("hex");
|
|
56
|
+
}
|
|
57
|
+
signedGet(path, params = {}, skipLogging = false) {
|
|
58
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
59
|
+
const allParams = Object.assign(Object.assign({}, params), { timestamp: Date.now() });
|
|
60
|
+
const queryString = this.buildQueryString(allParams);
|
|
61
|
+
const signature = this.sign(queryString);
|
|
62
|
+
const response = yield this.axiosClient.get(`${this.baseUrl}${path}?${queryString}&signature=${signature}`, { headers: { "X-MBX-APIKEY": this.apiKey }, skipLogging });
|
|
63
|
+
return response.data;
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
signedPost(path, params = {}) {
|
|
67
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
68
|
+
const allParams = Object.assign(Object.assign({}, params), { timestamp: Date.now() });
|
|
69
|
+
const queryString = this.buildQueryString(allParams);
|
|
70
|
+
const signature = this.sign(queryString);
|
|
71
|
+
const response = yield this.axiosClient.post(`${this.baseUrl}${path}?${queryString}&signature=${signature}`, null, { headers: { "X-MBX-APIKEY": this.apiKey } });
|
|
72
|
+
return response.data;
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
signedPostWithBody(path, body, queryParams = {}) {
|
|
76
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
77
|
+
const allQueryParams = Object.assign(Object.assign({}, queryParams), { timestamp: Date.now() });
|
|
78
|
+
const queryString = this.buildQueryString(allQueryParams);
|
|
79
|
+
const bodyString = JSON.stringify(body);
|
|
80
|
+
const signature = this.sign(queryString + bodyString);
|
|
81
|
+
const response = yield this.axiosClient.post(`${this.baseUrl}${path}?${queryString}&signature=${signature}`, body, {
|
|
82
|
+
headers: {
|
|
83
|
+
"X-MBX-APIKEY": this.apiKey,
|
|
84
|
+
"Content-Type": "application/json",
|
|
85
|
+
},
|
|
86
|
+
});
|
|
87
|
+
return response.data;
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
signedDelete(path, params = {}) {
|
|
91
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
92
|
+
const allParams = Object.assign(Object.assign({}, params), { timestamp: Date.now() });
|
|
93
|
+
const queryString = this.buildQueryString(allParams);
|
|
94
|
+
const signature = this.sign(queryString);
|
|
95
|
+
const response = yield this.axiosClient.delete(`${this.baseUrl}${path}?${queryString}&signature=${signature}`, { headers: { "X-MBX-APIKEY": this.apiKey } });
|
|
96
|
+
return response.data;
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
publicGet(path, params = {}) {
|
|
100
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
101
|
+
const filtered = {};
|
|
102
|
+
for (const [key, value] of Object.entries(params)) {
|
|
103
|
+
if (value !== undefined && value !== null) {
|
|
104
|
+
filtered[key] = String(value);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
const response = yield this.axiosClient.get(`${this.baseUrl}${path}`, {
|
|
108
|
+
params: filtered,
|
|
109
|
+
headers: { "X-MBX-APIKEY": this.apiKey },
|
|
110
|
+
});
|
|
111
|
+
return response.data;
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
// Account
|
|
115
|
+
getAccountInformation(skipLogging = false) {
|
|
116
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
117
|
+
return this.signedGet("/api/v3/account", {}, skipLogging);
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
getBalance(asset) {
|
|
121
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
122
|
+
const info = yield this.getAccountInformation();
|
|
123
|
+
const balance = info.balances.find((b) => b.asset === asset);
|
|
124
|
+
return (balance === null || balance === void 0 ? void 0 : balance.free) ? parseFloat(balance.free) : 0;
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
getAllBalances(assets) {
|
|
128
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
129
|
+
const info = yield this.getAccountInformation(true);
|
|
130
|
+
const result = {};
|
|
131
|
+
if (assets) {
|
|
132
|
+
const assetSet = new Set(assets);
|
|
133
|
+
info.balances
|
|
134
|
+
.filter((b) => assetSet.has(b.asset))
|
|
135
|
+
.forEach((b) => {
|
|
136
|
+
result[b.asset] = parseFloat(b.free) || 0;
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
else {
|
|
140
|
+
info.balances.forEach((b) => {
|
|
141
|
+
result[b.asset] = parseFloat(b.free) || 0;
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
console.log("Binance balances:", JSON.stringify(result));
|
|
145
|
+
return result;
|
|
146
|
+
});
|
|
147
|
+
}
|
|
148
|
+
// Trading
|
|
149
|
+
newOrder(params) {
|
|
150
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
151
|
+
return this.signedPost("/api/v3/order", params);
|
|
152
|
+
});
|
|
153
|
+
}
|
|
154
|
+
getOrder(symbol, orderId) {
|
|
155
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
156
|
+
return this.signedGet("/api/v3/order", { symbol, orderId });
|
|
157
|
+
});
|
|
158
|
+
}
|
|
159
|
+
cancelOrder(symbol, orderId) {
|
|
160
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
161
|
+
return this.signedDelete("/api/v3/order", { symbol, orderId });
|
|
162
|
+
});
|
|
163
|
+
}
|
|
164
|
+
getOpenOrders(symbol) {
|
|
165
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
166
|
+
return this.signedGet("/api/v3/openOrders", { symbol });
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
getAllOrders(symbol) {
|
|
170
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
171
|
+
return this.signedGet("/api/v3/allOrders", { symbol });
|
|
172
|
+
});
|
|
173
|
+
}
|
|
174
|
+
getMyTrades(symbol, orderId) {
|
|
175
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
176
|
+
return this.signedGet("/api/v3/myTrades", { symbol, orderId });
|
|
177
|
+
});
|
|
178
|
+
}
|
|
179
|
+
// Market data
|
|
180
|
+
getRecentTrades(symbol, limit) {
|
|
181
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
182
|
+
return this.publicGet("/api/v3/trades", { symbol, limit });
|
|
183
|
+
});
|
|
184
|
+
}
|
|
185
|
+
getExchangeInfo() {
|
|
186
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
187
|
+
return this.publicGet("/api/v3/exchangeInfo");
|
|
188
|
+
});
|
|
189
|
+
}
|
|
190
|
+
getOrderBook(symbol, limit) {
|
|
191
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
192
|
+
return this.publicGet("/api/v3/depth", { symbol, limit });
|
|
193
|
+
});
|
|
194
|
+
}
|
|
195
|
+
// Wallet
|
|
196
|
+
getDepositAddress(coin, network) {
|
|
197
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
198
|
+
return this.signedGet("/sapi/v1/capital/deposit/address", {
|
|
199
|
+
coin,
|
|
200
|
+
network,
|
|
201
|
+
});
|
|
202
|
+
});
|
|
203
|
+
}
|
|
204
|
+
withdraw(params) {
|
|
205
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
206
|
+
return this.signedPost("/sapi/v1/capital/withdraw/apply", params);
|
|
207
|
+
});
|
|
208
|
+
}
|
|
209
|
+
getWithdrawHistory(params) {
|
|
210
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
211
|
+
return this.signedGet("/sapi/v1/capital/withdraw/history", params || {});
|
|
212
|
+
});
|
|
213
|
+
}
|
|
214
|
+
getDepositHistory(params) {
|
|
215
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
216
|
+
return this.signedGet("/sapi/v1/capital/deposit/hisrec", params || {});
|
|
217
|
+
});
|
|
218
|
+
}
|
|
219
|
+
// Fiat
|
|
220
|
+
withdrawFiat(params) {
|
|
221
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
222
|
+
return this.signedPostWithBody("/sapi/v2/fiat/withdraw", params);
|
|
223
|
+
});
|
|
224
|
+
}
|
|
225
|
+
getFiatOrderDetail(orderNo) {
|
|
226
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
227
|
+
return this.signedGet("/sapi/v1/fiat/get-order-detail", { orderNo });
|
|
228
|
+
});
|
|
229
|
+
}
|
|
230
|
+
// Convenience methods
|
|
231
|
+
convertCryptoToBinanceDescriptor(cryptoAsset) {
|
|
232
|
+
switch (cryptoAsset) {
|
|
233
|
+
case common_1.Crypto.USDC:
|
|
234
|
+
return { coin: "USDC", network: "ETH" };
|
|
235
|
+
case common_1.Crypto.USDCPolygon:
|
|
236
|
+
return { coin: "USDC", network: "MATIC" };
|
|
237
|
+
case common_1.Crypto.USDCSolana:
|
|
238
|
+
return { coin: "USDC", network: "SOL" };
|
|
239
|
+
case common_1.Crypto.USDCStellar:
|
|
240
|
+
return { coin: "USDC", network: "XLM" };
|
|
241
|
+
case common_1.Crypto.USDCBase:
|
|
242
|
+
return { coin: "USDC", network: "BASE" };
|
|
243
|
+
case common_1.Crypto.USDTEthereum:
|
|
244
|
+
return { coin: "USDT", network: "ETH" };
|
|
245
|
+
case common_1.Crypto.USDTPolygon:
|
|
246
|
+
return { coin: "USDT", network: "MATIC" };
|
|
247
|
+
case common_1.Crypto.USDTTron:
|
|
248
|
+
return { coin: "USDT", network: "TRX" };
|
|
249
|
+
case common_1.Crypto.ETH:
|
|
250
|
+
return { coin: "ETH", network: "ETH" };
|
|
251
|
+
case common_1.Crypto.TRON:
|
|
252
|
+
return { coin: "TRX", network: "TRX" };
|
|
253
|
+
case common_1.Crypto.SOL:
|
|
254
|
+
return { coin: "SOL", network: "SOL" };
|
|
255
|
+
default:
|
|
256
|
+
return null;
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
getDepositAddressForCrypto(cryptoAsset) {
|
|
260
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
261
|
+
const descriptor = this.convertCryptoToBinanceDescriptor(cryptoAsset);
|
|
262
|
+
if (!descriptor) {
|
|
263
|
+
throw new Error("Unsupported crypto");
|
|
264
|
+
}
|
|
265
|
+
const response = yield this.getDepositAddress(descriptor.coin, descriptor.network);
|
|
266
|
+
return { address: response.address, memo: response.tag };
|
|
267
|
+
});
|
|
268
|
+
}
|
|
269
|
+
withdrawCrypto(cryptoAsset, amount, address, memo) {
|
|
270
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
271
|
+
if ([common_1.RioEnv.Sandbox, common_1.RioEnv.Local, common_1.RioEnv.Test].includes(process.env.RIO_ENV)) {
|
|
272
|
+
throw new Error("Binance withdraw not allowed in sandbox");
|
|
273
|
+
}
|
|
274
|
+
const descriptor = this.convertCryptoToBinanceDescriptor(cryptoAsset);
|
|
275
|
+
if (!descriptor) {
|
|
276
|
+
throw new Error("Unsupported crypto");
|
|
277
|
+
}
|
|
278
|
+
console.log("Withdrawing from Binance");
|
|
279
|
+
const withdrawOrderId = new mongoose_1.default.Types.ObjectId().toString();
|
|
280
|
+
console.log("Withdraw order id: ", withdrawOrderId);
|
|
281
|
+
try {
|
|
282
|
+
const response = yield this.withdraw({
|
|
283
|
+
coin: descriptor.coin,
|
|
284
|
+
address,
|
|
285
|
+
amount,
|
|
286
|
+
withdrawOrderId,
|
|
287
|
+
network: descriptor.network,
|
|
288
|
+
addressTag: memo,
|
|
289
|
+
});
|
|
290
|
+
console.log("Response: ", response);
|
|
291
|
+
return withdrawOrderId;
|
|
292
|
+
}
|
|
293
|
+
catch (error) {
|
|
294
|
+
console.log("Error withdrawing from Binance");
|
|
295
|
+
console.log("Error: ", error);
|
|
296
|
+
throw error;
|
|
297
|
+
}
|
|
298
|
+
});
|
|
299
|
+
}
|
|
300
|
+
withdrawMXN(amount, clabe) {
|
|
301
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
302
|
+
if ([common_1.RioEnv.Sandbox, common_1.RioEnv.Local, common_1.RioEnv.Test].includes(process.env.RIO_ENV)) {
|
|
303
|
+
throw new Error("Binance fiat withdraw not allowed in sandbox");
|
|
304
|
+
}
|
|
305
|
+
const response = yield this.withdrawFiat({
|
|
306
|
+
currency: "MXN",
|
|
307
|
+
apiPaymentMethod: "bank_transfer",
|
|
308
|
+
amount,
|
|
309
|
+
accountInfo: { accountNumber: clabe },
|
|
310
|
+
});
|
|
311
|
+
if (response.code !== "000000") {
|
|
312
|
+
throw new Error(`Fiat withdraw failed: ${response.message}`);
|
|
313
|
+
}
|
|
314
|
+
return response.data.orderId;
|
|
315
|
+
});
|
|
316
|
+
}
|
|
317
|
+
getWithdrawalHistoryByOrderId(withdrawalId) {
|
|
318
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
319
|
+
console.log("Withdrawal id: ", withdrawalId);
|
|
320
|
+
return this.getWithdrawHistory({ withdrawOrderId: withdrawalId });
|
|
321
|
+
});
|
|
322
|
+
}
|
|
323
|
+
getDepositByTxHash(hash) {
|
|
324
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
325
|
+
const response = yield this.getDepositHistory({ txId: hash });
|
|
326
|
+
return response.find((deposit) => deposit.txId === hash);
|
|
327
|
+
});
|
|
328
|
+
}
|
|
329
|
+
createMarketOrder(symbol, amount, side) {
|
|
330
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
331
|
+
return this.newOrder({
|
|
332
|
+
symbol,
|
|
333
|
+
side,
|
|
334
|
+
type: "MARKET",
|
|
335
|
+
quantity: side === "SELL" ? amount : undefined,
|
|
336
|
+
quoteOrderQty: side === "BUY" ? amount : undefined,
|
|
337
|
+
});
|
|
338
|
+
});
|
|
339
|
+
}
|
|
340
|
+
createLimitOrder(symbol, side, quantity, price, timeInForce = "GTC") {
|
|
341
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
342
|
+
return this.newOrder({
|
|
343
|
+
symbol,
|
|
344
|
+
side,
|
|
345
|
+
type: "LIMIT",
|
|
346
|
+
timeInForce,
|
|
347
|
+
quantity,
|
|
348
|
+
price,
|
|
349
|
+
});
|
|
350
|
+
});
|
|
351
|
+
}
|
|
352
|
+
getLatestTradedPrice(symbol) {
|
|
353
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
354
|
+
const trades = yield this.getRecentTrades(symbol);
|
|
355
|
+
return Number(trades[0].price);
|
|
356
|
+
});
|
|
357
|
+
}
|
|
358
|
+
getLowestAsk(symbol, limit = 5) {
|
|
359
|
+
var _a, _b;
|
|
360
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
361
|
+
const orderBook = yield this.getOrderBook(symbol, limit);
|
|
362
|
+
const lowestAsk = (_b = (_a = orderBook.asks) === null || _a === void 0 ? void 0 : _a[0]) === null || _b === void 0 ? void 0 : _b[0];
|
|
363
|
+
if (!lowestAsk) {
|
|
364
|
+
throw new Error("No lowest ask found");
|
|
365
|
+
}
|
|
366
|
+
return parseFloat(lowestAsk);
|
|
367
|
+
});
|
|
368
|
+
}
|
|
369
|
+
getHighestBid(symbol, limit = 5) {
|
|
370
|
+
var _a, _b;
|
|
371
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
372
|
+
const orderBook = yield this.getOrderBook(symbol, limit);
|
|
373
|
+
const highestBid = (_b = (_a = orderBook.bids) === null || _a === void 0 ? void 0 : _a[0]) === null || _b === void 0 ? void 0 : _b[0];
|
|
374
|
+
if (!highestBid) {
|
|
375
|
+
throw new Error("No highest bid found");
|
|
376
|
+
}
|
|
377
|
+
return parseFloat(highestBid);
|
|
378
|
+
});
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
const buildBinanceClient = () => __awaiter(void 0, void 0, void 0, function* () {
|
|
382
|
+
const BINANCE_API_KEY = yield secret_manager_client_1.secretManagerClient.getSecretValue("BINANCE_API_KEY");
|
|
383
|
+
if (!BINANCE_API_KEY) {
|
|
384
|
+
throw new common_1.SecretManagerError();
|
|
385
|
+
}
|
|
386
|
+
const BINANCE_API_SECRET = yield secret_manager_client_1.secretManagerClient.getSecretValue("BINANCE_API_SECRET");
|
|
387
|
+
if (!BINANCE_API_SECRET) {
|
|
388
|
+
throw new common_1.SecretManagerError();
|
|
389
|
+
}
|
|
390
|
+
const env = [
|
|
391
|
+
common_1.RioEnv.Production,
|
|
392
|
+
common_1.RioEnv.Development,
|
|
393
|
+
].includes(process.env.RIO_ENV)
|
|
394
|
+
? "Production"
|
|
395
|
+
: "Staging";
|
|
396
|
+
return new BinanceClient(BINANCE_API_KEY, BINANCE_API_SECRET, env);
|
|
397
|
+
});
|
|
398
|
+
exports.buildBinanceClient = buildBinanceClient;
|
package/build/index.d.ts
CHANGED
|
@@ -137,6 +137,7 @@ export * from "./clients/bitso-client";
|
|
|
137
137
|
export * from "./clients/circle-client";
|
|
138
138
|
export * from "./clients/coincover-client";
|
|
139
139
|
export * from "./clients/google-sheets-api-client";
|
|
140
|
+
export * from "./clients/binance-client";
|
|
140
141
|
export * from "./helpers/get-user-helper";
|
|
141
142
|
export * from "./helpers/get-processor-fees";
|
|
142
143
|
export * from "./helpers/get-network-fees";
|
package/build/index.js
CHANGED
|
@@ -153,6 +153,7 @@ __exportStar(require("./clients/bitso-client"), exports);
|
|
|
153
153
|
__exportStar(require("./clients/circle-client"), exports);
|
|
154
154
|
__exportStar(require("./clients/coincover-client"), exports);
|
|
155
155
|
__exportStar(require("./clients/google-sheets-api-client"), exports);
|
|
156
|
+
__exportStar(require("./clients/binance-client"), exports);
|
|
156
157
|
__exportStar(require("./helpers/get-user-helper"), exports);
|
|
157
158
|
__exportStar(require("./helpers/get-processor-fees"), exports);
|
|
158
159
|
__exportStar(require("./helpers/get-network-fees"), exports);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@riocrypto/common-server",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.2749",
|
|
4
4
|
"description": "",
|
|
5
5
|
"main": "./build/index.js",
|
|
6
6
|
"types": "./build/index.d.ts",
|
|
@@ -28,7 +28,7 @@
|
|
|
28
28
|
"@google-cloud/secret-manager": "^5.3.0",
|
|
29
29
|
"@google-cloud/storage": "^6.9.5",
|
|
30
30
|
"@hyperdx/node-opentelemetry": "^0.7.0",
|
|
31
|
-
"@riocrypto/common": "^1.0.
|
|
31
|
+
"@riocrypto/common": "^1.0.2541",
|
|
32
32
|
"@slack/web-api": "^7.9.2",
|
|
33
33
|
"@types/express": "^4.17.13",
|
|
34
34
|
"axios": "^1.7.4",
|