@gainsnetwork/sdk 1.4.0-rc1 → 1.4.2-rc1
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/lib/backend/globalTrades/index.js +10 -10
- package/lib/backend/tradingVariables/converter.js +57 -57
- package/lib/backend/tradingVariables/index.js +6 -7
- package/lib/constants.js +2 -2
- package/lib/contracts/addresses.js +4 -1
- package/lib/contracts/index.d.ts +1 -1
- package/lib/contracts/index.js +3 -3
- package/lib/contracts/types/generated/GFarmTradingStorageV5.d.ts +1911 -0
- package/lib/contracts/types/generated/GFarmTradingStorageV5.js +2 -0
- package/lib/contracts/types/generated/GNSBorrowingFees.d.ts +1067 -0
- package/lib/contracts/types/generated/GNSBorrowingFees.js +2 -0
- package/lib/contracts/types/generated/GNSBorrowingFeesV6_3_2.d.ts +979 -0
- package/lib/contracts/types/generated/GNSBorrowingFeesV6_3_2.js +2 -0
- package/lib/contracts/types/generated/GNSBorrowingFeesV6_4.d.ts +1058 -0
- package/lib/contracts/types/generated/GNSBorrowingFeesV6_4.js +2 -0
- package/lib/contracts/types/generated/GNSMultiCollatDiamond.d.ts +386 -260
- package/lib/contracts/types/generated/GNSNftRewardsV6.d.ts +533 -0
- package/lib/contracts/types/generated/GNSNftRewardsV6.js +2 -0
- package/lib/contracts/types/generated/GNSNftRewardsV6_3_1.d.ts +613 -0
- package/lib/contracts/types/generated/GNSNftRewardsV6_3_1.js +2 -0
- package/lib/contracts/types/generated/GNSPairInfosV6_1.d.ts +911 -0
- package/lib/contracts/types/generated/GNSPairInfosV6_1.js +2 -0
- package/lib/contracts/types/generated/GNSPairsStorageV6.d.ts +660 -0
- package/lib/contracts/types/generated/GNSPairsStorageV6.js +2 -0
- package/lib/contracts/types/generated/GNSTrading.d.ts +758 -0
- package/lib/contracts/types/generated/GNSTrading.js +2 -0
- package/lib/contracts/types/generated/GNSTradingCallbacks.d.ts +875 -0
- package/lib/contracts/types/generated/GNSTradingCallbacks.js +2 -0
- package/lib/contracts/types/generated/GNSTradingCallbacksV6_3_2.d.ts +806 -0
- package/lib/contracts/types/generated/GNSTradingCallbacksV6_3_2.js +2 -0
- package/lib/contracts/types/generated/GNSTradingCallbacksV6_4.d.ts +821 -0
- package/lib/contracts/types/generated/GNSTradingCallbacksV6_4.js +2 -0
- package/lib/contracts/types/generated/GNSTradingStorage.d.ts +1387 -0
- package/lib/contracts/types/generated/GNSTradingStorage.js +2 -0
- package/lib/contracts/types/generated/GTokenV6_3_2.d.ts +1838 -0
- package/lib/contracts/types/generated/GTokenV6_3_2.js +2 -0
- package/lib/contracts/types/generated/factories/GFarmTradingStorageV5__factory.d.ts +83 -0
- package/lib/contracts/types/generated/factories/GFarmTradingStorageV5__factory.js +2691 -0
- package/lib/contracts/types/generated/factories/GNSBorrowingFeesV6_3_2__factory.d.ts +88 -0
- package/lib/contracts/types/generated/factories/GNSBorrowingFeesV6_3_2__factory.js +1654 -0
- package/lib/contracts/types/generated/factories/GNSBorrowingFeesV6_4__factory.d.ts +113 -0
- package/lib/contracts/types/generated/factories/GNSBorrowingFeesV6_4__factory.js +1742 -0
- package/lib/contracts/types/generated/factories/GNSBorrowingFees__factory.d.ts +124 -0
- package/lib/contracts/types/generated/factories/GNSBorrowingFees__factory.js +1784 -0
- package/lib/contracts/types/generated/factories/GNSMultiCollatDiamond__factory.d.ts +2 -10
- package/lib/contracts/types/generated/factories/GNSMultiCollatDiamond__factory.js +1621 -219
- package/lib/contracts/types/generated/factories/GNSNftRewardsV6_3_1__factory.d.ts +100 -0
- package/lib/contracts/types/generated/factories/GNSNftRewardsV6_3_1__factory.js +1116 -0
- package/lib/contracts/types/generated/factories/GNSNftRewardsV6__factory.d.ts +100 -0
- package/lib/contracts/types/generated/factories/GNSNftRewardsV6__factory.js +1003 -0
- package/lib/contracts/types/generated/factories/GNSPairInfosV6_1__factory.d.ts +98 -0
- package/lib/contracts/types/generated/factories/GNSPairInfosV6_1__factory.js +1485 -0
- package/lib/contracts/types/generated/factories/GNSPairsStorageV6__factory.d.ts +117 -0
- package/lib/contracts/types/generated/factories/GNSPairsStorageV6__factory.js +1265 -0
- package/lib/contracts/types/generated/factories/GNSTradingCallbacksV6_3_2__factory.d.ts +82 -0
- package/lib/contracts/types/generated/factories/GNSTradingCallbacksV6_3_2__factory.js +1273 -0
- package/lib/contracts/types/generated/factories/GNSTradingCallbacksV6_4__factory.d.ts +82 -0
- package/lib/contracts/types/generated/factories/GNSTradingCallbacksV6_4__factory.js +1326 -0
- package/lib/contracts/types/generated/factories/GNSTradingCallbacks__factory.d.ts +113 -0
- package/lib/contracts/types/generated/factories/GNSTradingCallbacks__factory.js +1428 -0
- package/lib/contracts/types/generated/factories/GNSTradingStorage__factory.d.ts +96 -0
- package/lib/contracts/types/generated/factories/GNSTradingStorage__factory.js +2241 -0
- package/lib/contracts/types/generated/factories/GNSTrading__factory.d.ts +95 -0
- package/lib/contracts/types/generated/factories/GNSTrading__factory.js +1071 -0
- package/lib/contracts/types/generated/factories/GTokenV6_3_2__factory.d.ts +110 -0
- package/lib/contracts/types/generated/factories/GTokenV6_3_2__factory.js +2682 -0
- package/lib/contracts/utils/borrowingFees.js +9 -20
- package/lib/contracts/utils/openTrades.js +11 -20
- package/lib/contracts/utils/pairs.js +12 -21
- package/lib/markets/forex.js +1 -1
- package/lib/markets/leverage/builder.js +2 -2
- package/lib/markets/oi/fetcher.d.ts +58 -0
- package/lib/markets/oi/fetcher.js +181 -0
- package/lib/markets/oi/validation.d.ts +80 -0
- package/lib/markets/oi/validation.js +172 -0
- package/lib/markets/price/index.d.ts +1 -0
- package/lib/markets/price/index.js +1 -0
- package/lib/markets/price/signedPrices.d.ts +36 -0
- package/lib/markets/price/signedPrices.js +181 -0
- package/lib/markets/price/types.d.ts +27 -0
- package/lib/pricing/depthBands/converter.d.ts +65 -0
- package/lib/pricing/depthBands/converter.js +155 -0
- package/lib/pricing/depthBands/decoder.d.ts +32 -0
- package/lib/pricing/depthBands/decoder.js +109 -0
- package/lib/pricing/depthBands/encoder.d.ts +19 -0
- package/lib/pricing/depthBands/encoder.js +105 -0
- package/lib/pricing/depthBands/index.d.ts +8 -0
- package/lib/pricing/depthBands/index.js +26 -0
- package/lib/pricing/depthBands/types.d.ts +49 -0
- package/lib/pricing/depthBands/types.js +10 -0
- package/lib/pricing/depthBands/validator.d.ts +22 -0
- package/lib/pricing/depthBands/validator.js +113 -0
- package/lib/pricing/depthBands.d.ts +39 -0
- package/lib/pricing/depthBands.js +94 -0
- package/lib/pricing/index.d.ts +4 -0
- package/lib/pricing/index.js +20 -0
- package/lib/trade/effectiveLeverage/builder.d.ts +23 -0
- package/lib/trade/effectiveLeverage/builder.js +30 -0
- package/lib/trade/fees/borrowing/builder.js +2 -3
- package/lib/trade/fees/borrowing/converter.js +5 -1
- package/lib/trade/fees/borrowing/index.js +5 -5
- package/lib/trade/fees/borrowingV2/builder.js +3 -4
- package/lib/trade/fees/borrowingV2/converter.js +1 -1
- package/lib/trade/fees/borrowingV2/fetcher.js +26 -32
- package/lib/trade/fees/borrowingV2/index.js +3 -3
- package/lib/trade/fees/converter.js +22 -22
- package/lib/trade/fees/fundingFees/builder.js +6 -7
- package/lib/trade/fees/fundingFees/converter.js +1 -1
- package/lib/trade/fees/fundingFees/fetcher.js +16 -25
- package/lib/trade/fees/fundingFees/index.js +2 -3
- package/lib/trade/fees/holdingFees/index.d.ts +46 -0
- package/lib/trade/fees/holdingFees/index.js +105 -0
- package/lib/trade/fees/holdingFees/types.d.ts +23 -0
- package/lib/trade/fees/holdingFees/types.js +5 -0
- package/lib/trade/fees/tiers/index.js +1 -2
- package/lib/trade/fees/trading/holdingFees.d.ts +28 -0
- package/lib/trade/fees/trading/holdingFees.js +66 -0
- package/lib/trade/fees/trading/holdingFeesStructured.d.ts +28 -0
- package/lib/trade/fees/trading/holdingFeesStructured.js +66 -0
- package/lib/trade/fees/trading/index.js +5 -3
- package/lib/trade/liquidation/builder.js +1 -2
- package/lib/trade/liquidation/index.js +4 -6
- package/lib/trade/oiWindows.js +1 -2
- package/lib/trade/pnl/builder.js +1 -2
- package/lib/trade/pnl/converter.js +1 -1
- package/lib/trade/pnl/index.js +4 -7
- package/lib/trade/priceImpact/close/builder.js +1 -2
- package/lib/trade/priceImpact/close/index.js +4 -1
- package/lib/trade/priceImpact/cumulVol/builder.js +18 -10
- package/lib/trade/priceImpact/cumulVol/index.js +21 -16
- package/lib/trade/priceImpact/cumulVol/types.d.ts +11 -0
- package/lib/trade/priceImpact/cumulVol/types.js +2 -0
- package/lib/trade/priceImpact/open/builder.js +1 -2
- package/lib/trade/priceImpact/open/index.js +4 -1
- package/lib/trade/priceImpact/skew/builder.js +2 -3
- package/lib/trade/priceImpact/skew/converter.js +1 -1
- package/lib/trade/priceImpact/skew/fetcher.js +24 -33
- package/package.json +2 -2
- package/lib/trade/liquidation.d.ts +0 -12
- package/lib/trade/liquidation.js +0 -55
- package/lib/trade/pnl.d.ts +0 -10
- package/lib/trade/pnl.js +0 -33
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* @dev OI Validation module
|
|
4
|
+
* @dev Provides validation functions for Open Interest limits
|
|
5
|
+
*/
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
exports.validateOiLimits = exports.getGroupDynamicOi = exports.withinMaxGroupOiDynamic = exports.getRemainingOiCapacity = exports.calculateDynamicOi = exports.withinMaxPairOi = void 0;
|
|
8
|
+
const converter_1 = require("./converter");
|
|
9
|
+
/**
|
|
10
|
+
* @dev Check if a position would exceed per-pair OI limits
|
|
11
|
+
* @param pairOi Current OI data for the pair
|
|
12
|
+
* @param long Whether the position is long
|
|
13
|
+
* @param positionSizeCollateral Position size in collateral
|
|
14
|
+
* @param currentPrice Current collateral price in USD (required for dynamic OI)
|
|
15
|
+
* @returns true if within limits, false if would exceed
|
|
16
|
+
*/
|
|
17
|
+
const withinMaxPairOi = (pairOi, long, positionSizeCollateral, currentPrice) => {
|
|
18
|
+
// If maxCollateral is 0, unlimited OI allowed
|
|
19
|
+
if (pairOi.maxCollateral === 0) {
|
|
20
|
+
return true;
|
|
21
|
+
}
|
|
22
|
+
// Calculate current dynamic OI
|
|
23
|
+
const computed = (0, converter_1.computeOiValues)(pairOi, currentPrice);
|
|
24
|
+
const currentOi = long
|
|
25
|
+
? computed.totalDynamicCollateral.long
|
|
26
|
+
: computed.totalDynamicCollateral.short;
|
|
27
|
+
// Check if adding position would exceed max
|
|
28
|
+
const newOi = currentOi + positionSizeCollateral;
|
|
29
|
+
return newOi <= pairOi.maxCollateral;
|
|
30
|
+
};
|
|
31
|
+
exports.withinMaxPairOi = withinMaxPairOi;
|
|
32
|
+
/**
|
|
33
|
+
* @dev Calculate dynamic OI for a specific side
|
|
34
|
+
* @param pairOi OI data for the pair
|
|
35
|
+
* @param currentPrice Current collateral price in USD
|
|
36
|
+
* @param long Whether to calculate for long side
|
|
37
|
+
* @returns Dynamic OI in collateral value
|
|
38
|
+
*/
|
|
39
|
+
const calculateDynamicOi = (pairOi, currentPrice, long) => {
|
|
40
|
+
const computed = (0, converter_1.computeOiValues)(pairOi, currentPrice);
|
|
41
|
+
return long
|
|
42
|
+
? computed.totalDynamicCollateral.long
|
|
43
|
+
: computed.totalDynamicCollateral.short;
|
|
44
|
+
};
|
|
45
|
+
exports.calculateDynamicOi = calculateDynamicOi;
|
|
46
|
+
/**
|
|
47
|
+
* @dev Calculate remaining OI capacity for a side
|
|
48
|
+
* @param pairOi OI data for the pair
|
|
49
|
+
* @param currentPrice Current collateral price in USD
|
|
50
|
+
* @param long Whether to calculate for long side
|
|
51
|
+
* @returns Remaining capacity in collateral (0 if unlimited)
|
|
52
|
+
*/
|
|
53
|
+
const getRemainingOiCapacity = (pairOi, currentPrice, long) => {
|
|
54
|
+
// If maxCollateral is 0, unlimited capacity
|
|
55
|
+
if (pairOi.maxCollateral === 0) {
|
|
56
|
+
return 0; // Indicates unlimited
|
|
57
|
+
}
|
|
58
|
+
const dynamicOi = (0, exports.calculateDynamicOi)(pairOi, currentPrice, long);
|
|
59
|
+
const remaining = pairOi.maxCollateral - dynamicOi;
|
|
60
|
+
// Return 0 if already at or over capacity
|
|
61
|
+
return Math.max(0, remaining);
|
|
62
|
+
};
|
|
63
|
+
exports.getRemainingOiCapacity = getRemainingOiCapacity;
|
|
64
|
+
/**
|
|
65
|
+
* @dev Updated group OI validation using dynamic OI
|
|
66
|
+
* @param pairIndex Index of the trading pair
|
|
67
|
+
* @param long Whether the position is long
|
|
68
|
+
* @param positionSizeCollateral Position size in collateral
|
|
69
|
+
* @param currentPrice Current collateral price in USD
|
|
70
|
+
* @param context Context with groups, pairs, and OI data
|
|
71
|
+
* @returns true if within group limits, false if would exceed
|
|
72
|
+
*/
|
|
73
|
+
const withinMaxGroupOiDynamic = (pairIndex, long, positionSizeCollateral, currentPrice, context) => {
|
|
74
|
+
const pair = context.pairs[pairIndex];
|
|
75
|
+
if (!pair)
|
|
76
|
+
return false;
|
|
77
|
+
// Get group index from first group in pair's groups array
|
|
78
|
+
const groupIndex = pair.groups.length > 0 ? pair.groups[0].groupIndex : 0;
|
|
79
|
+
const group = context.groups[groupIndex];
|
|
80
|
+
if (!group)
|
|
81
|
+
return false;
|
|
82
|
+
// If maxOi is 0, unlimited OI allowed
|
|
83
|
+
if (group.oi.max === 0) {
|
|
84
|
+
return true;
|
|
85
|
+
}
|
|
86
|
+
// Calculate total dynamic OI for all pairs in group
|
|
87
|
+
let totalGroupOi = 0;
|
|
88
|
+
context.pairs.forEach((p, idx) => {
|
|
89
|
+
const pGroupIndex = p.groups.length > 0 ? p.groups[0].groupIndex : 0;
|
|
90
|
+
if (pGroupIndex === groupIndex && context.pairOis[idx]) {
|
|
91
|
+
const pairOi = context.pairOis[idx];
|
|
92
|
+
const computed = (0, converter_1.computeOiValues)(pairOi, currentPrice);
|
|
93
|
+
// Add both long and short OI for the pair
|
|
94
|
+
totalGroupOi +=
|
|
95
|
+
computed.totalDynamicCollateral.long +
|
|
96
|
+
computed.totalDynamicCollateral.short;
|
|
97
|
+
}
|
|
98
|
+
});
|
|
99
|
+
// Check if adding position would exceed group max
|
|
100
|
+
const newTotalOi = totalGroupOi + positionSizeCollateral;
|
|
101
|
+
return newTotalOi <= group.oi.max;
|
|
102
|
+
};
|
|
103
|
+
exports.withinMaxGroupOiDynamic = withinMaxGroupOiDynamic;
|
|
104
|
+
/**
|
|
105
|
+
* @dev Calculate total dynamic OI for a group
|
|
106
|
+
* @param groupIndex Index of the group
|
|
107
|
+
* @param currentPrice Current collateral price in USD
|
|
108
|
+
* @param context Context with pairs and OI data
|
|
109
|
+
* @returns Total dynamic OI for the group
|
|
110
|
+
*/
|
|
111
|
+
const getGroupDynamicOi = (groupIndex, currentPrice, context) => {
|
|
112
|
+
let longOi = 0;
|
|
113
|
+
let shortOi = 0;
|
|
114
|
+
context.pairs.forEach((p, idx) => {
|
|
115
|
+
const pGroupIndex = p.groups.length > 0 ? p.groups[0].groupIndex : 0;
|
|
116
|
+
if (pGroupIndex === groupIndex && context.pairOis[idx]) {
|
|
117
|
+
const pairOi = context.pairOis[idx];
|
|
118
|
+
const computed = (0, converter_1.computeOiValues)(pairOi, currentPrice);
|
|
119
|
+
longOi += computed.totalDynamicCollateral.long;
|
|
120
|
+
shortOi += computed.totalDynamicCollateral.short;
|
|
121
|
+
}
|
|
122
|
+
});
|
|
123
|
+
return {
|
|
124
|
+
long: longOi,
|
|
125
|
+
short: shortOi,
|
|
126
|
+
total: longOi + shortOi,
|
|
127
|
+
};
|
|
128
|
+
};
|
|
129
|
+
exports.getGroupDynamicOi = getGroupDynamicOi;
|
|
130
|
+
/**
|
|
131
|
+
* @dev Check both pair and group OI limits
|
|
132
|
+
* @param pairIndex Index of the trading pair
|
|
133
|
+
* @param long Whether the position is long
|
|
134
|
+
* @param positionSizeCollateral Position size in collateral
|
|
135
|
+
* @param currentPrice Current collateral price in USD
|
|
136
|
+
* @param context Full context with all required data
|
|
137
|
+
* @returns Object with validation results
|
|
138
|
+
*/
|
|
139
|
+
const validateOiLimits = (pairIndex, long, positionSizeCollateral, currentPrice, context) => {
|
|
140
|
+
const pairOi = context.pairOis[pairIndex];
|
|
141
|
+
if (!pairOi) {
|
|
142
|
+
return {
|
|
143
|
+
withinPairLimit: false,
|
|
144
|
+
withinGroupLimit: false,
|
|
145
|
+
pairRemainingCapacity: 0,
|
|
146
|
+
groupRemainingCapacity: 0,
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
// Check pair limits
|
|
150
|
+
const withinPairLimit = (0, exports.withinMaxPairOi)(pairOi, long, positionSizeCollateral, currentPrice);
|
|
151
|
+
const pairRemainingCapacity = (0, exports.getRemainingOiCapacity)(pairOi, currentPrice, long);
|
|
152
|
+
// Check group limits
|
|
153
|
+
const withinGroupLimit = (0, exports.withinMaxGroupOiDynamic)(pairIndex, long, positionSizeCollateral, currentPrice, context);
|
|
154
|
+
// Calculate group remaining capacity
|
|
155
|
+
const pair = context.pairs[pairIndex];
|
|
156
|
+
let groupRemainingCapacity = 0;
|
|
157
|
+
if (pair) {
|
|
158
|
+
const groupIndex = pair.groups.length > 0 ? pair.groups[0].groupIndex : 0;
|
|
159
|
+
const group = context.groups[groupIndex];
|
|
160
|
+
if (group && group.oi.max > 0) {
|
|
161
|
+
const groupOi = (0, exports.getGroupDynamicOi)(groupIndex, currentPrice, context);
|
|
162
|
+
groupRemainingCapacity = Math.max(0, group.oi.max - groupOi.total);
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
return {
|
|
166
|
+
withinPairLimit,
|
|
167
|
+
withinGroupLimit,
|
|
168
|
+
pairRemainingCapacity,
|
|
169
|
+
groupRemainingCapacity,
|
|
170
|
+
};
|
|
171
|
+
};
|
|
172
|
+
exports.validateOiLimits = validateOiLimits;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { Oracle, SignedPricesResponse } from "./types";
|
|
2
|
+
import { PendingOrderType } from "../../trade";
|
|
3
|
+
export interface FetchSignedPricesInput {
|
|
4
|
+
oracles: Oracle[];
|
|
5
|
+
pairs: number[];
|
|
6
|
+
chain: number;
|
|
7
|
+
minAnswer?: number;
|
|
8
|
+
timeoutMs?: number;
|
|
9
|
+
}
|
|
10
|
+
export declare const fetchSignedPrices: (input: FetchSignedPricesInput) => Promise<SignedPricesResponse[] | null>;
|
|
11
|
+
export interface FetchSignedLookbackPricesInput {
|
|
12
|
+
oracles: Oracle[];
|
|
13
|
+
trader: string;
|
|
14
|
+
tradeIndex: number;
|
|
15
|
+
pair: number;
|
|
16
|
+
orderType: PendingOrderType;
|
|
17
|
+
currentBlock: number;
|
|
18
|
+
fromBlock: number;
|
|
19
|
+
chain: number;
|
|
20
|
+
minAnswer?: number;
|
|
21
|
+
timeoutMs?: number;
|
|
22
|
+
}
|
|
23
|
+
export declare const fetchSignedLookbackPrices: (input: FetchSignedLookbackPricesInput) => Promise<SignedPricesResponse[] | null>;
|
|
24
|
+
export interface RetryOptions {
|
|
25
|
+
maxRetries?: number;
|
|
26
|
+
retryDelayMs?: number;
|
|
27
|
+
backoffMultiplier?: number;
|
|
28
|
+
}
|
|
29
|
+
export declare const fetchSignedPricesWithRetry: (input: FetchSignedPricesInput, retryOptions?: RetryOptions) => Promise<SignedPricesResponse[] | null>;
|
|
30
|
+
export declare const fetchSignedLookbackPricesWithRetry: (input: FetchSignedLookbackPricesInput, retryOptions?: RetryOptions) => Promise<SignedPricesResponse[] | null>;
|
|
31
|
+
export declare const validateSignedPricesPairs: (pairs: number[]) => {
|
|
32
|
+
valid: boolean;
|
|
33
|
+
pairs: number[];
|
|
34
|
+
};
|
|
35
|
+
export declare const isValidSignedPricesChain: (chainId: number) => boolean;
|
|
36
|
+
export declare const isValidSignedPricesOrderType: (orderType: PendingOrderType) => boolean;
|
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.isValidSignedPricesOrderType = exports.isValidSignedPricesChain = exports.validateSignedPricesPairs = exports.fetchSignedLookbackPricesWithRetry = exports.fetchSignedPricesWithRetry = exports.fetchSignedLookbackPrices = exports.fetchSignedPrices = void 0;
|
|
4
|
+
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
|
|
5
|
+
const types_1 = require("../../contracts/types");
|
|
6
|
+
const trade_1 = require("../../trade");
|
|
7
|
+
const fetchSignedPrices = async (input) => {
|
|
8
|
+
const { minAnswers, timeoutMs, oracles, chain } = {
|
|
9
|
+
minAnswers: input.chain === types_1.ChainId.ARBITRUM_SEPOLIA ? 2 : 3,
|
|
10
|
+
timeoutMs: 1000,
|
|
11
|
+
...input,
|
|
12
|
+
};
|
|
13
|
+
if (!(0, exports.isValidSignedPricesChain)(chain))
|
|
14
|
+
throw new Error(`Invalid chain ${chain}`);
|
|
15
|
+
const { valid, pairs } = (0, exports.validateSignedPricesPairs)(input.pairs);
|
|
16
|
+
if (!valid)
|
|
17
|
+
throw new Error(`Invalid pairs array`);
|
|
18
|
+
return await initiateSignedPricesRequest(oracles, "signPrices", JSON.stringify({ pairs, chain }), minAnswers, timeoutMs);
|
|
19
|
+
};
|
|
20
|
+
exports.fetchSignedPrices = fetchSignedPrices;
|
|
21
|
+
const fetchSignedLookbackPrices = async (input) => {
|
|
22
|
+
const { minAnswers, timeoutMs, oracles, trader, tradeIndex, pair, orderType, currentBlock, fromBlock, chain, } = {
|
|
23
|
+
minAnswers: input.chain === types_1.ChainId.ARBITRUM_SEPOLIA ? 2 : 3,
|
|
24
|
+
timeoutMs: 6000,
|
|
25
|
+
...input,
|
|
26
|
+
};
|
|
27
|
+
if (!(0, exports.isValidSignedPricesChain)(chain))
|
|
28
|
+
throw new Error(`Invalid chain ${chain}`);
|
|
29
|
+
if (!(0, exports.isValidSignedPricesOrderType)(orderType))
|
|
30
|
+
throw new Error(`Invalid orderType ${orderType}`);
|
|
31
|
+
if (isNaN(pair))
|
|
32
|
+
throw new Error(`Invalid pair ${pair}`);
|
|
33
|
+
if (isNaN(tradeIndex) || tradeIndex < 0)
|
|
34
|
+
throw new Error(`Invalid tradeIndex ${tradeIndex}`);
|
|
35
|
+
if (!currentBlock || !fromBlock)
|
|
36
|
+
throw new Error(`Invalid block numbers`);
|
|
37
|
+
return await initiateSignedPricesRequest(oracles, "signLookbackPrices", JSON.stringify({
|
|
38
|
+
trader,
|
|
39
|
+
tradeIndex,
|
|
40
|
+
pair,
|
|
41
|
+
orderType,
|
|
42
|
+
currentBlock,
|
|
43
|
+
fromBlock,
|
|
44
|
+
chain,
|
|
45
|
+
}), minAnswers, timeoutMs);
|
|
46
|
+
};
|
|
47
|
+
exports.fetchSignedLookbackPrices = fetchSignedLookbackPrices;
|
|
48
|
+
// Helper to determine if an error is likely transient
|
|
49
|
+
const isTransientError = (error) => {
|
|
50
|
+
const message = (error instanceof Error ? error.message : String(error))?.toLowerCase() ||
|
|
51
|
+
"";
|
|
52
|
+
return (message.includes("timeout") ||
|
|
53
|
+
message.includes("aborted") ||
|
|
54
|
+
message.includes("not enough valid signed prices") ||
|
|
55
|
+
message.includes("network") ||
|
|
56
|
+
message.includes("fetch failed"));
|
|
57
|
+
};
|
|
58
|
+
// Fetch signed prices with retry logic for transient failures
|
|
59
|
+
const fetchSignedPricesWithRetry = async (input, retryOptions) => {
|
|
60
|
+
const { maxRetries = 2, retryDelayMs = 500, backoffMultiplier = 1.5, } = retryOptions || {};
|
|
61
|
+
let lastError;
|
|
62
|
+
for (let attempt = 0; attempt <= maxRetries; attempt++) {
|
|
63
|
+
try {
|
|
64
|
+
return await (0, exports.fetchSignedPrices)(input);
|
|
65
|
+
}
|
|
66
|
+
catch (error) {
|
|
67
|
+
lastError = error;
|
|
68
|
+
// Don't retry non-transient errors or if we're out of retries
|
|
69
|
+
if (attempt === maxRetries || !isTransientError(error)) {
|
|
70
|
+
throw error;
|
|
71
|
+
}
|
|
72
|
+
// Wait with exponential backoff before retry
|
|
73
|
+
const delay = Math.floor(retryDelayMs * Math.pow(backoffMultiplier, attempt));
|
|
74
|
+
await new Promise(resolve => setTimeout(resolve, delay));
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
throw lastError;
|
|
78
|
+
};
|
|
79
|
+
exports.fetchSignedPricesWithRetry = fetchSignedPricesWithRetry;
|
|
80
|
+
// Fetch lookback prices with retry logic
|
|
81
|
+
const fetchSignedLookbackPricesWithRetry = async (input, retryOptions) => {
|
|
82
|
+
const { maxRetries = 2, retryDelayMs = 1000, backoffMultiplier = 2, } = retryOptions || {};
|
|
83
|
+
let lastError;
|
|
84
|
+
for (let attempt = 0; attempt <= maxRetries; attempt++) {
|
|
85
|
+
try {
|
|
86
|
+
return await (0, exports.fetchSignedLookbackPrices)(input);
|
|
87
|
+
}
|
|
88
|
+
catch (error) {
|
|
89
|
+
lastError = error;
|
|
90
|
+
// Don't retry non-transient errors or if we're out of retries
|
|
91
|
+
if (attempt === maxRetries || !isTransientError(error)) {
|
|
92
|
+
throw error;
|
|
93
|
+
}
|
|
94
|
+
// Wait with exponential backoff before retry
|
|
95
|
+
const delay = Math.floor(retryDelayMs * Math.pow(backoffMultiplier, attempt));
|
|
96
|
+
await new Promise(resolve => setTimeout(resolve, delay));
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
throw lastError;
|
|
100
|
+
};
|
|
101
|
+
exports.fetchSignedLookbackPricesWithRetry = fetchSignedLookbackPricesWithRetry;
|
|
102
|
+
// @todo optional filtering to minAnswers best responses
|
|
103
|
+
const initiateSignedPricesRequest = async (oracles, request, requestBody, minAnswers, timeoutMs) => {
|
|
104
|
+
try {
|
|
105
|
+
// Fetch signed prices from all oracles in parallel
|
|
106
|
+
const signedPrices = await Promise.allSettled(oracles.map(oracle => _getSignedPricesFromSigner(`${oracle.url}/${request}`, requestBody, oracle?.key, timeoutMs)));
|
|
107
|
+
// Filter out failed requests and null responses, then sort by signerId
|
|
108
|
+
const successfulResponses = signedPrices.filter(res => res.status === "fulfilled" && res.value !== null // Filter out failed or null responses
|
|
109
|
+
)
|
|
110
|
+
// Extract `value`
|
|
111
|
+
.map((res) => res.value)
|
|
112
|
+
// Sort by signerId, contracts expect signerId ascending
|
|
113
|
+
.sort((a, b) => a.signedData.signerId - b.signedData.signerId);
|
|
114
|
+
// Ensure we have at least `minAnswers` valid responses
|
|
115
|
+
if (successfulResponses.length < minAnswers) {
|
|
116
|
+
throw new Error(`Not enough valid signed prices. Wanted ${minAnswers} but got ${successfulResponses.length}`);
|
|
117
|
+
}
|
|
118
|
+
return successfulResponses;
|
|
119
|
+
}
|
|
120
|
+
catch (e) {
|
|
121
|
+
console.error("Error processing signed prices", e);
|
|
122
|
+
throw e;
|
|
123
|
+
}
|
|
124
|
+
};
|
|
125
|
+
const _getSignedPricesFromSigner = async (url, requestBody, authKey, timeoutMs) => {
|
|
126
|
+
try {
|
|
127
|
+
const controller = new AbortController();
|
|
128
|
+
const timeout = setTimeout(() => {
|
|
129
|
+
controller.abort();
|
|
130
|
+
}, timeoutMs || 2000);
|
|
131
|
+
const response = await fetch(`${url}`, {
|
|
132
|
+
method: "POST",
|
|
133
|
+
headers: {
|
|
134
|
+
"Content-Type": "application/json",
|
|
135
|
+
"x-api-key": authKey || "",
|
|
136
|
+
},
|
|
137
|
+
body: requestBody,
|
|
138
|
+
signal: controller.signal,
|
|
139
|
+
});
|
|
140
|
+
clearTimeout(timeout);
|
|
141
|
+
if (!response.ok) {
|
|
142
|
+
throw new Error(`Failed to fetch signed prices from ${url}: ${response.statusText}`);
|
|
143
|
+
}
|
|
144
|
+
return (await response.json());
|
|
145
|
+
}
|
|
146
|
+
catch (error) {
|
|
147
|
+
console.error(`Error fetching signed prices from ${url}:`, {
|
|
148
|
+
error: error?.message,
|
|
149
|
+
});
|
|
150
|
+
return null;
|
|
151
|
+
}
|
|
152
|
+
};
|
|
153
|
+
const validateSignedPricesPairs = (pairs) => {
|
|
154
|
+
if (!Array.isArray(pairs) || pairs?.length === 0 || pairs.some(p => isNaN(p)))
|
|
155
|
+
return { valid: false, pairs: [] };
|
|
156
|
+
// Pairs must always be in ascending order
|
|
157
|
+
return { valid: true, pairs: [...new Set(pairs)].sort((a, b) => a - b) };
|
|
158
|
+
};
|
|
159
|
+
exports.validateSignedPricesPairs = validateSignedPricesPairs;
|
|
160
|
+
const isValidSignedPricesChain = (chainId) => {
|
|
161
|
+
return (!isNaN(chainId) &&
|
|
162
|
+
[
|
|
163
|
+
types_1.ChainId.POLYGON,
|
|
164
|
+
types_1.ChainId.BASE,
|
|
165
|
+
types_1.ChainId.ARBITRUM,
|
|
166
|
+
types_1.ChainId.ARBITRUM_SEPOLIA,
|
|
167
|
+
types_1.ChainId.APECHAIN,
|
|
168
|
+
].includes(chainId));
|
|
169
|
+
};
|
|
170
|
+
exports.isValidSignedPricesChain = isValidSignedPricesChain;
|
|
171
|
+
const isValidSignedPricesOrderType = (orderType) => {
|
|
172
|
+
return (!isNaN(orderType) &&
|
|
173
|
+
[
|
|
174
|
+
trade_1.PendingOrderType.LIMIT_OPEN,
|
|
175
|
+
trade_1.PendingOrderType.STOP_OPEN,
|
|
176
|
+
trade_1.PendingOrderType.TP_CLOSE,
|
|
177
|
+
trade_1.PendingOrderType.SL_CLOSE,
|
|
178
|
+
trade_1.PendingOrderType.LIQ_CLOSE,
|
|
179
|
+
].includes(orderType));
|
|
180
|
+
};
|
|
181
|
+
exports.isValidSignedPricesOrderType = isValidSignedPricesOrderType;
|
|
@@ -21,3 +21,30 @@ export type MarketPriceContext = {
|
|
|
21
21
|
oiShortToken: number;
|
|
22
22
|
};
|
|
23
23
|
};
|
|
24
|
+
/**
|
|
25
|
+
* @dev Types for signed prices data structure
|
|
26
|
+
*/
|
|
27
|
+
export type SignedPricesResponse = {
|
|
28
|
+
signedData: SignedPrices;
|
|
29
|
+
missingPrices: number[];
|
|
30
|
+
};
|
|
31
|
+
export type SignedPrices = {
|
|
32
|
+
signerId: number;
|
|
33
|
+
expiryTs: number;
|
|
34
|
+
fromBlock: number;
|
|
35
|
+
isLookback: boolean;
|
|
36
|
+
pairIndices: number[];
|
|
37
|
+
prices: Price[];
|
|
38
|
+
signature: string;
|
|
39
|
+
};
|
|
40
|
+
export type Price = {
|
|
41
|
+
open: string;
|
|
42
|
+
high: string;
|
|
43
|
+
low: string;
|
|
44
|
+
current: string;
|
|
45
|
+
ts: number;
|
|
46
|
+
};
|
|
47
|
+
export type Oracle = {
|
|
48
|
+
url: string;
|
|
49
|
+
key?: string;
|
|
50
|
+
};
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @dev Depth bands conversion utilities
|
|
3
|
+
*/
|
|
4
|
+
import { type DepthBandsInput } from "./types";
|
|
5
|
+
/**
|
|
6
|
+
* Convert raw depth data from exchanges to depth bands input format
|
|
7
|
+
* @param totalDepthUsd Total depth in USD (already in 6 decimal precision)
|
|
8
|
+
* @param depthLevels Array of depth levels with cumulative USD amounts
|
|
9
|
+
* @returns Formatted depth bands input
|
|
10
|
+
*/
|
|
11
|
+
export declare function formatDepthBandsInput(totalDepthUsd: number, depthLevels: Array<{
|
|
12
|
+
cumulativeUsd: number;
|
|
13
|
+
}>): DepthBandsInput;
|
|
14
|
+
/**
|
|
15
|
+
* Convert percentage-based depth configuration to cumulative USD values
|
|
16
|
+
* @param totalDepthUsd Total depth in USD
|
|
17
|
+
* @param percentages Array of 30 cumulative percentages (0-100)
|
|
18
|
+
* @returns Depth bands input with cumulative USD values
|
|
19
|
+
*/
|
|
20
|
+
export declare function percentagesToDepthBands(totalDepthUsd: number, percentages: number[]): DepthBandsInput;
|
|
21
|
+
/**
|
|
22
|
+
* Convert basis points array to percentage array
|
|
23
|
+
* @param bps Array of values in basis points
|
|
24
|
+
* @returns Array of percentages (0-100)
|
|
25
|
+
*/
|
|
26
|
+
export declare function bpsToPercentages(bps: number[]): number[];
|
|
27
|
+
/**
|
|
28
|
+
* Convert percentage array to basis points array
|
|
29
|
+
* @param percentages Array of percentages (0-100)
|
|
30
|
+
* @returns Array of values in basis points
|
|
31
|
+
*/
|
|
32
|
+
export declare function percentagesToBps(percentages: number[]): number[];
|
|
33
|
+
/**
|
|
34
|
+
* Convert parts per million (ppm) to percentage
|
|
35
|
+
* @param ppm Value in parts per million
|
|
36
|
+
* @returns Percentage value
|
|
37
|
+
*/
|
|
38
|
+
export declare function ppmToPercentage(ppm: number): number;
|
|
39
|
+
/**
|
|
40
|
+
* Convert percentage to parts per million (ppm)
|
|
41
|
+
* @param percentage Percentage value
|
|
42
|
+
* @returns Value in parts per million
|
|
43
|
+
*/
|
|
44
|
+
export declare function percentageToPpm(percentage: number): number;
|
|
45
|
+
/**
|
|
46
|
+
* Create a linear depth bands configuration
|
|
47
|
+
* @param totalDepthUsd Total depth in USD
|
|
48
|
+
* @returns Linear depth bands from 0% to 100%
|
|
49
|
+
*/
|
|
50
|
+
export declare function createLinearDepthBands(totalDepthUsd: number): DepthBandsInput;
|
|
51
|
+
/**
|
|
52
|
+
* Create an exponential depth bands configuration
|
|
53
|
+
* @param totalDepthUsd Total depth in USD
|
|
54
|
+
* @param factor Exponential factor (higher = more concentrated near 0)
|
|
55
|
+
* @returns Exponential depth bands configuration
|
|
56
|
+
*/
|
|
57
|
+
export declare function createExponentialDepthBands(totalDepthUsd: number, factor?: number): DepthBandsInput;
|
|
58
|
+
/**
|
|
59
|
+
* Create a concentrated depth bands configuration
|
|
60
|
+
* @param totalDepthUsd Total depth in USD
|
|
61
|
+
* @param concentrationPoint Percentage (0-100) where to concentrate liquidity
|
|
62
|
+
* @param concentrationStrength How much to concentrate (0-1, higher = more concentrated)
|
|
63
|
+
* @returns Concentrated depth bands configuration
|
|
64
|
+
*/
|
|
65
|
+
export declare function createConcentratedDepthBands(totalDepthUsd: number, concentrationPoint?: number, concentrationStrength?: number): DepthBandsInput;
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* @dev Depth bands conversion utilities
|
|
4
|
+
*/
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.createConcentratedDepthBands = exports.createExponentialDepthBands = exports.createLinearDepthBands = exports.percentageToPpm = exports.ppmToPercentage = exports.percentagesToBps = exports.bpsToPercentages = exports.percentagesToDepthBands = exports.formatDepthBandsInput = void 0;
|
|
7
|
+
const types_1 = require("./types");
|
|
8
|
+
/**
|
|
9
|
+
* Convert raw depth data from exchanges to depth bands input format
|
|
10
|
+
* @param totalDepthUsd Total depth in USD (already in 6 decimal precision)
|
|
11
|
+
* @param depthLevels Array of depth levels with cumulative USD amounts
|
|
12
|
+
* @returns Formatted depth bands input
|
|
13
|
+
*/
|
|
14
|
+
function formatDepthBandsInput(totalDepthUsd, depthLevels) {
|
|
15
|
+
// Ensure we have exactly 30 levels
|
|
16
|
+
if (depthLevels.length !== 30) {
|
|
17
|
+
throw new Error(`Expected 30 depth levels, got ${depthLevels.length}`);
|
|
18
|
+
}
|
|
19
|
+
const cumulativeDepthUsd = depthLevels.map((level) => level.cumulativeUsd);
|
|
20
|
+
return {
|
|
21
|
+
totalDepthUsd,
|
|
22
|
+
cumulativeDepthUsd,
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
exports.formatDepthBandsInput = formatDepthBandsInput;
|
|
26
|
+
/**
|
|
27
|
+
* Convert percentage-based depth configuration to cumulative USD values
|
|
28
|
+
* @param totalDepthUsd Total depth in USD
|
|
29
|
+
* @param percentages Array of 30 cumulative percentages (0-100)
|
|
30
|
+
* @returns Depth bands input with cumulative USD values
|
|
31
|
+
*/
|
|
32
|
+
function percentagesToDepthBands(totalDepthUsd, percentages) {
|
|
33
|
+
if (percentages.length !== 30) {
|
|
34
|
+
throw new Error(`Expected 30 percentages, got ${percentages.length}`);
|
|
35
|
+
}
|
|
36
|
+
const cumulativeDepthUsd = percentages.map((percentage) => {
|
|
37
|
+
if (percentage < 0 || percentage > 100) {
|
|
38
|
+
throw new Error(`Invalid percentage: ${percentage}. Must be between 0 and 100`);
|
|
39
|
+
}
|
|
40
|
+
return (percentage * totalDepthUsd) / 100;
|
|
41
|
+
});
|
|
42
|
+
return {
|
|
43
|
+
totalDepthUsd,
|
|
44
|
+
cumulativeDepthUsd,
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
exports.percentagesToDepthBands = percentagesToDepthBands;
|
|
48
|
+
/**
|
|
49
|
+
* Convert basis points array to percentage array
|
|
50
|
+
* @param bps Array of values in basis points
|
|
51
|
+
* @returns Array of percentages (0-100)
|
|
52
|
+
*/
|
|
53
|
+
function bpsToPercentages(bps) {
|
|
54
|
+
return bps.map((value) => (value * 100) / types_1.HUNDRED_P_BPS);
|
|
55
|
+
}
|
|
56
|
+
exports.bpsToPercentages = bpsToPercentages;
|
|
57
|
+
/**
|
|
58
|
+
* Convert percentage array to basis points array
|
|
59
|
+
* @param percentages Array of percentages (0-100)
|
|
60
|
+
* @returns Array of values in basis points
|
|
61
|
+
*/
|
|
62
|
+
function percentagesToBps(percentages) {
|
|
63
|
+
return percentages.map((percentage) => {
|
|
64
|
+
const bps = Math.round((percentage * types_1.HUNDRED_P_BPS) / 100);
|
|
65
|
+
if (bps > types_1.HUNDRED_P_BPS) {
|
|
66
|
+
throw new Error(`Percentage ${percentage}% converts to ${bps} bps, which exceeds maximum ${types_1.HUNDRED_P_BPS} bps`);
|
|
67
|
+
}
|
|
68
|
+
return bps;
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
exports.percentagesToBps = percentagesToBps;
|
|
72
|
+
/**
|
|
73
|
+
* Convert parts per million (ppm) to percentage
|
|
74
|
+
* @param ppm Value in parts per million
|
|
75
|
+
* @returns Percentage value
|
|
76
|
+
*/
|
|
77
|
+
function ppmToPercentage(ppm) {
|
|
78
|
+
return ppm / 10000;
|
|
79
|
+
}
|
|
80
|
+
exports.ppmToPercentage = ppmToPercentage;
|
|
81
|
+
/**
|
|
82
|
+
* Convert percentage to parts per million (ppm)
|
|
83
|
+
* @param percentage Percentage value
|
|
84
|
+
* @returns Value in parts per million
|
|
85
|
+
*/
|
|
86
|
+
function percentageToPpm(percentage) {
|
|
87
|
+
return Math.round(percentage * 10000);
|
|
88
|
+
}
|
|
89
|
+
exports.percentageToPpm = percentageToPpm;
|
|
90
|
+
/**
|
|
91
|
+
* Create a linear depth bands configuration
|
|
92
|
+
* @param totalDepthUsd Total depth in USD
|
|
93
|
+
* @returns Linear depth bands from 0% to 100%
|
|
94
|
+
*/
|
|
95
|
+
function createLinearDepthBands(totalDepthUsd) {
|
|
96
|
+
const cumulativeDepthUsd = [];
|
|
97
|
+
for (let i = 0; i < 30; i++) {
|
|
98
|
+
// Linear progression from 0 to 100%
|
|
99
|
+
const percentage = ((i + 1) / 30) * 100;
|
|
100
|
+
cumulativeDepthUsd.push((percentage * totalDepthUsd) / 100);
|
|
101
|
+
}
|
|
102
|
+
return {
|
|
103
|
+
totalDepthUsd,
|
|
104
|
+
cumulativeDepthUsd,
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
exports.createLinearDepthBands = createLinearDepthBands;
|
|
108
|
+
/**
|
|
109
|
+
* Create an exponential depth bands configuration
|
|
110
|
+
* @param totalDepthUsd Total depth in USD
|
|
111
|
+
* @param factor Exponential factor (higher = more concentrated near 0)
|
|
112
|
+
* @returns Exponential depth bands configuration
|
|
113
|
+
*/
|
|
114
|
+
function createExponentialDepthBands(totalDepthUsd, factor = 2) {
|
|
115
|
+
const cumulativeDepthUsd = [];
|
|
116
|
+
for (let i = 0; i < 30; i++) {
|
|
117
|
+
// Exponential curve: y = (e^(factor * x) - 1) / (e^factor - 1)
|
|
118
|
+
const x = (i + 1) / 30;
|
|
119
|
+
const percentage = ((Math.exp(factor * x) - 1) / (Math.exp(factor) - 1)) * 100;
|
|
120
|
+
cumulativeDepthUsd.push((percentage * totalDepthUsd) / 100);
|
|
121
|
+
}
|
|
122
|
+
return {
|
|
123
|
+
totalDepthUsd,
|
|
124
|
+
cumulativeDepthUsd,
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
exports.createExponentialDepthBands = createExponentialDepthBands;
|
|
128
|
+
/**
|
|
129
|
+
* Create a concentrated depth bands configuration
|
|
130
|
+
* @param totalDepthUsd Total depth in USD
|
|
131
|
+
* @param concentrationPoint Percentage (0-100) where to concentrate liquidity
|
|
132
|
+
* @param concentrationStrength How much to concentrate (0-1, higher = more concentrated)
|
|
133
|
+
* @returns Concentrated depth bands configuration
|
|
134
|
+
*/
|
|
135
|
+
function createConcentratedDepthBands(totalDepthUsd, concentrationPoint = 20, concentrationStrength = 0.7) {
|
|
136
|
+
const cumulativeDepthUsd = [];
|
|
137
|
+
for (let i = 0; i < 30; i++) {
|
|
138
|
+
const x = (i + 1) / 30;
|
|
139
|
+
const targetX = concentrationPoint / 100;
|
|
140
|
+
// Sigmoid-like concentration around the target point
|
|
141
|
+
const steepness = 10 * concentrationStrength;
|
|
142
|
+
const sigmoid = 1 / (1 + Math.exp(-steepness * (x - targetX)));
|
|
143
|
+
// Blend between linear and concentrated
|
|
144
|
+
const linear = x;
|
|
145
|
+
const percentage = (linear * (1 - concentrationStrength) + sigmoid * concentrationStrength) * 100;
|
|
146
|
+
cumulativeDepthUsd.push(Math.min((percentage * totalDepthUsd) / 100, totalDepthUsd));
|
|
147
|
+
}
|
|
148
|
+
// Ensure last value is exactly totalDepthUsd
|
|
149
|
+
cumulativeDepthUsd[29] = totalDepthUsd;
|
|
150
|
+
return {
|
|
151
|
+
totalDepthUsd,
|
|
152
|
+
cumulativeDepthUsd,
|
|
153
|
+
};
|
|
154
|
+
}
|
|
155
|
+
exports.createConcentratedDepthBands = createConcentratedDepthBands;
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @dev Depth bands decoding functions
|
|
3
|
+
*/
|
|
4
|
+
import { type DecodedDepthBands, type DecodedDepthBandsMapping, type EncodedDepthBands, type PairDepthBands } from "./types";
|
|
5
|
+
/**
|
|
6
|
+
* Decode depth bands from encoded slots
|
|
7
|
+
* @param encoded Encoded depth bands
|
|
8
|
+
* @returns Decoded depth bands with totalDepthUsd and band percentages
|
|
9
|
+
*/
|
|
10
|
+
export declare function decodeDepthBands(encoded: EncodedDepthBands): DecodedDepthBands;
|
|
11
|
+
/**
|
|
12
|
+
* Decode pair depth bands (both directions)
|
|
13
|
+
* @param pairBands Encoded pair depth bands
|
|
14
|
+
* @returns Decoded depth bands for above and below
|
|
15
|
+
*/
|
|
16
|
+
export declare function decodePairDepthBands(pairBands: PairDepthBands): {
|
|
17
|
+
above: DecodedDepthBands;
|
|
18
|
+
below: DecodedDepthBands;
|
|
19
|
+
};
|
|
20
|
+
/**
|
|
21
|
+
* Decode depth bands mapping (global offsets)
|
|
22
|
+
* @param slot1 First slot containing bands 0-13
|
|
23
|
+
* @param slot2 Second slot containing bands 14-29
|
|
24
|
+
* @returns Decoded mapping with band offset values in ppm
|
|
25
|
+
*/
|
|
26
|
+
export declare function decodeDepthBandsMapping(slot1: bigint, slot2: bigint): DecodedDepthBandsMapping;
|
|
27
|
+
/**
|
|
28
|
+
* Convert decoded band percentages back to cumulative depth USD
|
|
29
|
+
* @param decoded Decoded depth bands
|
|
30
|
+
* @returns Array of cumulative depth values in USD
|
|
31
|
+
*/
|
|
32
|
+
export declare function bandsToCumulativeDepth(decoded: DecodedDepthBands): number[];
|