@sundaeswap/math 0.5.0 → 0.6.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.
@@ -1,214 +1,709 @@
1
1
  "use strict";
2
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
3
  Object.defineProperty(exports, "__esModule", {
5
4
  value: true
6
5
  });
7
- exports.getSwapOutput = exports.getSwapInput = exports.calculateLiquidity = void 0;
6
+ exports.upperEdge = exports.uniformLadder = exports.swapSteps = exports.shapedLadder = exports.reservesAt = exports.prefixes = exports.nextBand = exports.minCreateCounter = exports.maxDxInBand = exports.liquidityOf = exports.indexLadder = exports.getSwapOutput = exports.findWitnessInBand = exports.findWitness = exports.feeFor = exports.delta = exports.coeffB = exports.coeffA = exports.buildIndex = exports.bandWeights = exports.bandView = exports.bandStates = exports.bandProof = exports.bandOutput = exports.bandOf = exports.bandFee = exports.bandCapacity = exports.bSat = exports.aSat = exports.MIN_COUNTER_PER_WEIGHT = exports.FIXED_ONE = void 0;
8
7
  var _asset = require("@sundaeswap/asset");
9
8
  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."); }
9
+ 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); }
10
+ function _createForOfIteratorHelper(r, e) { var t = "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (!t) { if (Array.isArray(r) || (t = _unsupportedIterableToArray(r)) || e && r && "number" == typeof r.length) { t && (r = t); var _n = 0, F = function F() {}; return { s: F, n: function n() { return _n >= r.length ? { done: !0 } : { done: !1, value: r[_n++] }; }, e: function e(r) { throw r; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var o, a = !0, u = !1; return { s: function s() { t = t.call(r); }, n: function n() { var r = t.next(); return a = r.done, r; }, e: function e(r) { u = !0, o = r; }, f: function f() { try { a || null == t["return"] || t["return"](); } finally { if (u) throw o; } } }; }
14
11
  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
12
  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; }
13
+ function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
14
+ function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
15
+ function _defineProperty(e, r, t) { return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, { value: t, enumerable: !0, configurable: !0, writable: !0 }) : e[r] = t, e; }
16
+ function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == _typeof(i) ? i : i + ""; }
17
+ function _toPrimitive(t, r) { if ("object" != _typeof(t) || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != _typeof(i)) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }
18
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.
19
+ * Holds the calculated outcome of a concentrated-liquidity swap. It has the
20
+ * same shape as `ConstantProductPool.TSwapOutcome`, so the generic
21
+ * swap-outcome consumers accept it.
22
22
  */
23
23
 
