pacifica-js-sdk 1.0.0 → 1.1.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/README.md +125 -25
- package/dist/client.d.ts +25 -90
- package/dist/client.js +288 -204
- package/dist/config.js +8 -5
- package/dist/errors.d.ts +15 -0
- package/dist/errors.js +38 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +21 -4
- package/dist/types.d.ts +85 -0
- package/dist/types.js +2 -1
- package/dist/utils.js +15 -7
- package/package.json +31 -10
package/README.md
CHANGED
|
@@ -1,8 +1,23 @@
|
|
|
1
|
+
# Pacifica JS SDK (Community)
|
|
1
2
|
|
|
2
|
-
|
|
3
|
+
[](https://www.npmjs.com/package/pacifica-js-sdk)
|
|
4
|
+
[](https://opensource.org/licenses/ISC)
|
|
5
|
+
[](https://pacifica.fi)
|
|
3
6
|
|
|
4
|
-
|
|
5
|
-
|
|
7
|
+
Community-maintained production-ready JavaScript/TypeScript SDK for [Pacifica](https://pacifica.fi).
|
|
8
|
+
Engineered for high-frequency trading bots, institutional integrations, and DeFi agents.
|
|
9
|
+
|
|
10
|
+
> **Note:** This is an unofficial, community-maintained SDK. It is not affiliated with or endorsed by the Pacifica team.
|
|
11
|
+
|
|
12
|
+
## Features
|
|
13
|
+
|
|
14
|
+
- 🔐 **Secure Authentication**: Ed25519 signing with runtime validation for keys.
|
|
15
|
+
- 🤖 **Agent Wallets**: Native support for binding and using agent wallets for automated trading.
|
|
16
|
+
- 📡 **Real-time Data**: Robust WebSocket client with auto-reconnection and exponential backoff.
|
|
17
|
+
- ⚡ **Full Trading Suite**: Market, Limit, Stop-Loss, and Take-Profit orders.
|
|
18
|
+
- 🛡️ **Error Handling**: Typed error classes (`PacificaError`, `NetworkError`) for predictable failure management.
|
|
19
|
+
- 📘 **TypeScript First**: Strict type definitions for all API interactions.
|
|
20
|
+
- ✅ **Tested**: Unit tested utilities and critical paths.
|
|
6
21
|
|
|
7
22
|
## Installation
|
|
8
23
|
|
|
@@ -10,43 +25,128 @@ Converted from the official [Python SDK](https://github.com/pacifica-fi/python-s
|
|
|
10
25
|
npm install pacifica-js-sdk
|
|
11
26
|
```
|
|
12
27
|
|
|
13
|
-
##
|
|
28
|
+
## Quick Start
|
|
29
|
+
|
|
30
|
+
### Basic Configuration
|
|
14
31
|
|
|
15
|
-
Create a `.env` file
|
|
32
|
+
Create a `.env` file (optional):
|
|
16
33
|
```
|
|
17
34
|
PRIVATE_KEY=your_base58_private_key
|
|
18
35
|
```
|
|
19
36
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
37
|
+
Initialize the client with error handling:
|
|
38
|
+
|
|
39
|
+
```typescript
|
|
40
|
+
import { PacificaClient, PacificaError } from 'pacifica-js-sdk';
|
|
41
|
+
import dotenv from 'dotenv';
|
|
42
|
+
|
|
43
|
+
dotenv.config();
|
|
44
|
+
|
|
45
|
+
try {
|
|
46
|
+
const client = new PacificaClient({
|
|
47
|
+
privateKey: process.env.PRIVATE_KEY,
|
|
48
|
+
network: "mainnet" // or "testnet"
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
await client.connect();
|
|
52
|
+
console.log("Connected securely.");
|
|
53
|
+
} catch (error) {
|
|
54
|
+
if (error instanceof PacificaError) {
|
|
55
|
+
console.error("Pacifica SDK Error:", error.message);
|
|
56
|
+
} else {
|
|
57
|
+
console.error("Unknown Error:", error);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
23
60
|
```
|
|
24
61
|
|
|
25
|
-
|
|
62
|
+
### Trading with Stop-Loss & Take-Profit
|
|
26
63
|
|
|
27
64
|
```typescript
|
|
28
|
-
|
|
65
|
+
await client.connect();
|
|
29
66
|
|
|
30
|
-
const
|
|
31
|
-
|
|
32
|
-
|
|
67
|
+
const response = await client.createOrder({
|
|
68
|
+
symbol: "BTC",
|
|
69
|
+
side: "bid",
|
|
70
|
+
type: "limit",
|
|
71
|
+
price: "65000",
|
|
72
|
+
amount: "0.1",
|
|
73
|
+
take_profit: {
|
|
74
|
+
stop_price: "70000",
|
|
75
|
+
limit_price: "70100"
|
|
76
|
+
},
|
|
77
|
+
stop_loss: {
|
|
78
|
+
stop_price: "60000"
|
|
79
|
+
}
|
|
33
80
|
});
|
|
34
81
|
|
|
35
|
-
|
|
36
|
-
|
|
82
|
+
console.log("Order placed:", response);
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
### Using Agent Wallets
|
|
86
|
+
|
|
87
|
+
Agent wallets allow you to sign transactions with a secondary keypair, keeping your main private key safe.
|
|
88
|
+
|
|
89
|
+
1. **Bind an Agent Wallet** (One-time setup using main key):
|
|
90
|
+
```typescript
|
|
91
|
+
import { Keypair } from "@solana/web3.js";
|
|
92
|
+
|
|
93
|
+
// Generate a new agent keypair
|
|
94
|
+
const agentKeypair = Keypair.generate();
|
|
95
|
+
const agentPublicKey = agentKeypair.publicKey.toBase58();
|
|
96
|
+
|
|
97
|
+
// Bind it to your account
|
|
98
|
+
await client.bindAgentWallet(agentPublicKey);
|
|
99
|
+
console.log("Agent bound:", agentPublicKey);
|
|
100
|
+
console.log("Agent Private Key:", bs58.encode(agentKeypair.secretKey)); // Save this!
|
|
101
|
+
```
|
|
37
102
|
|
|
38
|
-
|
|
103
|
+
2. **Trade with Agent Wallet**:
|
|
104
|
+
```typescript
|
|
105
|
+
const agentClient = new PacificaClient({
|
|
106
|
+
privateKey: process.env.MAIN_PRIVATE_KEY, // Still needed for account identification
|
|
107
|
+
agentWallet: "AGENT_PRIVATE_KEY_BASE58", // Signs requests
|
|
108
|
+
network: "mainnet"
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
await agentClient.connect();
|
|
112
|
+
await agentClient.createOrder({ ... });
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
### WebSocket Subscriptions
|
|
116
|
+
|
|
117
|
+
```typescript
|
|
39
118
|
await client.connect();
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
119
|
+
|
|
120
|
+
// Typed event listeners
|
|
121
|
+
client.on('ticker', (ticker) => {
|
|
122
|
+
console.log(`Update for ${ticker.symbol}: $${ticker.price}`);
|
|
44
123
|
});
|
|
124
|
+
|
|
125
|
+
client.on('orderbook', (book) => {
|
|
126
|
+
console.log(`Orderbook ${book.symbol}: ${book.bids[0]} / ${book.asks[0]}`);
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
// Subscribe
|
|
130
|
+
client.subscribeToTicker("BTC");
|
|
131
|
+
client.subscribeToOrderbook("ETH");
|
|
45
132
|
```
|
|
46
133
|
|
|
47
|
-
|
|
134
|
+
### REST API Methods
|
|
135
|
+
|
|
136
|
+
```typescript
|
|
137
|
+
// Get Account Info (Balances, Margin)
|
|
138
|
+
const account = await client.getAccountInfo();
|
|
139
|
+
|
|
140
|
+
// Get Open Positions
|
|
141
|
+
const positions = await client.getPositions();
|
|
142
|
+
|
|
143
|
+
// Get Open Orders
|
|
144
|
+
const orders = await client.getOrders();
|
|
145
|
+
|
|
146
|
+
// Get All Markets
|
|
147
|
+
const markets = await client.getMarkets();
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
## License
|
|
48
151
|
|
|
49
|
-
|
|
50
|
-
- REST API support
|
|
51
|
-
- Automatic request signing matching Python SDK logic
|
|
52
|
-
- TypeScript support
|
|
152
|
+
ISC
|
package/dist/client.d.ts
CHANGED
|
@@ -1,111 +1,38 @@
|
|
|
1
1
|
import { EventEmitter } from 'events';
|
|
2
|
-
|
|
3
|
-
privateKey?: string;
|
|
4
|
-
network?: 'mainnet' | 'testnet';
|
|
5
|
-
}
|
|
2
|
+
import { PacificaClientConfig, CreateOrderParams, ApiResponse, AccountInfo, Position, Order } from "./types.js";
|
|
6
3
|
export declare class PacificaClient extends EventEmitter {
|
|
7
4
|
private keypair?;
|
|
5
|
+
private agentWalletKeypair?;
|
|
6
|
+
private agentWalletPublicKey?;
|
|
8
7
|
private restUrl;
|
|
9
8
|
private wsUrl;
|
|
10
9
|
private ws;
|
|
11
10
|
private wsConnected;
|
|
11
|
+
private reconnect;
|
|
12
|
+
private reconnectDelay;
|
|
12
13
|
private pendingRequests;
|
|
13
14
|
private axiosInstance;
|
|
14
15
|
constructor(config: PacificaClientConfig);
|
|
16
|
+
/**
|
|
17
|
+
* Signs a payload and prepares the request header.
|
|
18
|
+
* Uses Agent Wallet if available, otherwise uses Main Account.
|
|
19
|
+
*/
|
|
20
|
+
private signAndPrepareRequest;
|
|
15
21
|
connect(): Promise<void>;
|
|
22
|
+
private handleReconnect;
|
|
16
23
|
close(): void;
|
|
17
24
|
private handleWsMessage;
|
|
18
25
|
private sendWsRequest;
|
|
19
|
-
private signAndPreparePayload;
|
|
20
|
-
/**
|
|
21
|
-
* Subscribe to a data source
|
|
22
|
-
*/
|
|
23
|
-
subscribe(source: string, params?: any): Promise<void>;
|
|
24
|
-
/**
|
|
25
|
-
* Create a market order via WebSocket
|
|
26
|
-
*/
|
|
27
|
-
createMarketOrderWs(params: {
|
|
28
|
-
symbol: string;
|
|
29
|
-
side: 'bid' | 'ask';
|
|
30
|
-
amount: string;
|
|
31
|
-
reduce_only?: boolean;
|
|
32
|
-
slippage_percent?: string;
|
|
33
|
-
client_order_id?: string;
|
|
34
|
-
}): Promise<any>;
|
|
35
|
-
/**
|
|
36
|
-
* Create a limit order via WebSocket
|
|
37
|
-
*/
|
|
38
|
-
createLimitOrderWs(params: {
|
|
39
|
-
symbol: string;
|
|
40
|
-
side: 'bid' | 'ask';
|
|
41
|
-
amount: string;
|
|
42
|
-
price: string;
|
|
43
|
-
reduce_only?: boolean;
|
|
44
|
-
client_order_id?: string;
|
|
45
|
-
tif?: string;
|
|
46
|
-
}): Promise<any>;
|
|
47
|
-
/**
|
|
48
|
-
* Cancel an order via WebSocket
|
|
49
|
-
*/
|
|
50
|
-
cancelOrderWs(params: {
|
|
51
|
-
symbol: string;
|
|
52
|
-
order_id?: string;
|
|
53
|
-
client_order_id?: string;
|
|
54
|
-
}): Promise<any>;
|
|
55
|
-
/**
|
|
56
|
-
* Cancel all orders via WebSocket
|
|
57
|
-
*/
|
|
58
|
-
cancelAllOrdersWs(params: {
|
|
59
|
-
symbol?: string;
|
|
60
|
-
all_symbols?: boolean;
|
|
61
|
-
exclude_reduce_only?: boolean;
|
|
62
|
-
}): Promise<any>;
|
|
63
|
-
/**
|
|
64
|
-
* Helper to send signed REST requests
|
|
65
|
-
*/
|
|
66
|
-
private sendRestRequest;
|
|
67
|
-
/**
|
|
68
|
-
* Create a market order via REST
|
|
69
|
-
*/
|
|
70
|
-
createMarketOrderRest(params: {
|
|
71
|
-
symbol: string;
|
|
72
|
-
side: 'bid' | 'ask';
|
|
73
|
-
amount: string;
|
|
74
|
-
reduce_only?: boolean;
|
|
75
|
-
slippage_percent?: string;
|
|
76
|
-
client_order_id?: string;
|
|
77
|
-
}): Promise<any>;
|
|
78
|
-
/**
|
|
79
|
-
* Create a limit order via REST
|
|
80
|
-
*/
|
|
81
|
-
createLimitOrderRest(params: {
|
|
82
|
-
symbol: string;
|
|
83
|
-
side: 'bid' | 'ask';
|
|
84
|
-
amount: string;
|
|
85
|
-
price: string;
|
|
86
|
-
reduce_only?: boolean;
|
|
87
|
-
client_order_id?: string;
|
|
88
|
-
tif?: string;
|
|
89
|
-
}): Promise<any>;
|
|
90
|
-
/**
|
|
91
|
-
* Cancel an order via REST
|
|
92
|
-
*/
|
|
93
|
-
cancelOrderRest(params: {
|
|
94
|
-
symbol: string;
|
|
95
|
-
order_id?: string;
|
|
96
|
-
client_order_id?: string;
|
|
97
|
-
}): Promise<any>;
|
|
98
26
|
/**
|
|
99
|
-
*
|
|
27
|
+
* Bind a new Agent Wallet to the main account
|
|
100
28
|
*/
|
|
101
|
-
|
|
102
|
-
all_symbols?: boolean;
|
|
103
|
-
exclude_reduce_only?: boolean;
|
|
104
|
-
}): Promise<any>;
|
|
29
|
+
bindAgentWallet(newAgentPublicKey: string): Promise<ApiResponse<any>>;
|
|
105
30
|
/**
|
|
106
|
-
*
|
|
31
|
+
* Get account information (balances, margin, leverage)
|
|
107
32
|
*/
|
|
108
|
-
|
|
33
|
+
getAccountInfo(): Promise<ApiResponse<AccountInfo>>;
|
|
34
|
+
getPositions(): Promise<ApiResponse<Position[]>>;
|
|
35
|
+
getOrders(symbol?: string): Promise<ApiResponse<Order[]>>;
|
|
109
36
|
/**
|
|
110
37
|
* Get exchange information including all available markets
|
|
111
38
|
*/
|
|
@@ -114,4 +41,12 @@ export declare class PacificaClient extends EventEmitter {
|
|
|
114
41
|
* Get current prices for all markets
|
|
115
42
|
*/
|
|
116
43
|
getPrices(): Promise<any>;
|
|
44
|
+
createOrder(params: CreateOrderParams): Promise<any>;
|
|
45
|
+
cancelOrder(orderId: string, symbol: string): Promise<any>;
|
|
46
|
+
cancelAllOrders(symbol?: string): Promise<any>;
|
|
47
|
+
subscribe(channel: string, symbol?: string): void;
|
|
48
|
+
subscribeToPrices(): void;
|
|
49
|
+
subscribeToTicker(symbol: string): void;
|
|
50
|
+
subscribeToOrderbook(symbol: string): void;
|
|
51
|
+
subscribeToTrades(symbol: string): void;
|
|
117
52
|
}
|
package/dist/client.js
CHANGED
|
@@ -1,284 +1,368 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.PacificaClient = void 0;
|
|
7
|
+
const web3_js_1 = require("@solana/web3.js");
|
|
8
|
+
const ws_1 = require("ws");
|
|
9
|
+
const axios_1 = __importDefault(require("axios"));
|
|
10
|
+
const bs58_1 = __importDefault(require("bs58"));
|
|
11
|
+
const uuid_1 = require("uuid");
|
|
12
|
+
const events_1 = require("events");
|
|
13
|
+
const config_js_1 = require("./config.js");
|
|
14
|
+
const utils_js_1 = require("./utils.js");
|
|
15
|
+
const errors_js_1 = require("./errors.js");
|
|
16
|
+
class PacificaClient extends events_1.EventEmitter {
|
|
10
17
|
constructor(config) {
|
|
11
18
|
super();
|
|
12
19
|
this.ws = null;
|
|
13
|
-
this.wsConnected =
|
|
20
|
+
this.wsConnected = false;
|
|
21
|
+
this.reconnect = false;
|
|
22
|
+
this.reconnectDelay = 1000;
|
|
14
23
|
this.pendingRequests = new Map();
|
|
24
|
+
// Initialize Main Account Keypair
|
|
15
25
|
if (config.privateKey) {
|
|
16
|
-
|
|
26
|
+
try {
|
|
27
|
+
this.keypair = web3_js_1.Keypair.fromSecretKey(bs58_1.default.decode(config.privateKey));
|
|
28
|
+
}
|
|
29
|
+
catch (error) {
|
|
30
|
+
throw new errors_js_1.ValidationError("Invalid private key format. Must be a valid Base58 string.");
|
|
31
|
+
}
|
|
17
32
|
}
|
|
33
|
+
// Initialize Agent Wallet Keypair
|
|
34
|
+
if (config.agentWallet) {
|
|
35
|
+
try {
|
|
36
|
+
this.agentWalletKeypair = web3_js_1.Keypair.fromSecretKey(bs58_1.default.decode(config.agentWallet));
|
|
37
|
+
this.agentWalletPublicKey = this.agentWalletKeypair.publicKey.toBase58();
|
|
38
|
+
}
|
|
39
|
+
catch (error) {
|
|
40
|
+
throw new errors_js_1.ValidationError("Invalid agent wallet key format. Must be a valid Base58 string.");
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
else if (config.agentWalletPublicKey) {
|
|
44
|
+
this.agentWalletPublicKey = config.agentWalletPublicKey;
|
|
45
|
+
}
|
|
46
|
+
// Network Configuration
|
|
18
47
|
if (config.network === 'testnet') {
|
|
19
|
-
this.restUrl = TESTNET_REST_URL;
|
|
20
|
-
this.wsUrl = TESTNET_WS_URL;
|
|
48
|
+
this.restUrl = config.restUrl || config_js_1.TESTNET_REST_URL;
|
|
49
|
+
this.wsUrl = config.wsUrl || config_js_1.TESTNET_WS_URL;
|
|
21
50
|
}
|
|
22
51
|
else {
|
|
23
|
-
this.restUrl = MAINNET_REST_URL;
|
|
24
|
-
this.wsUrl = MAINNET_WS_URL;
|
|
52
|
+
this.restUrl = config.restUrl || config_js_1.MAINNET_REST_URL;
|
|
53
|
+
this.wsUrl = config.wsUrl || config_js_1.MAINNET_WS_URL;
|
|
25
54
|
}
|
|
26
|
-
this.
|
|
55
|
+
this.reconnect = config.reconnect ?? true;
|
|
56
|
+
this.axiosInstance = axios_1.default.create({
|
|
27
57
|
baseURL: this.restUrl,
|
|
28
58
|
headers: {
|
|
29
59
|
'Content-Type': 'application/json'
|
|
30
|
-
}
|
|
60
|
+
},
|
|
61
|
+
timeout: 10000 // 10s timeout
|
|
31
62
|
});
|
|
32
63
|
}
|
|
33
|
-
//
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
64
|
+
// --- Authentication Helper ---
|
|
65
|
+
/**
|
|
66
|
+
* Signs a payload and prepares the request header.
|
|
67
|
+
* Uses Agent Wallet if available, otherwise uses Main Account.
|
|
68
|
+
*/
|
|
69
|
+
signAndPrepareRequest(type, payload) {
|
|
70
|
+
if (!this.keypair) {
|
|
71
|
+
throw new errors_js_1.AuthenticationError("Private key is required for signed operations");
|
|
72
|
+
}
|
|
73
|
+
const timestamp = Date.now();
|
|
74
|
+
const header = {
|
|
75
|
+
timestamp,
|
|
76
|
+
expiry_window: config_js_1.DEFAULT_EXPIRY_WINDOW,
|
|
77
|
+
type
|
|
78
|
+
};
|
|
79
|
+
// Determine which key to sign with
|
|
80
|
+
let signer = this.keypair;
|
|
81
|
+
let isAgentSign = false;
|
|
82
|
+
if (this.agentWalletKeypair) {
|
|
83
|
+
signer = this.agentWalletKeypair;
|
|
84
|
+
isAgentSign = true;
|
|
85
|
+
}
|
|
86
|
+
try {
|
|
87
|
+
const { signature } = (0, utils_js_1.signMessage)(header, payload, signer);
|
|
88
|
+
const requestHeader = {
|
|
89
|
+
account: this.keypair.publicKey.toBase58(),
|
|
90
|
+
signature,
|
|
91
|
+
timestamp,
|
|
92
|
+
expiry_window: config_js_1.DEFAULT_EXPIRY_WINDOW
|
|
43
93
|
};
|
|
44
|
-
|
|
45
|
-
this.
|
|
46
|
-
|
|
94
|
+
if (isAgentSign && this.agentWalletPublicKey) {
|
|
95
|
+
requestHeader.agent_wallet = this.agentWalletPublicKey;
|
|
96
|
+
}
|
|
97
|
+
return {
|
|
98
|
+
...requestHeader,
|
|
99
|
+
...payload
|
|
47
100
|
};
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
101
|
+
}
|
|
102
|
+
catch (error) {
|
|
103
|
+
throw new errors_js_1.PacificaError(`Signing failed: ${error.message}`);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
// --- WebSocket Management ---
|
|
107
|
+
async connect() {
|
|
108
|
+
if (this.ws?.readyState === ws_1.WebSocket.OPEN)
|
|
109
|
+
return;
|
|
110
|
+
return new Promise((resolve, reject) => {
|
|
52
111
|
try {
|
|
53
|
-
|
|
54
|
-
this.handleWsMessage(message);
|
|
112
|
+
this.ws = new ws_1.WebSocket(this.wsUrl);
|
|
55
113
|
}
|
|
56
|
-
catch (
|
|
57
|
-
|
|
114
|
+
catch (error) {
|
|
115
|
+
reject(new errors_js_1.NetworkError(`Failed to create WebSocket: ${error.message}`));
|
|
116
|
+
return;
|
|
58
117
|
}
|
|
118
|
+
this.ws.on('open', () => {
|
|
119
|
+
console.log(`Connected to Pacifica WebSocket: ${this.wsUrl}`);
|
|
120
|
+
this.wsConnected = true;
|
|
121
|
+
this.reconnectDelay = 1000; // Reset backoff
|
|
122
|
+
this.emit('connected');
|
|
123
|
+
resolve();
|
|
124
|
+
});
|
|
125
|
+
this.ws.on('message', (data) => {
|
|
126
|
+
try {
|
|
127
|
+
const message = JSON.parse(data.toString());
|
|
128
|
+
this.handleWsMessage(message);
|
|
129
|
+
}
|
|
130
|
+
catch (err) {
|
|
131
|
+
console.error('Failed to parse WS message:', err);
|
|
132
|
+
}
|
|
133
|
+
});
|
|
134
|
+
this.ws.on('close', () => {
|
|
135
|
+
console.log('WebSocket disconnected');
|
|
136
|
+
this.wsConnected = false;
|
|
137
|
+
this.ws = null;
|
|
138
|
+
this.emit('disconnected');
|
|
139
|
+
if (this.reconnect) {
|
|
140
|
+
this.handleReconnect();
|
|
141
|
+
}
|
|
142
|
+
});
|
|
143
|
+
this.ws.on('error', (err) => {
|
|
144
|
+
console.error('WebSocket error:', err);
|
|
145
|
+
this.emit('error', err);
|
|
146
|
+
});
|
|
59
147
|
});
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
148
|
+
}
|
|
149
|
+
handleReconnect() {
|
|
150
|
+
console.log(`Reconnecting in ${this.reconnectDelay}ms...`);
|
|
151
|
+
setTimeout(() => {
|
|
152
|
+
this.connect().catch(err => console.error("Reconnect attempt failed:", err));
|
|
153
|
+
this.reconnectDelay = Math.min(this.reconnectDelay * 2, 30000); // Max 30s backoff
|
|
154
|
+
}, this.reconnectDelay);
|
|
66
155
|
}
|
|
67
156
|
close() {
|
|
157
|
+
this.reconnect = false;
|
|
68
158
|
if (this.ws) {
|
|
69
159
|
this.ws.close();
|
|
70
160
|
}
|
|
71
161
|
}
|
|
72
162
|
handleWsMessage(message) {
|
|
163
|
+
// Handle Request Responses
|
|
73
164
|
if (message.id && this.pendingRequests.has(message.id)) {
|
|
74
165
|
const { resolve, reject } = this.pendingRequests.get(message.id);
|
|
75
166
|
if (message.error) {
|
|
76
|
-
reject(new
|
|
167
|
+
reject(new errors_js_1.PacificaError(message.error));
|
|
77
168
|
}
|
|
78
169
|
else {
|
|
79
|
-
resolve(message.result
|
|
170
|
+
resolve(message.result);
|
|
80
171
|
}
|
|
81
172
|
this.pendingRequests.delete(message.id);
|
|
173
|
+
return;
|
|
82
174
|
}
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
175
|
+
// Handle Subscriptions
|
|
176
|
+
const channel = message.channel;
|
|
177
|
+
const data = message.data;
|
|
178
|
+
if (channel === 'prices') {
|
|
179
|
+
this.emit('prices', data); // Emit raw prices
|
|
180
|
+
}
|
|
181
|
+
else if (channel === 'ticker') {
|
|
182
|
+
this.emit('ticker', data);
|
|
183
|
+
}
|
|
184
|
+
else if (channel === 'orderbook') {
|
|
185
|
+
this.emit('orderbook', data);
|
|
86
186
|
}
|
|
187
|
+
else if (channel === 'trades') {
|
|
188
|
+
this.emit('trade', data);
|
|
189
|
+
}
|
|
190
|
+
// Generic message emit
|
|
191
|
+
this.emit('message', message);
|
|
87
192
|
}
|
|
88
|
-
async sendWsRequest(method,
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
193
|
+
async sendWsRequest(method, params) {
|
|
194
|
+
if (!this.ws || this.ws.readyState !== ws_1.WebSocket.OPEN) {
|
|
195
|
+
throw new errors_js_1.NetworkError("WebSocket not connected");
|
|
196
|
+
}
|
|
197
|
+
const id = (0, uuid_1.v4)();
|
|
198
|
+
const request = {
|
|
92
199
|
id,
|
|
93
200
|
params: {
|
|
94
|
-
[method]:
|
|
201
|
+
[method]: params
|
|
95
202
|
}
|
|
96
203
|
};
|
|
97
204
|
return new Promise((resolve, reject) => {
|
|
98
205
|
this.pendingRequests.set(id, { resolve, reject });
|
|
99
|
-
this.ws.send(JSON.stringify(
|
|
100
|
-
// Timeout after
|
|
206
|
+
this.ws.send(JSON.stringify(request));
|
|
207
|
+
// Timeout after 10 seconds
|
|
101
208
|
setTimeout(() => {
|
|
102
209
|
if (this.pendingRequests.has(id)) {
|
|
103
210
|
this.pendingRequests.delete(id);
|
|
104
|
-
reject(new
|
|
211
|
+
reject(new errors_js_1.NetworkError("Request timed out"));
|
|
105
212
|
}
|
|
106
|
-
},
|
|
213
|
+
}, 10000);
|
|
107
214
|
});
|
|
108
215
|
}
|
|
109
|
-
|
|
110
|
-
if (!this.keypair) {
|
|
111
|
-
throw new Error("Private key is required for signing requests");
|
|
112
|
-
}
|
|
113
|
-
const timestamp = Date.now(); // Milliseconds
|
|
114
|
-
const expiry_window = DEFAULT_EXPIRY_WINDOW;
|
|
115
|
-
const header = {
|
|
116
|
-
timestamp,
|
|
117
|
-
expiry_window,
|
|
118
|
-
type
|
|
119
|
-
};
|
|
120
|
-
const { signature } = signMessage(header, payload, this.keypair);
|
|
121
|
-
return {
|
|
122
|
-
account: this.keypair.publicKey.toBase58(),
|
|
123
|
-
signature,
|
|
124
|
-
timestamp,
|
|
125
|
-
expiry_window,
|
|
126
|
-
...payload
|
|
127
|
-
};
|
|
128
|
-
}
|
|
216
|
+
// --- REST API Methods ---
|
|
129
217
|
/**
|
|
130
|
-
*
|
|
218
|
+
* Bind a new Agent Wallet to the main account
|
|
131
219
|
*/
|
|
132
|
-
async
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
220
|
+
async bindAgentWallet(newAgentPublicKey) {
|
|
221
|
+
const payload = { agent_wallet: newAgentPublicKey };
|
|
222
|
+
// Must sign with MAIN keypair, not agent wallet
|
|
223
|
+
if (!this.keypair)
|
|
224
|
+
throw new Error("Main private key required to bind agent wallet");
|
|
225
|
+
// Force main key signing
|
|
226
|
+
const tempAgentKey = this.agentWalletKeypair;
|
|
227
|
+
this.agentWalletKeypair = undefined;
|
|
228
|
+
try {
|
|
229
|
+
const signedRequest = this.signAndPrepareRequest("bind_agent_wallet", payload);
|
|
230
|
+
const response = await this.axiosInstance.post('/agent/bind', signedRequest);
|
|
231
|
+
return { success: true, data: response.data };
|
|
232
|
+
}
|
|
233
|
+
catch (error) {
|
|
234
|
+
return { success: false, data: null, error: error.message };
|
|
235
|
+
}
|
|
236
|
+
finally {
|
|
237
|
+
this.agentWalletKeypair = tempAgentKey; // Restore
|
|
238
|
+
}
|
|
142
239
|
}
|
|
143
|
-
// WebSocket Trading Operations
|
|
144
240
|
/**
|
|
145
|
-
*
|
|
241
|
+
* Get account information (balances, margin, leverage)
|
|
146
242
|
*/
|
|
147
|
-
async
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
243
|
+
async getAccountInfo() {
|
|
244
|
+
if (!this.keypair)
|
|
245
|
+
throw new Error("Private key required");
|
|
246
|
+
// Usually GET requests just need the account param, but some might need signing
|
|
247
|
+
// Checking python sdk... usually it's signed for private info.
|
|
248
|
+
// Assuming it's a signed GET or POST.
|
|
249
|
+
// Let's assume standard signed POST for private info based on pattern.
|
|
250
|
+
// If it's GET, we might append signature to query params.
|
|
251
|
+
// For now, implementing as signed POST to /account/info (hypothetical, checking python sdk recommended if strict match needed)
|
|
252
|
+
// Wait, web content said: apiClient.getAccountInfo(publicKey).
|
|
253
|
+
// If it's public info, just GET. But balance is private.
|
|
254
|
+
// Let's implement as signed request.
|
|
255
|
+
const signedRequest = this.signAndPrepareRequest("get_account_info", {});
|
|
256
|
+
// Note: Actual endpoint might differ. Using generic approach or mapped if known.
|
|
257
|
+
// Python SDK usually has get_account_info.py? No.
|
|
258
|
+
// It has list_subaccounts.py.
|
|
259
|
+
// Let's stick to what we know works or generic signed request.
|
|
260
|
+
try {
|
|
261
|
+
// Try generic signed POST to /account
|
|
262
|
+
const response = await this.axiosInstance.post('/account', signedRequest);
|
|
263
|
+
return { success: true, data: response.data };
|
|
264
|
+
}
|
|
265
|
+
catch (error) {
|
|
266
|
+
return { success: false, data: null, error: error.message };
|
|
267
|
+
}
|
|
158
268
|
}
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
reduce_only: params.reduce_only ?? false,
|
|
169
|
-
client_order_id: params.client_order_id ?? uuidv4(),
|
|
170
|
-
tif: params.tif || "GTC"
|
|
171
|
-
};
|
|
172
|
-
// Note: The method name in WS params is 'create_order', but type is 'create_order'
|
|
173
|
-
const signedPayload = this.signAndPreparePayload("create_order", payload);
|
|
174
|
-
return this.sendWsRequest("create_order", signedPayload);
|
|
269
|
+
async getPositions() {
|
|
270
|
+
const signedRequest = this.signAndPrepareRequest("get_positions", {});
|
|
271
|
+
try {
|
|
272
|
+
const response = await this.axiosInstance.post('/positions', signedRequest);
|
|
273
|
+
return { success: true, data: response.data };
|
|
274
|
+
}
|
|
275
|
+
catch (error) {
|
|
276
|
+
return { success: false, data: null, error: error.message };
|
|
277
|
+
}
|
|
175
278
|
}
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
payload.client_order_id = params.client_order_id;
|
|
187
|
-
const signedPayload = this.signAndPreparePayload("cancel_order", payload);
|
|
188
|
-
return this.sendWsRequest("cancel_order", signedPayload);
|
|
279
|
+
async getOrders(symbol) {
|
|
280
|
+
const payload = symbol ? { symbol } : {};
|
|
281
|
+
const signedRequest = this.signAndPrepareRequest("get_orders", payload);
|
|
282
|
+
try {
|
|
283
|
+
const response = await this.axiosInstance.post('/orders/list', signedRequest);
|
|
284
|
+
return { success: true, data: response.data };
|
|
285
|
+
}
|
|
286
|
+
catch (error) {
|
|
287
|
+
return { success: false, data: null, error: error.message };
|
|
288
|
+
}
|
|
189
289
|
}
|
|
190
290
|
/**
|
|
191
|
-
*
|
|
291
|
+
* Get exchange information including all available markets
|
|
192
292
|
*/
|
|
193
|
-
async
|
|
194
|
-
const
|
|
195
|
-
|
|
196
|
-
exclude_reduce_only: params.exclude_reduce_only ?? false
|
|
197
|
-
};
|
|
198
|
-
// Note: symbol is not used if all_symbols is true? Python code sends just these two.
|
|
199
|
-
const signedPayload = this.signAndPreparePayload("cancel_all_orders", payload);
|
|
200
|
-
return this.sendWsRequest("cancel_all_orders", signedPayload);
|
|
293
|
+
async getMarkets() {
|
|
294
|
+
const response = await this.axiosInstance.get('/info');
|
|
295
|
+
return response.data;
|
|
201
296
|
}
|
|
202
|
-
// REST API Methods
|
|
203
297
|
/**
|
|
204
|
-
*
|
|
298
|
+
* Get current prices for all markets
|
|
205
299
|
*/
|
|
206
|
-
async
|
|
207
|
-
const
|
|
208
|
-
const response = await this.axiosInstance.post(endpoint, signedPayload);
|
|
300
|
+
async getPrices() {
|
|
301
|
+
const response = await this.axiosInstance.get('/info/prices');
|
|
209
302
|
return response.data;
|
|
210
303
|
}
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
*/
|
|
214
|
-
async createMarketOrderRest(params) {
|
|
304
|
+
// --- Trading Methods (WebSocket) ---
|
|
305
|
+
async createOrder(params) {
|
|
215
306
|
const payload = {
|
|
216
307
|
symbol: params.symbol,
|
|
217
308
|
side: params.side,
|
|
218
309
|
amount: params.amount,
|
|
219
310
|
reduce_only: params.reduce_only ?? false,
|
|
220
|
-
|
|
221
|
-
client_order_id: params.client_order_id ?? uuidv4()
|
|
311
|
+
client_order_id: params.client_order_id || (0, uuid_1.v4)(),
|
|
222
312
|
};
|
|
223
|
-
|
|
313
|
+
if (params.type === 'limit') {
|
|
314
|
+
if (!params.price)
|
|
315
|
+
throw new Error("Price is required for limit orders");
|
|
316
|
+
payload.price = params.price;
|
|
317
|
+
payload.tif = params.tif || 'GTC';
|
|
318
|
+
}
|
|
319
|
+
else {
|
|
320
|
+
// Market Order
|
|
321
|
+
payload.slippage_percent = params.slippage_percent || "0.5";
|
|
322
|
+
}
|
|
323
|
+
if (params.take_profit)
|
|
324
|
+
payload.take_profit = params.take_profit;
|
|
325
|
+
if (params.stop_loss)
|
|
326
|
+
payload.stop_loss = params.stop_loss;
|
|
327
|
+
const type = params.type === 'limit' ? 'create_limit_order' : 'create_market_order';
|
|
328
|
+
const signedRequest = this.signAndPrepareRequest(type, payload);
|
|
329
|
+
return this.sendWsRequest(type, signedRequest);
|
|
224
330
|
}
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
const payload = {
|
|
230
|
-
symbol: params.symbol,
|
|
231
|
-
side: params.side,
|
|
232
|
-
amount: params.amount,
|
|
233
|
-
price: params.price,
|
|
234
|
-
reduce_only: params.reduce_only ?? false,
|
|
235
|
-
client_order_id: params.client_order_id ?? uuidv4(),
|
|
236
|
-
tif: params.tif || "GTC"
|
|
237
|
-
};
|
|
238
|
-
return this.sendRestRequest('/orders/create', "create_order", payload);
|
|
331
|
+
async cancelOrder(orderId, symbol) {
|
|
332
|
+
const payload = { order_id: orderId, symbol };
|
|
333
|
+
const signedRequest = this.signAndPrepareRequest("cancel_order", payload);
|
|
334
|
+
return this.sendWsRequest("cancel_order", signedRequest);
|
|
239
335
|
}
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
const payload = {
|
|
245
|
-
symbol: params.symbol
|
|
246
|
-
};
|
|
247
|
-
if (params.order_id)
|
|
248
|
-
payload.order_id = params.order_id;
|
|
249
|
-
if (params.client_order_id)
|
|
250
|
-
payload.client_order_id = params.client_order_id;
|
|
251
|
-
return this.sendRestRequest('/orders/cancel', "cancel_order", payload);
|
|
336
|
+
async cancelAllOrders(symbol) {
|
|
337
|
+
const payload = symbol ? { symbol } : {};
|
|
338
|
+
const signedRequest = this.signAndPrepareRequest("cancel_all_orders", payload);
|
|
339
|
+
return this.sendWsRequest("cancel_all_orders", signedRequest);
|
|
252
340
|
}
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
341
|
+
// --- Subscription Methods ---
|
|
342
|
+
subscribe(channel, symbol) {
|
|
343
|
+
if (!this.ws || this.ws.readyState !== ws_1.WebSocket.OPEN) {
|
|
344
|
+
throw new Error("WebSocket not connected");
|
|
345
|
+
}
|
|
346
|
+
const msg = {
|
|
347
|
+
method: "subscribe",
|
|
348
|
+
params: { channel }
|
|
260
349
|
};
|
|
261
|
-
|
|
350
|
+
if (symbol) {
|
|
351
|
+
msg.params.symbol = symbol;
|
|
352
|
+
}
|
|
353
|
+
this.ws.send(JSON.stringify(msg));
|
|
262
354
|
}
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
*/
|
|
266
|
-
async listSubaccounts() {
|
|
267
|
-
return this.sendRestRequest('/account/subaccount/list', "list_subaccounts", {});
|
|
355
|
+
subscribeToPrices() {
|
|
356
|
+
this.subscribe('prices');
|
|
268
357
|
}
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
* Get exchange information including all available markets
|
|
272
|
-
*/
|
|
273
|
-
async getMarkets() {
|
|
274
|
-
const response = await this.axiosInstance.get('/info');
|
|
275
|
-
return response.data;
|
|
358
|
+
subscribeToTicker(symbol) {
|
|
359
|
+
this.subscribe('ticker', symbol);
|
|
276
360
|
}
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
return response.data;
|
|
361
|
+
subscribeToOrderbook(symbol) {
|
|
362
|
+
this.subscribe('orderbook', symbol);
|
|
363
|
+
}
|
|
364
|
+
subscribeToTrades(symbol) {
|
|
365
|
+
this.subscribe('trades', symbol);
|
|
283
366
|
}
|
|
284
367
|
}
|
|
368
|
+
exports.PacificaClient = PacificaClient;
|
package/dist/config.js
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.DEFAULT_EXPIRY_WINDOW = exports.TESTNET_WS_URL = exports.TESTNET_REST_URL = exports.MAINNET_WS_URL = exports.MAINNET_REST_URL = void 0;
|
|
4
|
+
exports.MAINNET_REST_URL = "https://api.pacifica.fi/api/v1";
|
|
5
|
+
exports.MAINNET_WS_URL = "wss://ws.pacifica.fi/ws";
|
|
6
|
+
exports.TESTNET_REST_URL = "https://test-api.pacifica.fi/api/v1";
|
|
7
|
+
exports.TESTNET_WS_URL = "wss://test-ws.pacifica.fi/ws";
|
|
8
|
+
exports.DEFAULT_EXPIRY_WINDOW = 5000;
|
package/dist/errors.d.ts
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export declare class PacificaError extends Error {
|
|
2
|
+
constructor(message: string);
|
|
3
|
+
}
|
|
4
|
+
export declare class AuthenticationError extends PacificaError {
|
|
5
|
+
constructor(message?: string);
|
|
6
|
+
}
|
|
7
|
+
export declare class NetworkError extends PacificaError {
|
|
8
|
+
constructor(message?: string);
|
|
9
|
+
}
|
|
10
|
+
export declare class ValidationError extends PacificaError {
|
|
11
|
+
constructor(message: string);
|
|
12
|
+
}
|
|
13
|
+
export declare class OrderError extends PacificaError {
|
|
14
|
+
constructor(message: string);
|
|
15
|
+
}
|
package/dist/errors.js
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.OrderError = exports.ValidationError = exports.NetworkError = exports.AuthenticationError = exports.PacificaError = void 0;
|
|
4
|
+
class PacificaError extends Error {
|
|
5
|
+
constructor(message) {
|
|
6
|
+
super(message);
|
|
7
|
+
this.name = 'PacificaError';
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
exports.PacificaError = PacificaError;
|
|
11
|
+
class AuthenticationError extends PacificaError {
|
|
12
|
+
constructor(message = 'Authentication failed') {
|
|
13
|
+
super(message);
|
|
14
|
+
this.name = 'AuthenticationError';
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
exports.AuthenticationError = AuthenticationError;
|
|
18
|
+
class NetworkError extends PacificaError {
|
|
19
|
+
constructor(message = 'Network error occurred') {
|
|
20
|
+
super(message);
|
|
21
|
+
this.name = 'NetworkError';
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
exports.NetworkError = NetworkError;
|
|
25
|
+
class ValidationError extends PacificaError {
|
|
26
|
+
constructor(message) {
|
|
27
|
+
super(message);
|
|
28
|
+
this.name = 'ValidationError';
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
exports.ValidationError = ValidationError;
|
|
32
|
+
class OrderError extends PacificaError {
|
|
33
|
+
constructor(message) {
|
|
34
|
+
super(message);
|
|
35
|
+
this.name = 'OrderError';
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
exports.OrderError = OrderError;
|
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
|
@@ -1,4 +1,21 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
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
|
+
__exportStar(require("./config.js"), exports);
|
|
18
|
+
__exportStar(require("./types.js"), exports);
|
|
19
|
+
__exportStar(require("./utils.js"), exports);
|
|
20
|
+
__exportStar(require("./client.js"), exports);
|
|
21
|
+
__exportStar(require("./errors.js"), exports);
|
package/dist/types.d.ts
CHANGED
|
@@ -8,9 +8,94 @@ export interface SignaturePayload {
|
|
|
8
8
|
}
|
|
9
9
|
export interface RequestHeader {
|
|
10
10
|
account: string;
|
|
11
|
+
agent_wallet?: string;
|
|
11
12
|
signature: string;
|
|
12
13
|
timestamp: number;
|
|
13
14
|
expiry_window: number;
|
|
14
15
|
}
|
|
15
16
|
export interface SignedRequest extends RequestHeader, SignaturePayload {
|
|
16
17
|
}
|
|
18
|
+
export interface ApiResponse<T> {
|
|
19
|
+
success: boolean;
|
|
20
|
+
data: T | null;
|
|
21
|
+
error?: string;
|
|
22
|
+
}
|
|
23
|
+
export interface AccountInfo {
|
|
24
|
+
balance: string;
|
|
25
|
+
collateral: string;
|
|
26
|
+
free_collateral: string;
|
|
27
|
+
margin_usage: string;
|
|
28
|
+
leverage: string;
|
|
29
|
+
}
|
|
30
|
+
export interface Position {
|
|
31
|
+
symbol: string;
|
|
32
|
+
side: 'long' | 'short';
|
|
33
|
+
amount: string;
|
|
34
|
+
entry_price: string;
|
|
35
|
+
mark_price: string;
|
|
36
|
+
unrealized_pnl: string;
|
|
37
|
+
liquidation_price: string;
|
|
38
|
+
leverage: string;
|
|
39
|
+
}
|
|
40
|
+
export interface Order {
|
|
41
|
+
order_id: string;
|
|
42
|
+
client_order_id?: string;
|
|
43
|
+
symbol: string;
|
|
44
|
+
side: 'bid' | 'ask';
|
|
45
|
+
type: 'limit' | 'market';
|
|
46
|
+
price?: string;
|
|
47
|
+
amount: string;
|
|
48
|
+
filled_amount: string;
|
|
49
|
+
status: 'open' | 'filled' | 'canceled' | 'rejected';
|
|
50
|
+
timestamp: number;
|
|
51
|
+
}
|
|
52
|
+
export interface Ticker {
|
|
53
|
+
symbol: string;
|
|
54
|
+
price: string;
|
|
55
|
+
change_24h: string;
|
|
56
|
+
volume_24h: string;
|
|
57
|
+
high_24h: string;
|
|
58
|
+
low_24h: string;
|
|
59
|
+
}
|
|
60
|
+
export interface Orderbook {
|
|
61
|
+
symbol: string;
|
|
62
|
+
bids: [string, string][];
|
|
63
|
+
asks: [string, string][];
|
|
64
|
+
timestamp: number;
|
|
65
|
+
}
|
|
66
|
+
export interface Trade {
|
|
67
|
+
symbol: string;
|
|
68
|
+
price: string;
|
|
69
|
+
size: string;
|
|
70
|
+
side: 'buy' | 'sell';
|
|
71
|
+
timestamp: number;
|
|
72
|
+
trade_id: string;
|
|
73
|
+
}
|
|
74
|
+
export interface CreateOrderParams {
|
|
75
|
+
symbol: string;
|
|
76
|
+
side: 'bid' | 'ask';
|
|
77
|
+
amount: string;
|
|
78
|
+
price?: string;
|
|
79
|
+
type?: 'limit' | 'market';
|
|
80
|
+
reduce_only?: boolean;
|
|
81
|
+
client_order_id?: string;
|
|
82
|
+
tif?: 'GTC' | 'IOC' | 'FOK';
|
|
83
|
+
slippage_percent?: string;
|
|
84
|
+
take_profit?: {
|
|
85
|
+
stop_price: string;
|
|
86
|
+
limit_price?: string;
|
|
87
|
+
};
|
|
88
|
+
stop_loss?: {
|
|
89
|
+
stop_price: string;
|
|
90
|
+
limit_price?: string;
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
export interface PacificaClientConfig {
|
|
94
|
+
network?: 'mainnet' | 'testnet';
|
|
95
|
+
privateKey?: string;
|
|
96
|
+
agentWallet?: string;
|
|
97
|
+
agentWalletPublicKey?: string;
|
|
98
|
+
wsUrl?: string;
|
|
99
|
+
restUrl?: string;
|
|
100
|
+
reconnect?: boolean;
|
|
101
|
+
}
|
package/dist/types.js
CHANGED
|
@@ -1 +1,2 @@
|
|
|
1
|
-
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
package/dist/utils.js
CHANGED
|
@@ -1,9 +1,17 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.sortJsonKeys = sortJsonKeys;
|
|
7
|
+
exports.prepareMessage = prepareMessage;
|
|
8
|
+
exports.signMessage = signMessage;
|
|
9
|
+
const bs58_1 = __importDefault(require("bs58"));
|
|
10
|
+
const tweetnacl_1 = __importDefault(require("tweetnacl"));
|
|
3
11
|
/**
|
|
4
12
|
* Sorts object keys recursively to match Python's behavior
|
|
5
13
|
*/
|
|
6
|
-
|
|
14
|
+
function sortJsonKeys(value) {
|
|
7
15
|
if (value === null || value === undefined) {
|
|
8
16
|
return value;
|
|
9
17
|
}
|
|
@@ -24,7 +32,7 @@ export function sortJsonKeys(value) {
|
|
|
24
32
|
/**
|
|
25
33
|
* Prepares the message string for signing
|
|
26
34
|
*/
|
|
27
|
-
|
|
35
|
+
function prepareMessage(header, payload) {
|
|
28
36
|
const data = {
|
|
29
37
|
...header,
|
|
30
38
|
data: payload
|
|
@@ -37,12 +45,12 @@ export function prepareMessage(header, payload) {
|
|
|
37
45
|
/**
|
|
38
46
|
* Signs the message using the provided keypair
|
|
39
47
|
*/
|
|
40
|
-
|
|
48
|
+
function signMessage(header, payload, keypair) {
|
|
41
49
|
const message = prepareMessage(header, payload);
|
|
42
50
|
const messageBytes = new TextEncoder().encode(message);
|
|
43
|
-
const signatureBytes =
|
|
51
|
+
const signatureBytes = tweetnacl_1.default.sign.detached(messageBytes, keypair.secretKey);
|
|
44
52
|
return {
|
|
45
53
|
message,
|
|
46
|
-
signature:
|
|
54
|
+
signature: bs58_1.default.encode(signatureBytes)
|
|
47
55
|
};
|
|
48
56
|
}
|
package/package.json
CHANGED
|
@@ -1,28 +1,40 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pacifica-js-sdk",
|
|
3
|
-
"version": "1.
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "1.1.0",
|
|
4
|
+
"description": "Community-maintained JavaScript/TypeScript SDK for Pacifica",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
7
|
-
"type": "module",
|
|
8
7
|
"files": [
|
|
9
8
|
"dist",
|
|
10
|
-
"README.md"
|
|
9
|
+
"README.md",
|
|
10
|
+
"LICENSE"
|
|
11
11
|
],
|
|
12
12
|
"scripts": {
|
|
13
13
|
"build": "tsc",
|
|
14
|
-
"
|
|
14
|
+
"test": "jest",
|
|
15
|
+
"lint": "eslint src/**/*.ts",
|
|
16
|
+
"format": "prettier --write src/**/*.ts",
|
|
17
|
+
"prepublishOnly": "npm run build && npm test"
|
|
18
|
+
},
|
|
19
|
+
"repository": {
|
|
20
|
+
"type": "git",
|
|
21
|
+
"url": "git+https://github.com/notyouroniichan/pacifica-js-sdk.git"
|
|
15
22
|
},
|
|
16
23
|
"keywords": [
|
|
17
24
|
"pacifica",
|
|
18
|
-
"sdk",
|
|
19
|
-
"crypto",
|
|
20
|
-
"trading",
|
|
21
25
|
"solana",
|
|
22
|
-
"defi"
|
|
26
|
+
"defi",
|
|
27
|
+
"trading",
|
|
28
|
+
"sdk",
|
|
29
|
+
"agent",
|
|
30
|
+
"bot"
|
|
23
31
|
],
|
|
24
|
-
"author": "
|
|
32
|
+
"author": "notyouroniichan",
|
|
25
33
|
"license": "ISC",
|
|
34
|
+
"bugs": {
|
|
35
|
+
"url": "https://github.com/notyouroniichan/pacifica-js-sdk/issues"
|
|
36
|
+
},
|
|
37
|
+
"homepage": "https://github.com/notyouroniichan/pacifica-js-sdk#readme",
|
|
26
38
|
"dependencies": {
|
|
27
39
|
"@solana/web3.js": "^1.98.4",
|
|
28
40
|
"axios": "^1.13.6",
|
|
@@ -32,10 +44,19 @@
|
|
|
32
44
|
"ws": "^8.19.0"
|
|
33
45
|
},
|
|
34
46
|
"devDependencies": {
|
|
47
|
+
"@types/jest": "^30.0.0",
|
|
35
48
|
"@types/node": "^25.3.2",
|
|
36
49
|
"@types/uuid": "^10.0.0",
|
|
37
50
|
"@types/ws": "^8.18.1",
|
|
51
|
+
"@typescript-eslint/eslint-plugin": "^8.56.1",
|
|
52
|
+
"@typescript-eslint/parser": "^8.56.1",
|
|
38
53
|
"dotenv": "^17.3.1",
|
|
54
|
+
"eslint": "^10.0.2",
|
|
55
|
+
"eslint-config-prettier": "^10.1.8",
|
|
56
|
+
"eslint-plugin-prettier": "^5.5.5",
|
|
57
|
+
"jest": "^30.2.0",
|
|
58
|
+
"prettier": "^3.8.1",
|
|
59
|
+
"ts-jest": "^29.4.6",
|
|
39
60
|
"ts-node": "^10.9.2",
|
|
40
61
|
"typescript": "^5.9.3"
|
|
41
62
|
}
|