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,240 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.PairsCache = void 0;
|
|
4
|
+
const types_1 = require("../types");
|
|
5
|
+
const config_1 = require("../config");
|
|
6
|
+
/**
|
|
7
|
+
* RPC module for caching and managing trading pair information
|
|
8
|
+
*/
|
|
9
|
+
class PairsCache {
|
|
10
|
+
constructor(provider, pairStorageContract) {
|
|
11
|
+
this.getPairInfoNameFromIndex = async (index) => {
|
|
12
|
+
const pairData = await this.pairStorageContract.getPairData(index);
|
|
13
|
+
return {
|
|
14
|
+
from: pairData.from,
|
|
15
|
+
to: pairData.to
|
|
16
|
+
};
|
|
17
|
+
};
|
|
18
|
+
this.getOtherPairInfoFromIndex = async (index) => {
|
|
19
|
+
const pairData = await this.pairStorageContract.pairs(index);
|
|
20
|
+
const values = pairData[9];
|
|
21
|
+
const result = {
|
|
22
|
+
feed: {
|
|
23
|
+
maxOpenDeviationP: pairData.feed.maxOpenDeviationP,
|
|
24
|
+
maxCloseDeviationP: pairData.feed.maxCloseDeviationP,
|
|
25
|
+
feedId: pairData.feed.feedId,
|
|
26
|
+
},
|
|
27
|
+
backupFeed: {
|
|
28
|
+
maxDeviationP: pairData.backupFeed.maxDeviationP,
|
|
29
|
+
feedId: pairData.backupFeed.feedId,
|
|
30
|
+
},
|
|
31
|
+
spreadP: pairData.spreadP,
|
|
32
|
+
pnlSpreadP: pairData.pnlSpreadP,
|
|
33
|
+
leverages: {
|
|
34
|
+
minLeverage: pairData.leverages.minLeverage,
|
|
35
|
+
maxLeverage: pairData.leverages.maxLeverage,
|
|
36
|
+
pnlMinLeverage: pairData.leverages.pnlMinLeverage,
|
|
37
|
+
pnlMaxLeverage: pairData.leverages.pnlMaxLeverage,
|
|
38
|
+
},
|
|
39
|
+
priceImpactMultiplier: pairData.priceImpactMultiplier,
|
|
40
|
+
skewImpactMultiplier: pairData.skewImpactMultiplier,
|
|
41
|
+
groupIndex: pairData.groupIndex,
|
|
42
|
+
feeIndex: pairData.feeIndex,
|
|
43
|
+
values: {
|
|
44
|
+
maxGainP: values.maxGainP,
|
|
45
|
+
maxSlP: values.maxSlP,
|
|
46
|
+
maxLongOiP: values.maxLongOiP,
|
|
47
|
+
maxShortOiP: values.maxShortOiP,
|
|
48
|
+
groupOpenInterestPercentageP: values.groupOpenInterestPercentageP,
|
|
49
|
+
maxWalletOIP: values.maxWalletOIP,
|
|
50
|
+
isUSDCAligned: values.isUSDCAligned,
|
|
51
|
+
},
|
|
52
|
+
};
|
|
53
|
+
return result;
|
|
54
|
+
};
|
|
55
|
+
this.provider = provider;
|
|
56
|
+
this.pairStorageContract = pairStorageContract;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Get all trading pairs from blockchain (with caching)
|
|
60
|
+
* @param forceRefresh - Force refresh from blockchain
|
|
61
|
+
* @returns Map of pair index to PairInfo
|
|
62
|
+
*/
|
|
63
|
+
async getPairsInfo(forceRefresh = false) {
|
|
64
|
+
if (this.pairsCache && !forceRefresh) {
|
|
65
|
+
return this.pairsCache;
|
|
66
|
+
}
|
|
67
|
+
const pairs = new Map();
|
|
68
|
+
const pairNameToIndex = new Map();
|
|
69
|
+
try {
|
|
70
|
+
// Get pairs count
|
|
71
|
+
const pairsCount = await this.pairStorageContract.pairsCount();
|
|
72
|
+
const count = Number(pairsCount);
|
|
73
|
+
// Fetch all pairs
|
|
74
|
+
for (let i = 0; i < count; i++) {
|
|
75
|
+
const pairData = await this.getOtherPairInfoFromIndex(i);
|
|
76
|
+
const pair = await this.getPairInfoNameFromIndex(i);
|
|
77
|
+
const pairInfo = {
|
|
78
|
+
from: pair.from,
|
|
79
|
+
to: pair.to,
|
|
80
|
+
spread: {
|
|
81
|
+
min: (0, types_1.fromBlockchain10)(pairData.spreadP),
|
|
82
|
+
max: (0, types_1.fromBlockchain10)(pairData.spreadP),
|
|
83
|
+
},
|
|
84
|
+
groupIndex: Number(pairData.groupIndex),
|
|
85
|
+
feeIndex: Number(pairData.feeIndex),
|
|
86
|
+
maxLeverage: (0, types_1.fromBlockchain10)(pairData.leverages.maxLeverage),
|
|
87
|
+
maxShortOiP: (0, types_1.fromBlockchain10)(pairData.values.maxShortOiP),
|
|
88
|
+
maxLongOiP: (0, types_1.fromBlockchain10)(pairData.values.maxLongOiP)
|
|
89
|
+
};
|
|
90
|
+
pairs.set(i, pairInfo);
|
|
91
|
+
pairNameToIndex.set(`${pairInfo.from}/${pairInfo.to}`, i);
|
|
92
|
+
}
|
|
93
|
+
this.pairsCache = pairs;
|
|
94
|
+
this.pairNameToIndexMap = pairNameToIndex;
|
|
95
|
+
return pairs;
|
|
96
|
+
}
|
|
97
|
+
catch (error) {
|
|
98
|
+
console.error('Error fetching pairs info from blockchain:', error);
|
|
99
|
+
throw error;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
async getPairBackend(index) {
|
|
103
|
+
const [pair, group, fee] = await this.pairStorageContract.pairsBackend(index);
|
|
104
|
+
const mapped = {
|
|
105
|
+
pair: {
|
|
106
|
+
feed: {
|
|
107
|
+
maxOpenDeviationP: pair.feed.maxOpenDeviationP,
|
|
108
|
+
maxCloseDeviationP: pair.feed.maxCloseDeviationP,
|
|
109
|
+
feedId: pair.feed.feedId,
|
|
110
|
+
},
|
|
111
|
+
backupFeed: {
|
|
112
|
+
maxDeviationP: pair.backupFeed.maxDeviationP,
|
|
113
|
+
feedId: pair.backupFeed.feedId,
|
|
114
|
+
},
|
|
115
|
+
spreadP: pair.spreadP,
|
|
116
|
+
pnlSpreadP: pair.pnlSpreadP,
|
|
117
|
+
leverages: {
|
|
118
|
+
minLeverage: pair.leverages.minLeverage,
|
|
119
|
+
maxLeverage: pair.leverages.maxLeverage,
|
|
120
|
+
pnlMinLeverage: pair.leverages.pnlMinLeverage,
|
|
121
|
+
pnlMaxLeverage: pair.leverages.pnlMaxLeverage,
|
|
122
|
+
},
|
|
123
|
+
priceImpactMultiplier: pair.priceImpactMultiplier,
|
|
124
|
+
skewImpactMultiplier: pair.skewImpactMultiplier,
|
|
125
|
+
groupIndex: pair.groupIndex,
|
|
126
|
+
feeIndex: pair.feeIndex,
|
|
127
|
+
values: {
|
|
128
|
+
maxGainP: pair[9].maxGainP,
|
|
129
|
+
maxSlP: pair[9].maxSlP,
|
|
130
|
+
maxLongOiP: pair[9].maxLongOiP,
|
|
131
|
+
maxShortOiP: pair[9].maxShortOiP,
|
|
132
|
+
groupOpenInterestPercentageP: pair[9].groupOpenInterestPercentageP,
|
|
133
|
+
maxWalletOIP: pair[9].maxWalletOIP,
|
|
134
|
+
isUSDCAligned: pair[9].isUSDCAligned,
|
|
135
|
+
},
|
|
136
|
+
},
|
|
137
|
+
group: {
|
|
138
|
+
name: group.name,
|
|
139
|
+
maxOpenInterestP: group.maxOpenInterestP,
|
|
140
|
+
isSpreadDynamic: group.isSpreadDynamic,
|
|
141
|
+
},
|
|
142
|
+
fee: {
|
|
143
|
+
openFeeP: fee.openFeeP,
|
|
144
|
+
closeFeeP: fee.closeFeeP,
|
|
145
|
+
limitOrderFeeP: fee.limitOrderFeeP,
|
|
146
|
+
minLevPosUSDC: fee.minLevPosUSDC,
|
|
147
|
+
pnlFees: {
|
|
148
|
+
numTiers: fee.pnlFees.numTiers,
|
|
149
|
+
tierP: [...fee.pnlFees.tierP],
|
|
150
|
+
feesP: [...fee.pnlFees.feesP],
|
|
151
|
+
},
|
|
152
|
+
},
|
|
153
|
+
};
|
|
154
|
+
return mapped;
|
|
155
|
+
}
|
|
156
|
+
/**
|
|
157
|
+
* Get pair information from socket API
|
|
158
|
+
* @returns Pair information from API
|
|
159
|
+
*/
|
|
160
|
+
async getPairInfoFromSocket() {
|
|
161
|
+
try {
|
|
162
|
+
const response = await fetch(config_1.API_ENDPOINTS.SOCKET_API);
|
|
163
|
+
if (!response.ok) {
|
|
164
|
+
throw new Error(`Failed to fetch from socket API: ${response.statusText}`);
|
|
165
|
+
}
|
|
166
|
+
return await response.json();
|
|
167
|
+
}
|
|
168
|
+
catch (error) {
|
|
169
|
+
console.error('Error fetching pair info from socket API:', error);
|
|
170
|
+
throw error;
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
/**
|
|
174
|
+
* Get pair index from pair name
|
|
175
|
+
* @param pairName - Pair name (e.g., "BTC/USD")
|
|
176
|
+
* @returns Pair index or undefined if not found
|
|
177
|
+
*/
|
|
178
|
+
async getPairIndex(pairName) {
|
|
179
|
+
if (!this.pairNameToIndexMap) {
|
|
180
|
+
await this.getPairsInfo();
|
|
181
|
+
}
|
|
182
|
+
return this.pairNameToIndexMap?.get(pairName);
|
|
183
|
+
}
|
|
184
|
+
/**
|
|
185
|
+
* Get pair name from index
|
|
186
|
+
* @param pairIndex - Pair index
|
|
187
|
+
* @returns Pair name or undefined if not found
|
|
188
|
+
*/
|
|
189
|
+
async getPairName(pairIndex) {
|
|
190
|
+
if (!this.pairsCache) {
|
|
191
|
+
await this.getPairsInfo();
|
|
192
|
+
}
|
|
193
|
+
const pair = this.pairsCache?.get(pairIndex);
|
|
194
|
+
return pair ? `${pair.from}/${pair.to}` : undefined;
|
|
195
|
+
}
|
|
196
|
+
/**
|
|
197
|
+
* Get all unique group indexes
|
|
198
|
+
* @returns Array of group indexes
|
|
199
|
+
*/
|
|
200
|
+
async getGroupIndexes() {
|
|
201
|
+
const pairs = await this.getPairsInfo();
|
|
202
|
+
const groupIndexes = new Set();
|
|
203
|
+
pairs.forEach((pair) => {
|
|
204
|
+
groupIndexes.add(pair.groupIndex);
|
|
205
|
+
});
|
|
206
|
+
return Array.from(groupIndexes).sort((a, b) => a - b);
|
|
207
|
+
}
|
|
208
|
+
/**
|
|
209
|
+
* Get all pairs in a specific group
|
|
210
|
+
* @param groupIndex - Group index
|
|
211
|
+
* @returns Array of pair indexes in the group
|
|
212
|
+
*/
|
|
213
|
+
async getPairsInGroup(groupIndex) {
|
|
214
|
+
const pairs = await this.getPairsInfo();
|
|
215
|
+
const pairsInGroup = [];
|
|
216
|
+
pairs.forEach((pair, index) => {
|
|
217
|
+
if (pair.groupIndex === groupIndex) {
|
|
218
|
+
pairsInGroup.push(index);
|
|
219
|
+
}
|
|
220
|
+
});
|
|
221
|
+
return pairsInGroup;
|
|
222
|
+
}
|
|
223
|
+
/**
|
|
224
|
+
* Get pair info by index
|
|
225
|
+
* @param pairIndex - Pair index
|
|
226
|
+
* @returns PairInfo or undefined
|
|
227
|
+
*/
|
|
228
|
+
async getPairByIndex(pairIndex) {
|
|
229
|
+
const pairs = await this.getPairsInfo();
|
|
230
|
+
return pairs.get(pairIndex);
|
|
231
|
+
}
|
|
232
|
+
/**
|
|
233
|
+
* Clear the cache
|
|
234
|
+
*/
|
|
235
|
+
clearCache() {
|
|
236
|
+
this.pairsCache = undefined;
|
|
237
|
+
this.pairNameToIndexMap = undefined;
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
exports.PairsCache = PairsCache;
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { Contract, TransactionReceipt } from 'ethers';
|
|
2
|
+
import { ReferralTier, ReferralDiscount } from '../types';
|
|
3
|
+
import { BaseSigner } from '../signers/base';
|
|
4
|
+
/**
|
|
5
|
+
* Referral Operations RPC
|
|
6
|
+
* Handles referral program functionality including codes, tiers, and discounts
|
|
7
|
+
*/
|
|
8
|
+
export declare class ReferralOperationsRPC {
|
|
9
|
+
private referralContract;
|
|
10
|
+
private signer?;
|
|
11
|
+
constructor(referralContract: Contract, signer?: BaseSigner | undefined);
|
|
12
|
+
/**
|
|
13
|
+
* Get referral information for a trader
|
|
14
|
+
* @param account - Trader address
|
|
15
|
+
* @returns Referral code and referrer address
|
|
16
|
+
*/
|
|
17
|
+
getTraderReferralInfo(account: string): Promise<{
|
|
18
|
+
code: string;
|
|
19
|
+
referrer: string;
|
|
20
|
+
}>;
|
|
21
|
+
/**
|
|
22
|
+
* Get referrer tier
|
|
23
|
+
* @param account - Referrer address
|
|
24
|
+
* @returns Tier ID
|
|
25
|
+
*/
|
|
26
|
+
getReferrerTier(account: string): Promise<number>;
|
|
27
|
+
/**
|
|
28
|
+
* Get tier information
|
|
29
|
+
* @param tierId - Tier ID
|
|
30
|
+
* @returns Tier information with fee discount and rebate percentages
|
|
31
|
+
*/
|
|
32
|
+
getTierInfo(tierId: number): Promise<ReferralTier>;
|
|
33
|
+
/**
|
|
34
|
+
* Calculate referral discount for a trader and fee
|
|
35
|
+
* @param account - Trader address
|
|
36
|
+
* @param fee - Original fee amount
|
|
37
|
+
* @returns Discount information
|
|
38
|
+
*/
|
|
39
|
+
getTraderReferralDiscount(account: string, fee: number): Promise<ReferralDiscount>;
|
|
40
|
+
/**
|
|
41
|
+
* Set referral code for the caller
|
|
42
|
+
* @param code - Referral code (max 32 characters)
|
|
43
|
+
* @returns Transaction receipt
|
|
44
|
+
*/
|
|
45
|
+
setReferralCode(code: string): Promise<TransactionReceipt | null>;
|
|
46
|
+
/**
|
|
47
|
+
* Check if an account has a referral code set
|
|
48
|
+
* @param account - Trader address
|
|
49
|
+
* @returns True if referral code is set
|
|
50
|
+
*/
|
|
51
|
+
hasReferralCode(account: string): Promise<boolean>;
|
|
52
|
+
/**
|
|
53
|
+
* Get effective fee after referral discount
|
|
54
|
+
* @param account - Trader address
|
|
55
|
+
* @param baseFee - Base fee amount
|
|
56
|
+
* @returns Effective fee after discount
|
|
57
|
+
*/
|
|
58
|
+
getEffectiveFee(account: string, baseFee: number): Promise<number>;
|
|
59
|
+
/**
|
|
60
|
+
* Helper method to sign and send transactions
|
|
61
|
+
*/
|
|
62
|
+
private signAndSend;
|
|
63
|
+
/**
|
|
64
|
+
* Set signer for transactions
|
|
65
|
+
*/
|
|
66
|
+
setSigner(signer: BaseSigner): void;
|
|
67
|
+
}
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ReferralOperationsRPC = void 0;
|
|
4
|
+
const ethers_1 = require("ethers");
|
|
5
|
+
/**
|
|
6
|
+
* Referral Operations RPC
|
|
7
|
+
* Handles referral program functionality including codes, tiers, and discounts
|
|
8
|
+
*/
|
|
9
|
+
class ReferralOperationsRPC {
|
|
10
|
+
constructor(referralContract, signer) {
|
|
11
|
+
this.referralContract = referralContract;
|
|
12
|
+
this.signer = signer;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Get referral information for a trader
|
|
16
|
+
* @param account - Trader address
|
|
17
|
+
* @returns Referral code and referrer address
|
|
18
|
+
*/
|
|
19
|
+
async getTraderReferralInfo(account) {
|
|
20
|
+
const [code, referrer] = await this.referralContract.getTraderReferralInfo(account);
|
|
21
|
+
return {
|
|
22
|
+
code: ethers_1.ethers.decodeBytes32String(code),
|
|
23
|
+
referrer,
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Get referrer tier
|
|
28
|
+
* @param account - Referrer address
|
|
29
|
+
* @returns Tier ID
|
|
30
|
+
*/
|
|
31
|
+
async getReferrerTier(account) {
|
|
32
|
+
const tier = await this.referralContract.referrerTiers(account);
|
|
33
|
+
return Number(tier);
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Get tier information
|
|
37
|
+
* @param tierId - Tier ID
|
|
38
|
+
* @returns Tier information with fee discount and rebate percentages
|
|
39
|
+
*/
|
|
40
|
+
async getTierInfo(tierId) {
|
|
41
|
+
const tier = await this.referralContract.tiers(tierId);
|
|
42
|
+
return {
|
|
43
|
+
feeDiscountPct: Number(tier.feeDiscountPct),
|
|
44
|
+
refRebatePct: Number(tier.refRebatePct),
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Calculate referral discount for a trader and fee
|
|
49
|
+
* @param account - Trader address
|
|
50
|
+
* @param fee - Original fee amount
|
|
51
|
+
* @returns Discount information
|
|
52
|
+
*/
|
|
53
|
+
async getTraderReferralDiscount(account, fee) {
|
|
54
|
+
const result = await this.referralContract.traderReferralDiscount(account, fee);
|
|
55
|
+
return {
|
|
56
|
+
traderDiscount: Number(result.traderDiscount),
|
|
57
|
+
referrer: result.referrer,
|
|
58
|
+
rebateShare: Number(result.rebateShare),
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Set referral code for the caller
|
|
63
|
+
* @param code - Referral code (max 32 characters)
|
|
64
|
+
* @returns Transaction receipt
|
|
65
|
+
*/
|
|
66
|
+
async setReferralCode(code) {
|
|
67
|
+
if (!this.signer) {
|
|
68
|
+
throw new Error('Signer required for setting referral code');
|
|
69
|
+
}
|
|
70
|
+
// Convert string to bytes32
|
|
71
|
+
const codeBytes32 = ethers_1.ethers.encodeBytes32String(code);
|
|
72
|
+
const tx = {
|
|
73
|
+
to: await this.referralContract.getAddress(),
|
|
74
|
+
data: this.referralContract.interface.encodeFunctionData('setTraderReferralCodeByUser', [
|
|
75
|
+
codeBytes32,
|
|
76
|
+
]),
|
|
77
|
+
};
|
|
78
|
+
return await this.signAndSend(tx);
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Check if an account has a referral code set
|
|
82
|
+
* @param account - Trader address
|
|
83
|
+
* @returns True if referral code is set
|
|
84
|
+
*/
|
|
85
|
+
async hasReferralCode(account) {
|
|
86
|
+
const { code } = await this.getTraderReferralInfo(account);
|
|
87
|
+
return code !== '' && code !== '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00';
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Get effective fee after referral discount
|
|
91
|
+
* @param account - Trader address
|
|
92
|
+
* @param baseFee - Base fee amount
|
|
93
|
+
* @returns Effective fee after discount
|
|
94
|
+
*/
|
|
95
|
+
async getEffectiveFee(account, baseFee) {
|
|
96
|
+
const discount = await this.getTraderReferralDiscount(account, baseFee);
|
|
97
|
+
return baseFee - discount.traderDiscount;
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Helper method to sign and send transactions
|
|
101
|
+
*/
|
|
102
|
+
async signAndSend(tx) {
|
|
103
|
+
if (!this.signer) {
|
|
104
|
+
throw new Error('Signer not set');
|
|
105
|
+
}
|
|
106
|
+
const address = await this.signer.getAddress();
|
|
107
|
+
tx.from = address;
|
|
108
|
+
const provider = this.referralContract.runner?.provider;
|
|
109
|
+
if (!provider) {
|
|
110
|
+
throw new Error('Provider not available');
|
|
111
|
+
}
|
|
112
|
+
if (!tx.chainId) {
|
|
113
|
+
const network = await provider.getNetwork();
|
|
114
|
+
tx.chainId = network.chainId;
|
|
115
|
+
}
|
|
116
|
+
if (tx.nonce === undefined) {
|
|
117
|
+
tx.nonce = await provider.getTransactionCount(address);
|
|
118
|
+
}
|
|
119
|
+
if (!tx.gasLimit) {
|
|
120
|
+
tx.gasLimit = await provider.estimateGas(tx);
|
|
121
|
+
}
|
|
122
|
+
if (!tx.maxFeePerGas && !tx.gasPrice) {
|
|
123
|
+
const feeData = await provider.getFeeData();
|
|
124
|
+
if (feeData.maxFeePerGas) {
|
|
125
|
+
tx.maxFeePerGas = feeData.maxFeePerGas;
|
|
126
|
+
tx.maxPriorityFeePerGas = feeData.maxPriorityFeePerGas || feeData.maxFeePerGas;
|
|
127
|
+
}
|
|
128
|
+
else {
|
|
129
|
+
tx.gasPrice = feeData.gasPrice || undefined;
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
const signedTx = await this.signer.signTransaction(tx);
|
|
133
|
+
const txResponse = await provider.broadcastTransaction(signedTx);
|
|
134
|
+
return await txResponse.wait();
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* Set signer for transactions
|
|
138
|
+
*/
|
|
139
|
+
setSigner(signer) {
|
|
140
|
+
this.signer = signer;
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
exports.ReferralOperationsRPC = ReferralOperationsRPC;
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { Snapshot, Group, PairData, PairsBackendReturn } from '../types';
|
|
2
|
+
import { PairsCache } from './pairs_cache';
|
|
3
|
+
import { AssetParametersRPC } from './asset_parameters';
|
|
4
|
+
import { CategoryParametersRPC } from './category_parameters';
|
|
5
|
+
import { FeeParametersRPC } from './fee_parameters';
|
|
6
|
+
import { BlendedRPC } from './blended';
|
|
7
|
+
/**
|
|
8
|
+
* RPC module for aggregating all market data into a snapshot
|
|
9
|
+
* Optimized to use getPairBackend() to reduce duplicate contract calls
|
|
10
|
+
*/
|
|
11
|
+
export declare class SnapshotRPC {
|
|
12
|
+
private pairsCache;
|
|
13
|
+
private assetParams;
|
|
14
|
+
private categoryParams;
|
|
15
|
+
private feeParams;
|
|
16
|
+
private blendedParams;
|
|
17
|
+
constructor(pairsCache: PairsCache, assetParams: AssetParametersRPC, categoryParams: CategoryParametersRPC, feeParams: FeeParametersRPC, blendedParams: BlendedRPC);
|
|
18
|
+
/**
|
|
19
|
+
* Get comprehensive market snapshot with all data
|
|
20
|
+
* Optimized to use getPairBackend() to reduce contract calls
|
|
21
|
+
* @returns Snapshot object containing all market parameters
|
|
22
|
+
*/
|
|
23
|
+
getSnapshot(): Promise<Snapshot>;
|
|
24
|
+
/**
|
|
25
|
+
* Get snapshot for a specific group
|
|
26
|
+
* @param groupIndex - Group index
|
|
27
|
+
* @returns Group data
|
|
28
|
+
*/
|
|
29
|
+
getGroupSnapshot(groupIndex: number): Promise<Group | undefined>;
|
|
30
|
+
/**
|
|
31
|
+
* Get snapshot for a specific pair
|
|
32
|
+
* @param pairName - Pair name (e.g., "BTC/USD")
|
|
33
|
+
* @returns Pair data
|
|
34
|
+
*/
|
|
35
|
+
getPairSnapshot(pairName: string): Promise<PairData | undefined>;
|
|
36
|
+
/**
|
|
37
|
+
* Get full backend data for a specific pair (includes all pair config, group, and fee info)
|
|
38
|
+
* This provides more detailed information than the standard snapshot
|
|
39
|
+
* @param pairIndex - Pair index
|
|
40
|
+
* @returns Complete backend data for the pair
|
|
41
|
+
*/
|
|
42
|
+
getPairFullData(pairIndex: number): Promise<PairsBackendReturn>;
|
|
43
|
+
/**
|
|
44
|
+
* Get full backend data for all pairs
|
|
45
|
+
* Useful for getting complete configuration data in one call
|
|
46
|
+
* @returns Map of pair index to full backend data
|
|
47
|
+
*/
|
|
48
|
+
getAllPairsFullData(): Promise<Map<number, PairsBackendReturn>>;
|
|
49
|
+
}
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.SnapshotRPC = void 0;
|
|
4
|
+
const types_1 = require("../types");
|
|
5
|
+
/**
|
|
6
|
+
* RPC module for aggregating all market data into a snapshot
|
|
7
|
+
* Optimized to use getPairBackend() to reduce duplicate contract calls
|
|
8
|
+
*/
|
|
9
|
+
class SnapshotRPC {
|
|
10
|
+
constructor(pairsCache, assetParams, categoryParams, feeParams, blendedParams) {
|
|
11
|
+
this.pairsCache = pairsCache;
|
|
12
|
+
this.assetParams = assetParams;
|
|
13
|
+
this.categoryParams = categoryParams;
|
|
14
|
+
this.feeParams = feeParams;
|
|
15
|
+
this.blendedParams = blendedParams;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Get comprehensive market snapshot with all data
|
|
19
|
+
* Optimized to use getPairBackend() to reduce contract calls
|
|
20
|
+
* @returns Snapshot object containing all market parameters
|
|
21
|
+
*/
|
|
22
|
+
async getSnapshot() {
|
|
23
|
+
console.log('Fetching market snapshot (optimized)...');
|
|
24
|
+
// Get basic pair info first to know how many pairs exist
|
|
25
|
+
const pairs = await this.pairsCache.getPairsInfo();
|
|
26
|
+
const pairIndices = Array.from(pairs.keys());
|
|
27
|
+
// Fetch all pair backend data in parallel (includes pair config, group info, and fees)
|
|
28
|
+
const pairBackendPromises = pairIndices.map(idx => this.pairsCache.getPairBackend(idx));
|
|
29
|
+
// Fetch only the dynamic data that changes (OI, utilization, skew, depth)
|
|
30
|
+
// Note: Category-level metrics may not be available if contract methods don't exist
|
|
31
|
+
const [pairBackendData, assetOI, assetUtilization, assetSkew, blendedUtilization, blendedSkew, depth,] = await Promise.all([
|
|
32
|
+
Promise.all(pairBackendPromises),
|
|
33
|
+
this.assetParams.getOI(),
|
|
34
|
+
this.assetParams.getUtilization(),
|
|
35
|
+
this.assetParams.getAssetSkew(),
|
|
36
|
+
this.blendedParams.getBlendedUtilization(),
|
|
37
|
+
this.blendedParams.getBlendedSkew(),
|
|
38
|
+
this.assetParams.getOnePercentDepth(),
|
|
39
|
+
]);
|
|
40
|
+
// Try to get category data, but don't fail if it's not available
|
|
41
|
+
let categoryOI = new Map();
|
|
42
|
+
let categoryUtilization = new Map();
|
|
43
|
+
let categorySkew = new Map();
|
|
44
|
+
try {
|
|
45
|
+
categoryOI = await this.categoryParams.getOI();
|
|
46
|
+
categoryUtilization = await this.categoryParams.getUtilization();
|
|
47
|
+
categorySkew = await this.categoryParams.getCategorySkew();
|
|
48
|
+
}
|
|
49
|
+
catch (error) {
|
|
50
|
+
console.warn('Category-level metrics not available:', error);
|
|
51
|
+
}
|
|
52
|
+
// Build a map of pairIndex -> backend data
|
|
53
|
+
const backendDataMap = new Map();
|
|
54
|
+
pairIndices.forEach((idx, i) => {
|
|
55
|
+
backendDataMap.set(idx, pairBackendData[i]);
|
|
56
|
+
});
|
|
57
|
+
// Build a map of groupIndex -> group info (from backend data)
|
|
58
|
+
const groupInfoMap = new Map();
|
|
59
|
+
pairBackendData.forEach(data => {
|
|
60
|
+
const groupIdx = Number(data.pair.groupIndex);
|
|
61
|
+
if (!groupInfoMap.has(groupIdx)) {
|
|
62
|
+
groupInfoMap.set(groupIdx, data.group);
|
|
63
|
+
}
|
|
64
|
+
});
|
|
65
|
+
// Build snapshot structure
|
|
66
|
+
const snapshot = {
|
|
67
|
+
groups: {},
|
|
68
|
+
};
|
|
69
|
+
// Group pairs by category
|
|
70
|
+
for (const [groupIndex, groupInfo] of groupInfoMap) {
|
|
71
|
+
const group = {
|
|
72
|
+
groupIndex,
|
|
73
|
+
pairs: {},
|
|
74
|
+
openInterest: categoryOI.get(groupIndex),
|
|
75
|
+
utilization: categoryUtilization.get(groupIndex),
|
|
76
|
+
skew: categorySkew.get(groupIndex),
|
|
77
|
+
};
|
|
78
|
+
// Get all pairs in this group
|
|
79
|
+
const pairsInGroup = pairIndices.filter(idx => {
|
|
80
|
+
const backend = backendDataMap.get(idx);
|
|
81
|
+
return backend && Number(backend.pair.groupIndex) === groupIndex;
|
|
82
|
+
});
|
|
83
|
+
for (const pairIndex of pairsInGroup) {
|
|
84
|
+
const pairInfo = pairs.get(pairIndex);
|
|
85
|
+
const backend = backendDataMap.get(pairIndex);
|
|
86
|
+
if (!pairInfo || !backend)
|
|
87
|
+
continue;
|
|
88
|
+
const pairName = `${pairInfo.from}/${pairInfo.to}`;
|
|
89
|
+
// Extract fee data from backend (no separate call needed)
|
|
90
|
+
const feeData = {
|
|
91
|
+
feeP: (0, types_1.fromBlockchain12)(backend.fee.openFeeP), // Using openFeeP as the main fee
|
|
92
|
+
};
|
|
93
|
+
const pairData = {
|
|
94
|
+
pairInfo,
|
|
95
|
+
openInterest: assetOI.get(pairIndex),
|
|
96
|
+
utilization: blendedUtilization.get(pairIndex),
|
|
97
|
+
skew: blendedSkew.get(pairIndex),
|
|
98
|
+
fee: feeData,
|
|
99
|
+
depth: {
|
|
100
|
+
onePercentDepthAboveUsdc: depth.get(pairIndex)?.above || 0,
|
|
101
|
+
onePercentDepthBelowUsdc: depth.get(pairIndex)?.below || 0,
|
|
102
|
+
},
|
|
103
|
+
spread: (0, types_1.fromBlockchain10)(backend.pair.spreadP), // Use spread from backend
|
|
104
|
+
};
|
|
105
|
+
group.pairs[pairName] = pairData;
|
|
106
|
+
}
|
|
107
|
+
snapshot.groups[`group_${groupIndex}`] = group;
|
|
108
|
+
}
|
|
109
|
+
console.log('Market snapshot complete (optimized)');
|
|
110
|
+
return snapshot;
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Get snapshot for a specific group
|
|
114
|
+
* @param groupIndex - Group index
|
|
115
|
+
* @returns Group data
|
|
116
|
+
*/
|
|
117
|
+
async getGroupSnapshot(groupIndex) {
|
|
118
|
+
const snapshot = await this.getSnapshot();
|
|
119
|
+
return snapshot.groups[`group_${groupIndex}`];
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* Get snapshot for a specific pair
|
|
123
|
+
* @param pairName - Pair name (e.g., "BTC/USD")
|
|
124
|
+
* @returns Pair data
|
|
125
|
+
*/
|
|
126
|
+
async getPairSnapshot(pairName) {
|
|
127
|
+
const snapshot = await this.getSnapshot();
|
|
128
|
+
// Find the pair in all groups
|
|
129
|
+
for (const group of Object.values(snapshot.groups)) {
|
|
130
|
+
if (group.pairs[pairName]) {
|
|
131
|
+
return group.pairs[pairName];
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
return undefined;
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* Get full backend data for a specific pair (includes all pair config, group, and fee info)
|
|
138
|
+
* This provides more detailed information than the standard snapshot
|
|
139
|
+
* @param pairIndex - Pair index
|
|
140
|
+
* @returns Complete backend data for the pair
|
|
141
|
+
*/
|
|
142
|
+
async getPairFullData(pairIndex) {
|
|
143
|
+
return await this.pairsCache.getPairBackend(pairIndex);
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* Get full backend data for all pairs
|
|
147
|
+
* Useful for getting complete configuration data in one call
|
|
148
|
+
* @returns Map of pair index to full backend data
|
|
149
|
+
*/
|
|
150
|
+
async getAllPairsFullData() {
|
|
151
|
+
const pairs = await this.pairsCache.getPairsInfo();
|
|
152
|
+
const pairIndices = Array.from(pairs.keys());
|
|
153
|
+
const backendDataPromises = pairIndices.map(idx => this.pairsCache.getPairBackend(idx));
|
|
154
|
+
const backendData = await Promise.all(backendDataPromises);
|
|
155
|
+
const dataMap = new Map();
|
|
156
|
+
pairIndices.forEach((idx, i) => {
|
|
157
|
+
dataMap.set(idx, backendData[i]);
|
|
158
|
+
});
|
|
159
|
+
return dataMap;
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
exports.SnapshotRPC = SnapshotRPC;
|