Merge pull request #254 from tiagosiebler/typesamdtraces
v3.5.8: feat() easier env-controlled HTTP traces. Add missing properties for asset v5 types.
This commit is contained in:
10
README.md
10
README.md
@@ -305,9 +305,11 @@ See [websocket-client.ts](./src/websocket-client.ts) for further information.
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Customise Logging
|
## Logging
|
||||||
|
|
||||||
Pass a custom logger which supports the log methods `silly`, `debug`, `notice`, `info`, `warning` and `error`, or override methods from the default logger as desired.
|
### Customise logging
|
||||||
|
|
||||||
|
Pass a custom logger (or mutate the imported DefaultLogger class) which supports the log methods `silly`, `debug`, `notice`, `info`, `warning` and `error`, or override methods from the default logger as desired, as in the example below:
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
const { WebsocketClient, DefaultLogger } = require('bybit-api');
|
const { WebsocketClient, DefaultLogger } = require('bybit-api');
|
||||||
@@ -321,6 +323,10 @@ const customLogger = {
|
|||||||
const ws = new WebsocketClient({ key: 'xxx', secret: 'yyy' }, customLogger);
|
const ws = new WebsocketClient({ key: 'xxx', secret: 'yyy' }, customLogger);
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Debug HTTP requests
|
||||||
|
|
||||||
|
In rare situations, you may want to see the raw HTTP requets being built as well as the API response. These can be enabled by setting the `BYBITTRACE` env var to `true`.
|
||||||
|
|
||||||
## Browser Usage
|
## Browser Usage
|
||||||
|
|
||||||
Build a bundle using webpack:
|
Build a bundle using webpack:
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "bybit-api",
|
"name": "bybit-api",
|
||||||
"version": "3.5.7",
|
"version": "3.5.8",
|
||||||
"description": "Complete & robust Node.js SDK for Bybit's REST APIs and WebSockets, with TypeScript & strong end to end tests.",
|
"description": "Complete & robust Node.js SDK for Bybit's REST APIs and WebSockets, with TypeScript & strong end to end tests.",
|
||||||
"main": "lib/index.js",
|
"main": "lib/index.js",
|
||||||
"types": "lib/index.d.ts",
|
"types": "lib/index.d.ts",
|
||||||
|
|||||||
@@ -39,6 +39,7 @@ export interface GetAccountCoinBalanceParamsV5 {
|
|||||||
accountType: AccountTypeV5;
|
accountType: AccountTypeV5;
|
||||||
coin: string;
|
coin: string;
|
||||||
withBonus?: number;
|
withBonus?: number;
|
||||||
|
withTransferSafeAmount?: 0 | 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface GetInternalTransferParamsV5 {
|
export interface GetInternalTransferParamsV5 {
|
||||||
@@ -119,6 +120,7 @@ export interface WithdrawParamsV5 {
|
|||||||
address: string;
|
address: string;
|
||||||
tag?: string;
|
tag?: string;
|
||||||
amount: string;
|
amount: string;
|
||||||
|
timestamp: number;
|
||||||
forceChain?: number;
|
forceChain?: number;
|
||||||
accountType?: 'SPOT' | 'FUND';
|
accountType?: 'SPOT' | 'FUND';
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,11 +11,12 @@ import {
|
|||||||
} from './requestUtils';
|
} from './requestUtils';
|
||||||
import { signMessage } from './node-support';
|
import { signMessage } from './node-support';
|
||||||
|
|
||||||
if (
|
const ENABLE_HTTP_TRACE =
|
||||||
typeof process === 'object' &&
|
typeof process === 'object' &&
|
||||||
typeof process.env === 'object' &&
|
typeof process.env === 'object' &&
|
||||||
process.env.BYBITTRACE
|
process.env.BYBITTRACE;
|
||||||
) {
|
|
||||||
|
if (ENABLE_HTTP_TRACE) {
|
||||||
// axios.interceptors.request.use((request) => {
|
// axios.interceptors.request.use((request) => {
|
||||||
// console.log(
|
// console.log(
|
||||||
// new Date(),
|
// new Date(),
|
||||||
@@ -209,7 +210,7 @@ export default abstract class BaseRestClient {
|
|||||||
if (this.options.syncTimeBeforePrivateRequests) {
|
if (this.options.syncTimeBeforePrivateRequests) {
|
||||||
this.timeOffset = await this.fetchTimeOffset();
|
this.timeOffset = await this.fetchTimeOffset();
|
||||||
}
|
}
|
||||||
|
|
||||||
return this.signRequest(params || {}, method, signMethod);
|
return this.signRequest(params || {}, method, signMethod);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -314,6 +315,10 @@ export default abstract class BaseRestClient {
|
|||||||
isPublicApi,
|
isPublicApi,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
if (ENABLE_HTTP_TRACE) {
|
||||||
|
console.log('full request: ', options);
|
||||||
|
}
|
||||||
|
|
||||||
// Dispatch request
|
// Dispatch request
|
||||||
return axios(options)
|
return axios(options)
|
||||||
.then((response) => {
|
.then((response) => {
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ describe('Private Contract REST API GET Endpoints', () => {
|
|||||||
const symbol = 'BTCUSDT';
|
const symbol = 'BTCUSDT';
|
||||||
it('getHistoricOrders()', async () => {
|
it('getHistoricOrders()', async () => {
|
||||||
expect(await api.getHistoricOrders({ symbol })).toMatchObject(
|
expect(await api.getHistoricOrders({ symbol })).toMatchObject(
|
||||||
successResponseObjectV3()
|
successResponseObjectV3(),
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -29,7 +29,7 @@ describe('Private Contract REST API GET Endpoints', () => {
|
|||||||
'eyJza2lwX2xvY2FsX3N5bWJvbCI6ZmFsc2UsInBhZ2VfdG9rZW4iOiJleUpOSWpwN0luQnJJanA3SWtJaU9pSktSRmt6VG1wcmVFMXFaM2xNVkUwMFQwUlpkRTVFUlRKTmFURm9UakpPYWt4WFVUSk9lbFY1VDBSU2FrMVhXVEJOZHowOUluMHNJbDl6YTE4aU9uc2lRaUk2SWtaNFltMWFZMDV6TUROek1rNTZXVFZOVkVrMFRXa3dlazlFWnpKTVZGRjRUbXBKZEZsVVpHcFplVEZyVG1wak1VMXFaekJaZWtadFRrUk5QU0o5TENKZmRYTmZJanA3SWtJaU9pSkJLMmt2WkZGRlJ5SjlmWDA9In0=';
|
'eyJza2lwX2xvY2FsX3N5bWJvbCI6ZmFsc2UsInBhZ2VfdG9rZW4iOiJleUpOSWpwN0luQnJJanA3SWtJaU9pSktSRmt6VG1wcmVFMXFaM2xNVkUwMFQwUlpkRTVFUlRKTmFURm9UakpPYWt4WFVUSk9lbFY1VDBSU2FrMVhXVEJOZHowOUluMHNJbDl6YTE4aU9uc2lRaUk2SWtaNFltMWFZMDV6TUROek1rNTZXVFZOVkVrMFRXa3dlazlFWnpKTVZGRjRUbXBKZEZsVVpHcFplVEZyVG1wak1VMXFaekJaZWtadFRrUk5QU0o5TENKZmRYTmZJanA3SWtJaU9pSkJLMmt2WkZGRlJ5SjlmWDA9In0=';
|
||||||
|
|
||||||
expect(
|
expect(
|
||||||
await api.getHistoricOrders({ symbol, cursor, limit: 1 })
|
await api.getHistoricOrders({ symbol, cursor, limit: 1 }),
|
||||||
).toMatchObject({
|
).toMatchObject({
|
||||||
// retCode: API_ERROR_CODE.DB_ERROR_WRONG_CURSOR,
|
// retCode: API_ERROR_CODE.DB_ERROR_WRONG_CURSOR,
|
||||||
...successResponseObjectV3(),
|
...successResponseObjectV3(),
|
||||||
@@ -43,7 +43,7 @@ describe('Private Contract REST API GET Endpoints', () => {
|
|||||||
const cursor = orders.result.nextPageCursor;
|
const cursor = orders.result.nextPageCursor;
|
||||||
|
|
||||||
expect(
|
expect(
|
||||||
await api.getHistoricOrders({ symbol, cursor, limit: 1 })
|
await api.getHistoricOrders({ symbol, cursor, limit: 1 }),
|
||||||
).toMatchObject({
|
).toMatchObject({
|
||||||
...successResponseObjectV3(),
|
...successResponseObjectV3(),
|
||||||
retMsg: 'OK',
|
retMsg: 'OK',
|
||||||
@@ -51,26 +51,27 @@ describe('Private Contract REST API GET Endpoints', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('getActiveOrders()', async () => {
|
it('getActiveOrders()', async () => {
|
||||||
expect(await api.getActiveOrders({ symbol })).toMatchObject(
|
expect(await api.getActiveOrders({ symbol })).toMatchObject({
|
||||||
successResponseObjectV3()
|
...successResponseObjectV3(),
|
||||||
);
|
retMsg: 'OK',
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('getPositions()', async () => {
|
it('getPositions()', async () => {
|
||||||
expect(await api.getPositions({ symbol })).toMatchObject(
|
expect(await api.getPositions({ symbol })).toMatchObject(
|
||||||
successResponseObjectV3()
|
successResponseObjectV3(),
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('getUserExecutionHistory()', async () => {
|
it('getUserExecutionHistory()', async () => {
|
||||||
expect(await api.getUserExecutionHistory({ symbol })).toMatchObject(
|
expect(await api.getUserExecutionHistory({ symbol })).toMatchObject(
|
||||||
successResponseObjectV3()
|
successResponseObjectV3(),
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('getClosedProfitAndLoss()', async () => {
|
it('getClosedProfitAndLoss()', async () => {
|
||||||
expect(await api.getClosedProfitAndLoss({ symbol })).toMatchObject(
|
expect(await api.getClosedProfitAndLoss({ symbol })).toMatchObject(
|
||||||
successResponseObjectV3()
|
successResponseObjectV3(),
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -88,13 +89,13 @@ describe('Private Contract REST API GET Endpoints', () => {
|
|||||||
|
|
||||||
it('getTradingFeeRate()', async () => {
|
it('getTradingFeeRate()', async () => {
|
||||||
expect(await api.getTradingFeeRate()).toMatchObject(
|
expect(await api.getTradingFeeRate()).toMatchObject(
|
||||||
successResponseObjectV3()
|
successResponseObjectV3(),
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('getWalletFundRecords()', async () => {
|
it('getWalletFundRecords()', async () => {
|
||||||
expect(await api.getWalletFundRecords()).toMatchObject(
|
expect(await api.getWalletFundRecords()).toMatchObject(
|
||||||
successResponseObjectV3()
|
successResponseObjectV3(),
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -46,7 +46,7 @@ describe('Private WRITE V5 REST API Endpoints', () => {
|
|||||||
side: orderSide,
|
side: orderSide,
|
||||||
qty: '1',
|
qty: '1',
|
||||||
positionIdx: 1,
|
positionIdx: 1,
|
||||||
})
|
}),
|
||||||
).toMatchObject({
|
).toMatchObject({
|
||||||
// ...successResponseObjectV3(),
|
// ...successResponseObjectV3(),
|
||||||
// retMsg: '',
|
// retMsg: '',
|
||||||
@@ -61,7 +61,7 @@ describe('Private WRITE V5 REST API Endpoints', () => {
|
|||||||
symbol: linearSymbol,
|
symbol: linearSymbol,
|
||||||
qty: '2',
|
qty: '2',
|
||||||
orderId: fakeOrderId,
|
orderId: fakeOrderId,
|
||||||
})
|
}),
|
||||||
).toMatchObject({
|
).toMatchObject({
|
||||||
// ...successResponseObjectV3(),
|
// ...successResponseObjectV3(),
|
||||||
// retMsg: '',
|
// retMsg: '',
|
||||||
@@ -75,7 +75,7 @@ describe('Private WRITE V5 REST API Endpoints', () => {
|
|||||||
category: 'linear',
|
category: 'linear',
|
||||||
symbol: linearSymbol,
|
symbol: linearSymbol,
|
||||||
orderId: fakeOrderId,
|
orderId: fakeOrderId,
|
||||||
})
|
}),
|
||||||
).toMatchObject({
|
).toMatchObject({
|
||||||
// ...successResponseObjectV3(),
|
// ...successResponseObjectV3(),
|
||||||
// retMsg: '',
|
// retMsg: '',
|
||||||
@@ -88,7 +88,7 @@ describe('Private WRITE V5 REST API Endpoints', () => {
|
|||||||
await api.cancelAllOrders({
|
await api.cancelAllOrders({
|
||||||
category: 'linear',
|
category: 'linear',
|
||||||
settleCoin: settleCoin,
|
settleCoin: settleCoin,
|
||||||
})
|
}),
|
||||||
).toMatchObject({
|
).toMatchObject({
|
||||||
...successResponseObjectV3(),
|
...successResponseObjectV3(),
|
||||||
});
|
});
|
||||||
@@ -122,7 +122,7 @@ describe('Private WRITE V5 REST API Endpoints', () => {
|
|||||||
side: orderSide,
|
side: orderSide,
|
||||||
symbol: optionsSymbol,
|
symbol: optionsSymbol,
|
||||||
},
|
},
|
||||||
])
|
]),
|
||||||
).toMatchObject({
|
).toMatchObject({
|
||||||
...successResponseObjectV3(),
|
...successResponseObjectV3(),
|
||||||
});
|
});
|
||||||
@@ -141,7 +141,7 @@ describe('Private WRITE V5 REST API Endpoints', () => {
|
|||||||
qty: '4',
|
qty: '4',
|
||||||
symbol: optionsSymbol,
|
symbol: optionsSymbol,
|
||||||
},
|
},
|
||||||
])
|
]),
|
||||||
).toMatchObject({
|
).toMatchObject({
|
||||||
...successResponseObjectV3(),
|
...successResponseObjectV3(),
|
||||||
});
|
});
|
||||||
@@ -158,7 +158,7 @@ describe('Private WRITE V5 REST API Endpoints', () => {
|
|||||||
orderLinkId: 'customOrderId2',
|
orderLinkId: 'customOrderId2',
|
||||||
symbol: optionsSymbol,
|
symbol: optionsSymbol,
|
||||||
},
|
},
|
||||||
])
|
]),
|
||||||
).toMatchObject({
|
).toMatchObject({
|
||||||
...successResponseObjectV3(),
|
...successResponseObjectV3(),
|
||||||
});
|
});
|
||||||
@@ -171,7 +171,7 @@ describe('Private WRITE V5 REST API Endpoints', () => {
|
|||||||
// ...successResponseObjectV3(),
|
// ...successResponseObjectV3(),
|
||||||
// retMsg: '',
|
// retMsg: '',
|
||||||
retCode: API_ERROR_CODE.V5_API_KEY_PERMISSION_DENIED,
|
retCode: API_ERROR_CODE.V5_API_KEY_PERMISSION_DENIED,
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -184,7 +184,7 @@ describe('Private WRITE V5 REST API Endpoints', () => {
|
|||||||
buyLeverage: '5',
|
buyLeverage: '5',
|
||||||
sellLeverage: '5',
|
sellLeverage: '5',
|
||||||
symbol: linearSymbol,
|
symbol: linearSymbol,
|
||||||
})
|
}),
|
||||||
).toMatchObject({
|
).toMatchObject({
|
||||||
// ...successResponseObjectV3(),
|
// ...successResponseObjectV3(),
|
||||||
// retMsg: '',
|
// retMsg: '',
|
||||||
@@ -201,7 +201,7 @@ describe('Private WRITE V5 REST API Endpoints', () => {
|
|||||||
symbol: linearSymbol,
|
symbol: linearSymbol,
|
||||||
// isolated
|
// isolated
|
||||||
tradeMode: 1,
|
tradeMode: 1,
|
||||||
})
|
}),
|
||||||
).toMatchObject({
|
).toMatchObject({
|
||||||
// ...successResponseObjectV3(),
|
// ...successResponseObjectV3(),
|
||||||
// retMsg: '',
|
// retMsg: '',
|
||||||
@@ -215,7 +215,7 @@ describe('Private WRITE V5 REST API Endpoints', () => {
|
|||||||
category: 'linear',
|
category: 'linear',
|
||||||
symbol: linearSymbol,
|
symbol: linearSymbol,
|
||||||
tpSlMode: 'Full',
|
tpSlMode: 'Full',
|
||||||
})
|
}),
|
||||||
).toMatchObject({
|
).toMatchObject({
|
||||||
// ...successResponseObjectV3(),
|
// ...successResponseObjectV3(),
|
||||||
// retMsg: '',
|
// retMsg: '',
|
||||||
@@ -230,7 +230,7 @@ describe('Private WRITE V5 REST API Endpoints', () => {
|
|||||||
// both sides
|
// both sides
|
||||||
mode: 3,
|
mode: 3,
|
||||||
coin: settleCoin,
|
coin: settleCoin,
|
||||||
})
|
}),
|
||||||
).toMatchObject({
|
).toMatchObject({
|
||||||
...successResponseObjectV3(),
|
...successResponseObjectV3(),
|
||||||
});
|
});
|
||||||
@@ -243,7 +243,7 @@ describe('Private WRITE V5 REST API Endpoints', () => {
|
|||||||
positionIdx: 1,
|
positionIdx: 1,
|
||||||
riskId: 1,
|
riskId: 1,
|
||||||
symbol: linearSymbol,
|
symbol: linearSymbol,
|
||||||
})
|
}),
|
||||||
).toMatchObject({
|
).toMatchObject({
|
||||||
// ...successResponseObjectV3(),
|
// ...successResponseObjectV3(),
|
||||||
// retMsg: '',
|
// retMsg: '',
|
||||||
@@ -260,7 +260,7 @@ describe('Private WRITE V5 REST API Endpoints', () => {
|
|||||||
slSize: '100',
|
slSize: '100',
|
||||||
slTriggerBy: 'LastPrice',
|
slTriggerBy: 'LastPrice',
|
||||||
stopLoss: '25000',
|
stopLoss: '25000',
|
||||||
})
|
}),
|
||||||
).toMatchObject({
|
).toMatchObject({
|
||||||
// ...successResponseObjectV3(),
|
// ...successResponseObjectV3(),
|
||||||
// retMsg: '',
|
// retMsg: '',
|
||||||
@@ -275,7 +275,7 @@ describe('Private WRITE V5 REST API Endpoints', () => {
|
|||||||
autoAddMargin: 0,
|
autoAddMargin: 0,
|
||||||
symbol: linearSymbol,
|
symbol: linearSymbol,
|
||||||
positionIdx: 0,
|
positionIdx: 0,
|
||||||
})
|
}),
|
||||||
).toMatchObject({
|
).toMatchObject({
|
||||||
// ...successResponseObjectV3(),
|
// ...successResponseObjectV3(),
|
||||||
// retMsg: '',
|
// retMsg: '',
|
||||||
@@ -301,7 +301,7 @@ describe('Private WRITE V5 REST API Endpoints', () => {
|
|||||||
frozenPeriod: '1',
|
frozenPeriod: '1',
|
||||||
qtyLimit: '1',
|
qtyLimit: '1',
|
||||||
window: '1',
|
window: '1',
|
||||||
})
|
}),
|
||||||
).toMatchObject({
|
).toMatchObject({
|
||||||
// ...successResponseObjectV3(),
|
// ...successResponseObjectV3(),
|
||||||
// retMsg: '',
|
// retMsg: '',
|
||||||
@@ -326,8 +326,8 @@ describe('Private WRITE V5 REST API Endpoints', () => {
|
|||||||
settleCoin,
|
settleCoin,
|
||||||
'100',
|
'100',
|
||||||
'SPOT',
|
'SPOT',
|
||||||
'CONTRACT'
|
'CONTRACT',
|
||||||
)
|
),
|
||||||
).toMatchObject({
|
).toMatchObject({
|
||||||
// ...successResponseObjectV3(),
|
// ...successResponseObjectV3(),
|
||||||
// retMsg: '',
|
// retMsg: '',
|
||||||
@@ -351,7 +351,7 @@ describe('Private WRITE V5 REST API Endpoints', () => {
|
|||||||
toAccountType: 'CONTRACT',
|
toAccountType: 'CONTRACT',
|
||||||
toMemberId: 2,
|
toMemberId: 2,
|
||||||
transferId: fakeTransferId,
|
transferId: fakeTransferId,
|
||||||
})
|
}),
|
||||||
).toMatchObject({
|
).toMatchObject({
|
||||||
// ...successResponseObjectV3(),
|
// ...successResponseObjectV3(),
|
||||||
// retMsg: '',
|
// retMsg: '',
|
||||||
@@ -366,7 +366,8 @@ describe('Private WRITE V5 REST API Endpoints', () => {
|
|||||||
amount: '100',
|
amount: '100',
|
||||||
chain: 'TRC20',
|
chain: 'TRC20',
|
||||||
coin: settleCoin,
|
coin: settleCoin,
|
||||||
})
|
timestamp: Date.now(),
|
||||||
|
}),
|
||||||
).toMatchObject({
|
).toMatchObject({
|
||||||
// ...successResponseObjectV3(),
|
// ...successResponseObjectV3(),
|
||||||
// retMsg: '',
|
// retMsg: '',
|
||||||
@@ -391,7 +392,7 @@ describe('Private WRITE V5 REST API Endpoints', () => {
|
|||||||
username: 'sub1account',
|
username: 'sub1account',
|
||||||
switch: 1,
|
switch: 1,
|
||||||
note: 'created via e2e test',
|
note: 'created via e2e test',
|
||||||
})
|
}),
|
||||||
).toMatchObject({
|
).toMatchObject({
|
||||||
// ...successResponseObjectV3(),
|
// ...successResponseObjectV3(),
|
||||||
// retMsg: '',
|
// retMsg: '',
|
||||||
@@ -421,7 +422,7 @@ describe('Private WRITE V5 REST API Endpoints', () => {
|
|||||||
await api.purchaseSpotLeveragedToken({
|
await api.purchaseSpotLeveragedToken({
|
||||||
amount: '100',
|
amount: '100',
|
||||||
ltCoin: leverageToken.ltCoin,
|
ltCoin: leverageToken.ltCoin,
|
||||||
})
|
}),
|
||||||
).toMatchObject({
|
).toMatchObject({
|
||||||
// ...successResponseObjectV3(),
|
// ...successResponseObjectV3(),
|
||||||
retCode: API_ERROR_CODE.SPOT_LEVERAGE_QUIZ_REQUIRED,
|
retCode: API_ERROR_CODE.SPOT_LEVERAGE_QUIZ_REQUIRED,
|
||||||
@@ -434,7 +435,7 @@ describe('Private WRITE V5 REST API Endpoints', () => {
|
|||||||
await api.redeemSpotLeveragedToken({
|
await api.redeemSpotLeveragedToken({
|
||||||
quantity: '100',
|
quantity: '100',
|
||||||
ltCoin: leverageToken.ltCoin,
|
ltCoin: leverageToken.ltCoin,
|
||||||
})
|
}),
|
||||||
).toMatchObject({
|
).toMatchObject({
|
||||||
// ...successResponseObjectV3(),
|
// ...successResponseObjectV3(),
|
||||||
retCode: API_ERROR_CODE.SPOT_LEVERAGE_TOKEN_INSUFFICIENT_BALANCE,
|
retCode: API_ERROR_CODE.SPOT_LEVERAGE_TOKEN_INSUFFICIENT_BALANCE,
|
||||||
|
|||||||
Reference in New Issue
Block a user