@exponent-labs/market-three-math 0.9.13 → 0.9.14
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/build/existingPositionEqualization.d.ts +63 -0
- package/build/existingPositionEqualization.js +241 -0
- package/build/existingPositionEqualization.js.map +1 -0
- package/build/index.d.ts +2 -0
- package/build/index.js +5 -1
- package/build/index.js.map +1 -1
- package/build/swapLegacy.d.ts +16 -0
- package/build/swapLegacy.js +229 -0
- package/build/swapLegacy.js.map +1 -0
- package/build/utils.d.ts +2 -2
- package/build/utils.js +5 -4
- package/build/utils.js.map +1 -1
- package/jest.config.ts +9 -0
- package/package.json +2 -2
- package/src/existingPositionEqualization.test.ts +162 -0
- package/src/existingPositionEqualization.ts +367 -0
- package/src/index.ts +11 -0
- package/src/utils.ts +6 -4
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import type { LpPositionCLMM, Ticks } from "@exponent-labs/exponent-fetcher";
|
|
2
|
+
export type CrossingEqualizationDirection = "add" | "remove";
|
|
3
|
+
export type CrossingEqualizationPlanStep = {
|
|
4
|
+
shareIndex: number;
|
|
5
|
+
tickIdx: number;
|
|
6
|
+
direction: CrossingEqualizationDirection;
|
|
7
|
+
shareDeltaRaw: bigint;
|
|
8
|
+
ptDelta: bigint;
|
|
9
|
+
syDelta: bigint;
|
|
10
|
+
};
|
|
11
|
+
export type ExistingPositionEqualization = {
|
|
12
|
+
sySpent: bigint;
|
|
13
|
+
ptSpent: bigint;
|
|
14
|
+
syReleased: bigint;
|
|
15
|
+
ptReleased: bigint;
|
|
16
|
+
plan: CrossingEqualizationPlanStep[];
|
|
17
|
+
};
|
|
18
|
+
export type ExistingPositionBudgetEffect = {
|
|
19
|
+
userMaxSy: bigint;
|
|
20
|
+
userMaxPt: bigint;
|
|
21
|
+
effectiveMaxSy: bigint;
|
|
22
|
+
effectiveMaxPt: bigint;
|
|
23
|
+
fixedSySpent: bigint;
|
|
24
|
+
fixedPtSpent: bigint;
|
|
25
|
+
fixedSyReleased: bigint;
|
|
26
|
+
fixedPtReleased: bigint;
|
|
27
|
+
};
|
|
28
|
+
/**
|
|
29
|
+
* Mirrors `precalc_existing_position_add_liquidity` from the CLMM program.
|
|
30
|
+
*
|
|
31
|
+
* The returned `ptSpent` and `sySpent` are the exact token budget that must be
|
|
32
|
+
* reserved before adding more liquidity to a position with an active crossing split.
|
|
33
|
+
* All PreciseNumber operations are performed on raw fixed-point `bigint` values so
|
|
34
|
+
* the rounding matches the contract's `fast_floor_u128`, `fast_mul_ratio`, and
|
|
35
|
+
* `muldiv_ceil_u128` paths.
|
|
36
|
+
*/
|
|
37
|
+
export declare function computeExistingPositionEqualization(ticks: Ticks, position: LpPositionCLMM): ExistingPositionEqualization;
|
|
38
|
+
/**
|
|
39
|
+
* Mirrors the contract's `compute_existing_position_budget_effect`.
|
|
40
|
+
*
|
|
41
|
+
* It throws the same invariant class when the supplied user budgets cannot cover
|
|
42
|
+
* the fixed equalization spend, for example `userMaxPt=0` while `ptSpent>0`.
|
|
43
|
+
*/
|
|
44
|
+
export declare function computeExistingPositionBudgetEffect(params: {
|
|
45
|
+
ticks: Ticks;
|
|
46
|
+
position: LpPositionCLMM;
|
|
47
|
+
userMaxSy: bigint;
|
|
48
|
+
userMaxPt: bigint;
|
|
49
|
+
}): ExistingPositionBudgetEffect;
|
|
50
|
+
/**
|
|
51
|
+
* Mirrors `required_user_max_sy/pt`: expands a desired post-equalization budget
|
|
52
|
+
* into the user-facing max token amounts that should be passed to the instruction.
|
|
53
|
+
*/
|
|
54
|
+
export declare function computeRequiredUserMaxForExistingPositionEqualization(params: {
|
|
55
|
+
ticks: Ticks;
|
|
56
|
+
position: LpPositionCLMM;
|
|
57
|
+
desiredEffectiveMaxSy: bigint;
|
|
58
|
+
desiredEffectiveMaxPt: bigint;
|
|
59
|
+
}): {
|
|
60
|
+
userMaxSy: bigint;
|
|
61
|
+
userMaxPt: bigint;
|
|
62
|
+
equalization: ExistingPositionEqualization;
|
|
63
|
+
};
|
|
@@ -0,0 +1,241 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.computeExistingPositionEqualization = computeExistingPositionEqualization;
|
|
4
|
+
exports.computeExistingPositionBudgetEffect = computeExistingPositionBudgetEffect;
|
|
5
|
+
exports.computeRequiredUserMaxForExistingPositionEqualization = computeRequiredUserMaxForExistingPositionEqualization;
|
|
6
|
+
const SENTINEL_TICK_INDEX = 0xffffffff;
|
|
7
|
+
const PRECISE_NUMBER_DENOM = 1000000000000n;
|
|
8
|
+
const U64_MAX = (1n << 64n) - 1n;
|
|
9
|
+
const U128_MAX = (1n << 128n) - 1n;
|
|
10
|
+
const invariantError = (message) => new Error(`CrossingEqualizationInvariantViolated: ${message}`);
|
|
11
|
+
const assertU64 = (value, label) => {
|
|
12
|
+
if (value < 0n || value > U64_MAX) {
|
|
13
|
+
throw invariantError(`${label} does not fit in u64: ${value.toString()}`);
|
|
14
|
+
}
|
|
15
|
+
return value;
|
|
16
|
+
};
|
|
17
|
+
const assertU128 = (value, label) => {
|
|
18
|
+
if (value < 0n || value > U128_MAX) {
|
|
19
|
+
throw invariantError(`${label} does not fit in u128: ${value.toString()}`);
|
|
20
|
+
}
|
|
21
|
+
return value;
|
|
22
|
+
};
|
|
23
|
+
const checkedAddU64 = (left, right, label) => assertU64(left + right, label);
|
|
24
|
+
const checkedSubU64 = (left, right, label) => {
|
|
25
|
+
if (right > left) {
|
|
26
|
+
throw invariantError(`${label} underflow: ${left.toString()} - ${right.toString()}`);
|
|
27
|
+
}
|
|
28
|
+
return left - right;
|
|
29
|
+
};
|
|
30
|
+
const checkedMulU128 = (left, right, label) => assertU128(left * right, label);
|
|
31
|
+
const ceilMulDivU128 = (left, right, denominator, label) => {
|
|
32
|
+
if (denominator <= 0n) {
|
|
33
|
+
throw invariantError(`${label} division by zero`);
|
|
34
|
+
}
|
|
35
|
+
const product = checkedMulU128(left, right, `${label} product`);
|
|
36
|
+
return assertU128(product + denominator - 1n, `${label} ceil numerator`) / denominator;
|
|
37
|
+
};
|
|
38
|
+
const fastFloorU128 = (rawPreciseNumber) => assertU128(rawPreciseNumber, "precise number raw") / PRECISE_NUMBER_DENOM;
|
|
39
|
+
const fastMulRatioRaw = (rawPreciseNumber, numerator, denominator, label) => {
|
|
40
|
+
if (denominator <= 0n) {
|
|
41
|
+
throw invariantError(`${label} division by zero`);
|
|
42
|
+
}
|
|
43
|
+
const raw = assertU128(rawPreciseNumber, `${label} raw precise number`);
|
|
44
|
+
const product = checkedMulU128(raw, numerator, `${label} product`);
|
|
45
|
+
return product / denominator;
|
|
46
|
+
};
|
|
47
|
+
const getTickByIndex = (ticks, tickIdx) => {
|
|
48
|
+
const tick = ticks.ticksTree[tickIdx - 1];
|
|
49
|
+
if (!tick || tick.apyBasePoints <= 0) {
|
|
50
|
+
throw invariantError(`missing tick at index ${tickIdx}`);
|
|
51
|
+
}
|
|
52
|
+
return tick;
|
|
53
|
+
};
|
|
54
|
+
const getTickKey = (ticks, tickIdx) => getTickByIndex(ticks, tickIdx).apyBasePoints;
|
|
55
|
+
const successorIdx = (ticks, tickIdx) => {
|
|
56
|
+
const tickKey = getTickKey(ticks, tickIdx);
|
|
57
|
+
let best = null;
|
|
58
|
+
for (let index = 0; index < ticks.ticksTree.length; index++) {
|
|
59
|
+
const key = ticks.ticksTree[index].apyBasePoints;
|
|
60
|
+
if (key <= tickKey) {
|
|
61
|
+
continue;
|
|
62
|
+
}
|
|
63
|
+
if (!best || key < best.key) {
|
|
64
|
+
best = { tickIdx: index + 1, key };
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
return best?.tickIdx ?? null;
|
|
68
|
+
};
|
|
69
|
+
const isCrossingSplitActive = (position) => position.crossingSplit.crossLeftIdx !== SENTINEL_TICK_INDEX &&
|
|
70
|
+
position.crossingSplit.crossRightIdx !== SENTINEL_TICK_INDEX;
|
|
71
|
+
const shareIsWithinCrossingRange = (ticks, position, share) => {
|
|
72
|
+
const shareLeftKey = getTickKey(ticks, share.tickIdx);
|
|
73
|
+
let shareRightIdx = share.rightTickIdx;
|
|
74
|
+
if (share.rightTickIdx === SENTINEL_TICK_INDEX) {
|
|
75
|
+
shareRightIdx = successorIdx(ticks, share.tickIdx);
|
|
76
|
+
}
|
|
77
|
+
if (shareRightIdx == null) {
|
|
78
|
+
return false;
|
|
79
|
+
}
|
|
80
|
+
const shareRightKey = getTickKey(ticks, shareRightIdx);
|
|
81
|
+
const crossLeftKey = getTickKey(ticks, position.crossingSplit.crossLeftIdx);
|
|
82
|
+
const crossRightKey = getTickKey(ticks, position.crossingSplit.crossRightIdx);
|
|
83
|
+
return shareLeftKey >= crossLeftKey && shareRightKey <= crossRightKey;
|
|
84
|
+
};
|
|
85
|
+
const computeAddDeltas = (params) => {
|
|
86
|
+
const ptDelta = params.ownedPt > 0n
|
|
87
|
+
? assertU64(ceilMulDivU128(params.ownedPt, params.liquidityDelta, params.lActual, "PT equalization in"), "PT equalization in")
|
|
88
|
+
: 0n;
|
|
89
|
+
const syDelta = params.ownedSy > 0n
|
|
90
|
+
? assertU64(ceilMulDivU128(params.ownedSy, params.liquidityDelta, params.lActual, "SY equalization in"), "SY equalization in")
|
|
91
|
+
: 0n;
|
|
92
|
+
return [ptDelta, syDelta];
|
|
93
|
+
};
|
|
94
|
+
const computeRemoveDeltas = (params) => {
|
|
95
|
+
const burnShares = fastFloorU128(params.shareDeltaRaw);
|
|
96
|
+
const ptDelta = assertU64(checkedMulU128(burnShares, params.node.principalPt, "PT equalization out product") / params.supply, "PT equalization out");
|
|
97
|
+
const syDelta = assertU64(checkedMulU128(burnShares, params.node.principalSy, "SY equalization out product") / params.supply, "SY equalization out");
|
|
98
|
+
return [ptDelta, syDelta];
|
|
99
|
+
};
|
|
100
|
+
const summarizePlan = (plan) => {
|
|
101
|
+
let sySpent = 0n;
|
|
102
|
+
let ptSpent = 0n;
|
|
103
|
+
let syReleased = 0n;
|
|
104
|
+
let ptReleased = 0n;
|
|
105
|
+
for (const step of plan) {
|
|
106
|
+
if (step.direction === "add") {
|
|
107
|
+
sySpent = checkedAddU64(sySpent, step.syDelta, "equalization sy spent");
|
|
108
|
+
ptSpent = checkedAddU64(ptSpent, step.ptDelta, "equalization pt spent");
|
|
109
|
+
continue;
|
|
110
|
+
}
|
|
111
|
+
syReleased = checkedAddU64(syReleased, step.syDelta, "equalization sy released");
|
|
112
|
+
ptReleased = checkedAddU64(ptReleased, step.ptDelta, "equalization pt released");
|
|
113
|
+
}
|
|
114
|
+
return {
|
|
115
|
+
sySpent,
|
|
116
|
+
ptSpent,
|
|
117
|
+
syReleased,
|
|
118
|
+
ptReleased,
|
|
119
|
+
plan,
|
|
120
|
+
};
|
|
121
|
+
};
|
|
122
|
+
/**
|
|
123
|
+
* Mirrors `precalc_existing_position_add_liquidity` from the CLMM program.
|
|
124
|
+
*
|
|
125
|
+
* The returned `ptSpent` and `sySpent` are the exact token budget that must be
|
|
126
|
+
* reserved before adding more liquidity to a position with an active crossing split.
|
|
127
|
+
* All PreciseNumber operations are performed on raw fixed-point `bigint` values so
|
|
128
|
+
* the rounding matches the contract's `fast_floor_u128`, `fast_mul_ratio`, and
|
|
129
|
+
* `muldiv_ceil_u128` paths.
|
|
130
|
+
*/
|
|
131
|
+
function computeExistingPositionEqualization(ticks, position) {
|
|
132
|
+
if (!isCrossingSplitActive(position)) {
|
|
133
|
+
return summarizePlan([]);
|
|
134
|
+
}
|
|
135
|
+
const lActual = assertU64(position.crossingSplit.lpBalanceCrossing, "lpBalanceCrossing");
|
|
136
|
+
const lpBalance = assertU64(position.lpBalance, "lpBalance");
|
|
137
|
+
if (lpBalance === lActual) {
|
|
138
|
+
return summarizePlan([]);
|
|
139
|
+
}
|
|
140
|
+
if (lActual === 0n) {
|
|
141
|
+
throw invariantError("active crossing split has zero actual liquidity");
|
|
142
|
+
}
|
|
143
|
+
const direction = lpBalance > lActual ? "add" : "remove";
|
|
144
|
+
const liquidityDelta = lpBalance > lActual ? lpBalance - lActual : lActual - lpBalance;
|
|
145
|
+
const plan = [];
|
|
146
|
+
let sawCrossingRangeShare = false;
|
|
147
|
+
let skippedCrossingShareDueToDust = false;
|
|
148
|
+
for (let shareIndex = 0; shareIndex < position.shareTrackers.length; shareIndex++) {
|
|
149
|
+
const share = position.shareTrackers[shareIndex];
|
|
150
|
+
if (!shareIsWithinCrossingRange(ticks, position, share)) {
|
|
151
|
+
continue;
|
|
152
|
+
}
|
|
153
|
+
sawCrossingRangeShare = true;
|
|
154
|
+
const node = getTickByIndex(ticks, share.tickIdx);
|
|
155
|
+
const supply = fastFloorU128(node.principalShareSupply);
|
|
156
|
+
if (supply === 0n) {
|
|
157
|
+
skippedCrossingShareDueToDust = true;
|
|
158
|
+
continue;
|
|
159
|
+
}
|
|
160
|
+
const shareFloor = fastFloorU128(share.lpShare);
|
|
161
|
+
if (shareFloor === 0n) {
|
|
162
|
+
skippedCrossingShareDueToDust = true;
|
|
163
|
+
continue;
|
|
164
|
+
}
|
|
165
|
+
const ownedPt = assertU64(checkedMulU128(shareFloor, node.principalPt, "owned PT product") / supply, "owned PT");
|
|
166
|
+
const ownedSy = assertU64(checkedMulU128(shareFloor, node.principalSy, "owned SY product") / supply, "owned SY");
|
|
167
|
+
const shareDeltaRaw = fastMulRatioRaw(share.lpShare, liquidityDelta, lActual, "share delta");
|
|
168
|
+
let deltas;
|
|
169
|
+
if (direction === "add") {
|
|
170
|
+
deltas = computeAddDeltas({
|
|
171
|
+
ownedPt,
|
|
172
|
+
ownedSy,
|
|
173
|
+
liquidityDelta,
|
|
174
|
+
lActual,
|
|
175
|
+
});
|
|
176
|
+
}
|
|
177
|
+
else {
|
|
178
|
+
deltas = computeRemoveDeltas({
|
|
179
|
+
shareDeltaRaw,
|
|
180
|
+
node,
|
|
181
|
+
supply,
|
|
182
|
+
});
|
|
183
|
+
}
|
|
184
|
+
const [ptDelta, syDelta] = deltas;
|
|
185
|
+
if (shareDeltaRaw === 0n && ptDelta === 0n && syDelta === 0n) {
|
|
186
|
+
skippedCrossingShareDueToDust = true;
|
|
187
|
+
continue;
|
|
188
|
+
}
|
|
189
|
+
plan.push({
|
|
190
|
+
shareIndex,
|
|
191
|
+
tickIdx: share.tickIdx,
|
|
192
|
+
direction,
|
|
193
|
+
shareDeltaRaw,
|
|
194
|
+
ptDelta,
|
|
195
|
+
syDelta,
|
|
196
|
+
});
|
|
197
|
+
}
|
|
198
|
+
if (plan.length === 0 && sawCrossingRangeShare && skippedCrossingShareDueToDust) {
|
|
199
|
+
return summarizePlan([]);
|
|
200
|
+
}
|
|
201
|
+
if (plan.length === 0) {
|
|
202
|
+
throw invariantError("active crossing split has no equalizable crossing-range shares");
|
|
203
|
+
}
|
|
204
|
+
return summarizePlan(plan);
|
|
205
|
+
}
|
|
206
|
+
/**
|
|
207
|
+
* Mirrors the contract's `compute_existing_position_budget_effect`.
|
|
208
|
+
*
|
|
209
|
+
* It throws the same invariant class when the supplied user budgets cannot cover
|
|
210
|
+
* the fixed equalization spend, for example `userMaxPt=0` while `ptSpent>0`.
|
|
211
|
+
*/
|
|
212
|
+
function computeExistingPositionBudgetEffect(params) {
|
|
213
|
+
const equalization = computeExistingPositionEqualization(params.ticks, params.position);
|
|
214
|
+
const effectiveMaxSy = checkedAddU64(checkedSubU64(params.userMaxSy, equalization.sySpent, "effective max SY"), equalization.syReleased, "effective max SY");
|
|
215
|
+
const effectiveMaxPt = checkedAddU64(checkedSubU64(params.userMaxPt, equalization.ptSpent, "effective max PT"), equalization.ptReleased, "effective max PT");
|
|
216
|
+
return {
|
|
217
|
+
userMaxSy: params.userMaxSy,
|
|
218
|
+
userMaxPt: params.userMaxPt,
|
|
219
|
+
effectiveMaxSy,
|
|
220
|
+
effectiveMaxPt,
|
|
221
|
+
fixedSySpent: equalization.sySpent,
|
|
222
|
+
fixedPtSpent: equalization.ptSpent,
|
|
223
|
+
fixedSyReleased: equalization.syReleased,
|
|
224
|
+
fixedPtReleased: equalization.ptReleased,
|
|
225
|
+
};
|
|
226
|
+
}
|
|
227
|
+
/**
|
|
228
|
+
* Mirrors `required_user_max_sy/pt`: expands a desired post-equalization budget
|
|
229
|
+
* into the user-facing max token amounts that should be passed to the instruction.
|
|
230
|
+
*/
|
|
231
|
+
function computeRequiredUserMaxForExistingPositionEqualization(params) {
|
|
232
|
+
const equalization = computeExistingPositionEqualization(params.ticks, params.position);
|
|
233
|
+
const userMaxSy = checkedSubU64(checkedAddU64(params.desiredEffectiveMaxSy, equalization.sySpent, "required user max SY"), equalization.syReleased, "required user max SY");
|
|
234
|
+
const userMaxPt = checkedSubU64(checkedAddU64(params.desiredEffectiveMaxPt, equalization.ptSpent, "required user max PT"), equalization.ptReleased, "required user max PT");
|
|
235
|
+
return {
|
|
236
|
+
userMaxSy,
|
|
237
|
+
userMaxPt,
|
|
238
|
+
equalization,
|
|
239
|
+
};
|
|
240
|
+
}
|
|
241
|
+
//# sourceMappingURL=existingPositionEqualization.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"existingPositionEqualization.js","sourceRoot":"","sources":["../src/existingPositionEqualization.ts"],"names":[],"mappings":"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"}
|
package/build/index.d.ts
CHANGED
|
@@ -17,6 +17,8 @@ export { EffSnap, TicksWrapper, calculateFeeRate, getFeeFromAmount } from "./uti
|
|
|
17
17
|
export { simulateBuyYt, simulateSellYt, simulateBuyYtWithSyIn } from "./ytTrades";
|
|
18
18
|
export type { BuyYtSimulationArgs, BuyYtSimulationResult, SellYtSimulationArgs, SellYtSimulationResult, } from "./ytTrades";
|
|
19
19
|
export { simulateAddLiquidity, computeLiquidityTargetAndTokenNeeds, computeTokenNeedsWithCrossing, getCrossingTickStateFromTicks, scaleCrossingTickInputs, calculateLpOut, estimateBalancedDeposit, calcDepositSyAndPtFromBaseAmount, simulateWrapperProvideLiquidity, simulateSwapAndSupply, } from "./addLiquidity";
|
|
20
|
+
export { computeExistingPositionBudgetEffect, computeExistingPositionEqualization, computeRequiredUserMaxForExistingPositionEqualization, } from "./existingPositionEqualization";
|
|
21
|
+
export type { CrossingEqualizationDirection, CrossingEqualizationPlanStep, ExistingPositionBudgetEffect, ExistingPositionEqualization, } from "./existingPositionEqualization";
|
|
20
22
|
export { getPtAndSyOnWithdrawLiquidity } from "./withdrawLiquidity";
|
|
21
23
|
export { bisectSearch2 } from "./bisect";
|
|
22
24
|
export { buildLiquidityHistogram, buildLiquidityHistogramSimple } from "./liquidityHistogram";
|
package/build/index.js
CHANGED
|
@@ -25,7 +25,7 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
|
25
25
|
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
26
26
|
};
|
|
27
27
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
28
|
-
exports.SwapDirection = exports.buildLiquidityHistogramSimple = exports.buildLiquidityHistogram = exports.bisectSearch2 = exports.getPtAndSyOnWithdrawLiquidity = exports.simulateSwapAndSupply = exports.simulateWrapperProvideLiquidity = exports.calcDepositSyAndPtFromBaseAmount = exports.estimateBalancedDeposit = exports.calculateLpOut = exports.scaleCrossingTickInputs = exports.getCrossingTickStateFromTicks = exports.computeTokenNeedsWithCrossing = exports.computeLiquidityTargetAndTokenNeeds = exports.simulateAddLiquidity = exports.simulateBuyYtWithSyIn = exports.simulateSellYt = exports.simulateBuyYt = exports.getFeeFromAmount = exports.calculateFeeRate = exports.TicksWrapper = exports.EffSnap = exports.QuoteDirection = exports.getSwapQuote = exports.simulateSwap = exports.getSuccessorTickIdxByIdx = exports.calcPtPriceInAsset = exports.convertApyBpToApy = exports.convertApyToApyBp = exports.findTickByKey = exports.getImpliedRate = exports.getPredecessorTickKey = exports.getSuccessorTickKey = exports.getActiveLiquidity = exports.normalizedTimeRemaining = void 0;
|
|
28
|
+
exports.SwapDirection = exports.buildLiquidityHistogramSimple = exports.buildLiquidityHistogram = exports.bisectSearch2 = exports.getPtAndSyOnWithdrawLiquidity = exports.computeRequiredUserMaxForExistingPositionEqualization = exports.computeExistingPositionEqualization = exports.computeExistingPositionBudgetEffect = exports.simulateSwapAndSupply = exports.simulateWrapperProvideLiquidity = exports.calcDepositSyAndPtFromBaseAmount = exports.estimateBalancedDeposit = exports.calculateLpOut = exports.scaleCrossingTickInputs = exports.getCrossingTickStateFromTicks = exports.computeTokenNeedsWithCrossing = exports.computeLiquidityTargetAndTokenNeeds = exports.simulateAddLiquidity = exports.simulateBuyYtWithSyIn = exports.simulateSellYt = exports.simulateBuyYt = exports.getFeeFromAmount = exports.calculateFeeRate = exports.TicksWrapper = exports.EffSnap = exports.QuoteDirection = exports.getSwapQuote = exports.simulateSwap = exports.getSuccessorTickIdxByIdx = exports.calcPtPriceInAsset = exports.convertApyBpToApy = exports.convertApyToApyBp = exports.findTickByKey = exports.getImpliedRate = exports.getPredecessorTickKey = exports.getSuccessorTickKey = exports.getActiveLiquidity = exports.normalizedTimeRemaining = void 0;
|
|
29
29
|
// Export types
|
|
30
30
|
__exportStar(require("./types"), exports);
|
|
31
31
|
// Export utility functions
|
|
@@ -69,6 +69,10 @@ Object.defineProperty(exports, "estimateBalancedDeposit", { enumerable: true, ge
|
|
|
69
69
|
Object.defineProperty(exports, "calcDepositSyAndPtFromBaseAmount", { enumerable: true, get: function () { return addLiquidity_1.calcDepositSyAndPtFromBaseAmount; } });
|
|
70
70
|
Object.defineProperty(exports, "simulateWrapperProvideLiquidity", { enumerable: true, get: function () { return addLiquidity_1.simulateWrapperProvideLiquidity; } });
|
|
71
71
|
Object.defineProperty(exports, "simulateSwapAndSupply", { enumerable: true, get: function () { return addLiquidity_1.simulateSwapAndSupply; } });
|
|
72
|
+
var existingPositionEqualization_1 = require("./existingPositionEqualization");
|
|
73
|
+
Object.defineProperty(exports, "computeExistingPositionBudgetEffect", { enumerable: true, get: function () { return existingPositionEqualization_1.computeExistingPositionBudgetEffect; } });
|
|
74
|
+
Object.defineProperty(exports, "computeExistingPositionEqualization", { enumerable: true, get: function () { return existingPositionEqualization_1.computeExistingPositionEqualization; } });
|
|
75
|
+
Object.defineProperty(exports, "computeRequiredUserMaxForExistingPositionEqualization", { enumerable: true, get: function () { return existingPositionEqualization_1.computeRequiredUserMaxForExistingPositionEqualization; } });
|
|
72
76
|
var withdrawLiquidity_1 = require("./withdrawLiquidity");
|
|
73
77
|
Object.defineProperty(exports, "getPtAndSyOnWithdrawLiquidity", { enumerable: true, get: function () { return withdrawLiquidity_1.getPtAndSyOnWithdrawLiquidity; } });
|
|
74
78
|
// Export bisect search utility
|
package/build/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;GAUG;;;;;;;;;;;;;;;;;AAEH,eAAe;AACf,0CAAuB;AAEvB,2BAA2B;AAC3B,iCAWgB;AAVd,gHAAA,uBAAuB,OAAA;AACvB,2GAAA,kBAAkB,OAAA;AAClB,4GAAA,mBAAmB,OAAA;AACnB,8GAAA,qBAAqB,OAAA;AACrB,uGAAA,cAAc,OAAA;AACd,sGAAA,aAAa,OAAA;AACb,0GAAA,iBAAiB,OAAA;AACjB,0GAAA,iBAAiB,OAAA;AACjB,2GAAA,kBAAkB,OAAA;AAClB,iHAAA,wBAAwB,OAAA;AAG1B,wBAAwB;AACxB,mCAAuC;AAA9B,sGAAA,YAAY,OAAA;AACrB,iCAAsD;AAA7C,qGAAA,YAAY,OAAA;AAAE,uGAAA,cAAc,OAAA;AAErC,sBAAsB;AACtB,qCAAqF;AAA5E,kGAAA,OAAO,OAAA;AAAE,uGAAA,YAAY,OAAA;AAAE,2GAAA,gBAAgB,OAAA;AAAE,2GAAA,gBAAgB,OAAA;AAElE,4BAA4B;AAC5B,uCAAiF;AAAxE,yGAAA,aAAa,OAAA;AAAE,0GAAA,cAAc,OAAA;AAAE,iHAAA,qBAAqB,OAAA;AAQ7D,iCAAiC;AACjC,+CAWuB;AAVrB,oHAAA,oBAAoB,OAAA;AACpB,mIAAA,mCAAmC,OAAA;AACnC,6HAAA,6BAA6B,OAAA;AAC7B,6HAAA,6BAA6B,OAAA;AAC7B,uHAAA,uBAAuB,OAAA;AACvB,8GAAA,cAAc,OAAA;AACd,uHAAA,uBAAuB,OAAA;AACvB,gIAAA,gCAAgC,OAAA;AAChC,+HAAA,+BAA+B,OAAA;AAC/B,qHAAA,qBAAqB,OAAA;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;GAUG;;;;;;;;;;;;;;;;;AAEH,eAAe;AACf,0CAAuB;AAEvB,2BAA2B;AAC3B,iCAWgB;AAVd,gHAAA,uBAAuB,OAAA;AACvB,2GAAA,kBAAkB,OAAA;AAClB,4GAAA,mBAAmB,OAAA;AACnB,8GAAA,qBAAqB,OAAA;AACrB,uGAAA,cAAc,OAAA;AACd,sGAAA,aAAa,OAAA;AACb,0GAAA,iBAAiB,OAAA;AACjB,0GAAA,iBAAiB,OAAA;AACjB,2GAAA,kBAAkB,OAAA;AAClB,iHAAA,wBAAwB,OAAA;AAG1B,wBAAwB;AACxB,mCAAuC;AAA9B,sGAAA,YAAY,OAAA;AACrB,iCAAsD;AAA7C,qGAAA,YAAY,OAAA;AAAE,uGAAA,cAAc,OAAA;AAErC,sBAAsB;AACtB,qCAAqF;AAA5E,kGAAA,OAAO,OAAA;AAAE,uGAAA,YAAY,OAAA;AAAE,2GAAA,gBAAgB,OAAA;AAAE,2GAAA,gBAAgB,OAAA;AAElE,4BAA4B;AAC5B,uCAAiF;AAAxE,yGAAA,aAAa,OAAA;AAAE,0GAAA,cAAc,OAAA;AAAE,iHAAA,qBAAqB,OAAA;AAQ7D,iCAAiC;AACjC,+CAWuB;AAVrB,oHAAA,oBAAoB,OAAA;AACpB,mIAAA,mCAAmC,OAAA;AACnC,6HAAA,6BAA6B,OAAA;AAC7B,6HAAA,6BAA6B,OAAA;AAC7B,uHAAA,uBAAuB,OAAA;AACvB,8GAAA,cAAc,OAAA;AACd,uHAAA,uBAAuB,OAAA;AACvB,gIAAA,gCAAgC,OAAA;AAChC,+HAAA,+BAA+B,OAAA;AAC/B,qHAAA,qBAAqB,OAAA;AAEvB,+EAIuC;AAHrC,mJAAA,mCAAmC,OAAA;AACnC,mJAAA,mCAAmC,OAAA;AACnC,qKAAA,qDAAqD,OAAA;AASvD,yDAAmE;AAA1D,kIAAA,6BAA6B,OAAA;AAEtC,+BAA+B;AAC/B,mCAAwC;AAA/B,uGAAA,aAAa,OAAA;AAEtB,uCAAuC;AACvC,2DAA6F;AAApF,6HAAA,uBAAuB,OAAA;AAAE,mIAAA,6BAA6B,OAAA;AAc/D,iCAAuC;AAA9B,sGAAA,aAAa,OAAA"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CLMM Swap simulation
|
|
3
|
+
* Ported from exponent_clmm/src/state/market_three/helpers/swap.rs
|
|
4
|
+
*/
|
|
5
|
+
import { MarketThreeState, SwapArgs, SwapDirection, SwapOutcome } from "./types";
|
|
6
|
+
/**
|
|
7
|
+
* Simulate a swap on the CLMM market
|
|
8
|
+
* This is a pure function that does not mutate the market state
|
|
9
|
+
* Returns the swap outcome including amounts and final state
|
|
10
|
+
*/
|
|
11
|
+
export declare function simulateSwap(marketState: MarketThreeState, args: SwapArgs): SwapOutcome;
|
|
12
|
+
/**
|
|
13
|
+
* Calculate the expected output for a given input amount
|
|
14
|
+
* This is a convenience wrapper around simulateSwap
|
|
15
|
+
*/
|
|
16
|
+
export declare function getSwapQuote(marketState: MarketThreeState, amountIn: number, direction: SwapDirection): SwapOutcome;
|
|
@@ -0,0 +1,229 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.getSwapQuote = exports.simulateSwap = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* CLMM Swap simulation
|
|
6
|
+
* Ported from exponent_clmm/src/state/market_three/helpers/swap.rs
|
|
7
|
+
*/
|
|
8
|
+
const types_1 = require("./types");
|
|
9
|
+
const utils_1 = require("./utils");
|
|
10
|
+
const BASE_POINTS = 10000;
|
|
11
|
+
/**
|
|
12
|
+
* Simulate a swap on the CLMM market
|
|
13
|
+
* This is a pure function that does not mutate the market state
|
|
14
|
+
* Returns the swap outcome including amounts and final state
|
|
15
|
+
*/
|
|
16
|
+
function simulateSwap(marketState, args) {
|
|
17
|
+
const { financials, configurationOptions, ticks } = marketState;
|
|
18
|
+
const secondsRemaining = Math.max(0, Number(financials.expirationTs) - Date.now() / 1000);
|
|
19
|
+
// Create effective price snapshot
|
|
20
|
+
const snapshot = new utils_1.EffSnap((0, utils_1.normalizedTimeRemaining)(secondsRemaining), args.syExchangeRate);
|
|
21
|
+
// Current state
|
|
22
|
+
let currentPriceSpot = ticks.currentSpotPrice;
|
|
23
|
+
let currentLeftBoundaryIndex = ticks.currentTick;
|
|
24
|
+
// Use currentPrefixSum if available, otherwise fall back to calculating it
|
|
25
|
+
let activeLiquidityU64 = ticks.currentPrefixSum ?? 0n;
|
|
26
|
+
let activeLiquidityF64 = Number(activeLiquidityU64);
|
|
27
|
+
// Fees
|
|
28
|
+
const lpFeeRate = (0, utils_1.calculateFeeRate)(configurationOptions.lnFeeRateRoot, secondsRemaining);
|
|
29
|
+
const protocolFeeBps = configurationOptions.treasuryFeeBps;
|
|
30
|
+
// Check price limits
|
|
31
|
+
if (args.priceSpotLimit !== undefined) {
|
|
32
|
+
if (args.direction === types_1.SwapDirection.PtToSy) {
|
|
33
|
+
if (args.priceSpotLimit < currentPriceSpot) {
|
|
34
|
+
throw new Error("Price limit violated: limit must be >= current price for PtToSy");
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
else {
|
|
38
|
+
if (args.priceSpotLimit > currentPriceSpot) {
|
|
39
|
+
throw new Error("Price limit violated: limit must be <= current price for SyToPt");
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
// Accumulators
|
|
44
|
+
let amountOutNet = 0;
|
|
45
|
+
let feeLpOut = 0;
|
|
46
|
+
let feeProtocolOut = 0;
|
|
47
|
+
let amountInLeft = args.amountIn;
|
|
48
|
+
// Main loop across contiguous intervals
|
|
49
|
+
let iterations = 0;
|
|
50
|
+
const maxIterations = 1000;
|
|
51
|
+
while (amountInLeft > 0 && iterations < maxIterations) {
|
|
52
|
+
iterations++;
|
|
53
|
+
// Get right boundary of current interval
|
|
54
|
+
const rightBoundaryIndexOpt = (0, utils_1.getSuccessorTickKey)(ticks, currentLeftBoundaryIndex);
|
|
55
|
+
if (rightBoundaryIndexOpt === null) {
|
|
56
|
+
if (args.direction === types_1.SwapDirection.SyToPt) {
|
|
57
|
+
// Cross to create a new interval
|
|
58
|
+
const predecessor = (0, utils_1.getPredecessorTickKey)(ticks, currentLeftBoundaryIndex);
|
|
59
|
+
if (predecessor === null)
|
|
60
|
+
break;
|
|
61
|
+
// When crossing downward (SyToPt), update state
|
|
62
|
+
currentPriceSpot = (0, utils_1.getImpliedRate)(currentLeftBoundaryIndex); // Boundary we're crossing
|
|
63
|
+
currentLeftBoundaryIndex = predecessor; // New left boundary
|
|
64
|
+
// Update active liquidity by subtracting liquidity_net at boundary
|
|
65
|
+
const boundaryTick = (0, utils_1.findTickByKey)(ticks, predecessor);
|
|
66
|
+
if (boundaryTick) {
|
|
67
|
+
activeLiquidityU64 = (0, utils_1.bigIntMax)(0n, activeLiquidityU64 - boundaryTick.tick.liquidityNet);
|
|
68
|
+
activeLiquidityF64 = Number(activeLiquidityU64);
|
|
69
|
+
}
|
|
70
|
+
continue;
|
|
71
|
+
}
|
|
72
|
+
else {
|
|
73
|
+
// No more liquidity available
|
|
74
|
+
break;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
const rightBoundaryIndex = rightBoundaryIndexOpt;
|
|
78
|
+
// Get anchor prices for interval boundaries
|
|
79
|
+
const anchorULeft = (0, utils_1.getImpliedRate)(currentLeftBoundaryIndex);
|
|
80
|
+
const anchorURight = (0, utils_1.getImpliedRate)(rightBoundaryIndex);
|
|
81
|
+
// Effective price at current spot
|
|
82
|
+
const cEffOld = snapshot.getEffectivePrice(currentPriceSpot);
|
|
83
|
+
// Get principal ledgers for the interval
|
|
84
|
+
const currentTickData = (0, utils_1.findTickByKey)(ticks, currentLeftBoundaryIndex);
|
|
85
|
+
const principalPt = currentTickData?.tick.principalPt ?? 0n;
|
|
86
|
+
const principalSy = currentTickData?.tick.principalSy ?? 0n;
|
|
87
|
+
const eps = configurationOptions.epsilonClamp;
|
|
88
|
+
// Calculate kappa (scaling factor based on available principal)
|
|
89
|
+
// Y_max = (L/τ) * (C(u_old) - C(u_right))
|
|
90
|
+
const cEffAtBoundary = snapshot.getEffectivePrice(anchorURight);
|
|
91
|
+
const yMaxToBoundaryF = (Number(activeLiquidityF64) / snapshot.timeFactor) * (cEffOld - cEffAtBoundary);
|
|
92
|
+
const kappaSy = yMaxToBoundaryF > 0 ? Number(principalSy) / Number(yMaxToBoundaryF) : 0;
|
|
93
|
+
const duToLeft = currentPriceSpot - anchorULeft;
|
|
94
|
+
const ptMaxToLeftF = Number(activeLiquidityF64) * duToLeft;
|
|
95
|
+
const kappaPt = ptMaxToLeftF > 0 ? Number(principalPt) / ptMaxToLeftF : 0;
|
|
96
|
+
const kappa = Math.min(kappaPt, kappaSy, 1.0);
|
|
97
|
+
const lTradeF64 = Number(activeLiquidityF64) * kappa;
|
|
98
|
+
if (args.direction === types_1.SwapDirection.PtToSy) {
|
|
99
|
+
// PT -> SY swap (buying SY with PT)
|
|
100
|
+
const duByInput = lTradeF64 > 0 ? amountInLeft / lTradeF64 : 0;
|
|
101
|
+
const duToBoundary = anchorURight - currentPriceSpot;
|
|
102
|
+
const duActual = Math.min(duByInput, duToBoundary);
|
|
103
|
+
if (duToBoundary <= eps) {
|
|
104
|
+
// Cross boundary
|
|
105
|
+
const boundaryTick = (0, utils_1.findTickByKey)(ticks, rightBoundaryIndex);
|
|
106
|
+
if (boundaryTick) {
|
|
107
|
+
activeLiquidityU64 += boundaryTick.tick.liquidityNet;
|
|
108
|
+
activeLiquidityF64 = Number(activeLiquidityU64);
|
|
109
|
+
}
|
|
110
|
+
currentLeftBoundaryIndex = rightBoundaryIndex;
|
|
111
|
+
currentPriceSpot = anchorURight;
|
|
112
|
+
continue;
|
|
113
|
+
}
|
|
114
|
+
// Token flows for this segment
|
|
115
|
+
const ptInSegment = Math.floor(lTradeF64 * duActual);
|
|
116
|
+
const anchorUNew = currentPriceSpot + duActual;
|
|
117
|
+
const cEffNew = snapshot.getEffectivePrice(anchorUNew);
|
|
118
|
+
const syOutGross = Math.floor((lTradeF64 / snapshot.timeFactor) * (cEffOld - cEffNew));
|
|
119
|
+
const syOutGrossClamped = Math.min(syOutGross, Number(principalSy));
|
|
120
|
+
if (syOutGrossClamped > 0) {
|
|
121
|
+
const totalFeeOut = (0, utils_1.getFeeFromAmount)(syOutGrossClamped, lpFeeRate);
|
|
122
|
+
const protocolFeeOut = Math.floor((totalFeeOut * protocolFeeBps) / BASE_POINTS);
|
|
123
|
+
const lpFeeOut = totalFeeOut - protocolFeeOut;
|
|
124
|
+
const syOutNet = syOutGrossClamped - totalFeeOut;
|
|
125
|
+
amountOutNet += syOutNet;
|
|
126
|
+
feeLpOut += lpFeeOut;
|
|
127
|
+
feeProtocolOut += protocolFeeOut;
|
|
128
|
+
}
|
|
129
|
+
amountInLeft -= ptInSegment;
|
|
130
|
+
currentPriceSpot = anchorUNew;
|
|
131
|
+
}
|
|
132
|
+
else {
|
|
133
|
+
// SY -> PT swap (buying PT with SY)
|
|
134
|
+
const cEffLeft = snapshot.getEffectivePrice(anchorULeft);
|
|
135
|
+
const deltaCByInput = lTradeF64 > 0 ? (snapshot.timeFactor / lTradeF64) * amountInLeft : 0;
|
|
136
|
+
const deltaCToLeftBoundary = Math.max(0, cEffLeft - cEffOld);
|
|
137
|
+
const deltaCActual = Math.min(deltaCByInput, deltaCToLeftBoundary);
|
|
138
|
+
if (deltaCToLeftBoundary <= eps) {
|
|
139
|
+
// Cross boundary to the left
|
|
140
|
+
const predecessor = (0, utils_1.getPredecessorTickKey)(ticks, currentLeftBoundaryIndex);
|
|
141
|
+
if (predecessor === null)
|
|
142
|
+
break;
|
|
143
|
+
// Update active liquidity
|
|
144
|
+
const boundaryTick = (0, utils_1.findTickByKey)(ticks, currentLeftBoundaryIndex);
|
|
145
|
+
if (boundaryTick) {
|
|
146
|
+
activeLiquidityU64 = (0, utils_1.bigIntMax)(0n, activeLiquidityU64 - boundaryTick.tick.liquidityNet);
|
|
147
|
+
activeLiquidityF64 = Number(activeLiquidityU64);
|
|
148
|
+
}
|
|
149
|
+
currentPriceSpot = (0, utils_1.getImpliedRate)(currentLeftBoundaryIndex);
|
|
150
|
+
currentLeftBoundaryIndex = predecessor;
|
|
151
|
+
continue;
|
|
152
|
+
}
|
|
153
|
+
// New effective price and spot price after consuming ΔC
|
|
154
|
+
const cEffNew = cEffOld + deltaCActual;
|
|
155
|
+
const spotPriceNew = snapshot.spotPriceFromEffectivePrice(cEffNew);
|
|
156
|
+
// Token flows
|
|
157
|
+
const syInSegmentF = (lTradeF64 / snapshot.timeFactor) * (cEffNew - cEffOld);
|
|
158
|
+
const duAbs = currentPriceSpot - spotPriceNew;
|
|
159
|
+
const ptOutGrossF = lTradeF64 * duAbs;
|
|
160
|
+
// Clamp gross PT by available principal
|
|
161
|
+
const ptOutGrossU64 = (0, utils_1.bigIntMin)(BigInt(Math.floor(ptOutGrossF)), principalPt);
|
|
162
|
+
const syInSegmentU64 = BigInt(Math.floor(syInSegmentF));
|
|
163
|
+
if (ptOutGrossU64 === 0n) {
|
|
164
|
+
// Nothing to pay out; try to cross
|
|
165
|
+
const predecessor = (0, utils_1.getPredecessorTickKey)(ticks, currentLeftBoundaryIndex);
|
|
166
|
+
if (predecessor === null)
|
|
167
|
+
break;
|
|
168
|
+
// Update active liquidity
|
|
169
|
+
const boundaryTick = (0, utils_1.findTickByKey)(ticks, currentLeftBoundaryIndex);
|
|
170
|
+
if (boundaryTick) {
|
|
171
|
+
activeLiquidityU64 = (0, utils_1.bigIntMax)(0n, activeLiquidityU64 - boundaryTick.tick.liquidityNet);
|
|
172
|
+
activeLiquidityF64 = Number(activeLiquidityU64);
|
|
173
|
+
}
|
|
174
|
+
currentPriceSpot = (0, utils_1.getImpliedRate)(currentLeftBoundaryIndex);
|
|
175
|
+
currentLeftBoundaryIndex = predecessor;
|
|
176
|
+
continue;
|
|
177
|
+
}
|
|
178
|
+
// Fees in token_out (PT)
|
|
179
|
+
const totalFeeOut = (0, utils_1.getFeeFromAmount)(Number(ptOutGrossU64), lpFeeRate);
|
|
180
|
+
const protocolFeeOut = Math.floor((totalFeeOut * protocolFeeBps) / BASE_POINTS);
|
|
181
|
+
const lpFeeOut = totalFeeOut - protocolFeeOut;
|
|
182
|
+
const ptOutNet = Number(ptOutGrossU64) - totalFeeOut;
|
|
183
|
+
// Accumulate to user
|
|
184
|
+
amountOutNet += ptOutNet;
|
|
185
|
+
feeLpOut += lpFeeOut;
|
|
186
|
+
feeProtocolOut += protocolFeeOut;
|
|
187
|
+
// Consume input and advance state
|
|
188
|
+
amountInLeft -= Number(syInSegmentU64);
|
|
189
|
+
currentPriceSpot = spotPriceNew;
|
|
190
|
+
// If we hit boundary, cross
|
|
191
|
+
if (Math.abs(currentPriceSpot - anchorULeft) <= eps && amountInLeft > 0) {
|
|
192
|
+
const predecessor = (0, utils_1.getPredecessorTickKey)(ticks, currentLeftBoundaryIndex);
|
|
193
|
+
if (predecessor === null)
|
|
194
|
+
break;
|
|
195
|
+
// Update active liquidity
|
|
196
|
+
const boundaryTick = (0, utils_1.findTickByKey)(ticks, currentLeftBoundaryIndex);
|
|
197
|
+
if (boundaryTick) {
|
|
198
|
+
activeLiquidityU64 = (0, utils_1.bigIntMax)(0n, activeLiquidityU64 - boundaryTick.tick.liquidityNet);
|
|
199
|
+
activeLiquidityF64 = Number(activeLiquidityU64);
|
|
200
|
+
}
|
|
201
|
+
currentPriceSpot = (0, utils_1.getImpliedRate)(currentLeftBoundaryIndex);
|
|
202
|
+
currentLeftBoundaryIndex = predecessor;
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
return {
|
|
207
|
+
amountInConsumed: args.amountIn - amountInLeft,
|
|
208
|
+
amountOut: amountOutNet,
|
|
209
|
+
lpFeeChargedOutToken: feeLpOut,
|
|
210
|
+
protocolFeeChargedOutToken: feeProtocolOut,
|
|
211
|
+
finalSpotPrice: currentPriceSpot,
|
|
212
|
+
finalTickIndex: currentLeftBoundaryIndex,
|
|
213
|
+
};
|
|
214
|
+
}
|
|
215
|
+
exports.simulateSwap = simulateSwap;
|
|
216
|
+
/**
|
|
217
|
+
* Calculate the expected output for a given input amount
|
|
218
|
+
* This is a convenience wrapper around simulateSwap
|
|
219
|
+
*/
|
|
220
|
+
function getSwapQuote(marketState, amountIn, direction) {
|
|
221
|
+
return simulateSwap(marketState, {
|
|
222
|
+
direction,
|
|
223
|
+
amountIn,
|
|
224
|
+
syExchangeRate: marketState.currentSyExchangeRate,
|
|
225
|
+
isCurrentFlashSwap: false,
|
|
226
|
+
});
|
|
227
|
+
}
|
|
228
|
+
exports.getSwapQuote = getSwapQuote;
|
|
229
|
+
//# sourceMappingURL=swapLegacy.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"swapLegacy.js","sourceRoot":"","sources":["../src/swapLegacy.ts"],"names":[],"mappings":"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"}
|
package/build/utils.d.ts
CHANGED
|
@@ -107,11 +107,11 @@ export declare function findTickByKey(ticks: Ticks, tickKey: number): {
|
|
|
107
107
|
*/
|
|
108
108
|
export declare function findTickByIndex(ticks: Ticks, index: number): Tick;
|
|
109
109
|
/**
|
|
110
|
-
* Convert APY percentage to
|
|
110
|
+
* Convert APY percentage to CLMM tick-key units.
|
|
111
111
|
*/
|
|
112
112
|
export declare function convertApyToApyBp(apyPercent: number): number;
|
|
113
113
|
/**
|
|
114
|
-
* Convert
|
|
114
|
+
* Convert CLMM tick-key units to APY percentage.
|
|
115
115
|
*/
|
|
116
116
|
export declare function convertApyBpToApy(apyBp: number): number;
|
|
117
117
|
export declare function bigIntMax(...args: bigint[]): bigint;
|
package/build/utils.js
CHANGED
|
@@ -203,17 +203,18 @@ function findTickByKey(ticks, tickKey) {
|
|
|
203
203
|
function findTickByIndex(ticks, index) {
|
|
204
204
|
return ticks.ticksTree.at(index - 1) ?? null;
|
|
205
205
|
}
|
|
206
|
+
const CLMM_TICK_KEY_SCALE = 10_000;
|
|
206
207
|
/**
|
|
207
|
-
* Convert APY percentage to
|
|
208
|
+
* Convert APY percentage to CLMM tick-key units.
|
|
208
209
|
*/
|
|
209
210
|
function convertApyToApyBp(apyPercent) {
|
|
210
|
-
return Math.round(apyPercent *
|
|
211
|
+
return Math.round(apyPercent * CLMM_TICK_KEY_SCALE);
|
|
211
212
|
}
|
|
212
213
|
/**
|
|
213
|
-
* Convert
|
|
214
|
+
* Convert CLMM tick-key units to APY percentage.
|
|
214
215
|
*/
|
|
215
216
|
function convertApyBpToApy(apyBp) {
|
|
216
|
-
return apyBp /
|
|
217
|
+
return apyBp / CLMM_TICK_KEY_SCALE;
|
|
217
218
|
}
|
|
218
219
|
function bigIntMax(...args) {
|
|
219
220
|
return args.reduce((m, e) => (e > m ? e : m));
|
package/build/utils.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"utils.js","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":";;;AAoEA,0DAEC;AAMD,4CAGC;AAOD,4CAEC;AAMD,gDAYC;AASD,kDAYC;AAMD,4DAcC;AAMD,gEAcC;AASD,sDAYC;AAWD,wCAGC;AAMD,sCAIC;AAKD,0CAEC;
|
|
1
|
+
{"version":3,"file":"utils.js","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"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"}
|
package/jest.config.ts
ADDED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@exponent-labs/market-three-math",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.14",
|
|
4
4
|
"main": "build/index.js",
|
|
5
5
|
"types": "build/index.d.ts",
|
|
6
6
|
"license": "AGPL-3.0",
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
"test:live": "ts-node examples/test-live-market.ts"
|
|
11
11
|
},
|
|
12
12
|
"dependencies": {
|
|
13
|
-
"@exponent-labs/exponent-fetcher": "0.9.
|
|
13
|
+
"@exponent-labs/exponent-fetcher": "0.9.14",
|
|
14
14
|
"@solana/web3.js": "^1.95.8"
|
|
15
15
|
},
|
|
16
16
|
"devDependencies": {
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
import { PublicKey } from "@solana/web3.js"
|
|
2
|
+
|
|
3
|
+
import type { LpPositionCLMM, Ticks } from "@exponent-labs/exponent-fetcher"
|
|
4
|
+
|
|
5
|
+
import {
|
|
6
|
+
computeExistingPositionBudgetEffect,
|
|
7
|
+
computeExistingPositionEqualization,
|
|
8
|
+
computeRequiredUserMaxForExistingPositionEqualization,
|
|
9
|
+
} from "./existingPositionEqualization"
|
|
10
|
+
|
|
11
|
+
const PRECISE_NUMBER_DENOM = 1_000_000_000_000n
|
|
12
|
+
const SENTINEL_TICK_INDEX = 0xffffffff
|
|
13
|
+
const PUBLIC_KEY = PublicKey.default
|
|
14
|
+
|
|
15
|
+
const preciseRaw = (value: bigint) => value * PRECISE_NUMBER_DENOM
|
|
16
|
+
|
|
17
|
+
const makeTicks = (): Ticks => ({
|
|
18
|
+
currentTick: 1,
|
|
19
|
+
ticksTree: [
|
|
20
|
+
{
|
|
21
|
+
apyBasePoints: 63_000,
|
|
22
|
+
impliedRate: 1.063,
|
|
23
|
+
principalPt: 500n,
|
|
24
|
+
principalSy: 700n,
|
|
25
|
+
principalShareSupply: preciseRaw(100n),
|
|
26
|
+
liquidityNet: 0n,
|
|
27
|
+
liquidityGross: 0n,
|
|
28
|
+
feeGrowthOutsidePt: 0n,
|
|
29
|
+
feeGrowthOutsideSy: 0n,
|
|
30
|
+
farms: [],
|
|
31
|
+
emissions: [],
|
|
32
|
+
lastSplitEpoch: 0n,
|
|
33
|
+
frozenLiquidity: 0n,
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
apyBasePoints: 65_000,
|
|
37
|
+
impliedRate: 1.065,
|
|
38
|
+
principalPt: 0n,
|
|
39
|
+
principalSy: 0n,
|
|
40
|
+
principalShareSupply: 0n,
|
|
41
|
+
liquidityNet: 0n,
|
|
42
|
+
liquidityGross: 0n,
|
|
43
|
+
feeGrowthOutsidePt: 0n,
|
|
44
|
+
feeGrowthOutsideSy: 0n,
|
|
45
|
+
farms: [],
|
|
46
|
+
emissions: [],
|
|
47
|
+
lastSplitEpoch: 0n,
|
|
48
|
+
frozenLiquidity: 0n,
|
|
49
|
+
},
|
|
50
|
+
],
|
|
51
|
+
market: PUBLIC_KEY,
|
|
52
|
+
feeGrowthIndexGlobalPt: 0n,
|
|
53
|
+
feeGrowthIndexGlobalSy: 0n,
|
|
54
|
+
currentPrefixSum: 0n,
|
|
55
|
+
currentSpotPrice: 1.062,
|
|
56
|
+
})
|
|
57
|
+
|
|
58
|
+
const makePosition = (): LpPositionCLMM => ({
|
|
59
|
+
owner: PUBLIC_KEY,
|
|
60
|
+
market: PUBLIC_KEY,
|
|
61
|
+
feeInsideLastPt: 0n,
|
|
62
|
+
feeInsideLastSy: 0n,
|
|
63
|
+
lpBalance: 200n,
|
|
64
|
+
tokensOwedSy: 0n,
|
|
65
|
+
tokensOwedPt: 0n,
|
|
66
|
+
lowerTickIdx: 1,
|
|
67
|
+
upperTickIdx: 2,
|
|
68
|
+
farms: [],
|
|
69
|
+
shareTrackers: [
|
|
70
|
+
{
|
|
71
|
+
tickIdx: 1,
|
|
72
|
+
rightTickIdx: 2,
|
|
73
|
+
splitEpoch: 0n,
|
|
74
|
+
lpShare: preciseRaw(100n),
|
|
75
|
+
emissions: [],
|
|
76
|
+
},
|
|
77
|
+
],
|
|
78
|
+
crossingSplit: {
|
|
79
|
+
crossLeftIdx: 1,
|
|
80
|
+
crossRightIdx: 2,
|
|
81
|
+
lpBalanceCrossing: 100n,
|
|
82
|
+
isActive: true,
|
|
83
|
+
},
|
|
84
|
+
})
|
|
85
|
+
|
|
86
|
+
describe("existing position equalization", () => {
|
|
87
|
+
it("matches the contract add-direction budget math with integer rounding", () => {
|
|
88
|
+
const equalization = computeExistingPositionEqualization(makeTicks(), makePosition())
|
|
89
|
+
|
|
90
|
+
expect(equalization.sySpent).toBe(700n)
|
|
91
|
+
expect(equalization.ptSpent).toBe(500n)
|
|
92
|
+
expect(equalization.syReleased).toBe(0n)
|
|
93
|
+
expect(equalization.ptReleased).toBe(0n)
|
|
94
|
+
expect(equalization.plan).toEqual([
|
|
95
|
+
{
|
|
96
|
+
shareIndex: 0,
|
|
97
|
+
tickIdx: 1,
|
|
98
|
+
direction: "add",
|
|
99
|
+
shareDeltaRaw: preciseRaw(100n),
|
|
100
|
+
ptDelta: 500n,
|
|
101
|
+
syDelta: 700n,
|
|
102
|
+
},
|
|
103
|
+
])
|
|
104
|
+
})
|
|
105
|
+
|
|
106
|
+
it("throws when user budgets cannot cover fixed equalization spend", () => {
|
|
107
|
+
expect(() =>
|
|
108
|
+
computeExistingPositionBudgetEffect({
|
|
109
|
+
ticks: makeTicks(),
|
|
110
|
+
position: makePosition(),
|
|
111
|
+
userMaxSy: 700n,
|
|
112
|
+
userMaxPt: 499n,
|
|
113
|
+
}),
|
|
114
|
+
).toThrow("CrossingEqualizationInvariantViolated")
|
|
115
|
+
|
|
116
|
+
expect(
|
|
117
|
+
computeExistingPositionBudgetEffect({
|
|
118
|
+
ticks: makeTicks(),
|
|
119
|
+
position: makePosition(),
|
|
120
|
+
userMaxSy: 700n,
|
|
121
|
+
userMaxPt: 500n,
|
|
122
|
+
}),
|
|
123
|
+
).toMatchObject({
|
|
124
|
+
effectiveMaxSy: 0n,
|
|
125
|
+
effectiveMaxPt: 0n,
|
|
126
|
+
fixedSySpent: 700n,
|
|
127
|
+
fixedPtSpent: 500n,
|
|
128
|
+
})
|
|
129
|
+
})
|
|
130
|
+
|
|
131
|
+
it("expands desired effective budgets to user-facing instruction inputs", () => {
|
|
132
|
+
expect(
|
|
133
|
+
computeRequiredUserMaxForExistingPositionEqualization({
|
|
134
|
+
ticks: makeTicks(),
|
|
135
|
+
position: makePosition(),
|
|
136
|
+
desiredEffectiveMaxSy: 10n,
|
|
137
|
+
desiredEffectiveMaxPt: 20n,
|
|
138
|
+
}),
|
|
139
|
+
).toMatchObject({
|
|
140
|
+
userMaxSy: 710n,
|
|
141
|
+
userMaxPt: 520n,
|
|
142
|
+
})
|
|
143
|
+
})
|
|
144
|
+
|
|
145
|
+
it("returns a no-op for inactive crossing splits", () => {
|
|
146
|
+
const position = makePosition()
|
|
147
|
+
position.crossingSplit = {
|
|
148
|
+
crossLeftIdx: SENTINEL_TICK_INDEX,
|
|
149
|
+
crossRightIdx: SENTINEL_TICK_INDEX,
|
|
150
|
+
lpBalanceCrossing: 0n,
|
|
151
|
+
isActive: false,
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
expect(computeExistingPositionEqualization(makeTicks(), position)).toMatchObject({
|
|
155
|
+
sySpent: 0n,
|
|
156
|
+
ptSpent: 0n,
|
|
157
|
+
syReleased: 0n,
|
|
158
|
+
ptReleased: 0n,
|
|
159
|
+
plan: [],
|
|
160
|
+
})
|
|
161
|
+
})
|
|
162
|
+
})
|
|
@@ -0,0 +1,367 @@
|
|
|
1
|
+
import type { LpPositionCLMM, Tick, Ticks } from "@exponent-labs/exponent-fetcher"
|
|
2
|
+
|
|
3
|
+
const SENTINEL_TICK_INDEX = 0xffffffff
|
|
4
|
+
const PRECISE_NUMBER_DENOM = 1_000_000_000_000n
|
|
5
|
+
const U64_MAX = (1n << 64n) - 1n
|
|
6
|
+
const U128_MAX = (1n << 128n) - 1n
|
|
7
|
+
|
|
8
|
+
export type CrossingEqualizationDirection = "add" | "remove"
|
|
9
|
+
|
|
10
|
+
export type CrossingEqualizationPlanStep = {
|
|
11
|
+
shareIndex: number
|
|
12
|
+
tickIdx: number
|
|
13
|
+
direction: CrossingEqualizationDirection
|
|
14
|
+
shareDeltaRaw: bigint
|
|
15
|
+
ptDelta: bigint
|
|
16
|
+
syDelta: bigint
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export type ExistingPositionEqualization = {
|
|
20
|
+
sySpent: bigint
|
|
21
|
+
ptSpent: bigint
|
|
22
|
+
syReleased: bigint
|
|
23
|
+
ptReleased: bigint
|
|
24
|
+
plan: CrossingEqualizationPlanStep[]
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export type ExistingPositionBudgetEffect = {
|
|
28
|
+
userMaxSy: bigint
|
|
29
|
+
userMaxPt: bigint
|
|
30
|
+
effectiveMaxSy: bigint
|
|
31
|
+
effectiveMaxPt: bigint
|
|
32
|
+
fixedSySpent: bigint
|
|
33
|
+
fixedPtSpent: bigint
|
|
34
|
+
fixedSyReleased: bigint
|
|
35
|
+
fixedPtReleased: bigint
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const invariantError = (message: string) => new Error(`CrossingEqualizationInvariantViolated: ${message}`)
|
|
39
|
+
|
|
40
|
+
const assertU64 = (value: bigint, label: string): bigint => {
|
|
41
|
+
if (value < 0n || value > U64_MAX) {
|
|
42
|
+
throw invariantError(`${label} does not fit in u64: ${value.toString()}`)
|
|
43
|
+
}
|
|
44
|
+
return value
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
const assertU128 = (value: bigint, label: string): bigint => {
|
|
48
|
+
if (value < 0n || value > U128_MAX) {
|
|
49
|
+
throw invariantError(`${label} does not fit in u128: ${value.toString()}`)
|
|
50
|
+
}
|
|
51
|
+
return value
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
const checkedAddU64 = (left: bigint, right: bigint, label: string) => assertU64(left + right, label)
|
|
55
|
+
|
|
56
|
+
const checkedSubU64 = (left: bigint, right: bigint, label: string) => {
|
|
57
|
+
if (right > left) {
|
|
58
|
+
throw invariantError(`${label} underflow: ${left.toString()} - ${right.toString()}`)
|
|
59
|
+
}
|
|
60
|
+
return left - right
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
const checkedMulU128 = (left: bigint, right: bigint, label: string) => assertU128(left * right, label)
|
|
64
|
+
|
|
65
|
+
const ceilMulDivU128 = (left: bigint, right: bigint, denominator: bigint, label: string) => {
|
|
66
|
+
if (denominator <= 0n) {
|
|
67
|
+
throw invariantError(`${label} division by zero`)
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
const product = checkedMulU128(left, right, `${label} product`)
|
|
71
|
+
return assertU128(product + denominator - 1n, `${label} ceil numerator`) / denominator
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
const fastFloorU128 = (rawPreciseNumber: bigint) =>
|
|
75
|
+
assertU128(rawPreciseNumber, "precise number raw") / PRECISE_NUMBER_DENOM
|
|
76
|
+
|
|
77
|
+
const fastMulRatioRaw = (rawPreciseNumber: bigint, numerator: bigint, denominator: bigint, label: string) => {
|
|
78
|
+
if (denominator <= 0n) {
|
|
79
|
+
throw invariantError(`${label} division by zero`)
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
const raw = assertU128(rawPreciseNumber, `${label} raw precise number`)
|
|
83
|
+
const product = checkedMulU128(raw, numerator, `${label} product`)
|
|
84
|
+
return product / denominator
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
const getTickByIndex = (ticks: Ticks, tickIdx: number): Tick => {
|
|
88
|
+
const tick = ticks.ticksTree[tickIdx - 1]
|
|
89
|
+
if (!tick || tick.apyBasePoints <= 0) {
|
|
90
|
+
throw invariantError(`missing tick at index ${tickIdx}`)
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
return tick
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
const getTickKey = (ticks: Ticks, tickIdx: number) => getTickByIndex(ticks, tickIdx).apyBasePoints
|
|
97
|
+
|
|
98
|
+
const successorIdx = (ticks: Ticks, tickIdx: number): number | null => {
|
|
99
|
+
const tickKey = getTickKey(ticks, tickIdx)
|
|
100
|
+
let best: { tickIdx: number; key: number } | null = null
|
|
101
|
+
|
|
102
|
+
for (let index = 0; index < ticks.ticksTree.length; index++) {
|
|
103
|
+
const key = ticks.ticksTree[index].apyBasePoints
|
|
104
|
+
if (key <= tickKey) {
|
|
105
|
+
continue
|
|
106
|
+
}
|
|
107
|
+
if (!best || key < best.key) {
|
|
108
|
+
best = { tickIdx: index + 1, key }
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
return best?.tickIdx ?? null
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
const isCrossingSplitActive = (position: LpPositionCLMM) =>
|
|
116
|
+
position.crossingSplit.crossLeftIdx !== SENTINEL_TICK_INDEX &&
|
|
117
|
+
position.crossingSplit.crossRightIdx !== SENTINEL_TICK_INDEX
|
|
118
|
+
|
|
119
|
+
const shareIsWithinCrossingRange = (
|
|
120
|
+
ticks: Ticks,
|
|
121
|
+
position: LpPositionCLMM,
|
|
122
|
+
share: LpPositionCLMM["shareTrackers"][number],
|
|
123
|
+
): boolean => {
|
|
124
|
+
const shareLeftKey = getTickKey(ticks, share.tickIdx)
|
|
125
|
+
let shareRightIdx: number | null = share.rightTickIdx
|
|
126
|
+
if (share.rightTickIdx === SENTINEL_TICK_INDEX) {
|
|
127
|
+
shareRightIdx = successorIdx(ticks, share.tickIdx)
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
if (shareRightIdx == null) {
|
|
131
|
+
return false
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
const shareRightKey = getTickKey(ticks, shareRightIdx)
|
|
135
|
+
const crossLeftKey = getTickKey(ticks, position.crossingSplit.crossLeftIdx)
|
|
136
|
+
const crossRightKey = getTickKey(ticks, position.crossingSplit.crossRightIdx)
|
|
137
|
+
|
|
138
|
+
return shareLeftKey >= crossLeftKey && shareRightKey <= crossRightKey
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
const computeAddDeltas = (params: {
|
|
142
|
+
ownedPt: bigint
|
|
143
|
+
ownedSy: bigint
|
|
144
|
+
liquidityDelta: bigint
|
|
145
|
+
lActual: bigint
|
|
146
|
+
}): [bigint, bigint] => {
|
|
147
|
+
const ptDelta =
|
|
148
|
+
params.ownedPt > 0n
|
|
149
|
+
? assertU64(
|
|
150
|
+
ceilMulDivU128(params.ownedPt, params.liquidityDelta, params.lActual, "PT equalization in"),
|
|
151
|
+
"PT equalization in",
|
|
152
|
+
)
|
|
153
|
+
: 0n
|
|
154
|
+
const syDelta =
|
|
155
|
+
params.ownedSy > 0n
|
|
156
|
+
? assertU64(
|
|
157
|
+
ceilMulDivU128(params.ownedSy, params.liquidityDelta, params.lActual, "SY equalization in"),
|
|
158
|
+
"SY equalization in",
|
|
159
|
+
)
|
|
160
|
+
: 0n
|
|
161
|
+
|
|
162
|
+
return [ptDelta, syDelta]
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
const computeRemoveDeltas = (params: { shareDeltaRaw: bigint; node: Tick; supply: bigint }): [bigint, bigint] => {
|
|
166
|
+
const burnShares = fastFloorU128(params.shareDeltaRaw)
|
|
167
|
+
const ptDelta = assertU64(
|
|
168
|
+
checkedMulU128(burnShares, params.node.principalPt, "PT equalization out product") / params.supply,
|
|
169
|
+
"PT equalization out",
|
|
170
|
+
)
|
|
171
|
+
const syDelta = assertU64(
|
|
172
|
+
checkedMulU128(burnShares, params.node.principalSy, "SY equalization out product") / params.supply,
|
|
173
|
+
"SY equalization out",
|
|
174
|
+
)
|
|
175
|
+
|
|
176
|
+
return [ptDelta, syDelta]
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
const summarizePlan = (plan: CrossingEqualizationPlanStep[]): ExistingPositionEqualization => {
|
|
180
|
+
let sySpent = 0n
|
|
181
|
+
let ptSpent = 0n
|
|
182
|
+
let syReleased = 0n
|
|
183
|
+
let ptReleased = 0n
|
|
184
|
+
|
|
185
|
+
for (const step of plan) {
|
|
186
|
+
if (step.direction === "add") {
|
|
187
|
+
sySpent = checkedAddU64(sySpent, step.syDelta, "equalization sy spent")
|
|
188
|
+
ptSpent = checkedAddU64(ptSpent, step.ptDelta, "equalization pt spent")
|
|
189
|
+
continue
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
syReleased = checkedAddU64(syReleased, step.syDelta, "equalization sy released")
|
|
193
|
+
ptReleased = checkedAddU64(ptReleased, step.ptDelta, "equalization pt released")
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
return {
|
|
197
|
+
sySpent,
|
|
198
|
+
ptSpent,
|
|
199
|
+
syReleased,
|
|
200
|
+
ptReleased,
|
|
201
|
+
plan,
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
/**
|
|
206
|
+
* Mirrors `precalc_existing_position_add_liquidity` from the CLMM program.
|
|
207
|
+
*
|
|
208
|
+
* The returned `ptSpent` and `sySpent` are the exact token budget that must be
|
|
209
|
+
* reserved before adding more liquidity to a position with an active crossing split.
|
|
210
|
+
* All PreciseNumber operations are performed on raw fixed-point `bigint` values so
|
|
211
|
+
* the rounding matches the contract's `fast_floor_u128`, `fast_mul_ratio`, and
|
|
212
|
+
* `muldiv_ceil_u128` paths.
|
|
213
|
+
*/
|
|
214
|
+
export function computeExistingPositionEqualization(
|
|
215
|
+
ticks: Ticks,
|
|
216
|
+
position: LpPositionCLMM,
|
|
217
|
+
): ExistingPositionEqualization {
|
|
218
|
+
if (!isCrossingSplitActive(position)) {
|
|
219
|
+
return summarizePlan([])
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
const lActual = assertU64(position.crossingSplit.lpBalanceCrossing, "lpBalanceCrossing")
|
|
223
|
+
const lpBalance = assertU64(position.lpBalance, "lpBalance")
|
|
224
|
+
|
|
225
|
+
if (lpBalance === lActual) {
|
|
226
|
+
return summarizePlan([])
|
|
227
|
+
}
|
|
228
|
+
if (lActual === 0n) {
|
|
229
|
+
throw invariantError("active crossing split has zero actual liquidity")
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
const direction: CrossingEqualizationDirection = lpBalance > lActual ? "add" : "remove"
|
|
233
|
+
const liquidityDelta = lpBalance > lActual ? lpBalance - lActual : lActual - lpBalance
|
|
234
|
+
const plan: CrossingEqualizationPlanStep[] = []
|
|
235
|
+
let sawCrossingRangeShare = false
|
|
236
|
+
let skippedCrossingShareDueToDust = false
|
|
237
|
+
|
|
238
|
+
for (let shareIndex = 0; shareIndex < position.shareTrackers.length; shareIndex++) {
|
|
239
|
+
const share = position.shareTrackers[shareIndex]
|
|
240
|
+
if (!shareIsWithinCrossingRange(ticks, position, share)) {
|
|
241
|
+
continue
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
sawCrossingRangeShare = true
|
|
245
|
+
const node = getTickByIndex(ticks, share.tickIdx)
|
|
246
|
+
const supply = fastFloorU128(node.principalShareSupply)
|
|
247
|
+
if (supply === 0n) {
|
|
248
|
+
skippedCrossingShareDueToDust = true
|
|
249
|
+
continue
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
const shareFloor = fastFloorU128(share.lpShare)
|
|
253
|
+
if (shareFloor === 0n) {
|
|
254
|
+
skippedCrossingShareDueToDust = true
|
|
255
|
+
continue
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
const ownedPt = assertU64(checkedMulU128(shareFloor, node.principalPt, "owned PT product") / supply, "owned PT")
|
|
259
|
+
const ownedSy = assertU64(checkedMulU128(shareFloor, node.principalSy, "owned SY product") / supply, "owned SY")
|
|
260
|
+
const shareDeltaRaw = fastMulRatioRaw(share.lpShare, liquidityDelta, lActual, "share delta")
|
|
261
|
+
|
|
262
|
+
let deltas: [bigint, bigint]
|
|
263
|
+
if (direction === "add") {
|
|
264
|
+
deltas = computeAddDeltas({
|
|
265
|
+
ownedPt,
|
|
266
|
+
ownedSy,
|
|
267
|
+
liquidityDelta,
|
|
268
|
+
lActual,
|
|
269
|
+
})
|
|
270
|
+
} else {
|
|
271
|
+
deltas = computeRemoveDeltas({
|
|
272
|
+
shareDeltaRaw,
|
|
273
|
+
node,
|
|
274
|
+
supply,
|
|
275
|
+
})
|
|
276
|
+
}
|
|
277
|
+
const [ptDelta, syDelta] = deltas
|
|
278
|
+
|
|
279
|
+
if (shareDeltaRaw === 0n && ptDelta === 0n && syDelta === 0n) {
|
|
280
|
+
skippedCrossingShareDueToDust = true
|
|
281
|
+
continue
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
plan.push({
|
|
285
|
+
shareIndex,
|
|
286
|
+
tickIdx: share.tickIdx,
|
|
287
|
+
direction,
|
|
288
|
+
shareDeltaRaw,
|
|
289
|
+
ptDelta,
|
|
290
|
+
syDelta,
|
|
291
|
+
})
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
if (plan.length === 0 && sawCrossingRangeShare && skippedCrossingShareDueToDust) {
|
|
295
|
+
return summarizePlan([])
|
|
296
|
+
}
|
|
297
|
+
if (plan.length === 0) {
|
|
298
|
+
throw invariantError("active crossing split has no equalizable crossing-range shares")
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
return summarizePlan(plan)
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
/**
|
|
305
|
+
* Mirrors the contract's `compute_existing_position_budget_effect`.
|
|
306
|
+
*
|
|
307
|
+
* It throws the same invariant class when the supplied user budgets cannot cover
|
|
308
|
+
* the fixed equalization spend, for example `userMaxPt=0` while `ptSpent>0`.
|
|
309
|
+
*/
|
|
310
|
+
export function computeExistingPositionBudgetEffect(params: {
|
|
311
|
+
ticks: Ticks
|
|
312
|
+
position: LpPositionCLMM
|
|
313
|
+
userMaxSy: bigint
|
|
314
|
+
userMaxPt: bigint
|
|
315
|
+
}): ExistingPositionBudgetEffect {
|
|
316
|
+
const equalization = computeExistingPositionEqualization(params.ticks, params.position)
|
|
317
|
+
const effectiveMaxSy = checkedAddU64(
|
|
318
|
+
checkedSubU64(params.userMaxSy, equalization.sySpent, "effective max SY"),
|
|
319
|
+
equalization.syReleased,
|
|
320
|
+
"effective max SY",
|
|
321
|
+
)
|
|
322
|
+
const effectiveMaxPt = checkedAddU64(
|
|
323
|
+
checkedSubU64(params.userMaxPt, equalization.ptSpent, "effective max PT"),
|
|
324
|
+
equalization.ptReleased,
|
|
325
|
+
"effective max PT",
|
|
326
|
+
)
|
|
327
|
+
|
|
328
|
+
return {
|
|
329
|
+
userMaxSy: params.userMaxSy,
|
|
330
|
+
userMaxPt: params.userMaxPt,
|
|
331
|
+
effectiveMaxSy,
|
|
332
|
+
effectiveMaxPt,
|
|
333
|
+
fixedSySpent: equalization.sySpent,
|
|
334
|
+
fixedPtSpent: equalization.ptSpent,
|
|
335
|
+
fixedSyReleased: equalization.syReleased,
|
|
336
|
+
fixedPtReleased: equalization.ptReleased,
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
/**
|
|
341
|
+
* Mirrors `required_user_max_sy/pt`: expands a desired post-equalization budget
|
|
342
|
+
* into the user-facing max token amounts that should be passed to the instruction.
|
|
343
|
+
*/
|
|
344
|
+
export function computeRequiredUserMaxForExistingPositionEqualization(params: {
|
|
345
|
+
ticks: Ticks
|
|
346
|
+
position: LpPositionCLMM
|
|
347
|
+
desiredEffectiveMaxSy: bigint
|
|
348
|
+
desiredEffectiveMaxPt: bigint
|
|
349
|
+
}): { userMaxSy: bigint; userMaxPt: bigint; equalization: ExistingPositionEqualization } {
|
|
350
|
+
const equalization = computeExistingPositionEqualization(params.ticks, params.position)
|
|
351
|
+
const userMaxSy = checkedSubU64(
|
|
352
|
+
checkedAddU64(params.desiredEffectiveMaxSy, equalization.sySpent, "required user max SY"),
|
|
353
|
+
equalization.syReleased,
|
|
354
|
+
"required user max SY",
|
|
355
|
+
)
|
|
356
|
+
const userMaxPt = checkedSubU64(
|
|
357
|
+
checkedAddU64(params.desiredEffectiveMaxPt, equalization.ptSpent, "required user max PT"),
|
|
358
|
+
equalization.ptReleased,
|
|
359
|
+
"required user max PT",
|
|
360
|
+
)
|
|
361
|
+
|
|
362
|
+
return {
|
|
363
|
+
userMaxSy,
|
|
364
|
+
userMaxPt,
|
|
365
|
+
equalization,
|
|
366
|
+
}
|
|
367
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -56,6 +56,17 @@ export {
|
|
|
56
56
|
simulateWrapperProvideLiquidity,
|
|
57
57
|
simulateSwapAndSupply,
|
|
58
58
|
} from "./addLiquidity"
|
|
59
|
+
export {
|
|
60
|
+
computeExistingPositionBudgetEffect,
|
|
61
|
+
computeExistingPositionEqualization,
|
|
62
|
+
computeRequiredUserMaxForExistingPositionEqualization,
|
|
63
|
+
} from "./existingPositionEqualization"
|
|
64
|
+
export type {
|
|
65
|
+
CrossingEqualizationDirection,
|
|
66
|
+
CrossingEqualizationPlanStep,
|
|
67
|
+
ExistingPositionBudgetEffect,
|
|
68
|
+
ExistingPositionEqualization,
|
|
69
|
+
} from "./existingPositionEqualization"
|
|
59
70
|
|
|
60
71
|
export { getPtAndSyOnWithdrawLiquidity } from "./withdrawLiquidity"
|
|
61
72
|
|
package/src/utils.ts
CHANGED
|
@@ -219,18 +219,20 @@ export function findTickByIndex(ticks: Ticks, index: number): Tick {
|
|
|
219
219
|
return ticks.ticksTree.at(index - 1) ?? null
|
|
220
220
|
}
|
|
221
221
|
|
|
222
|
+
const CLMM_TICK_KEY_SCALE = 10_000
|
|
223
|
+
|
|
222
224
|
/**
|
|
223
|
-
* Convert APY percentage to
|
|
225
|
+
* Convert APY percentage to CLMM tick-key units.
|
|
224
226
|
*/
|
|
225
227
|
export function convertApyToApyBp(apyPercent: number): number {
|
|
226
|
-
return Math.round(apyPercent *
|
|
228
|
+
return Math.round(apyPercent * CLMM_TICK_KEY_SCALE)
|
|
227
229
|
}
|
|
228
230
|
|
|
229
231
|
/**
|
|
230
|
-
* Convert
|
|
232
|
+
* Convert CLMM tick-key units to APY percentage.
|
|
231
233
|
*/
|
|
232
234
|
export function convertApyBpToApy(apyBp: number): number {
|
|
233
|
-
return apyBp /
|
|
235
|
+
return apyBp / CLMM_TICK_KEY_SCALE
|
|
234
236
|
}
|
|
235
237
|
|
|
236
238
|
export function bigIntMax(...args: bigint[]): bigint {
|