@1inch/swap-vm-sdk 0.1.2-rc.7 → 0.1.3

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 (31) hide show
  1. package/dist/index.js +205 -26
  2. package/dist/index.mjs +205 -26
  3. package/dist/swap-vm/instructions/concentrate/index.d.mts +1 -1
  4. package/dist/swap-vm/instructions/concentrate/index.d.ts +1 -1
  5. package/dist/swap-vm/instructions/concentrate/price/index.d.mts +1 -1
  6. package/dist/swap-vm/instructions/concentrate/price/index.d.ts +1 -1
  7. package/dist/swap-vm/instructions/index.d.mts +1 -0
  8. package/dist/swap-vm/instructions/index.d.ts +1 -0
  9. package/dist/swap-vm/instructions/pegged-swap/index.d.mts +4 -0
  10. package/dist/swap-vm/instructions/pegged-swap/index.d.ts +4 -0
  11. package/dist/swap-vm/instructions/pegged-swap/pegged-swap-calculator/index.d.mts +2 -0
  12. package/dist/swap-vm/instructions/pegged-swap/pegged-swap-calculator/index.d.ts +2 -0
  13. package/dist/swap-vm/instructions/pegged-swap/pegged-swap-calculator/pegged-swap-calculator.d.mts +16 -0
  14. package/dist/swap-vm/instructions/pegged-swap/pegged-swap-calculator/pegged-swap-calculator.d.ts +16 -0
  15. package/dist/swap-vm/instructions/pegged-swap/pegged-swap-calculator/types.d.mts +9 -0
  16. package/dist/swap-vm/instructions/pegged-swap/pegged-swap-calculator/types.d.ts +9 -0
  17. package/dist/swap-vm/instructions/pegged-swap/pegged-swap-math/pegged-swap-math.d.mts +18 -0
  18. package/dist/swap-vm/instructions/pegged-swap/pegged-swap-math/pegged-swap-math.d.ts +18 -0
  19. package/dist/swap-vm/instructions/pegged-swap/price/index.d.mts +2 -0
  20. package/dist/swap-vm/instructions/pegged-swap/price/index.d.ts +2 -0
  21. package/dist/swap-vm/instructions/pegged-swap/price/pegged-price.d.mts +28 -0
  22. package/dist/swap-vm/instructions/pegged-swap/price/pegged-price.d.ts +28 -0
  23. package/dist/swap-vm/instructions/pegged-swap/price/types.d.mts +30 -0
  24. package/dist/swap-vm/instructions/pegged-swap/price/types.d.ts +30 -0
  25. package/dist/swap-vm/instructions/utils/index.d.mts +2 -0
  26. package/dist/swap-vm/instructions/utils/index.d.ts +2 -0
  27. package/package.json +4 -4
  28. /package/dist/swap-vm/instructions/{concentrate → utils}/bigint-sqrt.d.mts +0 -0
  29. /package/dist/swap-vm/instructions/{concentrate → utils}/bigint-sqrt.d.ts +0 -0
  30. /package/dist/swap-vm/instructions/{concentrate/price → utils}/truncate-human-decimal-string.d.mts +0 -0
  31. /package/dist/swap-vm/instructions/{concentrate/price → utils}/truncate-human-decimal-string.d.ts +0 -0
package/dist/index.js CHANGED
@@ -1866,7 +1866,7 @@ var ConcentrateGrowLiquidity2DArgsCoder = class {
1866
1866
  };
1867
1867
 
1868
1868
  //#endregion
