@sundaeswap/math 0.2.2 → 0.4.0

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.
Files changed (33) hide show
  1. package/dist/cjs/PoolMath/ConcentratedLiquidityPool.js +214 -0
  2. package/dist/cjs/PoolMath/ConcentratedLiquidityPool.js.map +1 -0
  3. package/dist/cjs/PoolMath/ConstantSumPool.js +284 -0
  4. package/dist/cjs/PoolMath/ConstantSumPool.js.map +1 -0
  5. package/dist/cjs/PoolMath/V4StableswapPool.js +529 -0
  6. package/dist/cjs/PoolMath/V4StableswapPool.js.map +1 -0
  7. package/dist/cjs/PoolMath/index.js +7 -1
  8. package/dist/cjs/PoolMath/index.js.map +1 -1
  9. package/dist/esm/PoolMath/ConcentratedLiquidityPool.js +181 -0
  10. package/dist/esm/PoolMath/ConcentratedLiquidityPool.js.map +1 -0
  11. package/dist/esm/PoolMath/ConstantSumPool.js +266 -0
  12. package/dist/esm/PoolMath/ConstantSumPool.js.map +1 -0
  13. package/dist/esm/PoolMath/V4StableswapPool.js +495 -0
  14. package/dist/esm/PoolMath/V4StableswapPool.js.map +1 -0
  15. package/dist/esm/PoolMath/index.js +3 -0
  16. package/dist/esm/PoolMath/index.js.map +1 -1
  17. package/dist/types/PoolMath/ConcentratedLiquidityPool.d.ts +60 -0
  18. package/dist/types/PoolMath/ConcentratedLiquidityPool.d.ts.map +1 -0
  19. package/dist/types/PoolMath/ConstantSumPool.d.ts +133 -0
  20. package/dist/types/PoolMath/ConstantSumPool.d.ts.map +1 -0
  21. package/dist/types/PoolMath/V4StableswapPool.d.ts +221 -0
  22. package/dist/types/PoolMath/V4StableswapPool.d.ts.map +1 -0
  23. package/dist/types/PoolMath/index.d.ts +3 -0
  24. package/dist/types/PoolMath/index.d.ts.map +1 -1
  25. package/dist/types/tsconfig.build.tsbuildinfo +1 -1
  26. package/package.json +2 -2
  27. package/src/PoolMath/ConcentratedLiquidityPool.ts +275 -0
  28. package/src/PoolMath/ConstantSumPool.ts +371 -0
  29. package/src/PoolMath/V4StableswapPool.ts +638 -0
  30. package/src/PoolMath/__tests__/ConcentratedLiquidityPool.test.ts +225 -0
  31. package/src/PoolMath/__tests__/ConstantSumPool.test.ts +322 -0
  32. package/src/PoolMath/__tests__/V4StableswapPool.test.ts +688 -0
  33. package/src/PoolMath/index.ts +3 -0
