@hypurrquant/defi-cli 1.0.7 → 1.0.9

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/dist/main.js CHANGED
@@ -4077,6 +4077,79 @@ var init_dist2 = __esm({
4077
4077
  gas_estimate: 3e5
4078
4078
  };
4079
4079
  }
4080
+ /**
4081
+ * List every LB pair from the factory with basic pair info (no rewarder /
4082
+ * APR enrichment). Useful when the factory has pools but none have hooks
4083
+ * deployed yet (e.g. early-stage Monad TraderJoe).
4084
+ *
4085
+ * Three multicall batches: pair addresses, token addresses, token symbols.
4086
+ */
4087
+ async discoverAllPools() {
4088
+ const rpcUrl = this.requireRpc();
4089
+ const client = createPublicClient8({ transport: http8(rpcUrl) });
4090
+ const pairCount = await client.readContract({
4091
+ address: this.lbFactory,
4092
+ abi: lbFactoryAbi,
4093
+ functionName: "getNumberOfLBPairs"
4094
+ });
4095
+ const count = Number(pairCount);
4096
+ if (count === 0) return [];
4097
+ const indexCalls = Array.from({ length: count }, (_, i) => [
4098
+ this.lbFactory,
4099
+ encodeFunctionData12({ abi: lbFactoryAbi, functionName: "getLBPairAtIndex", args: [BigInt(i)] })
4100
+ ]);
4101
+ const indexResults = await multicallRead(rpcUrl, indexCalls);
4102
+ const pairs = indexResults.map((r) => decodeAddressResult(r)).filter((a) => a !== null);
4103
+ if (pairs.length === 0) return [];
4104
+ const tokenCalls = [];
4105
+ for (const pool of pairs) {
4106
+ tokenCalls.push([pool, encodeFunctionData12({ abi: lbPairAbi, functionName: "getTokenX" })]);
4107
+ tokenCalls.push([pool, encodeFunctionData12({ abi: lbPairAbi, functionName: "getTokenY" })]);
4108
+ }
4109
+ const tokenResults = await multicallRead(rpcUrl, tokenCalls);
4110
+ const tokensX = [];
4111
+ const tokensY = [];
4112
+ for (let i = 0; i < pairs.length; i++) {
4113
+ tokensX.push(decodeAddressResult(tokenResults[i * 2] ?? null));
4114
+ tokensY.push(decodeAddressResult(tokenResults[i * 2 + 1] ?? null));
4115
+ }
4116
+ const uniqueTokens = Array.from(
4117
+ new Set([...tokensX, ...tokensY].filter((a) => a !== null))
4118
+ );
4119
+ const symbolCalls = uniqueTokens.map((t) => [
4120
+ t,
4121
+ encodeFunctionData12({ abi: erc20Abi2, functionName: "symbol" })
4122
+ ]);
4123
+ const symbolResults = await multicallRead(rpcUrl, symbolCalls);
4124
+ const symbolMap = /* @__PURE__ */ new Map();
4125
+ for (let i = 0; i < uniqueTokens.length; i++) {
4126
+ const raw = symbolResults[i];
4127
+ if (!raw) continue;
4128
+ try {
4129
+ const sym = decodeFunctionResult4({
4130
+ abi: parseAbi12(["function f() external view returns (string)"]),
4131
+ functionName: "f",
4132
+ data: raw
4133
+ });
4134
+ symbolMap.set(uniqueTokens[i].toLowerCase(), sym);
4135
+ } catch {
4136
+ }
4137
+ }
4138
+ const out = [];
4139
+ for (let i = 0; i < pairs.length; i++) {
4140
+ const tx = tokensX[i];
4141
+ const ty = tokensY[i];
4142
+ if (!tx || !ty) continue;
4143
+ out.push({
4144
+ pool: pairs[i],
4145
+ tokenX: tx,
4146
+ tokenY: ty,
4147
+ symbolX: symbolMap.get(tx.toLowerCase()) ?? "?",
4148
+ symbolY: symbolMap.get(ty.toLowerCase()) ?? "?"
4149
+ });
4150
+ }
4151
+ return out;
4152
+ }
4080
4153
  /**
4081
4154
  * Discover all active rewarded LB pools by iterating the factory.
4082
4155
  * Uses 7 multicall batches to minimise RPC round-trips and avoid 429s.
@@ -5057,6 +5130,7 @@ var init_dist2 = __esm({
5057
5130
  "function repay(address asset, uint256 amount, uint256 interestRateMode, address onBehalfOf) external returns (uint256)",
5058
5131
  "function withdraw(address asset, uint256 amount, address to) external returns (uint256)",
5059
5132
  "function getUserAccountData(address user) external view returns (uint256 totalCollateralBase, uint256 totalDebtBase, uint256 availableBorrowsBase, uint256 currentLiquidationThreshold, uint256 ltv, uint256 healthFactor)",
5133
+ "function getReservesList() external view returns (address[])",
5060
5134
  "function getReserveData(address asset) external view returns (uint256 configuration, uint128 liquidityIndex, uint128 currentLiquidityRate, uint128 variableBorrowIndex, uint128 currentVariableBorrowRate, uint128 currentStableBorrowRate, uint40 lastUpdateTimestamp, uint16 id, address aTokenAddress, address stableDebtTokenAddress, address variableDebtTokenAddress, address interestRateStrategyAddress, uint128 accruedToTreasury, uint128 unbacked, uint128 isolationModeTotalDebt)"
5061
5135
  ]);
5062
5136
  ERC20_ABI2 = parseAbi14([
@@ -5143,13 +5217,37 @@ var init_dist2 = __esm({
5143
5217
  };
5144
5218
  }
5145
5219
  async buildWithdraw(params) {
5220
+ let withdrawAmount = params.amount;
5221
+ if (this.rpcUrl) {
5222
+ try {
5223
+ const client = createPublicClient10({ transport: http10(this.rpcUrl) });
5224
+ const reserveData = await client.readContract({
5225
+ address: this.pool,
5226
+ abi: POOL_ABI,
5227
+ functionName: "getReserveData",
5228
+ args: [params.asset]
5229
+ });
5230
+ const aToken = reserveData[8];
5231
+ const aBal = await client.readContract({
5232
+ address: aToken,
5233
+ abi: parseAbi14(["function balanceOf(address) view returns (uint256)"]),
5234
+ functionName: "balanceOf",
5235
+ args: [params.to]
5236
+ });
5237
+ if (aBal > 0n && params.amount >= aBal) {
5238
+ withdrawAmount = (1n << 256n) - 1n;
5239
+ }
5240
+ } catch {
5241
+ }
5242
+ }
5146
5243
  const data = encodeFunctionData14({
5147
5244
  abi: POOL_ABI,
5148
5245
  functionName: "withdraw",
5149
- args: [params.asset, params.amount, params.to]
5246
+ args: [params.asset, withdrawAmount, params.to]
5150
5247
  });
5248
+ const isMax = withdrawAmount === (1n << 256n) - 1n;
5151
5249
  return {
5152
- description: `[${this.protocolName}] Withdraw ${params.amount} from pool`,
5250
+ description: `[${this.protocolName}] Withdraw ${isMax ? "all (auto-max)" : withdrawAmount} from pool`,
5153
5251
  to: this.pool,
5154
5252
  data,
5155
5253
  value: 0n,
@@ -5343,7 +5441,7 @@ var init_dist2 = __esm({
5343
5441
  async getUserPosition(user) {
5344
5442
  if (!this.rpcUrl) throw DefiError.rpcError("No RPC URL configured");
5345
5443
  const client = createPublicClient10({ transport: http10(this.rpcUrl) });
5346
- const result = await client.readContract({
5444
+ const accountData = await client.readContract({
5347
5445
  address: this.pool,
5348
5446
  abi: POOL_ABI,
5349
5447
  functionName: "getUserAccountData",
@@ -5351,21 +5449,63 @@ var init_dist2 = __esm({
5351
5449
  }).catch((e) => {
5352
5450
  throw DefiError.rpcError(`[${this.protocolName}] getUserAccountData failed: ${e}`);
5353
5451
  });
5354
- const [totalCollateralBase, totalDebtBase, , , ltv, healthFactor] = result;
5452
+ const [totalCollateralBase, totalDebtBase, , , ltv, healthFactor] = accountData;
5355
5453
  const MAX_UINT2562 = 2n ** 256n - 1n;
5356
- const hf = healthFactor >= MAX_UINT2562 ? Infinity : Number(healthFactor) / 1e18;
5454
+ const hf = healthFactor >= MAX_UINT2562 ? null : Number(healthFactor) / 1e18;
5357
5455
  const collateralUsd = u256ToF64(totalCollateralBase) / 1e8;
5358
5456
  const debtUsd = u256ToF64(totalDebtBase) / 1e8;
5359
- const ltvBps = u256ToF64(ltv);
5360
- const supplies = collateralUsd > 0 ? [{ asset: zeroAddress8, symbol: "Total Collateral", amount: totalCollateralBase, value_usd: collateralUsd }] : [];
5361
- const borrows = debtUsd > 0 ? [{ asset: zeroAddress8, symbol: "Total Debt", amount: totalDebtBase, value_usd: debtUsd }] : [];
5457
+ const ltvPct = u256ToF64(ltv) / 100;
5458
+ const supplies = [];
5459
+ const borrows = [];
5460
+ try {
5461
+ const reserves = await client.readContract({
5462
+ address: this.pool,
5463
+ abi: POOL_ABI,
5464
+ functionName: "getReservesList"
5465
+ });
5466
+ const reserveData = await Promise.allSettled(reserves.map(async (asset) => {
5467
+ const data = await client.readContract({
5468
+ address: this.pool,
5469
+ abi: POOL_ABI,
5470
+ functionName: "getReserveData",
5471
+ args: [asset]
5472
+ });
5473
+ const aToken = data[8];
5474
+ const debtToken = data[10];
5475
+ return { asset, aToken, debtToken };
5476
+ }));
5477
+ const ERC20_ABI42 = parseAbi14([
5478
+ "function balanceOf(address) view returns (uint256)",
5479
+ "function symbol() view returns (string)"
5480
+ ]);
5481
+ const positions = await Promise.allSettled(reserveData.map(async (r) => {
5482
+ if (r.status !== "fulfilled") return null;
5483
+ const { asset, aToken, debtToken } = r.value;
5484
+ const [aBal, dBal, sym] = await Promise.all([
5485
+ client.readContract({ address: aToken, abi: ERC20_ABI42, functionName: "balanceOf", args: [user] }),
5486
+ client.readContract({ address: debtToken, abi: ERC20_ABI42, functionName: "balanceOf", args: [user] }),
5487
+ client.readContract({ address: asset, abi: ERC20_ABI42, functionName: "symbol" }).catch(() => "?")
5488
+ ]);
5489
+ return { asset, symbol: sym, supply: aBal, borrow: dBal };
5490
+ }));
5491
+ for (const p of positions) {
5492
+ if (p.status !== "fulfilled" || !p.value) continue;
5493
+ if (p.value.supply > 0n) supplies.push({ asset: p.value.asset, symbol: p.value.symbol, amount: p.value.supply });
5494
+ if (p.value.borrow > 0n) borrows.push({ asset: p.value.asset, symbol: p.value.symbol, amount: p.value.borrow });
5495
+ }
5496
+ } catch {
5497
+ if (collateralUsd > 0) supplies.push({ asset: zeroAddress8, symbol: "Total Collateral (per-asset breakdown unavailable)", amount: totalCollateralBase });
5498
+ if (debtUsd > 0) borrows.push({ asset: zeroAddress8, symbol: "Total Debt (per-asset breakdown unavailable)", amount: totalDebtBase });
5499
+ }
5362
5500
  return {
5363
5501
  protocol: this.protocolName,
5364
5502
  user,
5365
5503
  supplies,
5366
5504
  borrows,
5367
5505
  health_factor: hf,
5368
- net_apy: ltvBps / 100
5506
+ ltv_pct: ltvPct,
5507
+ total_collateral_usd: collateralUsd,
5508
+ total_debt_usd: debtUsd
5369
5509
  };
5370
5510
  }
5371
5511
  };
@@ -5622,6 +5762,7 @@ var init_dist2 = __esm({
5622
5762
  "function borrowBalanceStored(address account) external view returns (uint256)",
5623
5763
  "function mint(uint256 mintAmount) external returns (uint256)",
5624
5764
  "function redeem(uint256 redeemTokens) external returns (uint256)",
5765
+ "function redeemUnderlying(uint256 redeemAmount) external returns (uint256)",
5625
5766
  "function borrow(uint256 borrowAmount) external returns (uint256)",
5626
5767
  "function repayBorrow(uint256 repayAmount) external returns (uint256)"
5627
5768
  ]);
@@ -5664,57 +5805,55 @@ var init_dist2 = __esm({
5664
5805
  name() {
5665
5806
  return this.protocolName;
5666
5807
  }
5808
+ // Resolve the vToken whose underlying() matches params.asset. Compound V2 has
5809
+ // a separate vToken per asset, so all builders must dispatch on the request
5810
+ // asset. Returns the resolved vToken or throws if no candidate matches.
5811
+ async vtokenFor(asset) {
5812
+ const v = await this.resolveVtoken(asset);
5813
+ if (!v) throw DefiError.contractError(`[${this.protocolName}] no vToken for asset ${asset}`);
5814
+ return v;
5815
+ }
5667
5816
  async buildSupply(params) {
5668
- const data = encodeFunctionData16({
5669
- abi: CTOKEN_ABI,
5670
- functionName: "mint",
5671
- args: [params.amount]
5672
- });
5817
+ const vtoken = await this.vtokenFor(params.asset);
5818
+ const data = encodeFunctionData16({ abi: CTOKEN_ABI, functionName: "mint", args: [params.amount] });
5673
5819
  return {
5674
- description: `[${this.protocolName}] Supply ${params.amount} to Venus`,
5675
- to: this.defaultVtoken,
5820
+ description: `[${this.protocolName}] Supply ${params.amount} of ${params.asset} to Venus`,
5821
+ to: vtoken,
5676
5822
  data,
5677
5823
  value: 0n,
5678
- gas_estimate: 3e5
5824
+ gas_estimate: 3e5,
5825
+ approvals: [{ token: params.asset, spender: vtoken, amount: params.amount }]
5679
5826
  };
5680
5827
  }
5681
5828
  async buildBorrow(params) {
5682
- const data = encodeFunctionData16({
5683
- abi: CTOKEN_ABI,
5684
- functionName: "borrow",
5685
- args: [params.amount]
5686
- });
5829
+ const vtoken = await this.vtokenFor(params.asset);
5830
+ const data = encodeFunctionData16({ abi: CTOKEN_ABI, functionName: "borrow", args: [params.amount] });
5687
5831
  return {
5688
- description: `[${this.protocolName}] Borrow ${params.amount} from Venus`,
5689
- to: this.defaultVtoken,
5832
+ description: `[${this.protocolName}] Borrow ${params.amount} of ${params.asset} from Venus`,
5833
+ to: vtoken,
5690
5834
  data,
5691
5835
  value: 0n,
5692
5836
  gas_estimate: 35e4
5693
5837
  };
5694
5838
  }
5695
5839
  async buildRepay(params) {
5696
- const data = encodeFunctionData16({
5697
- abi: CTOKEN_ABI,
5698
- functionName: "repayBorrow",
5699
- args: [params.amount]
5700
- });
5840
+ const vtoken = await this.vtokenFor(params.asset);
5841
+ const data = encodeFunctionData16({ abi: CTOKEN_ABI, functionName: "repayBorrow", args: [params.amount] });
5701
5842
  return {
5702
- description: `[${this.protocolName}] Repay ${params.amount} to Venus`,
5703
- to: this.defaultVtoken,
5843
+ description: `[${this.protocolName}] Repay ${params.amount} of ${params.asset} to Venus`,
5844
+ to: vtoken,
5704
5845
  data,
5705
5846
  value: 0n,
5706
- gas_estimate: 3e5
5847
+ gas_estimate: 3e5,
5848
+ approvals: [{ token: params.asset, spender: vtoken, amount: params.amount }]
5707
5849
  };
5708
5850
  }
5709
5851
  async buildWithdraw(params) {
5710
- const data = encodeFunctionData16({
5711
- abi: CTOKEN_ABI,
5712
- functionName: "redeem",
5713
- args: [params.amount]
5714
- });
5852
+ const vtoken = await this.vtokenFor(params.asset);
5853
+ const data = encodeFunctionData16({ abi: CTOKEN_ABI, functionName: "redeemUnderlying", args: [params.amount] });
5715
5854
  return {
5716
- description: `[${this.protocolName}] Withdraw from Venus`,
5717
- to: this.defaultVtoken,
5855
+ description: `[${this.protocolName}] Withdraw ${params.amount} of ${params.asset} from Venus`,
5856
+ to: vtoken,
5718
5857
  data,
5719
5858
  value: 0n,
5720
5859
  gas_estimate: 25e4
@@ -7248,24 +7387,69 @@ var Executor = class _Executor {
7248
7387
  `);
7249
7388
  if (approveTxUrl) process.stderr.write(` Explorer: ${approveTxUrl}
7250
7389
  `);
7251
- await publicClient.waitForTransactionReceipt({ hash: approveTxHash });
7390
+ const approveReceipt = await _Executor.waitForReceiptWithRetry(publicClient, approveTxHash);
7391
+ if (approveReceipt.status !== "success") {
7392
+ throw new Error(`Approve tx ${approveTxHash} reverted on-chain (status=${approveReceipt.status}). Aborting downstream tx.`);
7393
+ }
7252
7394
  process.stderr.write(
7253
7395
  ` Approved ${amount} of ${token} for ${spender}
7254
7396
  `
7255
7397
  );
7256
7398
  }
7257
- /** Fetch EIP-1559 fee params from the network. Returns [maxFeePerGas, maxPriorityFeePerGas]. */
7399
+ /**
7400
+ * Wait for a tx receipt with bounded retries. Some L2 RPCs (notably Mantle)
7401
+ * occasionally fail to surface a receipt even after the tx is mined; viem's
7402
+ * default `waitForTransactionReceipt` errors out instead of polling longer.
7403
+ * We retry up to `attempts` times with exponential backoff before giving up.
7404
+ */
7405
+ static async waitForReceiptWithRetry(client, hash, attempts = 6) {
7406
+ let lastErr;
7407
+ for (let i = 0; i < attempts; i++) {
7408
+ try {
7409
+ return await client.waitForTransactionReceipt({
7410
+ hash,
7411
+ timeout: 6e4,
7412
+ retryCount: 8
7413
+ });
7414
+ } catch (e) {
7415
+ lastErr = e;
7416
+ const backoffMs = Math.min(2e3 * Math.pow(2, i), 6e4);
7417
+ await new Promise((resolve6) => setTimeout(resolve6, backoffMs));
7418
+ }
7419
+ }
7420
+ throw new Error(`waitForReceiptWithRetry: gave up after ${attempts} attempts. Last error: ${lastErr instanceof Error ? lastErr.message : String(lastErr)}`);
7421
+ }
7422
+ /**
7423
+ * Fetch EIP-1559 fee params. Returns [maxFeePerGas, maxPriorityFeePerGas].
7424
+ *
7425
+ * Strategy: read the latest block's `baseFeePerGas` and use the canonical
7426
+ * EIP-1559 formula `maxFee = baseFee * 2 + priorityFee` (1 block of head-room
7427
+ * after a 12.5% bump). Falls back to `getGasPrice() + priorityFee` only when
7428
+ * the chain doesn't expose `baseFeePerGas` (pre-1559).
7429
+ *
7430
+ * Why not gasPrice * 2: `getGasPrice()` returns `baseFee + priorityFee`, so
7431
+ * doubling double-counts the priority component and produces nonsense on
7432
+ * chains where baseFee is already high (e.g., Mantle 50 gwei → 100 gwei,
7433
+ * which can drain MNT before the actual tx settles).
7434
+ */
7258
7435
  async fetchEip1559Fees(rpcUrl) {
7259
7436
  try {
7260
7437
  const client = createPublicClient2({ transport: http2(rpcUrl) });
7261
- const gasPrice = await client.getGasPrice();
7262
7438
  let priorityFee = DEFAULT_PRIORITY_FEE_WEI;
7263
7439
  try {
7264
7440
  priorityFee = await client.estimateMaxPriorityFeePerGas();
7265
7441
  } catch {
7266
7442
  }
7267
- const maxFee = gasPrice * 2n + priorityFee;
7268
- return [maxFee, priorityFee];
7443
+ try {
7444
+ const block = await client.getBlock({ blockTag: "latest" });
7445
+ if (block.baseFeePerGas !== null && block.baseFeePerGas !== void 0) {
7446
+ const maxFee = block.baseFeePerGas * 2n + priorityFee;
7447
+ return [maxFee, priorityFee];
7448
+ }
7449
+ } catch {
7450
+ }
7451
+ const gasPrice = await client.getGasPrice();
7452
+ return [gasPrice + priorityFee, priorityFee];
7269
7453
  } catch {
7270
7454
  return [0n, 0n];
7271
7455
  }
@@ -7429,8 +7613,8 @@ var Executor = class _Executor {
7429
7613
  `);
7430
7614
  if (preTxUrl) process.stderr.write(` Explorer: ${preTxUrl}
7431
7615
  `);
7432
- const preReceipt = await publicClient.waitForTransactionReceipt({ hash: preTxHash });
7433
- if (preReceipt.status !== "success") {
7616
+ const preReceiptResult = await _Executor.waitForReceiptWithRetry(publicClient, preTxHash);
7617
+ if (preReceiptResult.status !== "success") {
7434
7618
  throw new DefiError("TX_FAILED", `Pre-transaction failed: ${preTx.description}`);
7435
7619
  }
7436
7620
  process.stderr.write(` Pre-tx confirmed
@@ -7472,7 +7656,7 @@ var Executor = class _Executor {
7472
7656
  if (txUrl) process.stderr.write(`Explorer: ${txUrl}
7473
7657
  `);
7474
7658
  process.stderr.write("Waiting for confirmation...\n");
7475
- const receipt = await publicClient.waitForTransactionReceipt({ hash: txHash });
7659
+ const receipt = await _Executor.waitForReceiptWithRetry(publicClient, txHash);
7476
7660
  const status = receipt.status === "success" ? TxStatus.Confirmed : TxStatus.Failed;
7477
7661
  let mintedTokenId;
7478
7662
  if (receipt.status === "success" && receipt.logs) {
@@ -8538,8 +8722,9 @@ function registerLP(parent, getOpts, makeExecutor2) {
8538
8722
  }
8539
8723
  if (protocol.interface === "uniswap_v2" && protocol.contracts?.["lb_factory"]) {
8540
8724
  const adapter = createMerchantMoeLB(protocol, rpcUrl);
8541
- const pools = await adapter.discoverRewardedPools();
8542
- for (const p of pools) {
8725
+ const rewardedPools = await adapter.discoverRewardedPools();
8726
+ const rewardedSet = new Set(rewardedPools.map((p) => p.pool.toLowerCase()));
8727
+ for (const p of rewardedPools) {
8543
8728
  if (!opts.emissionOnly || !p.stopped) {
8544
8729
  results.push({
8545
8730
  protocol: protocol.slug,
@@ -8561,6 +8746,19 @@ function registerLP(parent, getOpts, makeExecutor2) {
8561
8746
  });
8562
8747
  }
8563
8748
  }
8749
+ if (!opts.emissionOnly) {
8750
+ const allPools = await adapter.discoverAllPools().catch(() => []);
8751
+ for (const p of allPools) {
8752
+ if (rewardedSet.has(p.pool.toLowerCase())) continue;
8753
+ results.push({
8754
+ protocol: protocol.slug,
8755
+ pool: p.pool,
8756
+ pair: `${p.symbolX}/${p.symbolY}`,
8757
+ type: "FEE",
8758
+ source: "lb_hooks"
8759
+ });
8760
+ }
8761
+ }
8564
8762
  }
8565
8763
  if (protocol.interface === "uniswap_v3" && protocol.contracts?.["masterchef"]) {
8566
8764
  const mcAddr = protocol.contracts["masterchef"];
@@ -8692,7 +8890,7 @@ function registerLP(parent, getOpts, makeExecutor2) {
8692
8890
  const recipient = opts.recipient ?? process.env["DEFI_WALLET_ADDRESS"] ?? "0x0000000000000000000000000000000000000001";
8693
8891
  const poolAddr = opts.pool ? resolvePoolAddress(registry, opts.protocol, opts.pool) : void 0;
8694
8892
  if (protocol.interface === "uniswap_v2" && protocol.contracts?.["lb_factory"]) {
8695
- if (!poolAddr) throw new Error("--pool is required for Merchant Moe LB add");
8893
+ if (!poolAddr) throw new Error(`--pool is required for ${protocol.name} (Liquidity Book \u2014 pass --pool <addr>; use \`lp discover --protocol ${protocol.slug}\` to list active pools)`);
8696
8894
  const lbAdapter = createMerchantMoeLB(protocol, chain.effectiveRpcUrl());
8697
8895
  const [tokenX, tokenY, amountX, amountY] = tokenA.toLowerCase() < tokenB.toLowerCase() ? [tokenA, tokenB, BigInt(opts.amountA), BigInt(opts.amountB)] : [tokenB, tokenA, BigInt(opts.amountB), BigInt(opts.amountA)];
8698
8896
  const client = createPublicClient23({ transport: http23(chain.effectiveRpcUrl()) });
@@ -8935,7 +9133,7 @@ function registerLP(parent, getOpts, makeExecutor2) {
8935
9133
  return;
8936
9134
  }
8937
9135
  if (iface === "uniswap_v2" && protocol.contracts?.["lb_factory"]) {
8938
- if (!opts.pool) throw new Error("--pool is required for Merchant Moe LB claim");
9136
+ if (!opts.pool) throw new Error(`--pool is required for ${protocol.name} (Liquidity Book \u2014 pass --pool <addr>)`);
8939
9137
  const adapter = createMerchantMoeLB(protocol, rpcUrl);
8940
9138
  const binIds = opts.bins ? opts.bins.split(",").map((s) => parseInt(s.trim())) : void 0;
8941
9139
  const tx = await adapter.buildClaimRewards(account, opts.pool, binIds);
@@ -9011,7 +9209,7 @@ function registerLP(parent, getOpts, makeExecutor2) {
9011
9209
  const iface = protocol.interface;
9012
9210
  const recipient = opts.recipient ?? process.env["DEFI_WALLET_ADDRESS"] ?? "0x0000000000000000000000000000000000000001";
9013
9211
  if (iface === "uniswap_v2" && protocol.contracts?.["lb_factory"]) {
9014
- if (!opts.pool) throw new Error("--pool is required for Merchant Moe LB remove");
9212
+ if (!opts.pool) throw new Error(`--pool is required for ${protocol.name} (Liquidity Book \u2014 pass --pool <addr>)`);
9015
9213
  if (!opts.bins) throw new Error("--bins <id1,id2,...> is required for Merchant Moe LB remove");
9016
9214
  const lbAdapter = createMerchantMoeLB(protocol, rpcUrl);
9017
9215
  const tokenA2 = opts.tokenA.startsWith("0x") ? opts.tokenA : registry.resolveToken(chainName, opts.tokenA).address;