24
- /** A sqrt-price bound from the CL config, as an exact rational `[num, den]`. */
25
-
26
24
  /**
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:
25
+ * Concentrated liquidity: Sundae v4's ladder invariant.
26
+ *
27
+ * A pool is a ladder of bands in ascending sqrt-price order. Each band is a
28
+ * concentrated-liquidity arc (`curve` 0) or a constant-sum bin (`curve` 1)
29
+ * with its own share of the pool's liquidity (`weight / weightTotal`) and
30
+ * its own two fees. LP is one fungible token for the whole ladder; a
31
+ * deposit or withdrawal scales every band.
32
32
  *
33
- * VA = a·spbNum + L·spbDen
34
- * VB = b·spaDen + L·spaNum
33
+ * The chain never stores the price. It stores reserves, and the state is a
34
+ * WITNESS `(X, k)`: the ladder counter `X` (the pool's `total_lp`, spec V12)
35
+ * and the active band `k`, which the reserves must prove. Everything here
36
+ * mirrors `lib/modules/cl_check.ak` and the scooper's ladder
37
+ * math, rounding included; where they disagree the chain wins
38
+ * and the transaction fails. The rounding is not negotiable:
35
39
  *
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
+ * - `L_k` floors; saturation ceils, in ONE division;
41
+ * - the band fee ceils, per step, on the step's real input;
42
+ * - the prefix sums come from the LADDER INDEX (cumulative coefficients
43
+ * in fixed point at 2^64, spec §2.3), multiplied by the counter and
44
+ * ceiled ONCE. A per-band sum of ceilings is a different number and the
45
+ * chain rejects it.
46
+ */
47
+
48
+ /** An exact rational `num / den`. */
49
+
50
+ /** One band of the ladder. */
51
+
52
+ /** A ladder: bands, the top edge, and the sum of the weights. */
53
+
54
+ /** The witness the chain checks: the ladder counter and the active band. */
55
+
56
+ /** 2^64, the fixed-point scale of the ladder index. */
57
+ var FIXED_ONE = exports.FIXED_ONE = 1n << 64n;
58
+
59
+ /**
60
+ * The least counter per unit of weight a ladder may be created with.
61
+ * Mirrors `cl_check.min_counter_per_weight` (sundae-v4 #229, SV4-007):
62
+ * Create requires `total_lp >= MIN_COUNTER_PER_WEIGHT * weightTotal`.
63
+ */
64
+ var MIN_COUNTER_PER_WEIGHT = exports.MIN_COUNTER_PER_WEIGHT = 1000n;
65
+
66
+ /** The least counter (initial `total_lp`) the chain accepts at Create for `ladder`. */
67
+ var minCreateCounter = exports.minCreateCounter = function minCreateCounter(ladder) {
68
+ return MIN_COUNTER_PER_WEIGHT * ladder.weightTotal;
69
+ };
70
+ var ceilDiv = function ceilDiv(n, d) {
71
+ return (n + d - 1n) / d;
72
+ };
73
+
74
+ /** Band i's upper sqrt-price edge. */
75
+ var upperEdge = exports.upperEdge = function upperEdge(l, i) {
76
+ return i + 1 < l.bands.length ? l.bands[i + 1].start : l.closing;
77
+ };
78
+
79
+ /** `D_i = hi.num·lo.den − lo.num·hi.den`: positive exactly when the edges increase. */
80
+ var delta = exports.delta = function delta(lo, hi) {
81
+ return hi.num * lo.den - lo.num * hi.den;
82
+ };
83
+
84
+ /** `a_sat_i = ceil(w_i·X·D_i / (W·lo.num·hi.num))`: the A a band above the price holds. */
85
+ var aSat = exports.aSat = function aSat(l, x, i) {
86
+ var lo = l.bands[i].start;
87
+ var hi = upperEdge(l, i);
88
+ return ceilDiv(l.bands[i].weight * x * delta(lo, hi), l.weightTotal * lo.num * hi.num);
89
+ };
90
+
91
+ /** `b_sat_i = ceil(w_i·X·D_i / (W·lo.den·hi.den))`: the B a band below the price holds. */
92
+ var bSat = exports.bSat = function bSat(l, x, i) {
93
+ var lo = l.bands[i].start;
94
+ var hi = upperEdge(l, i);
95
+ return ceilDiv(l.bands[i].weight * x * delta(lo, hi), l.weightTotal * lo.den * hi.den);
96
+ };
97
+
98
+ /** `L_k = floor(w_k·X / W)`. */
99
+ var liquidityOf = exports.liquidityOf = function liquidityOf(l, x, k) {
100
+ return l.bands[k].weight * x / l.weightTotal;
101
+ };
102
+
103
+ /** Band i's A-side saturation coefficient: the part of `a_sat_i` independent of X, rounded up. */
104
+ var coeffA = exports.coeffA = function coeffA(l, i) {
105
+ var lo = l.bands[i].start;
106
+ var hi = upperEdge(l, i);
107
+ return ceilDiv(l.bands[i].weight * delta(lo, hi) * FIXED_ONE, l.weightTotal * lo.num * hi.num);
108
+ };
109
+
110
+ /** The same on the B side. */
111
+ var coeffB = exports.coeffB = function coeffB(l, i) {
112
+ var lo = l.bands[i].start;
113
+ var hi = upperEdge(l, i);
114
+ return ceilDiv(l.bands[i].weight * delta(lo, hi) * FIXED_ONE, l.weightTotal * lo.den * hi.den);
115
+ };
116
+
117
+ /** One index entry: the cumulative coefficients above and below band k. */
118
+
119
+ /**
120
+ * The ladder index `Create` pins and every spend reads: entry k is the pair
121
+ * of cumulative coefficients for the bands strictly above and strictly
122
+ * below band k. `cl_check.build_index`, to the digit.
40
123
  */