@@ -0,0 +1,214 @@
1
+ "use strict";
2
+
3
+ function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof(o); }
4
+ Object.defineProperty(exports, "__esModule", {
5
+ value: true
6
+ });
7
+ exports.getSwapOutput = exports.getSwapInput = exports.calculateLiquidity = void 0;
8
+ var _asset = require("@sundaeswap/asset");
9
+ var _fraction = require("@sundaeswap/fraction");
10
+ var ConstantProductPool = _interopRequireWildcard(require("./ConstantProductPool.js"));
11
+ function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function _interopRequireWildcard(e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, "default": e }; if (null === e || "object" != _typeof(e) && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (var _t in e) "default" !== _t && {}.hasOwnProperty.call(e, _t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, _t)) && (i.get || i.set) ? o(f, _t, i) : f[_t] = e[_t]); return f; })(e, t); }
12
+ function _slicedToArray(r, e) { return _arrayWithHoles(r) || _iterableToArrayLimit(r, e) || _unsupportedIterableToArray(r, e) || _nonIterableRest(); }
13
+ function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
14
+ function _unsupportedIterableToArray(r, a) { if (r) { if ("string" == typeof r) return _arrayLikeToArray(r, a); var t = {}.toString.call(r).slice(8, -1); return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0; } }
15
+ function _arrayLikeToArray(r, a) { (null == a || a > r.length) && (a = r.length); for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e]; return n; }
16
+ function _iterableToArrayLimit(r, l) { var t = null == r ? null : "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (null != t) { var e, n, i, u, a = [], f = !0, o = !1; try { if (i = (t = t.call(r)).next, 0 === l) { if (Object(t) !== t) return; f = !1; } else for (; !(f = (e = i.call(t)).done) && (a.push(e.value), a.length !== l); f = !0); } catch (r) { o = !0, n = r; } finally { try { if (!f && null != t["return"] && (u = t["return"](), Object(u) !== u)) return; } finally { if (o) throw n; } } return a; } }
17
+ function _arrayWithHoles(r) { if (Array.isArray(r)) return r; }
18
+ /**
19
+ * Holds the calculated outcome of a concentrated-liquidity swap. Mirrors
20
+ * {@link ConstantProductPool.TSwapOutcome} so it flows through the same generic
21
+ * swap-outcome consumers.
22
+ */
23
+
24
+ /** A sqrt-price bound from the CL config, as an exact rational `[num, den]`. */
25
+
26
+ /**
27
+ * Concentrated liquidity is Sundae v4's single-range invariant. Unlike Uniswap
28
+ * v3 there are no per-position ranges or ticks: the whole pool shares ONE
29
+ * immutable price range `[sqrtPriceA, sqrtPriceB]` (a < b) set at creation, and
30
+ * LP is a single fungible token. Swaps run on *virtual* reserves that fold the
31
+ * pool's liquidity `L` (its total LP supply) into each side:
32
+ *
33
+ * VA = a·spbNum + L·spbDen
34
+ * VB = b·spaDen + L·spaNum
35
+ *
36
+ * where `a`/`b` are the raw assetA/assetB reserves. This is a direct port of the
37
+ * scooper's `cl_swap_result` (scooper-v2/src/sundaev4/swap_math.rs) and the
38
+ * on-chain `cl_check_swap` (sundae-v4/lib/modules/cl_check.ak) — those are the
39
+ * source of truth; keep this in lockstep with them.
40
+ */
41
+
42
+ var asFeeParts = function asFeeParts(fee) {
43
+ var f = _fraction.Fraction.asFraction(fee);
44
+ if (f.lt(_fraction.Fraction.ZERO) || f.gte(_fraction.Fraction.ONE)) throw new Error("fee must be in [0, 1)");
45
+ return [BigInt(f.numerator), BigInt(f.denominator)];
46
+ };
47
+
48
+ /**
49
+ * The raw forward swap: given a pre-fee input `dx`, return the output amount.
50
+ * A→B and B→A use different virtual-reserve scalings (see `cl_check_swap`).
51
+ * All quantities are non-negative so integer division floors, matching chain.
52
+ */
53
+ var rawSwapOutput = function rawSwapOutput(dx, aReserve, bReserve, totalLp, spaNum, spaDen, spbNum, spbDen, feeNum, feeDen, isAInput) {
54
+ var fee = dx * feeNum / feeDen;
55
+ var dxEff = dx - fee;
56
+ var va0 = aReserve * spbNum + totalLp * spbDen;
57
+ var vb0 = bReserve * spaDen + totalLp * spaNum;
58
+ if (isAInput) {
59
+ var dvaEff = dxEff * spbNum;
60
+ var _denom = (va0 + dvaEff) * spaDen;
61
+ if (_denom <= 0n) return 0n;
62
+ return vb0 * dvaEff / _denom;
63
+ }
64
+ var dvbEff = dxEff * spaNum;
65
+ var denom = (vb0 + dvbEff) * spbNum;
66
+ if (denom <= 0n) return 0n;
67
+ return va0 * dvbEff / denom;
68
+ };
69
+
70
+ /**
71
+ * Calculate the swap outcome for a concentrated-liquidity pool.
72
+ *
73
+ * @param inputMetadata Metadata for the supplied (input) asset — used for the fee AssetAmount.
74
+ * @param input The pre-fee amount of the input asset being swapped.
75
+ * @param aReserve The pool's raw reserve of asset A.
76
+ * @param bReserve The pool's raw reserve of asset B.
77
+ * @param totalLp The pool's total LP supply (the virtual liquidity `L`).
78
+ * @param sqrtPriceA The lower sqrt-price bound `[num, den]` from the CL config.
79
+ * @param sqrtPriceB The upper sqrt-price bound `[num, den]` from the CL config.
80
+ * @param fee The liquidity-provider fee (plus protocol fee) as a fraction.
81
+ * @param isAInput True when asset A is the supplied asset (A→B swap).
82
+ * @returns The swap details in the shared {@link TSwapOutcome} shape.
83
+ */
84
+ var getSwapOutput = exports.getSwapOutput = function getSwapOutput(inputMetadata, input, aReserve, bReserve, totalLp, sqrtPriceA, sqrtPriceB, fee, isAInput) {
85
+ if (input <= 0n || aReserve <= 0n || bReserve <= 0n || totalLp <= 0n) throw new Error("Input, reserves and liquidity must be positive");
86
+ var _sqrtPriceA = _slicedToArray(sqrtPriceA, 2),
87
+ spaNum = _sqrtPriceA[0],
88
+ spaDen = _sqrtPriceA[1];
89
+ var _sqrtPriceB = _slicedToArray(sqrtPriceB, 2),
90
+ spbNum = _sqrtPriceB[0],
91
+ spbDen = _sqrtPriceB[1];
92
+ if (spaNum <= 0n || spaDen <= 0n || spbNum <= 0n || spbDen <= 0n) throw new Error("sqrt prices must be positive");
93
+ var _asFeeParts = asFeeParts(fee),
94
+ _asFeeParts2 = _slicedToArray(_asFeeParts, 2),
95
+ feeNum = _asFeeParts2[0],
96
+ feeDen = _asFeeParts2[1];
97
+ var inputReserve = isAInput ? aReserve : bReserve;
98
+ var outputReserve = isAInput ? bReserve : aReserve;
99
+ var output = rawSwapOutput(input, aReserve, bReserve, totalLp, spaNum, spaDen, spbNum, spbDen, feeNum, feeDen, isAInput);
100
+ // Can't take more than the pool actually holds (virtual reserves can
101
+ // otherwise let the formula exceed the real reserve near the boundary).
102
+ if (output > outputReserve) output = outputReserve;
103
+ var inputLpFee = input * feeNum / feeDen;
104
+ var nextInputReserve = inputReserve + input;
105
+ var nextOutputReserve = outputReserve - output;
106
+
107
+ // Price impact vs the marginal (dx→0) rate. Marginal output-per-effective-
108
+ // input is vb0·spbNum/(va0·spaDen) for A→B (symmetric for B→A), so the ideal
109
+ // input-per-output is its reciprocal. Display-only.
110
+ var va0 = aReserve * spbNum + totalLp * spbDen;
111
+ var vb0 = bReserve * spaDen + totalLp * spaNum;
112
+ var priceImpact = _fraction.Fraction.ZERO;
113
+ if (output > 0n) {
114
+ var idealPrice = isAInput ? new _fraction.Fraction(va0 * spaDen, vb0 * spbNum) : new _fraction.Fraction(vb0 * spbNum, va0 * spaDen);
115
+ var actualPrice = new _fraction.Fraction(input - inputLpFee, output);
116
+ priceImpact = _fraction.Fraction.ONE.subtract(idealPrice.divide(actualPrice));
117
+ }
118
+ return {
119
+ input: input,
120
+ output: output,
121
+ lpFee: new _asset.AssetAmount(inputLpFee, inputMetadata),
122
+ nextInputReserve: nextInputReserve,
123
+ nextOutputReserve: nextOutputReserve,
124
+ priceImpact: priceImpact
125
+ };
126
+ };
127
+
128
+ /**
129
+ * Calculate the minimal input required to receive a given output — the inverse
130
+ * of {@link getSwapOutput}. The forward swap is linear-fractional in the
131
+ * effective input, so it inverts in closed form; a short correction loop
132
+ * absorbs the fee floor and integer rounding so the result is the exact minimal
133
+ * input whose forward swap yields at least `output`.
134
+ */
135
+ var getSwapInput = exports.getSwapInput = function getSwapInput(inputMetadata, output, aReserve, bReserve, totalLp, sqrtPriceA, sqrtPriceB, fee, isAInput) {
136
+ if (output <= 0n || aReserve <= 0n || bReserve <= 0n || totalLp <= 0n) throw new Error("Output, reserves and liquidity must be positive");
137
+ var _sqrtPriceA2 = _slicedToArray(sqrtPriceA, 2),
138
+ spaNum = _sqrtPriceA2[0],
139
+ spaDen = _sqrtPriceA2[1];
140
+ var _sqrtPriceB2 = _slicedToArray(sqrtPriceB, 2),
141
+ spbNum = _sqrtPriceB2[0],
142
+ spbDen = _sqrtPriceB2[1];
143
+ if (spaNum <= 0n || spaDen <= 0n || spbNum <= 0n || spbDen <= 0n) throw new Error("sqrt prices must be positive");
144
+ var outputReserve = isAInput ? bReserve : aReserve;
145
+ if (output > outputReserve) throw new Error("Output must not exceed the output reserve");
146
+ var _asFeeParts3 = asFeeParts(fee),
147
+ _asFeeParts4 = _slicedToArray(_asFeeParts3, 2),
148
+ feeNum = _asFeeParts4[0],
149
+ feeDen = _asFeeParts4[1];
150
+ var feeDiff = feeDen - feeNum;
151
+ var va0 = aReserve * spbNum + totalLp * spbDen;
152
+ var vb0 = bReserve * spaDen + totalLp * spaNum;
153
+ var ceilDiv = function ceilDiv(n, d) {
154
+ return (n + d - 1n) / d;
155
+ };
156
+
157
+ // Closed-form minimal effective input, then gross up for the fee floor.
158
+ var effMin;
159
+ if (isAInput) {
160
+ // dvaEff ≥ output·spaDen·va0 / (vb0 − output·spaDen)
161
+ var denom = vb0 - output * spaDen;
162
+ if (denom <= 0n) throw new Error("Output not reachable within the pool's range");
163
+ var dvaEffMin = ceilDiv(output * spaDen * va0, denom);
164
+ effMin = ceilDiv(dvaEffMin, spbNum);
165
+ } else {
166
+ var _denom2 = va0 - output * spbNum;
167
+ if (_denom2 <= 0n) throw new Error("Output not reachable within the pool's range");
168
+ var dvbEffMin = ceilDiv(output * spbNum * vb0, _denom2);
169
+ effMin = ceilDiv(dvbEffMin, spaNum);
170
+ }
171
+ var input = feeDiff > 0n ? ceilDiv(effMin * feeDen, feeDiff) : effMin;
172
+
173
+ // Correct for floor interactions: nudge up until the forward swap clears the
174
+ // target, then trim any over-shoot. Bounded — a couple of iterations at most.
175
+ var fwd = function fwd(dx) {
176
+ return rawSwapOutput(dx, aReserve, bReserve, totalLp, spaNum, spaDen, spbNum, spbDen, feeNum, feeDen, isAInput);
177
+ };
178
+ var guard = 0;
179
+ while (fwd(input) < output && guard++ < 64) input += 1n;
180
+ while (input > 1n && fwd(input - 1n) >= output) input -= 1n;
181
+ var inputLpFee = input * feeNum / feeDen;
182
+ var inputReserve = isAInput ? aReserve : bReserve;
183
+ var nextInputReserve = inputReserve + input;
184
+ var nextOutputReserve = outputReserve - output;
185
+ var priceImpact = _fraction.Fraction.ZERO;
186
+ if (output > 0n) {
187
+ var idealPrice = isAInput ? new _fraction.Fraction(va0 * spaDen, vb0 * spbNum) : new _fraction.Fraction(vb0 * spbNum, va0 * spaDen);
188
+ var actualPrice = new _fraction.Fraction(input - inputLpFee, output);
189
+ priceImpact = _fraction.Fraction.ONE.subtract(idealPrice.divide(actualPrice));
190
+ }
191
+ return {
192
+ input: input,
193
+ output: output,
194
+ lpFee: new _asset.AssetAmount(inputLpFee, inputMetadata),
195
+ nextInputReserve: nextInputReserve,
196
+ nextOutputReserve: nextOutputReserve,
197
+ priceImpact: priceImpact
198
+ };
199
+ };
200
+
201
+ /**
202
+ * Deposit LP estimate for a concentrated-liquidity pool. CL deposits reuse the
203
+ * constant-product *proportional* pinning: minting by the scarcest offered
204
+ * asset and ceil-pinning the reserve deltas gives, per asset,
205
+ * `a1·L0 ≥ a0·L1` and `b1·L0 ≥ b0·L1` — and those two bounds multiply to
206
+ * exactly the on-chain CL non-swap invariant `va1·vb1·L0² ≥ va0·vb0·L1²`
207
+ * (`cl_check.ak`). So the proportional deposit is always chain-valid; excess of
208
+ * either asset is refunded via aChange/bChange. This mirrors the scooper's
209
+ * `resolve_cl_deposit` (which likewise reuses the CP pinning).
210
+ */
211
+ var calculateLiquidity = exports.calculateLiquidity = function calculateLiquidity(a, b, aReserve, bReserve, totalLp) {
212
+ return ConstantProductPool.calculateLiquidity(a, b, aReserve, bReserve, totalLp);
213
+ };
214
+ //# sourceMappingURL=ConcentratedLiquidityPool.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ConcentratedLiquidityPool.js","names":["_asset","require","_fraction","ConstantProductPool","_interopRequireWildcard","e","t","WeakMap","r","n","__esModule","o","i","f","__proto__","_typeof","has","get","set","_t","hasOwnProperty","call","Object","defineProperty","getOwnPropertyDescriptor","_slicedToArray","_arrayWithHoles","_iterableToArrayLimit","_unsupportedIterableToArray","_nonIterableRest","TypeError","a","_arrayLikeToArray","toString","slice","constructor","name","Array","from","test","length","l","Symbol","iterator","u","next","done","push","value","isArray","asFeeParts","fee","Fraction","asFraction","lt","ZERO","gte","ONE","Error","BigInt","numerator","denominator","rawSwapOutput","dx","aReserve","bReserve","totalLp","spaNum","spaDen","spbNum","spbDen","feeNum","feeDen","isAInput","dxEff","va0","vb0","dvaEff","denom","dvbEff","getSwapOutput","exports","inputMetadata","input","sqrtPriceA","sqrtPriceB","_sqrtPriceA","_sqrtPriceB","_asFeeParts","_asFeeParts2","inputReserve","outputReserve","output","inputLpFee","nextInputReserve","nextOutputReserve","priceImpact","idealPrice","actualPrice","subtract","divide","lpFee","AssetAmount","getSwapInput","_sqrtPriceA2","_sqrtPriceB2","_asFeeParts3","_asFeeParts4","feeDiff","ceilDiv","d","effMin","dvaEffMin","dvbEffMin","fwd","guard","calculateLiquidity","b"],"sources":["../../../src/PoolMath/ConcentratedLiquidityPool.ts"],"sourcesContent":["import { AssetAmount, IAssetAmountMetadata } from \"@sundaeswap/asset\";\nimport { Fraction, type TFractionLike } from \"@sundaeswap/fraction\";\n\nimport * as ConstantProductPool from \"./ConstantProductPool.js\";\n\n/**\n * Holds the calculated outcome of a concentrated-liquidity swap. Mirrors\n * {@link ConstantProductPool.TSwapOutcome} so it flows through the same generic\n * swap-outcome consumers.\n */\nexport type TSwapOutcome = {\n input: bigint;\n output: bigint;\n lpFee: AssetAmount<IAssetAmountMetadata>;\n nextInputReserve: bigint;\n nextOutputReserve: bigint;\n priceImpact: Fraction;\n};\n\n/** A sqrt-price bound from the CL config, as an exact rational `[num, den]`. */\nexport type TSqrtPrice = [bigint, bigint];\n\n/**\n * Concentrated liquidity is Sundae v4's single-range invariant. Unlike Uniswap\n * v3 there are no per-position ranges or ticks: the whole pool shares ONE\n * immutable price range `[sqrtPriceA, sqrtPriceB]` (a < b) set at creation, and\n * LP is a single fungible token. Swaps run on *virtual* reserves that fold the\n * pool's liquidity `L` (its total LP supply) into each side:\n *\n * VA = a·spbNum + L·spbDen\n * VB = b·spaDen + L·spaNum\n *\n * where `a`/`b` are the raw assetA/assetB reserves. This is a direct port of the\n * scooper's `cl_swap_result` (scooper-v2/src/sundaev4/swap_math.rs) and the\n * on-chain `cl_check_swap` (sundae-v4/lib/modules/cl_check.ak) — those are the\n * source of truth; keep this in lockstep with them.\n */\n\nconst asFeeParts = (fee: TFractionLike): [bigint, bigint] => {\n const f = Fraction.asFraction(fee);\n if (f.lt(Fraction.ZERO) || f.gte(Fraction.ONE))\n throw new Error(\"fee must be in [0, 1)\");\n return [BigInt(f.numerator), BigInt(f.denominator)];\n};\n\n/**\n * The raw forward swap: given a pre-fee input `dx`, return the output amount.\n * A→B and B→A use different virtual-reserve scalings (see `cl_check_swap`).\n * All quantities are non-negative so integer division floors, matching chain.\n */\nconst rawSwapOutput = (\n dx: bigint,\n aReserve: bigint,\n bReserve: bigint,\n totalLp: bigint,\n spaNum: bigint,\n spaDen: bigint,\n spbNum: bigint,\n spbDen: bigint,\n feeNum: bigint,\n feeDen: bigint,\n isAInput: boolean,\n): bigint => {\n const fee = (dx * feeNum) / feeDen;\n const dxEff = dx - fee;\n const va0 = aReserve * spbNum + totalLp * spbDen;\n const vb0 = bReserve * spaDen + totalLp * spaNum;\n if (isAInput) {\n const dvaEff = dxEff * spbNum;\n const denom = (va0 + dvaEff) * spaDen;\n if (denom <= 0n) return 0n;\n return (vb0 * dvaEff) / denom;\n }\n const dvbEff = dxEff * spaNum;\n const denom = (vb0 + dvbEff) * spbNum;\n if (denom <= 0n) return 0n;\n return (va0 * dvbEff) / denom;\n};\n\n/**\n * Calculate the swap outcome for a concentrated-liquidity pool.\n *\n * @param inputMetadata Metadata for the supplied (input) asset — used for the fee AssetAmount.\n * @param input The pre-fee amount of the input asset being swapped.\n * @param aReserve The pool's raw reserve of asset A.\n * @param bReserve The pool's raw reserve of asset B.\n * @param totalLp The pool's total LP supply (the virtual liquidity `L`).\n * @param sqrtPriceA The lower sqrt-price bound `[num, den]` from the CL config.\n * @param sqrtPriceB The upper sqrt-price bound `[num, den]` from the CL config.\n * @param fee The liquidity-provider fee (plus protocol fee) as a fraction.\n * @param isAInput True when asset A is the supplied asset (A→B swap).\n * @returns The swap details in the shared {@link TSwapOutcome} shape.\n */\nexport const getSwapOutput = (\n inputMetadata: IAssetAmountMetadata,\n input: bigint,\n aReserve: bigint,\n bReserve: bigint,\n totalLp: bigint,\n sqrtPriceA: TSqrtPrice,\n sqrtPriceB: TSqrtPrice,\n fee: TFractionLike,\n isAInput: boolean,\n): TSwapOutcome => {\n if (input <= 0n || aReserve <= 0n || bReserve <= 0n || totalLp <= 0n)\n throw new Error(\"Input, reserves and liquidity must be positive\");\n const [spaNum, spaDen] = sqrtPriceA;\n const [spbNum, spbDen] = sqrtPriceB;\n if (spaNum <= 0n || spaDen <= 0n || spbNum <= 0n || spbDen <= 0n)\n throw new Error(\"sqrt prices must be positive\");\n const [feeNum, feeDen] = asFeeParts(fee);\n\n const inputReserve = isAInput ? aReserve : bReserve;\n const outputReserve = isAInput ? bReserve : aReserve;\n\n let output = rawSwapOutput(\n input,\n aReserve,\n bReserve,\n totalLp,\n spaNum,\n spaDen,\n spbNum,\n spbDen,\n feeNum,\n feeDen,\n isAInput,\n );\n // Can't take more than the pool actually holds (virtual reserves can\n // otherwise let the formula exceed the real reserve near the boundary).\n if (output > outputReserve) output = outputReserve;\n\n const inputLpFee = (input * feeNum) / feeDen;\n const nextInputReserve = inputReserve + input;\n const nextOutputReserve = outputReserve - output;\n\n // Price impact vs the marginal (dx→0) rate. Marginal output-per-effective-\n // input is vb0·spbNum/(va0·spaDen) for A→B (symmetric for B→A), so the ideal\n // input-per-output is its reciprocal. Display-only.\n const va0 = aReserve * spbNum + totalLp * spbDen;\n const vb0 = bReserve * spaDen + totalLp * spaNum;\n let priceImpact = Fraction.ZERO;\n if (output > 0n) {\n const idealPrice = isAInput\n ? new Fraction(va0 * spaDen, vb0 * spbNum)\n : new Fraction(vb0 * spbNum, va0 * spaDen);\n const actualPrice = new Fraction(input - inputLpFee, output);\n priceImpact = Fraction.ONE.subtract(idealPrice.divide(actualPrice));\n }\n\n return {\n input,\n output,\n lpFee: new AssetAmount(inputLpFee, inputMetadata),\n nextInputReserve,\n nextOutputReserve,\n priceImpact,\n };\n};\n\n/**\n * Calculate the minimal input required to receive a given output — the inverse\n * of {@link getSwapOutput}. The forward swap is linear-fractional in the\n * effective input, so it inverts in closed form; a short correction loop\n * absorbs the fee floor and integer rounding so the result is the exact minimal\n * input whose forward swap yields at least `output`.\n */\nexport const getSwapInput = (\n inputMetadata: IAssetAmountMetadata,\n output: bigint,\n aReserve: bigint,\n bReserve: bigint,\n totalLp: bigint,\n sqrtPriceA: TSqrtPrice,\n sqrtPriceB: TSqrtPrice,\n fee: TFractionLike,\n isAInput: boolean,\n): TSwapOutcome => {\n if (output <= 0n || aReserve <= 0n || bReserve <= 0n || totalLp <= 0n)\n throw new Error(\"Output, reserves and liquidity must be positive\");\n const [spaNum, spaDen] = sqrtPriceA;\n const [spbNum, spbDen] = sqrtPriceB;\n if (spaNum <= 0n || spaDen <= 0n || spbNum <= 0n || spbDen <= 0n)\n throw new Error(\"sqrt prices must be positive\");\n const outputReserve = isAInput ? bReserve : aReserve;\n if (output > outputReserve)\n throw new Error(\"Output must not exceed the output reserve\");\n\n const [feeNum, feeDen] = asFeeParts(fee);\n const feeDiff = feeDen - feeNum;\n\n const va0 = aReserve * spbNum + totalLp * spbDen;\n const vb0 = bReserve * spaDen + totalLp * spaNum;\n\n const ceilDiv = (n: bigint, d: bigint) => (n + d - 1n) / d;\n\n // Closed-form minimal effective input, then gross up for the fee floor.\n let effMin: bigint;\n if (isAInput) {\n // dvaEff ≥ output·spaDen·va0 / (vb0 − output·spaDen)\n const denom = vb0 - output * spaDen;\n if (denom <= 0n)\n throw new Error(\"Output not reachable within the pool's range\");\n const dvaEffMin = ceilDiv(output * spaDen * va0, denom);\n effMin = ceilDiv(dvaEffMin, spbNum);\n } else {\n const denom = va0 - output * spbNum;\n if (denom <= 0n)\n throw new Error(\"Output not reachable within the pool's range\");\n const dvbEffMin = ceilDiv(output * spbNum * vb0, denom);\n effMin = ceilDiv(dvbEffMin, spaNum);\n }\n let input = feeDiff > 0n ? ceilDiv(effMin * feeDen, feeDiff) : effMin;\n\n // Correct for floor interactions: nudge up until the forward swap clears the\n // target, then trim any over-shoot. Bounded — a couple of iterations at most.\n const fwd = (dx: bigint) =>\n rawSwapOutput(\n dx,\n aReserve,\n bReserve,\n totalLp,\n spaNum,\n spaDen,\n spbNum,\n spbDen,\n feeNum,\n feeDen,\n isAInput,\n );\n let guard = 0;\n while (fwd(input) < output && guard++ < 64) input += 1n;\n while (input > 1n && fwd(input - 1n) >= output) input -= 1n;\n\n const inputLpFee = (input * feeNum) / feeDen;\n const inputReserve = isAInput ? aReserve : bReserve;\n const nextInputReserve = inputReserve + input;\n const nextOutputReserve = outputReserve - output;\n\n let priceImpact = Fraction.ZERO;\n if (output > 0n) {\n const idealPrice = isAInput\n ? new Fraction(va0 * spaDen, vb0 * spbNum)\n : new Fraction(vb0 * spbNum, va0 * spaDen);\n const actualPrice = new Fraction(input - inputLpFee, output);\n priceImpact = Fraction.ONE.subtract(idealPrice.divide(actualPrice));\n }\n\n return {\n input,\n output,\n lpFee: new AssetAmount(inputLpFee, inputMetadata),\n nextInputReserve,\n nextOutputReserve,\n priceImpact,\n };\n};\n\n/**\n * Deposit LP estimate for a concentrated-liquidity pool. CL deposits reuse the\n * constant-product *proportional* pinning: minting by the scarcest offered\n * asset and ceil-pinning the reserve deltas gives, per asset,\n * `a1·L0 ≥ a0·L1` and `b1·L0 ≥ b0·L1` — and those two bounds multiply to\n * exactly the on-chain CL non-swap invariant `va1·vb1·L0² ≥ va0·vb0·L1²`\n * (`cl_check.ak`). So the proportional deposit is always chain-valid; excess of\n * either asset is refunded via aChange/bChange. This mirrors the scooper's\n * `resolve_cl_deposit` (which likewise reuses the CP pinning).\n */\nexport const calculateLiquidity = (\n a: bigint,\n b: bigint,\n aReserve: bigint,\n bReserve: bigint,\n totalLp: bigint,\n) => ConstantProductPool.calculateLiquidity(a, b, aReserve, bReserve, totalLp);\n"],"mappings":"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","ignoreList":[]}
@@ -0,0 +1,284 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.pinnedDepositFromAnchor = exports.getSwapOutput = exports.getSwapInput = exports.calculatePinnedDeposit = exports.calculateLiquidity = exports.calculateDepositN = void 0;
7
+ var _asset = require("@sundaeswap/asset");
8
+ var _fraction = require("@sundaeswap/fraction");
9
+ var _index = require("./index.js");
10
+ /**
11
+ * Holds the calculated outcome of a constant-sum swap. Mirrors
12
+ * {@link ConstantProductPool.TSwapOutcome} so both can flow through the same
13
+ * generic swap-outcome consumers.
14
+ */
15
+
16
+ /**
17
+ * Calculate the swap outcome for a constant-sum (fixed-price) pool — the
18
+ * invariant used by Sundae v4 stable/pegged pools. Unlike constant product,
19
+ * the exchange rate is fixed by the pool's per-asset `prices`: the input is
20
+ * converted to "value" at `priceIn`, the fee is taken off that value, and the
21
+ * remainder is converted to the output asset at `priceOut`. The result is
22
+ * capped at the output reserve (you can't take more than the pool holds).
23
+ *
24
+ * Matches the scooper's `cs_swap_result`:
25
+ * output = floor((input·priceIn − floor(input·priceIn·fee)) / priceOut)
26
+ *
27
+ * @param inputMetadata Metadata for the supplied (input) asset — used for the fee AssetAmount.
28
+ * @param input The amount of the input asset being swapped.
29
+ * @param inputReserve The pool's reserve of the input asset.
30
+ * @param outputReserve The pool's reserve of the output asset.
31
+ * @param priceIn The pool's price for the input asset (from the constant-sum config).
32
+ * @param priceOut The pool's price for the output asset.
33
+ * @param fee The liquidity-provider fee (plus protocol fee) as a fraction.
34
+ * @param roundOutputUp When true, round the output up instead of flooring.
35
+ * @returns The swap details in the shared {@link TSwapOutcome} shape.
36
+ */
37
+ var getSwapOutput = exports.getSwapOutput = function getSwapOutput(inputMetadata, input, inputReserve, outputReserve, priceIn, priceOut, fee, roundOutputUp) {
38
+ if (input <= 0n || inputReserve <= 0n || outputReserve <= 0n) throw new Error("Input and reserves must be positive");
39
+ if (priceIn <= 0n || priceOut <= 0n) throw new Error("Prices must be positive");
40
+ var feeFraction = _fraction.Fraction.asFraction(fee);
41
+ if (feeFraction.lt(_fraction.Fraction.ZERO) || feeFraction.gt(_fraction.Fraction.ONE)) throw new Error("fee must be between 0 and 1");
42
+ var inputValue = input * priceIn;
43
+ var feeValue = new _fraction.Fraction(inputValue * BigInt(feeFraction.numerator), BigInt(feeFraction.denominator)).quotient;
44
+ var outputValue = inputValue - feeValue;
45
+ var output = roundOutputUp ? (outputValue + priceOut - 1n) / priceOut : outputValue / priceOut;
46
+
47
+ // Can't take more than the pool holds.
48
+ if (output > outputReserve) {
49
+ output = outputReserve;
50
+ }
51
+
52
+ // LP fee expressed in input-asset units (value scales linearly with input,
53
+ // so the input-denominated fee is input·feeRate) — matching ConstantProductPool.
54
+ var inputLpFee = new _fraction.Fraction(input * BigInt(feeFraction.numerator), BigInt(feeFraction.denominator)).quotient;
55
+ var nextInputReserve = inputReserve + input;
56
+ var nextOutputReserve = outputReserve - output;
57
+
58
+ // Price impact vs the pool's par price (priceOut/priceIn input-per-output);
59
+ // ~0 for a constant-sum pool aside from the fee. See ConstantProductPool.
60
+ var priceImpact = _fraction.Fraction.ZERO;
61
+ if (output > 0n) {
62
+ var amountInLessFee = input - inputLpFee;
63
+ var idealPrice = new _fraction.Fraction(priceOut, priceIn);
64
+ var actualPrice = new _fraction.Fraction(amountInLessFee, output);
65
+ priceImpact = _fraction.Fraction.ONE.subtract(idealPrice.divide(actualPrice));
66
+ }
67
+ return {
68
+ input: input,
69
+ output: output,
70
+ lpFee: new _asset.AssetAmount(inputLpFee, inputMetadata),
71
+ nextInputReserve: nextInputReserve,
72
+ nextOutputReserve: nextOutputReserve,
73
+ priceImpact: priceImpact
74
+ };
75
+ };
76
+
77
+ /**
78
+ * Calculate the minimal input required to receive a given output from a
79
+ * constant-sum pool — the exact inverse of {@link getSwapOutput}.
80
+ *
81
+ * The forward math floors the fee off the input value, which makes the
82
+ * post-fee value `ceil(input·priceIn·(1−fee))`; inverting that ceiling gives
83
+ * the smallest input whose forward swap yields at least `output`.
84
+ *
85
+ * Unlike constant product there is no asymptote, so an output equal to the
86
+ * full output reserve is attainable (the pool can be drained at par).
87
+ *
88
+ * @param inputMetadata Metadata for the supplied (input) asset — used for the fee AssetAmount.
89
+ * @param output The desired amount of the output asset.
90
+ * @param inputReserve The pool's reserve of the input asset.
91
+ * @param outputReserve The pool's reserve of the output asset.
92
+ * @param priceIn The pool's price for the input asset (from the constant-sum config).
93
+ * @param priceOut The pool's price for the output asset.
94
+ * @param fee The liquidity-provider fee (plus protocol fee) as a fraction.
95
+ * @returns The swap details in the shared {@link TSwapOutcome} shape.
96
+ */
97
+ var getSwapInput = exports.getSwapInput = function getSwapInput(inputMetadata, output, inputReserve, outputReserve, priceIn, priceOut, fee) {
98
+ if (output <= 0n || inputReserve <= 0n || outputReserve <= 0n) throw new Error("Output and reserves must be positive");
99
+ if (priceIn <= 0n || priceOut <= 0n) throw new Error("Prices must be positive");
100
+ if (output > outputReserve) throw new Error("Output must not exceed the output reserve");
101
+ var feeFraction = _fraction.Fraction.asFraction(fee);
102
+ if (feeFraction.lt(_fraction.Fraction.ZERO) || feeFraction.gte(_fraction.Fraction.ONE)) throw new Error("fee must be [0,1)");
103
+ var feeNum = BigInt(feeFraction.numerator);
104
+ var feeDen = BigInt(feeFraction.denominator);
105
+ var feeDiff = feeDen - feeNum;
106
+
107
+ // Forward: outputValue = ceil(input·priceIn·feeDiff/feeDen), and the swap
108
+ // yields ≥ output iff outputValue ≥ output·priceOut. ceil(x/d) ≥ T for
109
+ // integer x iff x ≥ d·(T−1)+1, so the minimal input is the ceiling of
110
+ // (feeDen·(output·priceOut − 1) + 1) / (feeDiff·priceIn).
111
+ var targetValue = output * priceOut;
112
+ var numerator = feeDen * (targetValue - 1n) + 1n;
113
+ var denominator = feeDiff * priceIn;
114
+ var input = (numerator + denominator - 1n) / denominator;
115
+ var inputLpFee = new _fraction.Fraction(input * feeNum, feeDen).quotient;
116
+ var nextInputReserve = inputReserve + input;
117
+ var nextOutputReserve = outputReserve - output;
118
+
119
+ // Same par-price impact definition as getSwapOutput.
120
+ var amountInLessFee = input - inputLpFee;
121
+ var idealPrice = new _fraction.Fraction(priceOut, priceIn);
122
+ var actualPrice = new _fraction.Fraction(amountInLessFee, output);
123
+ var priceImpact = _fraction.Fraction.ONE.subtract(idealPrice.divide(actualPrice));
124
+ return {
125
+ input: input,
126
+ output: output,
127
+ lpFee: new _asset.AssetAmount(inputLpFee, inputMetadata),
128
+ nextInputReserve: nextInputReserve,
129
+ nextOutputReserve: nextOutputReserve,
130
+ priceImpact: priceImpact
131
+ };
132
+ };
133
+
134
+ /**
135
+ * Calculate the deposit parameters for a 2-asset constant-sum pool via the
136
+ * TARGET-PINNED rule the deployed validator enforces (see
137
+ * {@link calculatePinnedDeposit}): the mint is capped by the scarcest offered
138
+ * asset, both assets must be offered, and anything above the pinned deltas is
139
+ * refunded via aChange/bChange.
140
+ *
141
+ * @param {bigint} a - The amount of token A to deposit.
142
+ * @param {bigint} b - The amount of token B to deposit.
143
+ * @param {bigint} aReserve - The current reserve of token A in the pool.
144
+ * @param {bigint} bReserve - The current reserve of token B in the pool.
145
+ * @param {bigint} totalLp - The total lp tokens for the pool before the deposit.
146
+ * @param {bigint} priceA - The pool's price for token A (from the constant-sum config).
147
+ * @param {bigint} priceB - The pool's price for token B.
148
+ * @throws {Error} If the pool has no value or minted lp.
149
+ * @throws {Error} If both deposit amounts are zero, or either is negative.
150
+ * @throws {Error} If either price is non-positive.
151
+ */
152
+ var calculateLiquidity = exports.calculateLiquidity = function calculateLiquidity(a, b, aReserve, bReserve, totalLp, priceA, priceB) {
153
+ // Target-pinned (what the deployed validator accepts): mint by the
154
+ // scarcest offered asset; anything above the pinned deltas is refunded
155
+ // (aChange/bChange).
156
+ var _calculatePinnedDepos = calculatePinnedDeposit([a, b], [aReserve, bReserve], [priceA, priceB], totalLp),
157
+ deltas = _calculatePinnedDepos.deltas,
158
+ generatedLp = _calculatePinnedDepos.generatedLp,
159
+ nextTotalLp = _calculatePinnedDepos.nextTotalLp,
160
+ shareAfterDeposit = _calculatePinnedDepos.shareAfterDeposit;
161
+ return {
162
+ nextTotalLp: nextTotalLp,
163
+ generatedLp: generatedLp,
164
+ shareAfterDeposit: shareAfterDeposit,
165
+ aChange: a - deltas[0],
166
+ bChange: b - deltas[1],
167
+ actualDepositedA: deltas[0],
168
+ actualDepositedB: deltas[1]
169
+ };
170
+ };
171
+
172
+ /**
173
+ * The N-asset form of {@link calculateLiquidity}, mirroring the v4 contract's
174
+ * `compute_deposit_n` exactly: a deposit of any mix of the pool's assets is
175
+ * valued at the fixed prices against the value of ALL reserves —
176
+ *
177
+ * generatedLp = Σ(amount_i·price_i) · totalLp / Σ(reserve_i·price_i)
178
+ *
179
+ * The three arrays must be aligned to the pool's canonical asset order (the
180
+ * API's `assets`/`quantities`/`prices`). Estimating an N-asset pool's deposit
181
+ * from just two of its reserves overstates the minted LP — the denominator is
182
+ * the whole pool's value — which is exactly the mistake this exists to
183
+ * prevent.
184
+ */
185
+ /**
186
+ * The target-pinned deposit — what the deployed CS validator (cs_check tag 6)
187
+ * actually accepts, and what the scooper builds. Asymmetric deposits are
188
+ * disallowed on-chain: the fill declares a value delta `t` and every asset's
189
+ * contribution is ceil-pinned to `ceil(r_i·t/V_b)`, with total LP
190
+ * floor-pinned to `floor(lp_b·(V_b+t)/V_b)`. Given what the user offers, the
191
+ * largest fillable t is capped by the SCARCEST asset —
192
+ * `t = min_i floor(offered_i·V_b/r_i)` — and anything above the pinned
193
+ * deltas is returned as surplus. Every pool asset must be offered (> 0) or
194
+ * t is zero and the deposit can never fill.
195
+ *
196
+ * Contrast with `calculateDepositN`, which is the plain value formula:
197
+ * it matches the pin only for exactly proportional offers and OVERSTATES the
198
+ * mint otherwise — using it for `minReceived` makes non-proportional orders
199
+ * unfillable.
200
+ */
201
+ var calculatePinnedDeposit = exports.calculatePinnedDeposit = function calculatePinnedDeposit(offered, reserves, prices, totalLp) {
202
+ if (offered.length !== reserves.length || reserves.length !== prices.length) throw new Error("offered, reserves and prices must be aligned");
203
+ if (prices.some(function (p) {
204
+ return p <= 0n;
205
+ })) throw new Error("Prices must be positive");
206
+ if (totalLp <= 0n) throw new Error("Not enough pool liquidity");
207
+ var vB = 0n;
208
+ for (var i = 0; i < reserves.length; i++) {
209
+ vB += reserves[i] * prices[i];
210
+ }
211
+ if (vB <= 0n) throw new Error("Pool value is zero");
212
+ var t;
213
+ for (var _i = 0; _i < offered.length; _i++) {
214
+ if (reserves[_i] === 0n) continue;
215
+ var cap = offered[_i] * vB / reserves[_i];
216
+ t = t === undefined || cap < t ? cap : t;
217
+ }
218
+ if (t === undefined || t <= 0n) {
219
+ throw new Error("A constant-sum deposit must offer every pool asset in proportion (asymmetric deposits are disallowed on-chain)");
220
+ }
221
+ var deltas = reserves.map(function (r) {
222
+ return (r * t + vB - 1n) / vB;
223
+ }); // ceil
224
+ var nextTotalLp = totalLp * (vB + t) / vB; // floor
225
+ var generatedLp = nextTotalLp - totalLp;
226
+ if (generatedLp <= 0n) throw new Error("Deposit mints zero LP");
227
+ return {
228
+ targetDeltaV: t,
229
+ deltas: deltas,
230
+ generatedLp: generatedLp,
231
+ nextTotalLp: nextTotalLp,
232
+ shareAfterDeposit: _index.SharedPoolMath.getShare(generatedLp, nextTotalLp)
233
+ };
234
+ };
235
+
236
+ /**
237
+ * The per-asset amounts a pinned deposit needs when the user anchors on one
238
+ * asset's amount: t from the anchor (`floor(anchor·V_b/r_anchor)`), every
239
+ * delta ceil-pinned to it. Drives proportional auto-fill in deposit forms.
240
+ */
241
+ var pinnedDepositFromAnchor = exports.pinnedDepositFromAnchor = function pinnedDepositFromAnchor(anchorIndex, anchorAmount, reserves, prices) {
242
+ if (reserves.length !== prices.length) throw new Error("reserves and prices must be aligned");
243
+ if (anchorIndex < 0 || anchorIndex >= reserves.length || reserves[anchorIndex] <= 0n) throw new Error("anchor asset has no reserve");
244
+ if (anchorAmount <= 0n) return reserves.map(function () {
245
+ return 0n;
246
+ });
247
+ var vB = 0n;
248
+ for (var i = 0; i < reserves.length; i++) {
249
+ vB += reserves[i] * prices[i];
250
+ }
251
+ if (vB <= 0n) throw new Error("Pool value is zero");
252
+ var t = anchorAmount * vB / reserves[anchorIndex];
253
+ return reserves.map(function (r, i) {
254
+ return i === anchorIndex ? anchorAmount : (r * t + vB - 1n) / vB;
255
+ });
256
+ };
257
+ var calculateDepositN = exports.calculateDepositN = function calculateDepositN(amounts, reserves, prices, totalLp) {
258
+ if (amounts.length !== reserves.length || reserves.length !== prices.length) throw new Error("amounts, reserves and prices must be aligned");
259
+ if (prices.some(function (p) {
260
+ return p <= 0n;
261
+ })) throw new Error("Prices must be positive");
262
+ // Zeros in a MIX are fine — offering a subset is the point of the N-asset
263
+ // form. What's rejected is a negative amount, or offering nothing at all.
264
+ if (amounts.some(function (a) {
265
+ return a < 0n;
266
+ }) || amounts.every(function (a) {
267
+ return a === 0n;
268
+ })) throw new Error("Deposit amounts must be non-negative, with at least one positive");
269
+ var totalValue = 0n;
270
+ var depositValue = 0n;
271
+ for (var i = 0; i < amounts.length; i++) {
272
+ totalValue += reserves[i] * prices[i];
273
+ depositValue += amounts[i] * prices[i];
274
+ }
275
+ if (totalValue <= 0n || totalLp <= 0n) throw new Error("Not enough pool liquidity");
276
+ var generatedLp = depositValue * totalLp / totalValue;
277
+ var nextTotalLp = totalLp + generatedLp;
278
+ return {
279
+ nextTotalLp: nextTotalLp,
280
+ generatedLp: generatedLp,
281
+ shareAfterDeposit: _index.SharedPoolMath.getShare(generatedLp, nextTotalLp)
282
+ };
283
+ };
284
+ //# sourceMappingURL=ConstantSumPool.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ConstantSumPool.js","names":["_asset","require","_fraction","_index","getSwapOutput","exports","inputMetadata","input","inputReserve","outputReserve","priceIn","priceOut","fee","roundOutputUp","Error","feeFraction","Fraction","asFraction","lt","ZERO","gt","ONE","inputValue","feeValue","BigInt","numerator","denominator","quotient","outputValue","output","inputLpFee","nextInputReserve","nextOutputReserve","priceImpact","amountInLessFee","idealPrice","actualPrice","subtract","divide","lpFee","AssetAmount","getSwapInput","gte","feeNum","feeDen","feeDiff","targetValue","calculateLiquidity","a","b","aReserve","bReserve","totalLp","priceA","priceB","_calculatePinnedDepos","calculatePinnedDeposit","deltas","generatedLp","nextTotalLp","shareAfterDeposit","aChange","bChange","actualDepositedA","actualDepositedB","offered","reserves","prices","length","some","p","vB","i","t","cap","undefined","map","r","targetDeltaV","SharedPoolMath","getShare","pinnedDepositFromAnchor","anchorIndex","anchorAmount","calculateDepositN","amounts","every","totalValue","depositValue"],"sources":["../../../src/PoolMath/ConstantSumPool.ts"],"sourcesContent":["import { AssetAmount, IAssetAmountMetadata } from \"@sundaeswap/asset\";\nimport { Fraction, type TFractionLike } from \"@sundaeswap/fraction\";\nimport { SharedPoolMath } from \"./index.js\";\n\n/**\n * Holds the calculated outcome of a constant-sum swap. Mirrors\n * {@link ConstantProductPool.TSwapOutcome} so both can flow through the same\n * generic swap-outcome consumers.\n */\nexport type TSwapOutcome = {\n input: bigint;\n output: bigint;\n lpFee: AssetAmount<IAssetAmountMetadata>;\n nextInputReserve: bigint;\n nextOutputReserve: bigint;\n priceImpact: Fraction;\n};\n\n/**\n * Calculate the swap outcome for a constant-sum (fixed-price) pool — the\n * invariant used by Sundae v4 stable/pegged pools. Unlike constant product,\n * the exchange rate is fixed by the pool's per-asset `prices`: the input is\n * converted to \"value\" at `priceIn`, the fee is taken off that value, and the\n * remainder is converted to the output asset at `priceOut`. The result is\n * capped at the output reserve (you can't take more than the pool holds).\n *\n * Matches the scooper's `cs_swap_result`:\n * output = floor((input·priceIn − floor(input·priceIn·fee)) / priceOut)\n *\n * @param inputMetadata Metadata for the supplied (input) asset — used for the fee AssetAmount.\n * @param input The amount of the input asset being swapped.\n * @param inputReserve The pool's reserve of the input asset.\n * @param outputReserve The pool's reserve of the output asset.\n * @param priceIn The pool's price for the input asset (from the constant-sum config).\n * @param priceOut The pool's price for the output asset.\n * @param fee The liquidity-provider fee (plus protocol fee) as a fraction.\n * @param roundOutputUp When true, round the output up instead of flooring.\n * @returns The swap details in the shared {@link TSwapOutcome} shape.\n */\nexport const getSwapOutput = (\n inputMetadata: IAssetAmountMetadata,\n input: bigint,\n inputReserve: bigint,\n outputReserve: bigint,\n priceIn: bigint,\n priceOut: bigint,\n fee: TFractionLike,\n roundOutputUp?: boolean,\n): TSwapOutcome => {\n if (input <= 0n || inputReserve <= 0n || outputReserve <= 0n)\n throw new Error(\"Input and reserves must be positive\");\n if (priceIn <= 0n || priceOut <= 0n)\n throw new Error(\"Prices must be positive\");\n\n const feeFraction = Fraction.asFraction(fee);\n if (feeFraction.lt(Fraction.ZERO) || feeFraction.gt(Fraction.ONE))\n throw new Error(\"fee must be between 0 and 1\");\n\n const inputValue = input * priceIn;\n const feeValue = new Fraction(\n inputValue * BigInt(feeFraction.numerator),\n BigInt(feeFraction.denominator),\n ).quotient;\n const outputValue = inputValue - feeValue;\n\n let output = roundOutputUp\n ? (outputValue + priceOut - 1n) / priceOut\n : outputValue / priceOut;\n\n // Can't take more than the pool holds.\n if (output > outputReserve) {\n output = outputReserve;\n }\n\n // LP fee expressed in input-asset units (value scales linearly with input,\n // so the input-denominated fee is input·feeRate) — matching ConstantProductPool.\n const inputLpFee = new Fraction(\n input * BigInt(feeFraction.numerator),\n BigInt(feeFraction.denominator),\n ).quotient;\n\n const nextInputReserve = inputReserve + input;\n const nextOutputReserve = outputReserve - output;\n\n // Price impact vs the pool's par price (priceOut/priceIn input-per-output);\n // ~0 for a constant-sum pool aside from the fee. See ConstantProductPool.\n let priceImpact = Fraction.ZERO;\n if (output > 0n) {\n const amountInLessFee = input - inputLpFee;\n const idealPrice = new Fraction(priceOut, priceIn);\n const actualPrice = new Fraction(amountInLessFee, output);\n priceImpact = Fraction.ONE.subtract(idealPrice.divide(actualPrice));\n }\n\n return {\n input,\n output,\n lpFee: new AssetAmount(inputLpFee, inputMetadata),\n nextInputReserve,\n nextOutputReserve,\n priceImpact,\n };\n};\n\n/**\n * Calculate the minimal input required to receive a given output from a\n * constant-sum pool — the exact inverse of {@link getSwapOutput}.\n *\n * The forward math floors the fee off the input value, which makes the\n * post-fee value `ceil(input·priceIn·(1−fee))`; inverting that ceiling gives\n * the smallest input whose forward swap yields at least `output`.\n *\n * Unlike constant product there is no asymptote, so an output equal to the\n * full output reserve is attainable (the pool can be drained at par).\n *\n * @param inputMetadata Metadata for the supplied (input) asset — used for the fee AssetAmount.\n * @param output The desired amount of the output asset.\n * @param inputReserve The pool's reserve of the input asset.\n * @param outputReserve The pool's reserve of the output asset.\n * @param priceIn The pool's price for the input asset (from the constant-sum config).\n * @param priceOut The pool's price for the output asset.\n * @param fee The liquidity-provider fee (plus protocol fee) as a fraction.\n * @returns The swap details in the shared {@link TSwapOutcome} shape.\n */\nexport const getSwapInput = (\n inputMetadata: IAssetAmountMetadata,\n output: bigint,\n inputReserve: bigint,\n outputReserve: bigint,\n priceIn: bigint,\n priceOut: bigint,\n fee: TFractionLike,\n): TSwapOutcome => {\n if (output <= 0n || inputReserve <= 0n || outputReserve <= 0n)\n throw new Error(\"Output and reserves must be positive\");\n if (priceIn <= 0n || priceOut <= 0n)\n throw new Error(\"Prices must be positive\");\n if (output > outputReserve)\n throw new Error(\"Output must not exceed the output reserve\");\n\n const feeFraction = Fraction.asFraction(fee);\n if (feeFraction.lt(Fraction.ZERO) || feeFraction.gte(Fraction.ONE))\n throw new Error(\"fee must be [0,1)\");\n\n const feeNum = BigInt(feeFraction.numerator);\n const feeDen = BigInt(feeFraction.denominator);\n const feeDiff = feeDen - feeNum;\n\n // Forward: outputValue = ceil(input·priceIn·feeDiff/feeDen), and the swap\n // yields ≥ output iff outputValue ≥ output·priceOut. ceil(x/d) ≥ T for\n // integer x iff x ≥ d·(T−1)+1, so the minimal input is the ceiling of\n // (feeDen·(output·priceOut − 1) + 1) / (feeDiff·priceIn).\n const targetValue = output * priceOut;\n const numerator = feeDen * (targetValue - 1n) + 1n;\n const denominator = feeDiff * priceIn;\n const input = (numerator + denominator - 1n) / denominator;\n\n const inputLpFee = new Fraction(input * feeNum, feeDen).quotient;\n const nextInputReserve = inputReserve + input;\n const nextOutputReserve = outputReserve - output;\n\n // Same par-price impact definition as getSwapOutput.\n const amountInLessFee = input - inputLpFee;\n const idealPrice = new Fraction(priceOut, priceIn);\n const actualPrice = new Fraction(amountInLessFee, output);\n const priceImpact = Fraction.ONE.subtract(idealPrice.divide(actualPrice));\n\n return {\n input,\n output,\n lpFee: new AssetAmount(inputLpFee, inputMetadata),\n nextInputReserve,\n nextOutputReserve,\n priceImpact,\n };\n};\n\n/**\n * Calculate the deposit parameters for a 2-asset constant-sum pool via the\n * TARGET-PINNED rule the deployed validator enforces (see\n * {@link calculatePinnedDeposit}): the mint is capped by the scarcest offered\n * asset, both assets must be offered, and anything above the pinned deltas is\n * refunded via aChange/bChange.\n *\n * @param {bigint} a - The amount of token A to deposit.\n * @param {bigint} b - The amount of token B to deposit.\n * @param {bigint} aReserve - The current reserve of token A in the pool.\n * @param {bigint} bReserve - The current reserve of token B in the pool.\n * @param {bigint} totalLp - The total lp tokens for the pool before the deposit.\n * @param {bigint} priceA - The pool's price for token A (from the constant-sum config).\n * @param {bigint} priceB - The pool's price for token B.\n * @throws {Error} If the pool has no value or minted lp.\n * @throws {Error} If both deposit amounts are zero, or either is negative.\n * @throws {Error} If either price is non-positive.\n */\nexport const calculateLiquidity = (\n a: bigint,\n b: bigint,\n aReserve: bigint,\n bReserve: bigint,\n totalLp: bigint,\n priceA: bigint,\n priceB: bigint,\n) => {\n // Target-pinned (what the deployed validator accepts): mint by the\n // scarcest offered asset; anything above the pinned deltas is refunded\n // (aChange/bChange).\n const { deltas, generatedLp, nextTotalLp, shareAfterDeposit } =\n calculatePinnedDeposit(\n [a, b],\n [aReserve, bReserve],\n [priceA, priceB],\n totalLp,\n );\n\n return {\n nextTotalLp,\n generatedLp,\n shareAfterDeposit,\n aChange: a - deltas[0],\n bChange: b - deltas[1],\n actualDepositedA: deltas[0],\n actualDepositedB: deltas[1],\n };\n};\n\n/**\n * The N-asset form of {@link calculateLiquidity}, mirroring the v4 contract's\n * `compute_deposit_n` exactly: a deposit of any mix of the pool's assets is\n * valued at the fixed prices against the value of ALL reserves —\n *\n * generatedLp = Σ(amount_i·price_i) · totalLp / Σ(reserve_i·price_i)\n *\n * The three arrays must be aligned to the pool's canonical asset order (the\n * API's `assets`/`quantities`/`prices`). Estimating an N-asset pool's deposit\n * from just two of its reserves overstates the minted LP — the denominator is\n * the whole pool's value — which is exactly the mistake this exists to\n * prevent.\n */\n/**\n * The target-pinned deposit — what the deployed CS validator (cs_check tag 6)\n * actually accepts, and what the scooper builds. Asymmetric deposits are\n * disallowed on-chain: the fill declares a value delta `t` and every asset's\n * contribution is ceil-pinned to `ceil(r_i·t/V_b)`, with total LP\n * floor-pinned to `floor(lp_b·(V_b+t)/V_b)`. Given what the user offers, the\n * largest fillable t is capped by the SCARCEST asset —\n * `t = min_i floor(offered_i·V_b/r_i)` — and anything above the pinned\n * deltas is returned as surplus. Every pool asset must be offered (> 0) or\n * t is zero and the deposit can never fill.\n *\n * Contrast with `calculateDepositN`, which is the plain value formula:\n * it matches the pin only for exactly proportional offers and OVERSTATES the\n * mint otherwise — using it for `minReceived` makes non-proportional orders\n * unfillable.\n */\nexport const calculatePinnedDeposit = (\n offered: bigint[],\n reserves: bigint[],\n prices: bigint[],\n totalLp: bigint,\n): {\n targetDeltaV: bigint;\n deltas: bigint[];\n generatedLp: bigint;\n nextTotalLp: bigint;\n shareAfterDeposit: Fraction;\n} => {\n if (offered.length !== reserves.length || reserves.length !== prices.length)\n throw new Error(\"offered, reserves and prices must be aligned\");\n if (prices.some((p) => p <= 0n)) throw new Error(\"Prices must be positive\");\n if (totalLp <= 0n) throw new Error(\"Not enough pool liquidity\");\n\n let vB = 0n;\n for (let i = 0; i < reserves.length; i++) {\n vB += reserves[i] * prices[i];\n }\n if (vB <= 0n) throw new Error(\"Pool value is zero\");\n\n let t: bigint | undefined;\n for (let i = 0; i < offered.length; i++) {\n if (reserves[i] === 0n) continue;\n const cap = (offered[i] * vB) / reserves[i];\n t = t === undefined || cap < t ? cap : t;\n }\n if (t === undefined || t <= 0n) {\n throw new Error(\n \"A constant-sum deposit must offer every pool asset in proportion (asymmetric deposits are disallowed on-chain)\",\n );\n }\n\n const deltas = reserves.map((r) => (r * t! + vB - 1n) / vB); // ceil\n const nextTotalLp = (totalLp * (vB + t)) / vB; // floor\n const generatedLp = nextTotalLp - totalLp;\n if (generatedLp <= 0n) throw new Error(\"Deposit mints zero LP\");\n\n return {\n targetDeltaV: t,\n deltas,\n generatedLp,\n nextTotalLp,\n shareAfterDeposit: SharedPoolMath.getShare(generatedLp, nextTotalLp),\n };\n};\n\n/**\n * The per-asset amounts a pinned deposit needs when the user anchors on one\n * asset's amount: t from the anchor (`floor(anchor·V_b/r_anchor)`), every\n * delta ceil-pinned to it. Drives proportional auto-fill in deposit forms.\n */\nexport const pinnedDepositFromAnchor = (\n anchorIndex: number,\n anchorAmount: bigint,\n reserves: bigint[],\n prices: bigint[],\n): bigint[] => {\n if (reserves.length !== prices.length)\n throw new Error(\"reserves and prices must be aligned\");\n if (\n anchorIndex < 0 ||\n anchorIndex >= reserves.length ||\n reserves[anchorIndex] <= 0n\n )\n throw new Error(\"anchor asset has no reserve\");\n if (anchorAmount <= 0n) return reserves.map(() => 0n);\n\n let vB = 0n;\n for (let i = 0; i < reserves.length; i++) {\n vB += reserves[i] * prices[i];\n }\n if (vB <= 0n) throw new Error(\"Pool value is zero\");\n\n const t = (anchorAmount * vB) / reserves[anchorIndex];\n return reserves.map((r, i) =>\n i === anchorIndex ? anchorAmount : (r * t + vB - 1n) / vB,\n );\n};\n\nexport const calculateDepositN = (\n amounts: bigint[],\n reserves: bigint[],\n prices: bigint[],\n totalLp: bigint,\n) => {\n if (amounts.length !== reserves.length || reserves.length !== prices.length)\n throw new Error(\"amounts, reserves and prices must be aligned\");\n if (prices.some((p) => p <= 0n)) throw new Error(\"Prices must be positive\");\n // Zeros in a MIX are fine — offering a subset is the point of the N-asset\n // form. What's rejected is a negative amount, or offering nothing at all.\n if (amounts.some((a) => a < 0n) || amounts.every((a) => a === 0n))\n throw new Error(\n \"Deposit amounts must be non-negative, with at least one positive\",\n );\n\n let totalValue = 0n;\n let depositValue = 0n;\n for (let i = 0; i < amounts.length; i++) {\n totalValue += reserves[i] * prices[i];\n depositValue += amounts[i] * prices[i];\n }\n if (totalValue <= 0n || totalLp <= 0n)\n throw new Error(\"Not enough pool liquidity\");\n\n const generatedLp = (depositValue * totalLp) / totalValue;\n const nextTotalLp = totalLp + generatedLp;\n\n return {\n nextTotalLp,\n generatedLp,\n shareAfterDeposit: SharedPoolMath.getShare(generatedLp, nextTotalLp),\n };\n};\n"],"mappings":"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","ignoreList":[]}