bybit-p2p-sdk 1.0.0
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.
- package/LICENSE +21 -0
- package/README.md +151 -0
- package/dist/client.d.ts +19 -0
- package/dist/client.js +194 -0
- package/dist/constants.d.ts +6 -0
- package/dist/constants.js +34 -0
- package/dist/index.d.ts +119 -0
- package/dist/index.js +134 -0
- package/dist/types.d.ts +122 -0
- package/dist/types.js +4 -0
- package/package.json +49 -0
- package/src/client.ts +190 -0
- package/src/constants.ts +37 -0
- package/src/index.ts +136 -0
- package/src/types.ts +134 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Aadam Bala Idriss (ENGR ABI)
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
# bybit-p2p-sdk
|
|
2
|
+
|
|
3
|
+
[](LICENSE)
|
|
4
|
+
[](https://www.typescriptlang.org/)
|
|
5
|
+
|
|
6
|
+
## Bybit P2P API SDK for Node.js (TypeScript)
|
|
7
|
+
|
|
8
|
+
`bybit-p2p-sdk` is the unofficial Node.js SDK for Bybit's P2P API, enabling seamless integration of your software solutions with Bybit's [P2P trading platform](https://www.bybit.com/en/promo/global/p2p-introduce).
|
|
9
|
+
|
|
10
|
+
- **Full Type Support**: Written in TypeScript with complete definitions.
|
|
11
|
+
- **Easy Authentication**: Handles HMAC signature generation automatically.
|
|
12
|
+
- **Actively Maintained**: Supports latest V5 P2P endpoints.
|
|
13
|
+
|
|
14
|
+
## Features
|
|
15
|
+
|
|
16
|
+
This SDK implements all key methods available for the P2P API:
|
|
17
|
+
|
|
18
|
+
- Create, edit, delete, activate advertisements
|
|
19
|
+
- Get pending orders, mark orders as paid, release assets
|
|
20
|
+
- Get, send text messages, and upload files to chat
|
|
21
|
+
- Get all public advertisements
|
|
22
|
+
- And more!
|
|
23
|
+
|
|
24
|
+
## Installation
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
npm install bybit-p2p-sdk
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## Usage
|
|
31
|
+
|
|
32
|
+
### TypeScript
|
|
33
|
+
|
|
34
|
+
```typescript
|
|
35
|
+
import { P2P } from 'bybit-p2p-sdk';
|
|
36
|
+
|
|
37
|
+
const client = new P2P({
|
|
38
|
+
testnet: false, // Set to true for testnet
|
|
39
|
+
apiKey: "YOUR_API_KEY",
|
|
40
|
+
apiSecret: "YOUR_API_SECRET"
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
// 1. Get current balance
|
|
44
|
+
const balance = await client.getCurrentBalance({ accountType: "FUND", coin: "USDT" });
|
|
45
|
+
console.log(balance);
|
|
46
|
+
|
|
47
|
+
// 2. Get pending orders
|
|
48
|
+
const orders = await client.getPendingOrders({ page: 1, size: 10 });
|
|
49
|
+
console.log(orders);
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
### Configuration
|
|
53
|
+
The `P2P` constructor accepts the following config:
|
|
54
|
+
|
|
55
|
+
- `testnet`: `boolean` (default: false)
|
|
56
|
+
- `apiKey`: `string`
|
|
57
|
+
- `apiSecret`: `string`
|
|
58
|
+
- `recvWindow`: `number` (default: 20000) - Time window for request validity
|
|
59
|
+
|
|
60
|
+
## Documentation
|
|
61
|
+
|
|
62
|
+
This library provides a direct wrapper around Bybit's P2P REST API.
|
|
63
|
+
Official Documentation: [P2P API Guide](https://bybit-exchange.github.io/docs/p2p/guide)
|
|
64
|
+
|
|
65
|
+
### API Method Mapping
|
|
66
|
+
|
|
67
|
+
Here is how the SDK methods map to the API endpoints:
|
|
68
|
+
|
|
69
|
+
#### Advertisements
|
|
70
|
+
| SDK Method | API Endpoint | Description |
|
|
71
|
+
| --- | --- | --- |
|
|
72
|
+
| `getOnlineAds()` | [/v5/p2p/item/online](https://bybit-exchange.github.io/docs/p2p/ad/online-ad-list) | Get public online ads |
|
|
73
|
+
| `postNewAd()` | [/v5/p2p/item/create](https://bybit-exchange.github.io/docs/p2p/ad/post-new-ad) | Post a new ad |
|
|
74
|
+
| `removeAd()` | [/v5/p2p/item/cancel](https://bybit-exchange.github.io/docs/p2p/ad/remove-ad) | Cancel an ad |
|
|
75
|
+
| `updateAd()` | [/v5/p2p/item/update](https://bybit-exchange.github.io/docs/p2p/ad/update-list-ad) | Update or relist an ad |
|
|
76
|
+
| `getAdsList()` | [/v5/p2p/item/personal/list](https://bybit-exchange.github.io/docs/p2p/ad/ad-list) | Get my ads list |
|
|
77
|
+
| `getAdDetails()` | [/v5/p2p/item/info](https://bybit-exchange.github.io/docs/p2p/ad/ad-detail) | Get ad details |
|
|
78
|
+
|
|
79
|
+
#### Orders
|
|
80
|
+
| SDK Method | API Endpoint | Description |
|
|
81
|
+
| --- | --- | --- |
|
|
82
|
+
| `getOrders()` | [/v5/p2p/order/simplifyList](https://bybit-exchange.github.io/docs/p2p/order/order-list) | Get all orders |
|
|
83
|
+
| `getOrderDetails()` | [/v5/p2p/order/info](https://bybit-exchange.github.io/docs/p2p/order/order-detail) | Get order details |
|
|
84
|
+
| `getPendingOrders()` | [/v5/p2p/order/pending/simplifyList](https://bybit-exchange.github.io/docs/p2p/order/pending-order) | Get pending orders |
|
|
85
|
+
| `markAsPaid()` | [/v5/p2p/order/pay](https://bybit-exchange.github.io/docs/p2p/order/mark-order-as-paid) | Mark order as paid |
|
|
86
|
+
| `releaseAssets()` | [/v5/p2p/order/finish](https://bybit-exchange.github.io/docs/p2p/order/release-digital-asset) | Release crypto to buyer |
|
|
87
|
+
| `sendChatMessage()` | [/v5/p2p/order/message/send](https://bybit-exchange.github.io/docs/p2p/order/send-chat-msg) | Send a chat message |
|
|
88
|
+
| `uploadChatFile()` | [/v5/p2p/oss/upload_file](https://bybit-exchange.github.io/docs/p2p/order/upload-chat-file) | Upload a file to chat |
|
|
89
|
+
| `getChatMessages()` | [/v5/p2p/order/message/listpage](https://bybit-exchange.github.io/docs/p2p/order/chat-msg) | Get chat history |
|
|
90
|
+
|
|
91
|
+
#### User Info
|
|
92
|
+
| SDK Method | API Endpoint | Description |
|
|
93
|
+
| --- | --- | --- |
|
|
94
|
+
| `getAccountInformation()` | [/v5/p2p/user/personal/info](https://bybit-exchange.github.io/docs/p2p/user/acct-info) | Get my account info |
|
|
95
|
+
| `getCounterpartyInfo()` | [/v5/p2p/user/order/personal/info](https://bybit-exchange.github.io/docs/p2p/user/counterparty-user-info) | Get counterparty info |
|
|
96
|
+
| `getUserPaymentTypes()` | [/v5/p2p/user/payment/list](https://bybit-exchange.github.io/docs/p2p/user/user-payment) | Get my payment methods |
|
|
97
|
+
|
|
98
|
+
#### Misc
|
|
99
|
+
| SDK Method | API Endpoint | Description |
|
|
100
|
+
| --- | --- | --- |
|
|
101
|
+
| `getCurrentBalance()` | [/v5/asset/transfer/query-account-coins-balance](https://bybit-exchange.github.io/docs/p2p/all-balance) | Get wallet balance |
|
|
102
|
+
|
|
103
|
+
## Development
|
|
104
|
+
|
|
105
|
+
Contributions are welcome!
|
|
106
|
+
|
|
107
|
+
### Build
|
|
108
|
+
```bash
|
|
109
|
+
npm run build
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
### Run Examples
|
|
113
|
+
```bash
|
|
114
|
+
npx ts-node examples/quickstart.ts
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
## 🤝 Contributing
|
|
118
|
+
|
|
119
|
+
Contributions are welcome! Please see our contributing guidelines:
|
|
120
|
+
|
|
121
|
+
1. Fork the repository
|
|
122
|
+
2. Create a feature branch (`git checkout -b feature/amazing-feature`)
|
|
123
|
+
3. Commit your changes (`git commit -m 'Add amazing feature'`)
|
|
124
|
+
4. Push to the branch (`git push origin feature/amazing-feature`)
|
|
125
|
+
5. Open a Pull Request
|
|
126
|
+
|
|
127
|
+
### Code Style
|
|
128
|
+
|
|
129
|
+
- Follow TypeScript best practices
|
|
130
|
+
- Use ESLint and Prettier (configured in project)
|
|
131
|
+
- Write tests for new features
|
|
132
|
+
- Update documentation as needed
|
|
133
|
+
|
|
134
|
+
## 📄 License
|
|
135
|
+
|
|
136
|
+
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
|
|
137
|
+
|
|
138
|
+
## 🔗 Links
|
|
139
|
+
|
|
140
|
+
- **Issues**: [GitHub Issues](https://github.com/ENGR-ABI/bybit-p2p-sdk/issues)
|
|
141
|
+
- **Discussions**: [GitHub Discussions](https://github.com/ENGR-ABI/bybit-p2p-sdk/discussions)
|
|
142
|
+
|
|
143
|
+
## 📞 Support
|
|
144
|
+
|
|
145
|
+
For questions and support:
|
|
146
|
+
- Check the [Documentation](#documentation) section
|
|
147
|
+
- Open an [Issue](https://github.com/ENGR-ABI/bybit-p2p-sdk/issues)
|
|
148
|
+
|
|
149
|
+
---
|
|
150
|
+
|
|
151
|
+
**Built with ❤️ for traders by [ENGR-ABI](https://github.com/ENGR-ABI)**
|
package/dist/client.d.ts
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { P2PConfig } from './types';
|
|
2
|
+
import { P2PMethodDef } from './constants';
|
|
3
|
+
export declare class P2PClient {
|
|
4
|
+
private testnet;
|
|
5
|
+
private apiKey;
|
|
6
|
+
private apiSecret;
|
|
7
|
+
private domain;
|
|
8
|
+
private tld;
|
|
9
|
+
private recvWindow;
|
|
10
|
+
private rsa;
|
|
11
|
+
private disableSslChecks;
|
|
12
|
+
private client;
|
|
13
|
+
private url;
|
|
14
|
+
constructor(config: P2PConfig);
|
|
15
|
+
private sign;
|
|
16
|
+
private sortParams;
|
|
17
|
+
request<T = any>(methodDef: P2PMethodDef, params?: any): Promise<T>;
|
|
18
|
+
private handleFileUpload;
|
|
19
|
+
}
|
package/dist/client.js
ADDED
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
36
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
37
|
+
};
|
|
38
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
|
+
exports.P2PClient = void 0;
|
|
40
|
+
const axios_1 = __importDefault(require("axios"));
|
|
41
|
+
const crypto = __importStar(require("crypto"));
|
|
42
|
+
const fs = __importStar(require("fs"));
|
|
43
|
+
const path = __importStar(require("path"));
|
|
44
|
+
const SUBDOMAIN_TESTNET = "api-testnet";
|
|
45
|
+
const SUBDOMAIN_MAINNET = "api";
|
|
46
|
+
const DOMAIN_MAIN = "bybit";
|
|
47
|
+
const TLD_MAIN = "com";
|
|
48
|
+
class P2PClient {
|
|
49
|
+
constructor(config) {
|
|
50
|
+
this.testnet = config.testnet || false;
|
|
51
|
+
this.apiKey = config.apiKey || "";
|
|
52
|
+
this.apiSecret = config.apiSecret || "";
|
|
53
|
+
this.domain = config.domain || DOMAIN_MAIN;
|
|
54
|
+
this.tld = config.tld || TLD_MAIN;
|
|
55
|
+
this.recvWindow = config.recvWindow || 20000;
|
|
56
|
+
this.rsa = config.rsa || false;
|
|
57
|
+
this.disableSslChecks = config.disableSslChecks || false;
|
|
58
|
+
const subdomain = this.testnet ? SUBDOMAIN_TESTNET : SUBDOMAIN_MAINNET;
|
|
59
|
+
this.url = `https://${subdomain}.${this.domain}.${this.tld}`;
|
|
60
|
+
this.client = axios_1.default.create({
|
|
61
|
+
validateStatus: () => true, // Handle all statuses manually
|
|
62
|
+
httpsAgent: this.disableSslChecks ? new (require('https').Agent)({ rejectUnauthorized: false }) : undefined
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
sign(payload, timestamp) {
|
|
66
|
+
const signString = typeof payload === 'string'
|
|
67
|
+
? `${timestamp}${this.apiKey}${this.recvWindow}${payload}`
|
|
68
|
+
: Buffer.concat([Buffer.from(`${timestamp}${this.apiKey}${this.recvWindow}`), payload]);
|
|
69
|
+
if (this.rsa) {
|
|
70
|
+
const signer = crypto.createSign('SHA256');
|
|
71
|
+
signer.update(signString);
|
|
72
|
+
return signer.sign(this.apiSecret, 'base64');
|
|
73
|
+
}
|
|
74
|
+
else {
|
|
75
|
+
return crypto.createHmac('sha256', this.apiSecret).update(signString).digest('hex');
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
sortParams(params) {
|
|
79
|
+
const keys = Object.keys(params).sort();
|
|
80
|
+
return keys.map(key => `${key}=${params[key]}`).join('&');
|
|
81
|
+
}
|
|
82
|
+
// Helper to cast values to strings/ints recursively primarily for POST JSON
|
|
83
|
+
// Mirroring Python's _cast_values logic effectively happens by JSON.stringify
|
|
84
|
+
// But Python explicitly converts some to strings.
|
|
85
|
+
// In JS, JSON.stringify handles types well, but if the API expects strings for numbers, we might need to be careful.
|
|
86
|
+
// For now, we rely on the user passing correct types or simple JSON serialization.
|
|
87
|
+
async request(methodDef, params = {}) {
|
|
88
|
+
// Validate required params
|
|
89
|
+
for (const req of methodDef.requiredParams) {
|
|
90
|
+
if (!(req in params)) {
|
|
91
|
+
throw new Error(`Missing required parameter: ${req}`);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
const timestamp = Date.now();
|
|
95
|
+
let payload = "";
|
|
96
|
+
let signature = "";
|
|
97
|
+
let contentType = "application/json";
|
|
98
|
+
let headers = {};
|
|
99
|
+
let requestUrl = this.url + methodDef.url;
|
|
100
|
+
let axiosConfig = {
|
|
101
|
+
method: methodDef.method === 'FILE' ? 'POST' : methodDef.method,
|
|
102
|
+
url: requestUrl,
|
|
103
|
+
headers: {}
|
|
104
|
+
};
|
|
105
|
+
if (methodDef.method === 'FILE') {
|
|
106
|
+
return this.handleFileUpload(methodDef, params, timestamp);
|
|
107
|
+
}
|
|
108
|
+
else if (methodDef.method === 'GET') {
|
|
109
|
+
const cleanParams = Object.entries(params)
|
|
110
|
+
.filter(([_, v]) => v != null)
|
|
111
|
+
.reduce((acc, [k, v]) => ({ ...acc, [k]: v }), {});
|
|
112
|
+
payload = this.sortParams(cleanParams);
|
|
113
|
+
signature = this.sign(payload, timestamp);
|
|
114
|
+
if (payload) {
|
|
115
|
+
axiosConfig.url += `?${payload}`;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
else {
|
|
119
|
+
// POST
|
|
120
|
+
payload = JSON.stringify(params);
|
|
121
|
+
signature = this.sign(payload, timestamp);
|
|
122
|
+
axiosConfig.data = payload;
|
|
123
|
+
}
|
|
124
|
+
headers = {
|
|
125
|
+
'X-BAPI-API-KEY': this.apiKey,
|
|
126
|
+
'X-BAPI-SIGN': signature,
|
|
127
|
+
'X-BAPI-SIGN-TYPE': '2',
|
|
128
|
+
'X-BAPI-TIMESTAMP': timestamp.toString(),
|
|
129
|
+
'X-BAPI-RECV-WINDOW': this.recvWindow.toString(),
|
|
130
|
+
'Content-Type': contentType
|
|
131
|
+
};
|
|
132
|
+
axiosConfig.headers = { ...axiosConfig.headers, ...headers };
|
|
133
|
+
const response = await this.client.request(axiosConfig);
|
|
134
|
+
// Process response
|
|
135
|
+
if (response.status !== 200) {
|
|
136
|
+
// Basic error handling
|
|
137
|
+
throw new Error(`Request failed with status ${response.status}: ${JSON.stringify(response.data)}`);
|
|
138
|
+
}
|
|
139
|
+
const result = response.data;
|
|
140
|
+
const retCode = result.retCode !== undefined ? result.retCode : result.ret_code;
|
|
141
|
+
const retMsg = result.retMsg || result.ret_msg;
|
|
142
|
+
if (retCode !== 0) {
|
|
143
|
+
throw new Error(`${retMsg} (ErrCode: ${retCode})`);
|
|
144
|
+
}
|
|
145
|
+
return result;
|
|
146
|
+
}
|
|
147
|
+
async handleFileUpload(methodDef, params, timestamp) {
|
|
148
|
+
const uploadFile = params.upload_file;
|
|
149
|
+
let filename = params.filename;
|
|
150
|
+
let fileData;
|
|
151
|
+
if (Buffer.isBuffer(uploadFile)) {
|
|
152
|
+
if (!filename)
|
|
153
|
+
throw new Error("filename is required when passing raw buffer");
|
|
154
|
+
fileData = uploadFile;
|
|
155
|
+
}
|
|
156
|
+
else if (typeof uploadFile === 'string') {
|
|
157
|
+
if (!fs.existsSync(uploadFile))
|
|
158
|
+
throw new Error(`File not found: ${uploadFile}`);
|
|
159
|
+
fileData = fs.readFileSync(uploadFile);
|
|
160
|
+
if (!filename)
|
|
161
|
+
filename = path.basename(uploadFile);
|
|
162
|
+
}
|
|
163
|
+
else {
|
|
164
|
+
throw new Error("Invalid upload_file type. Must be string path or Buffer.");
|
|
165
|
+
}
|
|
166
|
+
const boundary = "boundary-for-file";
|
|
167
|
+
const mimeType = "image/png"; // Python SDK hardcodes this
|
|
168
|
+
// Manual payload construction to match signature
|
|
169
|
+
// Python: f"--{boundary}\r\nContent-Disposition: form-data; name=\"upload_file\"; filename=\"{filename}\"\r\nContent-Type: {mime_type}\r\n\r\n".encode() + data + f"\r\n--{boundary}--\r\n".encode()
|
|
170
|
+
const part1 = Buffer.from(`--${boundary}\r\nContent-Disposition: form-data; name="upload_file"; filename="${filename}"\r\nContent-Type: ${mimeType}\r\n\r\n`);
|
|
171
|
+
const part2 = fileData;
|
|
172
|
+
const part3 = Buffer.from(`\r\n--${boundary}--\r\n`);
|
|
173
|
+
const payloadBuffer = Buffer.concat([part1, part2, part3]);
|
|
174
|
+
const signature = this.sign(payloadBuffer, timestamp);
|
|
175
|
+
const headers = {
|
|
176
|
+
'X-BAPI-API-KEY': this.apiKey,
|
|
177
|
+
'X-BAPI-SIGN': signature,
|
|
178
|
+
'X-BAPI-SIGN-TYPE': '2',
|
|
179
|
+
'X-BAPI-TIMESTAMP': timestamp.toString(),
|
|
180
|
+
'X-BAPI-RECV-WINDOW': this.recvWindow.toString(),
|
|
181
|
+
'Content-Type': `multipart/form-data; boundary=${boundary}`
|
|
182
|
+
};
|
|
183
|
+
const response = await this.client.post(this.url + methodDef.url, payloadBuffer, { headers });
|
|
184
|
+
if (response.status !== 200) {
|
|
185
|
+
throw new Error(`Request failed with status ${response.status}: ${JSON.stringify(response.data)}`);
|
|
186
|
+
}
|
|
187
|
+
const result = response.data;
|
|
188
|
+
if (result.retCode !== 0) {
|
|
189
|
+
throw new Error(`${result.retMsg} (ErrCode: ${result.retCode})`);
|
|
190
|
+
}
|
|
191
|
+
return result;
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
exports.P2PClient = P2PClient;
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.P2PMethods = void 0;
|
|
4
|
+
exports.P2PMethods = {
|
|
5
|
+
GET_CURRENT_BALANCE: { url: "/v5/asset/transfer/query-account-coins-balance", method: "GET", requiredParams: ["accountType"] },
|
|
6
|
+
GET_ACCOUNT_INFORMATION: { url: "/v5/p2p/user/personal/info", method: "POST", requiredParams: [] },
|
|
7
|
+
GET_ADS_LIST: { url: "/v5/p2p/item/personal/list", method: "POST", requiredParams: [] },
|
|
8
|
+
GET_AD_DETAILS: { url: "/v5/p2p/item/info", method: "POST", requiredParams: ["itemId"] },
|
|
9
|
+
UPDATE_AD: {
|
|
10
|
+
url: "/v5/p2p/item/update", method: "POST", requiredParams: [
|
|
11
|
+
"id", "priceType", "premium", "price", "minAmount", "maxAmount", "remark",
|
|
12
|
+
"tradingPreferenceSet", "paymentIds", "actionType", "quantity", "paymentPeriod"
|
|
13
|
+
]
|
|
14
|
+
},
|
|
15
|
+
REMOVE_AD: { url: "/v5/p2p/item/cancel", method: "POST", requiredParams: ["itemId"] },
|
|
16
|
+
GET_ORDERS: { url: "/v5/p2p/order/simplifyList", method: "POST", requiredParams: ["page", "size"] },
|
|
17
|
+
GET_PENDING_ORDERS: { url: "/v5/p2p/order/pending/simplifyList", method: "POST", requiredParams: ["page", "size"] },
|
|
18
|
+
GET_COUNTERPARTY_INFO: { url: "/v5/p2p/user/order/personal/info", method: "POST", requiredParams: ["originalUid", "orderId"] },
|
|
19
|
+
GET_ORDER_DETAILS: { url: "/v5/p2p/order/info", method: "POST", requiredParams: ["orderId"] },
|
|
20
|
+
RELEASE_ASSETS: { url: "/v5/p2p/order/finish", method: "POST", requiredParams: ["orderId"] },
|
|
21
|
+
MARK_AS_PAID: { url: "/v5/p2p/order/pay", method: "POST", requiredParams: ["orderId", "paymentType", "paymentId"] },
|
|
22
|
+
GET_CHAT_MESSAGES: { url: "/v5/p2p/order/message/listpage", method: "POST", requiredParams: ["orderId", "size"] },
|
|
23
|
+
UPLOAD_CHAT_FILE: { url: "/v5/p2p/oss/upload_file", method: "FILE", requiredParams: ["upload_file"] },
|
|
24
|
+
SEND_CHAT_MESSAGE: { url: "/v5/p2p/order/message/send", method: "POST", requiredParams: ["message", "contentType", "orderId"] },
|
|
25
|
+
POST_NEW_AD: {
|
|
26
|
+
url: "/v5/p2p/item/create", method: "POST", requiredParams: [
|
|
27
|
+
"tokenId", "currencyId", "side", "priceType", "premium", "price", "minAmount",
|
|
28
|
+
"maxAmount", "remark", "tradingPreferenceSet", "paymentIds", "quantity",
|
|
29
|
+
"paymentPeriod", "itemType"
|
|
30
|
+
]
|
|
31
|
+
},
|
|
32
|
+
GET_ONLINE_ADS: { url: "/v5/p2p/item/online", method: "POST", requiredParams: ["tokenId", "currencyId", "side"] },
|
|
33
|
+
GET_USER_PAYMENT_TYPES: { url: "/v5/p2p/user/payment/list", method: "POST", requiredParams: [] }
|
|
34
|
+
};
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
import { P2PClient } from './client';
|
|
2
|
+
import * as types from './types';
|
|
3
|
+
export * from './types';
|
|
4
|
+
export * from './client';
|
|
5
|
+
export * from './constants';
|
|
6
|
+
export declare class P2P extends P2PClient {
|
|
7
|
+
/**
|
|
8
|
+
* Obtain wallet balance, query asset information of each currency.
|
|
9
|
+
* By default, currency information with assets or liabilities of 0 is not returned.
|
|
10
|
+
*/
|
|
11
|
+
getCurrentBalance(params: {
|
|
12
|
+
accountType: string;
|
|
13
|
+
[key: string]: any;
|
|
14
|
+
}): Promise<types.P2PResponse>;
|
|
15
|
+
/**
|
|
16
|
+
* Get Account Information
|
|
17
|
+
*/
|
|
18
|
+
getAccountInformation(): Promise<types.P2PResponse>;
|
|
19
|
+
/**
|
|
20
|
+
* Get Ads List
|
|
21
|
+
*/
|
|
22
|
+
getAdsList(params?: types.GetAdsListParams): Promise<types.P2PResponse>;
|
|
23
|
+
/**
|
|
24
|
+
* Get Ad Details
|
|
25
|
+
*/
|
|
26
|
+
getAdDetails(params: {
|
|
27
|
+
itemId: string;
|
|
28
|
+
[key: string]: any;
|
|
29
|
+
}): Promise<types.P2PResponse>;
|
|
30
|
+
/**
|
|
31
|
+
* Update or activate ads
|
|
32
|
+
*/
|
|
33
|
+
updateAd(params: types.UpdateAdParams): Promise<types.P2PResponse>;
|
|
34
|
+
/**
|
|
35
|
+
* Remove ad
|
|
36
|
+
*/
|
|
37
|
+
removeAd(params: {
|
|
38
|
+
itemId: string;
|
|
39
|
+
[key: string]: any;
|
|
40
|
+
}): Promise<types.P2PResponse>;
|
|
41
|
+
/**
|
|
42
|
+
* Get orders
|
|
43
|
+
*/
|
|
44
|
+
getOrders(params?: types.GetOrdersParams): Promise<types.P2PResponse>;
|
|
45
|
+
/**
|
|
46
|
+
* Get pending orders
|
|
47
|
+
*/
|
|
48
|
+
getPendingOrders(params?: types.GetOrdersParams): Promise<types.P2PResponse>;
|
|
49
|
+
/**
|
|
50
|
+
* Get counterparty info
|
|
51
|
+
*/
|
|
52
|
+
getCounterpartyInfo(params: {
|
|
53
|
+
originalUid: string;
|
|
54
|
+
orderId: string;
|
|
55
|
+
[key: string]: any;
|
|
56
|
+
}): Promise<types.P2PResponse>;
|
|
57
|
+
/**
|
|
58
|
+
* Get order details
|
|
59
|
+
*/
|
|
60
|
+
getOrderDetails(params: {
|
|
61
|
+
orderId: string;
|
|
62
|
+
[key: string]: any;
|
|
63
|
+
}): Promise<types.P2PResponse>;
|
|
64
|
+
/**
|
|
65
|
+
* Release digital asset
|
|
66
|
+
*/
|
|
67
|
+
releaseAssets(params: {
|
|
68
|
+
orderId: string;
|
|
69
|
+
[key: string]: any;
|
|
70
|
+
}): Promise<types.P2PResponse>;
|
|
71
|
+
/**
|
|
72
|
+
* Mark order as paid
|
|
73
|
+
*/
|
|
74
|
+
markAsPaid(params: {
|
|
75
|
+
orderId: string;
|
|
76
|
+
paymentType: string;
|
|
77
|
+
paymentId: string;
|
|
78
|
+
[key: string]: any;
|
|
79
|
+
}): Promise<types.P2PResponse>;
|
|
80
|
+
/**
|
|
81
|
+
* Get chat messages
|
|
82
|
+
*/
|
|
83
|
+
getChatMessages(params: {
|
|
84
|
+
orderId: string;
|
|
85
|
+
size?: number;
|
|
86
|
+
startMessageId?: number;
|
|
87
|
+
[key: string]: any;
|
|
88
|
+
}): Promise<types.P2PResponse>;
|
|
89
|
+
/**
|
|
90
|
+
* Upload file for chats
|
|
91
|
+
*/
|
|
92
|
+
uploadChatFile(params: types.UploadChatFileParams): Promise<types.P2PResponse>;
|
|
93
|
+
/**
|
|
94
|
+
* Send chat message
|
|
95
|
+
*/
|
|
96
|
+
sendChatMessage(params: {
|
|
97
|
+
message: string;
|
|
98
|
+
contentType: string;
|
|
99
|
+
orderId: string;
|
|
100
|
+
[key: string]: any;
|
|
101
|
+
}): Promise<types.P2PResponse>;
|
|
102
|
+
/**
|
|
103
|
+
* Post new advertisement
|
|
104
|
+
*/
|
|
105
|
+
postNewAd(params: types.PostNewAdParams): Promise<types.P2PResponse>;
|
|
106
|
+
/**
|
|
107
|
+
* Get online advertisements list
|
|
108
|
+
*/
|
|
109
|
+
getOnlineAds(params: {
|
|
110
|
+
tokenId: string;
|
|
111
|
+
currencyId: string;
|
|
112
|
+
side: string | number;
|
|
113
|
+
[key: string]: any;
|
|
114
|
+
}): Promise<types.P2PResponse>;
|
|
115
|
+
/**
|
|
116
|
+
* Get user payment types
|
|
117
|
+
*/
|
|
118
|
+
getUserPaymentTypes(): Promise<types.P2PResponse>;
|
|
119
|
+
}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
exports.P2P = void 0;
|
|
18
|
+
const client_1 = require("./client");
|
|
19
|
+
const constants_1 = require("./constants");
|
|
20
|
+
__exportStar(require("./types"), exports);
|
|
21
|
+
__exportStar(require("./client"), exports);
|
|
22
|
+
__exportStar(require("./constants"), exports);
|
|
23
|
+
class P2P extends client_1.P2PClient {
|
|
24
|
+
/**
|
|
25
|
+
* Obtain wallet balance, query asset information of each currency.
|
|
26
|
+
* By default, currency information with assets or liabilities of 0 is not returned.
|
|
27
|
+
*/
|
|
28
|
+
async getCurrentBalance(params) {
|
|
29
|
+
return this.request(constants_1.P2PMethods.GET_CURRENT_BALANCE, params);
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Get Account Information
|
|
33
|
+
*/
|
|
34
|
+
async getAccountInformation() {
|
|
35
|
+
return this.request(constants_1.P2PMethods.GET_ACCOUNT_INFORMATION, {});
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Get Ads List
|
|
39
|
+
*/
|
|
40
|
+
async getAdsList(params = {}) {
|
|
41
|
+
return this.request(constants_1.P2PMethods.GET_ADS_LIST, params);
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Get Ad Details
|
|
45
|
+
*/
|
|
46
|
+
async getAdDetails(params) {
|
|
47
|
+
return this.request(constants_1.P2PMethods.GET_AD_DETAILS, params);
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Update or activate ads
|
|
51
|
+
*/
|
|
52
|
+
async updateAd(params) {
|
|
53
|
+
return this.request(constants_1.P2PMethods.UPDATE_AD, params);
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Remove ad
|
|
57
|
+
*/
|
|
58
|
+
async removeAd(params) {
|
|
59
|
+
return this.request(constants_1.P2PMethods.REMOVE_AD, params);
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Get orders
|
|
63
|
+
*/
|
|
64
|
+
async getOrders(params = {}) {
|
|
65
|
+
return this.request(constants_1.P2PMethods.GET_ORDERS, params);
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Get pending orders
|
|
69
|
+
*/
|
|
70
|
+
async getPendingOrders(params = {}) {
|
|
71
|
+
return this.request(constants_1.P2PMethods.GET_PENDING_ORDERS, params);
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Get counterparty info
|
|
75
|
+
*/
|
|
76
|
+
async getCounterpartyInfo(params) {
|
|
77
|
+
return this.request(constants_1.P2PMethods.GET_COUNTERPARTY_INFO, params);
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Get order details
|
|
81
|
+
*/
|
|
82
|
+
async getOrderDetails(params) {
|
|
83
|
+
return this.request(constants_1.P2PMethods.GET_ORDER_DETAILS, params);
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Release digital asset
|
|
87
|
+
*/
|
|
88
|
+
async releaseAssets(params) {
|
|
89
|
+
return this.request(constants_1.P2PMethods.RELEASE_ASSETS, params);
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Mark order as paid
|
|
93
|
+
*/
|
|
94
|
+
async markAsPaid(params) {
|
|
95
|
+
return this.request(constants_1.P2PMethods.MARK_AS_PAID, params);
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Get chat messages
|
|
99
|
+
*/
|
|
100
|
+
async getChatMessages(params) {
|
|
101
|
+
return this.request(constants_1.P2PMethods.GET_CHAT_MESSAGES, params);
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Upload file for chats
|
|
105
|
+
*/
|
|
106
|
+
async uploadChatFile(params) {
|
|
107
|
+
return this.request(constants_1.P2PMethods.UPLOAD_CHAT_FILE, params);
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Send chat message
|
|
111
|
+
*/
|
|
112
|
+
async sendChatMessage(params) {
|
|
113
|
+
return this.request(constants_1.P2PMethods.SEND_CHAT_MESSAGE, params);
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Post new advertisement
|
|
117
|
+
*/
|
|
118
|
+
async postNewAd(params) {
|
|
119
|
+
return this.request(constants_1.P2PMethods.POST_NEW_AD, params);
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* Get online advertisements list
|
|
123
|
+
*/
|
|
124
|
+
async getOnlineAds(params) {
|
|
125
|
+
return this.request(constants_1.P2PMethods.GET_ONLINE_ADS, params);
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* Get user payment types
|
|
129
|
+
*/
|
|
130
|
+
async getUserPaymentTypes() {
|
|
131
|
+
return this.request(constants_1.P2PMethods.GET_USER_PAYMENT_TYPES, {});
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
exports.P2P = P2P;
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
export interface P2PConfig {
|
|
2
|
+
/**
|
|
3
|
+
* API Key
|
|
4
|
+
*/
|
|
5
|
+
apiKey?: string;
|
|
6
|
+
/**
|
|
7
|
+
* API Secret
|
|
8
|
+
*/
|
|
9
|
+
apiSecret?: string;
|
|
10
|
+
/**
|
|
11
|
+
* Whether to use Testnet (default: false)
|
|
12
|
+
*/
|
|
13
|
+
testnet?: boolean;
|
|
14
|
+
/**
|
|
15
|
+
* Custom domain (default: bybit)
|
|
16
|
+
*/
|
|
17
|
+
domain?: string;
|
|
18
|
+
/**
|
|
19
|
+
* Custom TLD (default: com)
|
|
20
|
+
*/
|
|
21
|
+
tld?: string;
|
|
22
|
+
/**
|
|
23
|
+
* Receive window in ms (default: 5000)
|
|
24
|
+
*/
|
|
25
|
+
recvWindow?: number;
|
|
26
|
+
/**
|
|
27
|
+
* Use RSA authentication (default: false)
|
|
28
|
+
*/
|
|
29
|
+
rsa?: boolean;
|
|
30
|
+
/**
|
|
31
|
+
* Disable SSL verification (default: false) - Not recommended
|
|
32
|
+
*/
|
|
33
|
+
disableSslChecks?: boolean;
|
|
34
|
+
/**
|
|
35
|
+
* Logging level (not fully implemented in this node version, serves as placeholder)
|
|
36
|
+
*/
|
|
37
|
+
loggingLevel?: any;
|
|
38
|
+
}
|
|
39
|
+
export interface P2PResponse<T = any> {
|
|
40
|
+
retCode?: number;
|
|
41
|
+
ret_code?: number;
|
|
42
|
+
retMsg?: string;
|
|
43
|
+
ret_msg?: string;
|
|
44
|
+
result: T;
|
|
45
|
+
retExtInfo?: any;
|
|
46
|
+
ext_code?: string;
|
|
47
|
+
ext_info?: any;
|
|
48
|
+
time?: number;
|
|
49
|
+
time_now?: string;
|
|
50
|
+
}
|
|
51
|
+
export interface GetAdsListParams {
|
|
52
|
+
itemId?: string;
|
|
53
|
+
status?: string | number;
|
|
54
|
+
side?: string | number;
|
|
55
|
+
tokenId?: string;
|
|
56
|
+
page?: number;
|
|
57
|
+
size?: number;
|
|
58
|
+
currencyId?: string;
|
|
59
|
+
[key: string]: any;
|
|
60
|
+
}
|
|
61
|
+
export interface UpdateAdParams {
|
|
62
|
+
id: string;
|
|
63
|
+
priceType?: number;
|
|
64
|
+
premium?: number | string;
|
|
65
|
+
price?: number | string;
|
|
66
|
+
minAmount?: number | string;
|
|
67
|
+
maxAmount?: number | string;
|
|
68
|
+
remark?: string;
|
|
69
|
+
tradingPreferenceSet?: TradingPreferenceSet;
|
|
70
|
+
paymentIds?: string[];
|
|
71
|
+
actionType?: 'MODIFY' | 'ACTIVE';
|
|
72
|
+
quantity?: string;
|
|
73
|
+
paymentPeriod?: string | number;
|
|
74
|
+
[key: string]: any;
|
|
75
|
+
}
|
|
76
|
+
export interface TradingPreferenceSet {
|
|
77
|
+
hasUnPostAd?: number;
|
|
78
|
+
isKyc?: number;
|
|
79
|
+
isEmail?: number;
|
|
80
|
+
isMobile?: number;
|
|
81
|
+
hasRegisterTime?: number;
|
|
82
|
+
registerTimeThreshold?: number;
|
|
83
|
+
orderFinishNumberDay30?: number;
|
|
84
|
+
completeRateDay30?: string;
|
|
85
|
+
nationalLimit?: string;
|
|
86
|
+
hasOrderFinishNumberDay30?: number;
|
|
87
|
+
hasCompleteRateDay30?: number;
|
|
88
|
+
hasNationalLimit?: number;
|
|
89
|
+
[key: string]: any;
|
|
90
|
+
}
|
|
91
|
+
export interface PostNewAdParams {
|
|
92
|
+
tokenId: string;
|
|
93
|
+
currencyId: string;
|
|
94
|
+
side: string | number;
|
|
95
|
+
priceType: number;
|
|
96
|
+
premium?: number | string;
|
|
97
|
+
price?: number | string;
|
|
98
|
+
minAmount?: number | string;
|
|
99
|
+
maxAmount?: number | string;
|
|
100
|
+
remark?: string;
|
|
101
|
+
tradingPreferenceSet?: TradingPreferenceSet;
|
|
102
|
+
paymentIds?: string[];
|
|
103
|
+
quantity?: string;
|
|
104
|
+
paymentPeriod?: string | number;
|
|
105
|
+
itemType?: 'ORIGIN' | 'BULK';
|
|
106
|
+
[key: string]: any;
|
|
107
|
+
}
|
|
108
|
+
export interface GetOrdersParams {
|
|
109
|
+
status?: string;
|
|
110
|
+
beginTime?: string | number;
|
|
111
|
+
endTime?: string | number;
|
|
112
|
+
tokenId?: string;
|
|
113
|
+
side?: number[];
|
|
114
|
+
page?: number;
|
|
115
|
+
size?: number;
|
|
116
|
+
[key: string]: any;
|
|
117
|
+
}
|
|
118
|
+
export interface UploadChatFileParams {
|
|
119
|
+
upload_file: string | Buffer;
|
|
120
|
+
filename?: string;
|
|
121
|
+
[key: string]: any;
|
|
122
|
+
}
|
package/dist/types.js
ADDED
package/package.json
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "bybit-p2p-sdk",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Bybit P2P Node.js SDK (TypeScript)",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"types": "dist/index.d.ts",
|
|
7
|
+
"scripts": {
|
|
8
|
+
"build": "tsc",
|
|
9
|
+
"prepublishOnly": "npm run build",
|
|
10
|
+
"test": "echo \"Error: no test specified\" && exit 1"
|
|
11
|
+
},
|
|
12
|
+
"keywords": [
|
|
13
|
+
"bybit",
|
|
14
|
+
"p2p",
|
|
15
|
+
"sdk",
|
|
16
|
+
"crypto",
|
|
17
|
+
"exchange",
|
|
18
|
+
"typescript",
|
|
19
|
+
"nodejs",
|
|
20
|
+
"api"
|
|
21
|
+
],
|
|
22
|
+
"homepage": "https://github.com/ENGR-ABI/bybit-p2p-sdk",
|
|
23
|
+
"bugs": {
|
|
24
|
+
"url": "https://github.com/ENGR-ABI/bybit-p2p-sdk/issues"
|
|
25
|
+
},
|
|
26
|
+
"repository": {
|
|
27
|
+
"type": "git",
|
|
28
|
+
"url": "git+https://github.com/ENGR-ABI/bybit-p2p-sdk.git"
|
|
29
|
+
},
|
|
30
|
+
"files": [
|
|
31
|
+
"dist",
|
|
32
|
+
"src",
|
|
33
|
+
"README.md",
|
|
34
|
+
"LICENSE"
|
|
35
|
+
],
|
|
36
|
+
"author": "Aadam Bala Idriss (ENGR ABI)",
|
|
37
|
+
"license": "MIT",
|
|
38
|
+
"dependencies": {
|
|
39
|
+
"axios": "^1.6.0",
|
|
40
|
+
"form-data": "^4.0.0",
|
|
41
|
+
"uuid": "^9.0.0"
|
|
42
|
+
},
|
|
43
|
+
"devDependencies": {
|
|
44
|
+
"@types/node": "^20.0.0",
|
|
45
|
+
"@types/uuid": "^9.0.0",
|
|
46
|
+
"ts-node": "^10.9.1",
|
|
47
|
+
"typescript": "^5.0.0"
|
|
48
|
+
}
|
|
49
|
+
}
|
package/src/client.ts
ADDED
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
import axios, { AxiosInstance, AxiosRequestConfig, Method } from 'axios';
|
|
2
|
+
import * as crypto from 'crypto';
|
|
3
|
+
import * as FormData from 'form-data';
|
|
4
|
+
import * as fs from 'fs';
|
|
5
|
+
import * as path from 'path';
|
|
6
|
+
import { P2PConfig, P2PResponse } from './types';
|
|
7
|
+
import { P2PMethodDef } from './constants';
|
|
8
|
+
|
|
9
|
+
const SUBDOMAIN_TESTNET = "api-testnet";
|
|
10
|
+
const SUBDOMAIN_MAINNET = "api";
|
|
11
|
+
const DOMAIN_MAIN = "bybit";
|
|
12
|
+
const TLD_MAIN = "com";
|
|
13
|
+
|
|
14
|
+
export class P2PClient {
|
|
15
|
+
private testnet: boolean;
|
|
16
|
+
private apiKey: string;
|
|
17
|
+
private apiSecret: string;
|
|
18
|
+
private domain: string;
|
|
19
|
+
private tld: string;
|
|
20
|
+
private recvWindow: number;
|
|
21
|
+
private rsa: boolean;
|
|
22
|
+
private disableSslChecks: boolean;
|
|
23
|
+
private client: AxiosInstance;
|
|
24
|
+
private url: string;
|
|
25
|
+
|
|
26
|
+
constructor(config: P2PConfig) {
|
|
27
|
+
this.testnet = config.testnet || false;
|
|
28
|
+
this.apiKey = config.apiKey || "";
|
|
29
|
+
this.apiSecret = config.apiSecret || "";
|
|
30
|
+
this.domain = config.domain || DOMAIN_MAIN;
|
|
31
|
+
this.tld = config.tld || TLD_MAIN;
|
|
32
|
+
this.recvWindow = config.recvWindow || 20000;
|
|
33
|
+
this.rsa = config.rsa || false;
|
|
34
|
+
this.disableSslChecks = config.disableSslChecks || false;
|
|
35
|
+
|
|
36
|
+
const subdomain = this.testnet ? SUBDOMAIN_TESTNET : SUBDOMAIN_MAINNET;
|
|
37
|
+
this.url = `https://${subdomain}.${this.domain}.${this.tld}`;
|
|
38
|
+
|
|
39
|
+
this.client = axios.create({
|
|
40
|
+
validateStatus: () => true, // Handle all statuses manually
|
|
41
|
+
httpsAgent: this.disableSslChecks ? new (require('https').Agent)({ rejectUnauthorized: false }) : undefined
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
private sign(payload: string | Buffer, timestamp: number): string {
|
|
46
|
+
const signString = typeof payload === 'string'
|
|
47
|
+
? `${timestamp}${this.apiKey}${this.recvWindow}${payload}`
|
|
48
|
+
: Buffer.concat([Buffer.from(`${timestamp}${this.apiKey}${this.recvWindow}`), payload]);
|
|
49
|
+
|
|
50
|
+
if (this.rsa) {
|
|
51
|
+
const signer = crypto.createSign('SHA256');
|
|
52
|
+
signer.update(signString);
|
|
53
|
+
return signer.sign(this.apiSecret, 'base64');
|
|
54
|
+
} else {
|
|
55
|
+
return crypto.createHmac('sha256', this.apiSecret).update(signString).digest('hex');
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
private sortParams(params: any): string {
|
|
60
|
+
const keys = Object.keys(params).sort();
|
|
61
|
+
return keys.map(key => `${key}=${params[key]}`).join('&');
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// Helper to cast values to strings/ints recursively primarily for POST JSON
|
|
65
|
+
// Mirroring Python's _cast_values logic effectively happens by JSON.stringify
|
|
66
|
+
// But Python explicitly converts some to strings.
|
|
67
|
+
// In JS, JSON.stringify handles types well, but if the API expects strings for numbers, we might need to be careful.
|
|
68
|
+
// For now, we rely on the user passing correct types or simple JSON serialization.
|
|
69
|
+
|
|
70
|
+
async request<T = any>(methodDef: P2PMethodDef, params: any = {}): Promise<T> {
|
|
71
|
+
// Validate required params
|
|
72
|
+
for (const req of methodDef.requiredParams) {
|
|
73
|
+
if (!(req in params)) {
|
|
74
|
+
throw new Error(`Missing required parameter: ${req}`);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
const timestamp = Date.now();
|
|
79
|
+
let payload = "";
|
|
80
|
+
let signature = "";
|
|
81
|
+
let contentType = "application/json";
|
|
82
|
+
let headers: any = {};
|
|
83
|
+
let requestUrl = this.url + methodDef.url;
|
|
84
|
+
let axiosConfig: AxiosRequestConfig = {
|
|
85
|
+
method: methodDef.method === 'FILE' ? 'POST' : methodDef.method as Method,
|
|
86
|
+
url: requestUrl,
|
|
87
|
+
headers: {}
|
|
88
|
+
};
|
|
89
|
+
|
|
90
|
+
if (methodDef.method === 'FILE') {
|
|
91
|
+
return this.handleFileUpload(methodDef, params, timestamp);
|
|
92
|
+
} else if (methodDef.method === 'GET') {
|
|
93
|
+
const cleanParams = Object.entries(params)
|
|
94
|
+
.filter(([_, v]) => v != null)
|
|
95
|
+
.reduce((acc, [k, v]) => ({ ...acc, [k]: v }), {});
|
|
96
|
+
payload = this.sortParams(cleanParams);
|
|
97
|
+
signature = this.sign(payload, timestamp);
|
|
98
|
+
if (payload) {
|
|
99
|
+
axiosConfig.url += `?${payload}`;
|
|
100
|
+
}
|
|
101
|
+
} else {
|
|
102
|
+
// POST
|
|
103
|
+
payload = JSON.stringify(params);
|
|
104
|
+
signature = this.sign(payload, timestamp);
|
|
105
|
+
axiosConfig.data = payload;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
headers = {
|
|
109
|
+
'X-BAPI-API-KEY': this.apiKey,
|
|
110
|
+
'X-BAPI-SIGN': signature,
|
|
111
|
+
'X-BAPI-SIGN-TYPE': '2',
|
|
112
|
+
'X-BAPI-TIMESTAMP': timestamp.toString(),
|
|
113
|
+
'X-BAPI-RECV-WINDOW': this.recvWindow.toString(),
|
|
114
|
+
'Content-Type': contentType
|
|
115
|
+
};
|
|
116
|
+
|
|
117
|
+
axiosConfig.headers = { ...axiosConfig.headers, ...headers };
|
|
118
|
+
|
|
119
|
+
const response = await this.client.request(axiosConfig);
|
|
120
|
+
|
|
121
|
+
// Process response
|
|
122
|
+
if (response.status !== 200) {
|
|
123
|
+
// Basic error handling
|
|
124
|
+
throw new Error(`Request failed with status ${response.status}: ${JSON.stringify(response.data)}`);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
const result = response.data;
|
|
128
|
+
|
|
129
|
+
const retCode = result.retCode !== undefined ? result.retCode : result.ret_code;
|
|
130
|
+
const retMsg = result.retMsg || result.ret_msg;
|
|
131
|
+
|
|
132
|
+
if (retCode !== 0) {
|
|
133
|
+
throw new Error(`${retMsg} (ErrCode: ${retCode})`);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
return result;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
private async handleFileUpload<T>(methodDef: P2PMethodDef, params: any, timestamp: number): Promise<T> {
|
|
140
|
+
const uploadFile = params.upload_file;
|
|
141
|
+
let filename = params.filename;
|
|
142
|
+
let fileData: Buffer;
|
|
143
|
+
|
|
144
|
+
if (Buffer.isBuffer(uploadFile)) {
|
|
145
|
+
if (!filename) throw new Error("filename is required when passing raw buffer");
|
|
146
|
+
fileData = uploadFile;
|
|
147
|
+
} else if (typeof uploadFile === 'string') {
|
|
148
|
+
if (!fs.existsSync(uploadFile)) throw new Error(`File not found: ${uploadFile}`);
|
|
149
|
+
fileData = fs.readFileSync(uploadFile);
|
|
150
|
+
if (!filename) filename = path.basename(uploadFile);
|
|
151
|
+
} else {
|
|
152
|
+
throw new Error("Invalid upload_file type. Must be string path or Buffer.");
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
const boundary = "boundary-for-file";
|
|
156
|
+
const mimeType = "image/png"; // Python SDK hardcodes this
|
|
157
|
+
|
|
158
|
+
// Manual payload construction to match signature
|
|
159
|
+
// Python: f"--{boundary}\r\nContent-Disposition: form-data; name=\"upload_file\"; filename=\"{filename}\"\r\nContent-Type: {mime_type}\r\n\r\n".encode() + data + f"\r\n--{boundary}--\r\n".encode()
|
|
160
|
+
|
|
161
|
+
const part1 = Buffer.from(`--${boundary}\r\nContent-Disposition: form-data; name="upload_file"; filename="${filename}"\r\nContent-Type: ${mimeType}\r\n\r\n`);
|
|
162
|
+
const part2 = fileData;
|
|
163
|
+
const part3 = Buffer.from(`\r\n--${boundary}--\r\n`);
|
|
164
|
+
|
|
165
|
+
const payloadBuffer = Buffer.concat([part1, part2, part3]);
|
|
166
|
+
|
|
167
|
+
const signature = this.sign(payloadBuffer, timestamp);
|
|
168
|
+
|
|
169
|
+
const headers = {
|
|
170
|
+
'X-BAPI-API-KEY': this.apiKey,
|
|
171
|
+
'X-BAPI-SIGN': signature,
|
|
172
|
+
'X-BAPI-SIGN-TYPE': '2',
|
|
173
|
+
'X-BAPI-TIMESTAMP': timestamp.toString(),
|
|
174
|
+
'X-BAPI-RECV-WINDOW': this.recvWindow.toString(),
|
|
175
|
+
'Content-Type': `multipart/form-data; boundary=${boundary}`
|
|
176
|
+
};
|
|
177
|
+
|
|
178
|
+
const response = await this.client.post(this.url + methodDef.url, payloadBuffer, { headers });
|
|
179
|
+
|
|
180
|
+
if (response.status !== 200) {
|
|
181
|
+
throw new Error(`Request failed with status ${response.status}: ${JSON.stringify(response.data)}`);
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
const result = response.data;
|
|
185
|
+
if (result.retCode !== 0) {
|
|
186
|
+
throw new Error(`${result.retMsg} (ErrCode: ${result.retCode})`);
|
|
187
|
+
}
|
|
188
|
+
return result;
|
|
189
|
+
}
|
|
190
|
+
}
|
package/src/constants.ts
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
export interface P2PMethodDef {
|
|
2
|
+
url: string;
|
|
3
|
+
method: 'GET' | 'POST' | 'FILE';
|
|
4
|
+
requiredParams: string[];
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
export const P2PMethods: Record<string, P2PMethodDef> = {
|
|
8
|
+
GET_CURRENT_BALANCE: { url: "/v5/asset/transfer/query-account-coins-balance", method: "GET", requiredParams: ["accountType"] },
|
|
9
|
+
GET_ACCOUNT_INFORMATION: { url: "/v5/p2p/user/personal/info", method: "POST", requiredParams: [] },
|
|
10
|
+
GET_ADS_LIST: { url: "/v5/p2p/item/personal/list", method: "POST", requiredParams: [] },
|
|
11
|
+
GET_AD_DETAILS: { url: "/v5/p2p/item/info", method: "POST", requiredParams: ["itemId"] },
|
|
12
|
+
UPDATE_AD: {
|
|
13
|
+
url: "/v5/p2p/item/update", method: "POST", requiredParams: [
|
|
14
|
+
"id", "priceType", "premium", "price", "minAmount", "maxAmount", "remark",
|
|
15
|
+
"tradingPreferenceSet", "paymentIds", "actionType", "quantity", "paymentPeriod"
|
|
16
|
+
]
|
|
17
|
+
},
|
|
18
|
+
REMOVE_AD: { url: "/v5/p2p/item/cancel", method: "POST", requiredParams: ["itemId"] },
|
|
19
|
+
GET_ORDERS: { url: "/v5/p2p/order/simplifyList", method: "POST", requiredParams: ["page", "size"] },
|
|
20
|
+
GET_PENDING_ORDERS: { url: "/v5/p2p/order/pending/simplifyList", method: "POST", requiredParams: ["page", "size"] },
|
|
21
|
+
GET_COUNTERPARTY_INFO: { url: "/v5/p2p/user/order/personal/info", method: "POST", requiredParams: ["originalUid", "orderId"] },
|
|
22
|
+
GET_ORDER_DETAILS: { url: "/v5/p2p/order/info", method: "POST", requiredParams: ["orderId"] },
|
|
23
|
+
RELEASE_ASSETS: { url: "/v5/p2p/order/finish", method: "POST", requiredParams: ["orderId"] },
|
|
24
|
+
MARK_AS_PAID: { url: "/v5/p2p/order/pay", method: "POST", requiredParams: ["orderId", "paymentType", "paymentId"] },
|
|
25
|
+
GET_CHAT_MESSAGES: { url: "/v5/p2p/order/message/listpage", method: "POST", requiredParams: ["orderId", "size"] },
|
|
26
|
+
UPLOAD_CHAT_FILE: { url: "/v5/p2p/oss/upload_file", method: "FILE", requiredParams: ["upload_file"] },
|
|
27
|
+
SEND_CHAT_MESSAGE: { url: "/v5/p2p/order/message/send", method: "POST", requiredParams: ["message", "contentType", "orderId"] },
|
|
28
|
+
POST_NEW_AD: {
|
|
29
|
+
url: "/v5/p2p/item/create", method: "POST", requiredParams: [
|
|
30
|
+
"tokenId", "currencyId", "side", "priceType", "premium", "price", "minAmount",
|
|
31
|
+
"maxAmount", "remark", "tradingPreferenceSet", "paymentIds", "quantity",
|
|
32
|
+
"paymentPeriod", "itemType"
|
|
33
|
+
]
|
|
34
|
+
},
|
|
35
|
+
GET_ONLINE_ADS: { url: "/v5/p2p/item/online", method: "POST", requiredParams: ["tokenId", "currencyId", "side"] },
|
|
36
|
+
GET_USER_PAYMENT_TYPES: { url: "/v5/p2p/user/payment/list", method: "POST", requiredParams: [] }
|
|
37
|
+
};
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
import { P2PClient } from './client';
|
|
2
|
+
import { P2PMethods } from './constants';
|
|
3
|
+
import * as types from './types';
|
|
4
|
+
|
|
5
|
+
export * from './types';
|
|
6
|
+
export * from './client';
|
|
7
|
+
export * from './constants';
|
|
8
|
+
|
|
9
|
+
export class P2P extends P2PClient {
|
|
10
|
+
/**
|
|
11
|
+
* Obtain wallet balance, query asset information of each currency.
|
|
12
|
+
* By default, currency information with assets or liabilities of 0 is not returned.
|
|
13
|
+
*/
|
|
14
|
+
async getCurrentBalance(params: { accountType: string;[key: string]: any }): Promise<types.P2PResponse> {
|
|
15
|
+
return this.request(P2PMethods.GET_CURRENT_BALANCE, params);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Get Account Information
|
|
20
|
+
*/
|
|
21
|
+
async getAccountInformation(): Promise<types.P2PResponse> {
|
|
22
|
+
return this.request(P2PMethods.GET_ACCOUNT_INFORMATION, {});
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Get Ads List
|
|
27
|
+
*/
|
|
28
|
+
async getAdsList(params: types.GetAdsListParams = {}): Promise<types.P2PResponse> {
|
|
29
|
+
return this.request(P2PMethods.GET_ADS_LIST, params);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Get Ad Details
|
|
34
|
+
*/
|
|
35
|
+
async getAdDetails(params: { itemId: string;[key: string]: any }): Promise<types.P2PResponse> {
|
|
36
|
+
return this.request(P2PMethods.GET_AD_DETAILS, params);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Update or activate ads
|
|
41
|
+
*/
|
|
42
|
+
async updateAd(params: types.UpdateAdParams): Promise<types.P2PResponse> {
|
|
43
|
+
return this.request(P2PMethods.UPDATE_AD, params);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Remove ad
|
|
48
|
+
*/
|
|
49
|
+
async removeAd(params: { itemId: string;[key: string]: any }): Promise<types.P2PResponse> {
|
|
50
|
+
return this.request(P2PMethods.REMOVE_AD, params);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Get orders
|
|
55
|
+
*/
|
|
56
|
+
async getOrders(params: types.GetOrdersParams = {}): Promise<types.P2PResponse> {
|
|
57
|
+
return this.request(P2PMethods.GET_ORDERS, params);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Get pending orders
|
|
62
|
+
*/
|
|
63
|
+
async getPendingOrders(params: types.GetOrdersParams = {}): Promise<types.P2PResponse> {
|
|
64
|
+
return this.request(P2PMethods.GET_PENDING_ORDERS, params);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Get counterparty info
|
|
69
|
+
*/
|
|
70
|
+
async getCounterpartyInfo(params: { originalUid: string; orderId: string;[key: string]: any }): Promise<types.P2PResponse> {
|
|
71
|
+
return this.request(P2PMethods.GET_COUNTERPARTY_INFO, params);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Get order details
|
|
76
|
+
*/
|
|
77
|
+
async getOrderDetails(params: { orderId: string;[key: string]: any }): Promise<types.P2PResponse> {
|
|
78
|
+
return this.request(P2PMethods.GET_ORDER_DETAILS, params);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Release digital asset
|
|
83
|
+
*/
|
|
84
|
+
async releaseAssets(params: { orderId: string;[key: string]: any }): Promise<types.P2PResponse> {
|
|
85
|
+
return this.request(P2PMethods.RELEASE_ASSETS, params);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Mark order as paid
|
|
90
|
+
*/
|
|
91
|
+
async markAsPaid(params: { orderId: string; paymentType: string; paymentId: string;[key: string]: any }): Promise<types.P2PResponse> {
|
|
92
|
+
return this.request(P2PMethods.MARK_AS_PAID, params);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Get chat messages
|
|
97
|
+
*/
|
|
98
|
+
async getChatMessages(params: { orderId: string; size?: number; startMessageId?: number;[key: string]: any }): Promise<types.P2PResponse> {
|
|
99
|
+
return this.request(P2PMethods.GET_CHAT_MESSAGES, params);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Upload file for chats
|
|
104
|
+
*/
|
|
105
|
+
async uploadChatFile(params: types.UploadChatFileParams): Promise<types.P2PResponse> {
|
|
106
|
+
return this.request(P2PMethods.UPLOAD_CHAT_FILE, params);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Send chat message
|
|
111
|
+
*/
|
|
112
|
+
async sendChatMessage(params: { message: string; contentType: string; orderId: string;[key: string]: any }): Promise<types.P2PResponse> {
|
|
113
|
+
return this.request(P2PMethods.SEND_CHAT_MESSAGE, params);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Post new advertisement
|
|
118
|
+
*/
|
|
119
|
+
async postNewAd(params: types.PostNewAdParams): Promise<types.P2PResponse> {
|
|
120
|
+
return this.request(P2PMethods.POST_NEW_AD, params);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Get online advertisements list
|
|
125
|
+
*/
|
|
126
|
+
async getOnlineAds(params: { tokenId: string; currencyId: string; side: string | number;[key: string]: any }): Promise<types.P2PResponse> {
|
|
127
|
+
return this.request(P2PMethods.GET_ONLINE_ADS, params);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* Get user payment types
|
|
132
|
+
*/
|
|
133
|
+
async getUserPaymentTypes(): Promise<types.P2PResponse> {
|
|
134
|
+
return this.request(P2PMethods.GET_USER_PAYMENT_TYPES, {});
|
|
135
|
+
}
|
|
136
|
+
}
|
package/src/types.ts
ADDED
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
export interface P2PConfig {
|
|
2
|
+
/**
|
|
3
|
+
* API Key
|
|
4
|
+
*/
|
|
5
|
+
apiKey?: string;
|
|
6
|
+
/**
|
|
7
|
+
* API Secret
|
|
8
|
+
*/
|
|
9
|
+
apiSecret?: string;
|
|
10
|
+
/**
|
|
11
|
+
* Whether to use Testnet (default: false)
|
|
12
|
+
*/
|
|
13
|
+
testnet?: boolean;
|
|
14
|
+
/**
|
|
15
|
+
* Custom domain (default: bybit)
|
|
16
|
+
*/
|
|
17
|
+
domain?: string;
|
|
18
|
+
/**
|
|
19
|
+
* Custom TLD (default: com)
|
|
20
|
+
*/
|
|
21
|
+
tld?: string;
|
|
22
|
+
/**
|
|
23
|
+
* Receive window in ms (default: 5000)
|
|
24
|
+
*/
|
|
25
|
+
recvWindow?: number;
|
|
26
|
+
/**
|
|
27
|
+
* Use RSA authentication (default: false)
|
|
28
|
+
*/
|
|
29
|
+
rsa?: boolean;
|
|
30
|
+
/**
|
|
31
|
+
* Disable SSL verification (default: false) - Not recommended
|
|
32
|
+
*/
|
|
33
|
+
disableSslChecks?: boolean;
|
|
34
|
+
/**
|
|
35
|
+
* Logging level (not fully implemented in this node version, serves as placeholder)
|
|
36
|
+
*/
|
|
37
|
+
loggingLevel?: any;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export interface P2PResponse<T = any> {
|
|
41
|
+
retCode?: number;
|
|
42
|
+
ret_code?: number;
|
|
43
|
+
retMsg?: string;
|
|
44
|
+
ret_msg?: string;
|
|
45
|
+
result: T;
|
|
46
|
+
retExtInfo?: any;
|
|
47
|
+
ext_code?: string;
|
|
48
|
+
ext_info?: any;
|
|
49
|
+
time?: number;
|
|
50
|
+
time_now?: string;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// Method Parameter Interfaces
|
|
54
|
+
|
|
55
|
+
export interface GetAdsListParams {
|
|
56
|
+
itemId?: string;
|
|
57
|
+
status?: string | number; // 1 - Sold out, 2 - Available
|
|
58
|
+
side?: string | number; // 0 - Buy, 1 - Sell
|
|
59
|
+
tokenId?: string;
|
|
60
|
+
page?: number;
|
|
61
|
+
size?: number;
|
|
62
|
+
currencyId?: string;
|
|
63
|
+
[key: string]: any;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
export interface UpdateAdParams {
|
|
67
|
+
id: string; // Advertisement ID
|
|
68
|
+
priceType?: number; // 0 - fixed, 1 - floating
|
|
69
|
+
premium?: number | string;
|
|
70
|
+
price?: number | string;
|
|
71
|
+
minAmount?: number | string;
|
|
72
|
+
maxAmount?: number | string;
|
|
73
|
+
remark?: string;
|
|
74
|
+
tradingPreferenceSet?: TradingPreferenceSet;
|
|
75
|
+
paymentIds?: string[];
|
|
76
|
+
actionType?: 'MODIFY' | 'ACTIVE';
|
|
77
|
+
quantity?: string;
|
|
78
|
+
paymentPeriod?: string | number;
|
|
79
|
+
[key: string]: any;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
export interface TradingPreferenceSet {
|
|
83
|
+
hasUnPostAd?: number;
|
|
84
|
+
isKyc?: number;
|
|
85
|
+
isEmail?: number;
|
|
86
|
+
isMobile?: number;
|
|
87
|
+
hasRegisterTime?: number;
|
|
88
|
+
registerTimeThreshold?: number;
|
|
89
|
+
orderFinishNumberDay30?: number;
|
|
90
|
+
completeRateDay30?: string;
|
|
91
|
+
nationalLimit?: string;
|
|
92
|
+
hasOrderFinishNumberDay30?: number;
|
|
93
|
+
hasCompleteRateDay30?: number;
|
|
94
|
+
hasNationalLimit?: number;
|
|
95
|
+
[key: string]: any;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
export interface PostNewAdParams {
|
|
99
|
+
tokenId: string;
|
|
100
|
+
currencyId: string;
|
|
101
|
+
side: string | number; // 0 - Buy, 1 - Sell
|
|
102
|
+
priceType: number;
|
|
103
|
+
premium?: number | string;
|
|
104
|
+
price?: number | string;
|
|
105
|
+
minAmount?: number | string;
|
|
106
|
+
maxAmount?: number | string;
|
|
107
|
+
remark?: string;
|
|
108
|
+
tradingPreferenceSet?: TradingPreferenceSet;
|
|
109
|
+
paymentIds?: string[];
|
|
110
|
+
quantity?: string;
|
|
111
|
+
paymentPeriod?: string | number;
|
|
112
|
+
itemType?: 'ORIGIN' | 'BULK';
|
|
113
|
+
[key: string]: any;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
export interface GetOrdersParams {
|
|
117
|
+
status?: string;
|
|
118
|
+
beginTime?: string | number;
|
|
119
|
+
endTime?: string | number;
|
|
120
|
+
tokenId?: string;
|
|
121
|
+
side?: number[];
|
|
122
|
+
page?: number;
|
|
123
|
+
size?: number;
|
|
124
|
+
[key: string]: any;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
export interface UploadChatFileParams {
|
|
128
|
+
upload_file: string | Buffer; // Path string or Buffer
|
|
129
|
+
filename?: string;
|
|
130
|
+
[key: string]: any;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
// ... Add more generalized interfaces as needed or use `any` for less common methods
|
|
134
|
+
// to keep the initial conversion manageable but extensible.
|