124
+ var buildIndex = exports.buildIndex = function buildIndex(l) {
125
+ var n = l.bands.length;
126
+ var a = Array.from({
127
+ length: n
128
+ }, function (_, i) {
129
+ return coeffA(l, i);
130
+ });
131
+ var b = Array.from({
132
+ length: n
133
+ }, function (_, i) {
134
+ return coeffB(l, i);
135
+ });
136
+ var out = [];
137
+ for (var k = 0; k < n; k++) {
138
+ var ca = 0n;
139
+ var cb = 0n;
140
+ for (var i = 0; i < n; i++) {
141
+ if (i > k) ca += a[i];
142
+ if (i < k) cb += b[i];
143
+ }
144
+ out.push({
145
+ ca: ca,
146
+ cb: cb
147
+ });
148
+ }
149
+ return out;
150
+ };
151
+
152
+ /**
153
+ * A ladder with its index built once. Every probe of the witness search
154
+ * reads the index for every band, and rebuilding it per probe is most of
155
+ * the cost of a quote.
156
+ */
157
+
158
+ var indexLadder = exports.indexLadder = function indexLadder(l) {
159
+ return "index" in l && Array.isArray(l.index) ? l : _objectSpread(_objectSpread({}, l), {}, {
160
+ index: buildIndex(l)
161
+ });
162
+ };
163
+
164
+ /** `C_A`, `C_B` at (X, k) from the index: one ceiling after the multiply by X. */
165
+ var prefixes = exports.prefixes = function prefixes(l, x, k) {
166
+ var e = l.index[k];
167
+ return {
168
+ ca: ceilDiv(e.ca * x, FIXED_ONE),
169
+ cb: ceilDiv(e.cb * x, FIXED_ONE)
170
+ };
171
+ };
41
172
 
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)];
173
+ /** `cl_check.f_at_raw`: the CL arc, cross-multiplied. */
174
+ var fAt = function fAt(a, b, L, lo, hi) {
175
+ return (a * hi.num + L * hi.den) * (b * lo.den + L * lo.num) - L * L * hi.num * lo.den;
46
176
  };
47
177
 
178
+ /** G at a witness, on whichever curve the active band carries. */
179
+ var gAt = function gAt(l, A, B, x, k) {
180
+ var _prefixes = prefixes(l, x, k),
181
+ ca = _prefixes.ca,
182
+ cb = _prefixes.cb;
183
+ var lo = l.bands[k].start;
184
+ var hi = upperEdge(l, k);
185
+ var ra = A - ca;
186
+ var rb = B - cb;
187
+ var L = liquidityOf(l, x, k);
188
+ return l.bands[k].curve === 0 ? fAt(ra, rb, L, lo, hi) : ra * (lo.num * hi.num) + rb * (lo.den * hi.den) - L * delta(lo, hi);
189
+ };
190
+
191
+ /** The band proof, P1 through P7. The chain runs exactly this. */
192
+ var bandProof = exports.bandProof = function bandProof(l, A, B, x, k) {
193
+ if (x < l.weightTotal) return false; // P1
194
+ var _prefixes2 = prefixes(l, x, k),
195
+ ca = _prefixes2.ca,
196
+ cb = _prefixes2.cb;
197
+ var ra = A - ca;
198
+ var rb = B - cb;
199
+ if (ra < 0n || rb < 0n) return false; // P2, P3
200
+ if (ra > aSat(l, x, k) || rb > bSat(l, x, k)) return false; // P4, P5
201
+ if (gAt(l, A, B, x, k) < 0n) return false; // P6
202
+ return gAt(l, A, B, x + 1n, k) < 0n; // P7
203
+ };
204
+ var SCAN = 400n;
205
+ var CAP = 1n << 80n;
206
+
48
207
  /**
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.
208
+ * The witness in band k, seeded at `hint` when given: the counter only
209
+ * grows along a swap, so the doubling search starts from the previous
210
+ * witness. `lo` is the largest x with non-negative residuals and G ≥ 0,
211
+ * and a witness is such an x whose successor fails G, so the scan walks
212
+ * DOWN from `lo` first. Mirrors the scooper's `find_witness_in_band_from`.
52
213
  */
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;
214
+ var findWitnessInBand = exports.findWitnessInBand = function findWitnessInBand(l, A, B, k, hint) {
215
+ var ok = function ok(x) {
216
+ var _prefixes3 = prefixes(l, x, k),
217
+ ca = _prefixes3.ca,
218
+ cb = _prefixes3.cb;
219
+ return A - ca >= 0n && B - cb >= 0n && gAt(l, A, B, x, k) >= 0n;
220
+ };
221
+ var search = function search(start) {
222
+ var lo = start;
223
+ var span = 1n;
224
+ var hi = lo + span;
225
+ while (ok(hi) && hi < CAP) {
226
+ lo = hi;
227
+ span *= 2n;
228
+ hi = lo + span;
229
+ }
230
+ while (lo + 1n < hi) {
231
+ var m = (lo + hi) / 2n;
232
+ if (ok(m)) lo = m;else hi = m;
233
+ }
234
+ var from = lo > SCAN ? lo - SCAN : 1n;
235
+ for (var x = lo; x >= from; x--) {
236
+ if (bandProof(l, A, B, x, k)) return {
237
+ x: x,
238
+ k: k
239
+ };
240
+ }
241
+ for (var _x = lo + 1n; _x <= lo + SCAN; _x++) {
242
+ if (bandProof(l, A, B, _x, k)) return {
243
+ x: _x,
244
+ k: k
245
+ };
246
+ }
247
+ return null;
248
+ };
249
+ if (hint !== undefined && hint > 0n && ok(hint)) {
250
+ var w = search(hint);
251
+ if (w) return w;
63
252
  }
64
- var dvbEff = dxEff * spaNum;
65
- var denom = (vb0 + dvbEff) * spbNum;
66
- if (denom <= 0n) return 0n;
67
- return va0 * dvbEff / denom;
253
+ if (!ok(1n)) return null;
254
+ return search(1n);
68
255
  };
