@hypurrquant/defi-cli 0.2.5 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/main.js CHANGED
@@ -707,6 +707,16 @@ function parse(toml, { maxDepth = 1e3, integersAsBigInt } = {}) {
707
707
 
708
708
  // ../defi-core/dist/index.js
709
709
  import { existsSync } from "fs";
710
+ var TxStatus = /* @__PURE__ */ ((TxStatus2) => {
711
+ TxStatus2["DryRun"] = "dry_run";
712
+ TxStatus2["Simulated"] = "simulated";
713
+ TxStatus2["SimulationFailed"] = "simulation_failed";
714
+ TxStatus2["NeedsApproval"] = "needs_approval";
715
+ TxStatus2["Pending"] = "pending";
716
+ TxStatus2["Confirmed"] = "confirmed";
717
+ TxStatus2["Failed"] = "failed";
718
+ return TxStatus2;
719
+ })(TxStatus || {});
710
720
  var InterestRateMode = /* @__PURE__ */ ((InterestRateMode2) => {
711
721
  InterestRateMode2["Variable"] = "variable";
712
722
  InterestRateMode2["Stable"] = "stable";
@@ -1135,6 +1145,46 @@ var Executor = class _Executor {
1135
1145
  const client = createPublicClient2({ transport: http2(rpcUrl) });
1136
1146
  const privateKey = process.env["DEFI_PRIVATE_KEY"];
1137
1147
  const from = privateKey ? privateKeyToAccount(privateKey).address : "0x0000000000000000000000000000000000000001";
1148
+ if (tx.approvals && tx.approvals.length > 0) {
1149
+ const pendingApprovals = [];
1150
+ for (const approval of tx.approvals) {
1151
+ try {
1152
+ const allowance = await client.readContract({
1153
+ address: approval.token,
1154
+ abi: ERC20_ABI,
1155
+ functionName: "allowance",
1156
+ args: [from, approval.spender]
1157
+ });
1158
+ if (allowance < approval.amount) {
1159
+ pendingApprovals.push({
1160
+ token: approval.token,
1161
+ spender: approval.spender,
1162
+ needed: approval.amount.toString(),
1163
+ current: allowance.toString()
1164
+ });
1165
+ }
1166
+ } catch {
1167
+ }
1168
+ }
1169
+ if (pendingApprovals.length > 0) {
1170
+ return {
1171
+ tx_hash: void 0,
1172
+ status: TxStatus.NeedsApproval,
1173
+ gas_used: tx.gas_estimate,
1174
+ description: tx.description,
1175
+ details: {
1176
+ to: tx.to,
1177
+ from,
1178
+ data: tx.data,
1179
+ value: tx.value.toString(),
1180
+ mode: "simulated",
1181
+ result: "needs_approval",
1182
+ pending_approvals: pendingApprovals,
1183
+ hint: "Use --broadcast to auto-approve and execute"
1184
+ }
1185
+ };
1186
+ }
1187
+ }
1138
1188
  try {
1139
1189
  await client.call({ to: tx.to, data: tx.data, value: tx.value, account: from });
1140
1190
  const gasEstimate = await this.estimateGasWithBuffer(rpcUrl, tx, from);
@@ -1800,26 +1850,33 @@ import { encodeFunctionData as encodeFunctionData22, parseAbi as parseAbi22, cre
1800
1850
  import { encodeFunctionData as encodeFunctionData32, parseAbi as parseAbi32, createPublicClient as createPublicClient32, http as http32, decodeAbiParameters as decodeAbiParameters3, concatHex, zeroAddress } from "viem";
1801
1851
  import { encodeFunctionData as encodeFunctionData42, parseAbi as parseAbi42, zeroAddress as zeroAddress2 } from "viem";
1802
1852
  import { encodeFunctionData as encodeFunctionData5, parseAbi as parseAbi5 } from "viem";
1803
- import { encodeFunctionData as encodeFunctionData6, parseAbi as parseAbi6, createPublicClient as createPublicClient42, http as http42, decodeAbiParameters as decodeAbiParameters4 } from "viem";
1853
+ import { encodeFunctionData as encodeFunctionData6, parseAbi as parseAbi6, decodeAbiParameters as decodeAbiParameters4 } from "viem";
1804
1854
  import { encodeFunctionData as encodeFunctionData7, parseAbi as parseAbi7, zeroAddress as zeroAddress3 } from "viem";
1805
- import { createPublicClient as createPublicClient5, encodeFunctionData as encodeFunctionData8, http as http5, parseAbi as parseAbi8, zeroAddress as zeroAddress4 } from "viem";
1806
- import { encodeFunctionData as encodeFunctionData9, parseAbi as parseAbi9, createPublicClient as createPublicClient6, http as http6 } from "viem";
1807
- import { createPublicClient as createPublicClient7, http as http7, parseAbi as parseAbi10, encodeFunctionData as encodeFunctionData10, zeroAddress as zeroAddress5 } from "viem";
1808
- import { createPublicClient as createPublicClient8, http as http8, parseAbi as parseAbi11, encodeFunctionData as encodeFunctionData11, zeroAddress as zeroAddress6 } from "viem";
1809
- import { createPublicClient as createPublicClient9, http as http9, parseAbi as parseAbi12 } from "viem";
1810
- import { createPublicClient as createPublicClient10, http as http10, parseAbi as parseAbi13, encodeFunctionData as encodeFunctionData12 } from "viem";
1811
- import { createPublicClient as createPublicClient11, http as http11, parseAbi as parseAbi14, encodeFunctionData as encodeFunctionData13 } from "viem";
1812
- import { createPublicClient as createPublicClient12, http as http12, parseAbi as parseAbi15, encodeFunctionData as encodeFunctionData14 } from "viem";
1813
- import { createPublicClient as createPublicClient13, http as http13, parseAbi as parseAbi16, encodeFunctionData as encodeFunctionData15, zeroAddress as zeroAddress7 } from "viem";
1814
- import { createPublicClient as createPublicClient14, http as http14, parseAbi as parseAbi17, encodeFunctionData as encodeFunctionData16, zeroAddress as zeroAddress8 } from "viem";
1815
- import { createPublicClient as createPublicClient15, http as http15, parseAbi as parseAbi18 } from "viem";
1816
- import { createPublicClient as createPublicClient16, http as http16, parseAbi as parseAbi19, encodeFunctionData as encodeFunctionData17 } from "viem";
1817
- import { parseAbi as parseAbi20, encodeFunctionData as encodeFunctionData18 } from "viem";
1818
- import { createPublicClient as createPublicClient17, http as http17, parseAbi as parseAbi21, encodeFunctionData as encodeFunctionData19, zeroAddress as zeroAddress9 } from "viem";
1819
- import { createPublicClient as createPublicClient18, http as http18, parseAbi as parseAbi222, encodeFunctionData as encodeFunctionData20, zeroAddress as zeroAddress10 } from "viem";
1820
- import { parseAbi as parseAbi23, encodeFunctionData as encodeFunctionData21 } from "viem";
1855
+ import { createPublicClient as createPublicClient42, encodeFunctionData as encodeFunctionData8, http as http42, parseAbi as parseAbi8, zeroAddress as zeroAddress4 } from "viem";
1856
+ import { encodeFunctionData as encodeFunctionData9, parseAbi as parseAbi9, createPublicClient as createPublicClient5, http as http5 } from "viem";
1857
+ import {
1858
+ encodeFunctionData as encodeFunctionData10,
1859
+ decodeFunctionResult as decodeFunctionResult22,
1860
+ parseAbi as parseAbi10,
1861
+ createPublicClient as createPublicClient6,
1862
+ http as http6
1863
+ } from "viem";
1864
+ import { createPublicClient as createPublicClient7, http as http7, parseAbi as parseAbi11, encodeFunctionData as encodeFunctionData11, decodeFunctionResult as decodeFunctionResult3, zeroAddress as zeroAddress5 } from "viem";
1865
+ import { createPublicClient as createPublicClient8, http as http8, parseAbi as parseAbi12, encodeFunctionData as encodeFunctionData12, zeroAddress as zeroAddress6 } from "viem";
1866
+ import { createPublicClient as createPublicClient9, http as http9, parseAbi as parseAbi13 } from "viem";
1867
+ import { createPublicClient as createPublicClient10, http as http10, parseAbi as parseAbi14, encodeFunctionData as encodeFunctionData13 } from "viem";
1868
+ import { createPublicClient as createPublicClient11, http as http11, parseAbi as parseAbi15, encodeFunctionData as encodeFunctionData14 } from "viem";
1869
+ import { createPublicClient as createPublicClient12, http as http12, parseAbi as parseAbi16, encodeFunctionData as encodeFunctionData15 } from "viem";
1870
+ import { parseAbi as parseAbi17, encodeFunctionData as encodeFunctionData16, decodeFunctionResult as decodeFunctionResult4, zeroAddress as zeroAddress7 } from "viem";
1871
+ import { createPublicClient as createPublicClient13, http as http13, parseAbi as parseAbi18, encodeFunctionData as encodeFunctionData17, zeroAddress as zeroAddress8 } from "viem";
1872
+ import { createPublicClient as createPublicClient14, http as http14, parseAbi as parseAbi19 } from "viem";
1873
+ import { createPublicClient as createPublicClient15, http as http15, parseAbi as parseAbi20, encodeFunctionData as encodeFunctionData18 } from "viem";
1874
+ import { parseAbi as parseAbi21, encodeFunctionData as encodeFunctionData19 } from "viem";
1875
+ import { createPublicClient as createPublicClient16, http as http16, parseAbi as parseAbi222, encodeFunctionData as encodeFunctionData20, zeroAddress as zeroAddress9 } from "viem";
1876
+ import { createPublicClient as createPublicClient17, http as http17, parseAbi as parseAbi23, encodeFunctionData as encodeFunctionData21, zeroAddress as zeroAddress10 } from "viem";
1821
1877
  import { parseAbi as parseAbi24, encodeFunctionData as encodeFunctionData222 } from "viem";
1822
- import { createPublicClient as createPublicClient19, http as http19, parseAbi as parseAbi25 } from "viem";
1878
+ import { parseAbi as parseAbi25, encodeFunctionData as encodeFunctionData23 } from "viem";
1879
+ import { createPublicClient as createPublicClient18, http as http18, parseAbi as parseAbi26 } from "viem";
1823
1880
  var DEFAULT_FEE = 3e3;
1824
1881
  var swapRouterAbi = parseAbi4([
1825
1882
  "struct ExactInputSingleParams { address tokenIn; address tokenOut; uint24 fee; address recipient; uint256 deadline; uint256 amountIn; uint256 amountOutMinimum; uint160 sqrtPriceLimitX96; }",
@@ -2636,15 +2693,6 @@ var SolidlyAdapter = class {
2636
2693
  approvals: [{ token: params.token_in, spender: this.router, amount: params.amount_in }]
2637
2694
  };
2638
2695
  }
2639
- async callGetAmountsOut(client, callData) {
2640
- const result = await client.call({ to: this.router, data: callData });
2641
- if (!result.data) return 0n;
2642
- const [amounts] = decodeAbiParameters4(
2643
- [{ name: "amounts", type: "uint256[]" }],
2644
- result.data
2645
- );
2646
- return amounts.length >= 2 ? amounts[amounts.length - 1] : 0n;
2647
- }
2648
2696
  encodeV1(params, stable) {
2649
2697
  return encodeFunctionData6({
2650
2698
  abi: abi4,
@@ -2661,7 +2709,6 @@ var SolidlyAdapter = class {
2661
2709
  }
2662
2710
  async quote(params) {
2663
2711
  if (!this.rpcUrl) throw DefiError.rpcError("No RPC URL configured");
2664
- const client = createPublicClient42({ transport: http42(this.rpcUrl) });
2665
2712
  const candidates = [
2666
2713
  { callData: this.encodeV1(params, false), stable: false },
2667
2714
  { callData: this.encodeV1(params, true), stable: true }
@@ -2672,16 +2719,26 @@ var SolidlyAdapter = class {
2672
2719
  { callData: this.encodeV2(params, true), stable: true }
2673
2720
  );
2674
2721
  }
2675
- const results = await Promise.allSettled(
2676
- candidates.map((c) => this.callGetAmountsOut(client, c.callData))
2722
+ const rawResults = await multicallRead(
2723
+ this.rpcUrl,
2724
+ candidates.map((c) => [this.router, c.callData])
2677
2725
  );
2678
2726
  let bestOut = 0n;
2679
2727
  let bestStable = false;
2680
- for (let i = 0; i < results.length; i++) {
2681
- const r = results[i];
2682
- if (r.status === "fulfilled" && r.value > bestOut) {
2683
- bestOut = r.value;
2684
- bestStable = candidates[i].stable;
2728
+ for (let i = 0; i < rawResults.length; i++) {
2729
+ const raw = rawResults[i];
2730
+ if (!raw) continue;
2731
+ try {
2732
+ const [amounts] = decodeAbiParameters4(
2733
+ [{ name: "amounts", type: "uint256[]" }],
2734
+ raw
2735
+ );
2736
+ const out = amounts.length >= 2 ? amounts[amounts.length - 1] : 0n;
2737
+ if (out > bestOut) {
2738
+ bestOut = out;
2739
+ bestStable = candidates[i].stable;
2740
+ }
2741
+ } catch {
2685
2742
  }
2686
2743
  }
2687
2744
  if (bestOut === 0n) {
@@ -2893,7 +2950,7 @@ var SolidlyGaugeAdapter = class {
2893
2950
  async buildClaimRewards(gauge, account) {
2894
2951
  if (account && this.rpcUrl) {
2895
2952
  try {
2896
- const client = createPublicClient5({ transport: http5(this.rpcUrl) });
2953
+ const client = createPublicClient42({ transport: http42(this.rpcUrl) });
2897
2954
  const listLen = await client.readContract({
2898
2955
  address: gauge,
2899
2956
  abi: gaugeAbi,
@@ -3151,7 +3208,7 @@ var MasterChefAdapter = class {
3151
3208
  if (!this.rpcUrl) {
3152
3209
  throw DefiError.unsupported(`[${this.protocolName}] getPendingRewards requires RPC`);
3153
3210
  }
3154
- const client = createPublicClient6({ transport: http6(this.rpcUrl) });
3211
+ const client = createPublicClient5({ transport: http5(this.rpcUrl) });
3155
3212
  const rewards = await client.readContract({
3156
3213
  address: this.masterchef,
3157
3214
  abi: masterchefAbi,
@@ -3165,7 +3222,682 @@ var MasterChefAdapter = class {
3165
3222
  }));
3166
3223
  }
3167
3224
  };
3168
- var POOL_ABI = parseAbi10([
3225
+ var lbRouterAbi = parseAbi10([
3226
+ "struct LiquidityParameters { address tokenX; address tokenY; uint256 binStep; uint256 amountX; uint256 amountY; uint256 amountXMin; uint256 amountYMin; uint256 activeIdDesired; uint256 idSlippage; int256[] deltaIds; uint256[] distributionX; uint256[] distributionY; address to; address refundTo; uint256 deadline; }",
3227
+ "function addLiquidity(LiquidityParameters calldata liquidityParameters) external returns (uint256 amountXAdded, uint256 amountYAdded, uint256 amountXLeft, uint256 amountYLeft, uint256[] memory depositIds, uint256[] memory liquidityMinted)",
3228
+ "function removeLiquidity(address tokenX, address tokenY, uint16 binStep, uint256 amountXMin, uint256 amountYMin, uint256[] memory ids, uint256[] memory amounts, address to, uint256 deadline) external returns (uint256 amountX, uint256 amountY)"
3229
+ ]);
3230
+ var lbFactoryAbi = parseAbi10([
3231
+ "function getNumberOfLBPairs() external view returns (uint256)",
3232
+ "function getLBPairAtIndex(uint256 index) external view returns (address)"
3233
+ ]);
3234
+ var lbPairAbi = parseAbi10([
3235
+ "function getLBHooksParameters() external view returns (bytes32)",
3236
+ "function getActiveId() external view returns (uint24)",
3237
+ "function getBinStep() external view returns (uint16)",
3238
+ "function getTokenX() external view returns (address)",
3239
+ "function getTokenY() external view returns (address)",
3240
+ "function balanceOf(address account, uint256 id) external view returns (uint256)",
3241
+ "function balanceOfBatch(address[] calldata accounts, uint256[] calldata ids) external view returns (uint256[] memory)"
3242
+ ]);
3243
+ var lbRewarderAbi = parseAbi10([
3244
+ "function getRewardToken() external view returns (address)",
3245
+ "function getRewardedRange() external view returns (uint256 minBinId, uint256 maxBinId)",
3246
+ "function getPendingRewards(address user, uint256[] calldata ids) external view returns (uint256 pendingRewards)",
3247
+ "function claim(address user, uint256[] calldata ids) external",
3248
+ "function getPid() external view returns (uint256)",
3249
+ "function isStopped() external view returns (bool)",
3250
+ "function getLBPair() external view returns (address)",
3251
+ "function getMasterChef() external view returns (address)"
3252
+ ]);
3253
+ var masterChefAbi = parseAbi10([
3254
+ "function getMoePerSecond() external view returns (uint256)",
3255
+ "function getTreasuryShare() external view returns (uint256)",
3256
+ "function getStaticShare() external view returns (uint256)",
3257
+ "function getVeMoe() external view returns (address)"
3258
+ ]);
3259
+ var veMoeAbi = parseAbi10([
3260
+ "function getWeight(uint256 pid) external view returns (uint256)",
3261
+ "function getTotalWeight() external view returns (uint256)",
3262
+ "function getTopPoolIds() external view returns (uint256[] memory)"
3263
+ ]);
3264
+ var lbPairBinAbi = parseAbi10([
3265
+ "function getBin(uint24 id) external view returns (uint128 reserveX, uint128 reserveY)",
3266
+ "function getActiveId() external view returns (uint24)"
3267
+ ]);
3268
+ var lbQuoterAbi2 = parseAbi10([
3269
+ "function findBestPathFromAmountIn(address[] calldata route, uint128 amountIn) external view returns ((address[] route, address[] pairs, uint256[] binSteps, uint256[] versions, uint128[] amounts, uint128[] virtualAmountsWithoutSlippage, uint128[] fees))"
3270
+ ]);
3271
+ var erc20Abi2 = parseAbi10([
3272
+ "function symbol() external view returns (string)"
3273
+ ]);
3274
+ var _addressAbi = parseAbi10(["function f() external view returns (address)"]);
3275
+ function decodeAddressResult(data) {
3276
+ if (!data) return null;
3277
+ try {
3278
+ return decodeFunctionResult22({ abi: _addressAbi, functionName: "f", data });
3279
+ } catch {
3280
+ return null;
3281
+ }
3282
+ }
3283
+ var _uint256Abi = parseAbi10(["function f() external view returns (uint256)"]);
3284
+ function decodeUint256Result(data) {
3285
+ if (!data) return null;
3286
+ try {
3287
+ return decodeFunctionResult22({ abi: _uint256Abi, functionName: "f", data });
3288
+ } catch {
3289
+ return null;
3290
+ }
3291
+ }
3292
+ var _boolAbi = parseAbi10(["function f() external view returns (bool)"]);
3293
+ function decodeBoolResult(data) {
3294
+ if (!data) return null;
3295
+ try {
3296
+ return decodeFunctionResult22({ abi: _boolAbi, functionName: "f", data });
3297
+ } catch {
3298
+ return null;
3299
+ }
3300
+ }
3301
+ function decodeStringResult(data) {
3302
+ if (!data) return "?";
3303
+ try {
3304
+ return decodeFunctionResult22({ abi: erc20Abi2, functionName: "symbol", data });
3305
+ } catch {
3306
+ return "?";
3307
+ }
3308
+ }
3309
+ var _rangeAbi = parseAbi10(["function f() external view returns (uint256 minBinId, uint256 maxBinId)"]);
3310
+ function decodeRangeResult(data) {
3311
+ if (!data) return null;
3312
+ try {
3313
+ return decodeFunctionResult22({ abi: _rangeAbi, functionName: "f", data });
3314
+ } catch {
3315
+ return null;
3316
+ }
3317
+ }
3318
+ var _binAbi = parseAbi10(["function f() external view returns (uint128 reserveX, uint128 reserveY)"]);
3319
+ function decodeBinResult(data) {
3320
+ if (!data) return null;
3321
+ try {
3322
+ return decodeFunctionResult22({ abi: _binAbi, functionName: "f", data });
3323
+ } catch {
3324
+ return null;
3325
+ }
3326
+ }
3327
+ var _uint256ArrayAbi = parseAbi10(["function f() external view returns (uint256[] memory)"]);
3328
+ function decodeUint256ArrayResult(data) {
3329
+ if (!data) return null;
3330
+ try {
3331
+ return decodeFunctionResult22({ abi: _uint256ArrayAbi, functionName: "f", data });
3332
+ } catch {
3333
+ return null;
3334
+ }
3335
+ }
3336
+ function extractRewarderAddress(hooksParams) {
3337
+ if (!hooksParams || hooksParams === "0x0000000000000000000000000000000000000000000000000000000000000000") {
3338
+ return null;
3339
+ }
3340
+ const hex = hooksParams.slice(2);
3341
+ if (hex.length < 64) return null;
3342
+ const addrHex = hex.slice(24, 64);
3343
+ if (addrHex === "0000000000000000000000000000000000000000") return null;
3344
+ return `0x${addrHex}`;
3345
+ }
3346
+ function buildUniformDistribution(deltaIds) {
3347
+ const PRECISION = 10n ** 18n;
3348
+ const n = deltaIds.length;
3349
+ const xBins = deltaIds.filter((d) => d >= 0).length;
3350
+ const yBins = deltaIds.filter((d) => d <= 0).length;
3351
+ const distributionX = [];
3352
+ const distributionY = [];
3353
+ for (const delta of deltaIds) {
3354
+ const xShare = delta >= 0 && xBins > 0 ? PRECISION / BigInt(xBins) : 0n;
3355
+ const yShare = delta <= 0 && yBins > 0 ? PRECISION / BigInt(yBins) : 0n;
3356
+ distributionX.push(xShare);
3357
+ distributionY.push(yShare);
3358
+ }
3359
+ const xSum = distributionX.reduce((a, b) => a + b, 0n);
3360
+ const ySum = distributionY.reduce((a, b) => a + b, 0n);
3361
+ if (xSum > 0n && xSum !== PRECISION) {
3362
+ const firstX = distributionX.findIndex((v) => v > 0n);
3363
+ if (firstX !== -1) distributionX[firstX] += PRECISION - xSum;
3364
+ }
3365
+ if (ySum > 0n && ySum !== PRECISION) {
3366
+ const firstY = distributionY.findIndex((v) => v > 0n);
3367
+ if (firstY !== -1) distributionY[firstY] += PRECISION - ySum;
3368
+ }
3369
+ return { distributionX, distributionY };
3370
+ }
3371
+ var MerchantMoeLBAdapter = class {
3372
+ protocolName;
3373
+ lbRouter;
3374
+ lbFactory;
3375
+ lbQuoter;
3376
+ rpcUrl;
3377
+ /** WMNT address (lb_mid_wmnt in config) used for MOE price routing */
3378
+ wmnt;
3379
+ /** USDT address (lb_mid_usdt in config) used for MNT/USD price routing */
3380
+ usdt;
3381
+ constructor(entry, rpcUrl) {
3382
+ this.protocolName = entry.name;
3383
+ const lbRouter = entry.contracts?.["lb_router"];
3384
+ if (!lbRouter) {
3385
+ throw new DefiError("CONTRACT_ERROR", "Missing 'lb_router' contract address");
3386
+ }
3387
+ const lbFactory = entry.contracts?.["lb_factory"];
3388
+ if (!lbFactory) {
3389
+ throw new DefiError("CONTRACT_ERROR", "Missing 'lb_factory' contract address");
3390
+ }
3391
+ this.lbRouter = lbRouter;
3392
+ this.lbFactory = lbFactory;
3393
+ this.lbQuoter = entry.contracts?.["lb_quoter"];
3394
+ this.wmnt = entry.contracts?.["lb_mid_wmnt"];
3395
+ this.usdt = entry.contracts?.["lb_mid_usdt"];
3396
+ this.rpcUrl = rpcUrl;
3397
+ }
3398
+ name() {
3399
+ return this.protocolName;
3400
+ }
3401
+ requireRpc() {
3402
+ if (!this.rpcUrl) {
3403
+ throw DefiError.rpcError(`[${this.protocolName}] RPC URL required`);
3404
+ }
3405
+ return this.rpcUrl;
3406
+ }
3407
+ /**
3408
+ * Build an addLiquidity transaction for a Liquidity Book pair.
3409
+ * Distributes tokenX/tokenY uniformly across active bin ± numBins.
3410
+ */
3411
+ async buildAddLiquidity(params) {
3412
+ const numBins = params.numBins ?? 5;
3413
+ const deadline = params.deadline ?? BigInt("18446744073709551615");
3414
+ let activeIdDesired = params.activeIdDesired;
3415
+ if (activeIdDesired === void 0) {
3416
+ const rpcUrl = this.requireRpc();
3417
+ const client = createPublicClient6({ transport: http6(rpcUrl) });
3418
+ const activeId = await client.readContract({
3419
+ address: params.pool,
3420
+ abi: lbPairAbi,
3421
+ functionName: "getActiveId"
3422
+ });
3423
+ activeIdDesired = activeId;
3424
+ }
3425
+ const deltaIds = [];
3426
+ for (let d = -numBins; d <= numBins; d++) {
3427
+ deltaIds.push(d);
3428
+ }
3429
+ const { distributionX, distributionY } = buildUniformDistribution(deltaIds);
3430
+ const data = encodeFunctionData10({
3431
+ abi: lbRouterAbi,
3432
+ functionName: "addLiquidity",
3433
+ args: [
3434
+ {
3435
+ tokenX: params.tokenX,
3436
+ tokenY: params.tokenY,
3437
+ binStep: BigInt(params.binStep),
3438
+ amountX: params.amountX,
3439
+ amountY: params.amountY,
3440
+ amountXMin: 0n,
3441
+ amountYMin: 0n,
3442
+ activeIdDesired: BigInt(activeIdDesired),
3443
+ idSlippage: BigInt(numBins + 2),
3444
+ deltaIds: deltaIds.map(BigInt),
3445
+ distributionX,
3446
+ distributionY,
3447
+ to: params.recipient,
3448
+ refundTo: params.recipient,
3449
+ deadline
3450
+ }
3451
+ ]
3452
+ });
3453
+ return {
3454
+ description: `[${this.protocolName}] LB addLiquidity ${params.amountX} tokenX + ${params.amountY} tokenY across ${deltaIds.length} bins`,
3455
+ to: this.lbRouter,
3456
+ data,
3457
+ value: 0n,
3458
+ gas_estimate: 8e5,
3459
+ approvals: [
3460
+ { token: params.tokenX, spender: this.lbRouter, amount: params.amountX },
3461
+ { token: params.tokenY, spender: this.lbRouter, amount: params.amountY }
3462
+ ]
3463
+ };
3464
+ }
3465
+ /**
3466
+ * Build a removeLiquidity transaction for specific LB bins.
3467
+ */
3468
+ async buildRemoveLiquidity(params) {
3469
+ const deadline = params.deadline ?? BigInt("18446744073709551615");
3470
+ const data = encodeFunctionData10({
3471
+ abi: lbRouterAbi,
3472
+ functionName: "removeLiquidity",
3473
+ args: [
3474
+ params.tokenX,
3475
+ params.tokenY,
3476
+ params.binStep,
3477
+ params.amountXMin ?? 0n,
3478
+ params.amountYMin ?? 0n,
3479
+ params.binIds.map(BigInt),
3480
+ params.amounts,
3481
+ params.recipient,
3482
+ deadline
3483
+ ]
3484
+ });
3485
+ return {
3486
+ description: `[${this.protocolName}] LB removeLiquidity from ${params.binIds.length} bins`,
3487
+ to: this.lbRouter,
3488
+ data,
3489
+ value: 0n,
3490
+ gas_estimate: 6e5
3491
+ };
3492
+ }
3493
+ /**
3494
+ * Auto-detect bin IDs for a pool from the rewarder's rewarded range.
3495
+ * Falls back to active bin ± 50 scan if no rewarder exists.
3496
+ */
3497
+ async autoDetectBins(pool) {
3498
+ const rpcUrl = this.requireRpc();
3499
+ const client = createPublicClient6({ transport: http6(rpcUrl) });
3500
+ const hooksParams = await client.readContract({
3501
+ address: pool,
3502
+ abi: lbPairAbi,
3503
+ functionName: "getLBHooksParameters"
3504
+ });
3505
+ const rewarder = extractRewarderAddress(hooksParams);
3506
+ if (rewarder) {
3507
+ const range = await client.readContract({
3508
+ address: rewarder,
3509
+ abi: lbRewarderAbi,
3510
+ functionName: "getRewardedRange"
3511
+ });
3512
+ const min = Number(range[0]);
3513
+ const max = Number(range[1]);
3514
+ const ids2 = [];
3515
+ for (let b = min; b <= max; b++) ids2.push(b);
3516
+ return ids2;
3517
+ }
3518
+ const activeId = await client.readContract({
3519
+ address: pool,
3520
+ abi: lbPairAbi,
3521
+ functionName: "getActiveId"
3522
+ });
3523
+ const ids = [];
3524
+ for (let b = activeId - 50; b <= activeId + 50; b++) ids.push(b);
3525
+ return ids;
3526
+ }
3527
+ /**
3528
+ * Get pending MOE rewards for a user across specified bin IDs.
3529
+ * If binIds is omitted, auto-detects from the rewarder's rewarded range.
3530
+ * Reads the rewarder address from the pool's hooks parameters.
3531
+ */
3532
+ async getPendingRewards(user, pool, binIds) {
3533
+ const rpcUrl = this.requireRpc();
3534
+ const client = createPublicClient6({ transport: http6(rpcUrl) });
3535
+ const hooksParams = await client.readContract({
3536
+ address: pool,
3537
+ abi: lbPairAbi,
3538
+ functionName: "getLBHooksParameters"
3539
+ });
3540
+ const rewarder = extractRewarderAddress(hooksParams);
3541
+ if (!rewarder) {
3542
+ return [];
3543
+ }
3544
+ let resolvedBinIds = binIds;
3545
+ if (!resolvedBinIds || resolvedBinIds.length === 0) {
3546
+ const range = await client.readContract({
3547
+ address: rewarder,
3548
+ abi: lbRewarderAbi,
3549
+ functionName: "getRewardedRange"
3550
+ });
3551
+ const min = Number(range[0]);
3552
+ const max = Number(range[1]);
3553
+ resolvedBinIds = [];
3554
+ for (let b = min; b <= max; b++) resolvedBinIds.push(b);
3555
+ }
3556
+ const [pending, rewardToken] = await Promise.all([
3557
+ client.readContract({
3558
+ address: rewarder,
3559
+ abi: lbRewarderAbi,
3560
+ functionName: "getPendingRewards",
3561
+ args: [user, resolvedBinIds.map(BigInt)]
3562
+ }),
3563
+ client.readContract({
3564
+ address: rewarder,
3565
+ abi: lbRewarderAbi,
3566
+ functionName: "getRewardToken"
3567
+ })
3568
+ ]);
3569
+ return [
3570
+ {
3571
+ token: rewardToken,
3572
+ symbol: "MOE",
3573
+ amount: pending
3574
+ }
3575
+ ];
3576
+ }
3577
+ /**
3578
+ * Build a claim rewards transaction for specific LB bins.
3579
+ * If binIds is omitted, auto-detects from the rewarder's rewarded range.
3580
+ */
3581
+ async buildClaimRewards(user, pool, binIds) {
3582
+ const rpcUrl = this.requireRpc();
3583
+ const client = createPublicClient6({ transport: http6(rpcUrl) });
3584
+ const hooksParams = await client.readContract({
3585
+ address: pool,
3586
+ abi: lbPairAbi,
3587
+ functionName: "getLBHooksParameters"
3588
+ });
3589
+ const rewarder = extractRewarderAddress(hooksParams);
3590
+ if (!rewarder) {
3591
+ throw new DefiError("CONTRACT_ERROR", `[${this.protocolName}] Pool ${pool} has no active rewarder`);
3592
+ }
3593
+ let resolvedBinIds = binIds;
3594
+ if (!resolvedBinIds || resolvedBinIds.length === 0) {
3595
+ const range = await client.readContract({
3596
+ address: rewarder,
3597
+ abi: lbRewarderAbi,
3598
+ functionName: "getRewardedRange"
3599
+ });
3600
+ const min = Number(range[0]);
3601
+ const max = Number(range[1]);
3602
+ resolvedBinIds = [];
3603
+ for (let b = min; b <= max; b++) resolvedBinIds.push(b);
3604
+ }
3605
+ const data = encodeFunctionData10({
3606
+ abi: lbRewarderAbi,
3607
+ functionName: "claim",
3608
+ args: [user, resolvedBinIds.map(BigInt)]
3609
+ });
3610
+ return {
3611
+ description: `[${this.protocolName}] LB claim rewards for ${resolvedBinIds.length} bins`,
3612
+ to: rewarder,
3613
+ data,
3614
+ value: 0n,
3615
+ gas_estimate: 3e5
3616
+ };
3617
+ }
3618
+ /**
3619
+ * Discover all active rewarded LB pools by iterating the factory.
3620
+ * Uses 7 multicall batches to minimise RPC round-trips and avoid 429s.
3621
+ *
3622
+ * Batch 1: getNumberOfLBPairs(), then getLBPairAtIndex(i) for all i
3623
+ * Batch 2: getLBHooksParameters() for all pairs → extract rewarder addresses
3624
+ * Batch 3: isStopped/getRewardedRange/getRewardToken/getPid/getMasterChef for each rewarder
3625
+ * Batch 4: getTokenX/getTokenY for each rewarded pair, then symbol() for unique tokens
3626
+ * Batch 5: Bootstrap MasterChef→VeMoe, then getMoePerSecond/getTreasuryShare/getStaticShare/getTotalWeight/getTopPoolIds
3627
+ * Batch 6: VeMoe.getWeight(pid) for each rewarded pool
3628
+ * Batch 7: Pool.getBin(binId) for all bins in rewarded range of each pool
3629
+ * Price: LB Quoter findBestPathFromAmountIn for MOE/WMNT and WMNT/USDT prices
3630
+ */
3631
+ async discoverRewardedPools() {
3632
+ const rpcUrl = this.requireRpc();
3633
+ const client = createPublicClient6({ transport: http6(rpcUrl) });
3634
+ const pairCount = await client.readContract({
3635
+ address: this.lbFactory,
3636
+ abi: lbFactoryAbi,
3637
+ functionName: "getNumberOfLBPairs"
3638
+ });
3639
+ const count = Number(pairCount);
3640
+ if (count === 0) return [];
3641
+ const batch1Calls = Array.from({ length: count }, (_, i) => [
3642
+ this.lbFactory,
3643
+ encodeFunctionData10({ abi: lbFactoryAbi, functionName: "getLBPairAtIndex", args: [BigInt(i)] })
3644
+ ]);
3645
+ const batch1Results = await multicallRead(rpcUrl, batch1Calls);
3646
+ const pairAddresses = batch1Results.map((r) => decodeAddressResult(r)).filter((a) => a !== null);
3647
+ if (pairAddresses.length === 0) return [];
3648
+ const batch2Calls = pairAddresses.map((pair) => [
3649
+ pair,
3650
+ encodeFunctionData10({ abi: lbPairAbi, functionName: "getLBHooksParameters" })
3651
+ ]);
3652
+ const batch2Results = await multicallRead(rpcUrl, batch2Calls);
3653
+ const rewardedPairs = [];
3654
+ for (let i = 0; i < pairAddresses.length; i++) {
3655
+ const raw = batch2Results[i];
3656
+ if (!raw) continue;
3657
+ let hooksBytes;
3658
+ try {
3659
+ const _bytes32Abi = parseAbi10(["function f() external view returns (bytes32)"]);
3660
+ hooksBytes = decodeFunctionResult22({ abi: _bytes32Abi, functionName: "f", data: raw });
3661
+ } catch {
3662
+ continue;
3663
+ }
3664
+ const rewarder = extractRewarderAddress(hooksBytes);
3665
+ if (rewarder) {
3666
+ rewardedPairs.push({ pool: pairAddresses[i], rewarder });
3667
+ }
3668
+ }
3669
+ if (rewardedPairs.length === 0) return [];
3670
+ const batch3Calls = [];
3671
+ for (const { rewarder } of rewardedPairs) {
3672
+ batch3Calls.push([rewarder, encodeFunctionData10({ abi: lbRewarderAbi, functionName: "isStopped" })]);
3673
+ batch3Calls.push([rewarder, encodeFunctionData10({ abi: lbRewarderAbi, functionName: "getRewardedRange" })]);
3674
+ batch3Calls.push([rewarder, encodeFunctionData10({ abi: lbRewarderAbi, functionName: "getRewardToken" })]);
3675
+ batch3Calls.push([rewarder, encodeFunctionData10({ abi: lbRewarderAbi, functionName: "getPid" })]);
3676
+ batch3Calls.push([rewarder, encodeFunctionData10({ abi: lbRewarderAbi, functionName: "getMasterChef" })]);
3677
+ }
3678
+ const batch3Results = await multicallRead(rpcUrl, batch3Calls);
3679
+ const batch4aCalls = [];
3680
+ for (const { pool } of rewardedPairs) {
3681
+ batch4aCalls.push([pool, encodeFunctionData10({ abi: lbPairAbi, functionName: "getTokenX" })]);
3682
+ batch4aCalls.push([pool, encodeFunctionData10({ abi: lbPairAbi, functionName: "getTokenY" })]);
3683
+ }
3684
+ const batch4aResults = await multicallRead(rpcUrl, batch4aCalls);
3685
+ const tokenXAddresses = [];
3686
+ const tokenYAddresses = [];
3687
+ for (let i = 0; i < rewardedPairs.length; i++) {
3688
+ tokenXAddresses.push(decodeAddressResult(batch4aResults[i * 2] ?? null));
3689
+ tokenYAddresses.push(decodeAddressResult(batch4aResults[i * 2 + 1] ?? null));
3690
+ }
3691
+ const uniqueTokens = Array.from(
3692
+ new Set([...tokenXAddresses, ...tokenYAddresses].filter((a) => a !== null))
3693
+ );
3694
+ const batch4bCalls = uniqueTokens.map((token) => [
3695
+ token,
3696
+ encodeFunctionData10({ abi: erc20Abi2, functionName: "symbol" })
3697
+ ]);
3698
+ const batch4bResults = await multicallRead(rpcUrl, batch4bCalls);
3699
+ const symbolMap = /* @__PURE__ */ new Map();
3700
+ for (let i = 0; i < uniqueTokens.length; i++) {
3701
+ symbolMap.set(uniqueTokens[i], decodeStringResult(batch4bResults[i] ?? null));
3702
+ }
3703
+ const STRIDE3 = 5;
3704
+ const poolData = [];
3705
+ for (let i = 0; i < rewardedPairs.length; i++) {
3706
+ const base = i * STRIDE3;
3707
+ poolData.push({
3708
+ stopped: decodeBoolResult(batch3Results[base] ?? null) ?? false,
3709
+ range: decodeRangeResult(batch3Results[base + 1] ?? null),
3710
+ rewardToken: decodeAddressResult(batch3Results[base + 2] ?? null),
3711
+ pid: Number(decodeUint256Result(batch3Results[base + 3] ?? null) ?? 0n),
3712
+ masterChef: decodeAddressResult(batch3Results[base + 4] ?? null)
3713
+ });
3714
+ }
3715
+ const masterChefAddr = poolData.map((d) => d.masterChef).find((a) => a !== null) ?? null;
3716
+ let moePerDay = 0;
3717
+ let topPoolIds = /* @__PURE__ */ new Set();
3718
+ let totalWeightRaw = 0n;
3719
+ let veMoeAddr = null;
3720
+ if (masterChefAddr) {
3721
+ veMoeAddr = await client.readContract({
3722
+ address: masterChefAddr,
3723
+ abi: masterChefAbi,
3724
+ functionName: "getVeMoe"
3725
+ });
3726
+ const batch5Calls = [
3727
+ [masterChefAddr, encodeFunctionData10({ abi: masterChefAbi, functionName: "getMoePerSecond" })],
3728
+ [masterChefAddr, encodeFunctionData10({ abi: masterChefAbi, functionName: "getTreasuryShare" })],
3729
+ [masterChefAddr, encodeFunctionData10({ abi: masterChefAbi, functionName: "getStaticShare" })],
3730
+ [veMoeAddr, encodeFunctionData10({ abi: veMoeAbi, functionName: "getTotalWeight" })],
3731
+ [veMoeAddr, encodeFunctionData10({ abi: veMoeAbi, functionName: "getTopPoolIds" })]
3732
+ ];
3733
+ const batch5Results = await multicallRead(rpcUrl, batch5Calls);
3734
+ const moePerSecRaw = decodeUint256Result(batch5Results[0] ?? null) ?? 0n;
3735
+ const treasuryShareRaw = decodeUint256Result(batch5Results[1] ?? null) ?? 0n;
3736
+ const staticShareRaw = decodeUint256Result(batch5Results[2] ?? null) ?? 0n;
3737
+ totalWeightRaw = decodeUint256Result(batch5Results[3] ?? null) ?? 0n;
3738
+ const topPoolIdsRaw = decodeUint256ArrayResult(batch5Results[4] ?? null) ?? [];
3739
+ topPoolIds = new Set(topPoolIdsRaw.map(Number));
3740
+ const PRECISION = 10n ** 18n;
3741
+ const netPerSec = moePerSecRaw * (PRECISION - treasuryShareRaw) / PRECISION * (PRECISION - staticShareRaw) / PRECISION;
3742
+ moePerDay = Number(netPerSec * 86400n) / 1e18;
3743
+ }
3744
+ const weightByPid = /* @__PURE__ */ new Map();
3745
+ if (veMoeAddr && rewardedPairs.length > 0) {
3746
+ const batch6Calls = poolData.map((d) => [
3747
+ veMoeAddr,
3748
+ encodeFunctionData10({ abi: veMoeAbi, functionName: "getWeight", args: [BigInt(d.pid)] })
3749
+ ]);
3750
+ const batch6Results = await multicallRead(rpcUrl, batch6Calls);
3751
+ for (let i = 0; i < poolData.length; i++) {
3752
+ weightByPid.set(poolData[i].pid, decodeUint256Result(batch6Results[i] ?? null) ?? 0n);
3753
+ }
3754
+ }
3755
+ let moePriceUsd = 0;
3756
+ let wmntPriceUsd = 0;
3757
+ const MOE_ADDR = "0x4515A45337F461A11Ff0FE8aBF3c606AE5dC00c9";
3758
+ if (this.lbQuoter && this.wmnt && this.usdt) {
3759
+ try {
3760
+ const [moeWmntQuote, wmntUsdtQuote] = await Promise.all([
3761
+ client.readContract({
3762
+ address: this.lbQuoter,
3763
+ abi: lbQuoterAbi2,
3764
+ functionName: "findBestPathFromAmountIn",
3765
+ args: [[MOE_ADDR, this.wmnt], 10n ** 18n]
3766
+ }),
3767
+ client.readContract({
3768
+ address: this.lbQuoter,
3769
+ abi: lbQuoterAbi2,
3770
+ functionName: "findBestPathFromAmountIn",
3771
+ args: [[this.wmnt, this.usdt], 10n ** 18n]
3772
+ })
3773
+ ]);
3774
+ const moeInWmnt = Number(moeWmntQuote.amounts.at(-1) ?? 0n) / 1e18;
3775
+ wmntPriceUsd = Number(wmntUsdtQuote.amounts.at(-1) ?? 0n) / 1e6;
3776
+ moePriceUsd = moeInWmnt * wmntPriceUsd;
3777
+ } catch {
3778
+ }
3779
+ }
3780
+ const binRequests = [];
3781
+ for (let i = 0; i < rewardedPairs.length; i++) {
3782
+ const range = poolData[i].range;
3783
+ if (!range) continue;
3784
+ const minBin = Number(range[0]);
3785
+ const maxBin = Number(range[1]);
3786
+ for (let b = minBin; b <= maxBin; b++) {
3787
+ binRequests.push({ poolIdx: i, binId: b });
3788
+ }
3789
+ }
3790
+ const binReservesX = /* @__PURE__ */ new Map();
3791
+ const binReservesY = /* @__PURE__ */ new Map();
3792
+ if (binRequests.length > 0) {
3793
+ const batch7Calls = binRequests.map(({ poolIdx, binId }) => [
3794
+ rewardedPairs[poolIdx].pool,
3795
+ encodeFunctionData10({ abi: lbPairBinAbi, functionName: "getBin", args: [binId] })
3796
+ ]);
3797
+ const batch7Results = await multicallRead(rpcUrl, batch7Calls);
3798
+ for (let j = 0; j < binRequests.length; j++) {
3799
+ const { poolIdx, binId } = binRequests[j];
3800
+ const decoded = decodeBinResult(batch7Results[j] ?? null);
3801
+ if (!decoded) continue;
3802
+ if (!binReservesX.has(poolIdx)) {
3803
+ binReservesX.set(poolIdx, /* @__PURE__ */ new Map());
3804
+ binReservesY.set(poolIdx, /* @__PURE__ */ new Map());
3805
+ }
3806
+ binReservesX.get(poolIdx).set(binId, decoded[0]);
3807
+ binReservesY.get(poolIdx).set(binId, decoded[1]);
3808
+ }
3809
+ }
3810
+ const stableSymbols = /* @__PURE__ */ new Set(["USDT", "USDC", "MUSD", "AUSD", "USDY", "FDUSD"]);
3811
+ const mntSymbols = /* @__PURE__ */ new Set(["WMNT", "MNT"]);
3812
+ const moeSymbols = /* @__PURE__ */ new Set(["MOE"]);
3813
+ const sixDecimalStables = /* @__PURE__ */ new Set(["USDT", "USDC", "FDUSD"]);
3814
+ const getTokenPriceUsd = (sym) => {
3815
+ if (stableSymbols.has(sym)) return 1;
3816
+ if (mntSymbols.has(sym)) return wmntPriceUsd;
3817
+ if (moeSymbols.has(sym)) return moePriceUsd;
3818
+ return 0;
3819
+ };
3820
+ const getTokenDecimals = (sym) => {
3821
+ return sixDecimalStables.has(sym) ? 6 : 18;
3822
+ };
3823
+ const results = [];
3824
+ for (let i = 0; i < rewardedPairs.length; i++) {
3825
+ const { pool, rewarder } = rewardedPairs[i];
3826
+ const data = poolData[i];
3827
+ const tokenX = tokenXAddresses[i] ?? "0x0000000000000000000000000000000000000000";
3828
+ const tokenY = tokenYAddresses[i] ?? "0x0000000000000000000000000000000000000000";
3829
+ const symX = symbolMap.get(tokenX) ?? "?";
3830
+ const symY = symbolMap.get(tokenY) ?? "?";
3831
+ const isTopPool = topPoolIds.has(data.pid);
3832
+ const weight = weightByPid.get(data.pid) ?? 0n;
3833
+ let poolMoePerDay = 0;
3834
+ if (isTopPool && totalWeightRaw > 0n && weight > 0n) {
3835
+ poolMoePerDay = moePerDay * (Number(weight) / Number(totalWeightRaw));
3836
+ }
3837
+ const rxMap = binReservesX.get(i);
3838
+ const ryMap = binReservesY.get(i);
3839
+ const range = data.range;
3840
+ let rangeTvlUsd = 0;
3841
+ let rewardedBins = 0;
3842
+ if (range) {
3843
+ const minBin = Number(range[0]);
3844
+ const maxBin = Number(range[1]);
3845
+ rewardedBins = maxBin - minBin + 1;
3846
+ if (rxMap && ryMap) {
3847
+ const priceX = getTokenPriceUsd(symX);
3848
+ const priceY = getTokenPriceUsd(symY);
3849
+ const decX = getTokenDecimals(symX);
3850
+ const decY = getTokenDecimals(symY);
3851
+ for (let b = minBin; b <= maxBin; b++) {
3852
+ const rx = rxMap.get(b) ?? 0n;
3853
+ const ry = ryMap.get(b) ?? 0n;
3854
+ rangeTvlUsd += Number(rx) / 10 ** decX * priceX;
3855
+ rangeTvlUsd += Number(ry) / 10 ** decY * priceY;
3856
+ }
3857
+ }
3858
+ }
3859
+ const aprPercent = rangeTvlUsd > 0 && moePriceUsd > 0 ? poolMoePerDay * moePriceUsd * 365 / rangeTvlUsd * 100 : 0;
3860
+ results.push({
3861
+ pool,
3862
+ rewarder,
3863
+ rewardToken: data.rewardToken ?? "0x0000000000000000000000000000000000000000",
3864
+ minBinId: range ? Number(range[0]) : 0,
3865
+ maxBinId: range ? Number(range[1]) : 0,
3866
+ pid: data.pid,
3867
+ stopped: data.stopped,
3868
+ tokenX,
3869
+ tokenY,
3870
+ symbolX: symX,
3871
+ symbolY: symY,
3872
+ isTopPool,
3873
+ moePerDay: poolMoePerDay,
3874
+ rangeTvlUsd,
3875
+ aprPercent,
3876
+ rewardedBins
3877
+ });
3878
+ }
3879
+ return results;
3880
+ }
3881
+ /**
3882
+ * Get a user's LB positions (bin balances) across a range of bin IDs.
3883
+ * If binIds is omitted, auto-detects from the rewarder's rewarded range (or active ± 50).
3884
+ */
3885
+ async getUserPositions(user, pool, binIds) {
3886
+ const rpcUrl = this.requireRpc();
3887
+ const client = createPublicClient6({ transport: http6(rpcUrl) });
3888
+ const resolvedBinIds = binIds && binIds.length > 0 ? binIds : await this.autoDetectBins(pool);
3889
+ const accounts = resolvedBinIds.map(() => user);
3890
+ const ids = resolvedBinIds.map(BigInt);
3891
+ const balances = await client.readContract({
3892
+ address: pool,
3893
+ abi: lbPairAbi,
3894
+ functionName: "balanceOfBatch",
3895
+ args: [accounts, ids]
3896
+ });
3897
+ return resolvedBinIds.map((binId, i) => ({ binId, balance: balances[i] ?? 0n })).filter((p) => p.balance > 0n);
3898
+ }
3899
+ };
3900
+ var POOL_ABI = parseAbi11([
3169
3901
  "function supply(address asset, uint256 amount, address onBehalfOf, uint16 referralCode) external",
3170
3902
  "function borrow(address asset, uint256 amount, uint256 interestRateMode, uint16 referralCode, address onBehalfOf) external",
3171
3903
  "function repay(address asset, uint256 amount, uint256 interestRateMode, address onBehalfOf) external returns (uint256)",
@@ -3173,27 +3905,27 @@ var POOL_ABI = parseAbi10([
3173
3905
  "function getUserAccountData(address user) external view returns (uint256 totalCollateralBase, uint256 totalDebtBase, uint256 availableBorrowsBase, uint256 currentLiquidationThreshold, uint256 ltv, uint256 healthFactor)",
3174
3906
  "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)"
3175
3907
  ]);
3176
- var ERC20_ABI2 = parseAbi10([
3908
+ var ERC20_ABI2 = parseAbi11([
3177
3909
  "function totalSupply() external view returns (uint256)"
3178
3910
  ]);
3179
- var INCENTIVES_ABI = parseAbi10([
3911
+ var INCENTIVES_ABI = parseAbi11([
3180
3912
  "function getIncentivesController() external view returns (address)"
3181
3913
  ]);
3182
- var REWARDS_CONTROLLER_ABI = parseAbi10([
3914
+ var REWARDS_CONTROLLER_ABI = parseAbi11([
3183
3915
  "function getRewardsByAsset(address asset) external view returns (address[])",
3184
3916
  "function getRewardsData(address asset, address reward) external view returns (uint256 index, uint256 emissionsPerSecond, uint256 lastUpdateTimestamp, uint256 distributionEnd)"
3185
3917
  ]);
3186
- var POOL_PROVIDER_ABI = parseAbi10([
3918
+ var POOL_PROVIDER_ABI = parseAbi11([
3187
3919
  "function ADDRESSES_PROVIDER() external view returns (address)"
3188
3920
  ]);
3189
- var ADDRESSES_PROVIDER_ABI = parseAbi10([
3921
+ var ADDRESSES_PROVIDER_ABI = parseAbi11([
3190
3922
  "function getPriceOracle() external view returns (address)"
3191
3923
  ]);
3192
- var ORACLE_ABI = parseAbi10([
3924
+ var ORACLE_ABI = parseAbi11([
3193
3925
  "function getAssetPrice(address asset) external view returns (uint256)",
3194
3926
  "function BASE_CURRENCY_UNIT() external view returns (uint256)"
3195
3927
  ]);
3196
- var ERC20_DECIMALS_ABI = parseAbi10([
3928
+ var ERC20_DECIMALS_ABI = parseAbi11([
3197
3929
  "function decimals() external view returns (uint8)"
3198
3930
  ]);
3199
3931
  function u256ToF64(v) {
@@ -3201,6 +3933,46 @@ function u256ToF64(v) {
3201
3933
  if (v > MAX_U128) return Infinity;
3202
3934
  return Number(v);
3203
3935
  }
3936
+ function decodeAddress(data) {
3937
+ if (!data || data.length < 66) return null;
3938
+ return `0x${data.slice(26, 66)}`;
3939
+ }
3940
+ function decodeAddressArray(data) {
3941
+ if (!data) return [];
3942
+ try {
3943
+ return decodeFunctionResult3({
3944
+ abi: REWARDS_CONTROLLER_ABI,
3945
+ functionName: "getRewardsByAsset",
3946
+ data
3947
+ });
3948
+ } catch {
3949
+ return [];
3950
+ }
3951
+ }
3952
+ function decodeReserveData(data) {
3953
+ if (!data) return null;
3954
+ try {
3955
+ return decodeFunctionResult3({
3956
+ abi: POOL_ABI,
3957
+ functionName: "getReserveData",
3958
+ data
3959
+ });
3960
+ } catch {
3961
+ return null;
3962
+ }
3963
+ }
3964
+ function decodeRewardsData(data) {
3965
+ if (!data) return null;
3966
+ try {
3967
+ return decodeFunctionResult3({
3968
+ abi: REWARDS_CONTROLLER_ABI,
3969
+ functionName: "getRewardsData",
3970
+ data
3971
+ });
3972
+ } catch {
3973
+ return null;
3974
+ }
3975
+ }
3204
3976
  var AaveV3Adapter = class {
3205
3977
  protocolName;
3206
3978
  pool;
@@ -3216,7 +3988,7 @@ var AaveV3Adapter = class {
3216
3988
  return this.protocolName;
3217
3989
  }
3218
3990
  async buildSupply(params) {
3219
- const data = encodeFunctionData10({
3991
+ const data = encodeFunctionData11({
3220
3992
  abi: POOL_ABI,
3221
3993
  functionName: "supply",
3222
3994
  args: [params.asset, params.amount, params.on_behalf_of, 0]
@@ -3232,7 +4004,7 @@ var AaveV3Adapter = class {
3232
4004
  }
3233
4005
  async buildBorrow(params) {
3234
4006
  const rateMode = params.interest_rate_mode === InterestRateMode.Stable ? 1n : 2n;
3235
- const data = encodeFunctionData10({
4007
+ const data = encodeFunctionData11({
3236
4008
  abi: POOL_ABI,
3237
4009
  functionName: "borrow",
3238
4010
  args: [params.asset, params.amount, rateMode, 0, params.on_behalf_of]
@@ -3247,7 +4019,7 @@ var AaveV3Adapter = class {
3247
4019
  }
3248
4020
  async buildRepay(params) {
3249
4021
  const rateMode = params.interest_rate_mode === InterestRateMode.Stable ? 1n : 2n;
3250
- const data = encodeFunctionData10({
4022
+ const data = encodeFunctionData11({
3251
4023
  abi: POOL_ABI,
3252
4024
  functionName: "repay",
3253
4025
  args: [params.asset, params.amount, rateMode, params.on_behalf_of]
@@ -3262,7 +4034,7 @@ var AaveV3Adapter = class {
3262
4034
  };
3263
4035
  }
3264
4036
  async buildWithdraw(params) {
3265
- const data = encodeFunctionData10({
4037
+ const data = encodeFunctionData11({
3266
4038
  abi: POOL_ABI,
3267
4039
  functionName: "withdraw",
3268
4040
  args: [params.asset, params.amount, params.to]
@@ -3277,15 +4049,21 @@ var AaveV3Adapter = class {
3277
4049
  }
3278
4050
  async getRates(asset) {
3279
4051
  if (!this.rpcUrl) throw DefiError.rpcError("No RPC URL configured");
3280
- const client = createPublicClient7({ transport: http7(this.rpcUrl) });
3281
- const result = await client.readContract({
3282
- address: this.pool,
4052
+ const reserveCallData = encodeFunctionData11({
3283
4053
  abi: POOL_ABI,
3284
4054
  functionName: "getReserveData",
3285
4055
  args: [asset]
3286
- }).catch((e) => {
4056
+ });
4057
+ const [reserveRaw] = await multicallRead(this.rpcUrl, [
4058
+ [this.pool, reserveCallData]
4059
+ ]).catch((e) => {
3287
4060
  throw DefiError.rpcError(`[${this.protocolName}] getReserveData failed: ${e}`);
3288
4061
  });
4062
+ const reserveDecoded = decodeReserveData(reserveRaw ?? null);
4063
+ if (!reserveDecoded) {
4064
+ throw DefiError.rpcError(`[${this.protocolName}] getReserveData returned no data`);
4065
+ }
4066
+ const result = reserveDecoded;
3289
4067
  const RAY = 1e27;
3290
4068
  const SECONDS_PER_YEAR4 = 31536e3;
3291
4069
  const toApy = (rayRate) => {
@@ -3297,74 +4075,56 @@ var AaveV3Adapter = class {
3297
4075
  const stableRate = toApy(result[5]);
3298
4076
  const aTokenAddress = result[8];
3299
4077
  const variableDebtTokenAddress = result[10];
3300
- const [totalSupply, totalBorrow] = await Promise.all([
3301
- client.readContract({
3302
- address: aTokenAddress,
3303
- abi: ERC20_ABI2,
3304
- functionName: "totalSupply"
3305
- }).catch(() => 0n),
3306
- client.readContract({
3307
- address: variableDebtTokenAddress,
3308
- abi: ERC20_ABI2,
3309
- functionName: "totalSupply"
3310
- }).catch(() => 0n)
4078
+ const [supplyRaw, borrowRaw] = await multicallRead(this.rpcUrl, [
4079
+ [aTokenAddress, encodeFunctionData11({ abi: ERC20_ABI2, functionName: "totalSupply" })],
4080
+ [variableDebtTokenAddress, encodeFunctionData11({ abi: ERC20_ABI2, functionName: "totalSupply" })]
3311
4081
  ]);
4082
+ const totalSupply = decodeU256(supplyRaw ?? null);
4083
+ const totalBorrow = decodeU256(borrowRaw ?? null);
3312
4084
  const utilization = totalSupply > 0n ? Number(totalBorrow * 10000n / totalSupply) / 100 : 0;
3313
4085
  const supplyRewardTokens = [];
3314
4086
  const borrowRewardTokens = [];
3315
4087
  const supplyEmissions = [];
3316
4088
  const borrowEmissions = [];
3317
4089
  try {
3318
- const controllerAddr = await client.readContract({
3319
- address: aTokenAddress,
3320
- abi: INCENTIVES_ABI,
3321
- functionName: "getIncentivesController"
3322
- });
4090
+ const [controllerRaw] = await multicallRead(this.rpcUrl, [
4091
+ [aTokenAddress, encodeFunctionData11({ abi: INCENTIVES_ABI, functionName: "getIncentivesController" })]
4092
+ ]);
4093
+ const controllerAddr = decodeAddress(controllerRaw ?? null);
3323
4094
  if (controllerAddr && controllerAddr !== zeroAddress5) {
3324
- const [supplyRewards, borrowRewards] = await Promise.all([
3325
- client.readContract({
3326
- address: controllerAddr,
3327
- abi: REWARDS_CONTROLLER_ABI,
3328
- functionName: "getRewardsByAsset",
3329
- args: [aTokenAddress]
3330
- }).catch(() => []),
3331
- client.readContract({
3332
- address: controllerAddr,
3333
- abi: REWARDS_CONTROLLER_ABI,
3334
- functionName: "getRewardsByAsset",
3335
- args: [variableDebtTokenAddress]
3336
- }).catch(() => [])
4095
+ const [supplyRewardsRaw, borrowRewardsRaw] = await multicallRead(this.rpcUrl, [
4096
+ [controllerAddr, encodeFunctionData11({ abi: REWARDS_CONTROLLER_ABI, functionName: "getRewardsByAsset", args: [aTokenAddress] })],
4097
+ [controllerAddr, encodeFunctionData11({ abi: REWARDS_CONTROLLER_ABI, functionName: "getRewardsByAsset", args: [variableDebtTokenAddress] })]
3337
4098
  ]);
3338
- const supplyDataPromises = supplyRewards.map(
3339
- (reward) => client.readContract({
3340
- address: controllerAddr,
3341
- abi: REWARDS_CONTROLLER_ABI,
3342
- functionName: "getRewardsData",
3343
- args: [aTokenAddress, reward]
3344
- }).catch(() => null)
3345
- );
3346
- const supplyData = await Promise.all(supplyDataPromises);
3347
- for (let i = 0; i < supplyRewards.length; i++) {
3348
- const data = supplyData[i];
3349
- if (data && data[1] > 0n) {
3350
- supplyRewardTokens.push(supplyRewards[i]);
3351
- supplyEmissions.push(data[1].toString());
4099
+ const supplyRewards = decodeAddressArray(supplyRewardsRaw ?? null);
4100
+ const borrowRewards = decodeAddressArray(borrowRewardsRaw ?? null);
4101
+ const rewardsDataCalls = [
4102
+ ...supplyRewards.map((reward) => [
4103
+ controllerAddr,
4104
+ encodeFunctionData11({ abi: REWARDS_CONTROLLER_ABI, functionName: "getRewardsData", args: [aTokenAddress, reward] })
4105
+ ]),
4106
+ ...borrowRewards.map((reward) => [
4107
+ controllerAddr,
4108
+ encodeFunctionData11({ abi: REWARDS_CONTROLLER_ABI, functionName: "getRewardsData", args: [variableDebtTokenAddress, reward] })
4109
+ ])
4110
+ ];
4111
+ if (rewardsDataCalls.length > 0) {
4112
+ const rewardsDataResults = await multicallRead(this.rpcUrl, rewardsDataCalls);
4113
+ const supplyDataResults = rewardsDataResults.slice(0, supplyRewards.length);
4114
+ const borrowDataResults = rewardsDataResults.slice(supplyRewards.length);
4115
+ for (let i = 0; i < supplyRewards.length; i++) {
4116
+ const data = decodeRewardsData(supplyDataResults[i] ?? null);
4117
+ if (data && data[1] > 0n) {
4118
+ supplyRewardTokens.push(supplyRewards[i]);
4119
+ supplyEmissions.push(data[1].toString());
4120
+ }
3352
4121
  }
3353
- }
3354
- const borrowDataPromises = borrowRewards.map(
3355
- (reward) => client.readContract({
3356
- address: controllerAddr,
3357
- abi: REWARDS_CONTROLLER_ABI,
3358
- functionName: "getRewardsData",
3359
- args: [variableDebtTokenAddress, reward]
3360
- }).catch(() => null)
3361
- );
3362
- const borrowData = await Promise.all(borrowDataPromises);
3363
- for (let i = 0; i < borrowRewards.length; i++) {
3364
- const data = borrowData[i];
3365
- if (data && data[1] > 0n) {
3366
- borrowRewardTokens.push(borrowRewards[i]);
3367
- borrowEmissions.push(data[1].toString());
4122
+ for (let i = 0; i < borrowRewards.length; i++) {
4123
+ const data = decodeRewardsData(borrowDataResults[i] ?? null);
4124
+ if (data && data[1] > 0n) {
4125
+ borrowRewardTokens.push(borrowRewards[i]);
4126
+ borrowEmissions.push(data[1].toString());
4127
+ }
3368
4128
  }
3369
4129
  }
3370
4130
  }
@@ -3376,55 +4136,49 @@ var AaveV3Adapter = class {
3376
4136
  const hasBorrowRewards = borrowRewardTokens.length > 0;
3377
4137
  if ((hasSupplyRewards || hasBorrowRewards) && totalSupply > 0n) {
3378
4138
  try {
3379
- const providerAddr = await client.readContract({
3380
- address: this.pool,
3381
- abi: POOL_PROVIDER_ABI,
3382
- functionName: "ADDRESSES_PROVIDER"
3383
- });
3384
- const oracleAddr = await client.readContract({
3385
- address: providerAddr,
3386
- abi: ADDRESSES_PROVIDER_ABI,
3387
- functionName: "getPriceOracle"
3388
- });
3389
- const [assetPrice, baseCurrencyUnit, assetDecimals] = await Promise.all([
3390
- client.readContract({
3391
- address: oracleAddr,
3392
- abi: ORACLE_ABI,
3393
- functionName: "getAssetPrice",
3394
- args: [asset]
3395
- }),
3396
- client.readContract({
3397
- address: oracleAddr,
3398
- abi: ORACLE_ABI,
3399
- functionName: "BASE_CURRENCY_UNIT"
3400
- }),
3401
- client.readContract({
3402
- address: asset,
3403
- abi: ERC20_DECIMALS_ABI,
3404
- functionName: "decimals"
3405
- }).catch(() => 18)
4139
+ const [providerRaw] = await multicallRead(this.rpcUrl, [
4140
+ [this.pool, encodeFunctionData11({ abi: POOL_PROVIDER_ABI, functionName: "ADDRESSES_PROVIDER" })]
4141
+ ]);
4142
+ const providerAddr = decodeAddress(providerRaw ?? null);
4143
+ if (!providerAddr) throw new Error("No provider address");
4144
+ const [oracleRaw] = await multicallRead(this.rpcUrl, [
4145
+ [providerAddr, encodeFunctionData11({ abi: ADDRESSES_PROVIDER_ABI, functionName: "getPriceOracle" })]
3406
4146
  ]);
3407
- const priceUnit = Number(baseCurrencyUnit);
4147
+ const oracleAddr = decodeAddress(oracleRaw ?? null);
4148
+ if (!oracleAddr) throw new Error("No oracle address");
4149
+ const [assetPriceRaw, baseCurrencyUnitRaw, assetDecimalsRaw] = await multicallRead(this.rpcUrl, [
4150
+ [oracleAddr, encodeFunctionData11({ abi: ORACLE_ABI, functionName: "getAssetPrice", args: [asset] })],
4151
+ [oracleAddr, encodeFunctionData11({ abi: ORACLE_ABI, functionName: "BASE_CURRENCY_UNIT" })],
4152
+ [asset, encodeFunctionData11({ abi: ERC20_DECIMALS_ABI, functionName: "decimals" })]
4153
+ ]);
4154
+ const assetPrice = decodeU256(assetPriceRaw ?? null);
4155
+ const baseCurrencyUnit = decodeU256(baseCurrencyUnitRaw ?? null);
4156
+ const assetDecimals = assetDecimalsRaw ? Number(decodeU256(assetDecimalsRaw)) : 18;
4157
+ const priceUnit = Number(baseCurrencyUnit) || 1e8;
3408
4158
  const assetPriceF = Number(assetPrice) / priceUnit;
3409
4159
  const assetDecimalsDivisor = 10 ** assetDecimals;
4160
+ const allRewardTokens = Array.from(/* @__PURE__ */ new Set([...supplyRewardTokens, ...borrowRewardTokens]));
4161
+ const rewardPriceCalls = allRewardTokens.flatMap((token) => [
4162
+ [oracleAddr, encodeFunctionData11({ abi: ORACLE_ABI, functionName: "getAssetPrice", args: [token] })],
4163
+ [token, encodeFunctionData11({ abi: ERC20_DECIMALS_ABI, functionName: "decimals" })]
4164
+ ]);
4165
+ const rewardPriceResults = rewardPriceCalls.length > 0 ? await multicallRead(this.rpcUrl, rewardPriceCalls) : [];
4166
+ const rewardPriceMap = /* @__PURE__ */ new Map();
4167
+ for (let i = 0; i < allRewardTokens.length; i++) {
4168
+ const priceRaw = rewardPriceResults[i * 2] ?? null;
4169
+ const decimalsRaw = rewardPriceResults[i * 2 + 1] ?? null;
4170
+ const price = decodeU256(priceRaw);
4171
+ const decimals = decimalsRaw ? Number(decodeU256(decimalsRaw)) : 18;
4172
+ rewardPriceMap.set(allRewardTokens[i].toLowerCase(), { price, decimals });
4173
+ }
3410
4174
  if (hasSupplyRewards) {
3411
4175
  let totalSupplyIncentiveUsdPerYear = 0;
3412
4176
  const totalSupplyUsd = Number(totalSupply) / assetDecimalsDivisor * assetPriceF;
3413
4177
  for (let i = 0; i < supplyRewardTokens.length; i++) {
3414
4178
  const emissionPerSec = BigInt(supplyEmissions[i]);
3415
- const [rewardPrice, rewardDecimals] = await Promise.all([
3416
- client.readContract({
3417
- address: oracleAddr,
3418
- abi: ORACLE_ABI,
3419
- functionName: "getAssetPrice",
3420
- args: [supplyRewardTokens[i]]
3421
- }).catch(() => 0n),
3422
- client.readContract({
3423
- address: supplyRewardTokens[i],
3424
- abi: ERC20_DECIMALS_ABI,
3425
- functionName: "decimals"
3426
- }).catch(() => 18)
3427
- ]);
4179
+ const entry = rewardPriceMap.get(supplyRewardTokens[i].toLowerCase());
4180
+ const rewardPrice = entry?.price ?? 0n;
4181
+ const rewardDecimals = entry?.decimals ?? 18;
3428
4182
  if (rewardPrice > 0n) {
3429
4183
  const rewardPriceF = Number(rewardPrice) / priceUnit;
3430
4184
  const emissionPerYear = Number(emissionPerSec) / 10 ** rewardDecimals * SECONDS_PER_YEAR4;
@@ -3440,19 +4194,9 @@ var AaveV3Adapter = class {
3440
4194
  const totalBorrowUsd = Number(totalBorrow) / assetDecimalsDivisor * assetPriceF;
3441
4195
  for (let i = 0; i < borrowRewardTokens.length; i++) {
3442
4196
  const emissionPerSec = BigInt(borrowEmissions[i]);
3443
- const [rewardPrice, rewardDecimals] = await Promise.all([
3444
- client.readContract({
3445
- address: oracleAddr,
3446
- abi: ORACLE_ABI,
3447
- functionName: "getAssetPrice",
3448
- args: [borrowRewardTokens[i]]
3449
- }).catch(() => 0n),
3450
- client.readContract({
3451
- address: borrowRewardTokens[i],
3452
- abi: ERC20_DECIMALS_ABI,
3453
- functionName: "decimals"
3454
- }).catch(() => 18)
3455
- ]);
4197
+ const entry = rewardPriceMap.get(borrowRewardTokens[i].toLowerCase());
4198
+ const rewardPrice = entry?.price ?? 0n;
4199
+ const rewardDecimals = entry?.decimals ?? 18;
3456
4200
  if (rewardPrice > 0n) {
3457
4201
  const rewardPriceF = Number(rewardPrice) / priceUnit;
3458
4202
  const emissionPerYear = Number(emissionPerSec) / 10 ** rewardDecimals * SECONDS_PER_YEAR4;
@@ -3516,7 +4260,7 @@ var AaveV3Adapter = class {
3516
4260
  };
3517
4261
  }
3518
4262
  };
3519
- var POOL_ABI2 = parseAbi11([
4263
+ var POOL_ABI2 = parseAbi12([
3520
4264
  "function deposit(address asset, uint256 amount, address onBehalfOf, uint16 referralCode) external",
3521
4265
  "function borrow(address asset, uint256 amount, uint256 interestRateMode, uint16 referralCode, address onBehalfOf) external",
3522
4266
  "function repay(address asset, uint256 amount, uint256 rateMode, address onBehalfOf) external returns (uint256)",
@@ -3529,7 +4273,7 @@ var POOL_ABI2 = parseAbi11([
3529
4273
  // [9]=variableDebtTokenAddress, [10]=interestRateStrategyAddress, [11]=id
3530
4274
  "function getReserveData(address asset) external view returns (uint256 configuration, uint128 liquidityIndex, uint128 variableBorrowIndex, uint128 currentLiquidityRate, uint128 currentVariableBorrowRate, uint128 currentStableBorrowRate, uint40 lastUpdateTimestamp, address aTokenAddress, address stableDebtTokenAddress, address variableDebtTokenAddress, address interestRateStrategyAddress, uint8 id)"
3531
4275
  ]);
3532
- var ERC20_ABI22 = parseAbi11([
4276
+ var ERC20_ABI22 = parseAbi12([
3533
4277
  "function totalSupply() external view returns (uint256)"
3534
4278
  ]);
3535
4279
  function u256ToF642(v) {
@@ -3552,7 +4296,7 @@ var AaveV2Adapter = class {
3552
4296
  return this.protocolName;
3553
4297
  }
3554
4298
  async buildSupply(params) {
3555
- const data = encodeFunctionData11({
4299
+ const data = encodeFunctionData12({
3556
4300
  abi: POOL_ABI2,
3557
4301
  functionName: "deposit",
3558
4302
  args: [params.asset, params.amount, params.on_behalf_of, 0]
@@ -3568,7 +4312,7 @@ var AaveV2Adapter = class {
3568
4312
  }
3569
4313
  async buildBorrow(params) {
3570
4314
  const rateMode = params.interest_rate_mode === InterestRateMode.Stable ? 1n : 2n;
3571
- const data = encodeFunctionData11({
4315
+ const data = encodeFunctionData12({
3572
4316
  abi: POOL_ABI2,
3573
4317
  functionName: "borrow",
3574
4318
  args: [params.asset, params.amount, rateMode, 0, params.on_behalf_of]
@@ -3583,7 +4327,7 @@ var AaveV2Adapter = class {
3583
4327
  }
3584
4328
  async buildRepay(params) {
3585
4329
  const rateMode = params.interest_rate_mode === InterestRateMode.Stable ? 1n : 2n;
3586
- const data = encodeFunctionData11({
4330
+ const data = encodeFunctionData12({
3587
4331
  abi: POOL_ABI2,
3588
4332
  functionName: "repay",
3589
4333
  args: [params.asset, params.amount, rateMode, params.on_behalf_of]
@@ -3598,7 +4342,7 @@ var AaveV2Adapter = class {
3598
4342
  };
3599
4343
  }
3600
4344
  async buildWithdraw(params) {
3601
- const data = encodeFunctionData11({
4345
+ const data = encodeFunctionData12({
3602
4346
  abi: POOL_ABI2,
3603
4347
  functionName: "withdraw",
3604
4348
  args: [params.asset, params.amount, params.to]
@@ -3686,7 +4430,7 @@ var AaveV2Adapter = class {
3686
4430
  };
3687
4431
  }
3688
4432
  };
3689
- var ORACLE_ABI2 = parseAbi12([
4433
+ var ORACLE_ABI2 = parseAbi13([
3690
4434
  "function getAssetPrice(address asset) external view returns (uint256)",
3691
4435
  "function getAssetsPrices(address[] calldata assets) external view returns (uint256[] memory)",
3692
4436
  "function BASE_CURRENCY_UNIT() external view returns (uint256)"
@@ -3763,7 +4507,7 @@ var AaveOracleAdapter = class {
3763
4507
  });
3764
4508
  }
3765
4509
  };
3766
- var CTOKEN_ABI = parseAbi13([
4510
+ var CTOKEN_ABI = parseAbi14([
3767
4511
  "function supplyRatePerBlock() external view returns (uint256)",
3768
4512
  "function borrowRatePerBlock() external view returns (uint256)",
3769
4513
  "function totalSupply() external view returns (uint256)",
@@ -3790,7 +4534,7 @@ var CompoundV2Adapter = class {
3790
4534
  return this.protocolName;
3791
4535
  }
3792
4536
  async buildSupply(params) {
3793
- const data = encodeFunctionData12({
4537
+ const data = encodeFunctionData13({
3794
4538
  abi: CTOKEN_ABI,
3795
4539
  functionName: "mint",
3796
4540
  args: [params.amount]
@@ -3804,7 +4548,7 @@ var CompoundV2Adapter = class {
3804
4548
  };
3805
4549
  }
3806
4550
  async buildBorrow(params) {
3807
- const data = encodeFunctionData12({
4551
+ const data = encodeFunctionData13({
3808
4552
  abi: CTOKEN_ABI,
3809
4553
  functionName: "borrow",
3810
4554
  args: [params.amount]
@@ -3818,7 +4562,7 @@ var CompoundV2Adapter = class {
3818
4562
  };
3819
4563
  }
3820
4564
  async buildRepay(params) {
3821
- const data = encodeFunctionData12({
4565
+ const data = encodeFunctionData13({
3822
4566
  abi: CTOKEN_ABI,
3823
4567
  functionName: "repayBorrow",
3824
4568
  args: [params.amount]
@@ -3832,7 +4576,7 @@ var CompoundV2Adapter = class {
3832
4576
  };
3833
4577
  }
3834
4578
  async buildWithdraw(params) {
3835
- const data = encodeFunctionData12({
4579
+ const data = encodeFunctionData13({
3836
4580
  abi: CTOKEN_ABI,
3837
4581
  functionName: "redeem",
3838
4582
  args: [params.amount]
@@ -3881,7 +4625,7 @@ var CompoundV2Adapter = class {
3881
4625
  );
3882
4626
  }
3883
4627
  };
3884
- var COMET_ABI = parseAbi14([
4628
+ var COMET_ABI = parseAbi15([
3885
4629
  "function getUtilization() external view returns (uint256)",
3886
4630
  "function getSupplyRate(uint256 utilization) external view returns (uint64)",
3887
4631
  "function getBorrowRate(uint256 utilization) external view returns (uint64)",
@@ -3907,7 +4651,7 @@ var CompoundV3Adapter = class {
3907
4651
  return this.protocolName;
3908
4652
  }
3909
4653
  async buildSupply(params) {
3910
- const data = encodeFunctionData13({
4654
+ const data = encodeFunctionData14({
3911
4655
  abi: COMET_ABI,
3912
4656
  functionName: "supply",
3913
4657
  args: [params.asset, params.amount]
@@ -3921,7 +4665,7 @@ var CompoundV3Adapter = class {
3921
4665
  };
3922
4666
  }
3923
4667
  async buildBorrow(params) {
3924
- const data = encodeFunctionData13({
4668
+ const data = encodeFunctionData14({
3925
4669
  abi: COMET_ABI,
3926
4670
  functionName: "withdraw",
3927
4671
  args: [params.asset, params.amount]
@@ -3935,7 +4679,7 @@ var CompoundV3Adapter = class {
3935
4679
  };
3936
4680
  }
3937
4681
  async buildRepay(params) {
3938
- const data = encodeFunctionData13({
4682
+ const data = encodeFunctionData14({
3939
4683
  abi: COMET_ABI,
3940
4684
  functionName: "supply",
3941
4685
  args: [params.asset, params.amount]
@@ -3949,7 +4693,7 @@ var CompoundV3Adapter = class {
3949
4693
  };
3950
4694
  }
3951
4695
  async buildWithdraw(params) {
3952
- const data = encodeFunctionData13({
4696
+ const data = encodeFunctionData14({
3953
4697
  abi: COMET_ABI,
3954
4698
  functionName: "withdraw",
3955
4699
  args: [params.asset, params.amount]
@@ -4003,7 +4747,7 @@ var CompoundV3Adapter = class {
4003
4747
  );
4004
4748
  }
4005
4749
  };
4006
- var EULER_VAULT_ABI = parseAbi15([
4750
+ var EULER_VAULT_ABI = parseAbi16([
4007
4751
  "function deposit(uint256 amount, address receiver) external returns (uint256)",
4008
4752
  "function withdraw(uint256 amount, address receiver, address owner) external returns (uint256)",
4009
4753
  "function borrow(uint256 amount, address receiver) external returns (uint256)",
@@ -4029,7 +4773,7 @@ var EulerV2Adapter = class {
4029
4773
  return this.protocolName;
4030
4774
  }
4031
4775
  async buildSupply(params) {
4032
- const data = encodeFunctionData14({
4776
+ const data = encodeFunctionData15({
4033
4777
  abi: EULER_VAULT_ABI,
4034
4778
  functionName: "deposit",
4035
4779
  args: [params.amount, params.on_behalf_of]
@@ -4043,7 +4787,7 @@ var EulerV2Adapter = class {
4043
4787
  };
4044
4788
  }
4045
4789
  async buildBorrow(params) {
4046
- const data = encodeFunctionData14({
4790
+ const data = encodeFunctionData15({
4047
4791
  abi: EULER_VAULT_ABI,
4048
4792
  functionName: "borrow",
4049
4793
  args: [params.amount, params.on_behalf_of]
@@ -4057,7 +4801,7 @@ var EulerV2Adapter = class {
4057
4801
  };
4058
4802
  }
4059
4803
  async buildRepay(params) {
4060
- const data = encodeFunctionData14({
4804
+ const data = encodeFunctionData15({
4061
4805
  abi: EULER_VAULT_ABI,
4062
4806
  functionName: "repay",
4063
4807
  args: [params.amount, params.on_behalf_of]
@@ -4071,7 +4815,7 @@ var EulerV2Adapter = class {
4071
4815
  };
4072
4816
  }
4073
4817
  async buildWithdraw(params) {
4074
- const data = encodeFunctionData14({
4818
+ const data = encodeFunctionData15({
4075
4819
  abi: EULER_VAULT_ABI,
4076
4820
  functionName: "withdraw",
4077
4821
  args: [params.amount, params.to, params.to]
@@ -4120,7 +4864,7 @@ var EulerV2Adapter = class {
4120
4864
  );
4121
4865
  }
4122
4866
  };
4123
- var MORPHO_ABI = parseAbi16([
4867
+ var MORPHO_ABI = parseAbi17([
4124
4868
  "function market(bytes32 id) external view returns (uint128 totalSupplyAssets, uint128 totalSupplyShares, uint128 totalBorrowAssets, uint128 totalBorrowShares, uint128 lastUpdate, uint128 fee)",
4125
4869
  "function idToMarketParams(bytes32 id) external view returns (address loanToken, address collateralToken, address oracle, address irm, uint256 lltv)",
4126
4870
  "function supply((address loanToken, address collateralToken, address oracle, address irm, uint256 lltv) marketParams, uint256 assets, uint256 shares, address onBehalf, bytes data) external returns (uint256 assetsSupplied, uint256 sharesSupplied)",
@@ -4128,13 +4872,13 @@ var MORPHO_ABI = parseAbi16([
4128
4872
  "function repay((address loanToken, address collateralToken, address oracle, address irm, uint256 lltv) marketParams, uint256 assets, uint256 shares, address onBehalf, bytes data) external returns (uint256 assetsRepaid, uint256 sharesRepaid)",
4129
4873
  "function withdraw((address loanToken, address collateralToken, address oracle, address irm, uint256 lltv) marketParams, uint256 assets, uint256 shares, address onBehalf, address receiver) external returns (uint256 assetsWithdrawn, uint256 sharesWithdrawn)"
4130
4874
  ]);
4131
- var META_MORPHO_ABI = parseAbi16([
4875
+ var META_MORPHO_ABI = parseAbi17([
4132
4876
  "function supplyQueueLength() external view returns (uint256)",
4133
4877
  "function supplyQueue(uint256 index) external view returns (bytes32)",
4134
4878
  "function totalAssets() external view returns (uint256)",
4135
4879
  "function totalSupply() external view returns (uint256)"
4136
4880
  ]);
4137
- var IRM_ABI = parseAbi16([
4881
+ var IRM_ABI = parseAbi17([
4138
4882
  "function borrowRateView((address loanToken, address collateralToken, address oracle, address irm, uint256 lltv) marketParams, (uint128 totalSupplyAssets, uint128 totalSupplyShares, uint128 totalBorrowAssets, uint128 totalBorrowShares, uint128 lastUpdate, uint128 fee) market) external view returns (uint256)"
4139
4883
  ]);
4140
4884
  var SECONDS_PER_YEAR3 = 365.25 * 24 * 3600;
@@ -4147,6 +4891,30 @@ function defaultMarketParams(loanToken = zeroAddress7) {
4147
4891
  lltv: 0n
4148
4892
  };
4149
4893
  }
4894
+ function decodeMarket(data) {
4895
+ if (!data) return null;
4896
+ try {
4897
+ return decodeFunctionResult4({
4898
+ abi: MORPHO_ABI,
4899
+ functionName: "market",
4900
+ data
4901
+ });
4902
+ } catch {
4903
+ return null;
4904
+ }
4905
+ }
4906
+ function decodeMarketParams(data) {
4907
+ if (!data) return null;
4908
+ try {
4909
+ return decodeFunctionResult4({
4910
+ abi: MORPHO_ABI,
4911
+ functionName: "idToMarketParams",
4912
+ data
4913
+ });
4914
+ } catch {
4915
+ return null;
4916
+ }
4917
+ }
4150
4918
  var MorphoBlueAdapter = class {
4151
4919
  protocolName;
4152
4920
  morpho;
@@ -4166,7 +4934,7 @@ var MorphoBlueAdapter = class {
4166
4934
  }
4167
4935
  async buildSupply(params) {
4168
4936
  const market = defaultMarketParams(params.asset);
4169
- const data = encodeFunctionData15({
4937
+ const data = encodeFunctionData16({
4170
4938
  abi: MORPHO_ABI,
4171
4939
  functionName: "supply",
4172
4940
  args: [market, params.amount, 0n, params.on_behalf_of, "0x"]
@@ -4181,7 +4949,7 @@ var MorphoBlueAdapter = class {
4181
4949
  }
4182
4950
  async buildBorrow(params) {
4183
4951
  const market = defaultMarketParams(params.asset);
4184
- const data = encodeFunctionData15({
4952
+ const data = encodeFunctionData16({
4185
4953
  abi: MORPHO_ABI,
4186
4954
  functionName: "borrow",
4187
4955
  args: [market, params.amount, 0n, params.on_behalf_of, params.on_behalf_of]
@@ -4196,7 +4964,7 @@ var MorphoBlueAdapter = class {
4196
4964
  }
4197
4965
  async buildRepay(params) {
4198
4966
  const market = defaultMarketParams(params.asset);
4199
- const data = encodeFunctionData15({
4967
+ const data = encodeFunctionData16({
4200
4968
  abi: MORPHO_ABI,
4201
4969
  functionName: "repay",
4202
4970
  args: [market, params.amount, 0n, params.on_behalf_of, "0x"]
@@ -4211,7 +4979,7 @@ var MorphoBlueAdapter = class {
4211
4979
  }
4212
4980
  async buildWithdraw(params) {
4213
4981
  const market = defaultMarketParams(params.asset);
4214
- const data = encodeFunctionData15({
4982
+ const data = encodeFunctionData16({
4215
4983
  abi: MORPHO_ABI,
4216
4984
  functionName: "withdraw",
4217
4985
  args: [market, params.amount, 0n, params.to, params.to]
@@ -4229,14 +4997,12 @@ var MorphoBlueAdapter = class {
4229
4997
  if (!this.defaultVault) {
4230
4998
  throw DefiError.contractError(`[${this.protocolName}] No MetaMorpho vault configured for rate query`);
4231
4999
  }
4232
- const client = createPublicClient13({ transport: http13(this.rpcUrl) });
4233
- const queueLen = await client.readContract({
4234
- address: this.defaultVault,
4235
- abi: META_MORPHO_ABI,
4236
- functionName: "supplyQueueLength"
4237
- }).catch((e) => {
5000
+ const [queueLenRaw] = await multicallRead(this.rpcUrl, [
5001
+ [this.defaultVault, encodeFunctionData16({ abi: META_MORPHO_ABI, functionName: "supplyQueueLength" })]
5002
+ ]).catch((e) => {
4238
5003
  throw DefiError.rpcError(`[${this.protocolName}] supplyQueueLength failed: ${e}`);
4239
5004
  });
5005
+ const queueLen = decodeU256(queueLenRaw ?? null);
4240
5006
  if (queueLen === 0n) {
4241
5007
  return {
4242
5008
  protocol: this.protocolName,
@@ -4248,45 +5014,40 @@ var MorphoBlueAdapter = class {
4248
5014
  total_borrow: 0n
4249
5015
  };
4250
5016
  }
4251
- const marketId = await client.readContract({
4252
- address: this.defaultVault,
4253
- abi: META_MORPHO_ABI,
4254
- functionName: "supplyQueue",
4255
- args: [0n]
4256
- }).catch((e) => {
5017
+ const [marketIdRaw] = await multicallRead(this.rpcUrl, [
5018
+ [this.defaultVault, encodeFunctionData16({ abi: META_MORPHO_ABI, functionName: "supplyQueue", args: [0n] })]
5019
+ ]).catch((e) => {
4257
5020
  throw DefiError.rpcError(`[${this.protocolName}] supplyQueue(0) failed: ${e}`);
4258
5021
  });
4259
- const mkt = await client.readContract({
4260
- address: this.morpho,
4261
- abi: MORPHO_ABI,
4262
- functionName: "market",
4263
- args: [marketId]
4264
- }).catch((e) => {
4265
- throw DefiError.rpcError(`[${this.protocolName}] market() failed: ${e}`);
5022
+ if (!marketIdRaw || marketIdRaw.length < 66) {
5023
+ throw DefiError.rpcError(`[${this.protocolName}] supplyQueue(0) returned no data`);
5024
+ }
5025
+ const marketId = marketIdRaw.slice(0, 66);
5026
+ const [marketRaw, paramsRaw] = await multicallRead(this.rpcUrl, [
5027
+ [this.morpho, encodeFunctionData16({ abi: MORPHO_ABI, functionName: "market", args: [marketId] })],
5028
+ [this.morpho, encodeFunctionData16({ abi: MORPHO_ABI, functionName: "idToMarketParams", args: [marketId] })]
5029
+ ]).catch((e) => {
5030
+ throw DefiError.rpcError(`[${this.protocolName}] market/idToMarketParams failed: ${e}`);
4266
5031
  });
4267
- const [totalSupplyAssets, totalSupplyShares, totalBorrowAssets, totalBorrowShares, lastUpdate, fee] = mkt;
5032
+ const mktDecoded = decodeMarket(marketRaw ?? null);
5033
+ if (!mktDecoded) throw DefiError.rpcError(`[${this.protocolName}] market() returned no data`);
5034
+ const [totalSupplyAssets, totalSupplyShares, totalBorrowAssets, totalBorrowShares, lastUpdate, fee] = mktDecoded;
5035
+ const paramsDecoded = decodeMarketParams(paramsRaw ?? null);
5036
+ if (!paramsDecoded) throw DefiError.rpcError(`[${this.protocolName}] idToMarketParams returned no data`);
5037
+ const [loanToken, collateralToken, oracle, irm, lltv] = paramsDecoded;
4268
5038
  const supplyF = Number(totalSupplyAssets);
4269
5039
  const borrowF = Number(totalBorrowAssets);
4270
5040
  const util = supplyF > 0 ? borrowF / supplyF : 0;
4271
- const params2 = await client.readContract({
4272
- address: this.morpho,
4273
- abi: MORPHO_ABI,
4274
- functionName: "idToMarketParams",
4275
- args: [marketId]
4276
- }).catch((e) => {
4277
- throw DefiError.rpcError(`[${this.protocolName}] idToMarketParams failed: ${e}`);
4278
- });
4279
- const [loanToken, collateralToken, oracle, irm, lltv] = params2;
4280
5041
  const irmMarketParams = { loanToken, collateralToken, oracle, irm, lltv };
4281
5042
  const irmMarket = { totalSupplyAssets, totalSupplyShares, totalBorrowAssets, totalBorrowShares, lastUpdate, fee };
4282
- const borrowRatePerSec = await client.readContract({
4283
- address: irm,
4284
- abi: IRM_ABI,
4285
- functionName: "borrowRateView",
4286
- args: [irmMarketParams, irmMarket]
4287
- }).catch((e) => {
4288
- throw DefiError.rpcError(`[${this.protocolName}] borrowRateView failed: ${e}`);
4289
- });
5043
+ const borrowRatePerSec = await (async () => {
5044
+ const [borrowRateRaw] = await multicallRead(this.rpcUrl, [
5045
+ [irm, encodeFunctionData16({ abi: IRM_ABI, functionName: "borrowRateView", args: [irmMarketParams, irmMarket] })]
5046
+ ]).catch((e) => {
5047
+ throw DefiError.rpcError(`[${this.protocolName}] borrowRateView failed: ${e}`);
5048
+ });
5049
+ return decodeU256(borrowRateRaw ?? null);
5050
+ })();
4290
5051
  const ratePerSec = Number(borrowRatePerSec) / 1e18;
4291
5052
  const borrowApy = ratePerSec * SECONDS_PER_YEAR3 * 100;
4292
5053
  const feePct = Number(fee) / 1e18;
@@ -4307,18 +5068,18 @@ var MorphoBlueAdapter = class {
4307
5068
  );
4308
5069
  }
4309
5070
  };
4310
- var BORROWER_OPS_ABI = parseAbi17([
5071
+ var BORROWER_OPS_ABI = parseAbi18([
4311
5072
  "function openTrove(address _owner, uint256 _ownerIndex, uint256 _collAmount, uint256 _boldAmount, uint256 _upperHint, uint256 _lowerHint, uint256 _annualInterestRate, uint256 _maxUpfrontFee, address _addManager, address _removeManager, address _receiver) external returns (uint256)",
4312
5073
  "function adjustTrove(uint256 _troveId, uint256 _collChange, bool _isCollIncrease, uint256 _debtChange, bool _isDebtIncrease, uint256 _upperHint, uint256 _lowerHint, uint256 _maxUpfrontFee) external",
4313
5074
  "function closeTrove(uint256 _troveId) external"
4314
5075
  ]);
4315
- var TROVE_MANAGER_ABI = parseAbi17([
5076
+ var TROVE_MANAGER_ABI = parseAbi18([
4316
5077
  "function getLatestTroveData(uint256 _troveId) external view returns (uint256 entireDebt, uint256 entireColl, uint256 redistDebtGain, uint256 redistCollGain, uint256 accruedInterest, uint256 recordedDebt, uint256 annualInterestRate, uint256 accruedBatchManagementFee, uint256 weightedRecordedDebt, uint256 lastInterestRateAdjTime)"
4317
5078
  ]);
4318
- var HINT_HELPERS_ABI = parseAbi17([
5079
+ var HINT_HELPERS_ABI = parseAbi18([
4319
5080
  "function getApproxHint(uint256 _collIndex, uint256 _interestRate, uint256 _numTrials, uint256 _inputRandomSeed) external view returns (uint256 hintId, uint256 diff, uint256 latestRandomSeed)"
4320
5081
  ]);
4321
- var SORTED_TROVES_ABI = parseAbi17([
5082
+ var SORTED_TROVES_ABI = parseAbi18([
4322
5083
  "function findInsertPosition(uint256 _annualInterestRate, uint256 _prevId, uint256 _nextId) external view returns (uint256 prevId, uint256 nextId)"
4323
5084
  ]);
4324
5085
  var FelixCdpAdapter = class {
@@ -4346,7 +5107,7 @@ var FelixCdpAdapter = class {
4346
5107
  if (!this.hintHelpers || !this.sortedTroves || !this.rpcUrl) {
4347
5108
  return [0n, 0n];
4348
5109
  }
4349
- const client = createPublicClient14({ transport: http14(this.rpcUrl) });
5110
+ const client = createPublicClient13({ transport: http13(this.rpcUrl) });
4350
5111
  const approxResult = await client.readContract({
4351
5112
  address: this.hintHelpers,
4352
5113
  abi: HINT_HELPERS_ABI,
@@ -4369,7 +5130,7 @@ var FelixCdpAdapter = class {
4369
5130
  const interestRate = 50000000000000000n;
4370
5131
  const [upperHint, lowerHint] = await this.getHints(interestRate);
4371
5132
  const hasHints = upperHint !== 0n || lowerHint !== 0n;
4372
- const data = encodeFunctionData16({
5133
+ const data = encodeFunctionData17({
4373
5134
  abi: BORROWER_OPS_ABI,
4374
5135
  functionName: "openTrove",
4375
5136
  args: [
@@ -4398,7 +5159,7 @@ var FelixCdpAdapter = class {
4398
5159
  async buildAdjust(params) {
4399
5160
  const collChange = params.collateral_delta ?? 0n;
4400
5161
  const debtChange = params.debt_delta ?? 0n;
4401
- const data = encodeFunctionData16({
5162
+ const data = encodeFunctionData17({
4402
5163
  abi: BORROWER_OPS_ABI,
4403
5164
  functionName: "adjustTrove",
4404
5165
  args: [
@@ -4421,7 +5182,7 @@ var FelixCdpAdapter = class {
4421
5182
  };
4422
5183
  }
4423
5184
  async buildClose(params) {
4424
- const data = encodeFunctionData16({
5185
+ const data = encodeFunctionData17({
4425
5186
  abi: BORROWER_OPS_ABI,
4426
5187
  functionName: "closeTrove",
4427
5188
  args: [params.cdp_id]
@@ -4437,7 +5198,7 @@ var FelixCdpAdapter = class {
4437
5198
  async getCdpInfo(cdpId) {
4438
5199
  if (!this.rpcUrl) throw DefiError.rpcError(`[${this.protocolName}] getCdpInfo requires RPC \u2014 set HYPEREVM_RPC_URL`);
4439
5200
  if (!this.troveManager) throw DefiError.contractError(`[${this.protocolName}] trove_manager contract not configured`);
4440
- const client = createPublicClient14({ transport: http14(this.rpcUrl) });
5201
+ const client = createPublicClient13({ transport: http13(this.rpcUrl) });
4441
5202
  const data = await client.readContract({
4442
5203
  address: this.troveManager,
4443
5204
  abi: TROVE_MANAGER_ABI,
@@ -4470,7 +5231,7 @@ var FelixCdpAdapter = class {
4470
5231
  };
4471
5232
  }
4472
5233
  };
4473
- var PRICE_FEED_ABI = parseAbi18([
5234
+ var PRICE_FEED_ABI = parseAbi19([
4474
5235
  "function fetchPrice() external view returns (uint256 price, bool isNewOracleFailureDetected)",
4475
5236
  "function lastGoodPrice() external view returns (uint256)"
4476
5237
  ]);
@@ -4496,7 +5257,7 @@ var FelixOracleAdapter = class {
4496
5257
  if (asset !== this.asset && this.asset !== "0x0000000000000000000000000000000000000000") {
4497
5258
  throw DefiError.unsupported(`[${this.protocolName}] Felix PriceFeed only supports asset ${this.asset}`);
4498
5259
  }
4499
- const client = createPublicClient15({ transport: http15(this.rpcUrl) });
5260
+ const client = createPublicClient14({ transport: http14(this.rpcUrl) });
4500
5261
  let priceVal;
4501
5262
  try {
4502
5263
  const result = await client.readContract({
@@ -4535,7 +5296,7 @@ var FelixOracleAdapter = class {
4535
5296
  return results;
4536
5297
  }
4537
5298
  };
4538
- var ERC4626_ABI = parseAbi19([
5299
+ var ERC4626_ABI = parseAbi20([
4539
5300
  "function asset() external view returns (address)",
4540
5301
  "function totalAssets() external view returns (uint256)",
4541
5302
  "function totalSupply() external view returns (uint256)",
@@ -4559,7 +5320,7 @@ var ERC4626VaultAdapter = class {
4559
5320
  return this.protocolName;
4560
5321
  }
4561
5322
  async buildDeposit(assets, receiver) {
4562
- const data = encodeFunctionData17({
5323
+ const data = encodeFunctionData18({
4563
5324
  abi: ERC4626_ABI,
4564
5325
  functionName: "deposit",
4565
5326
  args: [assets, receiver]
@@ -4573,7 +5334,7 @@ var ERC4626VaultAdapter = class {
4573
5334
  };
4574
5335
  }
4575
5336
  async buildWithdraw(assets, receiver, owner) {
4576
- const data = encodeFunctionData17({
5337
+ const data = encodeFunctionData18({
4577
5338
  abi: ERC4626_ABI,
4578
5339
  functionName: "withdraw",
4579
5340
  args: [assets, receiver, owner]
@@ -4588,7 +5349,7 @@ var ERC4626VaultAdapter = class {
4588
5349
  }
4589
5350
  async totalAssets() {
4590
5351
  if (!this.rpcUrl) throw DefiError.rpcError("No RPC URL configured");
4591
- const client = createPublicClient16({ transport: http16(this.rpcUrl) });
5352
+ const client = createPublicClient15({ transport: http15(this.rpcUrl) });
4592
5353
  return client.readContract({
4593
5354
  address: this.vaultAddress,
4594
5355
  abi: ERC4626_ABI,
@@ -4599,7 +5360,7 @@ var ERC4626VaultAdapter = class {
4599
5360
  }
4600
5361
  async convertToShares(assets) {
4601
5362
  if (!this.rpcUrl) throw DefiError.rpcError("No RPC URL configured");
4602
- const client = createPublicClient16({ transport: http16(this.rpcUrl) });
5363
+ const client = createPublicClient15({ transport: http15(this.rpcUrl) });
4603
5364
  return client.readContract({
4604
5365
  address: this.vaultAddress,
4605
5366
  abi: ERC4626_ABI,
@@ -4611,7 +5372,7 @@ var ERC4626VaultAdapter = class {
4611
5372
  }
4612
5373
  async convertToAssets(shares) {
4613
5374
  if (!this.rpcUrl) throw DefiError.rpcError("No RPC URL configured");
4614
- const client = createPublicClient16({ transport: http16(this.rpcUrl) });
5375
+ const client = createPublicClient15({ transport: http15(this.rpcUrl) });
4615
5376
  return client.readContract({
4616
5377
  address: this.vaultAddress,
4617
5378
  abi: ERC4626_ABI,
@@ -4623,7 +5384,7 @@ var ERC4626VaultAdapter = class {
4623
5384
  }
4624
5385
  async getVaultInfo() {
4625
5386
  if (!this.rpcUrl) throw DefiError.rpcError("No RPC URL configured");
4626
- const client = createPublicClient16({ transport: http16(this.rpcUrl) });
5387
+ const client = createPublicClient15({ transport: http15(this.rpcUrl) });
4627
5388
  const [totalAssets, totalSupply, asset] = await Promise.all([
4628
5389
  client.readContract({ address: this.vaultAddress, abi: ERC4626_ABI, functionName: "totalAssets" }).catch((e) => {
4629
5390
  throw DefiError.rpcError(`[${this.protocolName}] totalAssets failed: ${e}`);
@@ -4644,7 +5405,7 @@ var ERC4626VaultAdapter = class {
4644
5405
  };
4645
5406
  }
4646
5407
  };
4647
- var GENERIC_LST_ABI = parseAbi20([
5408
+ var GENERIC_LST_ABI = parseAbi21([
4648
5409
  "function stake() external payable returns (uint256)",
4649
5410
  "function unstake(uint256 amount) external returns (uint256)"
4650
5411
  ]);
@@ -4661,7 +5422,7 @@ var GenericLstAdapter = class {
4661
5422
  return this.protocolName;
4662
5423
  }
4663
5424
  async buildStake(params) {
4664
- const data = encodeFunctionData18({ abi: GENERIC_LST_ABI, functionName: "stake" });
5425
+ const data = encodeFunctionData19({ abi: GENERIC_LST_ABI, functionName: "stake" });
4665
5426
  return {
4666
5427
  description: `[${this.protocolName}] Stake ${params.amount} HYPE`,
4667
5428
  to: this.staking,
@@ -4671,7 +5432,7 @@ var GenericLstAdapter = class {
4671
5432
  };
4672
5433
  }
4673
5434
  async buildUnstake(params) {
4674
- const data = encodeFunctionData18({
5435
+ const data = encodeFunctionData19({
4675
5436
  abi: GENERIC_LST_ABI,
4676
5437
  functionName: "unstake",
4677
5438
  args: [params.amount]
@@ -4688,11 +5449,11 @@ var GenericLstAdapter = class {
4688
5449
  throw DefiError.unsupported(`[${this.protocolName}] getInfo requires RPC`);
4689
5450
  }
4690
5451
  };
4691
- var STHYPE_ABI = parseAbi21([
5452
+ var STHYPE_ABI = parseAbi222([
4692
5453
  "function submit(address referral) external payable returns (uint256)",
4693
5454
  "function requestWithdrawals(uint256[] amounts, address owner) external returns (uint256[] requestIds)"
4694
5455
  ]);
4695
- var ERC20_ABI3 = parseAbi21([
5456
+ var ERC20_ABI3 = parseAbi222([
4696
5457
  "function totalSupply() external view returns (uint256)"
4697
5458
  ]);
4698
5459
  var StHypeAdapter = class {
@@ -4712,7 +5473,7 @@ var StHypeAdapter = class {
4712
5473
  return this.protocolName;
4713
5474
  }
4714
5475
  async buildStake(params) {
4715
- const data = encodeFunctionData19({
5476
+ const data = encodeFunctionData20({
4716
5477
  abi: STHYPE_ABI,
4717
5478
  functionName: "submit",
4718
5479
  args: [zeroAddress9]
@@ -4726,7 +5487,7 @@ var StHypeAdapter = class {
4726
5487
  };
4727
5488
  }
4728
5489
  async buildUnstake(params) {
4729
- const data = encodeFunctionData19({
5490
+ const data = encodeFunctionData20({
4730
5491
  abi: STHYPE_ABI,
4731
5492
  functionName: "requestWithdrawals",
4732
5493
  args: [[params.amount], params.recipient]
@@ -4741,7 +5502,7 @@ var StHypeAdapter = class {
4741
5502
  }
4742
5503
  async getInfo() {
4743
5504
  if (!this.rpcUrl) throw DefiError.rpcError("No RPC URL configured");
4744
- const client = createPublicClient17({ transport: http17(this.rpcUrl) });
5505
+ const client = createPublicClient16({ transport: http16(this.rpcUrl) });
4745
5506
  const tokenAddr = this.sthypeToken ?? this.staking;
4746
5507
  const totalSupply = await client.readContract({
4747
5508
  address: tokenAddr,
@@ -4759,12 +5520,12 @@ var StHypeAdapter = class {
4759
5520
  };
4760
5521
  }
4761
5522
  };
4762
- var KINETIQ_ABI = parseAbi222([
5523
+ var KINETIQ_ABI = parseAbi23([
4763
5524
  "function stake() external payable returns (uint256)",
4764
5525
  "function requestUnstake(uint256 amount) external returns (uint256)",
4765
5526
  "function totalStaked() external view returns (uint256)"
4766
5527
  ]);
4767
- var ORACLE_ABI3 = parseAbi222([
5528
+ var ORACLE_ABI3 = parseAbi23([
4768
5529
  "function getAssetPrice(address asset) external view returns (uint256)"
4769
5530
  ]);
4770
5531
  var WHYPE = "0x5555555555555555555555555555555555555555";
@@ -4786,7 +5547,7 @@ var KinetiqAdapter = class {
4786
5547
  return this.protocolName;
4787
5548
  }
4788
5549
  async buildStake(params) {
4789
- const data = encodeFunctionData20({ abi: KINETIQ_ABI, functionName: "stake" });
5550
+ const data = encodeFunctionData21({ abi: KINETIQ_ABI, functionName: "stake" });
4790
5551
  return {
4791
5552
  description: `[${this.protocolName}] Stake ${params.amount} HYPE for kHYPE`,
4792
5553
  to: this.staking,
@@ -4796,7 +5557,7 @@ var KinetiqAdapter = class {
4796
5557
  };
4797
5558
  }
4798
5559
  async buildUnstake(params) {
4799
- const data = encodeFunctionData20({
5560
+ const data = encodeFunctionData21({
4800
5561
  abi: KINETIQ_ABI,
4801
5562
  functionName: "requestUnstake",
4802
5563
  args: [params.amount]
@@ -4811,7 +5572,7 @@ var KinetiqAdapter = class {
4811
5572
  }
4812
5573
  async getInfo() {
4813
5574
  if (!this.rpcUrl) throw DefiError.rpcError("No RPC URL configured");
4814
- const client = createPublicClient18({ transport: http18(this.rpcUrl) });
5575
+ const client = createPublicClient17({ transport: http17(this.rpcUrl) });
4815
5576
  const totalStaked = await client.readContract({
4816
5577
  address: this.staking,
4817
5578
  abi: KINETIQ_ABI,
@@ -4833,15 +5594,15 @@ var KinetiqAdapter = class {
4833
5594
  };
4834
5595
  }
4835
5596
  };
4836
- var HLP_ABI = parseAbi23([
5597
+ var HLP_ABI = parseAbi24([
4837
5598
  "function deposit(uint256 amount) external returns (uint256)",
4838
5599
  "function withdraw(uint256 shares) external returns (uint256)"
4839
5600
  ]);
4840
- var RYSK_ABI = parseAbi24([
5601
+ var RYSK_ABI = parseAbi25([
4841
5602
  "function openOption(address underlying, uint256 strikePrice, uint256 expiry, bool isCall, uint256 amount) external returns (uint256 premium)",
4842
5603
  "function closeOption(address underlying, uint256 strikePrice, uint256 expiry, bool isCall, uint256 amount) external returns (uint256 payout)"
4843
5604
  ]);
4844
- var ERC721_ABI = parseAbi25([
5605
+ var ERC721_ABI = parseAbi26([
4845
5606
  "function name() returns (string)",
4846
5607
  "function symbol() returns (string)",
4847
5608
  "function totalSupply() returns (uint256)",
@@ -4861,7 +5622,7 @@ var ERC721Adapter = class {
4861
5622
  }
4862
5623
  async getCollectionInfo(collection) {
4863
5624
  if (!this.rpcUrl) throw DefiError.rpcError("No RPC URL configured");
4864
- const client = createPublicClient19({ transport: http19(this.rpcUrl) });
5625
+ const client = createPublicClient18({ transport: http18(this.rpcUrl) });
4865
5626
  const [collectionName, symbol, totalSupply] = await Promise.all([
4866
5627
  client.readContract({ address: collection, abi: ERC721_ABI, functionName: "name" }).catch((e) => {
4867
5628
  throw DefiError.rpcError(`[${this.protocolName}] name failed: ${e}`);
@@ -4880,7 +5641,7 @@ var ERC721Adapter = class {
4880
5641
  }
4881
5642
  async getTokenInfo(collection, tokenId) {
4882
5643
  if (!this.rpcUrl) throw DefiError.rpcError("No RPC URL configured");
4883
- const client = createPublicClient19({ transport: http19(this.rpcUrl) });
5644
+ const client = createPublicClient18({ transport: http18(this.rpcUrl) });
4884
5645
  const [owner, tokenUri] = await Promise.all([
4885
5646
  client.readContract({ address: collection, abi: ERC721_ABI, functionName: "ownerOf", args: [tokenId] }).catch((e) => {
4886
5647
  throw DefiError.rpcError(`[${this.protocolName}] ownerOf failed: ${e}`);
@@ -4896,7 +5657,7 @@ var ERC721Adapter = class {
4896
5657
  }
4897
5658
  async getBalance(owner, collection) {
4898
5659
  if (!this.rpcUrl) throw DefiError.rpcError("No RPC URL configured");
4899
- const client = createPublicClient19({ transport: http19(this.rpcUrl) });
5660
+ const client = createPublicClient18({ transport: http18(this.rpcUrl) });
4900
5661
  return client.readContract({ address: collection, abi: ERC721_ABI, functionName: "balanceOf", args: [owner] }).catch((e) => {
4901
5662
  throw DefiError.rpcError(`[${this.protocolName}] balanceOf failed: ${e}`);
4902
5663
  });
@@ -5017,6 +5778,9 @@ function createOracleFromCdp(entry, _asset, rpcUrl) {
5017
5778
  throw DefiError.unsupported(`Oracle not available for CDP interface '${entry.interface}'`);
5018
5779
  }
5019
5780
  }
5781
+ function createMerchantMoeLB(entry, rpcUrl) {
5782
+ return new MerchantMoeLBAdapter(entry, rpcUrl);
5783
+ }
5020
5784
  var DexSpotPrice = class {
5021
5785
  /**
5022
5786
  * Get the spot price for `token` denominated in `quoteToken` (e.g. USDC).
@@ -6024,20 +6788,20 @@ function registerYield(parent, getOpts, makeExecutor2) {
6024
6788
  }
6025
6789
 
6026
6790
  // src/commands/portfolio.ts
6027
- import { encodeFunctionData as encodeFunctionData24, parseAbi as parseAbi27 } from "viem";
6791
+ import { encodeFunctionData as encodeFunctionData25, parseAbi as parseAbi28 } from "viem";
6028
6792
 
6029
6793
  // src/portfolio-tracker.ts
6030
6794
  import { mkdirSync, writeFileSync, readdirSync as readdirSync2, readFileSync as readFileSync2, existsSync as existsSync2 } from "fs";
6031
6795
  import { homedir } from "os";
6032
6796
  import { resolve as resolve2 } from "path";
6033
- import { encodeFunctionData as encodeFunctionData23, parseAbi as parseAbi26 } from "viem";
6034
- var ERC20_ABI4 = parseAbi26([
6797
+ import { encodeFunctionData as encodeFunctionData24, parseAbi as parseAbi27 } from "viem";
6798
+ var ERC20_ABI4 = parseAbi27([
6035
6799
  "function balanceOf(address owner) external view returns (uint256)"
6036
6800
  ]);
6037
- var ORACLE_ABI4 = parseAbi26([
6801
+ var ORACLE_ABI4 = parseAbi27([
6038
6802
  "function getAssetPrice(address asset) external view returns (uint256)"
6039
6803
  ]);
6040
- var POOL_ABI3 = parseAbi26([
6804
+ var POOL_ABI3 = parseAbi27([
6041
6805
  "function getUserAccountData(address user) external view returns (uint256 totalCollateralBase, uint256 totalDebtBase, uint256 availableBorrowsBase, uint256 currentLiquidationThreshold, uint256 ltv, uint256 healthFactor)"
6042
6806
  ]);
6043
6807
  function decodeU256Word(data, wordOffset = 0) {
@@ -6066,7 +6830,7 @@ async function takeSnapshot(chainName, wallet, registry) {
6066
6830
  tokenEntries.push({ symbol: t.symbol, address: entry.address, decimals: entry.decimals });
6067
6831
  calls.push([
6068
6832
  entry.address,
6069
- encodeFunctionData23({ abi: ERC20_ABI4, functionName: "balanceOf", args: [user] })
6833
+ encodeFunctionData24({ abi: ERC20_ABI4, functionName: "balanceOf", args: [user] })
6070
6834
  ]);
6071
6835
  callLabels.push(`balance:${t.symbol}`);
6072
6836
  }
@@ -6074,7 +6838,7 @@ async function takeSnapshot(chainName, wallet, registry) {
6074
6838
  for (const p of lendingProtocols) {
6075
6839
  calls.push([
6076
6840
  p.contracts["pool"],
6077
- encodeFunctionData23({ abi: POOL_ABI3, functionName: "getUserAccountData", args: [user] })
6841
+ encodeFunctionData24({ abi: POOL_ABI3, functionName: "getUserAccountData", args: [user] })
6078
6842
  ]);
6079
6843
  callLabels.push(`lending:${p.name}`);
6080
6844
  }
@@ -6084,7 +6848,7 @@ async function takeSnapshot(chainName, wallet, registry) {
6084
6848
  if (oracleAddr) {
6085
6849
  calls.push([
6086
6850
  oracleAddr,
6087
- encodeFunctionData23({ abi: ORACLE_ABI4, functionName: "getAssetPrice", args: [wrappedNative] })
6851
+ encodeFunctionData24({ abi: ORACLE_ABI4, functionName: "getAssetPrice", args: [wrappedNative] })
6088
6852
  ]);
6089
6853
  callLabels.push("price:native");
6090
6854
  }
@@ -6222,13 +6986,13 @@ function calculatePnL(current, previous) {
6222
6986
  }
6223
6987
 
6224
6988
  // src/commands/portfolio.ts
6225
- var ERC20_ABI5 = parseAbi27([
6989
+ var ERC20_ABI5 = parseAbi28([
6226
6990
  "function balanceOf(address owner) external view returns (uint256)"
6227
6991
  ]);
6228
- var POOL_ABI4 = parseAbi27([
6992
+ var POOL_ABI4 = parseAbi28([
6229
6993
  "function getUserAccountData(address user) external view returns (uint256 totalCollateralBase, uint256 totalDebtBase, uint256 availableBorrowsBase, uint256 currentLiquidationThreshold, uint256 ltv, uint256 healthFactor)"
6230
6994
  ]);
6231
- var ORACLE_ABI5 = parseAbi27([
6995
+ var ORACLE_ABI5 = parseAbi28([
6232
6996
  "function getAssetPrice(address asset) external view returns (uint256)"
6233
6997
  ]);
6234
6998
  function decodeU2562(data, wordOffset = 0) {
@@ -6268,7 +7032,7 @@ function registerPortfolio(parent, getOpts) {
6268
7032
  if (entry.address === "0x0000000000000000000000000000000000000000") continue;
6269
7033
  calls.push([
6270
7034
  entry.address,
6271
- encodeFunctionData24({ abi: ERC20_ABI5, functionName: "balanceOf", args: [user] })
7035
+ encodeFunctionData25({ abi: ERC20_ABI5, functionName: "balanceOf", args: [user] })
6272
7036
  ]);
6273
7037
  callLabels.push(`balance:${symbol}`);
6274
7038
  }
@@ -6276,7 +7040,7 @@ function registerPortfolio(parent, getOpts) {
6276
7040
  for (const p of lendingProtocols) {
6277
7041
  calls.push([
6278
7042
  p.contracts["pool"],
6279
- encodeFunctionData24({ abi: POOL_ABI4, functionName: "getUserAccountData", args: [user] })
7043
+ encodeFunctionData25({ abi: POOL_ABI4, functionName: "getUserAccountData", args: [user] })
6280
7044
  ]);
6281
7045
  callLabels.push(`lending:${p.name}`);
6282
7046
  }
@@ -6286,7 +7050,7 @@ function registerPortfolio(parent, getOpts) {
6286
7050
  if (oracleAddr) {
6287
7051
  calls.push([
6288
7052
  oracleAddr,
6289
- encodeFunctionData24({ abi: ORACLE_ABI5, functionName: "getAssetPrice", args: [wrappedNative] })
7053
+ encodeFunctionData25({ abi: ORACLE_ABI5, functionName: "getAssetPrice", args: [wrappedNative] })
6290
7054
  ]);
6291
7055
  callLabels.push("price:native");
6292
7056
  }
@@ -6648,14 +7412,14 @@ function registerAlert(parent, getOpts) {
6648
7412
  }
6649
7413
 
6650
7414
  // src/commands/scan.ts
6651
- import { encodeFunctionData as encodeFunctionData25, parseAbi as parseAbi28 } from "viem";
6652
- var AAVE_ORACLE_ABI = parseAbi28([
7415
+ import { encodeFunctionData as encodeFunctionData26, parseAbi as parseAbi29 } from "viem";
7416
+ var AAVE_ORACLE_ABI = parseAbi29([
6653
7417
  "function getAssetPrice(address asset) external view returns (uint256)"
6654
7418
  ]);
6655
- var UNIV2_ROUTER_ABI = parseAbi28([
7419
+ var UNIV2_ROUTER_ABI = parseAbi29([
6656
7420
  "function getAmountsOut(uint256 amountIn, address[] calldata path) external view returns (uint256[] memory)"
6657
7421
  ]);
6658
- var VTOKEN_ABI = parseAbi28([
7422
+ var VTOKEN_ABI = parseAbi29([
6659
7423
  "function exchangeRateStored() external view returns (uint256)"
6660
7424
  ]);
6661
7425
  var STABLECOINS = /* @__PURE__ */ new Set(["USDC", "USDT", "DAI", "USDT0"]);
@@ -6765,7 +7529,7 @@ function registerScan(parent, getOpts) {
6765
7529
  callTypes.push({ kind: "oracle", oracle: oracle.name, token: token.symbol, oracleDecimals: oracle.decimals });
6766
7530
  calls.push([
6767
7531
  oracle.addr,
6768
- encodeFunctionData25({ abi: AAVE_ORACLE_ABI, functionName: "getAssetPrice", args: [token.address] })
7532
+ encodeFunctionData26({ abi: AAVE_ORACLE_ABI, functionName: "getAssetPrice", args: [token.address] })
6769
7533
  ]);
6770
7534
  }
6771
7535
  }
@@ -6776,7 +7540,7 @@ function registerScan(parent, getOpts) {
6776
7540
  callTypes.push({ kind: "dex", token: token.symbol, outDecimals: quoteStable.decimals });
6777
7541
  calls.push([
6778
7542
  dexRouter,
6779
- encodeFunctionData25({ abi: UNIV2_ROUTER_ABI, functionName: "getAmountsOut", args: [amountIn, path] })
7543
+ encodeFunctionData26({ abi: UNIV2_ROUTER_ABI, functionName: "getAmountsOut", args: [amountIn, path] })
6780
7544
  ]);
6781
7545
  }
6782
7546
  }
@@ -6785,7 +7549,7 @@ function registerScan(parent, getOpts) {
6785
7549
  callTypes.push({ kind: "stable", from: "USDC", to: "USDT", outDecimals: usdt.decimals });
6786
7550
  calls.push([
6787
7551
  dexRouter,
6788
- encodeFunctionData25({
7552
+ encodeFunctionData26({
6789
7553
  abi: UNIV2_ROUTER_ABI,
6790
7554
  functionName: "getAmountsOut",
6791
7555
  args: [BigInt(10) ** BigInt(usdc.decimals), [usdc.address, usdt.address]]
@@ -6794,7 +7558,7 @@ function registerScan(parent, getOpts) {
6794
7558
  callTypes.push({ kind: "stable", from: "USDT", to: "USDC", outDecimals: usdc.decimals });
6795
7559
  calls.push([
6796
7560
  dexRouter,
6797
- encodeFunctionData25({
7561
+ encodeFunctionData26({
6798
7562
  abi: UNIV2_ROUTER_ABI,
6799
7563
  functionName: "getAmountsOut",
6800
7564
  args: [BigInt(10) ** BigInt(usdt.decimals), [usdt.address, usdc.address]]
@@ -6805,7 +7569,7 @@ function registerScan(parent, getOpts) {
6805
7569
  for (const fork of compoundForks) {
6806
7570
  for (const { key, addr } of fork.vtokens) {
6807
7571
  callTypes.push({ kind: "exchangeRate", protocol: fork.name, vtoken: key });
6808
- calls.push([addr, encodeFunctionData25({ abi: VTOKEN_ABI, functionName: "exchangeRateStored", args: [] })]);
7572
+ calls.push([addr, encodeFunctionData26({ abi: VTOKEN_ABI, functionName: "exchangeRateStored", args: [] })]);
6809
7573
  }
6810
7574
  }
6811
7575
  }
@@ -7023,22 +7787,22 @@ async function runAllChains(registry, patterns, oracleThreshold, stableThreshold
7023
7787
  for (const oracle of oracles) {
7024
7788
  for (const token of scanTokens) {
7025
7789
  cts.push({ kind: "oracle", oracle: oracle.name, token: token.symbol, dec: oracle.decimals });
7026
- calls.push([oracle.addr, encodeFunctionData25({ abi: AAVE_ORACLE_ABI, functionName: "getAssetPrice", args: [token.address] })]);
7790
+ calls.push([oracle.addr, encodeFunctionData26({ abi: AAVE_ORACLE_ABI, functionName: "getAssetPrice", args: [token.address] })]);
7027
7791
  }
7028
7792
  }
7029
7793
  if (dexRouter) {
7030
7794
  for (const token of scanTokens) {
7031
7795
  const path = wrappedNative && token.address.toLowerCase() === wrappedNative.toLowerCase() ? [token.address, quoteStable.address] : wrappedNative ? [token.address, wrappedNative, quoteStable.address] : [token.address, quoteStable.address];
7032
7796
  cts.push({ kind: "dex", token: token.symbol, dec: quoteStable.decimals });
7033
- calls.push([dexRouter, encodeFunctionData25({ abi: UNIV2_ROUTER_ABI, functionName: "getAmountsOut", args: [BigInt(10) ** BigInt(token.decimals), path] })]);
7797
+ calls.push([dexRouter, encodeFunctionData26({ abi: UNIV2_ROUTER_ABI, functionName: "getAmountsOut", args: [BigInt(10) ** BigInt(token.decimals), path] })]);
7034
7798
  }
7035
7799
  }
7036
7800
  }
7037
7801
  if (doStable && usdc && usdt && dexRouter) {
7038
7802
  cts.push({ kind: "stable", from: "USDC", to: "USDT", dec: usdt.decimals });
7039
- calls.push([dexRouter, encodeFunctionData25({ abi: UNIV2_ROUTER_ABI, functionName: "getAmountsOut", args: [BigInt(10) ** BigInt(usdc.decimals), [usdc.address, usdt.address]] })]);
7803
+ calls.push([dexRouter, encodeFunctionData26({ abi: UNIV2_ROUTER_ABI, functionName: "getAmountsOut", args: [BigInt(10) ** BigInt(usdc.decimals), [usdc.address, usdt.address]] })]);
7040
7804
  cts.push({ kind: "stable", from: "USDT", to: "USDC", dec: usdc.decimals });
7041
- calls.push([dexRouter, encodeFunctionData25({ abi: UNIV2_ROUTER_ABI, functionName: "getAmountsOut", args: [BigInt(10) ** BigInt(usdt.decimals), [usdt.address, usdc.address]] })]);
7805
+ calls.push([dexRouter, encodeFunctionData26({ abi: UNIV2_ROUTER_ABI, functionName: "getAmountsOut", args: [BigInt(10) ** BigInt(usdt.decimals), [usdt.address, usdc.address]] })]);
7042
7806
  }
7043
7807
  if (calls.length === 0) return null;
7044
7808
  const ct0 = Date.now();
@@ -7166,14 +7930,14 @@ function registerArb(parent, getOpts, makeExecutor2) {
7166
7930
  }
7167
7931
 
7168
7932
  // src/commands/positions.ts
7169
- import { encodeFunctionData as encodeFunctionData26, parseAbi as parseAbi29 } from "viem";
7170
- var ERC20_ABI6 = parseAbi29([
7933
+ import { encodeFunctionData as encodeFunctionData27, parseAbi as parseAbi30 } from "viem";
7934
+ var ERC20_ABI6 = parseAbi30([
7171
7935
  "function balanceOf(address owner) external view returns (uint256)"
7172
7936
  ]);
7173
- var POOL_ABI5 = parseAbi29([
7937
+ var POOL_ABI5 = parseAbi30([
7174
7938
  "function getUserAccountData(address user) external view returns (uint256 totalCollateralBase, uint256 totalDebtBase, uint256 availableBorrowsBase, uint256 currentLiquidationThreshold, uint256 ltv, uint256 healthFactor)"
7175
7939
  ]);
7176
- var ORACLE_ABI6 = parseAbi29([
7940
+ var ORACLE_ABI6 = parseAbi30([
7177
7941
  "function getAssetPrice(address asset) external view returns (uint256)"
7178
7942
  ]);
7179
7943
  function round22(x) {
@@ -7202,7 +7966,7 @@ async function scanSingleChain(chainName, rpc, user, tokens, lendingPools, oracl
7202
7966
  callTypes.push({ kind: "token", symbol: token.symbol, decimals: token.decimals });
7203
7967
  calls.push([
7204
7968
  token.address,
7205
- encodeFunctionData26({ abi: ERC20_ABI6, functionName: "balanceOf", args: [user] })
7969
+ encodeFunctionData27({ abi: ERC20_ABI6, functionName: "balanceOf", args: [user] })
7206
7970
  ]);
7207
7971
  }
7208
7972
  }
@@ -7210,14 +7974,14 @@ async function scanSingleChain(chainName, rpc, user, tokens, lendingPools, oracl
7210
7974
  callTypes.push({ kind: "lending", protocol: name, iface });
7211
7975
  calls.push([
7212
7976
  pool,
7213
- encodeFunctionData26({ abi: POOL_ABI5, functionName: "getUserAccountData", args: [user] })
7977
+ encodeFunctionData27({ abi: POOL_ABI5, functionName: "getUserAccountData", args: [user] })
7214
7978
  ]);
7215
7979
  }
7216
7980
  if (oracleAddr) {
7217
7981
  callTypes.push({ kind: "native_price" });
7218
7982
  calls.push([
7219
7983
  oracleAddr,
7220
- encodeFunctionData26({ abi: ORACLE_ABI6, functionName: "getAssetPrice", args: [wrappedNative] })
7984
+ encodeFunctionData27({ abi: ORACLE_ABI6, functionName: "getAssetPrice", args: [wrappedNative] })
7221
7985
  ]);
7222
7986
  }
7223
7987
  if (calls.length === 0) return null;
@@ -7510,14 +8274,14 @@ function registerPrice(parent, getOpts) {
7510
8274
  }
7511
8275
 
7512
8276
  // src/commands/wallet.ts
7513
- import { createPublicClient as createPublicClient20, http as http20, formatEther } from "viem";
8277
+ import { createPublicClient as createPublicClient19, http as http19, formatEther } from "viem";
7514
8278
  function registerWallet(parent, getOpts) {
7515
8279
  const wallet = parent.command("wallet").description("Wallet management");
7516
8280
  wallet.command("balance").description("Show native token balance").requiredOption("--address <address>", "Wallet address to query").action(async (opts) => {
7517
8281
  const chainName = parent.opts().chain ?? "hyperevm";
7518
8282
  const registry = Registry.loadEmbedded();
7519
8283
  const chain = registry.getChain(chainName);
7520
- const client = createPublicClient20({ transport: http20(chain.effectiveRpcUrl()) });
8284
+ const client = createPublicClient19({ transport: http19(chain.effectiveRpcUrl()) });
7521
8285
  const balance = await client.getBalance({ address: opts.address });
7522
8286
  printOutput({
7523
8287
  chain: chain.name,
@@ -7534,14 +8298,14 @@ function registerWallet(parent, getOpts) {
7534
8298
  }
7535
8299
 
7536
8300
  // src/commands/token.ts
7537
- import { createPublicClient as createPublicClient21, http as http21, maxUint256 } from "viem";
8301
+ import { createPublicClient as createPublicClient20, http as http20, maxUint256 } from "viem";
7538
8302
  function registerToken(parent, getOpts, makeExecutor2) {
7539
8303
  const token = parent.command("token").description("Token operations: approve, allowance, transfer, balance");
7540
8304
  token.command("balance").description("Query token balance for an address").requiredOption("--token <token>", "Token symbol or address").requiredOption("--owner <address>", "Wallet address to query").action(async (opts) => {
7541
8305
  const chainName = parent.opts().chain ?? "hyperevm";
7542
8306
  const registry = Registry.loadEmbedded();
7543
8307
  const chain = registry.getChain(chainName);
7544
- const client = createPublicClient21({ transport: http21(chain.effectiveRpcUrl()) });
8308
+ const client = createPublicClient20({ transport: http20(chain.effectiveRpcUrl()) });
7545
8309
  const tokenAddr = opts.token.startsWith("0x") ? opts.token : registry.resolveToken(chainName, opts.token).address;
7546
8310
  const [balance, symbol, decimals] = await Promise.all([
7547
8311
  client.readContract({ address: tokenAddr, abi: erc20Abi, functionName: "balanceOf", args: [opts.owner] }),
@@ -7570,7 +8334,7 @@ function registerToken(parent, getOpts, makeExecutor2) {
7570
8334
  const chainName = parent.opts().chain ?? "hyperevm";
7571
8335
  const registry = Registry.loadEmbedded();
7572
8336
  const chain = registry.getChain(chainName);
7573
- const client = createPublicClient21({ transport: http21(chain.effectiveRpcUrl()) });
8337
+ const client = createPublicClient20({ transport: http20(chain.effectiveRpcUrl()) });
7574
8338
  const tokenAddr = opts.token.startsWith("0x") ? opts.token : registry.resolveToken(chainName, opts.token).address;
7575
8339
  const allowance = await client.readContract({
7576
8340
  address: tokenAddr,
@@ -7592,8 +8356,8 @@ function registerToken(parent, getOpts, makeExecutor2) {
7592
8356
  }
7593
8357
 
7594
8358
  // src/commands/whales.ts
7595
- import { encodeFunctionData as encodeFunctionData27, parseAbi as parseAbi30 } from "viem";
7596
- var POOL_ABI6 = parseAbi30([
8359
+ import { encodeFunctionData as encodeFunctionData28, parseAbi as parseAbi31 } from "viem";
8360
+ var POOL_ABI6 = parseAbi31([
7597
8361
  "function getUserAccountData(address user) external view returns (uint256 totalCollateralBase, uint256 totalDebtBase, uint256 availableBorrowsBase, uint256 currentLiquidationThreshold, uint256 ltv, uint256 healthFactor)"
7598
8362
  ]);
7599
8363
  function round24(x) {
@@ -7704,7 +8468,7 @@ function registerWhales(parent, getOpts) {
7704
8468
  for (const { pool } of lendingPools) {
7705
8469
  calls.push([
7706
8470
  pool,
7707
- encodeFunctionData27({ abi: POOL_ABI6, functionName: "getUserAccountData", args: [whale.address] })
8471
+ encodeFunctionData28({ abi: POOL_ABI6, functionName: "getUserAccountData", args: [whale.address] })
7708
8472
  ]);
7709
8473
  }
7710
8474
  }
@@ -8132,11 +8896,11 @@ function registerBridge(parent, getOpts) {
8132
8896
  const amountUsdc = Number(BigInt(opts.amount)) / 1e6;
8133
8897
  const { fee, maxFeeSubunits } = await getCctpFeeEstimate(srcDomain, dstDomain, amountUsdc);
8134
8898
  const recipientPadded = `0x${"0".repeat(24)}${recipient.replace("0x", "").toLowerCase()}`;
8135
- const { encodeFunctionData: encodeFunctionData29, parseAbi: parseAbi33 } = await import("viem");
8136
- const tokenMessengerAbi = parseAbi33([
8899
+ const { encodeFunctionData: encodeFunctionData30, parseAbi: parseAbi34 } = await import("viem");
8900
+ const tokenMessengerAbi = parseAbi34([
8137
8901
  "function depositForBurn(uint256 amount, uint32 destinationDomain, bytes32 mintRecipient, address burnToken, bytes32 destinationCaller, uint256 maxFee, uint32 minFinalityThreshold) external returns (uint64 nonce)"
8138
8902
  ]);
8139
- const data = encodeFunctionData29({
8903
+ const data = encodeFunctionData30({
8140
8904
  abi: tokenMessengerAbi,
8141
8905
  functionName: "depositForBurn",
8142
8906
  args: [
@@ -8473,6 +9237,107 @@ function registerSetup(program2) {
8473
9237
  });
8474
9238
  }
8475
9239
 
9240
+ // src/commands/lb.ts
9241
+ function registerLB(parent, getOpts, makeExecutor2) {
9242
+ const lb = parent.command("lb").description("Merchant Moe Liquidity Book: add/remove liquidity, rewards, positions");
9243
+ lb.command("add").description("Add liquidity to a Liquidity Book pair").requiredOption("--protocol <protocol>", "Protocol slug (e.g. merchantmoe-mantle)").requiredOption("--pool <address>", "LB pair address").requiredOption("--token-x <address>", "Token X address").requiredOption("--token-y <address>", "Token Y address").requiredOption("--bin-step <step>", "Bin step of the pair").option("--amount-x <wei>", "Amount of token X in wei", "0").option("--amount-y <wei>", "Amount of token Y in wei", "0").option("--bins <N>", "Number of bins on each side of active bin", "5").option("--active-id <id>", "Active bin id (defaults to on-chain query)").option("--recipient <address>", "Recipient address").action(async (opts) => {
9244
+ const executor = makeExecutor2();
9245
+ const registry = Registry.loadEmbedded();
9246
+ const protocol = registry.getProtocol(opts.protocol);
9247
+ const chainName = parent.opts().chain;
9248
+ const chain = registry.getChain(chainName ?? "mantle");
9249
+ const rpcUrl = chain.effectiveRpcUrl();
9250
+ const adapter = createMerchantMoeLB(protocol, rpcUrl);
9251
+ const recipient = opts.recipient ?? process.env["DEFI_WALLET_ADDRESS"] ?? "0x0000000000000000000000000000000000000001";
9252
+ const tx = await adapter.buildAddLiquidity({
9253
+ pool: opts.pool,
9254
+ tokenX: opts.tokenX,
9255
+ tokenY: opts.tokenY,
9256
+ binStep: parseInt(opts.binStep),
9257
+ amountX: BigInt(opts.amountX),
9258
+ amountY: BigInt(opts.amountY),
9259
+ numBins: parseInt(opts.bins),
9260
+ activeIdDesired: opts.activeId ? parseInt(opts.activeId) : void 0,
9261
+ recipient
9262
+ });
9263
+ const result = await executor.execute(tx);
9264
+ printOutput(result, getOpts());
9265
+ });
9266
+ lb.command("remove").description("Remove liquidity from Liquidity Book bins").requiredOption("--protocol <protocol>", "Protocol slug").requiredOption("--token-x <address>", "Token X address").requiredOption("--token-y <address>", "Token Y address").requiredOption("--bin-step <step>", "Bin step of the pair").requiredOption("--bins <binIds>", "Comma-separated bin IDs to remove from").requiredOption("--amounts <amounts>", "Comma-separated LB token amounts to remove per bin (wei)").option("--recipient <address>", "Recipient address").action(async (opts) => {
9267
+ const executor = makeExecutor2();
9268
+ const registry = Registry.loadEmbedded();
9269
+ const protocol = registry.getProtocol(opts.protocol);
9270
+ const adapter = createMerchantMoeLB(protocol);
9271
+ const recipient = opts.recipient ?? process.env["DEFI_WALLET_ADDRESS"] ?? "0x0000000000000000000000000000000000000001";
9272
+ const binIds = opts.bins.split(",").map((s) => parseInt(s.trim()));
9273
+ const amounts = opts.amounts.split(",").map((s) => BigInt(s.trim()));
9274
+ const tx = await adapter.buildRemoveLiquidity({
9275
+ tokenX: opts.tokenX,
9276
+ tokenY: opts.tokenY,
9277
+ binStep: parseInt(opts.binStep),
9278
+ binIds,
9279
+ amounts,
9280
+ recipient
9281
+ });
9282
+ const result = await executor.execute(tx);
9283
+ printOutput(result, getOpts());
9284
+ });
9285
+ lb.command("rewards").description("Show pending MOE rewards for a pool").requiredOption("--protocol <protocol>", "Protocol slug").requiredOption("--pool <address>", "LB pair address").option("--bins <binIds>", "Comma-separated bin IDs to check (auto-detected from rewarder range if omitted)").option("--address <address>", "Wallet address (defaults to DEFI_WALLET_ADDRESS)").action(async (opts) => {
9286
+ const registry = Registry.loadEmbedded();
9287
+ const protocol = registry.getProtocol(opts.protocol);
9288
+ const chainName = parent.opts().chain;
9289
+ const chain = registry.getChain(chainName ?? "mantle");
9290
+ const rpcUrl = chain.effectiveRpcUrl();
9291
+ const adapter = createMerchantMoeLB(protocol, rpcUrl);
9292
+ const user = opts.address ?? process.env["DEFI_WALLET_ADDRESS"];
9293
+ if (!user) throw new Error("--address or DEFI_WALLET_ADDRESS required");
9294
+ const binIds = opts.bins ? opts.bins.split(",").map((s) => parseInt(s.trim())) : void 0;
9295
+ const rewards = await adapter.getPendingRewards(user, opts.pool, binIds);
9296
+ printOutput(rewards, getOpts());
9297
+ });
9298
+ lb.command("claim").description("Claim pending MOE rewards from a pool").requiredOption("--protocol <protocol>", "Protocol slug").requiredOption("--pool <address>", "LB pair address").option("--bins <binIds>", "Comma-separated bin IDs to claim from (auto-detected from rewarder range if omitted)").option("--address <address>", "Wallet address (defaults to DEFI_WALLET_ADDRESS)").action(async (opts) => {
9299
+ const executor = makeExecutor2();
9300
+ const registry = Registry.loadEmbedded();
9301
+ const protocol = registry.getProtocol(opts.protocol);
9302
+ const chainName = parent.opts().chain;
9303
+ const chain = registry.getChain(chainName ?? "mantle");
9304
+ const rpcUrl = chain.effectiveRpcUrl();
9305
+ const adapter = createMerchantMoeLB(protocol, rpcUrl);
9306
+ const user = opts.address ?? process.env["DEFI_WALLET_ADDRESS"];
9307
+ if (!user) throw new Error("--address or DEFI_WALLET_ADDRESS required");
9308
+ const binIds = opts.bins ? opts.bins.split(",").map((s) => parseInt(s.trim())) : void 0;
9309
+ const tx = await adapter.buildClaimRewards(user, opts.pool, binIds);
9310
+ const result = await executor.execute(tx);
9311
+ printOutput(result, getOpts());
9312
+ });
9313
+ lb.command("discover").description("Find all rewarded LB pools on chain").requiredOption("--protocol <protocol>", "Protocol slug").option("--active-only", "Only show non-stopped pools").action(async (opts) => {
9314
+ const registry = Registry.loadEmbedded();
9315
+ const protocol = registry.getProtocol(opts.protocol);
9316
+ const chainName = parent.opts().chain;
9317
+ const chain = registry.getChain(chainName ?? "mantle");
9318
+ const rpcUrl = chain.effectiveRpcUrl();
9319
+ const adapter = createMerchantMoeLB(protocol, rpcUrl);
9320
+ let pools = await adapter.discoverRewardedPools();
9321
+ if (opts.activeOnly) {
9322
+ pools = pools.filter((p) => !p.stopped);
9323
+ }
9324
+ printOutput(pools, getOpts());
9325
+ });
9326
+ lb.command("positions").description("Show user positions per bin in a LB pool").requiredOption("--protocol <protocol>", "Protocol slug").requiredOption("--pool <address>", "LB pair address").option("--bins <binIds>", "Comma-separated bin IDs to query (auto-detected from rewarder range or active \xB1 50 if omitted)").option("--address <address>", "Wallet address (defaults to DEFI_WALLET_ADDRESS)").action(async (opts) => {
9327
+ const registry = Registry.loadEmbedded();
9328
+ const protocol = registry.getProtocol(opts.protocol);
9329
+ const chainName = parent.opts().chain;
9330
+ const chain = registry.getChain(chainName ?? "mantle");
9331
+ const rpcUrl = chain.effectiveRpcUrl();
9332
+ const adapter = createMerchantMoeLB(protocol, rpcUrl);
9333
+ const user = opts.address ?? process.env["DEFI_WALLET_ADDRESS"];
9334
+ if (!user) throw new Error("--address or DEFI_WALLET_ADDRESS required");
9335
+ const binIds = opts.bins ? opts.bins.split(",").map((s) => parseInt(s.trim())) : void 0;
9336
+ const positions = await adapter.getUserPositions(user, opts.pool, binIds);
9337
+ printOutput(positions, getOpts());
9338
+ });
9339
+ }
9340
+
8476
9341
  // src/cli.ts
8477
9342
  var _require = createRequire(import.meta.url);
8478
9343
  var _pkg = _require("../package.json");
@@ -8484,7 +9349,7 @@ var BANNER = `
8484
9349
  \u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255D\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2551 \u2588\u2588\u2551 \u255A\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2551
8485
9350
  \u255A\u2550\u2550\u2550\u2550\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u2550\u255D\u255A\u2550\u255D \u255A\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u255D\u255A\u2550\u2550\u2550\u2550\u2550\u2550\u255D\u255A\u2550\u255D
8486
9351
 
8487
- 2 chains \xB7 32 protocols \xB7 by HypurrQuant
9352
+ 2 chains \xB7 30 protocols \xB7 by HypurrQuant
8488
9353
 
8489
9354
  Scan exploits, swap tokens, bridge assets, track whales,
8490
9355
  compare yields \u2014 all from your terminal.
@@ -8524,6 +9389,7 @@ registerSwap(program, getOutputMode, makeExecutor);
8524
9389
  registerBridge(program, getOutputMode);
8525
9390
  registerNft(program, getOutputMode);
8526
9391
  registerFarm(program, getOutputMode, makeExecutor);
9392
+ registerLB(program, getOutputMode, makeExecutor);
8527
9393
  registerSetup(program);
8528
9394
  program.command("agent").description("Agent mode: read JSON commands from stdin (for AI agents)").action(async () => {
8529
9395
  const executor = makeExecutor();
@@ -8534,13 +9400,13 @@ program.command("agent").description("Agent mode: read JSON commands from stdin
8534
9400
 
8535
9401
  // src/landing.ts
8536
9402
  import pc3 from "picocolors";
8537
- import { encodeFunctionData as encodeFunctionData28, parseAbi as parseAbi31, formatUnits } from "viem";
9403
+ import { encodeFunctionData as encodeFunctionData29, parseAbi as parseAbi33, formatUnits } from "viem";
8538
9404
  var HYPEREVM_DISPLAY = ["HYPE", "WHYPE", "USDC", "USDT0", "USDe", "kHYPE", "wstHYPE"];
8539
9405
  var MANTLE_DISPLAY = ["MNT", "WMNT", "USDC", "USDT", "WETH", "mETH"];
8540
- var balanceOfAbi = parseAbi31([
9406
+ var balanceOfAbi = parseAbi33([
8541
9407
  "function balanceOf(address account) view returns (uint256)"
8542
9408
  ]);
8543
- var getEthBalanceAbi = parseAbi31([
9409
+ var getEthBalanceAbi = parseAbi33([
8544
9410
  "function getEthBalance(address addr) view returns (uint256)"
8545
9411
  ]);
8546
9412
  async function fetchBalances(rpcUrl, wallet, tokens) {
@@ -8549,7 +9415,7 @@ async function fetchBalances(rpcUrl, wallet, tokens) {
8549
9415
  if (isNative) {
8550
9416
  return [
8551
9417
  MULTICALL3_ADDRESS,
8552
- encodeFunctionData28({
9418
+ encodeFunctionData29({
8553
9419
  abi: getEthBalanceAbi,
8554
9420
  functionName: "getEthBalance",
8555
9421
  args: [wallet]
@@ -8558,7 +9424,7 @@ async function fetchBalances(rpcUrl, wallet, tokens) {
8558
9424
  }
8559
9425
  return [
8560
9426
  t.address,
8561
- encodeFunctionData28({
9427
+ encodeFunctionData29({
8562
9428
  abi: balanceOfAbi,
8563
9429
  functionName: "balanceOf",
8564
9430
  args: [wallet]
@@ -8732,6 +9598,7 @@ async function main() {
8732
9598
  "bridge",
8733
9599
  "nft",
8734
9600
  "farm",
9601
+ "lb",
8735
9602
  "agent",
8736
9603
  "setup",
8737
9604
  "init"