@flaunch/sdk 0.9.6 → 0.9.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -836,6 +836,20 @@ const calls = addLiqCalls.map((call) => ({
836
836
  await sendCalls({ calls });
837
837
  ```
838
838
 
839
+ 3. **Single-Sided Coin Liquidity (Current Price to Infinity)**
840
+
841
+ You can easily provide single-sided coin liquidity from the current price to infinity.
842
+
843
+ ```ts
844
+ const singleSidedCalls = await flaunchWrite.getSingleSidedCoinAddLiquidityCalls(
845
+ {
846
+ coinAddress: "0x...", // Token contract address
847
+ coinAmount: parseEther("1000000"), // Amount of coins to provide as liquidity
848
+ version: FlaunchVersion.V1_2, // optional (auto-determines if not provided)
849
+ }
850
+ );
851
+ ```
852
+
839
853
  ### Import AND Add Liquidity calls in a single batch
840
854
 
841
855
  1. This allows an external coin to be live on flaunch, and be tradeable instantly with the liquidity being provided in the same transaction batch.
package/dist/index.cjs.js CHANGED
@@ -25467,6 +25467,10 @@ function maxLiquidityForAmount0Precise(sqrtRatioAX96, sqrtRatioBX96, amount0) {
25467
25467
  if (sqrtRatioAX96 > sqrtRatioBX96) {
25468
25468
  [sqrtRatioAX96, sqrtRatioBX96] = [sqrtRatioBX96, sqrtRatioAX96];
25469
25469
  }
25470
+ // Handle edge case where sqrt ratios are equal (division by zero)
25471
+ if (sqrtRatioAX96 === sqrtRatioBX96) {
25472
+ return 0n;
25473
+ }
25470
25474
  const Q96 = 2n ** 96n;
25471
25475
  const numerator = amount0 * sqrtRatioAX96 * sqrtRatioBX96;
25472
25476
  const denominator = Q96 * (sqrtRatioBX96 - sqrtRatioAX96);
@@ -25483,6 +25487,10 @@ function maxLiquidityForAmount1(sqrtRatioAX96, sqrtRatioBX96, amount1) {
25483
25487
  if (sqrtRatioAX96 > sqrtRatioBX96) {
25484
25488
  [sqrtRatioAX96, sqrtRatioBX96] = [sqrtRatioBX96, sqrtRatioAX96];
25485
25489
  }
25490
+ // Handle edge case where sqrt ratios are equal (division by zero)
25491
+ if (sqrtRatioAX96 === sqrtRatioBX96) {
25492
+ return 0n;
25493
+ }
25486
25494
  const Q96 = 2n ** 96n;
25487
25495
  return (amount1 * Q96) / (sqrtRatioBX96 - sqrtRatioAX96);
25488
25496
  }
@@ -26394,7 +26402,7 @@ class ReadFlaunchSDK {
26394
26402
  * @returns Promise<number> - The current tick of the pool
26395
26403
  */
26396
26404
  async currentTick(coinAddress, version) {
26397
- const coinVersion = version || (await this.getCoinVersion(coinAddress));
26405
+ const coinVersion = await this.determineCoinVersion(coinAddress, version);
26398
26406
  const poolId = await this.poolId(coinAddress, coinVersion);
26399
26407
  const poolState = await this.readStateView.poolSlot0({ poolId });
26400
26408
  return poolState.tick;
@@ -26406,7 +26414,7 @@ class ReadFlaunchSDK {
26406
26414
  * @returns Promise<string> - The price of the coin in ETH with 18 decimals precision
26407
26415
  */
26408
26416
  async coinPriceInETH(coinAddress, version) {
26409
- const coinVersion = version || (await this.getCoinVersion(coinAddress));
26417
+ const coinVersion = await this.determineCoinVersion(coinAddress, version);
26410
26418
  const isFLETHZero = this.flETHIsCurrencyZero(coinAddress);
26411
26419
  const currentTick = await this.currentTick(coinAddress, coinVersion);
26412
26420
  const price = Math.pow(1.0001, currentTick);
@@ -26426,7 +26434,7 @@ class ReadFlaunchSDK {
26426
26434
  * @returns Promise<string> - The price of the coin in USD with 18 decimal precision
26427
26435
  */
26428
26436
  async coinPriceInUSD({ coinAddress, version, drift, }) {
26429
- const coinVersion = version || (await this.getCoinVersion(coinAddress));
26437
+ const coinVersion = await this.determineCoinVersion(coinAddress, version);
26430
26438
  const ethPerCoin = await this.coinPriceInETH(coinAddress, coinVersion);
26431
26439
  const ethPrice = await this.getETHUSDCPrice(drift);
26432
26440
  return (parseFloat(ethPerCoin) * ethPrice).toFixed(18);
@@ -26474,7 +26482,7 @@ class ReadFlaunchSDK {
26474
26482
  * @returns Fair launch information from the appropriate contract version
26475
26483
  */
26476
26484
  async fairLaunchInfo(coinAddress, version) {
26477
- const coinVersion = version || (await this.getCoinVersion(coinAddress));
26485
+ const coinVersion = await this.determineCoinVersion(coinAddress, version);
26478
26486
  const poolId = await this.poolId(coinAddress, coinVersion);
26479
26487
  return this.getFairLaunch(coinVersion).fairLaunchInfo({ poolId });
26480
26488
  }
@@ -26485,12 +26493,12 @@ class ReadFlaunchSDK {
26485
26493
  * @returns Promise<boolean> - True if fair launch is active, false otherwise
26486
26494
  */
26487
26495
  async isFairLaunchActive(coinAddress, version) {
26488
- const coinVersion = version || (await this.getCoinVersion(coinAddress));
26496
+ const coinVersion = await this.determineCoinVersion(coinAddress, version);
26489
26497
  const poolId = await this.poolId(coinAddress, coinVersion);
26490
26498
  return this.getFairLaunch(coinVersion).isFairLaunchActive({ poolId });
26491
26499
  }
26492
26500
  async trustedPoolKeySignerStatus(coinAddress, version) {
26493
- const coinVersion = version || (await this.getCoinVersion(coinAddress));
26501
+ const coinVersion = await this.determineCoinVersion(coinAddress, version);
26494
26502
  if (coinVersion === exports.FlaunchVersion.ANY) {
26495
26503
  throw new Error("AnyPositionManager is not supported for TrustedSigner");
26496
26504
  }
@@ -26539,7 +26547,7 @@ class ReadFlaunchSDK {
26539
26547
  * @returns Promise<number> - The duration in seconds (30 minutes for V1, variable for V1.1)
26540
26548
  */
26541
26549
  async fairLaunchDuration(coinAddress, version) {
26542
- const coinVersion = version || (await this.getCoinVersion(coinAddress));
26550
+ const coinVersion = await this.determineCoinVersion(coinAddress, version);
26543
26551
  const poolId = await this.poolId(coinAddress, coinVersion);
26544
26552
  return this.getFairLaunch(coinVersion).fairLaunchDuration({ poolId });
26545
26553
  }
@@ -26550,7 +26558,7 @@ class ReadFlaunchSDK {
26550
26558
  * @returns Promise<number> - The initial tick value
26551
26559
  */
26552
26560
  async initialTick(coinAddress, version) {
26553
- const coinVersion = version || (await this.getCoinVersion(coinAddress));
26561
+ const coinVersion = await this.determineCoinVersion(coinAddress, version);
26554
26562
  const poolId = await this.poolId(coinAddress, coinVersion);
26555
26563
  const fairLaunchInfo = await this.getFairLaunch(coinVersion).fairLaunchInfo({ poolId });
26556
26564
  return fairLaunchInfo.initialTick;
@@ -26562,7 +26570,7 @@ class ReadFlaunchSDK {
26562
26570
  * @returns Promise<{flETHAmount: bigint, coinAmount: bigint, tickLower: number, tickUpper: number}> - Position details
26563
26571
  */
26564
26572
  async fairLaunchETHOnlyPosition(coinAddress, version) {
26565
- const coinVersion = version || (await this.getCoinVersion(coinAddress));
26573
+ const coinVersion = await this.determineCoinVersion(coinAddress, version);
26566
26574
  const poolId = await this.poolId(coinAddress, coinVersion);
26567
26575
  const initialTick = await this.initialTick(coinAddress, coinVersion);
26568
26576
  const currentTick = await this.currentTick(coinAddress, coinVersion);
@@ -26610,7 +26618,7 @@ class ReadFlaunchSDK {
26610
26618
  * @returns Promise<{flETHAmount: bigint, coinAmount: bigint, tickLower: number, tickUpper: number}> - Position details
26611
26619
  */
26612
26620
  async fairLaunchCoinOnlyPosition(coinAddress, version) {
26613
- const coinVersion = version || (await this.getCoinVersion(coinAddress));
26621
+ const coinVersion = await this.determineCoinVersion(coinAddress, version);
26614
26622
  const poolId = await this.poolId(coinAddress, coinVersion);
26615
26623
  const initialTick = await this.initialTick(coinAddress, coinVersion);
26616
26624
  const currentTick = await this.currentTick(coinAddress, coinVersion);
@@ -26658,7 +26666,7 @@ class ReadFlaunchSDK {
26658
26666
  * @returns Promise<{flETHAmount: bigint, coinAmount: bigint, pendingEth: bigint, tickLower: number, tickUpper: number}> - Bid wall position details
26659
26667
  */
26660
26668
  async bidWallPosition(coinAddress, version) {
26661
- const coinVersion = version || (await this.getCoinVersion(coinAddress));
26669
+ const coinVersion = await this.determineCoinVersion(coinAddress, version);
26662
26670
  const poolId = await this.poolId(coinAddress, coinVersion);
26663
26671
  const isFLETHZero = this.flETHIsCurrencyZero(coinAddress);
26664
26672
  const { amount0_: amount0, amount1_: amount1, pendingEth_: pendingEth, } = await this.getBidWall(coinVersion).position({ poolId });
@@ -26774,13 +26782,8 @@ class ReadFlaunchSDK {
26774
26782
  */
26775
26783
  async poolId(coinAddress, version) {
26776
26784
  let hookAddress;
26777
- if (version) {
26778
- hookAddress = this.getPositionManagerAddress(version);
26779
- }
26780
- else {
26781
- const coinVersion = await this.getCoinVersion(coinAddress);
26782
- hookAddress = this.getPositionManagerAddress(coinVersion);
26783
- }
26785
+ const coinVersion = await this.determineCoinVersion(coinAddress, version);
26786
+ hookAddress = this.getPositionManagerAddress(coinVersion);
26784
26787
  return getPoolId(orderPoolKey({
26785
26788
  currency0: FLETHAddress[this.chainId],
26786
26789
  currency1: coinAddress,
@@ -26838,7 +26841,7 @@ class ReadFlaunchSDK {
26838
26841
  * @returns Promise<bigint> - The expected amount of ETH to receive
26839
26842
  */
26840
26843
  async getSellQuoteExactInput({ coinAddress, version, amountIn, intermediatePoolKey, }) {
26841
- const coinVersion = version || (await this.getCoinVersion(coinAddress));
26844
+ const coinVersion = await this.determineCoinVersion(coinAddress, version);
26842
26845
  return this.readQuoter.getSellQuoteExactInput({
26843
26846
  coinAddress,
26844
26847
  amountIn,
@@ -26857,7 +26860,7 @@ class ReadFlaunchSDK {
26857
26860
  * @returns Promise<bigint> - The expected amount of coins to receive
26858
26861
  */
26859
26862
  async getBuyQuoteExactInput({ coinAddress, version, amountIn, intermediatePoolKey, hookData, userWallet, }) {
26860
- const coinVersion = version || (await this.getCoinVersion(coinAddress));
26863
+ const coinVersion = await this.determineCoinVersion(coinAddress, version);
26861
26864
  return this.readQuoter.getBuyQuoteExactInput({
26862
26865
  coinAddress,
26863
26866
  amountIn,
@@ -26878,7 +26881,7 @@ class ReadFlaunchSDK {
26878
26881
  * @returns Promise<bigint> - The required amount of ETH or inputToken to spend
26879
26882
  */
26880
26883
  async getBuyQuoteExactOutput({ coinAddress, amountOut, version, intermediatePoolKey, hookData, userWallet, }) {
26881
- const coinVersion = version || (await this.getCoinVersion(coinAddress));
26884
+ const coinVersion = await this.determineCoinVersion(coinAddress, version);
26882
26885
  return this.readQuoter.getBuyQuoteExactOutput({
26883
26886
  coinAddress,
26884
26887
  coinOut: amountOut,
@@ -27065,24 +27068,9 @@ class ReadFlaunchSDK {
27065
27068
  });
27066
27069
  // If no current tick is provided from the above calculation, get it from the pool state
27067
27070
  if (!currentTick) {
27068
- let version = params.version;
27069
- // if version is not provided, check on existing managers, else default to ANY
27070
- if (!version) {
27071
- try {
27072
- version = await this.getCoinVersion(coinAddress);
27073
- }
27074
- catch {
27075
- version = exports.FlaunchVersion.ANY;
27076
- }
27077
- }
27071
+ const version = await this.determineCoinVersion(coinAddress, params.version);
27078
27072
  const poolState = await this.readStateView.poolSlot0({
27079
- poolId: getPoolId(orderPoolKey({
27080
- currency0: coinAddress,
27081
- currency1: FLETHAddress[this.chainId],
27082
- fee: 0,
27083
- tickSpacing: TICK_SPACING,
27084
- hooks: this.getPositionManagerAddress(version),
27085
- })),
27073
+ poolId: getPoolId(this.createPoolKey(coinAddress, version)),
27086
27074
  });
27087
27075
  currentTick = poolState.tick;
27088
27076
  }
@@ -27156,24 +27144,9 @@ class ReadFlaunchSDK {
27156
27144
  });
27157
27145
  // get the current pool state for the coin
27158
27146
  if (!currentTick) {
27159
- let version = params.version;
27160
- // if version is not provided, check on existing managers, else default to ANY
27161
- if (!version) {
27162
- try {
27163
- version = await this.getCoinVersion(coinAddress);
27164
- }
27165
- catch {
27166
- version = exports.FlaunchVersion.ANY;
27167
- }
27168
- }
27147
+ const version = await this.determineCoinVersion(coinAddress, params.version);
27169
27148
  const poolState = await this.readStateView.poolSlot0({
27170
- poolId: getPoolId(orderPoolKey({
27171
- currency0: coinAddress,
27172
- currency1: FLETHAddress[this.chainId],
27173
- fee: 0,
27174
- tickSpacing: TICK_SPACING,
27175
- hooks: this.getPositionManagerAddress(version),
27176
- })),
27149
+ poolId: getPoolId(this.createPoolKey(coinAddress, version)),
27177
27150
  });
27178
27151
  currentTick = poolState.tick;
27179
27152
  }
@@ -27328,6 +27301,39 @@ class ReadFlaunchSDK {
27328
27301
  args: { owner, operator },
27329
27302
  });
27330
27303
  }
27304
+ /**
27305
+ * Determines the version for a coin, using provided version or fetching it
27306
+ * @param coinAddress - The coin address
27307
+ * @param version - Optional version, if not provided will be fetched
27308
+ * @returns The determined version
27309
+ */
27310
+ async determineCoinVersion(coinAddress, version) {
27311
+ if (!version) {
27312
+ try {
27313
+ version = await this.getCoinVersion(coinAddress);
27314
+ }
27315
+ catch {
27316
+ version = exports.FlaunchVersion.ANY;
27317
+ }
27318
+ }
27319
+ return version;
27320
+ }
27321
+ /**
27322
+ * Creates a pool key for the given coin and version
27323
+ * @param coinAddress - The coin address
27324
+ * @param version - The version to use for position manager
27325
+ * @returns The ordered pool key
27326
+ */
27327
+ createPoolKey(coinAddress, version) {
27328
+ const flethAddress = FLETHAddress[this.chainId];
27329
+ return orderPoolKey({
27330
+ currency0: coinAddress,
27331
+ currency1: flethAddress,
27332
+ fee: 0,
27333
+ tickSpacing: this.TICK_SPACING,
27334
+ hooks: this.getPositionManagerAddress(version),
27335
+ });
27336
+ }
27331
27337
  }
27332
27338
  class ReadWriteFlaunchSDK extends ReadFlaunchSDK {
27333
27339
  constructor(chainId, drift$1 = drift.createDrift(), publicClient) {
@@ -27452,7 +27458,7 @@ class ReadWriteFlaunchSDK extends ReadFlaunchSDK {
27452
27458
  * @returns Transaction response for the buy operation
27453
27459
  */
27454
27460
  async buyCoin(params, version) {
27455
- const coinVersion = version || (await this.getCoinVersion(params.coinAddress));
27461
+ const coinVersion = await this.determineCoinVersion(params.coinAddress, version);
27456
27462
  const sender = await this.drift.getSignerAddress();
27457
27463
  let amountIn;
27458
27464
  let amountOutMin;
@@ -27537,7 +27543,7 @@ class ReadWriteFlaunchSDK extends ReadFlaunchSDK {
27537
27543
  * @returns Transaction response for the sell operation
27538
27544
  */
27539
27545
  async sellCoin(params, version) {
27540
- const coinVersion = version || (await this.getCoinVersion(params.coinAddress));
27546
+ const coinVersion = await this.determineCoinVersion(params.coinAddress, version);
27541
27547
  let amountOutMin;
27542
27548
  await this.readQuoter.contract.cache.clear();
27543
27549
  if (params.amountOutMin === undefined) {
@@ -27760,22 +27766,8 @@ class ReadWriteFlaunchSDK extends ReadFlaunchSDK {
27760
27766
  let tickLower;
27761
27767
  let tickUpper;
27762
27768
  let currentTick;
27763
- let version = params.version;
27764
- if (!version) {
27765
- try {
27766
- version = await this.getCoinVersion(coinAddress);
27767
- }
27768
- catch {
27769
- version = exports.FlaunchVersion.ANY;
27770
- }
27771
- }
27772
- const poolKey = orderPoolKey({
27773
- currency0: coinAddress,
27774
- currency1: flethAddress,
27775
- fee: 0,
27776
- tickSpacing: this.TICK_SPACING,
27777
- hooks: this.getPositionManagerAddress(version),
27778
- });
27769
+ const version = await this.determineCoinVersion(coinAddress, params.version);
27770
+ const poolKey = this.createPoolKey(coinAddress, version);
27779
27771
  // Check if we need to calculate values or use direct values
27780
27772
  if ("tickLower" in params) {
27781
27773
  // Use the directly provided values
@@ -27973,6 +27965,173 @@ class ReadWriteFlaunchSDK extends ReadFlaunchSDK {
27973
27965
  // Determine amounts for each currency based on pool key ordering
27974
27966
  const amount0 = poolKey.currency0 === coinAddress ? coinAmount : flethAmount;
27975
27967
  const amount1 = poolKey.currency0 === coinAddress ? flethAmount : coinAmount;
27968
+ // Calculate and constrain liquidity using shared method
27969
+ const { finalLiquidity, finalAmount0, finalAmount1 } = this.calculateConstrainedLiquidity(currentTick, tickLower, tickUpper, amount0, amount1);
27970
+ // 6. Add liquidity
27971
+ calls.push(this.createLiquidityCall(poolKey, tickLower, tickUpper, finalLiquidity, finalAmount0, finalAmount1, userAddress));
27972
+ return calls;
27973
+ }
27974
+ /**
27975
+ * Gets the calls needed to import a memecoin to Flaunch and add liquidity to AnyPositionManager as a batch
27976
+ * @param params - Parameters for importing and adding liquidity
27977
+ * @returns Array of calls with descriptions
27978
+ */
27979
+ async getImportAndAddLiquidityCalls(params) {
27980
+ const importParams = await this.readWriteTokenImporter.getInitializeParams({
27981
+ coinAddress: params.coinAddress,
27982
+ creatorFeeAllocationPercent: params.creatorFeeAllocationPercent,
27983
+ initialMarketCapUSD: params.initialMarketCapUSD,
27984
+ verifier: params.verifier,
27985
+ });
27986
+ const addLiquidityCalls = await this.getAddLiquidityCalls({
27987
+ ...params,
27988
+ version: exports.FlaunchVersion.ANY, // optimize to avoid fetching if not passed
27989
+ });
27990
+ return [
27991
+ {
27992
+ to: this.readWriteTokenImporter.contract.address,
27993
+ data: this.readWriteTokenImporter.contract.encodeFunctionData("initialize", importParams),
27994
+ description: "Import Memecoin to Flaunch",
27995
+ },
27996
+ ...addLiquidityCalls,
27997
+ ];
27998
+ }
27999
+ /**
28000
+ * Gets the calls needed to add single-sided liquidity in coin from current tick to infinity
28001
+ * @param params - Parameters for adding single-sided liquidity
28002
+ * @returns Array of calls with descriptions
28003
+ */
28004
+ async getSingleSidedCoinAddLiquidityCalls(params) {
28005
+ const { coinAddress, coinAmount } = params;
28006
+ const version = await this.determineCoinVersion(coinAddress, params.version);
28007
+ const poolKey = this.createPoolKey(coinAddress, version);
28008
+ // get the current tick from the pool
28009
+ const poolState = await this.readStateView.poolSlot0({
28010
+ poolId: getPoolId(poolKey),
28011
+ });
28012
+ const currentTick = poolState.tick;
28013
+ // We want to add liquidity from current price to infinity (as coin appreciates vs flETH)
28014
+ // This means providing single-sided coin liquidity that becomes active as coin price increases
28015
+ const isFLETHZero = this.flETHIsCurrencyZero(coinAddress);
28016
+ let tickLower;
28017
+ let tickUpper;
28018
+ if (isFLETHZero) {
28019
+ // flETH is currency0, coin is currency1
28020
+ // Price = coin/flETH. As coin appreciates, price and tick increase.
28021
+ // For single-sided coin position, we need the range to end at current tick
28022
+ // so as price increases beyond current, position becomes coin-only
28023
+ tickLower = TickFinder.MIN_TICK;
28024
+ tickUpper = getValidTick({
28025
+ tick: currentTick,
28026
+ tickSpacing: this.TICK_SPACING,
28027
+ roundDown: true,
28028
+ });
28029
+ }
28030
+ else {
28031
+ // coin is currency0, flETH is currency1
28032
+ // Price = flETH/coin. As coin appreciates, price decreases and tick decreases.
28033
+ // For single-sided coin position, we need the range to start at current tick
28034
+ // so as price decreases below current, position becomes coin-only
28035
+ tickLower = getValidTick({
28036
+ tick: currentTick,
28037
+ tickSpacing: this.TICK_SPACING,
28038
+ roundDown: false,
28039
+ });
28040
+ tickUpper = TickFinder.MAX_TICK;
28041
+ }
28042
+ // Fetch approvals via multicall
28043
+ const userAddress = await this.drift.getSignerAddress();
28044
+ const permit2Address = Permit2Address[this.chainId];
28045
+ const results = await this.drift.multicall({
28046
+ calls: [
28047
+ // coin -> permit2
28048
+ {
28049
+ address: coinAddress,
28050
+ abi: viem.erc20Abi,
28051
+ fn: "allowance",
28052
+ args: {
28053
+ owner: userAddress,
28054
+ spender: permit2Address,
28055
+ },
28056
+ },
28057
+ // coin --permit2--> uni position manager
28058
+ {
28059
+ address: permit2Address,
28060
+ abi: Permit2Abi,
28061
+ fn: "allowance",
28062
+ args: {
28063
+ 0: userAddress,
28064
+ 1: coinAddress,
28065
+ 2: UniV4PositionManagerAddress[this.chainId],
28066
+ },
28067
+ },
28068
+ // coin symbol
28069
+ {
28070
+ address: coinAddress,
28071
+ abi: viem.erc20Abi,
28072
+ fn: "symbol",
28073
+ },
28074
+ ],
28075
+ });
28076
+ const coinToPermit2 = results[0].value;
28077
+ const permit2ToUniPosManagerCoinAllowance = results[1].value;
28078
+ const coinSymbol = results[2].value;
28079
+ const needsCoinApproval = coinToPermit2 < coinAmount;
28080
+ const currentTime = Math.floor(Date.now() / 1000);
28081
+ const needsCoinPermit2Approval = permit2ToUniPosManagerCoinAllowance.amount < coinAmount ||
28082
+ permit2ToUniPosManagerCoinAllowance.expiration <= currentTime;
28083
+ const calls = [];
28084
+ // 1. Coin approval to Permit2
28085
+ if (needsCoinApproval) {
28086
+ calls.push({
28087
+ to: coinAddress,
28088
+ description: `Approve ${coinSymbol} for Permit2`,
28089
+ data: viem.encodeFunctionData({
28090
+ abi: viem.erc20Abi,
28091
+ functionName: "approve",
28092
+ args: [permit2Address, coinAmount],
28093
+ }),
28094
+ });
28095
+ }
28096
+ // 2. Permit2 approval for coin to uni position manager
28097
+ const expiration = Math.floor(Date.now() / 1000) + 3600; // 1 hour from now
28098
+ if (needsCoinPermit2Approval) {
28099
+ calls.push({
28100
+ to: permit2Address,
28101
+ description: `Permit2 approval for ${coinSymbol} to UniV4PositionManager`,
28102
+ data: viem.encodeFunctionData({
28103
+ abi: Permit2Abi,
28104
+ functionName: "approve",
28105
+ args: [
28106
+ coinAddress,
28107
+ UniV4PositionManagerAddress[this.chainId],
28108
+ coinAmount,
28109
+ expiration,
28110
+ ],
28111
+ }),
28112
+ });
28113
+ }
28114
+ // === generate add liquidity call ===
28115
+ // Determine amounts for each currency based on pool key ordering
28116
+ const flethAmount = 0n;
28117
+ const amount0 = poolKey.currency0 === coinAddress ? coinAmount : flethAmount;
28118
+ const amount1 = poolKey.currency0 === coinAddress ? flethAmount : coinAmount;
28119
+ // Calculate and constrain liquidity using shared method
28120
+ const { finalLiquidity, finalAmount0, finalAmount1 } = this.calculateConstrainedLiquidity(currentTick, tickLower, tickUpper, amount0, amount1);
28121
+ // 3. Add liquidity
28122
+ calls.push(this.createLiquidityCall(poolKey, tickLower, tickUpper, finalLiquidity, finalAmount0, finalAmount1, userAddress));
28123
+ return calls;
28124
+ }
28125
+ /**
28126
+ * Calculates and constrains liquidity amounts for a position
28127
+ * @param currentTick - Current pool tick
28128
+ * @param tickLower - Lower tick of the position
28129
+ * @param tickUpper - Upper tick of the position
28130
+ * @param amount0 - Amount of currency0
28131
+ * @param amount1 - Amount of currency1
28132
+ * @returns Final liquidity and amounts
28133
+ */
28134
+ calculateConstrainedLiquidity(currentTick, tickLower, tickUpper, amount0, amount1) {
27976
28135
  // Calculate liquidity first using user's input amounts
27977
28136
  const initialLiquidity = getLiquidityFromAmounts({
27978
28137
  currentTick,
@@ -28038,7 +28197,25 @@ class ReadWriteFlaunchSDK extends ReadFlaunchSDK {
28038
28197
  }
28039
28198
  finalAmount0 = amount0; // Use user's full amount as maximum
28040
28199
  finalAmount1 = amount1; // Use user's full amount as maximum
28041
- // Prepare mint position parameters (following swiss-knife pattern)
28200
+ return {
28201
+ finalLiquidity,
28202
+ finalAmount0,
28203
+ finalAmount1,
28204
+ };
28205
+ }
28206
+ /**
28207
+ * Creates the UniV4 Position Manager liquidity call
28208
+ * @param poolKey - The pool key
28209
+ * @param tickLower - Lower tick of the position
28210
+ * @param tickUpper - Upper tick of the position
28211
+ * @param finalLiquidity - Final liquidity amount
28212
+ * @param finalAmount0 - Final amount of currency0
28213
+ * @param finalAmount1 - Final amount of currency1
28214
+ * @param userAddress - User's address
28215
+ * @returns CallWithDescription for adding liquidity
28216
+ */
28217
+ createLiquidityCall(poolKey, tickLower, tickUpper, finalLiquidity, finalAmount0, finalAmount1, userAddress) {
28218
+ // Prepare mint position parameters
28042
28219
  const V4PMActions = {
28043
28220
  MINT_POSITION: "02",
28044
28221
  SETTLE_PAIR: "0d",
@@ -28092,8 +28269,7 @@ class ReadWriteFlaunchSDK extends ReadFlaunchSDK {
28092
28269
  currency1: poolKey.currency1,
28093
28270
  },
28094
28271
  ]);
28095
- // 6. Add liquidity
28096
- calls.push({
28272
+ return {
28097
28273
  to: UniV4PositionManagerAddress[this.chainId],
28098
28274
  data: viem.encodeFunctionData({
28099
28275
  abi: [
@@ -28119,33 +28295,7 @@ class ReadWriteFlaunchSDK extends ReadFlaunchSDK {
28119
28295
  }),
28120
28296
  value: 0n,
28121
28297
  description: "Add Liquidity",
28122
- });
28123
- return calls;
28124
- }
28125
- /**
28126
- * Gets the calls needed to import a memecoin to Flaunch and add liquidity to AnyPositionManager as a batch
28127
- * @param params - Parameters for importing and adding liquidity
28128
- * @returns Array of calls with descriptions
28129
- */
28130
- async getImportAndAddLiquidityCalls(params) {
28131
- const importParams = await this.readWriteTokenImporter.getInitializeParams({
28132
- coinAddress: params.coinAddress,
28133
- creatorFeeAllocationPercent: params.creatorFeeAllocationPercent,
28134
- initialMarketCapUSD: params.initialMarketCapUSD,
28135
- verifier: params.verifier,
28136
- });
28137
- const addLiquidityCalls = await this.getAddLiquidityCalls({
28138
- ...params,
28139
- version: exports.FlaunchVersion.ANY, // optimize to avoid fetching if not passed
28140
- });
28141
- return [
28142
- {
28143
- to: this.readWriteTokenImporter.contract.address,
28144
- data: this.readWriteTokenImporter.contract.encodeFunctionData("initialize", importParams),
28145
- description: "Import Memecoin to Flaunch",
28146
- },
28147
- ...addLiquidityCalls,
28148
- ];
28298
+ };
28149
28299
  }
28150
28300
  }
28151
28301