69
256
 
70
257
  /**
71
- * Calculate the swap outcome for a concentrated-liquidity pool.
258
+ * The witness `(X, k)` for a pool's reserves. A hint (the indexed
259
+ * `bandCounter` / `activeBand`) is checked first and seeds the search in
260
+ * its band; a stale hint falls back to every band. Null when the reserves
261
+ * sit on no point of the ladder — the chain would reject them too.
262
+ */
263
+ var findWitness = exports.findWitness = function findWitness(ladder, A, B, hint) {
264
+ var l = indexLadder(ladder);
265
+ if (hint && hint.k >= 0 && hint.k < l.bands.length) {
266
+ if (bandProof(l, A, B, hint.x, hint.k)) return hint;
267
+ var w = findWitnessInBand(l, A, B, hint.k, hint.x);
268
+ if (w) return w;
269
+ }
270
+ for (var k = 0; k < l.bands.length; k++) {
271
+ var _w = findWitnessInBand(l, A, B, k);
272
+ if (_w) return _w;
273
+ }
274
+ return null;
275
+ };
276
+
277
+ /** The active band's view at a witness: its residual reserves and liquidity. */
278
+
279
+ var bandView = exports.bandView = function bandView(l, A, B, w) {
280
+ var _prefixes4 = prefixes(l, w.x, w.k),
281
+ ca = _prefixes4.ca,
282
+ cb = _prefixes4.cb;
283
+ var band = l.bands[w.k];
284
+ return {
285
+ ra: A - ca,
286
+ rb: B - cb,
287
+ l: liquidityOf(l, w.x, w.k),
288
+ lo: band.start,
289
+ hi: upperEdge(l, w.k),
290
+ curve: band.curve,
291
+ feeBuy: band.feeBuy,
292
+ feeSell: band.feeSell
293
+ };
294
+ };
295
+
296
+ /** The band's fee for a direction: `feeSell` when A is sold, `feeBuy` when A is bought. */
297
+ var feeFor = exports.feeFor = function feeFor(v, isAInput) {
298
+ return isAInput ? v.feeSell : v.feeBuy;
299
+ };
300
+
301
+ /**
302
+ * The band fee on a step's real input `dx`: `ceil(dx * num / den)`.
303
+ * Mirrors `cl_check.band_fee` (sundae-v4 #228, SV4-006). The chain charges
304
+ * it per transcript step and rounds it UP, so a step below `den / num`
305
+ * units still pays one unit. A zero rate charges nothing.
306
+ */
307
+ var bandFee = exports.bandFee = function bandFee(dx, fee) {
308
+ return (dx * fee.num + fee.den - 1n) / fee.den;
309
+ };
310
+
311
+ /** The output one band pays for `dx` within itself. Mirrors the scooper's `band_output`. */
312
+ var bandOutput = exports.bandOutput = function bandOutput(v, isAInput, dx) {
313
+ var fee = feeFor(v, isAInput);
314
+ if (fee.den <= 0n) return 0n;
315
+ var dxEff = dx - bandFee(dx, fee);
316
+ if (dxEff <= 0n) return 0n;
317
+ if (v.curve === 0) {
318
+ var va0 = v.ra * v.hi.num + v.l * v.hi.den;
319
+ var vb0 = v.rb * v.lo.den + v.l * v.lo.num;
320
+ if (isAInput) {
321
+ var dva = dxEff * v.hi.num;
322
+ var _den = (va0 + dva) * v.lo.den;
323
+ return _den === 0n ? 0n : vb0 * dva / _den;
324
+ }
325
+ var dvb = dxEff * v.lo.den;
326
+ var den = (vb0 + dvb) * v.hi.num;
327
+ return den === 0n ? 0n : va0 * dvb / den;
328
+ }
329
+ var pn = v.lo.num * v.hi.num;
330
+ var pd = v.lo.den * v.hi.den;
331
+ return isAInput ? dxEff * pn / pd : dxEff * pd / pn;
332
+ };
333
+
334
+ /** What the band can pay out in a direction: its residual of the output asset. */
335
+ var bandCapacity = exports.bandCapacity = function bandCapacity(v, isAInput) {
336
+ return isAInput ? v.rb : v.ra;
337
+ };
338
+
339
+ /** The largest input whose output stays within the band. */
340
+ var maxDxInBand = exports.maxDxInBand = function maxDxInBand(v, isAInput) {
341
+ var cap = bandCapacity(v, isAInput);
342
+ if (cap <= 0n) return 0n;
343
+ var fits = function fits(dx) {
344
+ return bandOutput(v, isAInput, dx) <= cap;
345
+ };
346
+ var hi = 1n;
347
+ for (var guard = 0; fits(hi); guard++) {
348
+ hi *= 2n;
349
+ if (guard > 200) return hi;
350
+ }
351
+ var lo = 0n;
352
+ while (lo + 1n < hi) {
353
+ var m = (lo + hi) / 2n;
354
+ if (fits(m)) lo = m;else hi = m;
355
+ }
356
+ return lo;
357
+ };
358
+
359
+ /** The next band a fill enters: selling A walks down the ladder, buying A walks up. */
360
+ var nextBand = exports.nextBand = function nextBand(k, isAInput, n) {
361
+ return isAInput ? k === 0 ? null : k - 1 : k + 1 >= n ? null : k + 1;
362
+ };
363
+
364
+ /** One band of a fill: what it paid, and the state it left. */
365
+
366
+ /**
367
+ * Price `dx` across as many bands as it takes, as the scooper's
368
+ * `swap_steps` does: fill the active band, cross to the next, repeat.
369
+ * Returns the steps, or null when the ladder cannot absorb `dx` (the
370
+ * direction is exhausted, or the remainder pays nothing).
371
+ */
372
+ var swapSteps = exports.swapSteps = function swapSteps(ladder, A, B, isAInput, dx, hint) {
373
+ var l = indexLadder(ladder);
374
+ var n = l.bands.length;
375
+ var ca = A;
376
+ var cb = B;
377
+ var remaining = dx;
378
+ var steps = [];
379
+ var known = findWitness(l, A, B, hint);
380
+ if (!known) return null;
381
+ var prefer = null;
382
+ var hintX;
383
+ for (var guard = 0; remaining > 0n; guard++) {
384
+ if (guard > 2 * n + 2) return null;
385
+ var before = known;
386
+ known = null;
387
+ if (!before) {
388
+ if (prefer !== null) before = findWitnessInBand(l, ca, cb, prefer, hintX);
389
+ if (!before) before = findWitness(l, ca, cb);
390
+ if (!before) return null;
391
+ }
392
+ var view = bandView(l, ca, cb, before);
393
+ var capDx = maxDxInBand(view, isAInput);
394
+ var stepDx = capDx < remaining ? capDx : remaining;
395
+ var dy = stepDx > 0n ? bandOutput(view, isAInput, stepDx) : 0n;
396
+ if (dy <= 0n) {
397
+ var kNext = nextBand(before.k, isAInput, n);
398
+ if (kNext === null || prefer === kNext) return null;
399
+ prefer = kNext;
400
+ continue;
401
+ }
402
+ var na = isAInput ? ca + stepDx : ca - dy;
403
+ var nb = isAInput ? cb - dy : cb + stepDx;
404
+ var crossing = stepDx < remaining;
405
+ var after = null;
406
+ if (crossing) {
407
+ var _kNext = nextBand(before.k, isAInput, n);
408
+ if (_kNext !== null) after = findWitnessInBand(l, na, nb, _kNext, before.x);
409
+ } else {
410
+ after = findWitnessInBand(l, na, nb, before.k, before.x);
411
+ }
412
+ if (!after) after = findWitness(l, na, nb);
413
+ if (!after || after.x < before.x) return null;
414
+ steps.push({
415
+ band: before.k,
416
+ input: stepDx,
417
+ output: dy,
418
+ after: after
419
+ });
420
+ remaining -= stepDx;
421
+ ca = na;
422
+ cb = nb;
423
+ prefer = after.k;
424
+ hintX = after.x;
425
+ known = after;
426
+ }
427
+ return steps;
428
+ };
429
+
430
+ /**
431
+ * The swap output of a concentrated-liquidity pool for `input` of one asset, crossing
432
+ * bands as needed. `aReserve`/`bReserve` are the pool's reserves in
433
+ * canonical order; `hint` is the indexed `bandCounter` / `activeBand`,
434
+ * which seeds the witness search and may be stale.
72
435
  *
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.
436
+ * The `lpFee` is the fee the bands kept of the input, summed across the
437
+ * steps. `priceImpact` is against the active band's opening marginal
438
+ * price. Throws when the ladder cannot absorb the input.
83
439
  */
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];
440
+ var getSwapOutput = exports.getSwapOutput = function getSwapOutput(inputMetadata, input, aReserve, bReserve, ladder, isAInput, hint) {
441
+ if (input <= 0n || aReserve < 0n || bReserve < 0n) throw new Error("Input must be positive and reserves non-negative");
442
+ if (ladder.bands.length === 0 || ladder.weightTotal <= 0n) throw new Error("The ladder has no bands");
443
+ var l = indexLadder(ladder);
444
+ var steps = swapSteps(l, aReserve, bReserve, isAInput, input, hint);
445
+ if (!steps || steps.length === 0) throw new Error("The ladder cannot absorb this input in this direction");
446
+ var output = 0n;
447
+ var lpFee = 0n;
448
+ var _iterator = _createForOfIteratorHelper(steps),
449
+ _step;
450
+ try {
451
+ for (_iterator.s(); !(_step = _iterator.n()).done;) {
452
+ var s = _step.value;
453
+ output += s.output;
454
+ var band = l.bands[s.band];
455
+ var fee = isAInput ? band.feeSell : band.feeBuy;
456
+ lpFee += bandFee(s.input, fee);
457
+ }
458
+ } catch (err) {
459
+ _iterator.e(err);
460
+ } finally {
461
+ _iterator.f();
462
+ }
97
463
  var inputReserve = isAInput ? aReserve : bReserve;
98
464
  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
465
  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;
466
+ // Price impact against the opening marginal of the first band traded.
467
+ var w0 = findWitness(l, aReserve, bReserve, hint);
468
+ var v0 = bandView(l, aReserve, bReserve, w0);
112
469
  var priceImpact = _fraction.Fraction.ZERO;
113
470
  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));