1869
- //#region src/swap-vm/instructions/concentrate/bigint-sqrt.ts
1869
+ //#region src/swap-vm/instructions/utils/bigint-sqrt.ts
1870
1870
  function bigintSqrt(value) {
1871
1871
  if (value < 0n) throw new Error("square root of negative numbers is not supported");
1872
1872
  if (value < 2n) return value;
@@ -1882,7 +1882,7 @@ function bigintSqrt(value) {
1882
1882
 
1883
1883
  //#endregion
1884
1884
  //#region src/swap-vm/instructions/concentrate/concentrate-grow-liquidity-2d-args.ts
1885
- const ONE_E18 = 10n ** 18n;
1885
+ const ONE_E18$1 = 10n ** 18n;
1886
1886
  /**
1887
1887
  * Arguments for concentrateGrowLiquidity2D instruction
1888
1888
  * Contract encodes sqrtPriceMin and sqrtPriceMax (2 × uint256, 64 bytes)
@@ -1910,8 +1910,8 @@ var ConcentrateGrowLiquidity2DArgs = class ConcentrateGrowLiquidity2DArgs {
1910
1910
  * Computes sqrtPrice = sqrt(P * 1e18) so that (sqrtPrice/1e18)^2 = P/1e18.
1911
1911
  **/
1912
1912
  static fromRawPrices(rawPriceMin, rawPriceMax) {
1913
- const sqrtPriceMin = bigintSqrt(rawPriceMin * ONE_E18);
1914
- const sqrtPriceMax = bigintSqrt(rawPriceMax * ONE_E18);
1913
+ const sqrtPriceMin = bigintSqrt(rawPriceMin * ONE_E18$1);
1914
+ const sqrtPriceMax = bigintSqrt(rawPriceMax * ONE_E18$1);
1915
1915
  return new ConcentrateGrowLiquidity2DArgs(sqrtPriceMin, sqrtPriceMax);
1916
1916
  }
1917
1917
  /**
@@ -1955,8 +1955,8 @@ const ONE = 10n ** 18n;
1955
1955
  */
1956
1956
  function computeLiquidityFromAmounts(availableLt, availableGt, sqrtPspot, sqrtPmin, sqrtPmax) {
1957
1957
  if (sqrtPmin >= sqrtPmax) throw new Error("sqrtPmax should be greater than sqrtPmin");
1958
- const lFromLt = sqrtPmax > sqrtPspot ? mulDiv(availableLt, mulDiv(sqrtPmax, sqrtPspot, ONE), sqrtPmax - sqrtPspot) : __1inch_byte_utils.UINT_256_MAX;
1959
- const lFromGt = sqrtPspot > sqrtPmin ? mulDiv(availableGt, ONE, sqrtPspot - sqrtPmin) : __1inch_byte_utils.UINT_256_MAX;
1958
+ const lFromLt = sqrtPmax > sqrtPspot ? mulDiv$1(availableLt, mulDiv$1(sqrtPmax, sqrtPspot, ONE), sqrtPmax - sqrtPspot) : __1inch_byte_utils.UINT_256_MAX;
1959
+ const lFromGt = sqrtPspot > sqrtPmin ? mulDiv$1(availableGt, ONE, sqrtPspot - sqrtPmin) : __1inch_byte_utils.UINT_256_MAX;
1960
1960
  const targetL = lFromLt < lFromGt ? lFromLt : lFromGt;
1961
1961
  const { bLt: actualLt, bGt: actualGt } = computeBalances(targetL, sqrtPspot, sqrtPmin, sqrtPmax);
1962
1962
  return {
@@ -1980,8 +1980,8 @@ function computeLiquidityFromAmounts(availableLt, availableGt, sqrtPspot, sqrtPm
1980
1980
  */
1981
1981
  function computeBalances(targetL, sqrtPspot, sqrtPmin, sqrtPmax) {
1982
1982
  if (sqrtPmin >= sqrtPmax) throw new Error("sqrtPmax should be greater than sqrtPmin");
1983
- const bLt = sqrtPmax > sqrtPspot ? mulDiv(targetL, sqrtPmax - sqrtPspot, mulDiv(sqrtPmax, sqrtPspot, ONE)) : 0n;
1984
- const bGt = sqrtPspot > sqrtPmin ? mulDiv(targetL, sqrtPspot - sqrtPmin, ONE) : 0n;
1983
+ const bLt = sqrtPmax > sqrtPspot ? mulDiv$1(targetL, sqrtPmax - sqrtPspot, mulDiv$1(sqrtPmax, sqrtPspot, ONE)) : 0n;
1984
+ const bGt = sqrtPspot > sqrtPmin ? mulDiv$1(targetL, sqrtPspot - sqrtPmin, ONE) : 0n;
1985
1985
  return {
1986
1986
  bLt,
1987
1987
  bGt
@@ -2000,9 +2000,9 @@ function computeBalances(targetL, sqrtPspot, sqrtPmin, sqrtPmax) {
2000
2000
  */
2001
2001
  function computeLiquidityAndPrice(balanceLt, balanceGt, sqrtPriceMin, sqrtPriceMax) {
2002
2002
  const liquidity = computeL(balanceLt, balanceGt, sqrtPriceMin, sqrtPriceMax);
2003
- const virtualLt = balanceLt + mulDiv(liquidity, ONE, sqrtPriceMax);
2004
- const virtualGt = balanceGt + mulDiv(liquidity, sqrtPriceMin, ONE);
2005
- const sqrtPriceSpot = bigintSqrt(mulDiv(virtualGt, ONE * ONE, virtualLt));
2003
+ const virtualLt = balanceLt + mulDiv$1(liquidity, ONE, sqrtPriceMax);
2004
+ const virtualGt = balanceGt + mulDiv$1(liquidity, sqrtPriceMin, ONE);
2005
+ const sqrtPriceSpot = bigintSqrt(mulDiv$1(virtualGt, ONE * ONE, virtualLt));
2006
2006
  return {
2007
2007
  liquidity,
2008
2008
  sqrtPriceSpot
@@ -2013,19 +2013,19 @@ function computeLiquidityAndPrice(balanceLt, balanceGt, sqrtPriceMin, sqrtPriceM
2013
2013
  * Mirrors XYCConcentrateArgsBuilder._computeL in XYCConcentrate.sol.
2014
2014
  */
2015
2015
  function computeL(bLt, bGt, sqrtPriceMin, sqrtPriceMax) {
2016
- const alpha = ONE - mulDiv(sqrtPriceMin, ONE, sqrtPriceMax);
2017
- const beta = mulDiv(bLt, sqrtPriceMin, ONE) + mulDiv(bGt, ONE, sqrtPriceMax);
2018
- const fourAC = mulDiv(4n * alpha, bLt, ONE) * bGt;
2016
+ const alpha = ONE - mulDiv$1(sqrtPriceMin, ONE, sqrtPriceMax);
2017
+ const beta = mulDiv$1(bLt, sqrtPriceMin, ONE) + mulDiv$1(bGt, ONE, sqrtPriceMax);
2018
+ const fourAC = mulDiv$1(4n * alpha, bLt, ONE) * bGt;
2019
2019
  const disc = beta * beta + fourAC;
2020
- return mulDiv(beta + bigintSqrt(disc), ONE, 2n * alpha);
2020
+ return mulDiv$1(beta + bigintSqrt(disc), ONE, 2n * alpha);
2021
2021
  }
2022
- function mulDiv(a, b, c) {
2022
+ function mulDiv$1(a, b, c) {
2023
2023
  if (c === 0n) throw new Error("mulDiv: division by zero");
2024
2024
  return a * b / c;
2025
2025
  }
2026
2026
 
2027
2027
  //#endregion
2028
- //#region src/swap-vm/instructions/concentrate/price/truncate-human-decimal-string.ts
2028
+ //#region src/swap-vm/instructions/utils/truncate-human-decimal-string.ts
2029
2029
  /**
2030
2030
  * Round a decimal string to `maxFrac` fractional digits (half-up: if the first dropped digit
2031
2031
  * is `5`–`9`, round the last kept digit up), then strip trailing zeros after the dot.
@@ -2060,7 +2060,7 @@ function truncateHumanDecimalString(s, maxFrac) {
2060
2060
 
2061
2061
  //#endregion
2062
2062
  //#region src/swap-vm/instructions/concentrate/price/price.ts
2063
- const ONE_E18$1 = 10n ** 18n;
2063
+ const ONE_E18$2 = 10n ** 18n;
2064
2064
  var Price = class Price {
2065
2065
  constructor(sqrtP, token0, token1) {
2066
2066
  this.sqrtP = sqrtP;
@@ -2092,12 +2092,12 @@ var Price = class Price {
2092
2092
  if (scale > BigInt(Number.MAX_SAFE_INTEGER)) throw new Error("decimals sum too large for parseUnits");
2093
2093
  const scaledRaw = (0, viem.parseUnits)(price.trim(), Number(scale));
2094
2094
  if (pair.quoteToken.address.equal(t0.address)) {
2095
- const numerator = 10n ** (d1 + d1) * ONE_E18$1;
2096
- return new Price(bigintSqrt(numerator * ONE_E18$1 / scaledRaw), t0, t1);
2095
+ const numerator = 10n ** (d1 + d1) * ONE_E18$2;
2096
+ return new Price(bigintSqrt(numerator * ONE_E18$2 / scaledRaw), t0, t1);
2097
2097
  }
2098
2098
  if (pair.quoteToken.address.equal(t1.address)) {
2099
2099
  const denominator = 10n ** (d0 + d0);
2100
- return new Price(bigintSqrt(scaledRaw * ONE_E18$1 * ONE_E18$1 / denominator), t0, t1);
2100
+ return new Price(bigintSqrt(scaledRaw * ONE_E18$2 * ONE_E18$2 / denominator), t0, t1);
2101
2101
  }
2102
2102
  throw new Error("quote token must be one of the two pair tokens");
2103
2103
  }
@@ -2139,7 +2139,7 @@ var Price = class Price {
2139
2139
  * Raw price `P` with 1e18 fixed-point (`(sqrtP^2) / 1e18`), matching typical on-chain use.
2140
2140
  */
2141
2141
  toRaw() {
2142
- return this.sqrtP * this.sqrtP / ONE_E18$1;
2142
+ return this.sqrtP * this.sqrtP / ONE_E18$2;
2143
2143
  }
2144
2144
  toSqrt() {
2145
2145
  return this.sqrtP;
@@ -2183,12 +2183,12 @@ var Price = class Price {
2183
2183
  const d1 = this.token1.decimals;
2184
2184
  const sqrtP2 = this.sqrtP * this.sqrtP;
2185
2185
  if (quoteToken.equal(this.token0.address)) {
2186
- const numerator = 10n ** (d1 + d1) * ONE_E18$1;
2187
- return numerator * ONE_E18$1 / sqrtP2;
2186
+ const numerator = 10n ** (d1 + d1) * ONE_E18$2;
2187
+ return numerator * ONE_E18$2 / sqrtP2;
2188
2188
  }
2189
2189
  if (quoteToken.equal(this.token1.address)) {
2190
2190
  const numerator = 10n ** (d0 + d0);
2191
- return sqrtP2 * numerator / (ONE_E18$1 * ONE_E18$1);
2191
+ return sqrtP2 * numerator / (ONE_E18$2 * ONE_E18$2);
2192
2192
  }
2193
2193
  throw new Error("quote token must be one of the pair tokens");
2194
2194
  }
@@ -2314,7 +2314,7 @@ var PriceRange = class PriceRange {
2314
2314
  var concentrate_exports = {};
2315
2315
  __export(concentrate_exports, {
2316
2316
  ConcentrateGrowLiquidity2DArgs: () => ConcentrateGrowLiquidity2DArgs,
2317
- ONE_E18: () => ONE_E18,
2317
+ ONE_E18: () => ONE_E18$1,
2318
2318
  Price: () => Price,
2319
2319
  PriceRange: () => PriceRange,
2320
2320
  TokenReserve: () => TokenReserve,
@@ -3223,11 +3223,188 @@ var PeggedSwapArgs = class PeggedSwapArgs {
3223
3223
  **/
3224
3224
  const peggedSwapGrowPriceRange2D = new Opcode(Symbol("PeggedSwap.peggedSwapGrowPriceRange2D"), PeggedSwapArgs.CODER);
3225
3225
 
3226
+ //#endregion
3227
+ //#region src/swap-vm/instructions/pegged-swap/pegged-swap-calculator/pegged-swap-calculator.ts
3228
+ const MARGINAL_PRICE_ONE$1 = 10n ** 18n;
3229
+ var PeggedSwapCalculator = class PeggedSwapCalculator {
3230
+ constructor(tokenA, tokenB) {
3231
+ this.tokenA = tokenA;
3232
+ this.tokenB = tokenB;
3233
+ (0, assert.default)(!tokenA.address.equal(tokenB.address), "tokens must be different");
3234
+ }
3235
+ get tokenLt() {
3236
+ return this.tokenA.address.lt(this.tokenB.address) ? this.tokenA : this.tokenB;
3237
+ }
3238
+ get tokenGt() {
3239
+ return this.tokenA.address.lt(this.tokenB.address) ? this.tokenB : this.tokenA;
3240
+ }
3241
+ static new(args) {
3242
+ return new PeggedSwapCalculator(args.tokenA, args.tokenB);
3243
+ }
3244
+ /**
3245
+ * Initial balances before deployment (`currentReserve = initialReserve`, u = v = 1).
3246
+ * Given spot price and one raw initial reserve, returns the other.
3247
+ */
3248
+ computeFixedAllocation(spotPrice, fixedReserveForToken, fixedReserve) {
3249
+ (0, assert.default)(fixedReserve > 0n, "fixed reserve must be positive");
3250
+ (0, assert.default)(spotPrice.matchesTokens(this.tokenLt.address, this.tokenGt.address), "spot price must match calculator token pair");
3251
+ const marginalE18 = spotPrice.toGtPerLtE18();
3252
+ if (fixedReserveForToken.equal(this.tokenLt.address)) return {
3253
+ reserveLt: fixedReserve,
3254
+ reserveGt: fixedReserve * marginalE18 / MARGINAL_PRICE_ONE$1
3255
+ };
3256
+ if (fixedReserveForToken.equal(this.tokenGt.address)) return {
3257
+ reserveLt: fixedReserve * MARGINAL_PRICE_ONE$1 / marginalE18,
3258
+ reserveGt: fixedReserve
3259
+ };
3260
+ throw new Error("fixedReserveForToken token must be one of the two pair tokens");
3261
+ }
3262
+ };
3263
+
3264
+ //#endregion
3265
+ //#region src/swap-vm/instructions/pegged-swap/pegged-swap-math/pegged-swap-math.ts
3266
+ /** Matches `PeggedSwapMath.ONE` in swap-vm. */
3267
+ const PEGGED_SWAP_ONE = 10n ** 27n;
3268
+ const MARGINAL_PRICE_ONE = 10n ** 18n;
3269
+ /**
3270
+ * Spot price tokenGt per tokenLt (raw) in 1e18 fixed-point.
3271
+ *
3272
+ * P = (Y₀/X₀) · (1/(2√u) + A) / (1/(2√v) + A) · (rateLt/rateGt)
3273
+ *
3274
+ * where u = x·ONE/X₀, v = y·ONE/Y₀, x/y are rate-adjusted Lt/Gt balances, A = `linearWidth`.
3275
+ */
3276
+ function peggedSwapMarginalGtPerLtE18(balanceLtNorm, balanceGtNorm, x0, y0, linearWidth, rateLt, rateGt) {
3277
+ const u = normalizeReserve(balanceLtNorm, x0);
3278
+ const v = normalizeReserve(balanceGtNorm, y0);
3279
+ (0, assert.default)(u !== 0n && v !== 0n, "PeggedSwapMath: reserves cannot be zero");
3280
+ const slopeLt = peggedSwapMarginalWeight(bigintSqrt(u * PEGGED_SWAP_ONE), linearWidth);
3281
+ const slopeGt = peggedSwapMarginalWeight(bigintSqrt(v * PEGGED_SWAP_ONE), linearWidth);
3282
+ return y0 * slopeLt * rateLt * MARGINAL_PRICE_ONE / (x0 * slopeGt * rateGt);
3283
+ }
3284
+ /**
3285
+ * u = x·ONE/X₀, v = y·ONE/Y₀ (x, y are rate-adjusted reserves).
3286
+ */
3287
+ function normalizeReserve(currentReserve, initialReserve) {
3288
+ return mulDiv(currentReserve, PEGGED_SWAP_ONE, initialReserve);
3289
+ }
3290
+ /**
3291
+ * Marginal weight `1/(2√u) + A` (Lt side) or `1/(2√v) + A` (Gt side), A = `linearWidth`.
3292
+ */
3293
+ function peggedSwapMarginalWeight(sqrtCoord, linearWidth) {
3294
+ return mulDiv(PEGGED_SWAP_ONE, PEGGED_SWAP_ONE, 2n * sqrtCoord) + linearWidth;
3295
+ }
3296
+ function mulDiv(a, b, c) {
3297
+ if (c === 0n) throw new Error("mulDiv: division by zero");
3298
+ return a * b / c;
3299
+ }
3300
+
3301
+ //#endregion
3302
+ //#region src/swap-vm/instructions/pegged-swap/price/pegged-price.ts
3303
+ const ONE_E18 = 10n ** 18n;
3304
+ var PeggedPrice = class PeggedPrice {
3305
+ constructor(gtPerLtRaw, tokenLt, tokenGt) {
3306
+ this.gtPerLtRaw = gtPerLtRaw;
3307
+ this.tokenLt = tokenLt;
3308
+ this.tokenGt = tokenGt;
3309
+ (0, assert.default)(gtPerLtRaw > 0n, "price must be positive");
3310
+ (0, assert.default)(tokenLt.address.lt(tokenGt.address), "internal pair order violated");
3311
+ }
3312
+ /**
3313
+ * Spot price from per-token `initialReserve` / `currentReserve` (raw, not rate-scaled) and `linearWidth`.
3314
+ * Use currentReserve = initialReserve to calculate the spot price before the strategy was deployed
3315
+ */
3316
+ static fromReserves(input) {
3317
+ (0, assert.default)(input.reserveA.currentReserve > 0n && input.reserveB.currentReserve > 0n, "current reserves should be positive");
3318
+ (0, assert.default)(input.reserveA.initialReserve > 0n && input.reserveB.initialReserve > 0n, "initial reserves should be positive");
3319
+ const zeroForOne = input.reserveA.address.lt(input.reserveB.address);
3320
+ const reserveLt = zeroForOne ? input.reserveA : input.reserveB;
3321
+ const reserveGt = zeroForOne ? input.reserveB : input.reserveA;
3322
+ const rateLt = resolveRate(reserveLt.decimals, reserveGt.decimals);
3323
+ const rateGt = resolveRate(reserveGt.decimals, reserveLt.decimals);
3324
+ const initialLtNorm = reserveLt.initialReserve * rateLt;
3325
+ const initialGtNorm = reserveGt.initialReserve * rateGt;
3326
+ const marginalE18 = peggedSwapMarginalGtPerLtE18(reserveLt.currentReserve * rateLt, reserveGt.currentReserve * rateGt, initialLtNorm, initialGtNorm, input.linearWidth, rateLt, rateGt);
3327
+ return PeggedPrice.fromGtPerLtE18(marginalE18, reserveLt, reserveGt);
3328
+ }
3329
+ /**
3330
+ * Human decimal string for **quote per 1 base**.
3331
+ */
3332
+ static fromHuman(price, pair) {
3333
+ (0, assert.default)(!pair.quoteToken.address.equal(pair.baseToken.address), "quote and base must be different tokens");
3334
+ const quoteToBase = pair.quoteToken.address.lt(pair.baseToken.address);
3335
+ const tokenLt = quoteToBase ? pair.quoteToken : pair.baseToken;
3336
+ const tokenGt = quoteToBase ? pair.baseToken : pair.quoteToken;
3337
+ const parsed = (0, viem.parseUnits)(price.trim(), Number(pair.quoteToken.decimals));
3338
+ const ltDecimals = BigInt(tokenLt.decimals);
3339
+ const gtDecimals = BigInt(tokenGt.decimals);
3340
+ const marginalE18 = quoteToBase ? 10n ** (gtDecimals + 18n + ltDecimals) / (parsed * 10n ** gtDecimals) : parsed * ONE_E18 / 10n ** ltDecimals;
3341
+ return PeggedPrice.fromGtPerLtE18(marginalE18, tokenLt, tokenGt);
3342
+ }
3343
+ static fromJSON(input) {
3344
+ const tokenLt = {
3345
+ address: new __1inch_sdk_core.Address(input.tokenLt.address),
3346
+ decimals: Number(input.tokenLt.decimals)
3347
+ };
3348
+ const tokenGt = {
3349
+ address: new __1inch_sdk_core.Address(input.tokenGt.address),
3350
+ decimals: Number(input.tokenGt.decimals)
3351
+ };
3352
+ (0, assert.default)(tokenLt.address.lt(tokenGt.address), "tokenLt address must be less than tokenGt (canonical order)");
3353
+ return new PeggedPrice(BigInt(input.gtPerLtRaw), tokenLt, tokenGt);
3354
+ }
3355
+ static fromGtPerLtE18(marginalGtPerLtE18, tokenLt, tokenGt) {
3356
+ (0, assert.default)(marginalGtPerLtE18 > 0n, "marginal rate must be positive");
3357
+ const scale = BigInt(tokenLt.decimals + tokenGt.decimals);
3358
+ const gtPerLtRaw = marginalGtPerLtE18 * 10n ** scale / ONE_E18;
3359
+ return new PeggedPrice(gtPerLtRaw, tokenLt, tokenGt);
3360
+ }
3361
+ matchesTokens(tokenA, tokenB) {
3362
+ return tokenA.equal(this.tokenLt.address) && tokenB.equal(this.tokenGt.address) || tokenA.equal(this.tokenGt.address) && tokenB.equal(this.tokenLt.address);
3363
+ }
3364
+ equals(other) {
3365
+ return this.gtPerLtRaw === other.gtPerLtRaw && this.tokenLt.address.equal(other.tokenLt.address) && this.tokenGt.address.equal(other.tokenGt.address) && BigInt(this.tokenLt.decimals) === BigInt(other.tokenLt.decimals) && BigInt(this.tokenGt.decimals) === BigInt(other.tokenGt.decimals);
3366
+ }
3367
+ /**
3368
+ * Decimal string for **quote per 1 base**; rounded half-up to quote token decimals.
3369
+ */
3370
+ toHuman(quoteToken) {
3371
+ (0, assert.default)(quoteToken.equal(this.tokenLt.address) || quoteToken.equal(this.tokenGt.address), "quote token must be one of the pair tokens");
3372
+ const isQuoteLt = quoteToken.equal(this.tokenLt.address);
3373
+ const quoteDecimals = isQuoteLt ? this.tokenLt.decimals : this.tokenGt.decimals;
3374
+ const ltDecimals = BigInt(this.tokenLt.decimals);
3375
+ const gtDecimals = BigInt(this.tokenGt.decimals);
3376
+ const marginalE18 = this.toGtPerLtE18();
3377
+ const scaled = quoteToken.equal(this.tokenGt.address) ? marginalE18 * 10n ** ltDecimals / ONE_E18 : 10n ** (gtDecimals + 18n + ltDecimals) / (marginalE18 * 10n ** gtDecimals);
3378
+ const full = (0, viem.formatUnits)(scaled, Number(quoteDecimals));
3379
+ return truncateHumanDecimalString(full, Number(quoteDecimals));
3380
+ }
3381
+ /** Marginal gt-per-lt rate in 1e18 fixed-point. */
3382
+ toGtPerLtE18() {
3383
+ const scale = BigInt(this.tokenLt.decimals + this.tokenGt.decimals);
3384
+ return this.gtPerLtRaw * ONE_E18 / 10n ** scale;
3385
+ }
3386
+ toJSON() {
3387
+ return {
3388
+ gtPerLtRaw: this.gtPerLtRaw.toString(),
3389
+ tokenLt: {
3390
+ address: this.tokenLt.address.toString(),
3391
+ decimals: String(this.tokenLt.decimals)
3392
+ },
3393
+ tokenGt: {
3394
+ address: this.tokenGt.address.toString(),
3395
+ decimals: String(this.tokenGt.decimals)
3396
+ }
3397
+ };
3398
+ }
3399
+ };
3400
+
3226
3401
  //#endregion
3227
3402
  //#region src/swap-vm/instructions/pegged-swap/index.ts
3228
3403
  var pegged_swap_exports = {};
3229
3404
  __export(pegged_swap_exports, {
3405
+ PeggedPrice: () => PeggedPrice,
3230
3406
  PeggedSwapArgs: () => PeggedSwapArgs,
3407
+ PeggedSwapCalculator: () => PeggedSwapCalculator,
3231
3408
  peggedSwapGrowPriceRange2D: () => peggedSwapGrowPriceRange2D
3232
3409
  });
3233
3410
 
@@ -3333,6 +3510,7 @@ __export(instructions_exports, {
3333
3510
  aquaInstructions: () => aquaInstructions,
3334
3511
  balances: () => balances_exports,
3335
3512
  baseFeeAdjuster: () => base_fee_adjuster_exports,
3513
+ bigintSqrt: () => bigintSqrt,
3336
3514
  concentrate: () => concentrate_exports,
3337
3515
  controls: () => controls_exports,
3338
3516
  decay: () => decay_exports,
@@ -3345,6 +3523,7 @@ __export(instructions_exports, {
3345
3523
  oraclePriceAdjuster: () => oracle_price_adjuster_exports,
3346
3524
  peggedSwap: () => pegged_swap_exports,
3347
3525
  stableSwap: () => pegged_swap_exports,
3526
+ truncateHumanDecimalString: () => truncateHumanDecimalString,
3348
3527
  twapSwap: () => twap_swap_exports,
3349
3528
  xycSwap: () => xyc_swap_exports
3350
3529
  });
package/dist/index.mjs CHANGED
@@ -1847,7 +1847,7 @@ var ConcentrateGrowLiquidity2DArgsCoder = class {
1847
1847
  };
1848
1848
 
1849
1849
  //#endregion
1850
- //#region src/swap-vm/instructions/concentrate/bigint-sqrt.ts
1850
+ //#region src/swap-vm/instructions/utils/bigint-sqrt.ts
1851
1851
  function bigintSqrt(value) {
1852
1852
  if (value < 0n) throw new Error("square root of negative numbers is not supported");
1853
1853
  if (value < 2n) return value;
@@ -1863,7 +1863,7 @@ function bigintSqrt(value) {
1863
1863
 
1864
1864
  //#endregion
1865
1865
  //#region src/swap-vm/instructions/concentrate/concentrate-grow-liquidity-2d-args.ts
1866
- const ONE_E18 = 10n ** 18n;
1866
+ const ONE_E18$1 = 10n ** 18n;
1867
1867
  /**
1868
1868
  * Arguments for concentrateGrowLiquidity2D instruction
1869
1869
  * Contract encodes sqrtPriceMin and sqrtPriceMax (2 × uint256, 64 bytes)
@@ -1891,8 +1891,8 @@ var ConcentrateGrowLiquidity2DArgs = class ConcentrateGrowLiquidity2DArgs {
1891
1891
  * Computes sqrtPrice = sqrt(P * 1e18) so that (sqrtPrice/1e18)^2 = P/1e18.
1892
1892
  **/
1893
1893
  static fromRawPrices(rawPriceMin, rawPriceMax) {
1894
- const sqrtPriceMin = bigintSqrt(rawPriceMin * ONE_E18);
1895
- const sqrtPriceMax = bigintSqrt(rawPriceMax * ONE_E18);
1894
+ const sqrtPriceMin = bigintSqrt(rawPriceMin * ONE_E18$1);
1895
+ const sqrtPriceMax = bigintSqrt(rawPriceMax * ONE_E18$1);
1896
1896
  return new ConcentrateGrowLiquidity2DArgs(sqrtPriceMin, sqrtPriceMax);
1897
1897
  }
1898
1898
  /**
@@ -1936,8 +1936,8 @@ const ONE = 10n ** 18n;
1936
1936
  */
1937
1937
  function computeLiquidityFromAmounts(availableLt, availableGt, sqrtPspot, sqrtPmin, sqrtPmax) {
1938
1938
  if (sqrtPmin >= sqrtPmax) throw new Error("sqrtPmax should be greater than sqrtPmin");
1939
- const lFromLt = sqrtPmax > sqrtPspot ? mulDiv(availableLt, mulDiv(sqrtPmax, sqrtPspot, ONE), sqrtPmax - sqrtPspot) : UINT_256_MAX;
1940
- const lFromGt = sqrtPspot > sqrtPmin ? mulDiv(availableGt, ONE, sqrtPspot - sqrtPmin) : UINT_256_MAX;
1939
+ const lFromLt = sqrtPmax > sqrtPspot ? mulDiv$1(availableLt, mulDiv$1(sqrtPmax, sqrtPspot, ONE), sqrtPmax - sqrtPspot) : UINT_256_MAX;
1940
+ const lFromGt = sqrtPspot > sqrtPmin ? mulDiv$1(availableGt, ONE, sqrtPspot - sqrtPmin) : UINT_256_MAX;
1941
1941
  const targetL = lFromLt < lFromGt ? lFromLt : lFromGt;
1942
1942
  const { bLt: actualLt, bGt: actualGt } = computeBalances(targetL, sqrtPspot, sqrtPmin, sqrtPmax);
1943
1943
  return {
@@ -1961,8 +1961,8 @@ function computeLiquidityFromAmounts(availableLt, availableGt, sqrtPspot, sqrtPm
1961
1961
  */
1962
1962
  function computeBalances(targetL, sqrtPspot, sqrtPmin, sqrtPmax) {
1963
1963
  if (sqrtPmin >= sqrtPmax) throw new Error("sqrtPmax should be greater than sqrtPmin");
1964
- const bLt = sqrtPmax > sqrtPspot ? mulDiv(targetL, sqrtPmax - sqrtPspot, mulDiv(sqrtPmax, sqrtPspot, ONE)) : 0n;
1965
- const bGt = sqrtPspot > sqrtPmin ? mulDiv(targetL, sqrtPspot - sqrtPmin, ONE) : 0n;
1964
+ const bLt = sqrtPmax > sqrtPspot ? mulDiv$1(targetL, sqrtPmax - sqrtPspot, mulDiv$1(sqrtPmax, sqrtPspot, ONE)) : 0n;
1965
+ const bGt = sqrtPspot > sqrtPmin ? mulDiv$1(targetL, sqrtPspot - sqrtPmin, ONE) : 0n;
1966
1966
  return {
1967
1967
  bLt,
1968
1968
  bGt
@@ -1981,9 +1981,9 @@ function computeBalances(targetL, sqrtPspot, sqrtPmin, sqrtPmax) {
1981
1981
  */
1982
1982
  function computeLiquidityAndPrice(balanceLt, balanceGt, sqrtPriceMin, sqrtPriceMax) {
1983
1983
  const liquidity = computeL(balanceLt, balanceGt, sqrtPriceMin, sqrtPriceMax);
1984
- const virtualLt = balanceLt + mulDiv(liquidity, ONE, sqrtPriceMax);
1985
- const virtualGt = balanceGt + mulDiv(liquidity, sqrtPriceMin, ONE);
1986
- const sqrtPriceSpot = bigintSqrt(mulDiv(virtualGt, ONE * ONE, virtualLt));
1984
+ const virtualLt = balanceLt + mulDiv$1(liquidity, ONE, sqrtPriceMax);
1985
+ const virtualGt = balanceGt + mulDiv$1(liquidity, sqrtPriceMin, ONE);
1986
+ const sqrtPriceSpot = bigintSqrt(mulDiv$1(virtualGt, ONE * ONE, virtualLt));
1987
1987
  return {
1988
1988
  liquidity,
1989
1989
  sqrtPriceSpot
@@ -1994,19 +1994,19 @@ function computeLiquidityAndPrice(balanceLt, balanceGt, sqrtPriceMin, sqrtPriceM
1994
1994
  * Mirrors XYCConcentrateArgsBuilder._computeL in XYCConcentrate.sol.
1995
1995
  */
1996
1996
  function computeL(bLt, bGt, sqrtPriceMin, sqrtPriceMax) {
1997
- const alpha = ONE - mulDiv(sqrtPriceMin, ONE, sqrtPriceMax);
1998
- const beta = mulDiv(bLt, sqrtPriceMin, ONE) + mulDiv(bGt, ONE, sqrtPriceMax);
1999
- const fourAC = mulDiv(4n * alpha, bLt, ONE) * bGt;
1997
+ const alpha = ONE - mulDiv$1(sqrtPriceMin, ONE, sqrtPriceMax);
1998
+ const beta = mulDiv$1(bLt, sqrtPriceMin, ONE) + mulDiv$1(bGt, ONE, sqrtPriceMax);
1999
+ const fourAC = mulDiv$1(4n * alpha, bLt, ONE) * bGt;
2000
2000
  const disc = beta * beta + fourAC;
2001
- return mulDiv(beta + bigintSqrt(disc), ONE, 2n * alpha);
2001
+ return mulDiv$1(beta + bigintSqrt(disc), ONE, 2n * alpha);
2002
2002
  }
2003
- function mulDiv(a, b, c) {
2003
+ function mulDiv$1(a, b, c) {
2004
2004
  if (c === 0n) throw new Error("mulDiv: division by zero");
2005
2005
  return a * b / c;
2006
2006
  }
2007
2007
 
2008
2008
  //#endregion
2009
- //#region src/swap-vm/instructions/concentrate/price/truncate-human-decimal-string.ts
2009
+ //#region src/swap-vm/instructions/utils/truncate-human-decimal-string.ts
2010
2010
  /**
2011
2011
  * Round a decimal string to `maxFrac` fractional digits (half-up: if the first dropped digit
2012
2012
  * is `5`–`9`, round the last kept digit up), then strip trailing zeros after the dot.
@@ -2041,7 +2041,7 @@ function truncateHumanDecimalString(s, maxFrac) {
2041
2041
 
2042
2042
  //#endregion
2043
2043
  //#region src/swap-vm/instructions/concentrate/price/price.ts
2044
- const ONE_E18$1 = 10n ** 18n;
2044
+ const ONE_E18$2 = 10n ** 18n;
2045
2045
  var Price = class Price {
2046
2046
  constructor(sqrtP, token0, token1) {
2047
2047
  this.sqrtP = sqrtP;
@@ -2073,12 +2073,12 @@ var Price = class Price {
2073
2073
  if (scale > BigInt(Number.MAX_SAFE_INTEGER)) throw new Error("decimals sum too large for parseUnits");
2074
2074
  const scaledRaw = parseUnits(price.trim(), Number(scale));
2075
2075
  if (pair.quoteToken.address.equal(t0.address)) {
2076
- const numerator = 10n ** (d1 + d1) * ONE_E18$1;
2077
- return new Price(bigintSqrt(numerator * ONE_E18$1 / scaledRaw), t0, t1);
2076
+ const numerator = 10n ** (d1 + d1) * ONE_E18$2;
2077
+ return new Price(bigintSqrt(numerator * ONE_E18$2 / scaledRaw), t0, t1);
2078
2078
  }
2079
2079
  if (pair.quoteToken.address.equal(t1.address)) {
2080
2080
  const denominator = 10n ** (d0 + d0);
2081
- return new Price(bigintSqrt(scaledRaw * ONE_E18$1 * ONE_E18$1 / denominator), t0, t1);
2081
+ return new Price(bigintSqrt(scaledRaw * ONE_E18$2 * ONE_E18$2 / denominator), t0, t1);
2082
2082
  }
2083
2083
  throw new Error("quote token must be one of the two pair tokens");
2084
2084
  }
@@ -2120,7 +2120,7 @@ var Price = class Price {
2120
2120
  * Raw price `P` with 1e18 fixed-point (`(sqrtP^2) / 1e18`), matching typical on-chain use.
2121
2121
  */
2122
2122
  toRaw() {
2123
- return this.sqrtP * this.sqrtP / ONE_E18$1;
2123
+ return this.sqrtP * this.sqrtP / ONE_E18$2;
2124
2124
  }
2125
2125
  toSqrt() {
2126
2126
  return this.sqrtP;
@@ -2164,12 +2164,12 @@ var Price = class Price {
2164
2164
  const d1 = this.token1.decimals;
2165
2165
  const sqrtP2 = this.sqrtP * this.sqrtP;
2166
2166
  if (quoteToken.equal(this.token0.address)) {
2167
- const numerator = 10n ** (d1 + d1) * ONE_E18$1;
2168
- return numerator * ONE_E18$1 / sqrtP2;
2167
+ const numerator = 10n ** (d1 + d1) * ONE_E18$2;
2168
+ return numerator * ONE_E18$2 / sqrtP2;
2169
2169
  }
2170
2170
  if (quoteToken.equal(this.token1.address)) {
2171
2171
  const numerator = 10n ** (d0 + d0);
2172
- return sqrtP2 * numerator / (ONE_E18$1 * ONE_E18$1);
2172
+ return sqrtP2 * numerator / (ONE_E18$2 * ONE_E18$2);
2173
2173
  }
2174
2174
  throw new Error("quote token must be one of the pair tokens");
2175
2175
  }
@@ -2295,7 +2295,7 @@ var PriceRange = class PriceRange {
2295
2295
  var concentrate_exports = {};
2296
2296
  __export(concentrate_exports, {
2297
2297
  ConcentrateGrowLiquidity2DArgs: () => ConcentrateGrowLiquidity2DArgs,
2298
- ONE_E18: () => ONE_E18,
2298
+ ONE_E18: () => ONE_E18$1,
2299
2299
  Price: () => Price,
2300
2300
  PriceRange: () => PriceRange,
2301
2301
  TokenReserve: () => TokenReserve,
@@ -3204,11 +3204,188 @@ var PeggedSwapArgs = class PeggedSwapArgs {
3204
3204
  **/
3205
3205
  const peggedSwapGrowPriceRange2D = new Opcode(Symbol("PeggedSwap.peggedSwapGrowPriceRange2D"), PeggedSwapArgs.CODER);
3206
3206
 
3207
+ //#endregion
3208
+ //#region src/swap-vm/instructions/pegged-swap/pegged-swap-calculator/pegged-swap-calculator.ts
3209
+ const MARGINAL_PRICE_ONE$1 = 10n ** 18n;
3210
+ var PeggedSwapCalculator = class PeggedSwapCalculator {
3211
+ constructor(tokenA, tokenB) {
3212
+ this.tokenA = tokenA;
3213
+ this.tokenB = tokenB;
3214
+ assert(!tokenA.address.equal(tokenB.address), "tokens must be different");
3215
+ }
3216
+ get tokenLt() {
3217
+ return this.tokenA.address.lt(this.tokenB.address) ? this.tokenA : this.tokenB;
3218
+ }
3219
+ get tokenGt() {
3220
+ return this.tokenA.address.lt(this.tokenB.address) ? this.tokenB : this.tokenA;
3221
+ }
3222
+ static new(args) {
3223
+ return new PeggedSwapCalculator(args.tokenA, args.tokenB);
3224
+ }
3225
+ /**
3226
+ * Initial balances before deployment (`currentReserve = initialReserve`, u = v = 1).
3227
+ * Given spot price and one raw initial reserve, returns the other.
3228
+ */
3229
+ computeFixedAllocation(spotPrice, fixedReserveForToken, fixedReserve) {
3230
+ assert(fixedReserve > 0n, "fixed reserve must be positive");
3231
+ assert(spotPrice.matchesTokens(this.tokenLt.address, this.tokenGt.address), "spot price must match calculator token pair");
3232
+ const marginalE18 = spotPrice.toGtPerLtE18();
3233
+ if (fixedReserveForToken.equal(this.tokenLt.address)) return {
3234
+ reserveLt: fixedReserve,
3235
+ reserveGt: fixedReserve * marginalE18 / MARGINAL_PRICE_ONE$1
3236
+ };
3237
+ if (fixedReserveForToken.equal(this.tokenGt.address)) return {
3238
+ reserveLt: fixedReserve * MARGINAL_PRICE_ONE$1 / marginalE18,
3239
+ reserveGt: fixedReserve
3240
+ };
3241
+ throw new Error("fixedReserveForToken token must be one of the two pair tokens");
3242
+ }
3243
+ };
3244
+
3245
+ //#endregion
3246
+ //#region src/swap-vm/instructions/pegged-swap/pegged-swap-math/pegged-swap-math.ts
3247
+ /** Matches `PeggedSwapMath.ONE` in swap-vm. */
3248
+ const PEGGED_SWAP_ONE = 10n ** 27n;
3249
+ const MARGINAL_PRICE_ONE = 10n ** 18n;
3250
+ /**
3251
+ * Spot price tokenGt per tokenLt (raw) in 1e18 fixed-point.
3252
+ *
3253
+ * P = (Y₀/X₀) · (1/(2√u) + A) / (1/(2√v) + A) · (rateLt/rateGt)
3254
+ *
3255
+ * where u = x·ONE/X₀, v = y·ONE/Y₀, x/y are rate-adjusted Lt/Gt balances, A = `linearWidth`.
3256
+ */
3257
+ function peggedSwapMarginalGtPerLtE18(balanceLtNorm, balanceGtNorm, x0, y0, linearWidth, rateLt, rateGt) {
3258
+ const u = normalizeReserve(balanceLtNorm, x0);
3259
+ const v = normalizeReserve(balanceGtNorm, y0);
3260
+ assert(u !== 0n && v !== 0n, "PeggedSwapMath: reserves cannot be zero");
3261
+ const slopeLt = peggedSwapMarginalWeight(bigintSqrt(u * PEGGED_SWAP_ONE), linearWidth);
3262
+ const slopeGt = peggedSwapMarginalWeight(bigintSqrt(v * PEGGED_SWAP_ONE), linearWidth);
3263
+ return y0 * slopeLt * rateLt * MARGINAL_PRICE_ONE / (x0 * slopeGt * rateGt);
3264
+ }
3265
+ /**
3266
+ * u = x·ONE/X₀, v = y·ONE/Y₀ (x, y are rate-adjusted reserves).
3267
+ */
3268
+ function normalizeReserve(currentReserve, initialReserve) {
3269
+ return mulDiv(currentReserve, PEGGED_SWAP_ONE, initialReserve);
3270
+ }
3271
+ /**
3272
+ * Marginal weight `1/(2√u) + A` (Lt side) or `1/(2√v) + A` (Gt side), A = `linearWidth`.
3273
+ */
3274
+ function peggedSwapMarginalWeight(sqrtCoord, linearWidth) {
3275
+ return mulDiv(PEGGED_SWAP_ONE, PEGGED_SWAP_ONE, 2n * sqrtCoord) + linearWidth;
3276
+ }
3277
+ function mulDiv(a, b, c) {
3278
+ if (c === 0n) throw new Error("mulDiv: division by zero");
3279
+ return a * b / c;
3280
+ }
3281
+
3282
+ //#endregion
3283
+ //#region src/swap-vm/instructions/pegged-swap/price/pegged-price.ts
3284
+ const ONE_E18 = 10n ** 18n;
3285
+ var PeggedPrice = class PeggedPrice {
3286
+ constructor(gtPerLtRaw, tokenLt, tokenGt) {
3287
+ this.gtPerLtRaw = gtPerLtRaw;
3288
+ this.tokenLt = tokenLt;
3289
+ this.tokenGt = tokenGt;
3290
+ assert(gtPerLtRaw > 0n, "price must be positive");
3291
+ assert(tokenLt.address.lt(tokenGt.address), "internal pair order violated");
3292
+ }
3293
+ /**
3294
+ * Spot price from per-token `initialReserve` / `currentReserve` (raw, not rate-scaled) and `linearWidth`.
3295
+ * Use currentReserve = initialReserve to calculate the spot price before the strategy was deployed
3296
+ */
3297
+ static fromReserves(input) {
3298
+ assert(input.reserveA.currentReserve > 0n && input.reserveB.currentReserve > 0n, "current reserves should be positive");
3299
+ assert(input.reserveA.initialReserve > 0n && input.reserveB.initialReserve > 0n, "initial reserves should be positive");
3300
+ const zeroForOne = input.reserveA.address.lt(input.reserveB.address);
3301
+ const reserveLt = zeroForOne ? input.reserveA : input.reserveB;
3302
+ const reserveGt = zeroForOne ? input.reserveB : input.reserveA;
3303
+ const rateLt = resolveRate(reserveLt.decimals, reserveGt.decimals);
3304
+ const rateGt = resolveRate(reserveGt.decimals, reserveLt.decimals);
3305
+ const initialLtNorm = reserveLt.initialReserve * rateLt;
3306
+ const initialGtNorm = reserveGt.initialReserve * rateGt;
3307
+ const marginalE18 = peggedSwapMarginalGtPerLtE18(reserveLt.currentReserve * rateLt, reserveGt.currentReserve * rateGt, initialLtNorm, initialGtNorm, input.linearWidth, rateLt, rateGt);
3308
+ return PeggedPrice.fromGtPerLtE18(marginalE18, reserveLt, reserveGt);
3309
+ }
3310
+ /**
3311
+ * Human decimal string for **quote per 1 base**.
3312
+ */
3313
+ static fromHuman(price, pair) {
3314
+ assert(!pair.quoteToken.address.equal(pair.baseToken.address), "quote and base must be different tokens");
3315
+ const quoteToBase = pair.quoteToken.address.lt(pair.baseToken.address);
3316
+ const tokenLt = quoteToBase ? pair.quoteToken : pair.baseToken;
3317
+ const tokenGt = quoteToBase ? pair.baseToken : pair.quoteToken;
3318
+ const parsed = parseUnits(price.trim(), Number(pair.quoteToken.decimals));
3319
+ const ltDecimals = BigInt(tokenLt.decimals);
3320
+ const gtDecimals = BigInt(tokenGt.decimals);
3321
+ const marginalE18 = quoteToBase ? 10n ** (gtDecimals + 18n + ltDecimals) / (parsed * 10n ** gtDecimals) : parsed * ONE_E18 / 10n ** ltDecimals;
3322
+ return PeggedPrice.fromGtPerLtE18(marginalE18, tokenLt, tokenGt);
3323
+ }
3324
+ static fromJSON(input) {
3325
+ const tokenLt = {
3326
+ address: new Address$1(input.tokenLt.address),
3327
+ decimals: Number(input.tokenLt.decimals)
3328
+ };
3329
+ const tokenGt = {
3330
+ address: new Address$1(input.tokenGt.address),
3331
+ decimals: Number(input.tokenGt.decimals)
3332
+ };
3333
+ assert(tokenLt.address.lt(tokenGt.address), "tokenLt address must be less than tokenGt (canonical order)");
3334
+ return new PeggedPrice(BigInt(input.gtPerLtRaw), tokenLt, tokenGt);
3335
+ }
3336
+ static fromGtPerLtE18(marginalGtPerLtE18, tokenLt, tokenGt) {
3337
+ assert(marginalGtPerLtE18 > 0n, "marginal rate must be positive");
3338
+ const scale = BigInt(tokenLt.decimals + tokenGt.decimals);
3339
+ const gtPerLtRaw = marginalGtPerLtE18 * 10n ** scale / ONE_E18;
3340
+ return new PeggedPrice(gtPerLtRaw, tokenLt, tokenGt);
3341
+ }
3342
+ matchesTokens(tokenA, tokenB) {
3343
+ return tokenA.equal(this.tokenLt.address) && tokenB.equal(this.tokenGt.address) || tokenA.equal(this.tokenGt.address) && tokenB.equal(this.tokenLt.address);
3344
+ }
3345
+ equals(other) {
3346
+ return this.gtPerLtRaw === other.gtPerLtRaw && this.tokenLt.address.equal(other.tokenLt.address) && this.tokenGt.address.equal(other.tokenGt.address) && BigInt(this.tokenLt.decimals) === BigInt(other.tokenLt.decimals) && BigInt(this.tokenGt.decimals) === BigInt(other.tokenGt.decimals);
3347
+ }
3348
+ /**
3349
+ * Decimal string for **quote per 1 base**; rounded half-up to quote token decimals.
3350
+ */
3351
+ toHuman(quoteToken) {
3352
+ assert(quoteToken.equal(this.tokenLt.address) || quoteToken.equal(this.tokenGt.address), "quote token must be one of the pair tokens");
3353
+ const isQuoteLt = quoteToken.equal(this.tokenLt.address);
3354
+ const quoteDecimals = isQuoteLt ? this.tokenLt.decimals : this.tokenGt.decimals;
3355
+ const ltDecimals = BigInt(this.tokenLt.decimals);
3356
+ const gtDecimals = BigInt(this.tokenGt.decimals);
3357
+ const marginalE18 = this.toGtPerLtE18();
3358
+ const scaled = quoteToken.equal(this.tokenGt.address) ? marginalE18 * 10n ** ltDecimals / ONE_E18 : 10n ** (gtDecimals + 18n + ltDecimals) / (marginalE18 * 10n ** gtDecimals);
3359
+ const full = formatUnits(scaled, Number(quoteDecimals));
3360
+ return truncateHumanDecimalString(full, Number(quoteDecimals));
3361
+ }
3362
+ /** Marginal gt-per-lt rate in 1e18 fixed-point. */
3363
+ toGtPerLtE18() {
3364
+ const scale = BigInt(this.tokenLt.decimals + this.tokenGt.decimals);
3365
+ return this.gtPerLtRaw * ONE_E18 / 10n ** scale;
3366
+ }
3367
+ toJSON() {
3368
+ return {
3369
+ gtPerLtRaw: this.gtPerLtRaw.toString(),
3370
+ tokenLt: {
3371
+ address: this.tokenLt.address.toString(),
3372
+ decimals: String(this.tokenLt.decimals)
3373
+ },
3374
+ tokenGt: {
3375
+ address: this.tokenGt.address.toString(),
3376
+ decimals: String(this.tokenGt.decimals)
3377
+ }
3378
+ };
3379
+ }
3380
+ };
3381
+
3207
3382
  //#endregion
3208
3383
  //#region src/swap-vm/instructions/pegged-swap/index.ts
3209
3384
  var pegged_swap_exports = {};
3210
3385
  __export(pegged_swap_exports, {
3386
+ PeggedPrice: () => PeggedPrice,
3211
3387
  PeggedSwapArgs: () => PeggedSwapArgs,
3388
+ PeggedSwapCalculator: () => PeggedSwapCalculator,
3212
3389
  peggedSwapGrowPriceRange2D: () => peggedSwapGrowPriceRange2D
3213
3390
  });
3214
3391
 
@@ -3314,6 +3491,7 @@ __export(instructions_exports, {
3314
3491
  aquaInstructions: () => aquaInstructions,
3315
3492
  balances: () => balances_exports,
3316
3493
  baseFeeAdjuster: () => base_fee_adjuster_exports,
3494
+ bigintSqrt: () => bigintSqrt,
3317
3495
  concentrate: () => concentrate_exports,
3318
3496
  controls: () => controls_exports,
3319
3497
  decay: () => decay_exports,
@@ -3326,6 +3504,7 @@ __export(instructions_exports, {
3326
3504
  oraclePriceAdjuster: () => oracle_price_adjuster_exports,
3327
3505
  peggedSwap: () => pegged_swap_exports,
3328
3506
  stableSwap: () => pegged_swap_exports,
3507
+ truncateHumanDecimalString: () => truncateHumanDecimalString,
3329
3508
  twapSwap: () => twap_swap_exports,
3330
3509
  xycSwap: () => xyc_swap_exports
3331
3510
  });
@@ -8,4 +8,4 @@ export type { PriceRangeJSON } from './price-range';
8
8
  export { TokenReserve } from './token-reserve';
9
9
  export type { TokenReserveArgs, TokenReserveJSON } from './token-reserve';
10
10
  export type { ConcentrateTokenInfo, ConcentrateLiquidityCalculatorArgs, PriceAllocationRange, PriceBounds, ConcentratedLiquidityInfo, } from './concentrate-liquidity-calculator/types';
11
- export * from './bigint-sqrt';
11
+ export { bigintSqrt } from '../utils/bigint-sqrt';
@@ -8,4 +8,4 @@ export type { PriceRangeJSON } from './price-range';
8
8
  export { TokenReserve } from './token-reserve';
9
9
  export type { TokenReserveArgs, TokenReserveJSON } from './token-reserve';
10
10
  export type { ConcentrateTokenInfo, ConcentrateLiquidityCalculatorArgs, PriceAllocationRange, PriceBounds, ConcentratedLiquidityInfo, } from './concentrate-liquidity-calculator/types';
11
- export * from './bigint-sqrt';
11
+ export { bigintSqrt } from '../utils/bigint-sqrt';
@@ -1,3 +1,3 @@
1
1
  export { Price } from './price';
2
- export { truncateHumanDecimalString } from './truncate-human-decimal-string';
2
+ export { truncateHumanDecimalString } from '../../utils/truncate-human-decimal-string';
3
3
  export type { PriceJSON, PricePair, PriceToken } from './types';
@@ -1,3 +1,3 @@
1
1
  export { Price } from './price';
2
- export { truncateHumanDecimalString } from './truncate-human-decimal-string';
2
+ export { truncateHumanDecimalString } from '../../utils/truncate-human-decimal-string';
3
3
  export type { PriceJSON, PricePair, PriceToken } from './types';
@@ -1,6 +1,7 @@
1
1
  import type { Opcode } from './opcode';
2
2
  import type { IArgsData } from './types';
3
3
  export * from './types';
4
+ export { bigintSqrt, truncateHumanDecimalString } from './utils';
4
5
  export { EMPTY_OPCODE } from './empty';
5
6
  export * as balances from './balances';
6
7
  export * as controls from './controls';
@@ -1,6 +1,7 @@
1
1
  import type { Opcode } from './opcode';
2
2
  import type { IArgsData } from './types';
3
3
  export * from './types';
4
+ export { bigintSqrt, truncateHumanDecimalString } from './utils';
4
5
  export { EMPTY_OPCODE } from './empty';
5
6
  export * as balances from './balances';
6
7
  export * as controls from './controls';
@@ -1,3 +1,7 @@
1
1
  export * from './opcodes';
2
2
  export { PeggedSwapArgs } from './pegged-swap-args';
3
3
  export type { PeggedTokenInfo } from './types';
4
+ export { PeggedSwapCalculator } from './pegged-swap-calculator';
5
+ export { PeggedPrice } from './price';
6
+ export type { PeggedInitialBalances, PeggedSwapCalculatorArgs } from './pegged-swap-calculator';
7
+ export type { PeggedPriceJSON, PeggedPricePair, PeggedReservesInput, PeggedTokenRef, PeggedTokenReserve, } from './price';
@@ -1,3 +1,7 @@
1
1
  export * from './opcodes';
2
2
  export { PeggedSwapArgs } from './pegged-swap-args';
3
3
  export type { PeggedTokenInfo } from './types';
4
+ export { PeggedSwapCalculator } from './pegged-swap-calculator';
5
+ export { PeggedPrice } from './price';
6
+ export type { PeggedInitialBalances, PeggedSwapCalculatorArgs } from './pegged-swap-calculator';
7
+ export type { PeggedPriceJSON, PeggedPricePair, PeggedReservesInput, PeggedTokenRef, PeggedTokenReserve, } from './price';
@@ -0,0 +1,2 @@
1
+ export { PeggedSwapCalculator } from './pegged-swap-calculator';
2
+ export type { PeggedInitialBalances, PeggedSwapCalculatorArgs } from './types';
@@ -0,0 +1,2 @@
1
+ export { PeggedSwapCalculator } from './pegged-swap-calculator';
2
+ export type { PeggedInitialBalances, PeggedSwapCalculatorArgs } from './types';
@@ -0,0 +1,16 @@
1
+ import type { Address } from '@1inch/sdk-core';
2
+ import type { PeggedInitialBalances, PeggedSwapCalculatorArgs } from './types';
3
+ import type { PeggedPrice, PeggedTokenRef } from '../price';
4
+ export declare class PeggedSwapCalculator {
5
+ private readonly tokenA;
6
+ private readonly tokenB;
7
+ constructor(tokenA: PeggedTokenRef, tokenB: PeggedTokenRef);
8
+ get tokenLt(): PeggedTokenRef;
9
+ get tokenGt(): PeggedTokenRef;
10
+ static new(args: PeggedSwapCalculatorArgs): PeggedSwapCalculator;
11
+ /**
12
+ * Initial balances before deployment (`currentReserve = initialReserve`, u = v = 1).
13
+ * Given spot price and one raw initial reserve, returns the other.
14
+ */
15
+ computeFixedAllocation(spotPrice: PeggedPrice, fixedReserveForToken: Address, fixedReserve: bigint): PeggedInitialBalances;
16
+ }
@@ -0,0 +1,16 @@
1
+ import type { Address } from '@1inch/sdk-core';
2
+ import type { PeggedInitialBalances, PeggedSwapCalculatorArgs } from './types';
3
+ import type { PeggedPrice, PeggedTokenRef } from '../price';
4
+ export declare class PeggedSwapCalculator {
5
+ private readonly tokenA;
6
+ private readonly tokenB;
7
+ constructor(tokenA: PeggedTokenRef, tokenB: PeggedTokenRef);
8
+ get tokenLt(): PeggedTokenRef;
9
+ get tokenGt(): PeggedTokenRef;
10
+ static new(args: PeggedSwapCalculatorArgs): PeggedSwapCalculator;
11
+ /**
12
+ * Initial balances before deployment (`currentReserve = initialReserve`, u = v = 1).
13
+ * Given spot price and one raw initial reserve, returns the other.
14
+ */
15
+ computeFixedAllocation(spotPrice: PeggedPrice, fixedReserveForToken: Address, fixedReserve: bigint): PeggedInitialBalances;
16
+ }
@@ -0,0 +1,9 @@
1
+ import type { PeggedTokenRef } from '../price/types';
2
+ export type PeggedSwapCalculatorArgs = {
3
+ tokenA: PeggedTokenRef;
4
+ tokenB: PeggedTokenRef;
5
+ };
6
+ export type PeggedInitialBalances = {
7
+ reserveLt: bigint;
8
+ reserveGt: bigint;
9
+ };
@@ -0,0 +1,9 @@
1
+ import type { PeggedTokenRef } from '../price/types';
2
+ export type PeggedSwapCalculatorArgs = {
3
+ tokenA: PeggedTokenRef;
4
+ tokenB: PeggedTokenRef;
5
+ };
6
+ export type PeggedInitialBalances = {
7
+ reserveLt: bigint;
8
+ reserveGt: bigint;
9
+ };
@@ -0,0 +1,18 @@
1
+ /** Matches `PeggedSwapMath.ONE` in swap-vm. */
2
+ export declare const PEGGED_SWAP_ONE: bigint;
3
+ /**
4
+ * Spot price tokenGt per tokenLt (raw) in 1e18 fixed-point.
5
+ *
6
+ * P = (Y₀/X₀) · (1/(2√u) + A) / (1/(2√v) + A) · (rateLt/rateGt)
7
+ *
8
+ * where u = x·ONE/X₀, v = y·ONE/Y₀, x/y are rate-adjusted Lt/Gt balances, A = `linearWidth`.
9
+ */
10
+ export declare function peggedSwapMarginalGtPerLtE18(balanceLtNorm: bigint, balanceGtNorm: bigint, x0: bigint, y0: bigint, linearWidth: bigint, rateLt: bigint, rateGt: bigint): bigint;
11
+ /**
12
+ * u = x·ONE/X₀, v = y·ONE/Y₀ (x, y are rate-adjusted reserves).
13
+ */
14
+ export declare function normalizeReserve(currentReserve: bigint, initialReserve: bigint): bigint;
15
+ /**
16
+ * Marginal weight `1/(2√u) + A` (Lt side) or `1/(2√v) + A` (Gt side), A = `linearWidth`.
17
+ */
18
+ export declare function peggedSwapMarginalWeight(sqrtCoord: bigint, linearWidth: bigint): bigint;
@@ -0,0 +1,18 @@
1
+ /** Matches `PeggedSwapMath.ONE` in swap-vm. */
2
+ export declare const PEGGED_SWAP_ONE: bigint;
3
+ /**
4
+ * Spot price tokenGt per tokenLt (raw) in 1e18 fixed-point.
5
+ *
6
+ * P = (Y₀/X₀) · (1/(2√u) + A) / (1/(2√v) + A) · (rateLt/rateGt)
7
+ *
8
+ * where u = x·ONE/X₀, v = y·ONE/Y₀, x/y are rate-adjusted Lt/Gt balances, A = `linearWidth`.
9
+ */
10
+ export declare function peggedSwapMarginalGtPerLtE18(balanceLtNorm: bigint, balanceGtNorm: bigint, x0: bigint, y0: bigint, linearWidth: bigint, rateLt: bigint, rateGt: bigint): bigint;
11
+ /**
12
+ * u = x·ONE/X₀, v = y·ONE/Y₀ (x, y are rate-adjusted reserves).
13
+ */
14
+ export declare function normalizeReserve(currentReserve: bigint, initialReserve: bigint): bigint;
15
+ /**
16
+ * Marginal weight `1/(2√u) + A` (Lt side) or `1/(2√v) + A` (Gt side), A = `linearWidth`.
17
+ */
18
+ export declare function peggedSwapMarginalWeight(sqrtCoord: bigint, linearWidth: bigint): bigint;
@@ -0,0 +1,2 @@
1
+ export { PeggedPrice } from './pegged-price';
2
+ export type { PeggedPriceJSON, PeggedPricePair, PeggedReservesInput, PeggedTokenRef, PeggedTokenReserve, } from './types';
@@ -0,0 +1,2 @@
1
+ export { PeggedPrice } from './pegged-price';
2
+ export type { PeggedPriceJSON, PeggedPricePair, PeggedReservesInput, PeggedTokenRef, PeggedTokenReserve, } from './types';
@@ -0,0 +1,28 @@
1
+ import { Address } from '@1inch/sdk-core';
2
+ import type { PeggedPriceJSON, PeggedPricePair, PeggedReservesInput, PeggedTokenRef } from './types';
3
+ export declare class PeggedPrice {
4
+ private readonly gtPerLtRaw;
5
+ readonly tokenLt: PeggedTokenRef;
6
+ readonly tokenGt: PeggedTokenRef;
7
+ private constructor();
8
+ /**
9
+ * Spot price from per-token `initialReserve` / `currentReserve` (raw, not rate-scaled) and `linearWidth`.
10
+ * Use currentReserve = initialReserve to calculate the spot price before the strategy was deployed
11
+ */
12
+ static fromReserves(input: PeggedReservesInput): PeggedPrice;
13
+ /**
14
+ * Human decimal string for **quote per 1 base**.
15
+ */
16
+ static fromHuman(price: string, pair: PeggedPricePair): PeggedPrice;
17
+ static fromJSON(input: PeggedPriceJSON): PeggedPrice;
18
+ private static fromGtPerLtE18;
19
+ matchesTokens(tokenA: Address, tokenB: Address): boolean;
20
+ equals(other: PeggedPrice): boolean;
21
+ /**
22
+ * Decimal string for **quote per 1 base**; rounded half-up to quote token decimals.
23
+ */
24
+ toHuman(quoteToken: Address): string;
25
+ /** Marginal gt-per-lt rate in 1e18 fixed-point. */
26
+ toGtPerLtE18(): bigint;
27
+ toJSON(): PeggedPriceJSON;
28
+ }
@@ -0,0 +1,28 @@
1
+ import { Address } from '@1inch/sdk-core';
2
+ import type { PeggedPriceJSON, PeggedPricePair, PeggedReservesInput, PeggedTokenRef } from './types';
3
+ export declare class PeggedPrice {
4
+ private readonly gtPerLtRaw;
5
+ readonly tokenLt: PeggedTokenRef;
6
+ readonly tokenGt: PeggedTokenRef;
7
+ private constructor();
8
+ /**
9
+ * Spot price from per-token `initialReserve` / `currentReserve` (raw, not rate-scaled) and `linearWidth`.
10
+ * Use currentReserve = initialReserve to calculate the spot price before the strategy was deployed
11
+ */
12
+ static fromReserves(input: PeggedReservesInput): PeggedPrice;
13
+ /**
14
+ * Human decimal string for **quote per 1 base**.
15
+ */
16
+ static fromHuman(price: string, pair: PeggedPricePair): PeggedPrice;
17
+ static fromJSON(input: PeggedPriceJSON): PeggedPrice;
18
+ private static fromGtPerLtE18;
19
+ matchesTokens(tokenA: Address, tokenB: Address): boolean;
20
+ equals(other: PeggedPrice): boolean;
21
+ /**
22
+ * Decimal string for **quote per 1 base**; rounded half-up to quote token decimals.
23
+ */
24
+ toHuman(quoteToken: Address): string;
25
+ /** Marginal gt-per-lt rate in 1e18 fixed-point. */
26
+ toGtPerLtE18(): bigint;
27
+ toJSON(): PeggedPriceJSON;
28
+ }
@@ -0,0 +1,30 @@
1
+ import type { Address } from '@1inch/sdk-core';
2
+ export type PeggedTokenRef = {
3
+ address: Address;
4
+ decimals: number;
5
+ };
6
+ export type PeggedPricePair = {
7
+ quoteToken: PeggedTokenRef;
8
+ baseToken: PeggedTokenRef;
9
+ };
10
+ export type PeggedTokenReserve = PeggedTokenRef & {
11
+ initialReserve: bigint;
12
+ currentReserve: bigint;
13
+ };
14
+ export type PeggedReservesInput = {
15
+ reserveA: PeggedTokenReserve;
16
+ reserveB: PeggedTokenReserve;
17
+ linearWidth: bigint;
18
+ };
19
+ /** Snapshot from `PeggedPrice.prototype.toJSON` (bigints as decimal strings). */
20
+ export type PeggedPriceJSON = {
21
+ gtPerLtRaw: string;
22
+ tokenLt: {
23
+ address: string;
24
+ decimals: string;
25
+ };
26
+ tokenGt: {
27
+ address: string;
28
+ decimals: string;
29
+ };
30
+ };
@@ -0,0 +1,30 @@
1
+ import type { Address } from '@1inch/sdk-core';
2
+ export type PeggedTokenRef = {
3
+ address: Address;
4
+ decimals: number;
5
+ };
6
+ export type PeggedPricePair = {
7
+ quoteToken: PeggedTokenRef;
8
+ baseToken: PeggedTokenRef;
9
+ };
10
+ export type PeggedTokenReserve = PeggedTokenRef & {
11
+ initialReserve: bigint;
12
+ currentReserve: bigint;
13
+ };
14
+ export type PeggedReservesInput = {
15
+ reserveA: PeggedTokenReserve;
16
+ reserveB: PeggedTokenReserve;
17
+ linearWidth: bigint;
18
+ };
19
+ /** Snapshot from `PeggedPrice.prototype.toJSON` (bigints as decimal strings). */
20
+ export type PeggedPriceJSON = {
21
+ gtPerLtRaw: string;
22
+ tokenLt: {
23
+ address: string;
24
+ decimals: string;
25
+ };
26
+ tokenGt: {
27
+ address: string;
28
+ decimals: string;
29
+ };
30
+ };
@@ -0,0 +1,2 @@
1
+ export { bigintSqrt } from './bigint-sqrt';
2
+ export { truncateHumanDecimalString } from './truncate-human-decimal-string';
@@ -0,0 +1,2 @@
1
+ export { bigintSqrt } from './bigint-sqrt';
2
+ export { truncateHumanDecimalString } from './truncate-human-decimal-string';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@1inch/swap-vm-sdk",
3
- "version": "0.1.2-rc.7",
3
+ "version": "0.1.3",
4
4
  "description": "1inch Swap VM SDK",
5
5
  "author": "@1inch",
6
6
  "license": "LicenseRef-Degensoft-SwapVM-1.1",
@@ -42,11 +42,11 @@
42
42
  "@1inch/sdk-core": "0.1.2"
43
43
  },
44
44
  "devDependencies": {
45
- "@types/node": "^22.13.0",
45
+ "@types/node": "^22.19.17",
46
46
  "dotenv": "17.2.3",
47
- "eslint-plugin-license-header": "0.8.0",
47
+ "eslint-plugin-license-header": "0.9.0",
48
48
  "tsdown": "^0.2.17",
49
- "typescript": "^5.7.3",
49
+ "typescript": "^5.9.3",
50
50
  "vitest": "^3.2.4"
51
51
  },
52
52
  "volta": {