perps-sdk-ts 1.0.1
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/.claude/settings.local.json +11 -0
- package/CONTRACT_METHOD_FIXES.md +189 -0
- package/INTEGRATION_SUMMARY.md +219 -0
- package/OPTIMIZATION_GUIDE.md +238 -0
- package/README.md +384 -0
- package/SNAPSHOT_FIX_SUMMARY.md +161 -0
- package/SNAPSHOT_OPTIMIZATION_SUMMARY.md +199 -0
- package/dist/abis/Referral.d.ts +36 -0
- package/dist/abis/Referral.js +4 -0
- package/dist/abis/Trading.d.ts +57 -0
- package/dist/abis/Trading.js +742 -0
- package/dist/abis/erc20.d.ts +51 -0
- package/dist/abis/erc20.js +4 -0
- package/dist/abis/index.d.ts +8 -0
- package/dist/abis/index.js +24 -0
- package/dist/abis/multicall.d.ts +85 -0
- package/dist/abis/multicall.js +4 -0
- package/dist/abis/pairInfos.d.ts +77 -0
- package/dist/abis/pairInfos.js +4 -0
- package/dist/abis/pairStorage.d.ts +124 -0
- package/dist/abis/pairStorage.js +4 -0
- package/dist/abis/priceAggregator.d.ts +77 -0
- package/dist/abis/priceAggregator.js +4 -0
- package/dist/abis/tardingStorage.d.ts +97 -0
- package/dist/abis/tardingStorage.js +1295 -0
- package/dist/abis.d.ts +623 -0
- package/dist/abis.js +49 -0
- package/dist/client.d.ts +118 -0
- package/dist/client.js +224 -0
- package/dist/config.d.ts +43 -0
- package/dist/config.js +42 -0
- package/dist/crypto/spki.d.ts +55 -0
- package/dist/crypto/spki.js +160 -0
- package/dist/feed/feed_client.d.ts +68 -0
- package/dist/feed/feed_client.js +239 -0
- package/dist/index.d.ts +28 -0
- package/dist/index.js +87 -0
- package/dist/rpc/asset_parameters.d.ts +62 -0
- package/dist/rpc/asset_parameters.js +169 -0
- package/dist/rpc/blended.d.ts +23 -0
- package/dist/rpc/blended.js +55 -0
- package/dist/rpc/category_parameters.d.ts +34 -0
- package/dist/rpc/category_parameters.js +105 -0
- package/dist/rpc/delegation.d.ts +81 -0
- package/dist/rpc/delegation.js +180 -0
- package/dist/rpc/fee_parameters.d.ts +46 -0
- package/dist/rpc/fee_parameters.js +113 -0
- package/dist/rpc/multicall.d.ts +83 -0
- package/dist/rpc/multicall.js +117 -0
- package/dist/rpc/pair_info_queries.d.ts +101 -0
- package/dist/rpc/pair_info_queries.js +161 -0
- package/dist/rpc/pairs_cache.d.ts +62 -0
- package/dist/rpc/pairs_cache.js +240 -0
- package/dist/rpc/referral_operations.d.ts +67 -0
- package/dist/rpc/referral_operations.js +143 -0
- package/dist/rpc/snapshot.d.ts +49 -0
- package/dist/rpc/snapshot.js +162 -0
- package/dist/rpc/trade.d.ts +84 -0
- package/dist/rpc/trade.js +249 -0
- package/dist/rpc/trading_operations.d.ts +103 -0
- package/dist/rpc/trading_operations.js +295 -0
- package/dist/rpc/trading_parameters.d.ts +49 -0
- package/dist/rpc/trading_parameters.js +94 -0
- package/dist/signers/base.d.ts +24 -0
- package/dist/signers/base.js +10 -0
- package/dist/signers/kms.d.ts +47 -0
- package/dist/signers/kms.js +172 -0
- package/dist/signers/local.d.ts +43 -0
- package/dist/signers/local.js +64 -0
- package/dist/types.d.ts +1419 -0
- package/dist/types.js +245 -0
- package/dist/utils.d.ts +52 -0
- package/dist/utils.js +134 -0
- package/examples/advanced-queries.ts +181 -0
- package/examples/basic-usage.ts +78 -0
- package/examples/delegation-and-referrals.ts +130 -0
- package/examples/get-pyth-ids.ts +61 -0
- package/examples/kms-signer.ts +31 -0
- package/examples/optimized-snapshot.ts +153 -0
- package/examples/price-feed-with-sdk-ids.ts +97 -0
- package/examples/price-feed.ts +36 -0
- package/examples/trading-operations.ts +149 -0
- package/package.json +41 -0
- package/src/abis/Referral.ts +3 -0
- package/src/abis/Trading.ts +741 -0
- package/src/abis/erc20.ts +3 -0
- package/src/abis/index.ts +8 -0
- package/src/abis/multicall.ts +3 -0
- package/src/abis/pairInfos.ts +3 -0
- package/src/abis/pairStorage.ts +3 -0
- package/src/abis/priceAggregator.ts +3 -0
- package/src/abis/tardingStorage.ts +1294 -0
- package/src/abis.ts +56 -0
- package/src/client.ts +373 -0
- package/src/config.ts +62 -0
- package/src/crypto/spki.ts +197 -0
- package/src/feed/feed_client.ts +288 -0
- package/src/index.ts +114 -0
- package/src/rpc/asset_parameters.ts +217 -0
- package/src/rpc/blended.ts +77 -0
- package/src/rpc/category_parameters.ts +128 -0
- package/src/rpc/delegation.ts +225 -0
- package/src/rpc/fee_parameters.ts +150 -0
- package/src/rpc/multicall.ts +164 -0
- package/src/rpc/pair_info_queries.ts +208 -0
- package/src/rpc/pairs_cache.ts +268 -0
- package/src/rpc/referral_operations.ts +164 -0
- package/src/rpc/snapshot.ts +210 -0
- package/src/rpc/trade.ts +306 -0
- package/src/rpc/trading_operations.ts +378 -0
- package/src/rpc/trading_parameters.ts +127 -0
- package/src/signers/base.ts +27 -0
- package/src/signers/kms.ts +212 -0
- package/src/signers/local.ts +70 -0
- package/src/types.ts +410 -0
- package/src/utils.ts +155 -0
- package/tsconfig.json +18 -0
|
@@ -0,0 +1,295 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.TradingOperationsRPC = void 0;
|
|
4
|
+
const types_1 = require("../types");
|
|
5
|
+
/**
|
|
6
|
+
* Trading Operations RPC
|
|
7
|
+
* Handles all trading contract interactions including opening/closing trades,
|
|
8
|
+
* updating margins, and managing limit orders.
|
|
9
|
+
*/
|
|
10
|
+
class TradingOperationsRPC {
|
|
11
|
+
constructor(tradingContract, tradingStorageContract, signer) {
|
|
12
|
+
this.tradingContract = tradingContract;
|
|
13
|
+
this.tradingStorageContract = tradingStorageContract;
|
|
14
|
+
this.signer = signer;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Get execution fee required for trading operations
|
|
18
|
+
* @returns Execution fee in ETH
|
|
19
|
+
*/
|
|
20
|
+
async getExecutionFee() {
|
|
21
|
+
const fee = await this.tradingContract.getExecutionFee();
|
|
22
|
+
return (0, types_1.fromBlockchain18)(fee);
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Open a new trade position
|
|
26
|
+
* @param trade - Trade parameters
|
|
27
|
+
* @param orderType - Order type (MARKET, LIMIT, etc.)
|
|
28
|
+
* @param slippageP - Slippage percentage (e.g., 1 for 1%)
|
|
29
|
+
* @param executionFeeEth - Execution fee in ETH (optional, will fetch if not provided)
|
|
30
|
+
* @returns Transaction receipt
|
|
31
|
+
*/
|
|
32
|
+
async openTrade(trade, orderType, slippageP, executionFeeEth) {
|
|
33
|
+
if (!this.signer) {
|
|
34
|
+
throw new Error('Signer required for trading operations');
|
|
35
|
+
}
|
|
36
|
+
// Get execution fee if not provided
|
|
37
|
+
if (!executionFeeEth) {
|
|
38
|
+
executionFeeEth = await this.getExecutionFee();
|
|
39
|
+
}
|
|
40
|
+
// Convert order type to number
|
|
41
|
+
const orderTypeMap = {
|
|
42
|
+
[types_1.TradeInputOrderType.MARKET]: 0,
|
|
43
|
+
[types_1.TradeInputOrderType.STOP_LIMIT]: 1,
|
|
44
|
+
[types_1.TradeInputOrderType.LIMIT]: 2,
|
|
45
|
+
[types_1.TradeInputOrderType.MARKET_ZERO_FEE]: 3,
|
|
46
|
+
};
|
|
47
|
+
// Prepare trade struct with blockchain values
|
|
48
|
+
const tradeStruct = {
|
|
49
|
+
trader: trade.trader,
|
|
50
|
+
pairIndex: trade.pairIndex,
|
|
51
|
+
index: trade.index,
|
|
52
|
+
initialPosToken: (0, types_1.toBlockchain6)(trade.initialPosToken),
|
|
53
|
+
positionSizeUSDC: (0, types_1.toBlockchain6)(trade.positionSizeUSDC),
|
|
54
|
+
openPrice: (0, types_1.toBlockchain10)(trade.openPrice),
|
|
55
|
+
buy: trade.buy,
|
|
56
|
+
leverage: (0, types_1.toBlockchain10)(trade.leverage),
|
|
57
|
+
tp: (0, types_1.toBlockchain10)(trade.tp),
|
|
58
|
+
sl: (0, types_1.toBlockchain10)(trade.sl),
|
|
59
|
+
timestamp: Math.floor(Date.now() / 1000),
|
|
60
|
+
};
|
|
61
|
+
const slippageBlockchain = (0, types_1.toBlockchain10)(slippageP);
|
|
62
|
+
const executionFeeWei = (0, types_1.toBlockchain18)(executionFeeEth);
|
|
63
|
+
// Create transaction
|
|
64
|
+
const tx = {
|
|
65
|
+
to: await this.tradingContract.getAddress(),
|
|
66
|
+
data: this.tradingContract.interface.encodeFunctionData('openTrade', [
|
|
67
|
+
tradeStruct,
|
|
68
|
+
orderTypeMap[orderType],
|
|
69
|
+
slippageBlockchain,
|
|
70
|
+
]),
|
|
71
|
+
value: executionFeeWei,
|
|
72
|
+
};
|
|
73
|
+
return await this.signAndSend(tx);
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Close a trade position at market price
|
|
77
|
+
* @param pairIndex - Trading pair index
|
|
78
|
+
* @param index - Trade index
|
|
79
|
+
* @param closeAmount - Amount of collateral to close (USDC)
|
|
80
|
+
* @param executionFeeEth - Execution fee in ETH (optional)
|
|
81
|
+
* @returns Transaction receipt
|
|
82
|
+
*/
|
|
83
|
+
async closeTradeMarket(pairIndex, index, closeAmount, executionFeeEth) {
|
|
84
|
+
if (!this.signer) {
|
|
85
|
+
throw new Error('Signer required for trading operations');
|
|
86
|
+
}
|
|
87
|
+
if (!executionFeeEth) {
|
|
88
|
+
executionFeeEth = await this.getExecutionFee();
|
|
89
|
+
}
|
|
90
|
+
const closeAmountBlockchain = (0, types_1.toBlockchain6)(closeAmount);
|
|
91
|
+
const executionFeeWei = (0, types_1.toBlockchain18)(executionFeeEth);
|
|
92
|
+
const tx = {
|
|
93
|
+
to: await this.tradingContract.getAddress(),
|
|
94
|
+
data: this.tradingContract.interface.encodeFunctionData('closeTradeMarket', [
|
|
95
|
+
pairIndex,
|
|
96
|
+
index,
|
|
97
|
+
closeAmountBlockchain,
|
|
98
|
+
]),
|
|
99
|
+
value: executionFeeWei,
|
|
100
|
+
};
|
|
101
|
+
return await this.signAndSend(tx);
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Update margin for an existing trade
|
|
105
|
+
* @param pairIndex - Trading pair index
|
|
106
|
+
* @param index - Trade index
|
|
107
|
+
* @param updateType - DEPOSIT or WITHDRAW
|
|
108
|
+
* @param amount - Amount to add/remove (USDC)
|
|
109
|
+
* @param priceUpdateData - Price oracle update data
|
|
110
|
+
* @returns Transaction receipt
|
|
111
|
+
*/
|
|
112
|
+
async updateMargin(pairIndex, index, updateType, amount, priceUpdateData = []) {
|
|
113
|
+
if (!this.signer) {
|
|
114
|
+
throw new Error('Signer required for trading operations');
|
|
115
|
+
}
|
|
116
|
+
const amountBlockchain = (0, types_1.toBlockchain6)(amount);
|
|
117
|
+
const tx = {
|
|
118
|
+
to: await this.tradingContract.getAddress(),
|
|
119
|
+
data: this.tradingContract.interface.encodeFunctionData('updateMargin', [
|
|
120
|
+
pairIndex,
|
|
121
|
+
index,
|
|
122
|
+
updateType,
|
|
123
|
+
amountBlockchain,
|
|
124
|
+
priceUpdateData,
|
|
125
|
+
]),
|
|
126
|
+
value: 1n, // 1 wei for price update
|
|
127
|
+
};
|
|
128
|
+
return await this.signAndSend(tx);
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Update take profit and stop loss for a trade
|
|
132
|
+
* @param pairIndex - Trading pair index
|
|
133
|
+
* @param index - Trade index
|
|
134
|
+
* @param newSl - New stop loss price
|
|
135
|
+
* @param newTp - New take profit price
|
|
136
|
+
* @param priceUpdateData - Price oracle update data
|
|
137
|
+
* @returns Transaction receipt
|
|
138
|
+
*/
|
|
139
|
+
async updateTpAndSl(pairIndex, index, newSl, newTp, priceUpdateData = []) {
|
|
140
|
+
if (!this.signer) {
|
|
141
|
+
throw new Error('Signer required for trading operations');
|
|
142
|
+
}
|
|
143
|
+
const slBlockchain = (0, types_1.toBlockchain10)(newSl);
|
|
144
|
+
const tpBlockchain = (0, types_1.toBlockchain10)(newTp);
|
|
145
|
+
const tx = {
|
|
146
|
+
to: await this.tradingContract.getAddress(),
|
|
147
|
+
data: this.tradingContract.interface.encodeFunctionData('updateTpAndSl', [
|
|
148
|
+
pairIndex,
|
|
149
|
+
index,
|
|
150
|
+
slBlockchain,
|
|
151
|
+
tpBlockchain,
|
|
152
|
+
priceUpdateData,
|
|
153
|
+
]),
|
|
154
|
+
value: 1n, // 1 wei for price update
|
|
155
|
+
};
|
|
156
|
+
return await this.signAndSend(tx);
|
|
157
|
+
}
|
|
158
|
+
/**
|
|
159
|
+
* Cancel a pending limit order
|
|
160
|
+
* @param pairIndex - Trading pair index
|
|
161
|
+
* @param index - Order index
|
|
162
|
+
* @returns Transaction receipt
|
|
163
|
+
*/
|
|
164
|
+
async cancelOpenLimitOrder(pairIndex, index) {
|
|
165
|
+
if (!this.signer) {
|
|
166
|
+
throw new Error('Signer required for trading operations');
|
|
167
|
+
}
|
|
168
|
+
const tx = {
|
|
169
|
+
to: await this.tradingContract.getAddress(),
|
|
170
|
+
data: this.tradingContract.interface.encodeFunctionData('cancelOpenLimitOrder', [
|
|
171
|
+
pairIndex,
|
|
172
|
+
index,
|
|
173
|
+
]),
|
|
174
|
+
};
|
|
175
|
+
return await this.signAndSend(tx);
|
|
176
|
+
}
|
|
177
|
+
/**
|
|
178
|
+
* Get open trade information
|
|
179
|
+
* @param trader - Trader address
|
|
180
|
+
* @param pairIndex - Trading pair index
|
|
181
|
+
* @param index - Trade index
|
|
182
|
+
* @returns Trade information
|
|
183
|
+
*/
|
|
184
|
+
async getOpenTrade(trader, pairIndex, index) {
|
|
185
|
+
const result = await this.tradingStorageContract.openTrades(trader, pairIndex, index);
|
|
186
|
+
return {
|
|
187
|
+
trader: result.trader,
|
|
188
|
+
pairIndex: Number(result.pairIndex),
|
|
189
|
+
index: Number(result.index),
|
|
190
|
+
initialPosToken: (0, types_1.fromBlockchain6)(result.initialPosToken),
|
|
191
|
+
positionSizeUSDC: (0, types_1.fromBlockchain6)(result.positionSizeUSDC),
|
|
192
|
+
openPrice: (0, types_1.fromBlockchain10)(result.openPrice),
|
|
193
|
+
buy: result.buy,
|
|
194
|
+
leverage: (0, types_1.fromBlockchain10)(result.leverage),
|
|
195
|
+
tp: (0, types_1.fromBlockchain10)(result.tp),
|
|
196
|
+
sl: (0, types_1.fromBlockchain10)(result.sl),
|
|
197
|
+
timestamp: Number(result.timestamp),
|
|
198
|
+
};
|
|
199
|
+
}
|
|
200
|
+
/**
|
|
201
|
+
* Get additional trade information
|
|
202
|
+
* @param trader - Trader address
|
|
203
|
+
* @param pairIndex - Trading pair index
|
|
204
|
+
* @param index - Trade index
|
|
205
|
+
* @returns Trade info
|
|
206
|
+
*/
|
|
207
|
+
async getOpenTradeInfo(trader, pairIndex, index) {
|
|
208
|
+
const result = await this.tradingStorageContract.openTradesInfo(trader, pairIndex, index);
|
|
209
|
+
return {
|
|
210
|
+
openInterestUSDC: (0, types_1.fromBlockchain6)(result.openInterestUSDC),
|
|
211
|
+
tpLastUpdated: Number(result.tpLastUpdated),
|
|
212
|
+
slLastUpdated: Number(result.slLastUpdated),
|
|
213
|
+
beingMarketClosed: result.beingMarketClosed,
|
|
214
|
+
lossProtection: Number(result.lossProtection),
|
|
215
|
+
};
|
|
216
|
+
}
|
|
217
|
+
/**
|
|
218
|
+
* Get number of open trades for a trader on a pair
|
|
219
|
+
* @param trader - Trader address
|
|
220
|
+
* @param pairIndex - Trading pair index
|
|
221
|
+
* @returns Number of open trades
|
|
222
|
+
*/
|
|
223
|
+
async getOpenTradesCount(trader, pairIndex) {
|
|
224
|
+
const count = await this.tradingStorageContract.openTradesCount(trader, pairIndex);
|
|
225
|
+
return Number(count);
|
|
226
|
+
}
|
|
227
|
+
/**
|
|
228
|
+
* Get limit order information
|
|
229
|
+
* @param trader - Trader address
|
|
230
|
+
* @param pairIndex - Trading pair index
|
|
231
|
+
* @param index - Order index
|
|
232
|
+
* @returns Limit order information
|
|
233
|
+
*/
|
|
234
|
+
async getOpenLimitOrder(trader, pairIndex, index) {
|
|
235
|
+
const result = await this.tradingStorageContract.getOpenLimitOrder(trader, pairIndex, index);
|
|
236
|
+
return {
|
|
237
|
+
trader: result.trader,
|
|
238
|
+
pairIndex: Number(result.pairIndex),
|
|
239
|
+
index: Number(result.index),
|
|
240
|
+
positionSize: (0, types_1.fromBlockchain6)(result.positionSize),
|
|
241
|
+
buy: result.buy,
|
|
242
|
+
leverage: (0, types_1.fromBlockchain10)(result.leverage),
|
|
243
|
+
tp: (0, types_1.fromBlockchain10)(result.tp),
|
|
244
|
+
sl: (0, types_1.fromBlockchain10)(result.sl),
|
|
245
|
+
price: (0, types_1.fromBlockchain10)(result.price),
|
|
246
|
+
slippageP: (0, types_1.fromBlockchain10)(result.slippageP),
|
|
247
|
+
block: Number(result.block),
|
|
248
|
+
executionFee: (0, types_1.fromBlockchain18)(result.executionFee),
|
|
249
|
+
};
|
|
250
|
+
}
|
|
251
|
+
/**
|
|
252
|
+
* Helper method to sign and send transactions
|
|
253
|
+
*/
|
|
254
|
+
async signAndSend(tx) {
|
|
255
|
+
if (!this.signer) {
|
|
256
|
+
throw new Error('Signer not set');
|
|
257
|
+
}
|
|
258
|
+
const address = await this.signer.getAddress();
|
|
259
|
+
tx.from = address;
|
|
260
|
+
const provider = this.tradingContract.runner?.provider;
|
|
261
|
+
if (!provider) {
|
|
262
|
+
throw new Error('Provider not available');
|
|
263
|
+
}
|
|
264
|
+
if (!tx.chainId) {
|
|
265
|
+
const network = await provider.getNetwork();
|
|
266
|
+
tx.chainId = network.chainId;
|
|
267
|
+
}
|
|
268
|
+
if (tx.nonce === undefined) {
|
|
269
|
+
tx.nonce = await provider.getTransactionCount(address);
|
|
270
|
+
}
|
|
271
|
+
if (!tx.gasLimit) {
|
|
272
|
+
tx.gasLimit = await provider.estimateGas(tx);
|
|
273
|
+
}
|
|
274
|
+
if (!tx.maxFeePerGas && !tx.gasPrice) {
|
|
275
|
+
const feeData = await provider.getFeeData();
|
|
276
|
+
if (feeData.maxFeePerGas) {
|
|
277
|
+
tx.maxFeePerGas = feeData.maxFeePerGas;
|
|
278
|
+
tx.maxPriorityFeePerGas = feeData.maxPriorityFeePerGas || feeData.maxFeePerGas;
|
|
279
|
+
}
|
|
280
|
+
else {
|
|
281
|
+
tx.gasPrice = feeData.gasPrice || undefined;
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
const signedTx = await this.signer.signTransaction(tx);
|
|
285
|
+
const txResponse = await provider.broadcastTransaction(signedTx);
|
|
286
|
+
return await txResponse.wait();
|
|
287
|
+
}
|
|
288
|
+
/**
|
|
289
|
+
* Set signer for transactions
|
|
290
|
+
*/
|
|
291
|
+
setSigner(signer) {
|
|
292
|
+
this.signer = signer;
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
exports.TradingOperationsRPC = TradingOperationsRPC;
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { Contract, Provider } from 'ethers';
|
|
2
|
+
import { TradeInput, LossProtectionInfo } from '../types';
|
|
3
|
+
import { PairsCache } from './pairs_cache';
|
|
4
|
+
/**
|
|
5
|
+
* RPC module for trading-related parameters
|
|
6
|
+
*/
|
|
7
|
+
export declare class TradingParametersRPC {
|
|
8
|
+
private provider;
|
|
9
|
+
private pairInfosContract;
|
|
10
|
+
private pairsCache;
|
|
11
|
+
constructor(provider: Provider, pairInfosContract: Contract, pairsCache: PairsCache);
|
|
12
|
+
/**
|
|
13
|
+
* Get loss protection tier for a trade
|
|
14
|
+
* @param tradeInput - Trade input parameters
|
|
15
|
+
* @returns Loss protection tier
|
|
16
|
+
*/
|
|
17
|
+
getLossProtectionTier(tradeInput: TradeInput): Promise<number>;
|
|
18
|
+
/**
|
|
19
|
+
* Get loss protection percentage for a tier
|
|
20
|
+
* @param tier - Loss protection tier
|
|
21
|
+
* @param pairIndex - Pair index
|
|
22
|
+
* @returns Loss protection percentage
|
|
23
|
+
*/
|
|
24
|
+
getLossProtectionPercentage(tier: number, pairIndex: number): Promise<number>;
|
|
25
|
+
/**
|
|
26
|
+
* Calculate loss protection amount
|
|
27
|
+
* @param tier - Loss protection tier
|
|
28
|
+
* @param pairIndex - Pair index
|
|
29
|
+
* @param collateral - Collateral amount
|
|
30
|
+
* @param openingFee - Opening fee amount
|
|
31
|
+
* @returns Loss protection amount
|
|
32
|
+
*/
|
|
33
|
+
getLossProtectionAmount(tier: number, pairIndex: number, collateral: number, openingFee: number): Promise<number>;
|
|
34
|
+
/**
|
|
35
|
+
* Get complete loss protection info for a trade
|
|
36
|
+
* @param tradeInput - Trade input parameters
|
|
37
|
+
* @param openingFee - Opening fee amount
|
|
38
|
+
* @returns Loss protection info
|
|
39
|
+
*/
|
|
40
|
+
getLossProtectionInfo(tradeInput: TradeInput, openingFee: number): Promise<LossProtectionInfo>;
|
|
41
|
+
/**
|
|
42
|
+
* Get referral rebate for a trader
|
|
43
|
+
* @param trader - Trader address
|
|
44
|
+
* @param referrer - Referrer address
|
|
45
|
+
* @param openingFee - Opening fee amount
|
|
46
|
+
* @returns Rebate amount
|
|
47
|
+
*/
|
|
48
|
+
getTradeReferralRebate(trader: string, referrer: string, openingFee: number): Promise<number>;
|
|
49
|
+
}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.TradingParametersRPC = void 0;
|
|
4
|
+
const types_1 = require("../types");
|
|
5
|
+
/**
|
|
6
|
+
* RPC module for trading-related parameters
|
|
7
|
+
*/
|
|
8
|
+
class TradingParametersRPC {
|
|
9
|
+
constructor(provider, pairInfosContract, pairsCache) {
|
|
10
|
+
this.provider = provider;
|
|
11
|
+
this.pairInfosContract = pairInfosContract;
|
|
12
|
+
this.pairsCache = pairsCache;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Get loss protection tier for a trade
|
|
16
|
+
* @param tradeInput - Trade input parameters
|
|
17
|
+
* @returns Loss protection tier
|
|
18
|
+
*/
|
|
19
|
+
async getLossProtectionTier(tradeInput) {
|
|
20
|
+
const pairIndex = await this.pairsCache.getPairIndex(tradeInput.pair);
|
|
21
|
+
if (pairIndex === undefined) {
|
|
22
|
+
throw new Error(`Pair ${tradeInput.pair} not found`);
|
|
23
|
+
}
|
|
24
|
+
try {
|
|
25
|
+
const tier = await this.pairInfosContract.getLossProtectionTier(pairIndex, (0, types_1.toBlockchain6)(tradeInput.collateralInTrade));
|
|
26
|
+
return Number(tier);
|
|
27
|
+
}
|
|
28
|
+
catch (error) {
|
|
29
|
+
console.error('Error getting loss protection tier:', error);
|
|
30
|
+
return 0;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Get loss protection percentage for a tier
|
|
35
|
+
* @param tier - Loss protection tier
|
|
36
|
+
* @param pairIndex - Pair index
|
|
37
|
+
* @returns Loss protection percentage
|
|
38
|
+
*/
|
|
39
|
+
async getLossProtectionPercentage(tier, pairIndex) {
|
|
40
|
+
try {
|
|
41
|
+
const percentage = await this.pairInfosContract.getLossProtectionP(tier, pairIndex);
|
|
42
|
+
return (0, types_1.fromBlockchain10)(percentage);
|
|
43
|
+
}
|
|
44
|
+
catch (error) {
|
|
45
|
+
console.error('Error getting loss protection percentage:', error);
|
|
46
|
+
return 0;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Calculate loss protection amount
|
|
51
|
+
* @param tier - Loss protection tier
|
|
52
|
+
* @param pairIndex - Pair index
|
|
53
|
+
* @param collateral - Collateral amount
|
|
54
|
+
* @param openingFee - Opening fee amount
|
|
55
|
+
* @returns Loss protection amount
|
|
56
|
+
*/
|
|
57
|
+
async getLossProtectionAmount(tier, pairIndex, collateral, openingFee) {
|
|
58
|
+
const percentage = await this.getLossProtectionPercentage(tier, pairIndex);
|
|
59
|
+
return openingFee * (percentage / 100);
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Get complete loss protection info for a trade
|
|
63
|
+
* @param tradeInput - Trade input parameters
|
|
64
|
+
* @param openingFee - Opening fee amount
|
|
65
|
+
* @returns Loss protection info
|
|
66
|
+
*/
|
|
67
|
+
async getLossProtectionInfo(tradeInput, openingFee) {
|
|
68
|
+
const pairIndex = await this.pairsCache.getPairIndex(tradeInput.pair);
|
|
69
|
+
if (pairIndex === undefined) {
|
|
70
|
+
throw new Error(`Pair ${tradeInput.pair} not found`);
|
|
71
|
+
}
|
|
72
|
+
const tier = await this.getLossProtectionTier(tradeInput);
|
|
73
|
+
const percentage = await this.getLossProtectionPercentage(tier, pairIndex);
|
|
74
|
+
const amount = await this.getLossProtectionAmount(tier, pairIndex, tradeInput.collateralInTrade, openingFee);
|
|
75
|
+
return {
|
|
76
|
+
tier,
|
|
77
|
+
percentage,
|
|
78
|
+
amount,
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Get referral rebate for a trader
|
|
83
|
+
* @param trader - Trader address
|
|
84
|
+
* @param referrer - Referrer address
|
|
85
|
+
* @param openingFee - Opening fee amount
|
|
86
|
+
* @returns Rebate amount
|
|
87
|
+
*/
|
|
88
|
+
async getTradeReferralRebate(trader, referrer, openingFee) {
|
|
89
|
+
// This would typically call the referral contract
|
|
90
|
+
// For now, return 0 as a placeholder
|
|
91
|
+
return 0;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
exports.TradingParametersRPC = TradingParametersRPC;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { TransactionRequest } from 'ethers';
|
|
2
|
+
/**
|
|
3
|
+
* Abstract base class for transaction signers
|
|
4
|
+
* Implementations can use local private keys, AWS KMS, or other signing methods
|
|
5
|
+
*/
|
|
6
|
+
export declare abstract class BaseSigner {
|
|
7
|
+
/**
|
|
8
|
+
* Sign a transaction
|
|
9
|
+
* @param transaction - Transaction to sign
|
|
10
|
+
* @returns Signed transaction
|
|
11
|
+
*/
|
|
12
|
+
abstract signTransaction(transaction: TransactionRequest): Promise<string>;
|
|
13
|
+
/**
|
|
14
|
+
* Get the Ethereum address associated with this signer
|
|
15
|
+
* @returns Ethereum address
|
|
16
|
+
*/
|
|
17
|
+
abstract getAddress(): Promise<string>;
|
|
18
|
+
/**
|
|
19
|
+
* Sign a message
|
|
20
|
+
* @param message - Message to sign
|
|
21
|
+
* @returns Signature
|
|
22
|
+
*/
|
|
23
|
+
abstract signMessage(message: string | Uint8Array): Promise<string>;
|
|
24
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.BaseSigner = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* Abstract base class for transaction signers
|
|
6
|
+
* Implementations can use local private keys, AWS KMS, or other signing methods
|
|
7
|
+
*/
|
|
8
|
+
class BaseSigner {
|
|
9
|
+
}
|
|
10
|
+
exports.BaseSigner = BaseSigner;
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { Provider, TransactionRequest } from 'ethers';
|
|
2
|
+
import { BaseSigner } from './base';
|
|
3
|
+
/**
|
|
4
|
+
* AWS KMS signer for secure transaction signing without exposing private keys
|
|
5
|
+
* Private key never leaves AWS KMS hardware security modules
|
|
6
|
+
*/
|
|
7
|
+
export declare class KMSSigner extends BaseSigner {
|
|
8
|
+
private kmsClient;
|
|
9
|
+
private kmsKeyId;
|
|
10
|
+
private provider;
|
|
11
|
+
private addressCache?;
|
|
12
|
+
/**
|
|
13
|
+
* Create a KMS signer
|
|
14
|
+
* @param kmsKeyId - AWS KMS key ID
|
|
15
|
+
* @param provider - Ethereum provider
|
|
16
|
+
* @param region - AWS region (default: us-east-1)
|
|
17
|
+
*/
|
|
18
|
+
constructor(kmsKeyId: string, provider: Provider, region?: string);
|
|
19
|
+
/**
|
|
20
|
+
* Get the public key from KMS
|
|
21
|
+
* @returns DER-encoded public key
|
|
22
|
+
*/
|
|
23
|
+
private getPublicKey;
|
|
24
|
+
/**
|
|
25
|
+
* Get the Ethereum address derived from the KMS key
|
|
26
|
+
* @returns Ethereum address
|
|
27
|
+
*/
|
|
28
|
+
getAddress(): Promise<string>;
|
|
29
|
+
/**
|
|
30
|
+
* Sign a message hash using KMS
|
|
31
|
+
* @param msgHash - Message hash to sign
|
|
32
|
+
* @returns DER-encoded signature
|
|
33
|
+
*/
|
|
34
|
+
private signMsgHash;
|
|
35
|
+
/**
|
|
36
|
+
* Sign a transaction using KMS
|
|
37
|
+
* @param transaction - Transaction to sign
|
|
38
|
+
* @returns Signed transaction as hex string
|
|
39
|
+
*/
|
|
40
|
+
signTransaction(transaction: TransactionRequest): Promise<string>;
|
|
41
|
+
/**
|
|
42
|
+
* Sign a message using KMS
|
|
43
|
+
* @param message - Message to sign
|
|
44
|
+
* @returns Signature as hex string
|
|
45
|
+
*/
|
|
46
|
+
signMessage(message: string | Uint8Array): Promise<string>;
|
|
47
|
+
}
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.KMSSigner = void 0;
|
|
4
|
+
const client_kms_1 = require("@aws-sdk/client-kms");
|
|
5
|
+
const ethers_1 = require("ethers");
|
|
6
|
+
const base_1 = require("./base");
|
|
7
|
+
const spki_1 = require("../crypto/spki");
|
|
8
|
+
/**
|
|
9
|
+
* AWS KMS signer for secure transaction signing without exposing private keys
|
|
10
|
+
* Private key never leaves AWS KMS hardware security modules
|
|
11
|
+
*/
|
|
12
|
+
class KMSSigner extends base_1.BaseSigner {
|
|
13
|
+
/**
|
|
14
|
+
* Create a KMS signer
|
|
15
|
+
* @param kmsKeyId - AWS KMS key ID
|
|
16
|
+
* @param provider - Ethereum provider
|
|
17
|
+
* @param region - AWS region (default: us-east-1)
|
|
18
|
+
*/
|
|
19
|
+
constructor(kmsKeyId, provider, region = 'us-east-1') {
|
|
20
|
+
super();
|
|
21
|
+
this.kmsKeyId = kmsKeyId;
|
|
22
|
+
this.provider = provider;
|
|
23
|
+
this.kmsClient = new client_kms_1.KMSClient({ region });
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Get the public key from KMS
|
|
27
|
+
* @returns DER-encoded public key
|
|
28
|
+
*/
|
|
29
|
+
async getPublicKey() {
|
|
30
|
+
const command = new client_kms_1.GetPublicKeyCommand({
|
|
31
|
+
KeyId: this.kmsKeyId,
|
|
32
|
+
});
|
|
33
|
+
const response = await this.kmsClient.send(command);
|
|
34
|
+
if (!response.PublicKey) {
|
|
35
|
+
throw new Error('Failed to get public key from KMS');
|
|
36
|
+
}
|
|
37
|
+
return response.PublicKey;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Get the Ethereum address derived from the KMS key
|
|
41
|
+
* @returns Ethereum address
|
|
42
|
+
*/
|
|
43
|
+
async getAddress() {
|
|
44
|
+
if (this.addressCache) {
|
|
45
|
+
return this.addressCache;
|
|
46
|
+
}
|
|
47
|
+
const publicKey = await this.getPublicKey();
|
|
48
|
+
this.addressCache = (0, spki_1.derEncodedPublicKeyToEthAddress)(publicKey);
|
|
49
|
+
return this.addressCache;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Sign a message hash using KMS
|
|
53
|
+
* @param msgHash - Message hash to sign
|
|
54
|
+
* @returns DER-encoded signature
|
|
55
|
+
*/
|
|
56
|
+
async signMsgHash(msgHash) {
|
|
57
|
+
const command = new client_kms_1.SignCommand({
|
|
58
|
+
KeyId: this.kmsKeyId,
|
|
59
|
+
Message: msgHash,
|
|
60
|
+
MessageType: 'DIGEST',
|
|
61
|
+
SigningAlgorithm: 'ECDSA_SHA_256',
|
|
62
|
+
});
|
|
63
|
+
const response = await this.kmsClient.send(command);
|
|
64
|
+
if (!response.Signature) {
|
|
65
|
+
throw new Error('Failed to sign message with KMS');
|
|
66
|
+
}
|
|
67
|
+
return response.Signature;
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Sign a transaction using KMS
|
|
71
|
+
* @param transaction - Transaction to sign
|
|
72
|
+
* @returns Signed transaction as hex string
|
|
73
|
+
*/
|
|
74
|
+
async signTransaction(transaction) {
|
|
75
|
+
// Get the address to fill in the 'from' field if not set
|
|
76
|
+
const address = await this.getAddress();
|
|
77
|
+
// Fill in missing fields
|
|
78
|
+
const tx = {
|
|
79
|
+
...transaction,
|
|
80
|
+
from: address,
|
|
81
|
+
};
|
|
82
|
+
// Get chain ID if not provided
|
|
83
|
+
if (!tx.chainId) {
|
|
84
|
+
const network = await this.provider.getNetwork();
|
|
85
|
+
tx.chainId = network.chainId;
|
|
86
|
+
}
|
|
87
|
+
// Get nonce if not provided
|
|
88
|
+
if (tx.nonce === undefined) {
|
|
89
|
+
tx.nonce = await this.provider.getTransactionCount(address);
|
|
90
|
+
}
|
|
91
|
+
// Estimate gas if not provided
|
|
92
|
+
if (!tx.gasLimit) {
|
|
93
|
+
tx.gasLimit = await this.provider.estimateGas(tx);
|
|
94
|
+
}
|
|
95
|
+
// Get gas price if not provided (for legacy transactions)
|
|
96
|
+
if (!tx.maxFeePerGas && !tx.gasPrice) {
|
|
97
|
+
const feeData = await this.provider.getFeeData();
|
|
98
|
+
if (feeData.maxFeePerGas) {
|
|
99
|
+
tx.maxFeePerGas = feeData.maxFeePerGas;
|
|
100
|
+
tx.maxPriorityFeePerGas = feeData.maxPriorityFeePerGas || feeData.maxFeePerGas;
|
|
101
|
+
}
|
|
102
|
+
else {
|
|
103
|
+
tx.gasPrice = feeData.gasPrice || undefined;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
// Resolve address fields to strings
|
|
107
|
+
const resolvedTo = tx.to ? await (0, ethers_1.resolveAddress)(tx.to, this.provider) : null;
|
|
108
|
+
const resolvedFrom = tx.from ? await (0, ethers_1.resolveAddress)(tx.from, this.provider) : address;
|
|
109
|
+
// Create a transaction object with resolved fields
|
|
110
|
+
const resolvedTx = {
|
|
111
|
+
type: tx.type,
|
|
112
|
+
to: resolvedTo,
|
|
113
|
+
from: resolvedFrom,
|
|
114
|
+
nonce: tx.nonce,
|
|
115
|
+
gasLimit: tx.gasLimit,
|
|
116
|
+
gasPrice: tx.gasPrice,
|
|
117
|
+
maxFeePerGas: tx.maxFeePerGas,
|
|
118
|
+
maxPriorityFeePerGas: tx.maxPriorityFeePerGas,
|
|
119
|
+
data: tx.data,
|
|
120
|
+
value: tx.value,
|
|
121
|
+
chainId: tx.chainId,
|
|
122
|
+
accessList: tx.accessList,
|
|
123
|
+
};
|
|
124
|
+
// Create unsigned transaction
|
|
125
|
+
const unsignedTx = ethers_1.Transaction.from(resolvedTx);
|
|
126
|
+
const unsignedSerialized = unsignedTx.unsignedSerialized;
|
|
127
|
+
// Hash the unsigned transaction
|
|
128
|
+
const msgHash = (0, ethers_1.keccak256)(unsignedSerialized);
|
|
129
|
+
const msgHashBytes = (0, ethers_1.getBytes)(msgHash);
|
|
130
|
+
// Sign with KMS
|
|
131
|
+
const kmsSignature = await this.signMsgHash(msgHashBytes);
|
|
132
|
+
// Parse signature and recover v
|
|
133
|
+
const { r, s, v } = (0, spki_1.getSigRSV)(kmsSignature, msgHash, address);
|
|
134
|
+
// Create signed transaction
|
|
135
|
+
unsignedTx.signature = { r, s, v };
|
|
136
|
+
return unsignedTx.serialized;
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
139
|
+
* Sign a message using KMS
|
|
140
|
+
* @param message - Message to sign
|
|
141
|
+
* @returns Signature as hex string
|
|
142
|
+
*/
|
|
143
|
+
async signMessage(message) {
|
|
144
|
+
const address = await this.getAddress();
|
|
145
|
+
// Convert message to bytes
|
|
146
|
+
const messageBytes = typeof message === 'string' ? Buffer.from(message, 'utf8') : message;
|
|
147
|
+
// Create Ethereum signed message hash
|
|
148
|
+
const messageHash = (0, ethers_1.keccak256)(concat([
|
|
149
|
+
Buffer.from('\x19Ethereum Signed Message:\n', 'utf8'),
|
|
150
|
+
Buffer.from(String(messageBytes.length), 'utf8'),
|
|
151
|
+
messageBytes,
|
|
152
|
+
]));
|
|
153
|
+
const msgHashBytes = (0, ethers_1.getBytes)(messageHash);
|
|
154
|
+
// Sign with KMS
|
|
155
|
+
const kmsSignature = await this.signMsgHash(msgHashBytes);
|
|
156
|
+
// Parse signature and recover v
|
|
157
|
+
const { r, s, v } = (0, spki_1.getSigRSV)(kmsSignature, messageHash, address);
|
|
158
|
+
return (0, spki_1.signatureToHex)(r, s, v);
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
exports.KMSSigner = KMSSigner;
|
|
162
|
+
// Helper function for concat
|
|
163
|
+
function concat(arrays) {
|
|
164
|
+
const totalLength = arrays.reduce((acc, arr) => acc + arr.length, 0);
|
|
165
|
+
const result = new Uint8Array(totalLength);
|
|
166
|
+
let offset = 0;
|
|
167
|
+
for (const arr of arrays) {
|
|
168
|
+
result.set(arr, offset);
|
|
169
|
+
offset += arr.length;
|
|
170
|
+
}
|
|
171
|
+
return result;
|
|
172
|
+
}
|