471
+ var ideal;
472
+ if (v0.curve === 1) {
473
+ var pn = v0.lo.num * v0.hi.num;
474
+ var pd = v0.lo.den * v0.hi.den;
475
+ ideal = isAInput ? new _fraction.Fraction(pd, pn) : new _fraction.Fraction(pn, pd);
476
+ } else {
477
+ var va0 = v0.ra * v0.hi.num + v0.l * v0.hi.den;
478
+ var vb0 = v0.rb * v0.lo.den + v0.l * v0.lo.num;
479
+ ideal = isAInput ? new _fraction.Fraction(va0 * v0.lo.den, vb0 * v0.hi.num) : new _fraction.Fraction(vb0 * v0.hi.num, va0 * v0.lo.den);
480
+ }
481
+ var actual = new _fraction.Fraction(input - lpFee, output);
482
+ priceImpact = _fraction.Fraction.ONE.subtract(ideal.divide(actual));
117
483
  }
118
484
  return {
119
485
  input: input,
120
486
  output: output,
121
- lpFee: new _asset.AssetAmount(inputLpFee, inputMetadata),
122
- nextInputReserve: nextInputReserve,
123
- nextOutputReserve: nextOutputReserve,
124
- priceImpact: priceImpact
487
+ lpFee: new _asset.AssetAmount(lpFee, inputMetadata),
488
+ nextInputReserve: inputReserve + input,
489
+ nextOutputReserve: outputReserve - output,
490
+ priceImpact: priceImpact,
491
+ steps: steps
125
492
  };
