@pear-protocol/exchanges-sdk 0.4.0 → 0.5.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/dist/client/binance/rest.js +4 -3
- package/dist/client/bybit/rest.js +2 -1
- package/dist/client/hyperliquid/rest.js +3 -1
- package/dist/client/lighter/rest.js +17 -13
- package/dist/client/lighter/rest.test.js +2 -2
- package/dist/client/okx/rest.js +2 -1
- package/dist/index.d.ts +7 -0
- package/dist/sdk.js +2 -0
- package/package.json +4 -4
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { proxyFetch } from '@pear-protocol/utils';
|
|
1
2
|
import { hmacSha256Hex } from '../hmac';
|
|
2
3
|
|
|
3
4
|
const BASE_URL = "https://fapi.binance.com";
|
|
@@ -8,7 +9,7 @@ async function signedGet(creds, path, params, demo) {
|
|
|
8
9
|
const allParams = { ...params, timestamp, recvWindow: "5000" };
|
|
9
10
|
const queryString = new URLSearchParams(allParams).toString();
|
|
10
11
|
const signature = await hmacSha256Hex(creds.read.api_secret, queryString);
|
|
11
|
-
const response = await
|
|
12
|
+
const response = await proxyFetch(`${baseUrl}${path}?${queryString}&signature=${signature}`, {
|
|
12
13
|
headers: { "X-MBX-APIKEY": creds.read.api_key }
|
|
13
14
|
});
|
|
14
15
|
if (!response.ok) {
|
|
@@ -20,7 +21,7 @@ async function signedGet(creds, path, params, demo) {
|
|
|
20
21
|
}
|
|
21
22
|
async function createListenKey(apiKey, demo = false) {
|
|
22
23
|
const baseUrl = demo ? BASE_URL_TESTNET : BASE_URL;
|
|
23
|
-
const response = await
|
|
24
|
+
const response = await proxyFetch(`${baseUrl}/fapi/v1/listenKey`, {
|
|
24
25
|
method: "POST",
|
|
25
26
|
headers: { "X-MBX-APIKEY": apiKey }
|
|
26
27
|
});
|
|
@@ -32,7 +33,7 @@ async function createListenKey(apiKey, demo = false) {
|
|
|
32
33
|
}
|
|
33
34
|
async function keepAliveListenKey(apiKey, demo = false) {
|
|
34
35
|
const baseUrl = demo ? BASE_URL_TESTNET : BASE_URL;
|
|
35
|
-
const response = await
|
|
36
|
+
const response = await proxyFetch(`${baseUrl}/fapi/v1/listenKey`, {
|
|
36
37
|
method: "PUT",
|
|
37
38
|
headers: { "X-MBX-APIKEY": apiKey }
|
|
38
39
|
});
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { proxyFetch } from '@pear-protocol/utils';
|
|
1
2
|
import { hmacSha256Hex } from '../hmac';
|
|
2
3
|
|
|
3
4
|
const BASE_URL = "https://api.bybit.com";
|
|
@@ -9,7 +10,7 @@ async function signedGet(creds, path, params, demo) {
|
|
|
9
10
|
const queryString = new URLSearchParams(params).toString();
|
|
10
11
|
const signPayload = `${timestamp}${creds.api_key}${recvWindow}${queryString}`;
|
|
11
12
|
const signature = await hmacSha256Hex(creds.api_secret, signPayload);
|
|
12
|
-
const response = await
|
|
13
|
+
const response = await proxyFetch(`${baseUrl}${path}?${queryString}`, {
|
|
13
14
|
headers: {
|
|
14
15
|
"X-BAPI-API-KEY": creds.api_key,
|
|
15
16
|
"X-BAPI-SIGN": signature,
|
|
@@ -1,10 +1,12 @@
|
|
|
1
|
+
import { proxyFetch } from '@pear-protocol/utils';
|
|
2
|
+
|
|
1
3
|
const HL_INFO_URLS = {
|
|
2
4
|
mainnet: "https://api.hyperliquid.xyz/info",
|
|
3
5
|
testnet: "https://api.hyperliquid-testnet.xyz/info"
|
|
4
6
|
};
|
|
5
7
|
async function fetchInfo(body, demo = false) {
|
|
6
8
|
const url = demo ? HL_INFO_URLS.testnet : HL_INFO_URLS.mainnet;
|
|
7
|
-
const res = await
|
|
9
|
+
const res = await proxyFetch(url, {
|
|
8
10
|
method: "POST",
|
|
9
11
|
headers: { "Content-Type": "application/json" },
|
|
10
12
|
body: JSON.stringify(body)
|
|
@@ -1,8 +1,9 @@
|
|
|
1
|
+
import { proxyFetch } from '@pear-protocol/utils';
|
|
1
2
|
import { getLighterBaseUrl } from './constants';
|
|
2
3
|
|
|
3
4
|
async function fetchApiKeys(accountIndex, demo = false) {
|
|
4
5
|
const url = `${getLighterBaseUrl(demo)}/api/v1/apikeys?account_index=${accountIndex}`;
|
|
5
|
-
const response = await
|
|
6
|
+
const response = await proxyFetch(url);
|
|
6
7
|
const data = await readLighterResponse(response, "/apikeys");
|
|
7
8
|
return data.api_keys;
|
|
8
9
|
}
|
|
@@ -16,7 +17,7 @@ async function fetchAccountsByL1Address(l1Address, demo = false) {
|
|
|
16
17
|
l1_address: l1Address,
|
|
17
18
|
...cursor ? { cursor } : {}
|
|
18
19
|
});
|
|
19
|
-
const response = await
|
|
20
|
+
const response = await proxyFetch(`${getLighterBaseUrl(demo)}/api/v1/accountsByL1Address?${params.toString()}`);
|
|
20
21
|
const data = await readLighterResponse(response, "/accountsByL1Address", [200, 21100]);
|
|
21
22
|
if (data.code === 21100) return data;
|
|
22
23
|
message ??= data.message;
|
|
@@ -36,22 +37,25 @@ async function fetchAccountsByL1Address(l1Address, demo = false) {
|
|
|
36
37
|
};
|
|
37
38
|
}
|
|
38
39
|
async function fetchAccount(accountIndex, demo = false) {
|
|
39
|
-
const response = await
|
|
40
|
+
const response = await proxyFetch(`${getLighterBaseUrl(demo)}/api/v1/account?by=index&value=${accountIndex}`);
|
|
40
41
|
return readLighterResponse(response, "/account");
|
|
41
42
|
}
|
|
42
43
|
async function fetchAccountLimits(accountIndex, authToken, demo = false) {
|
|
43
|
-
const response = await
|
|
44
|
+
const response = await proxyFetch(`${getLighterBaseUrl(demo)}/api/v1/accountLimits?account_index=${accountIndex}`, {
|
|
44
45
|
headers: { authorization: authToken }
|
|
45
46
|
});
|
|
46
47
|
return readLighterResponse(response, "/accountLimits");
|
|
47
48
|
}
|
|
48
49
|
async function fetchAccountMetadata(accountIndex, authToken, demo = false) {
|
|
49
|
-
const response = await
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
50
|
+
const response = await proxyFetch(
|
|
51
|
+
`${getLighterBaseUrl(demo)}/api/v1/accountMetadata?by=index&value=${accountIndex}`,
|
|
52
|
+
{
|
|
53
|
+
headers: {
|
|
54
|
+
accept: "application/json",
|
|
55
|
+
authorization: authToken
|
|
56
|
+
}
|
|
53
57
|
}
|
|
54
|
-
|
|
58
|
+
);
|
|
55
59
|
const data = await readLighterResponse(response, "/accountMetadata");
|
|
56
60
|
const matchesAccount = data.account_metadatas?.some((metadata) => metadata.account_index === accountIndex);
|
|
57
61
|
if (!matchesAccount) {
|
|
@@ -59,12 +63,12 @@ async function fetchAccountMetadata(accountIndex, authToken, demo = false) {
|
|
|
59
63
|
}
|
|
60
64
|
}
|
|
61
65
|
async function fetchOrderBookDetails(demo = false) {
|
|
62
|
-
const response = await
|
|
66
|
+
const response = await proxyFetch(`${getLighterBaseUrl(demo)}/api/v1/orderBookDetails?filter=perp`);
|
|
63
67
|
const data = await readLighterResponse(response, "/orderBookDetails");
|
|
64
68
|
return data.order_book_details;
|
|
65
69
|
}
|
|
66
70
|
async function fetchAssetDetails(demo) {
|
|
67
|
-
const response = await
|
|
71
|
+
const response = await proxyFetch(`${getLighterBaseUrl(demo)}/api/v1/assetDetails`);
|
|
68
72
|
const data = await readLighterResponse(response, "/assetDetails");
|
|
69
73
|
return data.asset_details;
|
|
70
74
|
}
|
|
@@ -85,7 +89,7 @@ async function fetchTradesSince(accountIndex, authToken, since, demo = false) {
|
|
|
85
89
|
aggregate: "false",
|
|
86
90
|
...cursor ? { cursor } : {}
|
|
87
91
|
});
|
|
88
|
-
const response = await
|
|
92
|
+
const response = await proxyFetch(`${getLighterBaseUrl(demo)}/api/v1/trades?${params.toString()}`, {
|
|
89
93
|
headers: { authorization: authToken }
|
|
90
94
|
});
|
|
91
95
|
const data = await readLighterResponse(response, "/trades");
|
|
@@ -116,7 +120,7 @@ async function fetchPositionFundingSince(accountIndex, authToken, since, demo =
|
|
|
116
120
|
start_timestamp: since.getTime().toString(),
|
|
117
121
|
...cursor ? { cursor } : {}
|
|
118
122
|
});
|
|
119
|
-
const response = await
|
|
123
|
+
const response = await proxyFetch(`${getLighterBaseUrl(demo)}/api/v1/positionFunding?${params.toString()}`, {
|
|
120
124
|
headers: { authorization: authToken }
|
|
121
125
|
});
|
|
122
126
|
const data = await readLighterResponse(response, "/positionFunding");
|
|
@@ -13,7 +13,7 @@ describe("Lighter REST client", () => {
|
|
|
13
13
|
);
|
|
14
14
|
vi.stubGlobal("fetch", fetchMock);
|
|
15
15
|
await expect(fetchAccount(42, true)).rejects.toThrow("Lighter /account returned 20001: account not found");
|
|
16
|
-
expect(fetchMock).
|
|
16
|
+
expect(fetchMock.mock.calls[0]?.[0]).toBe("https://testnet.zklighter.elliot.ai/api/v1/account?by=index&value=42");
|
|
17
17
|
});
|
|
18
18
|
it("rejects HTTP failures before reading endpoint data", async () => {
|
|
19
19
|
vi.stubGlobal("fetch", vi.fn().mockResolvedValue(new Response("unavailable", { status: 503 })));
|
|
@@ -98,7 +98,7 @@ describe("Lighter REST client", () => {
|
|
|
98
98
|
await expect(fetchAssetDetails(false)).resolves.toEqual([
|
|
99
99
|
{ asset_id: 1, symbol: "ETH", l1_decimals: 18, decimals: 8 }
|
|
100
100
|
]);
|
|
101
|
-
expect(fetchMock).
|
|
101
|
+
expect(fetchMock.mock.calls[0]?.[0]).toBe("https://mainnet.zklighter.elliot.ai/api/v1/assetDetails");
|
|
102
102
|
});
|
|
103
103
|
it("paginates and de-duplicates funding rows by market and funding id", async () => {
|
|
104
104
|
const duplicate = fundingRow({ funding_id: 2, timestamp: 2e3 });
|
package/dist/client/okx/rest.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { proxyFetch } from '@pear-protocol/utils';
|
|
1
2
|
import { hmacSha256Base64 } from '../hmac';
|
|
2
3
|
|
|
3
4
|
const REST_BASE_URL = "https://www.okx.com";
|
|
@@ -17,7 +18,7 @@ async function signedGet(creds, path, params, demo) {
|
|
|
17
18
|
if (demo) {
|
|
18
19
|
headers["x-simulated-trading"] = "1";
|
|
19
20
|
}
|
|
20
|
-
const response = await
|
|
21
|
+
const response = await proxyFetch(`${REST_BASE_URL}${fullPath}`, { headers });
|
|
21
22
|
if (!response.ok) {
|
|
22
23
|
throw new Error(`OKX API error: ${response.status} ${response.statusText}`);
|
|
23
24
|
}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { HttpTypes, Connector, BinanceCredentialsDTO, BybitCredentialsDTO, OkxCredentialsDTO, TradeAccount } from '@pear-protocol/types';
|
|
2
2
|
import PearSDK from '@pear-protocol/core-sdk';
|
|
3
|
+
import { ProxyConfig } from '@pear-protocol/utils';
|
|
3
4
|
import { WebSocket } from 'partysocket';
|
|
4
5
|
import { WalletClient, Transport, Chain, Account } from 'viem';
|
|
5
6
|
|
|
@@ -8,6 +9,12 @@ type ExchangesSDKConfig = {
|
|
|
8
9
|
sdk: PearSDK;
|
|
9
10
|
demo?: boolean;
|
|
10
11
|
options?: ConnectOptions;
|
|
12
|
+
/**
|
|
13
|
+
* Optional forward-proxy for the exchange REST calls. When enabled, requests are re-pointed at
|
|
14
|
+
* `proxy.url` with the original venue host in `X-Proxy-Target`. Injected here because the SDK
|
|
15
|
+
* also runs in the browser, where env vars are unavailable.
|
|
16
|
+
*/
|
|
17
|
+
proxy?: ProxyConfig;
|
|
11
18
|
};
|
|
12
19
|
type AccountHealthStatus = 'active' | 'warning';
|
|
13
20
|
type AccountWarningReason = 'lighter_api_key_invalid' | 'lighter_integrator_not_approved' | 'hyperliquid_api_wallet_invalid' | 'hyperliquid_builder_fee_not_approved' | 'hyperliquid_account_mode_check_failed' | 'hyperliquid_account_mode_unsupported' | 'api_key_invalid';
|
package/dist/sdk.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { configureProxy } from '@pear-protocol/utils';
|
|
1
2
|
import './helper';
|
|
2
3
|
import { createExchangeHelper } from './helper/factory';
|
|
3
4
|
import { checkAccountStatus } from './status';
|
|
@@ -12,6 +13,7 @@ class ExchangesSDK {
|
|
|
12
13
|
this.sdk = config.sdk;
|
|
13
14
|
this.demo = config.demo ?? false;
|
|
14
15
|
this.options = config.options;
|
|
16
|
+
if (config.proxy) configureProxy(config.proxy);
|
|
15
17
|
}
|
|
16
18
|
async connect(tradeAccountId) {
|
|
17
19
|
return this.fetchCredentials(tradeAccountId);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pear-protocol/exchanges-sdk",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.0",
|
|
4
4
|
"description": "Pear Protocol Exchanges SDK",
|
|
5
5
|
"private": false,
|
|
6
6
|
"type": "module",
|
|
@@ -27,9 +27,9 @@
|
|
|
27
27
|
"test:watch": "vitest"
|
|
28
28
|
},
|
|
29
29
|
"dependencies": {
|
|
30
|
-
"@pear-protocol/core-sdk": "^1.
|
|
31
|
-
"@pear-protocol/types": "^1.
|
|
32
|
-
"@pear-protocol/utils": "^0.
|
|
30
|
+
"@pear-protocol/core-sdk": "^1.7.0",
|
|
31
|
+
"@pear-protocol/types": "^1.9.0",
|
|
32
|
+
"@pear-protocol/utils": "^0.2.0",
|
|
33
33
|
"bignumber.js": "^11.1.1",
|
|
34
34
|
"partysocket": "^1.0.3",
|
|
35
35
|
"viem": "^2.48.8"
|