@carbon-terminal/trading-sdk 0.2.5
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 +6 -0
- package/dist/client/index.d.ts +1 -0
- package/dist/client/index.js +17 -0
- package/dist/client/trading-sdk.d.ts +42 -0
- package/dist/client/trading-sdk.js +99 -0
- package/dist/client/types.d.ts +9 -0
- package/dist/client/types.js +18 -0
- package/dist/common/exceptions.d.ts +21 -0
- package/dist/common/exceptions.js +51 -0
- package/dist/common/index.d.ts +1 -0
- package/dist/common/index.js +17 -0
- package/dist/entities/account-entity.d.ts +6 -0
- package/dist/entities/account-entity.js +10 -0
- package/dist/entities/cancel-close-request.entity.d.ts +22 -0
- package/dist/entities/cancel-close-request.entity.js +54 -0
- package/dist/entities/cancel-request.entity.d.ts +22 -0
- package/dist/entities/cancel-request.entity.js +54 -0
- package/dist/entities/close-request.entity.d.ts +23 -0
- package/dist/entities/close-request.entity.js +63 -0
- package/dist/entities/index.d.ts +5 -0
- package/dist/entities/index.js +21 -0
- package/dist/entities/library/hookable-entity.d.ts +9 -0
- package/dist/entities/library/hookable-entity.js +20 -0
- package/dist/entities/position-entity.d.ts +29 -0
- package/dist/entities/position-entity.js +110 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +19 -0
- package/dist/modules/account-manager/index.d.ts +9 -0
- package/dist/modules/account-manager/index.js +43 -0
- package/dist/modules/auth-manager/index.d.ts +44 -0
- package/dist/modules/auth-manager/index.js +188 -0
- package/dist/modules/auth-manager/types.d.ts +7 -0
- package/dist/modules/auth-manager/types.js +2 -0
- package/dist/modules/index.d.ts +0 -0
- package/dist/modules/index.js +0 -0
- package/dist/modules/markets-manager/index.d.ts +23 -0
- package/dist/modules/markets-manager/index.js +119 -0
- package/dist/modules/trade-manager/index.d.ts +52 -0
- package/dist/modules/trade-manager/index.js +157 -0
- package/dist/modules/trade-manager/types.d.ts +0 -0
- package/dist/modules/trade-manager/types.js +0 -0
- package/dist/utils/api/getApiUrl.d.ts +1 -0
- package/dist/utils/api/getApiUrl.js +8 -0
- package/dist/utils/auth/apiAuth.d.ts +5 -0
- package/dist/utils/auth/apiAuth.js +23 -0
- package/dist/utils/auth/siweAuth.d.ts +20 -0
- package/dist/utils/auth/siweAuth.js +106 -0
- package/package.json +47 -0
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.TradeManager = void 0;
|
|
4
|
+
const core_1 = require("@carbon-terminal/core");
|
|
5
|
+
const exceptions_1 = require("../../common/exceptions");
|
|
6
|
+
const entities_1 = require("../../entities");
|
|
7
|
+
class TradeManager {
|
|
8
|
+
constructor(tradingSdk) {
|
|
9
|
+
this.tradingSdk = tradingSdk;
|
|
10
|
+
}
|
|
11
|
+
async getPositionInfo(positionId, chainId) {
|
|
12
|
+
const response = await this.tradingSdk.get(`/positions/open-request/status?positionId=${positionId}&chainId=${chainId}`);
|
|
13
|
+
if (!response.success) {
|
|
14
|
+
throw new exceptions_1.APIException({
|
|
15
|
+
message: response.error?.message,
|
|
16
|
+
code: response.error?.code,
|
|
17
|
+
httpStatusCode: response.httpStatusCode,
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
return response.data;
|
|
21
|
+
}
|
|
22
|
+
async getOpenPositionsForSubaccount(subaccountAddress, chainId) {
|
|
23
|
+
const response = await this.tradingSdk.get(`/positions/all?subaccountAddress=${subaccountAddress}&chainId=${chainId}`);
|
|
24
|
+
if (!response.success) {
|
|
25
|
+
throw new exceptions_1.APIException({
|
|
26
|
+
message: response.error?.message,
|
|
27
|
+
code: response.error?.code,
|
|
28
|
+
httpStatusCode: response.httpStatusCode,
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
return response.data;
|
|
32
|
+
}
|
|
33
|
+
async getCloseRequestInfo(closeRequestId, chainId) {
|
|
34
|
+
const response = await this.tradingSdk.get(`/positions/close-request/status?closeRequestId=${closeRequestId}&chainId=${chainId}`);
|
|
35
|
+
if (!response.success) {
|
|
36
|
+
throw new exceptions_1.APIException({
|
|
37
|
+
message: response.error?.message,
|
|
38
|
+
code: response.error?.code,
|
|
39
|
+
httpStatusCode: response.httpStatusCode,
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
return response.data;
|
|
43
|
+
}
|
|
44
|
+
async createPosition(params) {
|
|
45
|
+
let { marketId, subaccountAddress, chainId, positionType, orderType, limitPrice, quantity, deadline, slippage, leverage, solver, useInstantActions, } = params;
|
|
46
|
+
// Add parameter validation
|
|
47
|
+
const response = await this.tradingSdk.post("/trade/create-position", {
|
|
48
|
+
marketId,
|
|
49
|
+
subaccountAddress,
|
|
50
|
+
chainId,
|
|
51
|
+
positionType,
|
|
52
|
+
orderType,
|
|
53
|
+
limitPrice: orderType === core_1.OrderType.LIMIT ? limitPrice : null,
|
|
54
|
+
quantity,
|
|
55
|
+
leverage,
|
|
56
|
+
slippage: slippage ?? 0.01,
|
|
57
|
+
solver,
|
|
58
|
+
useInstantActions,
|
|
59
|
+
});
|
|
60
|
+
if (!response.success) {
|
|
61
|
+
throw new core_1.OpenPositionError(response.error.message, response.error.code);
|
|
62
|
+
}
|
|
63
|
+
const positionEntity = new entities_1.PositionEntity(this.tradingSdk, response.data);
|
|
64
|
+
return positionEntity;
|
|
65
|
+
}
|
|
66
|
+
// first version: only allowing market close
|
|
67
|
+
// todo: implement limit orders through the transaction relay
|
|
68
|
+
async closePosition(params) {
|
|
69
|
+
const response = await this.tradingSdk.post("/trade/close-position", {
|
|
70
|
+
quoteId: params.quoteId,
|
|
71
|
+
quantityToClose: params.quantityToClose,
|
|
72
|
+
chainId: params.chainId,
|
|
73
|
+
slippage: params.slippage,
|
|
74
|
+
orderType: params.orderType,
|
|
75
|
+
useInstantActions: params.useInstantActions,
|
|
76
|
+
});
|
|
77
|
+
return new entities_1.CloseRequestEntity(this.tradingSdk, response.data);
|
|
78
|
+
}
|
|
79
|
+
async setTpSlForPosition(params) {
|
|
80
|
+
const timestamp = Math.floor(Date.now() / 1000);
|
|
81
|
+
const deadline = timestamp + 500;
|
|
82
|
+
await this.tradingSdk.post("/tpsl/create", {
|
|
83
|
+
...params,
|
|
84
|
+
timestamp,
|
|
85
|
+
deadline,
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
async listTpSlForPositions(chainId, quoteIds) {
|
|
89
|
+
const response = await this.tradingSdk.post("/tpsl/list", { chainId, quoteIds });
|
|
90
|
+
if (!response.success) {
|
|
91
|
+
throw new exceptions_1.APIException({
|
|
92
|
+
message: response.error?.message,
|
|
93
|
+
code: response.error?.code,
|
|
94
|
+
httpStatusCode: response.httpStatusCode,
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
return response.data;
|
|
98
|
+
}
|
|
99
|
+
async getLockedParameters(chainId, solver, marketName, leverage) {
|
|
100
|
+
const response = await this.tradingSdk.get(`/solvers/locked-parameters?chainId=${chainId}&solver=${solver}&marketName=${marketName}&leverage=${leverage}`);
|
|
101
|
+
if (!response.success) {
|
|
102
|
+
throw new exceptions_1.APIException({
|
|
103
|
+
message: response.error?.message,
|
|
104
|
+
code: response.error?.code,
|
|
105
|
+
httpStatusCode: response.httpStatusCode,
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
return response.data;
|
|
109
|
+
}
|
|
110
|
+
// Cancel operations
|
|
111
|
+
async createCancelQuoteRequest(params) {
|
|
112
|
+
const response = await this.tradingSdk.post("/trade/cancel-quote", params);
|
|
113
|
+
if (!response.success) {
|
|
114
|
+
throw new exceptions_1.APIException({
|
|
115
|
+
message: response.error?.message,
|
|
116
|
+
code: response.error?.code,
|
|
117
|
+
httpStatusCode: response.httpStatusCode,
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
return new entities_1.CancelRequestEntity(this.tradingSdk, response.data);
|
|
121
|
+
}
|
|
122
|
+
async getCancelQuoteRequestInfo(cancelRequestId, chainId) {
|
|
123
|
+
const response = await this.tradingSdk.get(`/positions/cancel-request/status?cancelRequestId=${cancelRequestId}&chainId=${chainId}`);
|
|
124
|
+
if (!response.success) {
|
|
125
|
+
throw new exceptions_1.APIException({
|
|
126
|
+
message: response.error?.message,
|
|
127
|
+
code: response.error?.code,
|
|
128
|
+
httpStatusCode: response.httpStatusCode,
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
return response.data;
|
|
132
|
+
}
|
|
133
|
+
// Cancel close request operations
|
|
134
|
+
async cancelCloseRequest(params) {
|
|
135
|
+
const response = await this.tradingSdk.post("/trade/cancel-close-request", params);
|
|
136
|
+
if (!response.success) {
|
|
137
|
+
throw new exceptions_1.APIException({
|
|
138
|
+
message: response.error?.message,
|
|
139
|
+
code: response.error?.code,
|
|
140
|
+
httpStatusCode: response.httpStatusCode,
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
return new entities_1.CancelCloseRequestEntity(this.tradingSdk, response.data);
|
|
144
|
+
}
|
|
145
|
+
async getCancelCloseRequestInfo(cancelRequestId, chainId) {
|
|
146
|
+
const response = await this.tradingSdk.get(`/positions/cancel-close-request/status?cancelRequestId=${cancelRequestId}&chainId=${chainId}`);
|
|
147
|
+
if (!response.success) {
|
|
148
|
+
throw new exceptions_1.APIException({
|
|
149
|
+
message: response.error?.message,
|
|
150
|
+
code: response.error?.code,
|
|
151
|
+
httpStatusCode: response.httpStatusCode,
|
|
152
|
+
});
|
|
153
|
+
}
|
|
154
|
+
return response.data;
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
exports.TradeManager = TradeManager;
|
|
File without changes
|
|
File without changes
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function getApiUrl(): string;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.authenticateWithPrivateKey = authenticateWithPrivateKey;
|
|
4
|
+
const core_1 = require("@carbon-terminal/core");
|
|
5
|
+
const ethers_1 = require("ethers");
|
|
6
|
+
async function authenticateWithPrivateKey(apiUrl, privateKey) {
|
|
7
|
+
try {
|
|
8
|
+
// Create wallet from private key
|
|
9
|
+
const wallet = new ethers_1.ethers.Wallet(privateKey);
|
|
10
|
+
const address = wallet.address;
|
|
11
|
+
// Generate typed data for JWT token
|
|
12
|
+
const typedData = (0, core_1.generateIntentXJWTIssueMessage)(address, [core_1.AllowedScopes.FRONTEND_AUTH], core_1.AllowedExpiration.THIRTY_DAYS);
|
|
13
|
+
// Sign typed data
|
|
14
|
+
const signature = await wallet.signTypedData(typedData.domain, typedData.types, typedData.message);
|
|
15
|
+
// Get JWT token
|
|
16
|
+
const token = await (0, core_1.issueIntentXJWTToken)(typedData, signature);
|
|
17
|
+
return { address, token };
|
|
18
|
+
}
|
|
19
|
+
catch (error) {
|
|
20
|
+
console.error("Error:", error.response?.data || error.message);
|
|
21
|
+
throw error;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { AvailableSolvers, SupportedChainId } from "@carbon-terminal/core";
|
|
2
|
+
export declare function siweGetNonce(subaccountAddress: string, chainId: SupportedChainId, solver: AvailableSolvers): Promise<string>;
|
|
3
|
+
export declare function createSiweSignatureWithPrivateKey(subaccountAddress: string, chainId: SupportedChainId, solver: AvailableSolvers, privateKey: string): Promise<{
|
|
4
|
+
expirationTime: string;
|
|
5
|
+
issuedAt: string;
|
|
6
|
+
message: string;
|
|
7
|
+
signature: string;
|
|
8
|
+
nonce: string;
|
|
9
|
+
}>;
|
|
10
|
+
export declare function siweGetAccessToken(subaccountAddress: string, chainId: SupportedChainId, solver: AvailableSolvers, { expirationTime, issuedAt, signature, nonce, }: {
|
|
11
|
+
expirationTime: string;
|
|
12
|
+
issuedAt: string;
|
|
13
|
+
signature: string;
|
|
14
|
+
nonce: string;
|
|
15
|
+
}): Promise<string>;
|
|
16
|
+
export declare function createSiweMessage(address: string, statement: string, chainId: number, nonce: string, domain: string, uri: string, expirationSeconds?: number, version?: string): {
|
|
17
|
+
message: string;
|
|
18
|
+
issuedAt: string;
|
|
19
|
+
expirationTime: string;
|
|
20
|
+
};
|
|
@@ -0,0 +1,106 @@
|
|
|
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.siweGetNonce = siweGetNonce;
|
|
7
|
+
exports.createSiweSignatureWithPrivateKey = createSiweSignatureWithPrivateKey;
|
|
8
|
+
exports.siweGetAccessToken = siweGetAccessToken;
|
|
9
|
+
exports.createSiweMessage = createSiweMessage;
|
|
10
|
+
const core_1 = require("@carbon-terminal/core");
|
|
11
|
+
const axios_1 = __importDefault(require("axios"));
|
|
12
|
+
const ethers_1 = require("ethers");
|
|
13
|
+
const siwe_1 = require("siwe");
|
|
14
|
+
async function siweGetNonce(subaccountAddress, chainId, solver) {
|
|
15
|
+
const parsedSubaccountAddress = (0, ethers_1.getAddress)(subaccountAddress);
|
|
16
|
+
const solverBaseUrl = (0, core_1.getSolverBaseUrl)(solver, chainId);
|
|
17
|
+
const url = `${solverBaseUrl.http}nonce/${parsedSubaccountAddress}`;
|
|
18
|
+
try {
|
|
19
|
+
const response = await axios_1.default.get(url, {
|
|
20
|
+
headers: {
|
|
21
|
+
"Content-Type": "application/json",
|
|
22
|
+
Referer: "https://app.intentx.io/",
|
|
23
|
+
},
|
|
24
|
+
});
|
|
25
|
+
const data = response.data;
|
|
26
|
+
if (!data.nonce) {
|
|
27
|
+
throw new Error("No nonce found");
|
|
28
|
+
}
|
|
29
|
+
return data.nonce;
|
|
30
|
+
}
|
|
31
|
+
catch (error) {
|
|
32
|
+
console.error("Error fetching nonce:");
|
|
33
|
+
if (error.response) {
|
|
34
|
+
// The request was made and the server responded with a status code
|
|
35
|
+
// that falls out of the range of 2xx
|
|
36
|
+
console.error("Response data:", error.response.data);
|
|
37
|
+
console.error("Response status:", error.response.status);
|
|
38
|
+
}
|
|
39
|
+
else if (error.request) {
|
|
40
|
+
// The request was made but no response was received
|
|
41
|
+
console.error("No response received:", error.request);
|
|
42
|
+
}
|
|
43
|
+
else {
|
|
44
|
+
// Something happened in setting up the request that triggered an Error
|
|
45
|
+
console.error("Error message:", error.message);
|
|
46
|
+
}
|
|
47
|
+
throw error;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
async function createSiweSignatureWithPrivateKey(subaccountAddress, chainId, solver, privateKey) {
|
|
51
|
+
const parsedSubaccountAddress = (0, ethers_1.getAddress)(subaccountAddress);
|
|
52
|
+
const nonce = await siweGetNonce(parsedSubaccountAddress, chainId, solver);
|
|
53
|
+
// const TESTING_PRIVATE_KEY = process.env.TESTING_ACCOUNT_PRIVATE_KEY;
|
|
54
|
+
const wallet = new ethers_1.ethers.Wallet(privateKey);
|
|
55
|
+
const userAddress = wallet.address;
|
|
56
|
+
const solverBaseUrl = (0, core_1.getSolverBaseUrl)(solver, chainId);
|
|
57
|
+
const { expirationTime, issuedAt, message } = createSiweMessage(userAddress, `msg: ${parsedSubaccountAddress}`, chainId, nonce,
|
|
58
|
+
// host,
|
|
59
|
+
"app.intentx.io", `${solverBaseUrl?.http}login`);
|
|
60
|
+
const signature = await wallet.signMessage(message);
|
|
61
|
+
return { expirationTime, issuedAt, message, signature, nonce };
|
|
62
|
+
}
|
|
63
|
+
async function siweGetAccessToken(subaccountAddress, chainId, solver, { expirationTime, issuedAt, signature, nonce, }) {
|
|
64
|
+
const parsedSubaccountAddress = (0, ethers_1.getAddress)(subaccountAddress);
|
|
65
|
+
const solverBaseUrl = (0, core_1.getSolverBaseUrl)(solver, chainId);
|
|
66
|
+
try {
|
|
67
|
+
const { data } = await axios_1.default.post(`${solverBaseUrl.http}login`, {
|
|
68
|
+
account_address: parsedSubaccountAddress,
|
|
69
|
+
expiration_time: expirationTime,
|
|
70
|
+
issued_at: issuedAt,
|
|
71
|
+
signature,
|
|
72
|
+
nonce,
|
|
73
|
+
}, {
|
|
74
|
+
headers: {
|
|
75
|
+
"Content-Type": "application/json",
|
|
76
|
+
Referer: "https://app.intentx.io/",
|
|
77
|
+
Origin: "https://app.intentx.io/",
|
|
78
|
+
},
|
|
79
|
+
});
|
|
80
|
+
if (!data.access_token) {
|
|
81
|
+
throw new Error("No access token received");
|
|
82
|
+
}
|
|
83
|
+
return data.access_token;
|
|
84
|
+
}
|
|
85
|
+
catch (error) {
|
|
86
|
+
console.error("SIWE login error:", error.response?.data || error.message);
|
|
87
|
+
throw error;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
function createSiweMessage(address, statement, chainId, nonce, domain, uri, expirationSeconds = 60 * 60 * 24, version = "1") {
|
|
91
|
+
const issuedAt = new Date().toISOString();
|
|
92
|
+
const expirationTime = new Date(Date.now() + expirationSeconds * 1000).toISOString();
|
|
93
|
+
const parsedAddress = (0, ethers_1.getAddress)(address);
|
|
94
|
+
const message = new siwe_1.SiweMessage({
|
|
95
|
+
domain,
|
|
96
|
+
address: parsedAddress,
|
|
97
|
+
statement,
|
|
98
|
+
chainId,
|
|
99
|
+
nonce,
|
|
100
|
+
version,
|
|
101
|
+
uri,
|
|
102
|
+
issuedAt,
|
|
103
|
+
expirationTime,
|
|
104
|
+
});
|
|
105
|
+
return { message: message.prepareMessage(), issuedAt, expirationTime };
|
|
106
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@carbon-terminal/trading-sdk",
|
|
3
|
+
"version": "0.2.5",
|
|
4
|
+
"description": "This SDK is used to interact with the IntentX Trading API.",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"types": "dist/index.d.ts",
|
|
7
|
+
"exports": {
|
|
8
|
+
".": {
|
|
9
|
+
"types": "./dist/index.d.ts",
|
|
10
|
+
"default": "./dist/index.js"
|
|
11
|
+
},
|
|
12
|
+
"./dist/*": {
|
|
13
|
+
"types": "./dist/*.d.ts",
|
|
14
|
+
"default": "./dist/*.js"
|
|
15
|
+
}
|
|
16
|
+
},
|
|
17
|
+
"scripts": {
|
|
18
|
+
"clean": "rm -rf dist",
|
|
19
|
+
"build": "npm run clean && tsc",
|
|
20
|
+
"dev": "tsc -w",
|
|
21
|
+
"test": "echo 'no test yet'",
|
|
22
|
+
"example": "ts-node -r tsconfig-paths/register",
|
|
23
|
+
"build-publish": "npm run build && npm publish --access public"
|
|
24
|
+
},
|
|
25
|
+
"dependencies": {
|
|
26
|
+
"@carbon-terminal/core": "^1.0.0",
|
|
27
|
+
"axios": "^1.6.2",
|
|
28
|
+
"decimal.js": "^10.4.3",
|
|
29
|
+
"jsonwebtoken": "^9.0.2",
|
|
30
|
+
"siwe": "^3.0.0"
|
|
31
|
+
},
|
|
32
|
+
"devDependencies": {
|
|
33
|
+
"@types/node": "^20.10.4",
|
|
34
|
+
"ts-node": "^10.9.1",
|
|
35
|
+
"tsconfig-paths": "^4.2.0",
|
|
36
|
+
"typescript": "^5.3.3"
|
|
37
|
+
},
|
|
38
|
+
"author": "",
|
|
39
|
+
"license": "ISC",
|
|
40
|
+
"directories": {
|
|
41
|
+
"doc": "docs"
|
|
42
|
+
},
|
|
43
|
+
"files": [
|
|
44
|
+
"dist",
|
|
45
|
+
"README.md"
|
|
46
|
+
]
|
|
47
|
+
}
|