126
493
  };
127
494
 
495
+ /** What each band holds at the pool's reserves. */
496
+
128
497
  /**
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`.
498
+ * Every band's state at the pool's reserves: a band below the price holds
499
+ * only B, a band above it only A, the active band some of both. Null when
500
+ * the reserves sit on no point of the ladder.
134
501
  */
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
- };
502
+ var bandStates = exports.bandStates = function bandStates(ladder, aReserve, bReserve, hint) {
503
+ var l = indexLadder(ladder);
504
+ var w = findWitness(l, aReserve, bReserve, hint);
505
+ if (!w) return null;
506
+ var out = [];
507
+ var restA = 0n;
508
+ var restB = 0n;
509
+ for (var i = 0; i < l.bands.length; i++) {
510
+ var liquidity = liquidityOf(l, w.x, i);
511
+ if (i < w.k) {
512
+ var b = bSat(l, w.x, i);
513
+ restB += b;
514
+ out.push({
515
+ quantities: [0n, b],
516
+ liquidity: liquidity,
517
+ active: false
518
+ });
519
+ } else if (i > w.k) {
520
+ var a = aSat(l, w.x, i);
521
+ restA += a;
522
+ out.push({
523
+ quantities: [a, 0n],
524
+ liquidity: liquidity,
525
+ active: false
526
+ });
527
+ } else {
528
+ out.push({
529
+ quantities: [0n, 0n],
530
+ liquidity: liquidity,
531
+ active: true
532
+ });
533
+ }
534
+ }
535
+ var ra = aReserve - restA;
536
+ var rb = bReserve - restB;
537
+ out[w.k].quantities = [ra < 0n ? 0n : ra, rb < 0n ? 0n : rb];
538
+ return out;
539
+ };
156
540
 
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);
541
+ /** Which band holds a sqrt-price. */
542
+ var bandOf = exports.bandOf = function bandOf(l, s) {
543
+ for (var i = 0; i < l.bands.length; i++) {
544
+ var hi = upperEdge(l, i);
545
+ if (s.num * hi.den < hi.num * s.den) return i;
170
546
  }
171
- var input = feeDiff > 0n ? ceilDiv(effMin * feeDen, feeDiff) : effMin;
547
+ return l.bands.length - 1;
548
+ };
172
549
 
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);
550
+ /**
551
+ * The exact reserves a ladder holds at counter `x` with the price at
552
+ * sqrt-price `s`, which must lie in band `k`: what a pool creator deposits
553
+ * for a chosen shape, scale and launch price. The result is floored, so
554
+ * `findWitness` must still be run on it to learn the counter the chain
555
+ * derives — usually `x`, but rounding can move it.
556
+ */
557
+ var reservesAt = exports.reservesAt = function reservesAt(l, x, k, s) {
558
+ var A = 0n;
559
+ var B = 0n;
560
+ for (var i = 0; i < l.bands.length; i++) {
561
+ if (i > k) {
562
+ A += aSat(l, x, i);
563
+ continue;
564
+ }
565
+ if (i < k) {
566
+ B += bSat(l, x, i);
567
+ continue;
568
+ }
569
+ var lo = l.bands[i].start;
570
+ var hi = upperEdge(l, i);
571
+ var L = liquidityOf(l, x, i);
572
+ if (l.bands[i].curve === 1) {
573
+ // A constant-sum bin prices at the geometric mean; `s` only says how
574
+ // far through the bin the conversion has gone.
575
+ var K = L * delta(lo, hi);
576
+ var frac = (s.num * lo.den - lo.num * s.den) * hi.den;
577
+ var span = (hi.num * lo.den - lo.num * hi.den) * s.den;
578
+ var rb = K * frac / (span * (lo.den * hi.den));
579
+ A += (K - rb * (lo.den * hi.den)) / (lo.num * hi.num);
580
+ B += rb;
581
+ } else {
582
+ // a = L·(1/s − 1/hi), b = L·(s − lo), in exact rationals.
583
+ A += L * (s.den * hi.num - s.num * hi.den) / (s.num * hi.num);
584
+ B += L * (s.num * lo.den - lo.num * s.den) / (s.den * lo.den);
585
+ }
586
+ }
587
+ return {
588
+ A: A,
589
+ B: B
177
590
  };
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));
591
+ };
592
+
593
+ /** A fraction in lowest terms. */
594
+ var reduceFrac = function reduceFrac(f) {
595
+ var _gcd = function gcd(a, b) {
596
+ return b === 0n ? a : _gcd(b, a % b);
597
+ };
598
+ var g = _gcd(f.num < 0n ? -f.num : f.num, f.den);
599
+ return g > 1n ? {
600
+ num: f.num / g,
601
+ den: f.den / g
602
+ } : f;
603
+ };
604
+
605
+ /**
606
+ * An equal-weight ladder of `n` bands from `lo` to `hi`, every band a CL
607
+ * arc at `fee` unless named in `curves`. The edges are built over a common
608
+ * denominator and reduced: every rational component of a concentrated-liquidity config
609
+ * must stay below 2^64 (spec V9).
610
+ */
611
+ var uniformLadder = exports.uniformLadder = function uniformLadder(n, lo, hi, fee) {
612
+ var curves = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : [];
613
+ if (n < 1) throw new Error("A ladder needs at least one band");
614
+ if (lo.num * hi.den >= hi.num * lo.den) throw new Error("The lower edge must be strictly below the upper edge");
615
+ var span = hi.num * lo.den - lo.num * hi.den;
616
+ var commonDen = lo.den * hi.den * BigInt(n);
617
+ var bands = [];
618
+ for (var i = 0; i < n; i++) {
619
+ var _curves$i;
620
+ bands.push({
621
+ start: reduceFrac({
622
+ num: lo.num * hi.den * BigInt(n) + span * BigInt(i),
623
+ den: commonDen
624
+ }),
625
+ weight: 1n,
626
+ curve: (_curves$i = curves[i]) !== null && _curves$i !== void 0 ? _curves$i : 0,
627
+ feeBuy: fee,
628
+ feeSell: fee
629
+ });
190
630
  }
191
631
  return {
192
- input: input,
193
- output: output,
194
- lpFee: new _asset.AssetAmount(inputLpFee, inputMetadata),
195
- nextInputReserve: nextInputReserve,
196
- nextOutputReserve: nextOutputReserve,
197
- priceImpact: priceImpact
632
+ bands: bands,
633
+ closing: reduceFrac({
634
+ num: lo.num * hi.den * BigInt(n) + span * BigInt(n),
635
+ den: commonDen
636
+ }),
637
+ weightTotal: BigInt(n)
198
638
  };
199
639
  };
200
640
 
641
+ /** Band weight profiles. Every weight is at least 1, as `Create` demands. */
642
+
643
+ var bandWeights = exports.bandWeights = function bandWeights(n) {
644
+ var _opts$peak, _opts$tail, _opts$centre;
645
+ var shape = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : "concentrated";
646
+ var opts = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
647
+ if (shape === "flat") return Array.from({
648
+ length: n
649
+ }, function () {
650
+ return 1n;
651
+ });
652
+ var peak = Number((_opts$peak = opts.peak) !== null && _opts$peak !== void 0 ? _opts$peak : 64n);
653
+ var tail = Number((_opts$tail = opts.tail) !== null && _opts$tail !== void 0 ? _opts$tail : 1n);
654
+ var centre = (_opts$centre = opts.centre) !== null && _opts$centre !== void 0 ? _opts$centre : (n - 1) / 2;
655
+ var sigma = Math.max(n / 5, 0.75);
656
+ var bell = function bell(i, c) {
657
+ return Math.exp(-Math.pow((i - c) / sigma, 2));
658
+ };
659
+ var profile = function profile(i) {
660
+ switch (shape) {
661
+ case "concentrated":
662
+ return bell(i, centre);
663
+ case "skewed-low":
664
+ return Math.exp(-i / Math.max(n / 3, 1));
665
+ case "skewed-high":
666
+ return Math.exp(-(n - 1 - i) / Math.max(n / 3, 1));
667
+ case "bimodal":
668
+ return Math.max(bell(i, (n - 1) / 4), bell(i, 3 * (n - 1) / 4));
669
+ default:
670
+ return 1;
671
+ }
672
+ };
673
+ return Array.from({
674
+ length: n
675
+ }, function (_, i) {
676
+ var w = Math.round(tail + (peak - tail) * profile(i));
677
+ return BigInt(Math.max(1, w));
678
+ });
679
+ };
680
+
201
681
  /**
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).
682
+ * A ladder of `n` bands from `lo` to `hi` with a weight shape, optional
683
+ * constant-sum bins and an optional per-band fee. The edges are
684
+ * `uniformLadder`'s exactly; only the weights, curves and fees differ.
210
685
  */
211
- var calculateLiquidity = exports.calculateLiquidity = function calculateLiquidity(a, b, aReserve, bReserve, totalLp) {
212
- return ConstantProductPool.calculateLiquidity(a, b, aReserve, bReserve, totalLp);
686
+ var shapedLadder = exports.shapedLadder = function shapedLadder(n, lo, hi, fee) {
687
+ var _opts$shape, _opts$csBands;
688
+ var opts = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : {};
689
+ var base = uniformLadder(n, lo, hi, fee);
690
+ var weights = bandWeights(n, (_opts$shape = opts.shape) !== null && _opts$shape !== void 0 ? _opts$shape : "concentrated", opts);
691
+ var cs = new Set((_opts$csBands = opts.csBands) !== null && _opts$csBands !== void 0 ? _opts$csBands : []);
692
+ var bands = base.bands.map(function (b, i) {
693
+ var f = opts.feeAt ? opts.feeAt(i) : fee;
694
+ return _objectSpread(_objectSpread({}, b), {}, {
695
+ weight: weights[i],
696
+ curve: cs.has(i) ? 1 : 0,
697
+ feeBuy: f,
698
+ feeSell: f
699
+ });
700
+ });
701
+ return {
702
+ bands: bands,
703
+ closing: base.closing,
704
+ weightTotal: weights.reduce(function (s, w) {
705
+ return s + w;
706
+ }, 0n)
707
+ };
213
708
  };
214
709
  //# sourceMappingURL=ConcentratedLiquidityPool.js.map