@hypurrquant/defi-cli 0.2.5 → 0.3.1

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.
@@ -986,6 +986,7 @@ var init_dist2 = __esm({
986
986
  TxStatus2["DryRun"] = "dry_run";
987
987
  TxStatus2["Simulated"] = "simulated";
988
988
  TxStatus2["SimulationFailed"] = "simulation_failed";
989
+ TxStatus2["NeedsApproval"] = "needs_approval";
989
990
  TxStatus2["Pending"] = "pending";
990
991
  TxStatus2["Confirmed"] = "confirmed";
991
992
  TxStatus2["Failed"] = "failed";
@@ -1207,6 +1208,24 @@ var init_dist2 = __esm({
1207
1208
  if (!token) throw new Error(`Token not found: ${symbol}`);
1208
1209
  return token;
1209
1210
  }
1211
+ /**
1212
+ * Resolve a pool by name (e.g. "WHYPE/USDC") from a protocol's pool list.
1213
+ * Returns the pool info or throws if not found.
1214
+ */
1215
+ resolvePool(protocolSlug, poolName) {
1216
+ const protocol = this.getProtocol(protocolSlug);
1217
+ if (!protocol.pools || protocol.pools.length === 0) {
1218
+ throw new Error(`Protocol ${protocol.name} has no pools configured`);
1219
+ }
1220
+ const pool = protocol.pools.find(
1221
+ (p) => p.name.toLowerCase() === poolName.toLowerCase()
1222
+ );
1223
+ if (!pool) {
1224
+ const available = protocol.pools.map((p) => p.name).join(", ");
1225
+ throw new Error(`Pool '${poolName}' not found in ${protocol.name}. Available: ${available}`);
1226
+ }
1227
+ return pool;
1228
+ }
1210
1229
  };
1211
1230
  }
1212
1231
  });
@@ -1233,14 +1252,18 @@ __export(dist_exports2, {
1233
1252
  GenericOptionsAdapter: () => GenericOptionsAdapter,
1234
1253
  GenericYieldAdapter: () => GenericYieldAdapter,
1235
1254
  HlpVaultAdapter: () => HlpVaultAdapter,
1255
+ HybraGaugeAdapter: () => HybraGaugeAdapter,
1236
1256
  KinetiqAdapter: () => KinetiqAdapter,
1257
+ KittenSwapFarmingAdapter: () => KittenSwapFarmingAdapter,
1237
1258
  MasterChefAdapter: () => MasterChefAdapter,
1259
+ MerchantMoeLBAdapter: () => MerchantMoeLBAdapter,
1238
1260
  MorphoBlueAdapter: () => MorphoBlueAdapter,
1239
1261
  PendleAdapter: () => PendleAdapter,
1240
1262
  RyskAdapter: () => RyskAdapter,
1241
1263
  SolidlyAdapter: () => SolidlyAdapter,
1242
1264
  SolidlyGaugeAdapter: () => SolidlyGaugeAdapter,
1243
1265
  StHypeAdapter: () => StHypeAdapter,
1266
+ ThenaCLAdapter: () => ThenaCLAdapter,
1244
1267
  UniswapV2Adapter: () => UniswapV2Adapter,
1245
1268
  UniswapV3Adapter: () => UniswapV3Adapter,
1246
1269
  WooFiAdapter: () => WooFiAdapter,
@@ -1248,9 +1271,11 @@ __export(dist_exports2, {
1248
1271
  createDerivatives: () => createDerivatives,
1249
1272
  createDex: () => createDex,
1250
1273
  createGauge: () => createGauge,
1274
+ createKittenSwapFarming: () => createKittenSwapFarming,
1251
1275
  createLending: () => createLending,
1252
1276
  createLiquidStaking: () => createLiquidStaking,
1253
1277
  createMasterChef: () => createMasterChef,
1278
+ createMerchantMoeLB: () => createMerchantMoeLB,
1254
1279
  createNft: () => createNft,
1255
1280
  createOptions: () => createOptions,
1256
1281
  createOracleFromCdp: () => createOracleFromCdp,
@@ -1263,45 +1288,332 @@ import { encodeFunctionData as encodeFunctionData22, parseAbi as parseAbi22, cre
1263
1288
  import { encodeFunctionData as encodeFunctionData32, parseAbi as parseAbi32, createPublicClient as createPublicClient3, http as http3, decodeAbiParameters as decodeAbiParameters3, concatHex, zeroAddress } from "viem";
1264
1289
  import { encodeFunctionData as encodeFunctionData4, parseAbi as parseAbi4, zeroAddress as zeroAddress2 } from "viem";
1265
1290
  import { encodeFunctionData as encodeFunctionData5, parseAbi as parseAbi5 } from "viem";
1266
- import { encodeFunctionData as encodeFunctionData6, parseAbi as parseAbi6, createPublicClient as createPublicClient4, http as http4, decodeAbiParameters as decodeAbiParameters4 } from "viem";
1267
- import { encodeFunctionData as encodeFunctionData7, parseAbi as parseAbi7, zeroAddress as zeroAddress3 } from "viem";
1268
- import { createPublicClient as createPublicClient5, encodeFunctionData as encodeFunctionData8, http as http5, parseAbi as parseAbi8, zeroAddress as zeroAddress4 } from "viem";
1269
- import { encodeFunctionData as encodeFunctionData9, parseAbi as parseAbi9, createPublicClient as createPublicClient6, http as http6 } from "viem";
1270
- import { createPublicClient as createPublicClient7, http as http7, parseAbi as parseAbi10, encodeFunctionData as encodeFunctionData10, zeroAddress as zeroAddress5 } from "viem";
1271
- import { createPublicClient as createPublicClient8, http as http8, parseAbi as parseAbi11, encodeFunctionData as encodeFunctionData11, zeroAddress as zeroAddress6 } from "viem";
1272
- import { createPublicClient as createPublicClient9, http as http9, parseAbi as parseAbi12 } from "viem";
1273
- import { createPublicClient as createPublicClient10, http as http10, parseAbi as parseAbi13, encodeFunctionData as encodeFunctionData12 } from "viem";
1274
- import { createPublicClient as createPublicClient11, http as http11, parseAbi as parseAbi14, encodeFunctionData as encodeFunctionData13 } from "viem";
1275
- import { createPublicClient as createPublicClient12, http as http12, parseAbi as parseAbi15, encodeFunctionData as encodeFunctionData14 } from "viem";
1276
- import { createPublicClient as createPublicClient13, http as http13, parseAbi as parseAbi16, encodeFunctionData as encodeFunctionData15, zeroAddress as zeroAddress7 } from "viem";
1277
- import { createPublicClient as createPublicClient14, http as http14, parseAbi as parseAbi17, encodeFunctionData as encodeFunctionData16, zeroAddress as zeroAddress8 } from "viem";
1278
- import { createPublicClient as createPublicClient15, http as http15, parseAbi as parseAbi18 } from "viem";
1279
- import { createPublicClient as createPublicClient16, http as http16, parseAbi as parseAbi19, encodeFunctionData as encodeFunctionData17 } from "viem";
1280
- import { parseAbi as parseAbi20, encodeFunctionData as encodeFunctionData18 } from "viem";
1281
- import { createPublicClient as createPublicClient17, http as http17, parseAbi as parseAbi21, encodeFunctionData as encodeFunctionData19, zeroAddress as zeroAddress9 } from "viem";
1282
- import { createPublicClient as createPublicClient18, http as http18, parseAbi as parseAbi222, encodeFunctionData as encodeFunctionData20, zeroAddress as zeroAddress10 } from "viem";
1283
- import { parseAbi as parseAbi23, encodeFunctionData as encodeFunctionData21 } from "viem";
1291
+ import { encodeFunctionData as encodeFunctionData6, parseAbi as parseAbi6, decodeAbiParameters as decodeAbiParameters4 } from "viem";
1292
+ import { encodeFunctionData as encodeFunctionData7, parseAbi as parseAbi7, createPublicClient as createPublicClient4, http as http4, zeroAddress as zeroAddress3 } from "viem";
1293
+ import { createPublicClient as createPublicClient5, decodeFunctionResult as decodeFunctionResult22, encodeFunctionData as encodeFunctionData8, http as http5, parseAbi as parseAbi8, zeroAddress as zeroAddress4 } from "viem";
1294
+ import { encodeFunctionData as encodeFunctionData9, parseAbi as parseAbi9, zeroAddress as zeroAddress5 } from "viem";
1295
+ import { createPublicClient as createPublicClient6, decodeFunctionResult as decodeFunctionResult3, encodeFunctionData as encodeFunctionData10, http as http6, parseAbi as parseAbi10, zeroAddress as zeroAddress6 } from "viem";
1296
+ import { encodeFunctionData as encodeFunctionData11, parseAbi as parseAbi11, createPublicClient as createPublicClient7, http as http7 } from "viem";
1297
+ import {
1298
+ encodeFunctionData as encodeFunctionData12,
1299
+ decodeFunctionResult as decodeFunctionResult4,
1300
+ parseAbi as parseAbi12,
1301
+ createPublicClient as createPublicClient8,
1302
+ http as http8
1303
+ } from "viem";
1304
+ import {
1305
+ decodeAbiParameters as decodeAbiParameters5,
1306
+ encodeFunctionData as encodeFunctionData13,
1307
+ encodeAbiParameters,
1308
+ http as http9,
1309
+ createPublicClient as createPublicClient9,
1310
+ keccak256,
1311
+ parseAbi as parseAbi13,
1312
+ decodeFunctionResult as decodeFunctionResult5,
1313
+ zeroAddress as zeroAddress7
1314
+ } from "viem";
1315
+ import { createPublicClient as createPublicClient10, http as http10, parseAbi as parseAbi14, encodeFunctionData as encodeFunctionData14, decodeFunctionResult as decodeFunctionResult6, zeroAddress as zeroAddress8 } from "viem";
1316
+ import { createPublicClient as createPublicClient11, http as http11, parseAbi as parseAbi15, encodeFunctionData as encodeFunctionData15, zeroAddress as zeroAddress9 } from "viem";
1317
+ import { createPublicClient as createPublicClient12, http as http12, parseAbi as parseAbi16 } from "viem";
1318
+ import { createPublicClient as createPublicClient13, http as http13, parseAbi as parseAbi17, encodeFunctionData as encodeFunctionData16 } from "viem";
1319
+ import { createPublicClient as createPublicClient14, http as http14, parseAbi as parseAbi18, encodeFunctionData as encodeFunctionData17 } from "viem";
1320
+ import { createPublicClient as createPublicClient15, http as http15, parseAbi as parseAbi19, encodeFunctionData as encodeFunctionData18 } from "viem";
1321
+ import { parseAbi as parseAbi20, encodeFunctionData as encodeFunctionData19, decodeFunctionResult as decodeFunctionResult7, zeroAddress as zeroAddress10 } from "viem";
1322
+ import { createPublicClient as createPublicClient16, http as http16, parseAbi as parseAbi21, encodeFunctionData as encodeFunctionData20, zeroAddress as zeroAddress11 } from "viem";
1323
+ import { createPublicClient as createPublicClient17, http as http17, parseAbi as parseAbi222 } from "viem";
1324
+ import { createPublicClient as createPublicClient18, http as http18, parseAbi as parseAbi23, encodeFunctionData as encodeFunctionData21 } from "viem";
1284
1325
  import { parseAbi as parseAbi24, encodeFunctionData as encodeFunctionData222 } from "viem";
1285
- import { createPublicClient as createPublicClient19, http as http19, parseAbi as parseAbi25 } from "viem";
1326
+ import { createPublicClient as createPublicClient19, http as http19, parseAbi as parseAbi25, encodeFunctionData as encodeFunctionData23, zeroAddress as zeroAddress12 } from "viem";
1327
+ import { createPublicClient as createPublicClient20, http as http20, parseAbi as parseAbi26, encodeFunctionData as encodeFunctionData24, zeroAddress as zeroAddress13 } from "viem";
1328
+ import { parseAbi as parseAbi27, encodeFunctionData as encodeFunctionData25 } from "viem";
1329
+ import { parseAbi as parseAbi28, encodeFunctionData as encodeFunctionData26 } from "viem";
1330
+ import { createPublicClient as createPublicClient21, http as http21, parseAbi as parseAbi29 } from "viem";
1331
+ function pctToTickDelta(pct) {
1332
+ return Math.round(Math.log(1 + pct / 100) / Math.log(1.0001));
1333
+ }
1334
+ function alignTickDown(tick, tickSpacing) {
1335
+ return Math.floor(tick / tickSpacing) * tickSpacing;
1336
+ }
1337
+ function alignTickUp(tick, tickSpacing) {
1338
+ return Math.ceil(tick / tickSpacing) * tickSpacing;
1339
+ }
1340
+ function rangeToTicks(currentTick, rangePct, tickSpacing) {
1341
+ const delta = pctToTickDelta(rangePct);
1342
+ return {
1343
+ tickLower: alignTickDown(currentTick - delta, tickSpacing),
1344
+ tickUpper: alignTickUp(currentTick + delta, tickSpacing)
1345
+ };
1346
+ }
1347
+ function decodeAddress(data) {
1348
+ if (!data) return null;
1349
+ try {
1350
+ return decodeFunctionResult22({ abi: _addressDecodeAbi, functionName: "f", data });
1351
+ } catch {
1352
+ return null;
1353
+ }
1354
+ }
1355
+ function decodeSymbol(data) {
1356
+ if (!data) return "?";
1357
+ try {
1358
+ return decodeFunctionResult22({ abi: _symbolDecodeAbi, functionName: "symbol", data });
1359
+ } catch {
1360
+ return "?";
1361
+ }
1362
+ }
1363
+ function decodeAddress2(data) {
1364
+ if (!data) return null;
1365
+ try {
1366
+ return decodeFunctionResult3({ abi: _addressDecodeAbi2, functionName: "f", data });
1367
+ } catch {
1368
+ return null;
1369
+ }
1370
+ }
1371
+ function decodeSymbol2(data) {
1372
+ if (!data) return "?";
1373
+ try {
1374
+ return decodeFunctionResult3({ abi: _symbolDecodeAbi2, functionName: "symbol", data });
1375
+ } catch {
1376
+ return "?";
1377
+ }
1378
+ }
1379
+ function decodeBoolean(data) {
1380
+ try {
1381
+ return decodeFunctionResult3({ abi: _boolDecodeAbi, functionName: "f", data });
1382
+ } catch {
1383
+ return false;
1384
+ }
1385
+ }
1386
+ function decodeAddressResult(data) {
1387
+ if (!data) return null;
1388
+ try {
1389
+ return decodeFunctionResult4({ abi: _addressAbi, functionName: "f", data });
1390
+ } catch {
1391
+ return null;
1392
+ }
1393
+ }
1394
+ function decodeUint256Result(data) {
1395
+ if (!data) return null;
1396
+ try {
1397
+ return decodeFunctionResult4({ abi: _uint256Abi, functionName: "f", data });
1398
+ } catch {
1399
+ return null;
1400
+ }
1401
+ }
1402
+ function decodeBoolResult(data) {
1403
+ if (!data) return null;
1404
+ try {
1405
+ return decodeFunctionResult4({ abi: _boolAbi, functionName: "f", data });
1406
+ } catch {
1407
+ return null;
1408
+ }
1409
+ }
1410
+ function decodeStringResult(data) {
1411
+ if (!data) return "?";
1412
+ try {
1413
+ return decodeFunctionResult4({ abi: erc20Abi2, functionName: "symbol", data });
1414
+ } catch {
1415
+ return "?";
1416
+ }
1417
+ }
1418
+ function decodeRangeResult(data) {
1419
+ if (!data) return null;
1420
+ try {
1421
+ return decodeFunctionResult4({ abi: _rangeAbi, functionName: "f", data });
1422
+ } catch {
1423
+ return null;
1424
+ }
1425
+ }
1426
+ function decodeBinResult(data) {
1427
+ if (!data) return null;
1428
+ try {
1429
+ return decodeFunctionResult4({ abi: _binAbi, functionName: "f", data });
1430
+ } catch {
1431
+ return null;
1432
+ }
1433
+ }
1434
+ function decodeUint256ArrayResult(data) {
1435
+ if (!data) return null;
1436
+ try {
1437
+ return decodeFunctionResult4({ abi: _uint256ArrayAbi, functionName: "f", data });
1438
+ } catch {
1439
+ return null;
1440
+ }
1441
+ }
1442
+ function extractRewarderAddress(hooksParams) {
1443
+ if (!hooksParams || hooksParams === "0x0000000000000000000000000000000000000000000000000000000000000000") {
1444
+ return null;
1445
+ }
1446
+ const hex = hooksParams.slice(2);
1447
+ if (hex.length < 64) return null;
1448
+ const addrHex = hex.slice(24, 64);
1449
+ if (addrHex === "0000000000000000000000000000000000000000") return null;
1450
+ return `0x${addrHex}`;
1451
+ }
1452
+ function buildUniformDistribution(deltaIds) {
1453
+ const PRECISION = 10n ** 18n;
1454
+ const n = deltaIds.length;
1455
+ const xBins = deltaIds.filter((d) => d >= 0).length;
1456
+ const yBins = deltaIds.filter((d) => d <= 0).length;
1457
+ const distributionX = [];
1458
+ const distributionY = [];
1459
+ for (const delta of deltaIds) {
1460
+ const xShare = delta >= 0 && xBins > 0 ? PRECISION / BigInt(xBins) : 0n;
1461
+ const yShare = delta <= 0 && yBins > 0 ? PRECISION / BigInt(yBins) : 0n;
1462
+ distributionX.push(xShare);
1463
+ distributionY.push(yShare);
1464
+ }
1465
+ const xSum = distributionX.reduce((a, b) => a + b, 0n);
1466
+ const ySum = distributionY.reduce((a, b) => a + b, 0n);
1467
+ if (xSum > 0n && xSum !== PRECISION) {
1468
+ const firstX = distributionX.findIndex((v) => v > 0n);
1469
+ if (firstX !== -1) distributionX[firstX] += PRECISION - xSum;
1470
+ }
1471
+ if (ySum > 0n && ySum !== PRECISION) {
1472
+ const firstY = distributionY.findIndex((v) => v > 0n);
1473
+ if (firstY !== -1) distributionY[firstY] += PRECISION - ySum;
1474
+ }
1475
+ return { distributionX, distributionY };
1476
+ }
1477
+ function decodeAddress3(data) {
1478
+ if (!data) return null;
1479
+ try {
1480
+ return decodeFunctionResult5({ abi: _addressDecodeAbi3, functionName: "f", data });
1481
+ } catch {
1482
+ return null;
1483
+ }
1484
+ }
1485
+ function incentiveId(key) {
1486
+ return keccak256(
1487
+ encodeAbiParameters(
1488
+ [
1489
+ { name: "rewardToken", type: "address" },
1490
+ { name: "bonusRewardToken", type: "address" },
1491
+ { name: "pool", type: "address" },
1492
+ { name: "nonce", type: "uint256" }
1493
+ ],
1494
+ [key.rewardToken, key.bonusRewardToken, key.pool, key.nonce]
1495
+ )
1496
+ );
1497
+ }
1498
+ function encodeEnterFarming(key, tokenId) {
1499
+ return encodeFunctionData13({
1500
+ abi: farmingCenterAbi,
1501
+ functionName: "enterFarming",
1502
+ args: [key, tokenId]
1503
+ });
1504
+ }
1505
+ function encodeExitFarming(key, tokenId) {
1506
+ return encodeFunctionData13({
1507
+ abi: farmingCenterAbi,
1508
+ functionName: "exitFarming",
1509
+ args: [key, tokenId]
1510
+ });
1511
+ }
1512
+ function encodeCollectRewards(key, tokenId) {
1513
+ return encodeFunctionData13({
1514
+ abi: farmingCenterAbi,
1515
+ functionName: "collectRewards",
1516
+ args: [key, tokenId]
1517
+ });
1518
+ }
1519
+ function encodeClaimReward(rewardToken, to) {
1520
+ return encodeFunctionData13({
1521
+ abi: farmingCenterAbi,
1522
+ functionName: "claimReward",
1523
+ args: [rewardToken, to, 2n ** 128n - 1n]
1524
+ // max uint128
1525
+ });
1526
+ }
1527
+ function encodeMulticall(calls) {
1528
+ return encodeFunctionData13({
1529
+ abi: farmingCenterAbi,
1530
+ functionName: "multicall",
1531
+ args: [calls]
1532
+ });
1533
+ }
1286
1534
  function u256ToF64(v) {
1287
1535
  const MAX_U128 = (1n << 128n) - 1n;
1288
1536
  if (v > MAX_U128) return Infinity;
1289
1537
  return Number(v);
1290
1538
  }
1539
+ function decodeAddress4(data) {
1540
+ if (!data || data.length < 66) return null;
1541
+ return `0x${data.slice(26, 66)}`;
1542
+ }
1543
+ function decodeAddressArray(data) {
1544
+ if (!data) return [];
1545
+ try {
1546
+ return decodeFunctionResult6({
1547
+ abi: REWARDS_CONTROLLER_ABI,
1548
+ functionName: "getRewardsByAsset",
1549
+ data
1550
+ });
1551
+ } catch {
1552
+ return [];
1553
+ }
1554
+ }
1555
+ function decodeReserveData(data) {
1556
+ if (!data) return null;
1557
+ try {
1558
+ return decodeFunctionResult6({
1559
+ abi: POOL_ABI,
1560
+ functionName: "getReserveData",
1561
+ data
1562
+ });
1563
+ } catch {
1564
+ return null;
1565
+ }
1566
+ }
1567
+ function decodeRewardsData(data) {
1568
+ if (!data) return null;
1569
+ try {
1570
+ return decodeFunctionResult6({
1571
+ abi: REWARDS_CONTROLLER_ABI,
1572
+ functionName: "getRewardsData",
1573
+ data
1574
+ });
1575
+ } catch {
1576
+ return null;
1577
+ }
1578
+ }
1291
1579
  function u256ToF642(v) {
1292
1580
  const MAX_U128 = (1n << 128n) - 1n;
1293
1581
  if (v > MAX_U128) return Infinity;
1294
1582
  return Number(v);
1295
1583
  }
1296
- function defaultMarketParams(loanToken = zeroAddress7) {
1584
+ function defaultMarketParams(loanToken = zeroAddress10) {
1297
1585
  return {
1298
1586
  loanToken,
1299
- collateralToken: zeroAddress7,
1300
- oracle: zeroAddress7,
1301
- irm: zeroAddress7,
1587
+ collateralToken: zeroAddress10,
1588
+ oracle: zeroAddress10,
1589
+ irm: zeroAddress10,
1302
1590
  lltv: 0n
1303
1591
  };
1304
1592
  }
1593
+ function decodeMarket(data) {
1594
+ if (!data) return null;
1595
+ try {
1596
+ return decodeFunctionResult7({
1597
+ abi: MORPHO_ABI,
1598
+ functionName: "market",
1599
+ data
1600
+ });
1601
+ } catch {
1602
+ return null;
1603
+ }
1604
+ }
1605
+ function decodeMarketParams(data) {
1606
+ if (!data) return null;
1607
+ try {
1608
+ return decodeFunctionResult7({
1609
+ abi: MORPHO_ABI,
1610
+ functionName: "idToMarketParams",
1611
+ data
1612
+ });
1613
+ } catch {
1614
+ return null;
1615
+ }
1616
+ }
1305
1617
  function createDex(entry, rpcUrl) {
1306
1618
  switch (entry.interface) {
1307
1619
  case "uniswap_v3":
@@ -1317,6 +1629,8 @@ function createDex(entry, rpcUrl) {
1317
1629
  case "solidly_v2":
1318
1630
  case "solidly_cl":
1319
1631
  return new SolidlyAdapter(entry, rpcUrl);
1632
+ case "hybra":
1633
+ return new ThenaCLAdapter(entry, rpcUrl);
1320
1634
  case "curve_stableswap":
1321
1635
  return new CurveStableSwapAdapter(entry);
1322
1636
  case "balancer_v3":
@@ -1377,11 +1691,13 @@ function createLiquidStaking(entry, rpcUrl) {
1377
1691
  }
1378
1692
  }
1379
1693
  function createGauge(entry, rpcUrl) {
1694
+ if (entry.interface === "hybra" || entry.contracts?.["gauge_manager"]) {
1695
+ return new HybraGaugeAdapter(entry, rpcUrl);
1696
+ }
1380
1697
  switch (entry.interface) {
1381
1698
  case "solidly_v2":
1382
1699
  case "solidly_cl":
1383
1700
  case "algebra_v3":
1384
- case "hybra":
1385
1701
  return new SolidlyGaugeAdapter(entry, rpcUrl);
1386
1702
  default:
1387
1703
  throw DefiError.unsupported(`Gauge interface '${entry.interface}' not supported`);
@@ -1441,7 +1757,26 @@ function createOracleFromCdp(entry, _asset, rpcUrl) {
1441
1757
  throw DefiError.unsupported(`Oracle not available for CDP interface '${entry.interface}'`);
1442
1758
  }
1443
1759
  }
1444
- var DEFAULT_FEE, swapRouterAbi, quoterAbi, ramsesQuoterAbi, positionManagerAbi, UniswapV3Adapter, abi, lbQuoterAbi, UniswapV2Adapter, abi2, algebraQuoterAbi, algebraSingleQuoterAbi, algebraPositionManagerAbi, AlgebraV3Adapter, abi3, BalancerV3Adapter, poolAbi, CurveStableSwapAdapter, abi4, abiV2, SolidlyAdapter, abi5, WooFiAdapter, gaugeAbi, veAbi, voterAbi, SolidlyGaugeAdapter, masterchefAbi, MasterChefAdapter, POOL_ABI, ERC20_ABI, INCENTIVES_ABI, REWARDS_CONTROLLER_ABI, POOL_PROVIDER_ABI, ADDRESSES_PROVIDER_ABI, ORACLE_ABI, ERC20_DECIMALS_ABI, AaveV3Adapter, POOL_ABI2, ERC20_ABI2, AaveV2Adapter, ORACLE_ABI2, AaveOracleAdapter, CTOKEN_ABI, BSC_BLOCKS_PER_YEAR, CompoundV2Adapter, COMET_ABI, SECONDS_PER_YEAR, CompoundV3Adapter, EULER_VAULT_ABI, SECONDS_PER_YEAR2, EulerV2Adapter, MORPHO_ABI, META_MORPHO_ABI, IRM_ABI, SECONDS_PER_YEAR3, MorphoBlueAdapter, BORROWER_OPS_ABI, TROVE_MANAGER_ABI, HINT_HELPERS_ABI, SORTED_TROVES_ABI, FelixCdpAdapter, PRICE_FEED_ABI, FelixOracleAdapter, ERC4626_ABI, ERC4626VaultAdapter, GENERIC_LST_ABI, GenericLstAdapter, STHYPE_ABI, ERC20_ABI3, StHypeAdapter, KINETIQ_ABI, ORACLE_ABI3, WHYPE, HYPERLEND_ORACLE, KinetiqAdapter, PendleAdapter, GenericYieldAdapter, HLP_ABI, HlpVaultAdapter, GenericDerivativesAdapter, RYSK_ABI, RyskAdapter, GenericOptionsAdapter, ERC721_ABI, ERC721Adapter, DexSpotPrice;
1760
+ function createMerchantMoeLB(entry, rpcUrl) {
1761
+ return new MerchantMoeLBAdapter(entry, rpcUrl);
1762
+ }
1763
+ function createKittenSwapFarming(entry, rpcUrl) {
1764
+ const farmingCenter = entry.contracts?.["farming_center"];
1765
+ if (!farmingCenter) {
1766
+ throw new DefiError("CONTRACT_ERROR", `[${entry.name}] Missing 'farming_center' contract address`);
1767
+ }
1768
+ const eternalFarming = entry.contracts?.["eternal_farming"];
1769
+ if (!eternalFarming) {
1770
+ throw new DefiError("CONTRACT_ERROR", `[${entry.name}] Missing 'eternal_farming' contract address`);
1771
+ }
1772
+ const positionManager = entry.contracts?.["position_manager"];
1773
+ if (!positionManager) {
1774
+ throw new DefiError("CONTRACT_ERROR", `[${entry.name}] Missing 'position_manager' contract address`);
1775
+ }
1776
+ const factory = entry.contracts?.["factory"];
1777
+ return new KittenSwapFarmingAdapter(entry.name, farmingCenter, eternalFarming, positionManager, rpcUrl, factory);
1778
+ }
1779
+ var DEFAULT_FEE, swapRouterAbi, quoterAbi, ramsesQuoterAbi, positionManagerAbi, UniswapV3Adapter, abi, lbQuoterAbi, UniswapV2Adapter, abi2, algebraQuoterAbi, algebraSingleQuoterAbi, algebraIntegralPmAbi, algebraV2PmAbi, AlgebraV3Adapter, abi3, BalancerV3Adapter, poolAbi, CurveStableSwapAdapter, abi4, abiV2, SolidlyAdapter, thenaPmAbi, thenaRouterAbi, thenaPoolAbi, thenaFactoryAbi, ThenaCLAdapter, _addressDecodeAbi, _symbolDecodeAbi, gaugeManagerAbi, gaugeCLAbi, nfpmAbi, veAbi, voterAbi, HybraGaugeAdapter, abi5, WooFiAdapter, gaugeAbi, veAbi2, voterAbi2, _addressDecodeAbi2, _symbolDecodeAbi2, _boolDecodeAbi, HYPEREVM_TOKENS, CL_TICK_SPACINGS, SolidlyGaugeAdapter, masterchefAbi, MasterChefAdapter, lbRouterAbi, lbFactoryAbi, lbPairAbi, lbRewarderAbi, masterChefAbi, veMoeAbi, lbPairBinAbi, lbQuoterAbi2, erc20Abi2, _addressAbi, _uint256Abi, _boolAbi, _rangeAbi, _binAbi, _uint256ArrayAbi, MerchantMoeLBAdapter, KITTEN_TOKEN, WHYPE_TOKEN, MAX_NONCE_SCAN, HYPEREVM_TOKENS2, farmingCenterAbi, positionManagerAbi2, eternalFarmingAbi, algebraFactoryAbi, _addressDecodeAbi3, nonceCache, KittenSwapFarmingAdapter, POOL_ABI, ERC20_ABI, INCENTIVES_ABI, REWARDS_CONTROLLER_ABI, POOL_PROVIDER_ABI, ADDRESSES_PROVIDER_ABI, ORACLE_ABI, ERC20_DECIMALS_ABI, AaveV3Adapter, POOL_ABI2, ERC20_ABI2, AaveV2Adapter, ORACLE_ABI2, AaveOracleAdapter, CTOKEN_ABI, BSC_BLOCKS_PER_YEAR, CompoundV2Adapter, COMET_ABI, SECONDS_PER_YEAR, CompoundV3Adapter, EULER_VAULT_ABI, SECONDS_PER_YEAR2, EulerV2Adapter, MORPHO_ABI, META_MORPHO_ABI, IRM_ABI, SECONDS_PER_YEAR3, MorphoBlueAdapter, BORROWER_OPS_ABI, TROVE_MANAGER_ABI, HINT_HELPERS_ABI, SORTED_TROVES_ABI, FelixCdpAdapter, PRICE_FEED_ABI, FelixOracleAdapter, ERC4626_ABI, ERC4626VaultAdapter, GENERIC_LST_ABI, GenericLstAdapter, STHYPE_ABI, ERC20_ABI3, StHypeAdapter, KINETIQ_ABI, ORACLE_ABI3, WHYPE, HYPERLEND_ORACLE, KinetiqAdapter, PendleAdapter, GenericYieldAdapter, HLP_ABI, HlpVaultAdapter, GenericDerivativesAdapter, RYSK_ABI, RyskAdapter, GenericOptionsAdapter, ERC721_ABI, ERC721Adapter, DexSpotPrice;
1445
1780
  var init_dist3 = __esm({
1446
1781
  "../defi-protocols/dist/index.js"() {
1447
1782
  "use strict";
@@ -1475,6 +1810,10 @@ var init_dist3 = __esm({
1475
1810
  init_dist2();
1476
1811
  init_dist2();
1477
1812
  init_dist2();
1813
+ init_dist2();
1814
+ init_dist2();
1815
+ init_dist2();
1816
+ init_dist2();
1478
1817
  DEFAULT_FEE = 3e3;
1479
1818
  swapRouterAbi = parseAbi3([
1480
1819
  "struct ExactInputSingleParams { address tokenIn; address tokenOut; uint24 fee; address recipient; uint256 deadline; uint256 amountIn; uint256 amountOutMinimum; uint160 sqrtPriceLimitX96; }",
@@ -1936,7 +2275,11 @@ var init_dist3 = __esm({
1936
2275
  algebraSingleQuoterAbi = parseAbi32([
1937
2276
  "function quoteExactInputSingle((address tokenIn, address tokenOut, uint256 amountIn, uint160 limitSqrtPrice) params) external returns (uint256 amountOut, uint256 amountIn, uint160 sqrtPriceX96After)"
1938
2277
  ]);
1939
- algebraPositionManagerAbi = parseAbi32([
2278
+ algebraIntegralPmAbi = parseAbi32([
2279
+ "struct MintParams { address token0; address token1; address deployer; int24 tickLower; int24 tickUpper; uint256 amount0Desired; uint256 amount1Desired; uint256 amount0Min; uint256 amount1Min; address recipient; uint256 deadline; }",
2280
+ "function mint(MintParams calldata params) external payable returns (uint256 tokenId, uint128 liquidity, uint256 amount0, uint256 amount1)"
2281
+ ]);
2282
+ algebraV2PmAbi = parseAbi32([
1940
2283
  "struct MintParams { address token0; address token1; int24 tickLower; int24 tickUpper; uint256 amount0Desired; uint256 amount1Desired; uint256 amount0Min; uint256 amount1Min; address recipient; uint256 deadline; }",
1941
2284
  "function mint(MintParams calldata params) external payable returns (uint256 tokenId, uint128 liquidity, uint256 amount0, uint256 amount1)"
1942
2285
  ]);
@@ -2081,36 +2424,58 @@ var init_dist3 = __esm({
2081
2424
  throw new DefiError("CONTRACT_ERROR", "Position manager address not configured");
2082
2425
  }
2083
2426
  const [token0, token1, rawAmount0, rawAmount1] = params.token_a.toLowerCase() < params.token_b.toLowerCase() ? [params.token_a, params.token_b, params.amount_a, params.amount_b] : [params.token_b, params.token_a, params.amount_b, params.amount_a];
2084
- const amount0 = rawAmount0 === 0n && rawAmount1 > 0n ? 1n : rawAmount0;
2085
- const amount1 = rawAmount1 === 0n && rawAmount0 > 0n ? 1n : rawAmount1;
2086
- const data = encodeFunctionData32({
2087
- abi: algebraPositionManagerAbi,
2427
+ let tickLower = params.tick_lower ?? -887220;
2428
+ let tickUpper = params.tick_upper ?? 887220;
2429
+ const isSingleSide = rawAmount0 === 0n || rawAmount1 === 0n;
2430
+ const needsAutoTick = params.range_pct !== void 0 || isSingleSide && !params.tick_lower && !params.tick_upper;
2431
+ if (needsAutoTick) {
2432
+ if (!this.rpcUrl) throw DefiError.rpcError("RPC URL required for auto tick detection");
2433
+ const poolAddr = params.pool;
2434
+ if (!poolAddr) throw new DefiError("CONTRACT_ERROR", "Pool address required (use --pool)");
2435
+ const client = createPublicClient3({ transport: http3(this.rpcUrl) });
2436
+ const algebraPoolAbi = parseAbi32([
2437
+ "function globalState() view returns (uint160 price, int24 tick, uint16 lastFee, uint8 pluginConfig, uint16 communityFee, bool unlocked)",
2438
+ "function tickSpacing() view returns (int24)"
2439
+ ]);
2440
+ const [globalState, spacing] = await Promise.all([
2441
+ client.readContract({ address: poolAddr, abi: algebraPoolAbi, functionName: "globalState" }),
2442
+ client.readContract({ address: poolAddr, abi: algebraPoolAbi, functionName: "tickSpacing" })
2443
+ ]);
2444
+ const currentTick = Number(globalState[1]);
2445
+ const tickSpace = Number(spacing);
2446
+ if (params.range_pct !== void 0) {
2447
+ const range = rangeToTicks(currentTick, params.range_pct, tickSpace);
2448
+ tickLower = range.tickLower;
2449
+ tickUpper = range.tickUpper;
2450
+ } else if (rawAmount0 > 0n && rawAmount1 === 0n) {
2451
+ tickLower = alignTickUp(currentTick + tickSpace, tickSpace);
2452
+ tickUpper = 887220;
2453
+ } else {
2454
+ tickLower = -887220;
2455
+ tickUpper = alignTickDown(currentTick - tickSpace, tickSpace);
2456
+ }
2457
+ }
2458
+ const amount0 = rawAmount0;
2459
+ const amount1 = rawAmount1;
2460
+ const data = this.useSingleQuoter ? encodeFunctionData32({
2461
+ abi: algebraV2PmAbi,
2088
2462
  functionName: "mint",
2089
- args: [
2090
- {
2091
- token0,
2092
- token1,
2093
- tickLower: -887220,
2094
- tickUpper: 887220,
2095
- amount0Desired: amount0,
2096
- amount1Desired: amount1,
2097
- amount0Min: 0n,
2098
- amount1Min: 0n,
2099
- recipient: params.recipient,
2100
- deadline: BigInt("18446744073709551615")
2101
- }
2102
- ]
2463
+ args: [{ token0, token1, tickLower, tickUpper, amount0Desired: amount0, amount1Desired: amount1, amount0Min: 0n, amount1Min: 0n, recipient: params.recipient, deadline: BigInt("18446744073709551615") }]
2464
+ }) : encodeFunctionData32({
2465
+ abi: algebraIntegralPmAbi,
2466
+ functionName: "mint",
2467
+ args: [{ token0, token1, deployer: zeroAddress, tickLower, tickUpper, amount0Desired: amount0, amount1Desired: amount1, amount0Min: 0n, amount1Min: 0n, recipient: params.recipient, deadline: BigInt("18446744073709551615") }]
2103
2468
  });
2469
+ const approvals = [];
2470
+ if (amount0 > 0n) approvals.push({ token: token0, spender: pm, amount: amount0 });
2471
+ if (amount1 > 0n) approvals.push({ token: token1, spender: pm, amount: amount1 });
2104
2472
  return {
2105
- description: `[${this.protocolName}] Add liquidity`,
2473
+ description: `[${this.protocolName}] Add liquidity [${tickLower}, ${tickUpper}]`,
2106
2474
  to: pm,
2107
2475
  data,
2108
2476
  value: 0n,
2109
2477
  gas_estimate: 5e5,
2110
- approvals: [
2111
- { token: token0, spender: pm, amount: amount0 },
2112
- { token: token1, spender: pm, amount: amount1 }
2113
- ]
2478
+ approvals
2114
2479
  };
2115
2480
  }
2116
2481
  async buildRemoveLiquidity(_params) {
@@ -2291,15 +2656,6 @@ var init_dist3 = __esm({
2291
2656
  approvals: [{ token: params.token_in, spender: this.router, amount: params.amount_in }]
2292
2657
  };
2293
2658
  }
2294
- async callGetAmountsOut(client, callData) {
2295
- const result = await client.call({ to: this.router, data: callData });
2296
- if (!result.data) return 0n;
2297
- const [amounts] = decodeAbiParameters4(
2298
- [{ name: "amounts", type: "uint256[]" }],
2299
- result.data
2300
- );
2301
- return amounts.length >= 2 ? amounts[amounts.length - 1] : 0n;
2302
- }
2303
2659
  encodeV1(params, stable) {
2304
2660
  return encodeFunctionData6({
2305
2661
  abi: abi4,
@@ -2316,7 +2672,6 @@ var init_dist3 = __esm({
2316
2672
  }
2317
2673
  async quote(params) {
2318
2674
  if (!this.rpcUrl) throw DefiError.rpcError("No RPC URL configured");
2319
- const client = createPublicClient4({ transport: http4(this.rpcUrl) });
2320
2675
  const candidates = [
2321
2676
  { callData: this.encodeV1(params, false), stable: false },
2322
2677
  { callData: this.encodeV1(params, true), stable: true }
@@ -2327,16 +2682,26 @@ var init_dist3 = __esm({
2327
2682
  { callData: this.encodeV2(params, true), stable: true }
2328
2683
  );
2329
2684
  }
2330
- const results = await Promise.allSettled(
2331
- candidates.map((c) => this.callGetAmountsOut(client, c.callData))
2685
+ const rawResults = await multicallRead(
2686
+ this.rpcUrl,
2687
+ candidates.map((c) => [this.router, c.callData])
2332
2688
  );
2333
2689
  let bestOut = 0n;
2334
2690
  let bestStable = false;
2335
- for (let i = 0; i < results.length; i++) {
2336
- const r = results[i];
2337
- if (r.status === "fulfilled" && r.value > bestOut) {
2338
- bestOut = r.value;
2339
- bestStable = candidates[i].stable;
2691
+ for (let i = 0; i < rawResults.length; i++) {
2692
+ const raw = rawResults[i];
2693
+ if (!raw) continue;
2694
+ try {
2695
+ const [amounts] = decodeAbiParameters4(
2696
+ [{ name: "amounts", type: "uint256[]" }],
2697
+ raw
2698
+ );
2699
+ const out = amounts.length >= 2 ? amounts[amounts.length - 1] : 0n;
2700
+ if (out > bestOut) {
2701
+ bestOut = out;
2702
+ bestStable = candidates[i].stable;
2703
+ }
2704
+ } catch {
2340
2705
  }
2341
2706
  }
2342
2707
  if (bestOut === 0n) {
@@ -2402,347 +2767,1185 @@ var init_dist3 = __esm({
2402
2767
  };
2403
2768
  }
2404
2769
  };
2405
- abi5 = parseAbi7([
2406
- "function swap(address fromToken, address toToken, uint256 fromAmount, uint256 minToAmount, address to, address rebateTo) external payable returns (uint256 realToAmount)"
2770
+ thenaPmAbi = parseAbi7([
2771
+ "struct MintParams { address token0; address token1; int24 tickSpacing; int24 tickLower; int24 tickUpper; uint256 amount0Desired; uint256 amount1Desired; uint256 amount0Min; uint256 amount1Min; address recipient; uint256 deadline; uint160 sqrtPriceX96; }",
2772
+ "function mint(MintParams calldata params) external payable returns (uint256 tokenId, uint128 liquidity, uint256 amount0, uint256 amount1)"
2407
2773
  ]);
2408
- WooFiAdapter = class {
2774
+ thenaRouterAbi = parseAbi7([
2775
+ "struct ExactInputSingleParams { address tokenIn; address tokenOut; int24 tickSpacing; address recipient; uint256 deadline; uint256 amountIn; uint256 amountOutMinimum; uint160 sqrtPriceLimitX96; }",
2776
+ "function exactInputSingle(ExactInputSingleParams calldata params) external payable returns (uint256 amountOut)"
2777
+ ]);
2778
+ thenaPoolAbi = parseAbi7([
2779
+ "function slot0() view returns (uint160 sqrtPriceX96, int24 tick, uint16 observationIndex, uint16 observationCardinality, uint16 observationCardinalityNext, bool unlocked)",
2780
+ "function tickSpacing() view returns (int24)",
2781
+ "function token0() view returns (address)",
2782
+ "function token1() view returns (address)"
2783
+ ]);
2784
+ thenaFactoryAbi = parseAbi7([
2785
+ "function getPool(address tokenA, address tokenB, int24 tickSpacing) view returns (address)"
2786
+ ]);
2787
+ ThenaCLAdapter = class {
2409
2788
  protocolName;
2410
2789
  router;
2411
- constructor(entry, _rpcUrl) {
2790
+ positionManager;
2791
+ factory;
2792
+ rpcUrl;
2793
+ defaultTickSpacing;
2794
+ constructor(entry, rpcUrl) {
2412
2795
  this.protocolName = entry.name;
2413
2796
  const router = entry.contracts?.["router"];
2414
- if (!router) {
2415
- throw new DefiError("CONTRACT_ERROR", "Missing 'router' contract");
2416
- }
2797
+ if (!router) throw new DefiError("CONTRACT_ERROR", "Missing 'router' contract address");
2417
2798
  this.router = router;
2799
+ this.positionManager = entry.contracts?.["position_manager"];
2800
+ this.factory = entry.contracts?.["pool_factory"];
2801
+ this.rpcUrl = rpcUrl;
2802
+ this.defaultTickSpacing = 50;
2418
2803
  }
2419
2804
  name() {
2420
2805
  return this.protocolName;
2421
2806
  }
2422
2807
  async buildSwap(params) {
2423
- const minToAmount = 0n;
2424
2808
  const data = encodeFunctionData7({
2425
- abi: abi5,
2426
- functionName: "swap",
2427
- args: [
2428
- params.token_in,
2429
- params.token_out,
2430
- params.amount_in,
2431
- minToAmount,
2432
- params.recipient,
2433
- zeroAddress3
2434
- ]
2809
+ abi: thenaRouterAbi,
2810
+ functionName: "exactInputSingle",
2811
+ args: [{
2812
+ tokenIn: params.token_in,
2813
+ tokenOut: params.token_out,
2814
+ tickSpacing: this.defaultTickSpacing,
2815
+ recipient: params.recipient,
2816
+ deadline: BigInt(params.deadline ?? 18446744073709551615n),
2817
+ amountIn: params.amount_in,
2818
+ amountOutMinimum: 0n,
2819
+ sqrtPriceLimitX96: 0n
2820
+ }]
2435
2821
  });
2436
2822
  return {
2437
- description: `[${this.protocolName}] Swap ${params.amount_in} via WOOFi`,
2823
+ description: `[${this.protocolName}] Swap`,
2438
2824
  to: this.router,
2439
2825
  data,
2440
2826
  value: 0n,
2441
- gas_estimate: 2e5
2827
+ gas_estimate: 3e5,
2828
+ approvals: [{ token: params.token_in, spender: this.router, amount: params.amount_in }]
2442
2829
  };
2443
2830
  }
2444
2831
  async quote(_params) {
2445
- throw DefiError.unsupported(`[${this.protocolName}] quote requires RPC`);
2832
+ throw DefiError.unsupported(`[${this.protocolName}] quote not yet implemented \u2014 use swap router`);
2446
2833
  }
2447
- async buildAddLiquidity(_params) {
2448
- throw DefiError.unsupported(`[${this.protocolName}] WOOFi does not support LP positions via router`);
2834
+ async buildAddLiquidity(params) {
2835
+ const pm = this.positionManager;
2836
+ if (!pm) throw new DefiError("CONTRACT_ERROR", "Position manager not configured");
2837
+ if (!this.rpcUrl) throw DefiError.rpcError("RPC URL required");
2838
+ const [token0, token1, rawAmount0, rawAmount1] = params.token_a.toLowerCase() < params.token_b.toLowerCase() ? [params.token_a, params.token_b, params.amount_a, params.amount_b] : [params.token_b, params.token_a, params.amount_b, params.amount_a];
2839
+ const client = createPublicClient4({ transport: http4(this.rpcUrl) });
2840
+ const poolAddr = params.pool;
2841
+ let tickSpacing = this.defaultTickSpacing;
2842
+ let tickLower = params.tick_lower ?? 0;
2843
+ let tickUpper = params.tick_upper ?? 0;
2844
+ if (poolAddr || !params.tick_lower || !params.tick_upper) {
2845
+ let pool = poolAddr;
2846
+ if (!pool && this.factory) {
2847
+ pool = await client.readContract({
2848
+ address: this.factory,
2849
+ abi: thenaFactoryAbi,
2850
+ functionName: "getPool",
2851
+ args: [token0, token1, tickSpacing]
2852
+ });
2853
+ if (pool === zeroAddress3) throw new DefiError("CONTRACT_ERROR", "Pool not found");
2854
+ }
2855
+ if (pool) {
2856
+ const [slot0, ts] = await Promise.all([
2857
+ client.readContract({ address: pool, abi: thenaPoolAbi, functionName: "slot0" }),
2858
+ client.readContract({ address: pool, abi: thenaPoolAbi, functionName: "tickSpacing" })
2859
+ ]);
2860
+ const currentTick = Number(slot0[1]);
2861
+ tickSpacing = Number(ts);
2862
+ if (params.range_pct !== void 0) {
2863
+ const range = rangeToTicks(currentTick, params.range_pct, tickSpacing);
2864
+ tickLower = range.tickLower;
2865
+ tickUpper = range.tickUpper;
2866
+ } else if (!params.tick_lower && !params.tick_upper) {
2867
+ const isSingleSide = rawAmount0 === 0n || rawAmount1 === 0n;
2868
+ if (isSingleSide) {
2869
+ if (rawAmount0 > 0n) {
2870
+ tickLower = alignTickUp(currentTick + tickSpacing, tickSpacing);
2871
+ tickUpper = Math.floor(887272 / tickSpacing) * tickSpacing;
2872
+ } else {
2873
+ tickLower = Math.ceil(-887272 / tickSpacing) * tickSpacing;
2874
+ tickUpper = alignTickDown(currentTick - tickSpacing, tickSpacing);
2875
+ }
2876
+ } else {
2877
+ tickLower = Math.ceil(-887272 / tickSpacing) * tickSpacing;
2878
+ tickUpper = Math.floor(887272 / tickSpacing) * tickSpacing;
2879
+ }
2880
+ }
2881
+ }
2882
+ }
2883
+ if (params.tick_lower !== void 0) tickLower = params.tick_lower;
2884
+ if (params.tick_upper !== void 0) tickUpper = params.tick_upper;
2885
+ const data = encodeFunctionData7({
2886
+ abi: thenaPmAbi,
2887
+ functionName: "mint",
2888
+ args: [{
2889
+ token0,
2890
+ token1,
2891
+ tickSpacing,
2892
+ tickLower,
2893
+ tickUpper,
2894
+ amount0Desired: rawAmount0,
2895
+ amount1Desired: rawAmount1,
2896
+ amount0Min: 0n,
2897
+ amount1Min: 0n,
2898
+ recipient: params.recipient,
2899
+ deadline: BigInt("18446744073709551615"),
2900
+ sqrtPriceX96: 0n
2901
+ }]
2902
+ });
2903
+ const approvals = [];
2904
+ if (rawAmount0 > 0n) approvals.push({ token: token0, spender: pm, amount: rawAmount0 });
2905
+ if (rawAmount1 > 0n) approvals.push({ token: token1, spender: pm, amount: rawAmount1 });
2906
+ return {
2907
+ description: `[${this.protocolName}] Add liquidity [${tickLower}, ${tickUpper}]`,
2908
+ to: pm,
2909
+ data,
2910
+ value: 0n,
2911
+ gas_estimate: 7e5,
2912
+ approvals
2913
+ };
2449
2914
  }
2450
2915
  async buildRemoveLiquidity(_params) {
2451
- throw DefiError.unsupported(`[${this.protocolName}] WOOFi does not support LP positions via router`);
2916
+ throw DefiError.unsupported(`[${this.protocolName}] remove_liquidity requires tokenId`);
2452
2917
  }
2453
2918
  };
2454
- gaugeAbi = parseAbi8([
2455
- "function deposit(uint256 amount) external",
2456
- "function depositFor(uint256 amount, uint256 tokenId) external",
2457
- "function withdraw(uint256 amount) external",
2458
- "function getReward(address account) external",
2459
- "function getReward(address account, address[] tokens) external",
2460
- "function earned(address account) external view returns (uint256)",
2461
- "function earned(address token, address account) external view returns (uint256)",
2462
- "function rewardRate() external view returns (uint256)",
2463
- "function totalSupply() external view returns (uint256)",
2464
- "function rewardsListLength() external view returns (uint256)",
2465
- "function isReward(address token) external view returns (bool)"
2919
+ _addressDecodeAbi = parseAbi8(["function f() external view returns (address)"]);
2920
+ _symbolDecodeAbi = parseAbi8(["function symbol() external view returns (string)"]);
2921
+ gaugeManagerAbi = parseAbi8([
2922
+ "function gauges(address pool) view returns (address gauge)",
2923
+ "function isGauge(address gauge) view returns (bool)",
2924
+ "function isAlive(address gauge) view returns (bool)",
2925
+ "function claimRewards(address gauge, uint256[] tokenIds, uint8 redeemType) external"
2926
+ ]);
2927
+ gaugeCLAbi = parseAbi8([
2928
+ "function deposit(uint256 tokenId) external",
2929
+ "function withdraw(uint256 tokenId, uint8 redeemType) external",
2930
+ "function earned(uint256 tokenId) view returns (uint256)",
2931
+ "function balanceOf(uint256 tokenId) view returns (uint256)",
2932
+ "function rewardToken() view returns (address)"
2933
+ ]);
2934
+ nfpmAbi = parseAbi8([
2935
+ "function approve(address to, uint256 tokenId) external",
2936
+ "function getApproved(uint256 tokenId) view returns (address)"
2466
2937
  ]);
2467
2938
  veAbi = parseAbi8([
2468
2939
  "function create_lock(uint256 value, uint256 lock_duration) external returns (uint256)",
2469
2940
  "function increase_amount(uint256 tokenId, uint256 value) external",
2470
2941
  "function increase_unlock_time(uint256 tokenId, uint256 lock_duration) external",
2471
- "function withdraw(uint256 tokenId) external",
2472
- "function balanceOfNFT(uint256 tokenId) external view returns (uint256)",
2473
- "function locked(uint256 tokenId) external view returns (uint256 amount, uint256 end)"
2942
+ "function withdraw(uint256 tokenId) external"
2474
2943
  ]);
2475
2944
  voterAbi = parseAbi8([
2476
- "function vote(uint256 tokenId, address[] calldata pools, uint256[] calldata weights) external",
2477
- "function claimBribes(address[] calldata bribes, address[][] calldata tokens, uint256 tokenId) external",
2478
- "function claimFees(address[] calldata fees, address[][] calldata tokens, uint256 tokenId) external",
2479
- "function gauges(address pool) external view returns (address)"
2945
+ "function vote(uint256 tokenId, address[] pools, uint256[] weights) external",
2946
+ "function claimBribes(address[] bribes, address[][] tokens, uint256 tokenId) external",
2947
+ "function claimFees(address[] fees, address[][] tokens, uint256 tokenId) external"
2480
2948
  ]);
2481
- SolidlyGaugeAdapter = class {
2949
+ HybraGaugeAdapter = class {
2482
2950
  protocolName;
2483
- voter;
2951
+ gaugeManager;
2484
2952
  veToken;
2953
+ voter;
2954
+ positionManager;
2955
+ poolFactory;
2485
2956
  rpcUrl;
2486
2957
  constructor(entry, rpcUrl) {
2487
2958
  this.protocolName = entry.name;
2488
- const voter = entry.contracts?.["voter"];
2489
- if (!voter) {
2490
- throw new DefiError("CONTRACT_ERROR", "Missing 'voter' contract");
2491
- }
2492
- const veToken = entry.contracts?.["ve_token"];
2493
- if (!veToken) {
2494
- throw new DefiError("CONTRACT_ERROR", "Missing 've_token' contract");
2495
- }
2496
- this.voter = voter;
2497
- this.veToken = veToken;
2959
+ const gm = entry.contracts?.["gauge_manager"];
2960
+ if (!gm) throw new DefiError("CONTRACT_ERROR", "Missing 'gauge_manager' contract");
2961
+ this.gaugeManager = gm;
2962
+ const ve = entry.contracts?.["ve_token"];
2963
+ if (!ve) throw new DefiError("CONTRACT_ERROR", "Missing 've_token' contract");
2964
+ this.veToken = ve;
2965
+ this.voter = entry.contracts?.["voter"] ?? zeroAddress4;
2966
+ this.positionManager = entry.contracts?.["position_manager"] ?? zeroAddress4;
2967
+ this.poolFactory = entry.contracts?.["pool_factory"];
2498
2968
  this.rpcUrl = rpcUrl;
2499
2969
  }
2500
2970
  name() {
2501
2971
  return this.protocolName;
2502
2972
  }
2503
- // IGauge
2504
- async buildDeposit(gauge, amount, tokenId, lpToken) {
2505
- if (tokenId !== void 0) {
2506
- const data2 = encodeFunctionData8({
2507
- abi: gaugeAbi,
2508
- functionName: "depositFor",
2509
- args: [amount, tokenId]
2973
+ // ─── Gauge Discovery ──────────────────────────────────────
2974
+ async discoverGaugedPools() {
2975
+ if (!this.rpcUrl) throw DefiError.rpcError("RPC URL required for gauge discovery");
2976
+ if (!this.poolFactory) throw new DefiError("CONTRACT_ERROR", "Missing 'pool_factory' contract");
2977
+ const factoryAbi = parseAbi8([
2978
+ "function allPoolsLength() external view returns (uint256)",
2979
+ "function allPools(uint256) external view returns (address)"
2980
+ ]);
2981
+ const poolAbi2 = parseAbi8([
2982
+ "function token0() external view returns (address)",
2983
+ "function token1() external view returns (address)"
2984
+ ]);
2985
+ const erc20SymbolAbi = parseAbi8(["function symbol() external view returns (string)"]);
2986
+ const gaugesAbi = parseAbi8(["function gauges(address pool) view returns (address gauge)"]);
2987
+ const client = createPublicClient5({ transport: http5(this.rpcUrl) });
2988
+ let poolCount;
2989
+ try {
2990
+ poolCount = await client.readContract({
2991
+ address: this.poolFactory,
2992
+ abi: factoryAbi,
2993
+ functionName: "allPoolsLength"
2510
2994
  });
2511
- return {
2512
- description: `[${this.protocolName}] Deposit ${amount} LP to gauge (boost veNFT #${tokenId})`,
2513
- to: gauge,
2514
- data: data2,
2515
- value: 0n,
2516
- gas_estimate: 2e5,
2517
- approvals: lpToken ? [{ token: lpToken, spender: gauge, amount }] : void 0
2518
- };
2995
+ } catch {
2996
+ return [];
2519
2997
  }
2520
- const data = encodeFunctionData8({
2521
- abi: gaugeAbi,
2522
- functionName: "deposit",
2523
- args: [amount]
2998
+ const count = Number(poolCount);
2999
+ if (count === 0) return [];
3000
+ const poolAddressCalls = [];
3001
+ for (let i = 0; i < count; i++) {
3002
+ poolAddressCalls.push([
3003
+ this.poolFactory,
3004
+ encodeFunctionData8({ abi: factoryAbi, functionName: "allPools", args: [BigInt(i)] })
3005
+ ]);
3006
+ }
3007
+ const poolAddressResults = await multicallRead(this.rpcUrl, poolAddressCalls);
3008
+ const pools = poolAddressResults.map((r) => decodeAddress(r)).filter((a) => a !== null && a !== zeroAddress4);
3009
+ if (pools.length === 0) return [];
3010
+ const gaugeCalls = pools.map((pool) => [
3011
+ this.gaugeManager,
3012
+ encodeFunctionData8({ abi: gaugesAbi, functionName: "gauges", args: [pool] })
3013
+ ]);
3014
+ const gaugeResults = await multicallRead(this.rpcUrl, gaugeCalls);
3015
+ const gaugedPools = [];
3016
+ for (let i = 0; i < pools.length; i++) {
3017
+ const gauge = decodeAddress(gaugeResults[i] ?? null);
3018
+ if (gauge && gauge !== zeroAddress4) {
3019
+ gaugedPools.push({ pool: pools[i], gauge });
3020
+ }
3021
+ }
3022
+ if (gaugedPools.length === 0) return [];
3023
+ const tokenCalls = [];
3024
+ for (const { pool } of gaugedPools) {
3025
+ tokenCalls.push([pool, encodeFunctionData8({ abi: poolAbi2, functionName: "token0" })]);
3026
+ tokenCalls.push([pool, encodeFunctionData8({ abi: poolAbi2, functionName: "token1" })]);
3027
+ }
3028
+ const tokenResults = await multicallRead(this.rpcUrl, tokenCalls);
3029
+ const tokenAddrs = /* @__PURE__ */ new Set();
3030
+ for (let i = 0; i < gaugedPools.length; i++) {
3031
+ const t0 = decodeAddress(tokenResults[i * 2] ?? null);
3032
+ const t1 = decodeAddress(tokenResults[i * 2 + 1] ?? null);
3033
+ if (t0 && t0 !== zeroAddress4) tokenAddrs.add(t0);
3034
+ if (t1 && t1 !== zeroAddress4) tokenAddrs.add(t1);
3035
+ }
3036
+ const uniqueTokens = Array.from(tokenAddrs);
3037
+ const symbolCalls = uniqueTokens.map((t) => [
3038
+ t,
3039
+ encodeFunctionData8({ abi: erc20SymbolAbi, functionName: "symbol" })
3040
+ ]);
3041
+ const symbolResults = await multicallRead(this.rpcUrl, symbolCalls);
3042
+ const symbolMap = /* @__PURE__ */ new Map();
3043
+ for (let i = 0; i < uniqueTokens.length; i++) {
3044
+ symbolMap.set(uniqueTokens[i], decodeSymbol(symbolResults[i] ?? null));
3045
+ }
3046
+ const out = [];
3047
+ for (let i = 0; i < gaugedPools.length; i++) {
3048
+ const { pool, gauge } = gaugedPools[i];
3049
+ const t0 = decodeAddress(tokenResults[i * 2] ?? null);
3050
+ const t1 = decodeAddress(tokenResults[i * 2 + 1] ?? null);
3051
+ out.push({
3052
+ pool,
3053
+ gauge,
3054
+ token0: t0 ? symbolMap.get(t0) ?? t0.slice(0, 10) : "?",
3055
+ token1: t1 ? symbolMap.get(t1) ?? t1.slice(0, 10) : "?",
3056
+ type: "CL"
3057
+ });
3058
+ }
3059
+ return out;
3060
+ }
3061
+ // ─── Gauge Lookup ──────────────────────────────────────────
3062
+ async resolveGauge(pool) {
3063
+ if (!this.rpcUrl) throw DefiError.rpcError("RPC required");
3064
+ const client = createPublicClient5({ transport: http5(this.rpcUrl) });
3065
+ const gauge = await client.readContract({
3066
+ address: this.gaugeManager,
3067
+ abi: gaugeManagerAbi,
3068
+ functionName: "gauges",
3069
+ args: [pool]
2524
3070
  });
2525
- return {
2526
- description: `[${this.protocolName}] Deposit ${amount} LP to gauge`,
3071
+ if (gauge === zeroAddress4) throw new DefiError("CONTRACT_ERROR", `No gauge for pool ${pool}`);
3072
+ return gauge;
3073
+ }
3074
+ // ─── CL Gauge: NFT Deposit/Withdraw ──────────────────────────
3075
+ async buildDeposit(gauge, _amount, tokenId) {
3076
+ if (tokenId === void 0) throw new DefiError("CONTRACT_ERROR", "tokenId required for CL gauge deposit");
3077
+ const approveTx = {
3078
+ description: `[${this.protocolName}] Approve NFT #${tokenId} to gauge`,
3079
+ to: this.positionManager,
3080
+ data: encodeFunctionData8({ abi: nfpmAbi, functionName: "approve", args: [gauge, tokenId] }),
3081
+ value: 0n,
3082
+ gas_estimate: 8e4
3083
+ };
3084
+ return {
3085
+ description: `[${this.protocolName}] Deposit NFT #${tokenId} to gauge`,
2527
3086
  to: gauge,
2528
- data,
3087
+ data: encodeFunctionData8({ abi: gaugeCLAbi, functionName: "deposit", args: [tokenId] }),
2529
3088
  value: 0n,
2530
- gas_estimate: 2e5,
2531
- approvals: lpToken ? [{ token: lpToken, spender: gauge, amount }] : void 0
3089
+ gas_estimate: 5e5,
3090
+ pre_txs: [approveTx]
2532
3091
  };
2533
3092
  }
2534
- async buildWithdraw(gauge, amount) {
2535
- const data = encodeFunctionData8({
2536
- abi: gaugeAbi,
2537
- functionName: "withdraw",
2538
- args: [amount]
2539
- });
3093
+ async buildWithdraw(gauge, _amount, tokenId) {
3094
+ if (tokenId === void 0) throw new DefiError("CONTRACT_ERROR", "tokenId required for CL gauge withdraw");
2540
3095
  return {
2541
- description: `[${this.protocolName}] Withdraw ${amount} LP from gauge`,
3096
+ description: `[${this.protocolName}] Withdraw NFT #${tokenId} from gauge`,
2542
3097
  to: gauge,
2543
- data,
3098
+ data: encodeFunctionData8({ abi: gaugeCLAbi, functionName: "withdraw", args: [tokenId, 1] }),
2544
3099
  value: 0n,
2545
- gas_estimate: 2e5
3100
+ gas_estimate: 1e6
2546
3101
  };
2547
3102
  }
2548
- async buildClaimRewards(gauge, account) {
2549
- if (account && this.rpcUrl) {
2550
- try {
2551
- const client = createPublicClient5({ transport: http5(this.rpcUrl) });
2552
- const listLen = await client.readContract({
2553
- address: gauge,
2554
- abi: gaugeAbi,
2555
- functionName: "rewardsListLength"
2556
- });
2557
- if (listLen > 0n) {
2558
- const data2 = encodeFunctionData8({
2559
- abi: gaugeAbi,
2560
- functionName: "getReward",
2561
- args: [account, []]
2562
- });
2563
- return {
2564
- description: `[${this.protocolName}] Claim gauge rewards`,
2565
- to: gauge,
2566
- data: data2,
2567
- value: 0n,
2568
- gas_estimate: 3e5
2569
- };
2570
- }
2571
- } catch {
2572
- }
2573
- }
2574
- const data = encodeFunctionData8({
2575
- abi: gaugeAbi,
2576
- functionName: "getReward",
2577
- args: [account ?? zeroAddress4]
2578
- });
3103
+ // ─── Claim: via GaugeManager ──────────────────────────────────
3104
+ async buildClaimRewards(gauge, _account) {
3105
+ throw DefiError.unsupported(`[${this.protocolName}] Use buildClaimRewardsByTokenId for CL gauges`);
3106
+ }
3107
+ async buildClaimRewardsByTokenId(gauge, tokenId) {
2579
3108
  return {
2580
- description: `[${this.protocolName}] Claim gauge rewards`,
2581
- to: gauge,
2582
- data,
3109
+ description: `[${this.protocolName}] Claim rewards for NFT #${tokenId}`,
3110
+ to: this.gaugeManager,
3111
+ data: encodeFunctionData8({
3112
+ abi: gaugeManagerAbi,
3113
+ functionName: "claimRewards",
3114
+ args: [gauge, [tokenId], 1]
3115
+ // redeemType=1
3116
+ }),
2583
3117
  value: 0n,
2584
- gas_estimate: 2e5
3118
+ gas_estimate: 1e6
2585
3119
  };
2586
3120
  }
2587
- async getPendingRewards(_gauge, _user) {
2588
- throw DefiError.unsupported(`[${this.protocolName}] get_pending_rewards requires RPC`);
3121
+ // ─── Pending Rewards ──────────────────────────────────────────
3122
+ async getPendingRewards(gauge, _user) {
3123
+ throw DefiError.unsupported(`[${this.protocolName}] Use getPendingRewardsByTokenId for CL gauges`);
3124
+ }
3125
+ async getPendingRewardsByTokenId(gauge, tokenId) {
3126
+ if (!this.rpcUrl) throw DefiError.rpcError("RPC required");
3127
+ const client = createPublicClient5({ transport: http5(this.rpcUrl) });
3128
+ return await client.readContract({
3129
+ address: gauge,
3130
+ abi: gaugeCLAbi,
3131
+ functionName: "earned",
3132
+ args: [tokenId]
3133
+ });
2589
3134
  }
2590
- // IVoteEscrow
3135
+ // ─── VoteEscrow ──────────────────────────────────────────────
2591
3136
  async buildCreateLock(amount, lockDuration) {
2592
- const data = encodeFunctionData8({
2593
- abi: veAbi,
2594
- functionName: "create_lock",
2595
- args: [amount, BigInt(lockDuration)]
2596
- });
2597
3137
  return {
2598
- description: `[${this.protocolName}] Create veNFT lock: ${amount} tokens for ${lockDuration}s`,
3138
+ description: `[${this.protocolName}] Create veNFT lock`,
2599
3139
  to: this.veToken,
2600
- data,
3140
+ data: encodeFunctionData8({ abi: veAbi, functionName: "create_lock", args: [amount, BigInt(lockDuration)] }),
2601
3141
  value: 0n,
2602
3142
  gas_estimate: 3e5
2603
3143
  };
2604
3144
  }
2605
3145
  async buildIncreaseAmount(tokenId, amount) {
2606
- const data = encodeFunctionData8({
2607
- abi: veAbi,
2608
- functionName: "increase_amount",
2609
- args: [tokenId, amount]
2610
- });
2611
3146
  return {
2612
- description: `[${this.protocolName}] Increase veNFT #${tokenId} by ${amount}`,
3147
+ description: `[${this.protocolName}] Increase veNFT #${tokenId}`,
2613
3148
  to: this.veToken,
2614
- data,
3149
+ data: encodeFunctionData8({ abi: veAbi, functionName: "increase_amount", args: [tokenId, amount] }),
2615
3150
  value: 0n,
2616
3151
  gas_estimate: 2e5
2617
3152
  };
2618
3153
  }
2619
3154
  async buildIncreaseUnlockTime(tokenId, lockDuration) {
2620
- const data = encodeFunctionData8({
2621
- abi: veAbi,
2622
- functionName: "increase_unlock_time",
2623
- args: [tokenId, BigInt(lockDuration)]
2624
- });
2625
3155
  return {
2626
- description: `[${this.protocolName}] Extend veNFT #${tokenId} lock by ${lockDuration}s`,
3156
+ description: `[${this.protocolName}] Extend veNFT #${tokenId} lock`,
2627
3157
  to: this.veToken,
2628
- data,
3158
+ data: encodeFunctionData8({ abi: veAbi, functionName: "increase_unlock_time", args: [tokenId, BigInt(lockDuration)] }),
2629
3159
  value: 0n,
2630
3160
  gas_estimate: 2e5
2631
3161
  };
2632
3162
  }
2633
3163
  async buildWithdrawExpired(tokenId) {
2634
- const data = encodeFunctionData8({
2635
- abi: veAbi,
2636
- functionName: "withdraw",
2637
- args: [tokenId]
2638
- });
2639
3164
  return {
2640
3165
  description: `[${this.protocolName}] Withdraw expired veNFT #${tokenId}`,
2641
3166
  to: this.veToken,
2642
- data,
3167
+ data: encodeFunctionData8({ abi: veAbi, functionName: "withdraw", args: [tokenId] }),
2643
3168
  value: 0n,
2644
3169
  gas_estimate: 2e5
2645
3170
  };
2646
3171
  }
2647
- // IVoter
3172
+ // ─── Voter ──────────────────────────────────────────────────
2648
3173
  async buildVote(tokenId, pools, weights) {
2649
- const data = encodeFunctionData8({
2650
- abi: voterAbi,
2651
- functionName: "vote",
2652
- args: [tokenId, pools, weights]
2653
- });
2654
3174
  return {
2655
3175
  description: `[${this.protocolName}] Vote with veNFT #${tokenId}`,
2656
3176
  to: this.voter,
2657
- data,
3177
+ data: encodeFunctionData8({ abi: voterAbi, functionName: "vote", args: [tokenId, pools, weights] }),
2658
3178
  value: 0n,
2659
3179
  gas_estimate: 5e5
2660
3180
  };
2661
3181
  }
2662
3182
  async buildClaimBribes(bribes, tokenId) {
2663
3183
  const tokensPerBribe = bribes.map(() => []);
2664
- const data = encodeFunctionData8({
2665
- abi: voterAbi,
2666
- functionName: "claimBribes",
2667
- args: [bribes, tokensPerBribe, tokenId]
2668
- });
2669
3184
  return {
2670
3185
  description: `[${this.protocolName}] Claim bribes for veNFT #${tokenId}`,
2671
3186
  to: this.voter,
2672
- data,
3187
+ data: encodeFunctionData8({ abi: voterAbi, functionName: "claimBribes", args: [bribes, tokensPerBribe, tokenId] }),
2673
3188
  value: 0n,
2674
3189
  gas_estimate: 3e5
2675
3190
  };
2676
3191
  }
2677
3192
  async buildClaimFees(fees, tokenId) {
2678
3193
  const tokensPerFee = fees.map(() => []);
2679
- const data = encodeFunctionData8({
2680
- abi: voterAbi,
2681
- functionName: "claimFees",
2682
- args: [fees, tokensPerFee, tokenId]
2683
- });
2684
3194
  return {
2685
- description: `[${this.protocolName}] Claim trading fees for veNFT #${tokenId}`,
3195
+ description: `[${this.protocolName}] Claim fees for veNFT #${tokenId}`,
2686
3196
  to: this.voter,
2687
- data,
3197
+ data: encodeFunctionData8({ abi: voterAbi, functionName: "claimFees", args: [fees, tokensPerFee, tokenId] }),
2688
3198
  value: 0n,
2689
3199
  gas_estimate: 3e5
2690
3200
  };
2691
3201
  }
2692
3202
  };
2693
- masterchefAbi = parseAbi9([
2694
- "function deposit(uint256 pid, uint256 amount) external",
2695
- "function withdraw(uint256 pid, uint256 amount) external",
2696
- "function claim(uint256[] calldata pids) external",
2697
- "function pendingRewards(address account, uint256[] calldata pids) view returns (uint256[] memory moeRewards)",
2698
- "function getNumberOfFarms() view returns (uint256)",
2699
- "function getPidByPool(address pool) view returns (uint256)"
3203
+ abi5 = parseAbi9([
3204
+ "function swap(address fromToken, address toToken, uint256 fromAmount, uint256 minToAmount, address to, address rebateTo) external payable returns (uint256 realToAmount)"
2700
3205
  ]);
2701
- MasterChefAdapter = class {
3206
+ WooFiAdapter = class {
2702
3207
  protocolName;
2703
- masterchef;
3208
+ router;
3209
+ constructor(entry, _rpcUrl) {
3210
+ this.protocolName = entry.name;
3211
+ const router = entry.contracts?.["router"];
3212
+ if (!router) {
3213
+ throw new DefiError("CONTRACT_ERROR", "Missing 'router' contract");
3214
+ }
3215
+ this.router = router;
3216
+ }
3217
+ name() {
3218
+ return this.protocolName;
3219
+ }
3220
+ async buildSwap(params) {
3221
+ const minToAmount = 0n;
3222
+ const data = encodeFunctionData9({
3223
+ abi: abi5,
3224
+ functionName: "swap",
3225
+ args: [
3226
+ params.token_in,
3227
+ params.token_out,
3228
+ params.amount_in,
3229
+ minToAmount,
3230
+ params.recipient,
3231
+ zeroAddress5
3232
+ ]
3233
+ });
3234
+ return {
3235
+ description: `[${this.protocolName}] Swap ${params.amount_in} via WOOFi`,
3236
+ to: this.router,
3237
+ data,
3238
+ value: 0n,
3239
+ gas_estimate: 2e5
3240
+ };
3241
+ }
3242
+ async quote(_params) {
3243
+ throw DefiError.unsupported(`[${this.protocolName}] quote requires RPC`);
3244
+ }
3245
+ async buildAddLiquidity(_params) {
3246
+ throw DefiError.unsupported(`[${this.protocolName}] WOOFi does not support LP positions via router`);
3247
+ }
3248
+ async buildRemoveLiquidity(_params) {
3249
+ throw DefiError.unsupported(`[${this.protocolName}] WOOFi does not support LP positions via router`);
3250
+ }
3251
+ };
3252
+ gaugeAbi = parseAbi10([
3253
+ "function deposit(uint256 amount) external",
3254
+ "function depositFor(uint256 amount, uint256 tokenId) external",
3255
+ "function withdraw(uint256 amount) external",
3256
+ "function getReward() external",
3257
+ "function getReward(address account) external",
3258
+ "function getReward(address account, address[] tokens) external",
3259
+ "function getReward(uint256 tokenId) external",
3260
+ "function earned(address account) external view returns (uint256)",
3261
+ "function earned(address token, address account) external view returns (uint256)",
3262
+ "function earned(uint256 tokenId) external view returns (uint256)",
3263
+ "function rewardRate() external view returns (uint256)",
3264
+ "function rewardToken() external view returns (address)",
3265
+ "function totalSupply() external view returns (uint256)",
3266
+ "function rewardsListLength() external view returns (uint256)",
3267
+ "function rewardData(address token) external view returns (uint256 periodFinish, uint256 rewardRate, uint256 lastUpdateTime, uint256 rewardPerTokenStored)",
3268
+ "function nonfungiblePositionManager() external view returns (address)"
3269
+ ]);
3270
+ veAbi2 = parseAbi10([
3271
+ "function create_lock(uint256 value, uint256 lock_duration) external returns (uint256)",
3272
+ "function increase_amount(uint256 tokenId, uint256 value) external",
3273
+ "function increase_unlock_time(uint256 tokenId, uint256 lock_duration) external",
3274
+ "function withdraw(uint256 tokenId) external",
3275
+ "function balanceOfNFT(uint256 tokenId) external view returns (uint256)",
3276
+ "function locked(uint256 tokenId) external view returns (uint256 amount, uint256 end)"
3277
+ ]);
3278
+ voterAbi2 = parseAbi10([
3279
+ "function vote(uint256 tokenId, address[] calldata pools, uint256[] calldata weights) external",
3280
+ "function claimBribes(address[] calldata bribes, address[][] calldata tokens, uint256 tokenId) external",
3281
+ "function claimFees(address[] calldata fees, address[][] calldata tokens, uint256 tokenId) external",
3282
+ "function gauges(address pool) external view returns (address)",
3283
+ "function gaugeForPool(address pool) external view returns (address)",
3284
+ "function poolToGauge(address pool) external view returns (address)"
3285
+ ]);
3286
+ _addressDecodeAbi2 = parseAbi10(["function f() external view returns (address)"]);
3287
+ _symbolDecodeAbi2 = parseAbi10(["function symbol() external view returns (string)"]);
3288
+ _boolDecodeAbi = parseAbi10(["function f() external view returns (bool)"]);
3289
+ HYPEREVM_TOKENS = {
3290
+ WHYPE: "0x5555555555555555555555555555555555555555",
3291
+ USDC: "0xb88339CB7199b77E23DB6E890353E22632Ba630f",
3292
+ USDT0: "0xB8CE59FC3717ada4C02eaDF9682A9e934F625ebb",
3293
+ UETH: "0xBe6727B535545C67d5cAa73dEa54865B92CF7907",
3294
+ UBTC: "0x9FDBdA0A5e284c32744D2f17Ee5c74B284993463",
3295
+ USDH: "0x111111a1a0667d36bD57c0A9f569b98057111111",
3296
+ USDe: "0x5d3a1Ff2b6BAb83b63cd9AD0787074081a52ef34",
3297
+ sUSDe: "0x211Cc4DD073734dA055fbF44a2b4667d5E5fE5d2",
3298
+ XAUt0: "0xf4D9235269a96aaDaFc9aDAe454a0618eBE37949",
3299
+ kHYPE: "0xfD739d4e423301CE9385c1fb8850539D657C296D",
3300
+ RAM: "0x555570a286F15EbDFE42B66eDE2f724Aa1AB5555",
3301
+ hyperRAM: "0xAAAE8378809bb8815c08D3C59Eb0c7D1529aD769"
3302
+ };
3303
+ CL_TICK_SPACINGS = [1, 5, 10, 50, 100, 200];
3304
+ SolidlyGaugeAdapter = class {
3305
+ protocolName;
3306
+ voter;
3307
+ veToken;
2704
3308
  rpcUrl;
3309
+ clFactory;
3310
+ v2Factory;
2705
3311
  constructor(entry, rpcUrl) {
2706
3312
  this.protocolName = entry.name;
2707
- const masterchef = entry.contracts?.["masterchef"];
2708
- if (!masterchef) {
2709
- throw new DefiError("CONTRACT_ERROR", "Missing 'masterchef' contract");
3313
+ const voter = entry.contracts?.["voter"];
3314
+ if (!voter) {
3315
+ throw new DefiError("CONTRACT_ERROR", "Missing 'voter' contract");
2710
3316
  }
2711
- this.masterchef = masterchef;
3317
+ const veToken = entry.contracts?.["ve_token"];
3318
+ if (!veToken) {
3319
+ throw new DefiError("CONTRACT_ERROR", "Missing 've_token' contract");
3320
+ }
3321
+ this.voter = voter;
3322
+ this.veToken = veToken;
2712
3323
  this.rpcUrl = rpcUrl;
3324
+ this.clFactory = entry.contracts?.["cl_factory"] ?? entry.contracts?.["factory"];
3325
+ this.v2Factory = entry.contracts?.["pair_factory"] ?? entry.contracts?.["factory"];
2713
3326
  }
2714
3327
  name() {
2715
3328
  return this.protocolName;
2716
3329
  }
2717
- /**
2718
- * Deposit LP tokens into a MasterChef farm.
2719
- * `gauge` is the pool address (unused for calldata — MasterChef is the target).
2720
- * `tokenId` carries the farm pid.
2721
- */
2722
- async buildDeposit(gauge, amount, tokenId) {
2723
- const pid = tokenId ?? 0n;
2724
- const data = encodeFunctionData9({
2725
- abi: masterchefAbi,
3330
+ /** Scan V2 and CL factories for pools that have active emission gauges. */
3331
+ async discoverGaugedPools() {
3332
+ if (!this.rpcUrl) throw DefiError.rpcError("RPC URL required for gauge discovery");
3333
+ const results = [];
3334
+ await Promise.all([
3335
+ this._discoverV2GaugedPools(results),
3336
+ this._discoverCLGaugedPools(results)
3337
+ ]);
3338
+ return results;
3339
+ }
3340
+ async _discoverV2GaugedPools(out) {
3341
+ if (!this.rpcUrl || !this.v2Factory) return;
3342
+ const v2FactoryAbi = parseAbi10([
3343
+ "function allPairsLength() external view returns (uint256)",
3344
+ "function allPairs(uint256) external view returns (address)"
3345
+ ]);
3346
+ const pairAbi = parseAbi10([
3347
+ "function token0() external view returns (address)",
3348
+ "function token1() external view returns (address)",
3349
+ "function stable() external view returns (bool)"
3350
+ ]);
3351
+ const erc20SymbolAbi = parseAbi10(["function symbol() external view returns (string)"]);
3352
+ const client = createPublicClient6({ transport: http6(this.rpcUrl) });
3353
+ let pairCount;
3354
+ try {
3355
+ pairCount = await client.readContract({
3356
+ address: this.v2Factory,
3357
+ abi: v2FactoryAbi,
3358
+ functionName: "allPairsLength"
3359
+ });
3360
+ } catch {
3361
+ return;
3362
+ }
3363
+ const count = Number(pairCount);
3364
+ if (count === 0) return;
3365
+ const pairAddressCalls = [];
3366
+ for (let i = 0; i < count; i++) {
3367
+ pairAddressCalls.push([
3368
+ this.v2Factory,
3369
+ encodeFunctionData10({ abi: v2FactoryAbi, functionName: "allPairs", args: [BigInt(i)] })
3370
+ ]);
3371
+ }
3372
+ const pairAddressResults = await multicallRead(this.rpcUrl, pairAddressCalls);
3373
+ const pairs = pairAddressResults.map((r) => decodeAddress2(r)).filter((a) => a !== null && a !== zeroAddress6);
3374
+ if (pairs.length === 0) return;
3375
+ const gaugeForPoolAbi = parseAbi10(["function gaugeForPool(address) external view returns (address)"]);
3376
+ const poolToGaugeAbi = parseAbi10(["function poolToGauge(address) external view returns (address)"]);
3377
+ const gaugeCalls = pairs.map((pair) => [
3378
+ this.voter,
3379
+ encodeFunctionData10({ abi: gaugeForPoolAbi, functionName: "gaugeForPool", args: [pair] })
3380
+ ]);
3381
+ let gaugeResults = await multicallRead(this.rpcUrl, gaugeCalls);
3382
+ const allNullV2 = gaugeResults.every((r) => !r || decodeAddress2(r) === zeroAddress6 || decodeAddress2(r) === null);
3383
+ if (allNullV2) {
3384
+ const fallbackCalls = pairs.map((pair) => [
3385
+ this.voter,
3386
+ encodeFunctionData10({ abi: poolToGaugeAbi, functionName: "poolToGauge", args: [pair] })
3387
+ ]);
3388
+ gaugeResults = await multicallRead(this.rpcUrl, fallbackCalls);
3389
+ }
3390
+ const gaugedPairs = [];
3391
+ for (let i = 0; i < pairs.length; i++) {
3392
+ const gauge = decodeAddress2(gaugeResults[i] ?? null);
3393
+ if (gauge && gauge !== zeroAddress6) {
3394
+ gaugedPairs.push({ pair: pairs[i], gauge });
3395
+ }
3396
+ }
3397
+ if (gaugedPairs.length === 0) return;
3398
+ const metaCalls = [];
3399
+ for (const { pair } of gaugedPairs) {
3400
+ metaCalls.push([pair, encodeFunctionData10({ abi: pairAbi, functionName: "token0" })]);
3401
+ metaCalls.push([pair, encodeFunctionData10({ abi: pairAbi, functionName: "token1" })]);
3402
+ metaCalls.push([pair, encodeFunctionData10({ abi: pairAbi, functionName: "stable" })]);
3403
+ }
3404
+ const metaResults = await multicallRead(this.rpcUrl, metaCalls);
3405
+ const tokenAddrs = /* @__PURE__ */ new Set();
3406
+ for (let i = 0; i < gaugedPairs.length; i++) {
3407
+ const t0 = decodeAddress2(metaResults[i * 3] ?? null);
3408
+ const t1 = decodeAddress2(metaResults[i * 3 + 1] ?? null);
3409
+ if (t0 && t0 !== zeroAddress6) tokenAddrs.add(t0);
3410
+ if (t1 && t1 !== zeroAddress6) tokenAddrs.add(t1);
3411
+ }
3412
+ const uniqueTokens = Array.from(tokenAddrs);
3413
+ const symbolCalls = uniqueTokens.map((t) => [
3414
+ t,
3415
+ encodeFunctionData10({ abi: erc20SymbolAbi, functionName: "symbol" })
3416
+ ]);
3417
+ const symbolResults = await multicallRead(this.rpcUrl, symbolCalls);
3418
+ const symbolMap = /* @__PURE__ */ new Map();
3419
+ for (let i = 0; i < uniqueTokens.length; i++) {
3420
+ symbolMap.set(uniqueTokens[i], decodeSymbol2(symbolResults[i] ?? null));
3421
+ }
3422
+ for (let i = 0; i < gaugedPairs.length; i++) {
3423
+ const { pair, gauge } = gaugedPairs[i];
3424
+ const t0 = decodeAddress2(metaResults[i * 3] ?? null);
3425
+ const t1 = decodeAddress2(metaResults[i * 3 + 1] ?? null);
3426
+ const stableRaw = metaResults[i * 3 + 2];
3427
+ const stable = stableRaw ? decodeBoolean(stableRaw) : false;
3428
+ out.push({
3429
+ pool: pair,
3430
+ gauge,
3431
+ token0: t0 ? symbolMap.get(t0) ?? t0.slice(0, 10) : "?",
3432
+ token1: t1 ? symbolMap.get(t1) ?? t1.slice(0, 10) : "?",
3433
+ type: "V2",
3434
+ stable
3435
+ });
3436
+ }
3437
+ }
3438
+ async _discoverCLGaugedPools(out) {
3439
+ if (!this.rpcUrl || !this.clFactory) return;
3440
+ const clFactoryAbi = parseAbi10([
3441
+ "function getPool(address tokenA, address tokenB, int24 tickSpacing) external view returns (address pool)"
3442
+ ]);
3443
+ const algebraFactoryAbi2 = parseAbi10([
3444
+ "function poolByPair(address tokenA, address tokenB) external view returns (address pool)"
3445
+ ]);
3446
+ const poolAbi2 = parseAbi10([
3447
+ "function token0() external view returns (address)",
3448
+ "function token1() external view returns (address)"
3449
+ ]);
3450
+ const erc20SymbolAbi = parseAbi10(["function symbol() external view returns (string)"]);
3451
+ const gaugeForPoolAbi = parseAbi10(["function gaugeForPool(address) external view returns (address)"]);
3452
+ const poolToGaugeAbi = parseAbi10(["function poolToGauge(address) external view returns (address)"]);
3453
+ const tokenEntries = Object.entries(HYPEREVM_TOKENS);
3454
+ const tokenAddresses = tokenEntries.map(([, addr]) => addr);
3455
+ const pairs = [];
3456
+ for (let i = 0; i < tokenAddresses.length; i++) {
3457
+ for (let j = i + 1; j < tokenAddresses.length; j++) {
3458
+ pairs.push([tokenAddresses[i], tokenAddresses[j]]);
3459
+ }
3460
+ }
3461
+ const isAlgebra = await (async () => {
3462
+ try {
3463
+ const [result] = await multicallRead(this.rpcUrl, [[
3464
+ this.clFactory,
3465
+ encodeFunctionData10({ abi: algebraFactoryAbi2, functionName: "poolByPair", args: [tokenAddresses[0], tokenAddresses[1]] })
3466
+ ]]);
3467
+ return result !== null && result.length >= 66;
3468
+ } catch {
3469
+ return false;
3470
+ }
3471
+ })();
3472
+ const getPoolCalls = [];
3473
+ const callMeta = [];
3474
+ if (isAlgebra) {
3475
+ for (let p = 0; p < pairs.length; p++) {
3476
+ const [tokenA, tokenB] = pairs[p];
3477
+ getPoolCalls.push([
3478
+ this.clFactory,
3479
+ encodeFunctionData10({ abi: algebraFactoryAbi2, functionName: "poolByPair", args: [tokenA, tokenB] })
3480
+ ]);
3481
+ callMeta.push({ pairIdx: p, tickSpacing: 0 });
3482
+ }
3483
+ } else {
3484
+ for (let p = 0; p < pairs.length; p++) {
3485
+ const [tokenA, tokenB] = pairs[p];
3486
+ for (const ts of CL_TICK_SPACINGS) {
3487
+ getPoolCalls.push([
3488
+ this.clFactory,
3489
+ encodeFunctionData10({ abi: clFactoryAbi, functionName: "getPool", args: [tokenA, tokenB, ts] })
3490
+ ]);
3491
+ callMeta.push({ pairIdx: p, tickSpacing: ts });
3492
+ }
3493
+ }
3494
+ }
3495
+ const getPoolResults = await multicallRead(this.rpcUrl, getPoolCalls);
3496
+ const candidatePools = [];
3497
+ for (let i = 0; i < getPoolCalls.length; i++) {
3498
+ const pool = decodeAddress2(getPoolResults[i] ?? null);
3499
+ if (pool && pool !== zeroAddress6) {
3500
+ const { pairIdx, tickSpacing } = callMeta[i];
3501
+ const [tokenA, tokenB] = pairs[pairIdx];
3502
+ candidatePools.push({ pool, tokenA, tokenB, tickSpacing });
3503
+ }
3504
+ }
3505
+ if (candidatePools.length === 0) return;
3506
+ const gaugeCalls = candidatePools.map(({ pool }) => [
3507
+ this.voter,
3508
+ encodeFunctionData10({ abi: gaugeForPoolAbi, functionName: "gaugeForPool", args: [pool] })
3509
+ ]);
3510
+ let gaugeResults = await multicallRead(this.rpcUrl, gaugeCalls);
3511
+ const allNull = gaugeResults.every((r) => !r || decodeAddress2(r) === zeroAddress6 || decodeAddress2(r) === null);
3512
+ if (allNull) {
3513
+ const fallbackCalls = candidatePools.map(({ pool }) => [
3514
+ this.voter,
3515
+ encodeFunctionData10({ abi: poolToGaugeAbi, functionName: "poolToGauge", args: [pool] })
3516
+ ]);
3517
+ gaugeResults = await multicallRead(this.rpcUrl, fallbackCalls);
3518
+ }
3519
+ const gaugedCL = [];
3520
+ for (let i = 0; i < candidatePools.length; i++) {
3521
+ const gauge = decodeAddress2(gaugeResults[i] ?? null);
3522
+ if (gauge && gauge !== zeroAddress6) {
3523
+ gaugedCL.push({ ...candidatePools[i], gauge });
3524
+ }
3525
+ }
3526
+ if (gaugedCL.length === 0) return;
3527
+ const tokenAddrsInPools = /* @__PURE__ */ new Set();
3528
+ for (const { tokenA, tokenB } of gaugedCL) {
3529
+ tokenAddrsInPools.add(tokenA);
3530
+ tokenAddrsInPools.add(tokenB);
3531
+ }
3532
+ const uniqueTokens = Array.from(tokenAddrsInPools);
3533
+ const symbolCalls = uniqueTokens.map((t) => [
3534
+ t,
3535
+ encodeFunctionData10({ abi: erc20SymbolAbi, functionName: "symbol" })
3536
+ ]);
3537
+ const symbolResults = await multicallRead(this.rpcUrl, symbolCalls);
3538
+ const symbolMap = /* @__PURE__ */ new Map();
3539
+ for (let i = 0; i < uniqueTokens.length; i++) {
3540
+ symbolMap.set(uniqueTokens[i], decodeSymbol2(symbolResults[i] ?? null));
3541
+ }
3542
+ const poolTokenCalls = [];
3543
+ for (const { pool } of gaugedCL) {
3544
+ poolTokenCalls.push([pool, encodeFunctionData10({ abi: poolAbi2, functionName: "token0" })]);
3545
+ poolTokenCalls.push([pool, encodeFunctionData10({ abi: poolAbi2, functionName: "token1" })]);
3546
+ }
3547
+ const poolTokenResults = await multicallRead(this.rpcUrl, poolTokenCalls);
3548
+ for (let i = 0; i < gaugedCL.length; i++) {
3549
+ const { pool, gauge, tokenA, tokenB, tickSpacing } = gaugedCL[i];
3550
+ const rawT0 = decodeAddress2(poolTokenResults[i * 2] ?? null);
3551
+ const rawT1 = decodeAddress2(poolTokenResults[i * 2 + 1] ?? null);
3552
+ const t0 = rawT0 && rawT0 !== zeroAddress6 ? rawT0 : tokenA;
3553
+ const t1 = rawT1 && rawT1 !== zeroAddress6 ? rawT1 : tokenB;
3554
+ out.push({
3555
+ pool,
3556
+ gauge,
3557
+ token0: symbolMap.get(t0) ?? t0.slice(0, 10),
3558
+ token1: symbolMap.get(t1) ?? t1.slice(0, 10),
3559
+ type: "CL",
3560
+ tickSpacing
3561
+ });
3562
+ }
3563
+ }
3564
+ // IGauge
3565
+ async buildDeposit(gauge, amount, tokenId, lpToken) {
3566
+ if (tokenId !== void 0) {
3567
+ const data2 = encodeFunctionData10({
3568
+ abi: gaugeAbi,
3569
+ functionName: "depositFor",
3570
+ args: [amount, tokenId]
3571
+ });
3572
+ return {
3573
+ description: `[${this.protocolName}] Deposit ${amount} LP to gauge (boost veNFT #${tokenId})`,
3574
+ to: gauge,
3575
+ data: data2,
3576
+ value: 0n,
3577
+ gas_estimate: 2e5,
3578
+ approvals: lpToken ? [{ token: lpToken, spender: gauge, amount }] : void 0
3579
+ };
3580
+ }
3581
+ const data = encodeFunctionData10({
3582
+ abi: gaugeAbi,
2726
3583
  functionName: "deposit",
2727
- args: [pid, amount]
3584
+ args: [amount]
2728
3585
  });
2729
3586
  return {
2730
- description: `[${this.protocolName}] Deposit ${amount} LP to farm pid=${pid} (pool ${gauge})`,
2731
- to: this.masterchef,
3587
+ description: `[${this.protocolName}] Deposit ${amount} LP to gauge`,
3588
+ to: gauge,
2732
3589
  data,
2733
3590
  value: 0n,
2734
- gas_estimate: 2e5
3591
+ gas_estimate: 2e5,
3592
+ approvals: lpToken ? [{ token: lpToken, spender: gauge, amount }] : void 0
2735
3593
  };
2736
3594
  }
2737
- /**
2738
- * Withdraw LP tokens from a MasterChef farm.
2739
- * `gauge` is used to look up the pid description only; call site should pass pid via tokenId
3595
+ async buildWithdraw(gauge, amount) {
3596
+ const data = encodeFunctionData10({
3597
+ abi: gaugeAbi,
3598
+ functionName: "withdraw",
3599
+ args: [amount]
3600
+ });
3601
+ return {
3602
+ description: `[${this.protocolName}] Withdraw ${amount} LP from gauge`,
3603
+ to: gauge,
3604
+ data,
3605
+ value: 0n,
3606
+ gas_estimate: 2e5
3607
+ };
3608
+ }
3609
+ /**
3610
+ * Resolve gauge address from a pool address via voter contract.
3611
+ * Tries gaugeForPool (Ramses), poolToGauge (NEST), gauges (classic Solidly).
3612
+ */
3613
+ async resolveGauge(pool) {
3614
+ if (!this.rpcUrl) throw DefiError.rpcError("RPC URL required for gauge lookup");
3615
+ const client = createPublicClient6({ transport: http6(this.rpcUrl) });
3616
+ for (const fn of ["gaugeForPool", "poolToGauge", "gauges"]) {
3617
+ try {
3618
+ const gauge = await client.readContract({
3619
+ address: this.voter,
3620
+ abi: voterAbi2,
3621
+ functionName: fn,
3622
+ args: [pool]
3623
+ });
3624
+ if (gauge !== zeroAddress6) return gauge;
3625
+ } catch {
3626
+ }
3627
+ }
3628
+ throw new DefiError("CONTRACT_ERROR", `[${this.protocolName}] No gauge found for pool ${pool}`);
3629
+ }
3630
+ /**
3631
+ * Discover reward tokens for a gauge.
3632
+ * Returns { tokens, multiToken } where multiToken indicates getReward(account, tokens[]) support.
3633
+ */
3634
+ async discoverRewardTokens(gauge) {
3635
+ if (!this.rpcUrl) return { tokens: [], multiToken: false };
3636
+ const client = createPublicClient6({ transport: http6(this.rpcUrl) });
3637
+ try {
3638
+ const len = await client.readContract({
3639
+ address: gauge,
3640
+ abi: gaugeAbi,
3641
+ functionName: "rewardsListLength"
3642
+ });
3643
+ if (Number(len) > 0) {
3644
+ const candidates = [
3645
+ "0x5555555555555555555555555555555555555555",
3646
+ // WHYPE
3647
+ "0x555570a286F15EbDFE42B66eDE2f724Aa1AB5555",
3648
+ // xRAM
3649
+ "0x067b0C72aa4C6Bd3BFEFfF443c536DCd6a25a9C8",
3650
+ // HYBR
3651
+ "0x07c57E32a3C29D5659bda1d3EFC2E7BF004E3035"
3652
+ // NEST token
3653
+ ];
3654
+ const found = [];
3655
+ for (const token of candidates) {
3656
+ try {
3657
+ const rd = await client.readContract({
3658
+ address: gauge,
3659
+ abi: gaugeAbi,
3660
+ functionName: "rewardData",
3661
+ args: [token]
3662
+ });
3663
+ if (rd[0] > 0n || rd[1] > 0n) found.push(token);
3664
+ } catch {
3665
+ }
3666
+ }
3667
+ if (found.length > 0) return { tokens: found, multiToken: true };
3668
+ return { tokens: [], multiToken: true };
3669
+ }
3670
+ } catch {
3671
+ }
3672
+ try {
3673
+ const rt = await client.readContract({
3674
+ address: gauge,
3675
+ abi: gaugeAbi,
3676
+ functionName: "rewardToken"
3677
+ });
3678
+ if (rt !== zeroAddress6) return { tokens: [rt], multiToken: false };
3679
+ } catch {
3680
+ }
3681
+ return { tokens: [], multiToken: false };
3682
+ }
3683
+ async buildClaimRewards(gauge, account) {
3684
+ if (!this.rpcUrl || !account) {
3685
+ const data2 = encodeFunctionData10({
3686
+ abi: gaugeAbi,
3687
+ functionName: "getReward",
3688
+ args: [account ?? zeroAddress6]
3689
+ });
3690
+ return { description: `[${this.protocolName}] Claim gauge rewards`, to: gauge, data: data2, value: 0n, gas_estimate: 2e5 };
3691
+ }
3692
+ const { tokens, multiToken } = await this.discoverRewardTokens(gauge);
3693
+ if (multiToken && tokens.length > 0) {
3694
+ const data2 = encodeFunctionData10({
3695
+ abi: gaugeAbi,
3696
+ functionName: "getReward",
3697
+ args: [account, tokens]
3698
+ });
3699
+ return {
3700
+ description: `[${this.protocolName}] Claim gauge rewards (${tokens.length} tokens)`,
3701
+ to: gauge,
3702
+ data: data2,
3703
+ value: 0n,
3704
+ gas_estimate: 3e5
3705
+ };
3706
+ }
3707
+ const data = encodeFunctionData10({
3708
+ abi: gaugeAbi,
3709
+ functionName: "getReward",
3710
+ args: []
3711
+ });
3712
+ return {
3713
+ description: `[${this.protocolName}] Claim gauge rewards`,
3714
+ to: gauge,
3715
+ data,
3716
+ value: 0n,
3717
+ gas_estimate: 2e5
3718
+ };
3719
+ }
3720
+ /**
3721
+ * Claim rewards for a CL gauge by NFT tokenId (Hybra V4 style).
3722
+ */
3723
+ async buildClaimRewardsByTokenId(gauge, tokenId) {
3724
+ const data = encodeFunctionData10({
3725
+ abi: gaugeAbi,
3726
+ functionName: "getReward",
3727
+ args: [tokenId]
3728
+ });
3729
+ return {
3730
+ description: `[${this.protocolName}] Claim gauge rewards for NFT #${tokenId}`,
3731
+ to: gauge,
3732
+ data,
3733
+ value: 0n,
3734
+ gas_estimate: 3e5
3735
+ };
3736
+ }
3737
+ async getPendingRewards(gauge, user) {
3738
+ if (!this.rpcUrl) throw DefiError.rpcError("RPC URL required");
3739
+ const client = createPublicClient6({ transport: http6(this.rpcUrl) });
3740
+ const results = [];
3741
+ const { tokens, multiToken } = await this.discoverRewardTokens(gauge);
3742
+ if (multiToken && tokens.length > 0) {
3743
+ for (const token of tokens) {
3744
+ try {
3745
+ const earned = await client.readContract({
3746
+ address: gauge,
3747
+ abi: gaugeAbi,
3748
+ functionName: "earned",
3749
+ args: [token, user]
3750
+ });
3751
+ results.push({ token, symbol: token.slice(0, 10), amount: earned });
3752
+ } catch {
3753
+ }
3754
+ }
3755
+ } else if (tokens.length > 0) {
3756
+ try {
3757
+ const earned = await client.readContract({
3758
+ address: gauge,
3759
+ abi: gaugeAbi,
3760
+ functionName: "earned",
3761
+ args: [user]
3762
+ });
3763
+ results.push({ token: tokens[0], symbol: tokens[0].slice(0, 10), amount: earned });
3764
+ } catch {
3765
+ }
3766
+ } else {
3767
+ try {
3768
+ const earned = await client.readContract({
3769
+ address: gauge,
3770
+ abi: gaugeAbi,
3771
+ functionName: "earned",
3772
+ args: [user]
3773
+ });
3774
+ results.push({ token: zeroAddress6, symbol: "unknown", amount: earned });
3775
+ } catch {
3776
+ }
3777
+ }
3778
+ return results;
3779
+ }
3780
+ /**
3781
+ * Get pending rewards for a CL gauge NFT position (Hybra V4 style).
3782
+ */
3783
+ async getPendingRewardsByTokenId(gauge, tokenId) {
3784
+ if (!this.rpcUrl) throw DefiError.rpcError("RPC URL required");
3785
+ const client = createPublicClient6({ transport: http6(this.rpcUrl) });
3786
+ return await client.readContract({
3787
+ address: gauge,
3788
+ abi: gaugeAbi,
3789
+ functionName: "earned",
3790
+ args: [tokenId]
3791
+ });
3792
+ }
3793
+ // IVoteEscrow
3794
+ async buildCreateLock(amount, lockDuration) {
3795
+ const data = encodeFunctionData10({
3796
+ abi: veAbi2,
3797
+ functionName: "create_lock",
3798
+ args: [amount, BigInt(lockDuration)]
3799
+ });
3800
+ return {
3801
+ description: `[${this.protocolName}] Create veNFT lock: ${amount} tokens for ${lockDuration}s`,
3802
+ to: this.veToken,
3803
+ data,
3804
+ value: 0n,
3805
+ gas_estimate: 3e5
3806
+ };
3807
+ }
3808
+ async buildIncreaseAmount(tokenId, amount) {
3809
+ const data = encodeFunctionData10({
3810
+ abi: veAbi2,
3811
+ functionName: "increase_amount",
3812
+ args: [tokenId, amount]
3813
+ });
3814
+ return {
3815
+ description: `[${this.protocolName}] Increase veNFT #${tokenId} by ${amount}`,
3816
+ to: this.veToken,
3817
+ data,
3818
+ value: 0n,
3819
+ gas_estimate: 2e5
3820
+ };
3821
+ }
3822
+ async buildIncreaseUnlockTime(tokenId, lockDuration) {
3823
+ const data = encodeFunctionData10({
3824
+ abi: veAbi2,
3825
+ functionName: "increase_unlock_time",
3826
+ args: [tokenId, BigInt(lockDuration)]
3827
+ });
3828
+ return {
3829
+ description: `[${this.protocolName}] Extend veNFT #${tokenId} lock by ${lockDuration}s`,
3830
+ to: this.veToken,
3831
+ data,
3832
+ value: 0n,
3833
+ gas_estimate: 2e5
3834
+ };
3835
+ }
3836
+ async buildWithdrawExpired(tokenId) {
3837
+ const data = encodeFunctionData10({
3838
+ abi: veAbi2,
3839
+ functionName: "withdraw",
3840
+ args: [tokenId]
3841
+ });
3842
+ return {
3843
+ description: `[${this.protocolName}] Withdraw expired veNFT #${tokenId}`,
3844
+ to: this.veToken,
3845
+ data,
3846
+ value: 0n,
3847
+ gas_estimate: 2e5
3848
+ };
3849
+ }
3850
+ // IVoter
3851
+ async buildVote(tokenId, pools, weights) {
3852
+ const data = encodeFunctionData10({
3853
+ abi: voterAbi2,
3854
+ functionName: "vote",
3855
+ args: [tokenId, pools, weights]
3856
+ });
3857
+ return {
3858
+ description: `[${this.protocolName}] Vote with veNFT #${tokenId}`,
3859
+ to: this.voter,
3860
+ data,
3861
+ value: 0n,
3862
+ gas_estimate: 5e5
3863
+ };
3864
+ }
3865
+ async buildClaimBribes(bribes, tokenId) {
3866
+ const tokensPerBribe = bribes.map(() => []);
3867
+ const data = encodeFunctionData10({
3868
+ abi: voterAbi2,
3869
+ functionName: "claimBribes",
3870
+ args: [bribes, tokensPerBribe, tokenId]
3871
+ });
3872
+ return {
3873
+ description: `[${this.protocolName}] Claim bribes for veNFT #${tokenId}`,
3874
+ to: this.voter,
3875
+ data,
3876
+ value: 0n,
3877
+ gas_estimate: 3e5
3878
+ };
3879
+ }
3880
+ async buildClaimFees(fees, tokenId) {
3881
+ const tokensPerFee = fees.map(() => []);
3882
+ const data = encodeFunctionData10({
3883
+ abi: voterAbi2,
3884
+ functionName: "claimFees",
3885
+ args: [fees, tokensPerFee, tokenId]
3886
+ });
3887
+ return {
3888
+ description: `[${this.protocolName}] Claim trading fees for veNFT #${tokenId}`,
3889
+ to: this.voter,
3890
+ data,
3891
+ value: 0n,
3892
+ gas_estimate: 3e5
3893
+ };
3894
+ }
3895
+ };
3896
+ masterchefAbi = parseAbi11([
3897
+ "function deposit(uint256 pid, uint256 amount) external",
3898
+ "function withdraw(uint256 pid, uint256 amount) external",
3899
+ "function claim(uint256[] calldata pids) external",
3900
+ "function pendingRewards(address account, uint256[] calldata pids) view returns (uint256[] memory moeRewards)",
3901
+ "function getNumberOfFarms() view returns (uint256)",
3902
+ "function getPidByPool(address pool) view returns (uint256)"
3903
+ ]);
3904
+ MasterChefAdapter = class {
3905
+ protocolName;
3906
+ masterchef;
3907
+ rpcUrl;
3908
+ constructor(entry, rpcUrl) {
3909
+ this.protocolName = entry.name;
3910
+ const masterchef = entry.contracts?.["masterchef"];
3911
+ if (!masterchef) {
3912
+ throw new DefiError("CONTRACT_ERROR", "Missing 'masterchef' contract");
3913
+ }
3914
+ this.masterchef = masterchef;
3915
+ this.rpcUrl = rpcUrl;
3916
+ }
3917
+ name() {
3918
+ return this.protocolName;
3919
+ }
3920
+ /**
3921
+ * Deposit LP tokens into a MasterChef farm.
3922
+ * `gauge` is the pool address (unused for calldata — MasterChef is the target).
3923
+ * `tokenId` carries the farm pid.
3924
+ */
3925
+ async buildDeposit(gauge, amount, tokenId) {
3926
+ const pid = tokenId ?? 0n;
3927
+ const data = encodeFunctionData11({
3928
+ abi: masterchefAbi,
3929
+ functionName: "deposit",
3930
+ args: [pid, amount]
3931
+ });
3932
+ return {
3933
+ description: `[${this.protocolName}] Deposit ${amount} LP to farm pid=${pid} (pool ${gauge})`,
3934
+ to: this.masterchef,
3935
+ data,
3936
+ value: 0n,
3937
+ gas_estimate: 2e5
3938
+ };
3939
+ }
3940
+ /**
3941
+ * Withdraw LP tokens from a MasterChef farm.
3942
+ * `gauge` is used to look up the pid description only; call site should pass pid via tokenId
2740
3943
  * on the deposit flow. Here pid defaults to 0 — callers should encode the pid in the gauge
2741
3944
  * address slot or wrap this adapter with a pid-aware helper.
2742
3945
  */
2743
3946
  async buildWithdraw(gauge, amount) {
2744
3947
  const pid = 0n;
2745
- const data = encodeFunctionData9({
3948
+ const data = encodeFunctionData11({
2746
3949
  abi: masterchefAbi,
2747
3950
  functionName: "withdraw",
2748
3951
  args: [pid, amount]
@@ -2757,7 +3960,7 @@ var init_dist3 = __esm({
2757
3960
  }
2758
3961
  /** Withdraw LP tokens specifying a pid explicitly (MasterChef extension beyond IGauge). */
2759
3962
  async buildWithdrawPid(pid, amount) {
2760
- const data = encodeFunctionData9({
3963
+ const data = encodeFunctionData11({
2761
3964
  abi: masterchefAbi,
2762
3965
  functionName: "withdraw",
2763
3966
  args: [pid, amount]
@@ -2770,57 +3973,1018 @@ var init_dist3 = __esm({
2770
3973
  gas_estimate: 2e5
2771
3974
  };
2772
3975
  }
2773
- /** Claim pending MOE rewards. IGauge interface provides no pid — defaults to pid=0. */
2774
- async buildClaimRewards(gauge) {
2775
- const pid = 0n;
2776
- const data = encodeFunctionData9({
2777
- abi: masterchefAbi,
2778
- functionName: "claim",
2779
- args: [[pid]]
2780
- });
3976
+ /** Claim pending MOE rewards. IGauge interface provides no pid — defaults to pid=0. */
3977
+ async buildClaimRewards(gauge) {
3978
+ const pid = 0n;
3979
+ const data = encodeFunctionData11({
3980
+ abi: masterchefAbi,
3981
+ functionName: "claim",
3982
+ args: [[pid]]
3983
+ });
3984
+ return {
3985
+ description: `[${this.protocolName}] Claim MOE rewards for farm pid=${pid} (pool ${gauge})`,
3986
+ to: this.masterchef,
3987
+ data,
3988
+ value: 0n,
3989
+ gas_estimate: 2e5
3990
+ };
3991
+ }
3992
+ /** Claim pending MOE rewards for a specific pid (MasterChef extension beyond IGauge). */
3993
+ async buildClaimRewardsPid(pid) {
3994
+ const data = encodeFunctionData11({
3995
+ abi: masterchefAbi,
3996
+ functionName: "claim",
3997
+ args: [[pid]]
3998
+ });
3999
+ return {
4000
+ description: `[${this.protocolName}] Claim MOE rewards for farm pid=${pid}`,
4001
+ to: this.masterchef,
4002
+ data,
4003
+ value: 0n,
4004
+ gas_estimate: 2e5
4005
+ };
4006
+ }
4007
+ /** Get pending MOE rewards for a user. Requires rpcUrl. */
4008
+ async getPendingRewards(_gauge, user) {
4009
+ if (!this.rpcUrl) {
4010
+ throw DefiError.unsupported(`[${this.protocolName}] getPendingRewards requires RPC`);
4011
+ }
4012
+ const client = createPublicClient7({ transport: http7(this.rpcUrl) });
4013
+ const rewards = await client.readContract({
4014
+ address: this.masterchef,
4015
+ abi: masterchefAbi,
4016
+ functionName: "pendingRewards",
4017
+ args: [user, [0n]]
4018
+ });
4019
+ return rewards.map((amount) => ({
4020
+ token: this.masterchef,
4021
+ symbol: "MOE",
4022
+ amount
4023
+ }));
4024
+ }
4025
+ };
4026
+ lbRouterAbi = parseAbi12([
4027
+ "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; }",
4028
+ "function addLiquidity(LiquidityParameters calldata liquidityParameters) external returns (uint256 amountXAdded, uint256 amountYAdded, uint256 amountXLeft, uint256 amountYLeft, uint256[] memory depositIds, uint256[] memory liquidityMinted)",
4029
+ "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)"
4030
+ ]);
4031
+ lbFactoryAbi = parseAbi12([
4032
+ "function getNumberOfLBPairs() external view returns (uint256)",
4033
+ "function getLBPairAtIndex(uint256 index) external view returns (address)"
4034
+ ]);
4035
+ lbPairAbi = parseAbi12([
4036
+ "function getLBHooksParameters() external view returns (bytes32)",
4037
+ "function getActiveId() external view returns (uint24)",
4038
+ "function getBinStep() external view returns (uint16)",
4039
+ "function getTokenX() external view returns (address)",
4040
+ "function getTokenY() external view returns (address)",
4041
+ "function balanceOf(address account, uint256 id) external view returns (uint256)",
4042
+ "function balanceOfBatch(address[] calldata accounts, uint256[] calldata ids) external view returns (uint256[] memory)"
4043
+ ]);
4044
+ lbRewarderAbi = parseAbi12([
4045
+ "function getRewardToken() external view returns (address)",
4046
+ "function getRewardedRange() external view returns (uint256 minBinId, uint256 maxBinId)",
4047
+ "function getPendingRewards(address user, uint256[] calldata ids) external view returns (uint256 pendingRewards)",
4048
+ "function claim(address user, uint256[] calldata ids) external",
4049
+ "function getPid() external view returns (uint256)",
4050
+ "function isStopped() external view returns (bool)",
4051
+ "function getLBPair() external view returns (address)",
4052
+ "function getMasterChef() external view returns (address)"
4053
+ ]);
4054
+ masterChefAbi = parseAbi12([
4055
+ "function getMoePerSecond() external view returns (uint256)",
4056
+ "function getTreasuryShare() external view returns (uint256)",
4057
+ "function getStaticShare() external view returns (uint256)",
4058
+ "function getVeMoe() external view returns (address)"
4059
+ ]);
4060
+ veMoeAbi = parseAbi12([
4061
+ "function getWeight(uint256 pid) external view returns (uint256)",
4062
+ "function getTotalWeight() external view returns (uint256)",
4063
+ "function getTopPoolIds() external view returns (uint256[] memory)"
4064
+ ]);
4065
+ lbPairBinAbi = parseAbi12([
4066
+ "function getBin(uint24 id) external view returns (uint128 reserveX, uint128 reserveY)",
4067
+ "function getActiveId() external view returns (uint24)"
4068
+ ]);
4069
+ lbQuoterAbi2 = parseAbi12([
4070
+ "function findBestPathFromAmountIn(address[] calldata route, uint128 amountIn) external view returns ((address[] route, address[] pairs, uint256[] binSteps, uint256[] versions, uint128[] amounts, uint128[] virtualAmountsWithoutSlippage, uint128[] fees))"
4071
+ ]);
4072
+ erc20Abi2 = parseAbi12([
4073
+ "function symbol() external view returns (string)"
4074
+ ]);
4075
+ _addressAbi = parseAbi12(["function f() external view returns (address)"]);
4076
+ _uint256Abi = parseAbi12(["function f() external view returns (uint256)"]);
4077
+ _boolAbi = parseAbi12(["function f() external view returns (bool)"]);
4078
+ _rangeAbi = parseAbi12(["function f() external view returns (uint256 minBinId, uint256 maxBinId)"]);
4079
+ _binAbi = parseAbi12(["function f() external view returns (uint128 reserveX, uint128 reserveY)"]);
4080
+ _uint256ArrayAbi = parseAbi12(["function f() external view returns (uint256[] memory)"]);
4081
+ MerchantMoeLBAdapter = class {
4082
+ protocolName;
4083
+ lbRouter;
4084
+ lbFactory;
4085
+ lbQuoter;
4086
+ rpcUrl;
4087
+ /** WMNT address (lb_mid_wmnt in config) used for MOE price routing */
4088
+ wmnt;
4089
+ /** USDT address (lb_mid_usdt in config) used for MNT/USD price routing */
4090
+ usdt;
4091
+ constructor(entry, rpcUrl) {
4092
+ this.protocolName = entry.name;
4093
+ const lbRouter = entry.contracts?.["lb_router"];
4094
+ if (!lbRouter) {
4095
+ throw new DefiError("CONTRACT_ERROR", "Missing 'lb_router' contract address");
4096
+ }
4097
+ const lbFactory = entry.contracts?.["lb_factory"];
4098
+ if (!lbFactory) {
4099
+ throw new DefiError("CONTRACT_ERROR", "Missing 'lb_factory' contract address");
4100
+ }
4101
+ this.lbRouter = lbRouter;
4102
+ this.lbFactory = lbFactory;
4103
+ this.lbQuoter = entry.contracts?.["lb_quoter"];
4104
+ this.wmnt = entry.contracts?.["lb_mid_wmnt"];
4105
+ this.usdt = entry.contracts?.["lb_mid_usdt"];
4106
+ this.rpcUrl = rpcUrl;
4107
+ }
4108
+ name() {
4109
+ return this.protocolName;
4110
+ }
4111
+ requireRpc() {
4112
+ if (!this.rpcUrl) {
4113
+ throw DefiError.rpcError(`[${this.protocolName}] RPC URL required`);
4114
+ }
4115
+ return this.rpcUrl;
4116
+ }
4117
+ /**
4118
+ * Build an addLiquidity transaction for a Liquidity Book pair.
4119
+ * Distributes tokenX/tokenY uniformly across active bin ± numBins.
4120
+ */
4121
+ async buildAddLiquidity(params) {
4122
+ const numBins = params.numBins ?? 5;
4123
+ const deadline = params.deadline ?? BigInt("18446744073709551615");
4124
+ let activeIdDesired = params.activeIdDesired;
4125
+ if (activeIdDesired === void 0) {
4126
+ const rpcUrl = this.requireRpc();
4127
+ const client = createPublicClient8({ transport: http8(rpcUrl) });
4128
+ const activeId = await client.readContract({
4129
+ address: params.pool,
4130
+ abi: lbPairAbi,
4131
+ functionName: "getActiveId"
4132
+ });
4133
+ activeIdDesired = activeId;
4134
+ }
4135
+ const deltaIds = [];
4136
+ for (let d = -numBins; d <= numBins; d++) {
4137
+ deltaIds.push(d);
4138
+ }
4139
+ const { distributionX, distributionY } = buildUniformDistribution(deltaIds);
4140
+ const data = encodeFunctionData12({
4141
+ abi: lbRouterAbi,
4142
+ functionName: "addLiquidity",
4143
+ args: [
4144
+ {
4145
+ tokenX: params.tokenX,
4146
+ tokenY: params.tokenY,
4147
+ binStep: BigInt(params.binStep),
4148
+ amountX: params.amountX,
4149
+ amountY: params.amountY,
4150
+ amountXMin: 0n,
4151
+ amountYMin: 0n,
4152
+ activeIdDesired: BigInt(activeIdDesired),
4153
+ idSlippage: BigInt(numBins + 2),
4154
+ deltaIds: deltaIds.map(BigInt),
4155
+ distributionX,
4156
+ distributionY,
4157
+ to: params.recipient,
4158
+ refundTo: params.recipient,
4159
+ deadline
4160
+ }
4161
+ ]
4162
+ });
4163
+ return {
4164
+ description: `[${this.protocolName}] LB addLiquidity ${params.amountX} tokenX + ${params.amountY} tokenY across ${deltaIds.length} bins`,
4165
+ to: this.lbRouter,
4166
+ data,
4167
+ value: 0n,
4168
+ gas_estimate: 8e5,
4169
+ approvals: [
4170
+ { token: params.tokenX, spender: this.lbRouter, amount: params.amountX },
4171
+ { token: params.tokenY, spender: this.lbRouter, amount: params.amountY }
4172
+ ]
4173
+ };
4174
+ }
4175
+ /**
4176
+ * Build a removeLiquidity transaction for specific LB bins.
4177
+ */
4178
+ async buildRemoveLiquidity(params) {
4179
+ const deadline = params.deadline ?? BigInt("18446744073709551615");
4180
+ const data = encodeFunctionData12({
4181
+ abi: lbRouterAbi,
4182
+ functionName: "removeLiquidity",
4183
+ args: [
4184
+ params.tokenX,
4185
+ params.tokenY,
4186
+ params.binStep,
4187
+ params.amountXMin ?? 0n,
4188
+ params.amountYMin ?? 0n,
4189
+ params.binIds.map(BigInt),
4190
+ params.amounts,
4191
+ params.recipient,
4192
+ deadline
4193
+ ]
4194
+ });
4195
+ return {
4196
+ description: `[${this.protocolName}] LB removeLiquidity from ${params.binIds.length} bins`,
4197
+ to: this.lbRouter,
4198
+ data,
4199
+ value: 0n,
4200
+ gas_estimate: 6e5
4201
+ };
4202
+ }
4203
+ /**
4204
+ * Auto-detect bin IDs for a pool from the rewarder's rewarded range.
4205
+ * Falls back to active bin ± 50 scan if no rewarder exists.
4206
+ */
4207
+ async autoDetectBins(pool) {
4208
+ const rpcUrl = this.requireRpc();
4209
+ const client = createPublicClient8({ transport: http8(rpcUrl) });
4210
+ const hooksParams = await client.readContract({
4211
+ address: pool,
4212
+ abi: lbPairAbi,
4213
+ functionName: "getLBHooksParameters"
4214
+ });
4215
+ const rewarder = extractRewarderAddress(hooksParams);
4216
+ if (rewarder) {
4217
+ const range = await client.readContract({
4218
+ address: rewarder,
4219
+ abi: lbRewarderAbi,
4220
+ functionName: "getRewardedRange"
4221
+ });
4222
+ const min = Number(range[0]);
4223
+ const max = Number(range[1]);
4224
+ const ids2 = [];
4225
+ for (let b = min; b <= max; b++) ids2.push(b);
4226
+ return ids2;
4227
+ }
4228
+ const activeId = await client.readContract({
4229
+ address: pool,
4230
+ abi: lbPairAbi,
4231
+ functionName: "getActiveId"
4232
+ });
4233
+ const ids = [];
4234
+ for (let b = activeId - 50; b <= activeId + 50; b++) ids.push(b);
4235
+ return ids;
4236
+ }
4237
+ /**
4238
+ * Get pending MOE rewards for a user across specified bin IDs.
4239
+ * If binIds is omitted, auto-detects from the rewarder's rewarded range.
4240
+ * Reads the rewarder address from the pool's hooks parameters.
4241
+ */
4242
+ async getPendingRewards(user, pool, binIds) {
4243
+ const rpcUrl = this.requireRpc();
4244
+ const client = createPublicClient8({ transport: http8(rpcUrl) });
4245
+ const hooksParams = await client.readContract({
4246
+ address: pool,
4247
+ abi: lbPairAbi,
4248
+ functionName: "getLBHooksParameters"
4249
+ });
4250
+ const rewarder = extractRewarderAddress(hooksParams);
4251
+ if (!rewarder) {
4252
+ return [];
4253
+ }
4254
+ let resolvedBinIds = binIds;
4255
+ if (!resolvedBinIds || resolvedBinIds.length === 0) {
4256
+ const range = await client.readContract({
4257
+ address: rewarder,
4258
+ abi: lbRewarderAbi,
4259
+ functionName: "getRewardedRange"
4260
+ });
4261
+ const min = Number(range[0]);
4262
+ const max = Number(range[1]);
4263
+ resolvedBinIds = [];
4264
+ for (let b = min; b <= max; b++) resolvedBinIds.push(b);
4265
+ }
4266
+ const [pending, rewardToken] = await Promise.all([
4267
+ client.readContract({
4268
+ address: rewarder,
4269
+ abi: lbRewarderAbi,
4270
+ functionName: "getPendingRewards",
4271
+ args: [user, resolvedBinIds.map(BigInt)]
4272
+ }),
4273
+ client.readContract({
4274
+ address: rewarder,
4275
+ abi: lbRewarderAbi,
4276
+ functionName: "getRewardToken"
4277
+ })
4278
+ ]);
4279
+ return [
4280
+ {
4281
+ token: rewardToken,
4282
+ symbol: "MOE",
4283
+ amount: pending
4284
+ }
4285
+ ];
4286
+ }
4287
+ /**
4288
+ * Build a claim rewards transaction for specific LB bins.
4289
+ * If binIds is omitted, auto-detects from the rewarder's rewarded range.
4290
+ */
4291
+ async buildClaimRewards(user, pool, binIds) {
4292
+ const rpcUrl = this.requireRpc();
4293
+ const client = createPublicClient8({ transport: http8(rpcUrl) });
4294
+ const hooksParams = await client.readContract({
4295
+ address: pool,
4296
+ abi: lbPairAbi,
4297
+ functionName: "getLBHooksParameters"
4298
+ });
4299
+ const rewarder = extractRewarderAddress(hooksParams);
4300
+ if (!rewarder) {
4301
+ throw new DefiError("CONTRACT_ERROR", `[${this.protocolName}] Pool ${pool} has no active rewarder`);
4302
+ }
4303
+ let resolvedBinIds = binIds;
4304
+ if (!resolvedBinIds || resolvedBinIds.length === 0) {
4305
+ const range = await client.readContract({
4306
+ address: rewarder,
4307
+ abi: lbRewarderAbi,
4308
+ functionName: "getRewardedRange"
4309
+ });
4310
+ const min = Number(range[0]);
4311
+ const max = Number(range[1]);
4312
+ resolvedBinIds = [];
4313
+ for (let b = min; b <= max; b++) resolvedBinIds.push(b);
4314
+ }
4315
+ const data = encodeFunctionData12({
4316
+ abi: lbRewarderAbi,
4317
+ functionName: "claim",
4318
+ args: [user, resolvedBinIds.map(BigInt)]
4319
+ });
4320
+ return {
4321
+ description: `[${this.protocolName}] LB claim rewards for ${resolvedBinIds.length} bins`,
4322
+ to: rewarder,
4323
+ data,
4324
+ value: 0n,
4325
+ gas_estimate: 3e5
4326
+ };
4327
+ }
4328
+ /**
4329
+ * Discover all active rewarded LB pools by iterating the factory.
4330
+ * Uses 7 multicall batches to minimise RPC round-trips and avoid 429s.
4331
+ *
4332
+ * Batch 1: getNumberOfLBPairs(), then getLBPairAtIndex(i) for all i
4333
+ * Batch 2: getLBHooksParameters() for all pairs → extract rewarder addresses
4334
+ * Batch 3: isStopped/getRewardedRange/getRewardToken/getPid/getMasterChef for each rewarder
4335
+ * Batch 4: getTokenX/getTokenY for each rewarded pair, then symbol() for unique tokens
4336
+ * Batch 5: Bootstrap MasterChef→VeMoe, then getMoePerSecond/getTreasuryShare/getStaticShare/getTotalWeight/getTopPoolIds
4337
+ * Batch 6: VeMoe.getWeight(pid) for each rewarded pool
4338
+ * Batch 7: Pool.getBin(binId) for all bins in rewarded range of each pool
4339
+ * Price: LB Quoter findBestPathFromAmountIn for MOE/WMNT and WMNT/USDT prices
4340
+ */
4341
+ async discoverRewardedPools() {
4342
+ const rpcUrl = this.requireRpc();
4343
+ const client = createPublicClient8({ transport: http8(rpcUrl) });
4344
+ const pairCount = await client.readContract({
4345
+ address: this.lbFactory,
4346
+ abi: lbFactoryAbi,
4347
+ functionName: "getNumberOfLBPairs"
4348
+ });
4349
+ const count = Number(pairCount);
4350
+ if (count === 0) return [];
4351
+ const batch1Calls = Array.from({ length: count }, (_, i) => [
4352
+ this.lbFactory,
4353
+ encodeFunctionData12({ abi: lbFactoryAbi, functionName: "getLBPairAtIndex", args: [BigInt(i)] })
4354
+ ]);
4355
+ const batch1Results = await multicallRead(rpcUrl, batch1Calls);
4356
+ const pairAddresses = batch1Results.map((r) => decodeAddressResult(r)).filter((a) => a !== null);
4357
+ if (pairAddresses.length === 0) return [];
4358
+ const batch2Calls = pairAddresses.map((pair) => [
4359
+ pair,
4360
+ encodeFunctionData12({ abi: lbPairAbi, functionName: "getLBHooksParameters" })
4361
+ ]);
4362
+ const batch2Results = await multicallRead(rpcUrl, batch2Calls);
4363
+ const rewardedPairs = [];
4364
+ for (let i = 0; i < pairAddresses.length; i++) {
4365
+ const raw = batch2Results[i];
4366
+ if (!raw) continue;
4367
+ let hooksBytes;
4368
+ try {
4369
+ const _bytes32Abi = parseAbi12(["function f() external view returns (bytes32)"]);
4370
+ hooksBytes = decodeFunctionResult4({ abi: _bytes32Abi, functionName: "f", data: raw });
4371
+ } catch {
4372
+ continue;
4373
+ }
4374
+ const rewarder = extractRewarderAddress(hooksBytes);
4375
+ if (rewarder) {
4376
+ rewardedPairs.push({ pool: pairAddresses[i], rewarder });
4377
+ }
4378
+ }
4379
+ if (rewardedPairs.length === 0) return [];
4380
+ const batch3Calls = [];
4381
+ for (const { rewarder } of rewardedPairs) {
4382
+ batch3Calls.push([rewarder, encodeFunctionData12({ abi: lbRewarderAbi, functionName: "isStopped" })]);
4383
+ batch3Calls.push([rewarder, encodeFunctionData12({ abi: lbRewarderAbi, functionName: "getRewardedRange" })]);
4384
+ batch3Calls.push([rewarder, encodeFunctionData12({ abi: lbRewarderAbi, functionName: "getRewardToken" })]);
4385
+ batch3Calls.push([rewarder, encodeFunctionData12({ abi: lbRewarderAbi, functionName: "getPid" })]);
4386
+ batch3Calls.push([rewarder, encodeFunctionData12({ abi: lbRewarderAbi, functionName: "getMasterChef" })]);
4387
+ }
4388
+ const batch3Results = await multicallRead(rpcUrl, batch3Calls);
4389
+ const batch4aCalls = [];
4390
+ for (const { pool } of rewardedPairs) {
4391
+ batch4aCalls.push([pool, encodeFunctionData12({ abi: lbPairAbi, functionName: "getTokenX" })]);
4392
+ batch4aCalls.push([pool, encodeFunctionData12({ abi: lbPairAbi, functionName: "getTokenY" })]);
4393
+ }
4394
+ const batch4aResults = await multicallRead(rpcUrl, batch4aCalls);
4395
+ const tokenXAddresses = [];
4396
+ const tokenYAddresses = [];
4397
+ for (let i = 0; i < rewardedPairs.length; i++) {
4398
+ tokenXAddresses.push(decodeAddressResult(batch4aResults[i * 2] ?? null));
4399
+ tokenYAddresses.push(decodeAddressResult(batch4aResults[i * 2 + 1] ?? null));
4400
+ }
4401
+ const uniqueTokens = Array.from(
4402
+ new Set([...tokenXAddresses, ...tokenYAddresses].filter((a) => a !== null))
4403
+ );
4404
+ const batch4bCalls = uniqueTokens.map((token) => [
4405
+ token,
4406
+ encodeFunctionData12({ abi: erc20Abi2, functionName: "symbol" })
4407
+ ]);
4408
+ const batch4bResults = await multicallRead(rpcUrl, batch4bCalls);
4409
+ const symbolMap = /* @__PURE__ */ new Map();
4410
+ for (let i = 0; i < uniqueTokens.length; i++) {
4411
+ symbolMap.set(uniqueTokens[i], decodeStringResult(batch4bResults[i] ?? null));
4412
+ }
4413
+ const STRIDE3 = 5;
4414
+ const poolData = [];
4415
+ for (let i = 0; i < rewardedPairs.length; i++) {
4416
+ const base = i * STRIDE3;
4417
+ poolData.push({
4418
+ stopped: decodeBoolResult(batch3Results[base] ?? null) ?? false,
4419
+ range: decodeRangeResult(batch3Results[base + 1] ?? null),
4420
+ rewardToken: decodeAddressResult(batch3Results[base + 2] ?? null),
4421
+ pid: Number(decodeUint256Result(batch3Results[base + 3] ?? null) ?? 0n),
4422
+ masterChef: decodeAddressResult(batch3Results[base + 4] ?? null)
4423
+ });
4424
+ }
4425
+ const masterChefAddr = poolData.map((d) => d.masterChef).find((a) => a !== null) ?? null;
4426
+ let moePerDay = 0;
4427
+ let topPoolIds = /* @__PURE__ */ new Set();
4428
+ let totalWeightRaw = 0n;
4429
+ let veMoeAddr = null;
4430
+ if (masterChefAddr) {
4431
+ veMoeAddr = await client.readContract({
4432
+ address: masterChefAddr,
4433
+ abi: masterChefAbi,
4434
+ functionName: "getVeMoe"
4435
+ });
4436
+ const batch5Calls = [
4437
+ [masterChefAddr, encodeFunctionData12({ abi: masterChefAbi, functionName: "getMoePerSecond" })],
4438
+ [masterChefAddr, encodeFunctionData12({ abi: masterChefAbi, functionName: "getTreasuryShare" })],
4439
+ [masterChefAddr, encodeFunctionData12({ abi: masterChefAbi, functionName: "getStaticShare" })],
4440
+ [veMoeAddr, encodeFunctionData12({ abi: veMoeAbi, functionName: "getTotalWeight" })],
4441
+ [veMoeAddr, encodeFunctionData12({ abi: veMoeAbi, functionName: "getTopPoolIds" })]
4442
+ ];
4443
+ const batch5Results = await multicallRead(rpcUrl, batch5Calls);
4444
+ const moePerSecRaw = decodeUint256Result(batch5Results[0] ?? null) ?? 0n;
4445
+ const treasuryShareRaw = decodeUint256Result(batch5Results[1] ?? null) ?? 0n;
4446
+ const staticShareRaw = decodeUint256Result(batch5Results[2] ?? null) ?? 0n;
4447
+ totalWeightRaw = decodeUint256Result(batch5Results[3] ?? null) ?? 0n;
4448
+ const topPoolIdsRaw = decodeUint256ArrayResult(batch5Results[4] ?? null) ?? [];
4449
+ topPoolIds = new Set(topPoolIdsRaw.map(Number));
4450
+ const PRECISION = 10n ** 18n;
4451
+ const netPerSec = moePerSecRaw * (PRECISION - treasuryShareRaw) / PRECISION * (PRECISION - staticShareRaw) / PRECISION;
4452
+ moePerDay = Number(netPerSec * 86400n) / 1e18;
4453
+ }
4454
+ const weightByPid = /* @__PURE__ */ new Map();
4455
+ if (veMoeAddr && rewardedPairs.length > 0) {
4456
+ const batch6Calls = poolData.map((d) => [
4457
+ veMoeAddr,
4458
+ encodeFunctionData12({ abi: veMoeAbi, functionName: "getWeight", args: [BigInt(d.pid)] })
4459
+ ]);
4460
+ const batch6Results = await multicallRead(rpcUrl, batch6Calls);
4461
+ for (let i = 0; i < poolData.length; i++) {
4462
+ weightByPid.set(poolData[i].pid, decodeUint256Result(batch6Results[i] ?? null) ?? 0n);
4463
+ }
4464
+ }
4465
+ let moePriceUsd = 0;
4466
+ let wmntPriceUsd = 0;
4467
+ const MOE_ADDR = "0x4515A45337F461A11Ff0FE8aBF3c606AE5dC00c9";
4468
+ if (this.lbQuoter && this.wmnt && this.usdt) {
4469
+ try {
4470
+ const [moeWmntQuote, wmntUsdtQuote] = await Promise.all([
4471
+ client.readContract({
4472
+ address: this.lbQuoter,
4473
+ abi: lbQuoterAbi2,
4474
+ functionName: "findBestPathFromAmountIn",
4475
+ args: [[MOE_ADDR, this.wmnt], 10n ** 18n]
4476
+ }),
4477
+ client.readContract({
4478
+ address: this.lbQuoter,
4479
+ abi: lbQuoterAbi2,
4480
+ functionName: "findBestPathFromAmountIn",
4481
+ args: [[this.wmnt, this.usdt], 10n ** 18n]
4482
+ })
4483
+ ]);
4484
+ const moeInWmnt = Number(moeWmntQuote.amounts.at(-1) ?? 0n) / 1e18;
4485
+ wmntPriceUsd = Number(wmntUsdtQuote.amounts.at(-1) ?? 0n) / 1e6;
4486
+ moePriceUsd = moeInWmnt * wmntPriceUsd;
4487
+ } catch {
4488
+ }
4489
+ }
4490
+ const binRequests = [];
4491
+ for (let i = 0; i < rewardedPairs.length; i++) {
4492
+ const range = poolData[i].range;
4493
+ if (!range) continue;
4494
+ const minBin = Number(range[0]);
4495
+ const maxBin = Number(range[1]);
4496
+ for (let b = minBin; b <= maxBin; b++) {
4497
+ binRequests.push({ poolIdx: i, binId: b });
4498
+ }
4499
+ }
4500
+ const binReservesX = /* @__PURE__ */ new Map();
4501
+ const binReservesY = /* @__PURE__ */ new Map();
4502
+ if (binRequests.length > 0) {
4503
+ const batch7Calls = binRequests.map(({ poolIdx, binId }) => [
4504
+ rewardedPairs[poolIdx].pool,
4505
+ encodeFunctionData12({ abi: lbPairBinAbi, functionName: "getBin", args: [binId] })
4506
+ ]);
4507
+ const batch7Results = await multicallRead(rpcUrl, batch7Calls);
4508
+ for (let j = 0; j < binRequests.length; j++) {
4509
+ const { poolIdx, binId } = binRequests[j];
4510
+ const decoded = decodeBinResult(batch7Results[j] ?? null);
4511
+ if (!decoded) continue;
4512
+ if (!binReservesX.has(poolIdx)) {
4513
+ binReservesX.set(poolIdx, /* @__PURE__ */ new Map());
4514
+ binReservesY.set(poolIdx, /* @__PURE__ */ new Map());
4515
+ }
4516
+ binReservesX.get(poolIdx).set(binId, decoded[0]);
4517
+ binReservesY.get(poolIdx).set(binId, decoded[1]);
4518
+ }
4519
+ }
4520
+ const stableSymbols = /* @__PURE__ */ new Set(["USDT", "USDC", "MUSD", "AUSD", "USDY", "FDUSD"]);
4521
+ const mntSymbols = /* @__PURE__ */ new Set(["WMNT", "MNT"]);
4522
+ const moeSymbols = /* @__PURE__ */ new Set(["MOE"]);
4523
+ const sixDecimalStables = /* @__PURE__ */ new Set(["USDT", "USDC", "FDUSD"]);
4524
+ const getTokenPriceUsd = (sym) => {
4525
+ if (stableSymbols.has(sym)) return 1;
4526
+ if (mntSymbols.has(sym)) return wmntPriceUsd;
4527
+ if (moeSymbols.has(sym)) return moePriceUsd;
4528
+ return 0;
4529
+ };
4530
+ const getTokenDecimals = (sym) => {
4531
+ return sixDecimalStables.has(sym) ? 6 : 18;
4532
+ };
4533
+ const results = [];
4534
+ for (let i = 0; i < rewardedPairs.length; i++) {
4535
+ const { pool, rewarder } = rewardedPairs[i];
4536
+ const data = poolData[i];
4537
+ const tokenX = tokenXAddresses[i] ?? "0x0000000000000000000000000000000000000000";
4538
+ const tokenY = tokenYAddresses[i] ?? "0x0000000000000000000000000000000000000000";
4539
+ const symX = symbolMap.get(tokenX) ?? "?";
4540
+ const symY = symbolMap.get(tokenY) ?? "?";
4541
+ const isTopPool = topPoolIds.has(data.pid);
4542
+ const weight = weightByPid.get(data.pid) ?? 0n;
4543
+ let poolMoePerDay = 0;
4544
+ if (isTopPool && totalWeightRaw > 0n && weight > 0n) {
4545
+ poolMoePerDay = moePerDay * (Number(weight) / Number(totalWeightRaw));
4546
+ }
4547
+ const rxMap = binReservesX.get(i);
4548
+ const ryMap = binReservesY.get(i);
4549
+ const range = data.range;
4550
+ let rangeTvlUsd = 0;
4551
+ let rewardedBins = 0;
4552
+ if (range) {
4553
+ const minBin = Number(range[0]);
4554
+ const maxBin = Number(range[1]);
4555
+ rewardedBins = maxBin - minBin + 1;
4556
+ if (rxMap && ryMap) {
4557
+ const priceX = getTokenPriceUsd(symX);
4558
+ const priceY = getTokenPriceUsd(symY);
4559
+ const decX = getTokenDecimals(symX);
4560
+ const decY = getTokenDecimals(symY);
4561
+ for (let b = minBin; b <= maxBin; b++) {
4562
+ const rx = rxMap.get(b) ?? 0n;
4563
+ const ry = ryMap.get(b) ?? 0n;
4564
+ rangeTvlUsd += Number(rx) / 10 ** decX * priceX;
4565
+ rangeTvlUsd += Number(ry) / 10 ** decY * priceY;
4566
+ }
4567
+ }
4568
+ }
4569
+ const aprPercent = rangeTvlUsd > 0 && moePriceUsd > 0 ? poolMoePerDay * moePriceUsd * 365 / rangeTvlUsd * 100 : 0;
4570
+ results.push({
4571
+ pool,
4572
+ rewarder,
4573
+ rewardToken: data.rewardToken ?? "0x0000000000000000000000000000000000000000",
4574
+ minBinId: range ? Number(range[0]) : 0,
4575
+ maxBinId: range ? Number(range[1]) : 0,
4576
+ pid: data.pid,
4577
+ stopped: data.stopped,
4578
+ tokenX,
4579
+ tokenY,
4580
+ symbolX: symX,
4581
+ symbolY: symY,
4582
+ isTopPool,
4583
+ moePerDay: poolMoePerDay,
4584
+ rangeTvlUsd,
4585
+ aprPercent,
4586
+ rewardedBins
4587
+ });
4588
+ }
4589
+ return results;
4590
+ }
4591
+ /**
4592
+ * Get a user's LB positions (bin balances) across a range of bin IDs.
4593
+ * If binIds is omitted, auto-detects from the rewarder's rewarded range (or active ± 50).
4594
+ */
4595
+ async getUserPositions(user, pool, binIds) {
4596
+ const rpcUrl = this.requireRpc();
4597
+ const client = createPublicClient8({ transport: http8(rpcUrl) });
4598
+ const resolvedBinIds = binIds && binIds.length > 0 ? binIds : await this.autoDetectBins(pool);
4599
+ const accounts = resolvedBinIds.map(() => user);
4600
+ const ids = resolvedBinIds.map(BigInt);
4601
+ const balances = await client.readContract({
4602
+ address: pool,
4603
+ abi: lbPairAbi,
4604
+ functionName: "balanceOfBatch",
4605
+ args: [accounts, ids]
4606
+ });
4607
+ return resolvedBinIds.map((binId, i) => ({ binId, balance: balances[i] ?? 0n })).filter((p) => p.balance > 0n);
4608
+ }
4609
+ };
4610
+ KITTEN_TOKEN = "0x618275f8efe54c2afa87bfb9f210a52f0ff89364";
4611
+ WHYPE_TOKEN = "0x5555555555555555555555555555555555555555";
4612
+ MAX_NONCE_SCAN = 60;
4613
+ HYPEREVM_TOKENS2 = [
4614
+ "0x5555555555555555555555555555555555555555",
4615
+ // WHYPE
4616
+ "0xb88339CB7199b77E23DB6E890353E22632Ba630f",
4617
+ // USDC
4618
+ "0xB8CE59FC3717ada4C02eaDF9682A9e934F625ebb",
4619
+ // USDT0
4620
+ "0xBe6727B535545C67d5cAa73dEa54865B92CF7907",
4621
+ // UETH
4622
+ "0x9FDBdA0A5e284c32744D2f17Ee5c74B284993463",
4623
+ // UBTC
4624
+ "0x111111a1a0667d36bD57c0A9f569b98057111111",
4625
+ // USDH
4626
+ "0x5d3a1Ff2b6BAb83b63cd9AD0787074081a52ef34",
4627
+ // USDe
4628
+ "0x211Cc4DD073734dA055fbF44a2b4667d5E5fE5d2",
4629
+ // sUSDe
4630
+ "0xf4D9235269a96aaDaFc9aDAe454a0618eBE37949",
4631
+ // XAUt0
4632
+ "0xfD739d4e423301CE9385c1fb8850539D657C296D",
4633
+ // kHYPE
4634
+ KITTEN_TOKEN
4635
+ // KITTEN
4636
+ ];
4637
+ farmingCenterAbi = parseAbi13([
4638
+ "function multicall(bytes[] calldata data) external payable returns (bytes[] memory results)",
4639
+ "function enterFarming((address rewardToken, address bonusRewardToken, address pool, uint256 nonce) key, uint256 tokenId) external",
4640
+ "function exitFarming((address rewardToken, address bonusRewardToken, address pool, uint256 nonce) key, uint256 tokenId) external",
4641
+ "function collectRewards((address rewardToken, address bonusRewardToken, address pool, uint256 nonce) key, uint256 tokenId) external",
4642
+ "function claimReward(address rewardToken, address to, uint128 amountRequested) external returns (uint256 reward)"
4643
+ ]);
4644
+ positionManagerAbi2 = parseAbi13([
4645
+ "function approveForFarming(uint256 tokenId, bool approve, address farmingAddress) external",
4646
+ "function farmingApprovals(uint256 tokenId) external view returns (address)"
4647
+ ]);
4648
+ eternalFarmingAbi = parseAbi13([
4649
+ "function incentives(bytes32 incentiveId) external view returns (uint256 totalReward, uint256 bonusReward, address virtualPoolAddress, uint24 minimalPositionWidth, bool deactivated, address pluginAddress)",
4650
+ "function getRewardInfo((address rewardToken, address bonusRewardToken, address pool, uint256 nonce) key, uint256 tokenId) external view returns (uint256 reward, uint256 bonusReward)"
4651
+ ]);
4652
+ algebraFactoryAbi = parseAbi13([
4653
+ "function poolByPair(address tokenA, address tokenB) external view returns (address pool)"
4654
+ ]);
4655
+ _addressDecodeAbi3 = parseAbi13(["function f() external view returns (address)"]);
4656
+ nonceCache = /* @__PURE__ */ new Map();
4657
+ KittenSwapFarmingAdapter = class {
4658
+ protocolName;
4659
+ farmingCenter;
4660
+ eternalFarming;
4661
+ positionManager;
4662
+ rpcUrl;
4663
+ factory;
4664
+ constructor(protocolName, farmingCenter, eternalFarming, positionManager, rpcUrl, factory) {
4665
+ this.protocolName = protocolName;
4666
+ this.farmingCenter = farmingCenter;
4667
+ this.eternalFarming = eternalFarming;
4668
+ this.positionManager = positionManager;
4669
+ this.rpcUrl = rpcUrl;
4670
+ this.factory = factory;
4671
+ }
4672
+ name() {
4673
+ return this.protocolName;
4674
+ }
4675
+ /**
4676
+ * Discover the active IncentiveKey for a given pool.
4677
+ * 1. Check runtime cache
4678
+ * 2. Batch-query nonces 0-60 via single multicall (61 calls)
4679
+ * 3. Return first non-zero incentive (totalReward > 0 and not deactivated)
4680
+ */
4681
+ async discoverIncentiveKey(pool) {
4682
+ const poolLc = pool.toLowerCase();
4683
+ if (nonceCache.has(poolLc)) {
4684
+ return {
4685
+ rewardToken: KITTEN_TOKEN,
4686
+ bonusRewardToken: WHYPE_TOKEN,
4687
+ pool,
4688
+ nonce: nonceCache.get(poolLc)
4689
+ };
4690
+ }
4691
+ const calls = [];
4692
+ const nonces = [];
4693
+ for (let n = 0; n <= MAX_NONCE_SCAN; n++) {
4694
+ const nonce = BigInt(n);
4695
+ nonces.push(nonce);
4696
+ const key = {
4697
+ rewardToken: KITTEN_TOKEN,
4698
+ bonusRewardToken: WHYPE_TOKEN,
4699
+ pool,
4700
+ nonce
4701
+ };
4702
+ calls.push([
4703
+ this.eternalFarming,
4704
+ encodeFunctionData13({
4705
+ abi: eternalFarmingAbi,
4706
+ functionName: "incentives",
4707
+ args: [incentiveId(key)]
4708
+ })
4709
+ ]);
4710
+ }
4711
+ const results = await multicallRead(this.rpcUrl, calls);
4712
+ for (let i = 0; i < results.length; i++) {
4713
+ const data = results[i];
4714
+ if (!data || data.length < 66) continue;
4715
+ try {
4716
+ const decoded = decodeAbiParameters5(
4717
+ [
4718
+ { name: "totalReward", type: "uint256" },
4719
+ { name: "bonusReward", type: "uint256" },
4720
+ { name: "virtualPoolAddress", type: "address" },
4721
+ { name: "minimalPositionWidth", type: "uint24" },
4722
+ { name: "deactivated", type: "bool" },
4723
+ { name: "pluginAddress", type: "address" }
4724
+ ],
4725
+ data
4726
+ );
4727
+ const totalReward = decoded[0];
4728
+ const deactivated = decoded[4];
4729
+ if (totalReward > 0n && !deactivated) {
4730
+ const nonce = nonces[i];
4731
+ nonceCache.set(poolLc, nonce);
4732
+ return {
4733
+ rewardToken: KITTEN_TOKEN,
4734
+ bonusRewardToken: WHYPE_TOKEN,
4735
+ pool,
4736
+ nonce
4737
+ };
4738
+ }
4739
+ } catch {
4740
+ }
4741
+ }
4742
+ return null;
4743
+ }
4744
+ /**
4745
+ * Build approveForFarming tx on the PositionManager.
4746
+ * Required before enterFarming if not already approved.
4747
+ */
4748
+ async buildApproveForFarming(tokenId) {
4749
+ const client = createPublicClient9({ transport: http9(this.rpcUrl) });
4750
+ const currentApproval = await client.readContract({
4751
+ address: this.positionManager,
4752
+ abi: positionManagerAbi2,
4753
+ functionName: "farmingApprovals",
4754
+ args: [tokenId]
4755
+ });
4756
+ if (currentApproval.toLowerCase() === this.farmingCenter.toLowerCase()) {
4757
+ return null;
4758
+ }
4759
+ return {
4760
+ description: `[${this.protocolName}] Approve NFT #${tokenId} for farming`,
4761
+ to: this.positionManager,
4762
+ data: encodeFunctionData13({
4763
+ abi: positionManagerAbi2,
4764
+ functionName: "approveForFarming",
4765
+ args: [tokenId, true, this.farmingCenter]
4766
+ }),
4767
+ value: 0n,
4768
+ gas_estimate: 6e4
4769
+ };
4770
+ }
4771
+ /**
4772
+ * Build enterFarming tx for a position NFT.
4773
+ * Checks farming approval first and returns pre_txs if needed.
4774
+ */
4775
+ async buildEnterFarming(tokenId, pool, _owner) {
4776
+ const key = await this.discoverIncentiveKey(pool);
4777
+ if (!key) {
4778
+ throw new DefiError(
4779
+ "CONTRACT_ERROR",
4780
+ `[${this.protocolName}] No active incentive found for pool ${pool}`
4781
+ );
4782
+ }
4783
+ const approveTx = await this.buildApproveForFarming(tokenId);
4784
+ return {
4785
+ description: `[${this.protocolName}] Enter farming for NFT #${tokenId} in pool ${pool}`,
4786
+ to: this.farmingCenter,
4787
+ data: encodeEnterFarming(key, tokenId),
4788
+ value: 0n,
4789
+ gas_estimate: 4e5,
4790
+ pre_txs: approveTx ? [approveTx] : void 0
4791
+ };
4792
+ }
4793
+ /**
4794
+ * Build a tx that exits farming for a position NFT (unstakes).
4795
+ */
4796
+ async buildExitFarming(tokenId, pool) {
4797
+ const key = await this.discoverIncentiveKey(pool);
4798
+ if (!key) {
4799
+ throw new DefiError(
4800
+ "CONTRACT_ERROR",
4801
+ `[${this.protocolName}] No active incentive found for pool ${pool}`
4802
+ );
4803
+ }
4804
+ return {
4805
+ description: `[${this.protocolName}] Exit farming for NFT #${tokenId} in pool ${pool}`,
4806
+ to: this.farmingCenter,
4807
+ data: encodeExitFarming(key, tokenId),
4808
+ value: 0n,
4809
+ gas_estimate: 3e5
4810
+ };
4811
+ }
4812
+ /**
4813
+ * Build a multicall tx that collects rewards for a staked position and claims them.
4814
+ * Pattern: multicall([collectRewards(key, tokenId), claimReward(KITTEN, owner, max), claimReward(WHYPE, owner, max)])
4815
+ */
4816
+ async buildCollectRewards(tokenId, pool, owner) {
4817
+ const key = await this.discoverIncentiveKey(pool);
4818
+ if (!key) {
4819
+ throw new DefiError(
4820
+ "CONTRACT_ERROR",
4821
+ `[${this.protocolName}] No active incentive found for pool ${pool}`
4822
+ );
4823
+ }
4824
+ const calls = [
4825
+ encodeCollectRewards(key, tokenId),
4826
+ encodeClaimReward(KITTEN_TOKEN, owner),
4827
+ encodeClaimReward(WHYPE_TOKEN, owner)
4828
+ ];
2781
4829
  return {
2782
- description: `[${this.protocolName}] Claim MOE rewards for farm pid=${pid} (pool ${gauge})`,
2783
- to: this.masterchef,
2784
- data,
4830
+ description: `[${this.protocolName}] Collect + claim rewards for NFT #${tokenId} in pool ${pool}`,
4831
+ to: this.farmingCenter,
4832
+ data: encodeMulticall(calls),
2785
4833
  value: 0n,
2786
- gas_estimate: 2e5
4834
+ gas_estimate: 4e5
2787
4835
  };
2788
4836
  }
2789
- /** Claim pending MOE rewards for a specific pid (MasterChef extension beyond IGauge). */
2790
- async buildClaimRewardsPid(pid) {
2791
- const data = encodeFunctionData9({
2792
- abi: masterchefAbi,
2793
- functionName: "claim",
2794
- args: [[pid]]
2795
- });
4837
+ /**
4838
+ * Build a tx that only claims already-accumulated rewards (no position change needed).
4839
+ */
4840
+ async buildClaimReward(owner) {
4841
+ const calls = [
4842
+ encodeClaimReward(KITTEN_TOKEN, owner),
4843
+ encodeClaimReward(WHYPE_TOKEN, owner)
4844
+ ];
2796
4845
  return {
2797
- description: `[${this.protocolName}] Claim MOE rewards for farm pid=${pid}`,
2798
- to: this.masterchef,
2799
- data,
4846
+ description: `[${this.protocolName}] Claim KITTEN + WHYPE farming rewards to ${owner}`,
4847
+ to: this.farmingCenter,
4848
+ data: encodeMulticall(calls),
2800
4849
  value: 0n,
2801
4850
  gas_estimate: 2e5
2802
4851
  };
2803
4852
  }
2804
- /** Get pending MOE rewards for a user. Requires rpcUrl. */
2805
- async getPendingRewards(_gauge, user) {
2806
- if (!this.rpcUrl) {
2807
- throw DefiError.unsupported(`[${this.protocolName}] getPendingRewards requires RPC`);
4853
+ /**
4854
+ * Query pending rewards for a staked position NFT.
4855
+ */
4856
+ async getPendingRewards(tokenId, pool) {
4857
+ const key = await this.discoverIncentiveKey(pool);
4858
+ if (!key) {
4859
+ return { reward: 0n, bonusReward: 0n };
2808
4860
  }
2809
- const client = createPublicClient6({ transport: http6(this.rpcUrl) });
2810
- const rewards = await client.readContract({
2811
- address: this.masterchef,
2812
- abi: masterchefAbi,
2813
- functionName: "pendingRewards",
2814
- args: [user, [0n]]
4861
+ const client = createPublicClient9({ transport: http9(this.rpcUrl) });
4862
+ const result = await client.readContract({
4863
+ address: this.eternalFarming,
4864
+ abi: eternalFarmingAbi,
4865
+ functionName: "getRewardInfo",
4866
+ args: [key, tokenId]
2815
4867
  });
2816
- return rewards.map((amount) => ({
2817
- token: this.masterchef,
2818
- symbol: "MOE",
2819
- amount
2820
- }));
4868
+ return { reward: result[0], bonusReward: result[1] };
4869
+ }
4870
+ /**
4871
+ * Discover all KittenSwap pools with active farming incentives.
4872
+ *
4873
+ * Steps:
4874
+ * 1. Generate all unique token pair combos from HYPEREVM_TOKENS (includes KITTEN)
4875
+ * 2. Batch poolByPair calls via multicall against the Algebra factory
4876
+ * 3. For each found pool, batch-scan nonces 0-60 via multicall
4877
+ * 4. Return enriched FarmingPool[] for pools with active incentives
4878
+ */
4879
+ async discoverFarmingPools() {
4880
+ if (!this.factory) {
4881
+ return [];
4882
+ }
4883
+ const pairs = [];
4884
+ for (let i = 0; i < HYPEREVM_TOKENS2.length; i++) {
4885
+ for (let j = i + 1; j < HYPEREVM_TOKENS2.length; j++) {
4886
+ pairs.push([HYPEREVM_TOKENS2[i], HYPEREVM_TOKENS2[j]]);
4887
+ }
4888
+ }
4889
+ const poolByPairCalls = pairs.map(([tokenA, tokenB]) => [
4890
+ this.factory,
4891
+ encodeFunctionData13({
4892
+ abi: algebraFactoryAbi,
4893
+ functionName: "poolByPair",
4894
+ args: [tokenA, tokenB]
4895
+ })
4896
+ ]);
4897
+ const poolResults = await multicallRead(this.rpcUrl, poolByPairCalls);
4898
+ const poolSet = /* @__PURE__ */ new Set();
4899
+ for (const data of poolResults) {
4900
+ const addr = decodeAddress3(data);
4901
+ if (addr && addr !== zeroAddress7) {
4902
+ poolSet.add(addr.toLowerCase());
4903
+ }
4904
+ }
4905
+ if (poolSet.size === 0) return [];
4906
+ const pools = Array.from(poolSet);
4907
+ const NONCE_COUNT = MAX_NONCE_SCAN + 1;
4908
+ const allNonceCalls = [];
4909
+ for (const pool of pools) {
4910
+ for (let n = 0; n <= MAX_NONCE_SCAN; n++) {
4911
+ const key = {
4912
+ rewardToken: KITTEN_TOKEN,
4913
+ bonusRewardToken: WHYPE_TOKEN,
4914
+ pool,
4915
+ nonce: BigInt(n)
4916
+ };
4917
+ allNonceCalls.push([
4918
+ this.eternalFarming,
4919
+ encodeFunctionData13({
4920
+ abi: eternalFarmingAbi,
4921
+ functionName: "incentives",
4922
+ args: [incentiveId(key)]
4923
+ })
4924
+ ]);
4925
+ }
4926
+ }
4927
+ const allNonceResults = await multicallRead(this.rpcUrl, allNonceCalls);
4928
+ const results = [];
4929
+ for (let pi = 0; pi < pools.length; pi++) {
4930
+ const pool = pools[pi];
4931
+ const poolLc = pool.toLowerCase();
4932
+ const base = pi * NONCE_COUNT;
4933
+ let bestKey = null;
4934
+ let bestTotalReward = 0n;
4935
+ let bestBonusReward = 0n;
4936
+ let bestActive = false;
4937
+ for (let n = 0; n <= MAX_NONCE_SCAN; n++) {
4938
+ const data = allNonceResults[base + n];
4939
+ if (!data || data.length < 66) continue;
4940
+ try {
4941
+ const decoded = decodeAbiParameters5(
4942
+ [
4943
+ { name: "totalReward", type: "uint256" },
4944
+ { name: "bonusReward", type: "uint256" },
4945
+ { name: "virtualPoolAddress", type: "address" },
4946
+ { name: "minimalPositionWidth", type: "uint24" },
4947
+ { name: "deactivated", type: "bool" },
4948
+ { name: "pluginAddress", type: "address" }
4949
+ ],
4950
+ data
4951
+ );
4952
+ const totalReward = decoded[0];
4953
+ const bonusReward = decoded[1];
4954
+ const deactivated = decoded[4];
4955
+ if (totalReward > 0n) {
4956
+ const nonce = BigInt(n);
4957
+ const isActive = !deactivated;
4958
+ if (!bestKey || isActive && !bestActive || isActive === bestActive && nonce > bestKey.nonce) {
4959
+ bestKey = {
4960
+ rewardToken: KITTEN_TOKEN,
4961
+ bonusRewardToken: WHYPE_TOKEN,
4962
+ pool,
4963
+ nonce
4964
+ };
4965
+ bestTotalReward = totalReward;
4966
+ bestBonusReward = bonusReward;
4967
+ bestActive = isActive;
4968
+ }
4969
+ }
4970
+ } catch {
4971
+ }
4972
+ }
4973
+ if (bestKey) {
4974
+ nonceCache.set(poolLc, bestKey.nonce);
4975
+ results.push({
4976
+ pool,
4977
+ key: bestKey,
4978
+ totalReward: bestTotalReward,
4979
+ bonusReward: bestBonusReward,
4980
+ active: bestActive
4981
+ });
4982
+ }
4983
+ }
4984
+ return results;
2821
4985
  }
2822
4986
  };
2823
- POOL_ABI = parseAbi10([
4987
+ POOL_ABI = parseAbi14([
2824
4988
  "function supply(address asset, uint256 amount, address onBehalfOf, uint16 referralCode) external",
2825
4989
  "function borrow(address asset, uint256 amount, uint256 interestRateMode, uint16 referralCode, address onBehalfOf) external",
2826
4990
  "function repay(address asset, uint256 amount, uint256 interestRateMode, address onBehalfOf) external returns (uint256)",
@@ -2828,27 +4992,27 @@ var init_dist3 = __esm({
2828
4992
  "function getUserAccountData(address user) external view returns (uint256 totalCollateralBase, uint256 totalDebtBase, uint256 availableBorrowsBase, uint256 currentLiquidationThreshold, uint256 ltv, uint256 healthFactor)",
2829
4993
  "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)"
2830
4994
  ]);
2831
- ERC20_ABI = parseAbi10([
4995
+ ERC20_ABI = parseAbi14([
2832
4996
  "function totalSupply() external view returns (uint256)"
2833
4997
  ]);
2834
- INCENTIVES_ABI = parseAbi10([
4998
+ INCENTIVES_ABI = parseAbi14([
2835
4999
  "function getIncentivesController() external view returns (address)"
2836
5000
  ]);
2837
- REWARDS_CONTROLLER_ABI = parseAbi10([
5001
+ REWARDS_CONTROLLER_ABI = parseAbi14([
2838
5002
  "function getRewardsByAsset(address asset) external view returns (address[])",
2839
5003
  "function getRewardsData(address asset, address reward) external view returns (uint256 index, uint256 emissionsPerSecond, uint256 lastUpdateTimestamp, uint256 distributionEnd)"
2840
5004
  ]);
2841
- POOL_PROVIDER_ABI = parseAbi10([
5005
+ POOL_PROVIDER_ABI = parseAbi14([
2842
5006
  "function ADDRESSES_PROVIDER() external view returns (address)"
2843
5007
  ]);
2844
- ADDRESSES_PROVIDER_ABI = parseAbi10([
5008
+ ADDRESSES_PROVIDER_ABI = parseAbi14([
2845
5009
  "function getPriceOracle() external view returns (address)"
2846
5010
  ]);
2847
- ORACLE_ABI = parseAbi10([
5011
+ ORACLE_ABI = parseAbi14([
2848
5012
  "function getAssetPrice(address asset) external view returns (uint256)",
2849
5013
  "function BASE_CURRENCY_UNIT() external view returns (uint256)"
2850
5014
  ]);
2851
- ERC20_DECIMALS_ABI = parseAbi10([
5015
+ ERC20_DECIMALS_ABI = parseAbi14([
2852
5016
  "function decimals() external view returns (uint8)"
2853
5017
  ]);
2854
5018
  AaveV3Adapter = class {
@@ -2866,7 +5030,7 @@ var init_dist3 = __esm({
2866
5030
  return this.protocolName;
2867
5031
  }
2868
5032
  async buildSupply(params) {
2869
- const data = encodeFunctionData10({
5033
+ const data = encodeFunctionData14({
2870
5034
  abi: POOL_ABI,
2871
5035
  functionName: "supply",
2872
5036
  args: [params.asset, params.amount, params.on_behalf_of, 0]
@@ -2882,7 +5046,7 @@ var init_dist3 = __esm({
2882
5046
  }
2883
5047
  async buildBorrow(params) {
2884
5048
  const rateMode = params.interest_rate_mode === InterestRateMode.Stable ? 1n : 2n;
2885
- const data = encodeFunctionData10({
5049
+ const data = encodeFunctionData14({
2886
5050
  abi: POOL_ABI,
2887
5051
  functionName: "borrow",
2888
5052
  args: [params.asset, params.amount, rateMode, 0, params.on_behalf_of]
@@ -2897,7 +5061,7 @@ var init_dist3 = __esm({
2897
5061
  }
2898
5062
  async buildRepay(params) {
2899
5063
  const rateMode = params.interest_rate_mode === InterestRateMode.Stable ? 1n : 2n;
2900
- const data = encodeFunctionData10({
5064
+ const data = encodeFunctionData14({
2901
5065
  abi: POOL_ABI,
2902
5066
  functionName: "repay",
2903
5067
  args: [params.asset, params.amount, rateMode, params.on_behalf_of]
@@ -2912,7 +5076,7 @@ var init_dist3 = __esm({
2912
5076
  };
2913
5077
  }
2914
5078
  async buildWithdraw(params) {
2915
- const data = encodeFunctionData10({
5079
+ const data = encodeFunctionData14({
2916
5080
  abi: POOL_ABI,
2917
5081
  functionName: "withdraw",
2918
5082
  args: [params.asset, params.amount, params.to]
@@ -2927,15 +5091,21 @@ var init_dist3 = __esm({
2927
5091
  }
2928
5092
  async getRates(asset) {
2929
5093
  if (!this.rpcUrl) throw DefiError.rpcError("No RPC URL configured");
2930
- const client = createPublicClient7({ transport: http7(this.rpcUrl) });
2931
- const result = await client.readContract({
2932
- address: this.pool,
5094
+ const reserveCallData = encodeFunctionData14({
2933
5095
  abi: POOL_ABI,
2934
5096
  functionName: "getReserveData",
2935
5097
  args: [asset]
2936
- }).catch((e) => {
5098
+ });
5099
+ const [reserveRaw] = await multicallRead(this.rpcUrl, [
5100
+ [this.pool, reserveCallData]
5101
+ ]).catch((e) => {
2937
5102
  throw DefiError.rpcError(`[${this.protocolName}] getReserveData failed: ${e}`);
2938
5103
  });
5104
+ const reserveDecoded = decodeReserveData(reserveRaw ?? null);
5105
+ if (!reserveDecoded) {
5106
+ throw DefiError.rpcError(`[${this.protocolName}] getReserveData returned no data`);
5107
+ }
5108
+ const result = reserveDecoded;
2939
5109
  const RAY = 1e27;
2940
5110
  const SECONDS_PER_YEAR4 = 31536e3;
2941
5111
  const toApy = (rayRate) => {
@@ -2947,74 +5117,56 @@ var init_dist3 = __esm({
2947
5117
  const stableRate = toApy(result[5]);
2948
5118
  const aTokenAddress = result[8];
2949
5119
  const variableDebtTokenAddress = result[10];
2950
- const [totalSupply, totalBorrow] = await Promise.all([
2951
- client.readContract({
2952
- address: aTokenAddress,
2953
- abi: ERC20_ABI,
2954
- functionName: "totalSupply"
2955
- }).catch(() => 0n),
2956
- client.readContract({
2957
- address: variableDebtTokenAddress,
2958
- abi: ERC20_ABI,
2959
- functionName: "totalSupply"
2960
- }).catch(() => 0n)
5120
+ const [supplyRaw, borrowRaw] = await multicallRead(this.rpcUrl, [
5121
+ [aTokenAddress, encodeFunctionData14({ abi: ERC20_ABI, functionName: "totalSupply" })],
5122
+ [variableDebtTokenAddress, encodeFunctionData14({ abi: ERC20_ABI, functionName: "totalSupply" })]
2961
5123
  ]);
5124
+ const totalSupply = decodeU256(supplyRaw ?? null);
5125
+ const totalBorrow = decodeU256(borrowRaw ?? null);
2962
5126
  const utilization = totalSupply > 0n ? Number(totalBorrow * 10000n / totalSupply) / 100 : 0;
2963
5127
  const supplyRewardTokens = [];
2964
5128
  const borrowRewardTokens = [];
2965
5129
  const supplyEmissions = [];
2966
5130
  const borrowEmissions = [];
2967
5131
  try {
2968
- const controllerAddr = await client.readContract({
2969
- address: aTokenAddress,
2970
- abi: INCENTIVES_ABI,
2971
- functionName: "getIncentivesController"
2972
- });
2973
- if (controllerAddr && controllerAddr !== zeroAddress5) {
2974
- const [supplyRewards, borrowRewards] = await Promise.all([
2975
- client.readContract({
2976
- address: controllerAddr,
2977
- abi: REWARDS_CONTROLLER_ABI,
2978
- functionName: "getRewardsByAsset",
2979
- args: [aTokenAddress]
2980
- }).catch(() => []),
2981
- client.readContract({
2982
- address: controllerAddr,
2983
- abi: REWARDS_CONTROLLER_ABI,
2984
- functionName: "getRewardsByAsset",
2985
- args: [variableDebtTokenAddress]
2986
- }).catch(() => [])
5132
+ const [controllerRaw] = await multicallRead(this.rpcUrl, [
5133
+ [aTokenAddress, encodeFunctionData14({ abi: INCENTIVES_ABI, functionName: "getIncentivesController" })]
5134
+ ]);
5135
+ const controllerAddr = decodeAddress4(controllerRaw ?? null);
5136
+ if (controllerAddr && controllerAddr !== zeroAddress8) {
5137
+ const [supplyRewardsRaw, borrowRewardsRaw] = await multicallRead(this.rpcUrl, [
5138
+ [controllerAddr, encodeFunctionData14({ abi: REWARDS_CONTROLLER_ABI, functionName: "getRewardsByAsset", args: [aTokenAddress] })],
5139
+ [controllerAddr, encodeFunctionData14({ abi: REWARDS_CONTROLLER_ABI, functionName: "getRewardsByAsset", args: [variableDebtTokenAddress] })]
2987
5140
  ]);
2988
- const supplyDataPromises = supplyRewards.map(
2989
- (reward) => client.readContract({
2990
- address: controllerAddr,
2991
- abi: REWARDS_CONTROLLER_ABI,
2992
- functionName: "getRewardsData",
2993
- args: [aTokenAddress, reward]
2994
- }).catch(() => null)
2995
- );
2996
- const supplyData = await Promise.all(supplyDataPromises);
2997
- for (let i = 0; i < supplyRewards.length; i++) {
2998
- const data = supplyData[i];
2999
- if (data && data[1] > 0n) {
3000
- supplyRewardTokens.push(supplyRewards[i]);
3001
- supplyEmissions.push(data[1].toString());
5141
+ const supplyRewards = decodeAddressArray(supplyRewardsRaw ?? null);
5142
+ const borrowRewards = decodeAddressArray(borrowRewardsRaw ?? null);
5143
+ const rewardsDataCalls = [
5144
+ ...supplyRewards.map((reward) => [
5145
+ controllerAddr,
5146
+ encodeFunctionData14({ abi: REWARDS_CONTROLLER_ABI, functionName: "getRewardsData", args: [aTokenAddress, reward] })
5147
+ ]),
5148
+ ...borrowRewards.map((reward) => [
5149
+ controllerAddr,
5150
+ encodeFunctionData14({ abi: REWARDS_CONTROLLER_ABI, functionName: "getRewardsData", args: [variableDebtTokenAddress, reward] })
5151
+ ])
5152
+ ];
5153
+ if (rewardsDataCalls.length > 0) {
5154
+ const rewardsDataResults = await multicallRead(this.rpcUrl, rewardsDataCalls);
5155
+ const supplyDataResults = rewardsDataResults.slice(0, supplyRewards.length);
5156
+ const borrowDataResults = rewardsDataResults.slice(supplyRewards.length);
5157
+ for (let i = 0; i < supplyRewards.length; i++) {
5158
+ const data = decodeRewardsData(supplyDataResults[i] ?? null);
5159
+ if (data && data[1] > 0n) {
5160
+ supplyRewardTokens.push(supplyRewards[i]);
5161
+ supplyEmissions.push(data[1].toString());
5162
+ }
3002
5163
  }
3003
- }
3004
- const borrowDataPromises = borrowRewards.map(
3005
- (reward) => client.readContract({
3006
- address: controllerAddr,
3007
- abi: REWARDS_CONTROLLER_ABI,
3008
- functionName: "getRewardsData",
3009
- args: [variableDebtTokenAddress, reward]
3010
- }).catch(() => null)
3011
- );
3012
- const borrowData = await Promise.all(borrowDataPromises);
3013
- for (let i = 0; i < borrowRewards.length; i++) {
3014
- const data = borrowData[i];
3015
- if (data && data[1] > 0n) {
3016
- borrowRewardTokens.push(borrowRewards[i]);
3017
- borrowEmissions.push(data[1].toString());
5164
+ for (let i = 0; i < borrowRewards.length; i++) {
5165
+ const data = decodeRewardsData(borrowDataResults[i] ?? null);
5166
+ if (data && data[1] > 0n) {
5167
+ borrowRewardTokens.push(borrowRewards[i]);
5168
+ borrowEmissions.push(data[1].toString());
5169
+ }
3018
5170
  }
3019
5171
  }
3020
5172
  }
@@ -3026,55 +5178,49 @@ var init_dist3 = __esm({
3026
5178
  const hasBorrowRewards = borrowRewardTokens.length > 0;
3027
5179
  if ((hasSupplyRewards || hasBorrowRewards) && totalSupply > 0n) {
3028
5180
  try {
3029
- const providerAddr = await client.readContract({
3030
- address: this.pool,
3031
- abi: POOL_PROVIDER_ABI,
3032
- functionName: "ADDRESSES_PROVIDER"
3033
- });
3034
- const oracleAddr = await client.readContract({
3035
- address: providerAddr,
3036
- abi: ADDRESSES_PROVIDER_ABI,
3037
- functionName: "getPriceOracle"
3038
- });
3039
- const [assetPrice, baseCurrencyUnit, assetDecimals] = await Promise.all([
3040
- client.readContract({
3041
- address: oracleAddr,
3042
- abi: ORACLE_ABI,
3043
- functionName: "getAssetPrice",
3044
- args: [asset]
3045
- }),
3046
- client.readContract({
3047
- address: oracleAddr,
3048
- abi: ORACLE_ABI,
3049
- functionName: "BASE_CURRENCY_UNIT"
3050
- }),
3051
- client.readContract({
3052
- address: asset,
3053
- abi: ERC20_DECIMALS_ABI,
3054
- functionName: "decimals"
3055
- }).catch(() => 18)
5181
+ const [providerRaw] = await multicallRead(this.rpcUrl, [
5182
+ [this.pool, encodeFunctionData14({ abi: POOL_PROVIDER_ABI, functionName: "ADDRESSES_PROVIDER" })]
5183
+ ]);
5184
+ const providerAddr = decodeAddress4(providerRaw ?? null);
5185
+ if (!providerAddr) throw new Error("No provider address");
5186
+ const [oracleRaw] = await multicallRead(this.rpcUrl, [
5187
+ [providerAddr, encodeFunctionData14({ abi: ADDRESSES_PROVIDER_ABI, functionName: "getPriceOracle" })]
5188
+ ]);
5189
+ const oracleAddr = decodeAddress4(oracleRaw ?? null);
5190
+ if (!oracleAddr) throw new Error("No oracle address");
5191
+ const [assetPriceRaw, baseCurrencyUnitRaw, assetDecimalsRaw] = await multicallRead(this.rpcUrl, [
5192
+ [oracleAddr, encodeFunctionData14({ abi: ORACLE_ABI, functionName: "getAssetPrice", args: [asset] })],
5193
+ [oracleAddr, encodeFunctionData14({ abi: ORACLE_ABI, functionName: "BASE_CURRENCY_UNIT" })],
5194
+ [asset, encodeFunctionData14({ abi: ERC20_DECIMALS_ABI, functionName: "decimals" })]
3056
5195
  ]);
3057
- const priceUnit = Number(baseCurrencyUnit);
5196
+ const assetPrice = decodeU256(assetPriceRaw ?? null);
5197
+ const baseCurrencyUnit = decodeU256(baseCurrencyUnitRaw ?? null);
5198
+ const assetDecimals = assetDecimalsRaw ? Number(decodeU256(assetDecimalsRaw)) : 18;
5199
+ const priceUnit = Number(baseCurrencyUnit) || 1e8;
3058
5200
  const assetPriceF = Number(assetPrice) / priceUnit;
3059
5201
  const assetDecimalsDivisor = 10 ** assetDecimals;
5202
+ const allRewardTokens = Array.from(/* @__PURE__ */ new Set([...supplyRewardTokens, ...borrowRewardTokens]));
5203
+ const rewardPriceCalls = allRewardTokens.flatMap((token) => [
5204
+ [oracleAddr, encodeFunctionData14({ abi: ORACLE_ABI, functionName: "getAssetPrice", args: [token] })],
5205
+ [token, encodeFunctionData14({ abi: ERC20_DECIMALS_ABI, functionName: "decimals" })]
5206
+ ]);
5207
+ const rewardPriceResults = rewardPriceCalls.length > 0 ? await multicallRead(this.rpcUrl, rewardPriceCalls) : [];
5208
+ const rewardPriceMap = /* @__PURE__ */ new Map();
5209
+ for (let i = 0; i < allRewardTokens.length; i++) {
5210
+ const priceRaw = rewardPriceResults[i * 2] ?? null;
5211
+ const decimalsRaw = rewardPriceResults[i * 2 + 1] ?? null;
5212
+ const price = decodeU256(priceRaw);
5213
+ const decimals = decimalsRaw ? Number(decodeU256(decimalsRaw)) : 18;
5214
+ rewardPriceMap.set(allRewardTokens[i].toLowerCase(), { price, decimals });
5215
+ }
3060
5216
  if (hasSupplyRewards) {
3061
5217
  let totalSupplyIncentiveUsdPerYear = 0;
3062
5218
  const totalSupplyUsd = Number(totalSupply) / assetDecimalsDivisor * assetPriceF;
3063
5219
  for (let i = 0; i < supplyRewardTokens.length; i++) {
3064
5220
  const emissionPerSec = BigInt(supplyEmissions[i]);
3065
- const [rewardPrice, rewardDecimals] = await Promise.all([
3066
- client.readContract({
3067
- address: oracleAddr,
3068
- abi: ORACLE_ABI,
3069
- functionName: "getAssetPrice",
3070
- args: [supplyRewardTokens[i]]
3071
- }).catch(() => 0n),
3072
- client.readContract({
3073
- address: supplyRewardTokens[i],
3074
- abi: ERC20_DECIMALS_ABI,
3075
- functionName: "decimals"
3076
- }).catch(() => 18)
3077
- ]);
5221
+ const entry = rewardPriceMap.get(supplyRewardTokens[i].toLowerCase());
5222
+ const rewardPrice = entry?.price ?? 0n;
5223
+ const rewardDecimals = entry?.decimals ?? 18;
3078
5224
  if (rewardPrice > 0n) {
3079
5225
  const rewardPriceF = Number(rewardPrice) / priceUnit;
3080
5226
  const emissionPerYear = Number(emissionPerSec) / 10 ** rewardDecimals * SECONDS_PER_YEAR4;
@@ -3090,19 +5236,9 @@ var init_dist3 = __esm({
3090
5236
  const totalBorrowUsd = Number(totalBorrow) / assetDecimalsDivisor * assetPriceF;
3091
5237
  for (let i = 0; i < borrowRewardTokens.length; i++) {
3092
5238
  const emissionPerSec = BigInt(borrowEmissions[i]);
3093
- const [rewardPrice, rewardDecimals] = await Promise.all([
3094
- client.readContract({
3095
- address: oracleAddr,
3096
- abi: ORACLE_ABI,
3097
- functionName: "getAssetPrice",
3098
- args: [borrowRewardTokens[i]]
3099
- }).catch(() => 0n),
3100
- client.readContract({
3101
- address: borrowRewardTokens[i],
3102
- abi: ERC20_DECIMALS_ABI,
3103
- functionName: "decimals"
3104
- }).catch(() => 18)
3105
- ]);
5239
+ const entry = rewardPriceMap.get(borrowRewardTokens[i].toLowerCase());
5240
+ const rewardPrice = entry?.price ?? 0n;
5241
+ const rewardDecimals = entry?.decimals ?? 18;
3106
5242
  if (rewardPrice > 0n) {
3107
5243
  const rewardPriceF = Number(rewardPrice) / priceUnit;
3108
5244
  const emissionPerYear = Number(emissionPerSec) / 10 ** rewardDecimals * SECONDS_PER_YEAR4;
@@ -3139,7 +5275,7 @@ var init_dist3 = __esm({
3139
5275
  }
3140
5276
  async getUserPosition(user) {
3141
5277
  if (!this.rpcUrl) throw DefiError.rpcError("No RPC URL configured");
3142
- const client = createPublicClient7({ transport: http7(this.rpcUrl) });
5278
+ const client = createPublicClient10({ transport: http10(this.rpcUrl) });
3143
5279
  const result = await client.readContract({
3144
5280
  address: this.pool,
3145
5281
  abi: POOL_ABI,
@@ -3154,8 +5290,8 @@ var init_dist3 = __esm({
3154
5290
  const collateralUsd = u256ToF64(totalCollateralBase) / 1e8;
3155
5291
  const debtUsd = u256ToF64(totalDebtBase) / 1e8;
3156
5292
  const ltvBps = u256ToF64(ltv);
3157
- const supplies = collateralUsd > 0 ? [{ asset: zeroAddress5, symbol: "Total Collateral", amount: totalCollateralBase, value_usd: collateralUsd }] : [];
3158
- const borrows = debtUsd > 0 ? [{ asset: zeroAddress5, symbol: "Total Debt", amount: totalDebtBase, value_usd: debtUsd }] : [];
5293
+ const supplies = collateralUsd > 0 ? [{ asset: zeroAddress8, symbol: "Total Collateral", amount: totalCollateralBase, value_usd: collateralUsd }] : [];
5294
+ const borrows = debtUsd > 0 ? [{ asset: zeroAddress8, symbol: "Total Debt", amount: totalDebtBase, value_usd: debtUsd }] : [];
3159
5295
  return {
3160
5296
  protocol: this.protocolName,
3161
5297
  user,
@@ -3166,7 +5302,7 @@ var init_dist3 = __esm({
3166
5302
  };
3167
5303
  }
3168
5304
  };
3169
- POOL_ABI2 = parseAbi11([
5305
+ POOL_ABI2 = parseAbi15([
3170
5306
  "function deposit(address asset, uint256 amount, address onBehalfOf, uint16 referralCode) external",
3171
5307
  "function borrow(address asset, uint256 amount, uint256 interestRateMode, uint16 referralCode, address onBehalfOf) external",
3172
5308
  "function repay(address asset, uint256 amount, uint256 rateMode, address onBehalfOf) external returns (uint256)",
@@ -3179,7 +5315,7 @@ var init_dist3 = __esm({
3179
5315
  // [9]=variableDebtTokenAddress, [10]=interestRateStrategyAddress, [11]=id
3180
5316
  "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)"
3181
5317
  ]);
3182
- ERC20_ABI2 = parseAbi11([
5318
+ ERC20_ABI2 = parseAbi15([
3183
5319
  "function totalSupply() external view returns (uint256)"
3184
5320
  ]);
3185
5321
  AaveV2Adapter = class {
@@ -3197,7 +5333,7 @@ var init_dist3 = __esm({
3197
5333
  return this.protocolName;
3198
5334
  }
3199
5335
  async buildSupply(params) {
3200
- const data = encodeFunctionData11({
5336
+ const data = encodeFunctionData15({
3201
5337
  abi: POOL_ABI2,
3202
5338
  functionName: "deposit",
3203
5339
  args: [params.asset, params.amount, params.on_behalf_of, 0]
@@ -3213,7 +5349,7 @@ var init_dist3 = __esm({
3213
5349
  }
3214
5350
  async buildBorrow(params) {
3215
5351
  const rateMode = params.interest_rate_mode === InterestRateMode.Stable ? 1n : 2n;
3216
- const data = encodeFunctionData11({
5352
+ const data = encodeFunctionData15({
3217
5353
  abi: POOL_ABI2,
3218
5354
  functionName: "borrow",
3219
5355
  args: [params.asset, params.amount, rateMode, 0, params.on_behalf_of]
@@ -3228,7 +5364,7 @@ var init_dist3 = __esm({
3228
5364
  }
3229
5365
  async buildRepay(params) {
3230
5366
  const rateMode = params.interest_rate_mode === InterestRateMode.Stable ? 1n : 2n;
3231
- const data = encodeFunctionData11({
5367
+ const data = encodeFunctionData15({
3232
5368
  abi: POOL_ABI2,
3233
5369
  functionName: "repay",
3234
5370
  args: [params.asset, params.amount, rateMode, params.on_behalf_of]
@@ -3243,7 +5379,7 @@ var init_dist3 = __esm({
3243
5379
  };
3244
5380
  }
3245
5381
  async buildWithdraw(params) {
3246
- const data = encodeFunctionData11({
5382
+ const data = encodeFunctionData15({
3247
5383
  abi: POOL_ABI2,
3248
5384
  functionName: "withdraw",
3249
5385
  args: [params.asset, params.amount, params.to]
@@ -3258,7 +5394,7 @@ var init_dist3 = __esm({
3258
5394
  }
3259
5395
  async getRates(asset) {
3260
5396
  if (!this.rpcUrl) throw DefiError.rpcError("No RPC URL configured");
3261
- const client = createPublicClient8({ transport: http8(this.rpcUrl) });
5397
+ const client = createPublicClient11({ transport: http11(this.rpcUrl) });
3262
5398
  const result = await client.readContract({
3263
5399
  address: this.pool,
3264
5400
  abi: POOL_ABI2,
@@ -3304,7 +5440,7 @@ var init_dist3 = __esm({
3304
5440
  }
3305
5441
  async getUserPosition(user) {
3306
5442
  if (!this.rpcUrl) throw DefiError.rpcError("No RPC URL configured");
3307
- const client = createPublicClient8({ transport: http8(this.rpcUrl) });
5443
+ const client = createPublicClient11({ transport: http11(this.rpcUrl) });
3308
5444
  const result = await client.readContract({
3309
5445
  address: this.pool,
3310
5446
  abi: POOL_ABI2,
@@ -3319,8 +5455,8 @@ var init_dist3 = __esm({
3319
5455
  const collateralUsd = u256ToF642(totalCollateralBase) / 1e18;
3320
5456
  const debtUsd = u256ToF642(totalDebtBase) / 1e18;
3321
5457
  const ltvBps = u256ToF642(ltv);
3322
- const supplies = collateralUsd > 0 ? [{ asset: zeroAddress6, symbol: "Total Collateral", amount: totalCollateralBase, value_usd: collateralUsd }] : [];
3323
- const borrows = debtUsd > 0 ? [{ asset: zeroAddress6, symbol: "Total Debt", amount: totalDebtBase, value_usd: debtUsd }] : [];
5458
+ const supplies = collateralUsd > 0 ? [{ asset: zeroAddress9, symbol: "Total Collateral", amount: totalCollateralBase, value_usd: collateralUsd }] : [];
5459
+ const borrows = debtUsd > 0 ? [{ asset: zeroAddress9, symbol: "Total Debt", amount: totalDebtBase, value_usd: debtUsd }] : [];
3324
5460
  return {
3325
5461
  protocol: this.protocolName,
3326
5462
  user,
@@ -3331,7 +5467,7 @@ var init_dist3 = __esm({
3331
5467
  };
3332
5468
  }
3333
5469
  };
3334
- ORACLE_ABI2 = parseAbi12([
5470
+ ORACLE_ABI2 = parseAbi16([
3335
5471
  "function getAssetPrice(address asset) external view returns (uint256)",
3336
5472
  "function getAssetsPrices(address[] calldata assets) external view returns (uint256[] memory)",
3337
5473
  "function BASE_CURRENCY_UNIT() external view returns (uint256)"
@@ -3352,7 +5488,7 @@ var init_dist3 = __esm({
3352
5488
  return this.protocolName;
3353
5489
  }
3354
5490
  async getPrice(asset) {
3355
- const client = createPublicClient9({ transport: http9(this.rpcUrl) });
5491
+ const client = createPublicClient12({ transport: http12(this.rpcUrl) });
3356
5492
  const baseUnit = await client.readContract({
3357
5493
  address: this.oracle,
3358
5494
  abi: ORACLE_ABI2,
@@ -3379,7 +5515,7 @@ var init_dist3 = __esm({
3379
5515
  };
3380
5516
  }
3381
5517
  async getPrices(assets) {
3382
- const client = createPublicClient9({ transport: http9(this.rpcUrl) });
5518
+ const client = createPublicClient12({ transport: http12(this.rpcUrl) });
3383
5519
  const baseUnit = await client.readContract({
3384
5520
  address: this.oracle,
3385
5521
  abi: ORACLE_ABI2,
@@ -3408,7 +5544,7 @@ var init_dist3 = __esm({
3408
5544
  });
3409
5545
  }
3410
5546
  };
3411
- CTOKEN_ABI = parseAbi13([
5547
+ CTOKEN_ABI = parseAbi17([
3412
5548
  "function supplyRatePerBlock() external view returns (uint256)",
3413
5549
  "function borrowRatePerBlock() external view returns (uint256)",
3414
5550
  "function totalSupply() external view returns (uint256)",
@@ -3435,7 +5571,7 @@ var init_dist3 = __esm({
3435
5571
  return this.protocolName;
3436
5572
  }
3437
5573
  async buildSupply(params) {
3438
- const data = encodeFunctionData12({
5574
+ const data = encodeFunctionData16({
3439
5575
  abi: CTOKEN_ABI,
3440
5576
  functionName: "mint",
3441
5577
  args: [params.amount]
@@ -3449,7 +5585,7 @@ var init_dist3 = __esm({
3449
5585
  };
3450
5586
  }
3451
5587
  async buildBorrow(params) {
3452
- const data = encodeFunctionData12({
5588
+ const data = encodeFunctionData16({
3453
5589
  abi: CTOKEN_ABI,
3454
5590
  functionName: "borrow",
3455
5591
  args: [params.amount]
@@ -3463,7 +5599,7 @@ var init_dist3 = __esm({
3463
5599
  };
3464
5600
  }
3465
5601
  async buildRepay(params) {
3466
- const data = encodeFunctionData12({
5602
+ const data = encodeFunctionData16({
3467
5603
  abi: CTOKEN_ABI,
3468
5604
  functionName: "repayBorrow",
3469
5605
  args: [params.amount]
@@ -3477,7 +5613,7 @@ var init_dist3 = __esm({
3477
5613
  };
3478
5614
  }
3479
5615
  async buildWithdraw(params) {
3480
- const data = encodeFunctionData12({
5616
+ const data = encodeFunctionData16({
3481
5617
  abi: CTOKEN_ABI,
3482
5618
  functionName: "redeem",
3483
5619
  args: [params.amount]
@@ -3492,7 +5628,7 @@ var init_dist3 = __esm({
3492
5628
  }
3493
5629
  async getRates(asset) {
3494
5630
  if (!this.rpcUrl) throw DefiError.rpcError("No RPC URL configured");
3495
- const client = createPublicClient10({ transport: http10(this.rpcUrl) });
5631
+ const client = createPublicClient13({ transport: http13(this.rpcUrl) });
3496
5632
  const [supplyRate, borrowRate, totalSupply, totalBorrows] = await Promise.all([
3497
5633
  client.readContract({ address: this.defaultVtoken, abi: CTOKEN_ABI, functionName: "supplyRatePerBlock" }).catch((e) => {
3498
5634
  throw DefiError.rpcError(`[${this.protocolName}] supplyRatePerBlock failed: ${e}`);
@@ -3526,7 +5662,7 @@ var init_dist3 = __esm({
3526
5662
  );
3527
5663
  }
3528
5664
  };
3529
- COMET_ABI = parseAbi14([
5665
+ COMET_ABI = parseAbi18([
3530
5666
  "function getUtilization() external view returns (uint256)",
3531
5667
  "function getSupplyRate(uint256 utilization) external view returns (uint64)",
3532
5668
  "function getBorrowRate(uint256 utilization) external view returns (uint64)",
@@ -3552,7 +5688,7 @@ var init_dist3 = __esm({
3552
5688
  return this.protocolName;
3553
5689
  }
3554
5690
  async buildSupply(params) {
3555
- const data = encodeFunctionData13({
5691
+ const data = encodeFunctionData17({
3556
5692
  abi: COMET_ABI,
3557
5693
  functionName: "supply",
3558
5694
  args: [params.asset, params.amount]
@@ -3566,7 +5702,7 @@ var init_dist3 = __esm({
3566
5702
  };
3567
5703
  }
3568
5704
  async buildBorrow(params) {
3569
- const data = encodeFunctionData13({
5705
+ const data = encodeFunctionData17({
3570
5706
  abi: COMET_ABI,
3571
5707
  functionName: "withdraw",
3572
5708
  args: [params.asset, params.amount]
@@ -3580,7 +5716,7 @@ var init_dist3 = __esm({
3580
5716
  };
3581
5717
  }
3582
5718
  async buildRepay(params) {
3583
- const data = encodeFunctionData13({
5719
+ const data = encodeFunctionData17({
3584
5720
  abi: COMET_ABI,
3585
5721
  functionName: "supply",
3586
5722
  args: [params.asset, params.amount]
@@ -3594,7 +5730,7 @@ var init_dist3 = __esm({
3594
5730
  };
3595
5731
  }
3596
5732
  async buildWithdraw(params) {
3597
- const data = encodeFunctionData13({
5733
+ const data = encodeFunctionData17({
3598
5734
  abi: COMET_ABI,
3599
5735
  functionName: "withdraw",
3600
5736
  args: [params.asset, params.amount]
@@ -3609,7 +5745,7 @@ var init_dist3 = __esm({
3609
5745
  }
3610
5746
  async getRates(asset) {
3611
5747
  if (!this.rpcUrl) throw DefiError.rpcError("No RPC URL configured");
3612
- const client = createPublicClient11({ transport: http11(this.rpcUrl) });
5748
+ const client = createPublicClient14({ transport: http14(this.rpcUrl) });
3613
5749
  const utilization = await client.readContract({
3614
5750
  address: this.comet,
3615
5751
  abi: COMET_ABI,
@@ -3648,7 +5784,7 @@ var init_dist3 = __esm({
3648
5784
  );
3649
5785
  }
3650
5786
  };
3651
- EULER_VAULT_ABI = parseAbi15([
5787
+ EULER_VAULT_ABI = parseAbi19([
3652
5788
  "function deposit(uint256 amount, address receiver) external returns (uint256)",
3653
5789
  "function withdraw(uint256 amount, address receiver, address owner) external returns (uint256)",
3654
5790
  "function borrow(uint256 amount, address receiver) external returns (uint256)",
@@ -3674,7 +5810,7 @@ var init_dist3 = __esm({
3674
5810
  return this.protocolName;
3675
5811
  }
3676
5812
  async buildSupply(params) {
3677
- const data = encodeFunctionData14({
5813
+ const data = encodeFunctionData18({
3678
5814
  abi: EULER_VAULT_ABI,
3679
5815
  functionName: "deposit",
3680
5816
  args: [params.amount, params.on_behalf_of]
@@ -3688,7 +5824,7 @@ var init_dist3 = __esm({
3688
5824
  };
3689
5825
  }
3690
5826
  async buildBorrow(params) {
3691
- const data = encodeFunctionData14({
5827
+ const data = encodeFunctionData18({
3692
5828
  abi: EULER_VAULT_ABI,
3693
5829
  functionName: "borrow",
3694
5830
  args: [params.amount, params.on_behalf_of]
@@ -3702,7 +5838,7 @@ var init_dist3 = __esm({
3702
5838
  };
3703
5839
  }
3704
5840
  async buildRepay(params) {
3705
- const data = encodeFunctionData14({
5841
+ const data = encodeFunctionData18({
3706
5842
  abi: EULER_VAULT_ABI,
3707
5843
  functionName: "repay",
3708
5844
  args: [params.amount, params.on_behalf_of]
@@ -3716,7 +5852,7 @@ var init_dist3 = __esm({
3716
5852
  };
3717
5853
  }
3718
5854
  async buildWithdraw(params) {
3719
- const data = encodeFunctionData14({
5855
+ const data = encodeFunctionData18({
3720
5856
  abi: EULER_VAULT_ABI,
3721
5857
  functionName: "withdraw",
3722
5858
  args: [params.amount, params.to, params.to]
@@ -3731,7 +5867,7 @@ var init_dist3 = __esm({
3731
5867
  }
3732
5868
  async getRates(asset) {
3733
5869
  if (!this.rpcUrl) throw DefiError.rpcError("No RPC URL configured");
3734
- const client = createPublicClient12({ transport: http12(this.rpcUrl) });
5870
+ const client = createPublicClient15({ transport: http15(this.rpcUrl) });
3735
5871
  const [totalSupply, totalBorrows, interestRate] = await Promise.all([
3736
5872
  client.readContract({ address: this.euler, abi: EULER_VAULT_ABI, functionName: "totalSupply" }).catch((e) => {
3737
5873
  throw DefiError.rpcError(`[${this.protocolName}] totalSupply failed: ${e}`);
@@ -3765,7 +5901,7 @@ var init_dist3 = __esm({
3765
5901
  );
3766
5902
  }
3767
5903
  };
3768
- MORPHO_ABI = parseAbi16([
5904
+ MORPHO_ABI = parseAbi20([
3769
5905
  "function market(bytes32 id) external view returns (uint128 totalSupplyAssets, uint128 totalSupplyShares, uint128 totalBorrowAssets, uint128 totalBorrowShares, uint128 lastUpdate, uint128 fee)",
3770
5906
  "function idToMarketParams(bytes32 id) external view returns (address loanToken, address collateralToken, address oracle, address irm, uint256 lltv)",
3771
5907
  "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)",
@@ -3773,13 +5909,13 @@ var init_dist3 = __esm({
3773
5909
  "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)",
3774
5910
  "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)"
3775
5911
  ]);
3776
- META_MORPHO_ABI = parseAbi16([
5912
+ META_MORPHO_ABI = parseAbi20([
3777
5913
  "function supplyQueueLength() external view returns (uint256)",
3778
5914
  "function supplyQueue(uint256 index) external view returns (bytes32)",
3779
5915
  "function totalAssets() external view returns (uint256)",
3780
5916
  "function totalSupply() external view returns (uint256)"
3781
5917
  ]);
3782
- IRM_ABI = parseAbi16([
5918
+ IRM_ABI = parseAbi20([
3783
5919
  "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)"
3784
5920
  ]);
3785
5921
  SECONDS_PER_YEAR3 = 365.25 * 24 * 3600;
@@ -3802,7 +5938,7 @@ var init_dist3 = __esm({
3802
5938
  }
3803
5939
  async buildSupply(params) {
3804
5940
  const market = defaultMarketParams(params.asset);
3805
- const data = encodeFunctionData15({
5941
+ const data = encodeFunctionData19({
3806
5942
  abi: MORPHO_ABI,
3807
5943
  functionName: "supply",
3808
5944
  args: [market, params.amount, 0n, params.on_behalf_of, "0x"]
@@ -3817,7 +5953,7 @@ var init_dist3 = __esm({
3817
5953
  }
3818
5954
  async buildBorrow(params) {
3819
5955
  const market = defaultMarketParams(params.asset);
3820
- const data = encodeFunctionData15({
5956
+ const data = encodeFunctionData19({
3821
5957
  abi: MORPHO_ABI,
3822
5958
  functionName: "borrow",
3823
5959
  args: [market, params.amount, 0n, params.on_behalf_of, params.on_behalf_of]
@@ -3832,7 +5968,7 @@ var init_dist3 = __esm({
3832
5968
  }
3833
5969
  async buildRepay(params) {
3834
5970
  const market = defaultMarketParams(params.asset);
3835
- const data = encodeFunctionData15({
5971
+ const data = encodeFunctionData19({
3836
5972
  abi: MORPHO_ABI,
3837
5973
  functionName: "repay",
3838
5974
  args: [market, params.amount, 0n, params.on_behalf_of, "0x"]
@@ -3847,7 +5983,7 @@ var init_dist3 = __esm({
3847
5983
  }
3848
5984
  async buildWithdraw(params) {
3849
5985
  const market = defaultMarketParams(params.asset);
3850
- const data = encodeFunctionData15({
5986
+ const data = encodeFunctionData19({
3851
5987
  abi: MORPHO_ABI,
3852
5988
  functionName: "withdraw",
3853
5989
  args: [market, params.amount, 0n, params.to, params.to]
@@ -3865,14 +6001,12 @@ var init_dist3 = __esm({
3865
6001
  if (!this.defaultVault) {
3866
6002
  throw DefiError.contractError(`[${this.protocolName}] No MetaMorpho vault configured for rate query`);
3867
6003
  }
3868
- const client = createPublicClient13({ transport: http13(this.rpcUrl) });
3869
- const queueLen = await client.readContract({
3870
- address: this.defaultVault,
3871
- abi: META_MORPHO_ABI,
3872
- functionName: "supplyQueueLength"
3873
- }).catch((e) => {
6004
+ const [queueLenRaw] = await multicallRead(this.rpcUrl, [
6005
+ [this.defaultVault, encodeFunctionData19({ abi: META_MORPHO_ABI, functionName: "supplyQueueLength" })]
6006
+ ]).catch((e) => {
3874
6007
  throw DefiError.rpcError(`[${this.protocolName}] supplyQueueLength failed: ${e}`);
3875
6008
  });
6009
+ const queueLen = decodeU256(queueLenRaw ?? null);
3876
6010
  if (queueLen === 0n) {
3877
6011
  return {
3878
6012
  protocol: this.protocolName,
@@ -3884,45 +6018,40 @@ var init_dist3 = __esm({
3884
6018
  total_borrow: 0n
3885
6019
  };
3886
6020
  }
3887
- const marketId = await client.readContract({
3888
- address: this.defaultVault,
3889
- abi: META_MORPHO_ABI,
3890
- functionName: "supplyQueue",
3891
- args: [0n]
3892
- }).catch((e) => {
6021
+ const [marketIdRaw] = await multicallRead(this.rpcUrl, [
6022
+ [this.defaultVault, encodeFunctionData19({ abi: META_MORPHO_ABI, functionName: "supplyQueue", args: [0n] })]
6023
+ ]).catch((e) => {
3893
6024
  throw DefiError.rpcError(`[${this.protocolName}] supplyQueue(0) failed: ${e}`);
3894
6025
  });
3895
- const mkt = await client.readContract({
3896
- address: this.morpho,
3897
- abi: MORPHO_ABI,
3898
- functionName: "market",
3899
- args: [marketId]
3900
- }).catch((e) => {
3901
- throw DefiError.rpcError(`[${this.protocolName}] market() failed: ${e}`);
6026
+ if (!marketIdRaw || marketIdRaw.length < 66) {
6027
+ throw DefiError.rpcError(`[${this.protocolName}] supplyQueue(0) returned no data`);
6028
+ }
6029
+ const marketId = marketIdRaw.slice(0, 66);
6030
+ const [marketRaw, paramsRaw] = await multicallRead(this.rpcUrl, [
6031
+ [this.morpho, encodeFunctionData19({ abi: MORPHO_ABI, functionName: "market", args: [marketId] })],
6032
+ [this.morpho, encodeFunctionData19({ abi: MORPHO_ABI, functionName: "idToMarketParams", args: [marketId] })]
6033
+ ]).catch((e) => {
6034
+ throw DefiError.rpcError(`[${this.protocolName}] market/idToMarketParams failed: ${e}`);
3902
6035
  });
3903
- const [totalSupplyAssets, totalSupplyShares, totalBorrowAssets, totalBorrowShares, lastUpdate, fee] = mkt;
6036
+ const mktDecoded = decodeMarket(marketRaw ?? null);
6037
+ if (!mktDecoded) throw DefiError.rpcError(`[${this.protocolName}] market() returned no data`);
6038
+ const [totalSupplyAssets, totalSupplyShares, totalBorrowAssets, totalBorrowShares, lastUpdate, fee] = mktDecoded;
6039
+ const paramsDecoded = decodeMarketParams(paramsRaw ?? null);
6040
+ if (!paramsDecoded) throw DefiError.rpcError(`[${this.protocolName}] idToMarketParams returned no data`);
6041
+ const [loanToken, collateralToken, oracle, irm, lltv] = paramsDecoded;
3904
6042
  const supplyF = Number(totalSupplyAssets);
3905
6043
  const borrowF = Number(totalBorrowAssets);
3906
6044
  const util = supplyF > 0 ? borrowF / supplyF : 0;
3907
- const params2 = await client.readContract({
3908
- address: this.morpho,
3909
- abi: MORPHO_ABI,
3910
- functionName: "idToMarketParams",
3911
- args: [marketId]
3912
- }).catch((e) => {
3913
- throw DefiError.rpcError(`[${this.protocolName}] idToMarketParams failed: ${e}`);
3914
- });
3915
- const [loanToken, collateralToken, oracle, irm, lltv] = params2;
3916
6045
  const irmMarketParams = { loanToken, collateralToken, oracle, irm, lltv };
3917
6046
  const irmMarket = { totalSupplyAssets, totalSupplyShares, totalBorrowAssets, totalBorrowShares, lastUpdate, fee };
3918
- const borrowRatePerSec = await client.readContract({
3919
- address: irm,
3920
- abi: IRM_ABI,
3921
- functionName: "borrowRateView",
3922
- args: [irmMarketParams, irmMarket]
3923
- }).catch((e) => {
3924
- throw DefiError.rpcError(`[${this.protocolName}] borrowRateView failed: ${e}`);
3925
- });
6047
+ const borrowRatePerSec = await (async () => {
6048
+ const [borrowRateRaw] = await multicallRead(this.rpcUrl, [
6049
+ [irm, encodeFunctionData19({ abi: IRM_ABI, functionName: "borrowRateView", args: [irmMarketParams, irmMarket] })]
6050
+ ]).catch((e) => {
6051
+ throw DefiError.rpcError(`[${this.protocolName}] borrowRateView failed: ${e}`);
6052
+ });
6053
+ return decodeU256(borrowRateRaw ?? null);
6054
+ })();
3926
6055
  const ratePerSec = Number(borrowRatePerSec) / 1e18;
3927
6056
  const borrowApy = ratePerSec * SECONDS_PER_YEAR3 * 100;
3928
6057
  const feePct = Number(fee) / 1e18;
@@ -3943,18 +6072,18 @@ var init_dist3 = __esm({
3943
6072
  );
3944
6073
  }
3945
6074
  };
3946
- BORROWER_OPS_ABI = parseAbi17([
6075
+ BORROWER_OPS_ABI = parseAbi21([
3947
6076
  "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)",
3948
6077
  "function adjustTrove(uint256 _troveId, uint256 _collChange, bool _isCollIncrease, uint256 _debtChange, bool _isDebtIncrease, uint256 _upperHint, uint256 _lowerHint, uint256 _maxUpfrontFee) external",
3949
6078
  "function closeTrove(uint256 _troveId) external"
3950
6079
  ]);
3951
- TROVE_MANAGER_ABI = parseAbi17([
6080
+ TROVE_MANAGER_ABI = parseAbi21([
3952
6081
  "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)"
3953
6082
  ]);
3954
- HINT_HELPERS_ABI = parseAbi17([
6083
+ HINT_HELPERS_ABI = parseAbi21([
3955
6084
  "function getApproxHint(uint256 _collIndex, uint256 _interestRate, uint256 _numTrials, uint256 _inputRandomSeed) external view returns (uint256 hintId, uint256 diff, uint256 latestRandomSeed)"
3956
6085
  ]);
3957
- SORTED_TROVES_ABI = parseAbi17([
6086
+ SORTED_TROVES_ABI = parseAbi21([
3958
6087
  "function findInsertPosition(uint256 _annualInterestRate, uint256 _prevId, uint256 _nextId) external view returns (uint256 prevId, uint256 nextId)"
3959
6088
  ]);
3960
6089
  FelixCdpAdapter = class {
@@ -3982,7 +6111,7 @@ var init_dist3 = __esm({
3982
6111
  if (!this.hintHelpers || !this.sortedTroves || !this.rpcUrl) {
3983
6112
  return [0n, 0n];
3984
6113
  }
3985
- const client = createPublicClient14({ transport: http14(this.rpcUrl) });
6114
+ const client = createPublicClient16({ transport: http16(this.rpcUrl) });
3986
6115
  const approxResult = await client.readContract({
3987
6116
  address: this.hintHelpers,
3988
6117
  abi: HINT_HELPERS_ABI,
@@ -4005,7 +6134,7 @@ var init_dist3 = __esm({
4005
6134
  const interestRate = 50000000000000000n;
4006
6135
  const [upperHint, lowerHint] = await this.getHints(interestRate);
4007
6136
  const hasHints = upperHint !== 0n || lowerHint !== 0n;
4008
- const data = encodeFunctionData16({
6137
+ const data = encodeFunctionData20({
4009
6138
  abi: BORROWER_OPS_ABI,
4010
6139
  functionName: "openTrove",
4011
6140
  args: [
@@ -4034,7 +6163,7 @@ var init_dist3 = __esm({
4034
6163
  async buildAdjust(params) {
4035
6164
  const collChange = params.collateral_delta ?? 0n;
4036
6165
  const debtChange = params.debt_delta ?? 0n;
4037
- const data = encodeFunctionData16({
6166
+ const data = encodeFunctionData20({
4038
6167
  abi: BORROWER_OPS_ABI,
4039
6168
  functionName: "adjustTrove",
4040
6169
  args: [
@@ -4057,7 +6186,7 @@ var init_dist3 = __esm({
4057
6186
  };
4058
6187
  }
4059
6188
  async buildClose(params) {
4060
- const data = encodeFunctionData16({
6189
+ const data = encodeFunctionData20({
4061
6190
  abi: BORROWER_OPS_ABI,
4062
6191
  functionName: "closeTrove",
4063
6192
  args: [params.cdp_id]
@@ -4073,7 +6202,7 @@ var init_dist3 = __esm({
4073
6202
  async getCdpInfo(cdpId) {
4074
6203
  if (!this.rpcUrl) throw DefiError.rpcError(`[${this.protocolName}] getCdpInfo requires RPC \u2014 set HYPEREVM_RPC_URL`);
4075
6204
  if (!this.troveManager) throw DefiError.contractError(`[${this.protocolName}] trove_manager contract not configured`);
4076
- const client = createPublicClient14({ transport: http14(this.rpcUrl) });
6205
+ const client = createPublicClient16({ transport: http16(this.rpcUrl) });
4077
6206
  const data = await client.readContract({
4078
6207
  address: this.troveManager,
4079
6208
  abi: TROVE_MANAGER_ABI,
@@ -4091,13 +6220,13 @@ var init_dist3 = __esm({
4091
6220
  protocol: this.protocolName,
4092
6221
  cdp_id: cdpId,
4093
6222
  collateral: {
4094
- token: zeroAddress8,
6223
+ token: zeroAddress11,
4095
6224
  symbol: "WHYPE",
4096
6225
  amount: entireColl,
4097
6226
  decimals: 18
4098
6227
  },
4099
6228
  debt: {
4100
- token: zeroAddress8,
6229
+ token: zeroAddress11,
4101
6230
  symbol: "feUSD",
4102
6231
  amount: entireDebt,
4103
6232
  decimals: 18
@@ -4106,7 +6235,7 @@ var init_dist3 = __esm({
4106
6235
  };
4107
6236
  }
4108
6237
  };
4109
- PRICE_FEED_ABI = parseAbi18([
6238
+ PRICE_FEED_ABI = parseAbi222([
4110
6239
  "function fetchPrice() external view returns (uint256 price, bool isNewOracleFailureDetected)",
4111
6240
  "function lastGoodPrice() external view returns (uint256)"
4112
6241
  ]);
@@ -4132,7 +6261,7 @@ var init_dist3 = __esm({
4132
6261
  if (asset !== this.asset && this.asset !== "0x0000000000000000000000000000000000000000") {
4133
6262
  throw DefiError.unsupported(`[${this.protocolName}] Felix PriceFeed only supports asset ${this.asset}`);
4134
6263
  }
4135
- const client = createPublicClient15({ transport: http15(this.rpcUrl) });
6264
+ const client = createPublicClient17({ transport: http17(this.rpcUrl) });
4136
6265
  let priceVal;
4137
6266
  try {
4138
6267
  const result = await client.readContract({
@@ -4171,7 +6300,7 @@ var init_dist3 = __esm({
4171
6300
  return results;
4172
6301
  }
4173
6302
  };
4174
- ERC4626_ABI = parseAbi19([
6303
+ ERC4626_ABI = parseAbi23([
4175
6304
  "function asset() external view returns (address)",
4176
6305
  "function totalAssets() external view returns (uint256)",
4177
6306
  "function totalSupply() external view returns (uint256)",
@@ -4195,7 +6324,7 @@ var init_dist3 = __esm({
4195
6324
  return this.protocolName;
4196
6325
  }
4197
6326
  async buildDeposit(assets, receiver) {
4198
- const data = encodeFunctionData17({
6327
+ const data = encodeFunctionData21({
4199
6328
  abi: ERC4626_ABI,
4200
6329
  functionName: "deposit",
4201
6330
  args: [assets, receiver]
@@ -4209,7 +6338,7 @@ var init_dist3 = __esm({
4209
6338
  };
4210
6339
  }
4211
6340
  async buildWithdraw(assets, receiver, owner) {
4212
- const data = encodeFunctionData17({
6341
+ const data = encodeFunctionData21({
4213
6342
  abi: ERC4626_ABI,
4214
6343
  functionName: "withdraw",
4215
6344
  args: [assets, receiver, owner]
@@ -4224,7 +6353,7 @@ var init_dist3 = __esm({
4224
6353
  }
4225
6354
  async totalAssets() {
4226
6355
  if (!this.rpcUrl) throw DefiError.rpcError("No RPC URL configured");
4227
- const client = createPublicClient16({ transport: http16(this.rpcUrl) });
6356
+ const client = createPublicClient18({ transport: http18(this.rpcUrl) });
4228
6357
  return client.readContract({
4229
6358
  address: this.vaultAddress,
4230
6359
  abi: ERC4626_ABI,
@@ -4235,7 +6364,7 @@ var init_dist3 = __esm({
4235
6364
  }
4236
6365
  async convertToShares(assets) {
4237
6366
  if (!this.rpcUrl) throw DefiError.rpcError("No RPC URL configured");
4238
- const client = createPublicClient16({ transport: http16(this.rpcUrl) });
6367
+ const client = createPublicClient18({ transport: http18(this.rpcUrl) });
4239
6368
  return client.readContract({
4240
6369
  address: this.vaultAddress,
4241
6370
  abi: ERC4626_ABI,
@@ -4247,7 +6376,7 @@ var init_dist3 = __esm({
4247
6376
  }
4248
6377
  async convertToAssets(shares) {
4249
6378
  if (!this.rpcUrl) throw DefiError.rpcError("No RPC URL configured");
4250
- const client = createPublicClient16({ transport: http16(this.rpcUrl) });
6379
+ const client = createPublicClient18({ transport: http18(this.rpcUrl) });
4251
6380
  return client.readContract({
4252
6381
  address: this.vaultAddress,
4253
6382
  abi: ERC4626_ABI,
@@ -4259,7 +6388,7 @@ var init_dist3 = __esm({
4259
6388
  }
4260
6389
  async getVaultInfo() {
4261
6390
  if (!this.rpcUrl) throw DefiError.rpcError("No RPC URL configured");
4262
- const client = createPublicClient16({ transport: http16(this.rpcUrl) });
6391
+ const client = createPublicClient18({ transport: http18(this.rpcUrl) });
4263
6392
  const [totalAssets, totalSupply, asset] = await Promise.all([
4264
6393
  client.readContract({ address: this.vaultAddress, abi: ERC4626_ABI, functionName: "totalAssets" }).catch((e) => {
4265
6394
  throw DefiError.rpcError(`[${this.protocolName}] totalAssets failed: ${e}`);
@@ -4280,7 +6409,7 @@ var init_dist3 = __esm({
4280
6409
  };
4281
6410
  }
4282
6411
  };
4283
- GENERIC_LST_ABI = parseAbi20([
6412
+ GENERIC_LST_ABI = parseAbi24([
4284
6413
  "function stake() external payable returns (uint256)",
4285
6414
  "function unstake(uint256 amount) external returns (uint256)"
4286
6415
  ]);
@@ -4297,7 +6426,7 @@ var init_dist3 = __esm({
4297
6426
  return this.protocolName;
4298
6427
  }
4299
6428
  async buildStake(params) {
4300
- const data = encodeFunctionData18({ abi: GENERIC_LST_ABI, functionName: "stake" });
6429
+ const data = encodeFunctionData222({ abi: GENERIC_LST_ABI, functionName: "stake" });
4301
6430
  return {
4302
6431
  description: `[${this.protocolName}] Stake ${params.amount} HYPE`,
4303
6432
  to: this.staking,
@@ -4307,7 +6436,7 @@ var init_dist3 = __esm({
4307
6436
  };
4308
6437
  }
4309
6438
  async buildUnstake(params) {
4310
- const data = encodeFunctionData18({
6439
+ const data = encodeFunctionData222({
4311
6440
  abi: GENERIC_LST_ABI,
4312
6441
  functionName: "unstake",
4313
6442
  args: [params.amount]
@@ -4324,11 +6453,11 @@ var init_dist3 = __esm({
4324
6453
  throw DefiError.unsupported(`[${this.protocolName}] getInfo requires RPC`);
4325
6454
  }
4326
6455
  };
4327
- STHYPE_ABI = parseAbi21([
6456
+ STHYPE_ABI = parseAbi25([
4328
6457
  "function submit(address referral) external payable returns (uint256)",
4329
6458
  "function requestWithdrawals(uint256[] amounts, address owner) external returns (uint256[] requestIds)"
4330
6459
  ]);
4331
- ERC20_ABI3 = parseAbi21([
6460
+ ERC20_ABI3 = parseAbi25([
4332
6461
  "function totalSupply() external view returns (uint256)"
4333
6462
  ]);
4334
6463
  StHypeAdapter = class {
@@ -4348,10 +6477,10 @@ var init_dist3 = __esm({
4348
6477
  return this.protocolName;
4349
6478
  }
4350
6479
  async buildStake(params) {
4351
- const data = encodeFunctionData19({
6480
+ const data = encodeFunctionData23({
4352
6481
  abi: STHYPE_ABI,
4353
6482
  functionName: "submit",
4354
- args: [zeroAddress9]
6483
+ args: [zeroAddress12]
4355
6484
  });
4356
6485
  return {
4357
6486
  description: `[${this.protocolName}] Stake ${params.amount} HYPE for stHYPE`,
@@ -4362,7 +6491,7 @@ var init_dist3 = __esm({
4362
6491
  };
4363
6492
  }
4364
6493
  async buildUnstake(params) {
4365
- const data = encodeFunctionData19({
6494
+ const data = encodeFunctionData23({
4366
6495
  abi: STHYPE_ABI,
4367
6496
  functionName: "requestWithdrawals",
4368
6497
  args: [[params.amount], params.recipient]
@@ -4377,7 +6506,7 @@ var init_dist3 = __esm({
4377
6506
  }
4378
6507
  async getInfo() {
4379
6508
  if (!this.rpcUrl) throw DefiError.rpcError("No RPC URL configured");
4380
- const client = createPublicClient17({ transport: http17(this.rpcUrl) });
6509
+ const client = createPublicClient19({ transport: http19(this.rpcUrl) });
4381
6510
  const tokenAddr = this.sthypeToken ?? this.staking;
4382
6511
  const totalSupply = await client.readContract({
4383
6512
  address: tokenAddr,
@@ -4388,19 +6517,19 @@ var init_dist3 = __esm({
4388
6517
  });
4389
6518
  return {
4390
6519
  protocol: this.protocolName,
4391
- staked_token: zeroAddress9,
6520
+ staked_token: zeroAddress12,
4392
6521
  liquid_token: tokenAddr,
4393
6522
  exchange_rate: 1,
4394
6523
  total_staked: totalSupply
4395
6524
  };
4396
6525
  }
4397
6526
  };
4398
- KINETIQ_ABI = parseAbi222([
6527
+ KINETIQ_ABI = parseAbi26([
4399
6528
  "function stake() external payable returns (uint256)",
4400
6529
  "function requestUnstake(uint256 amount) external returns (uint256)",
4401
6530
  "function totalStaked() external view returns (uint256)"
4402
6531
  ]);
4403
- ORACLE_ABI3 = parseAbi222([
6532
+ ORACLE_ABI3 = parseAbi26([
4404
6533
  "function getAssetPrice(address asset) external view returns (uint256)"
4405
6534
  ]);
4406
6535
  WHYPE = "0x5555555555555555555555555555555555555555";
@@ -4422,7 +6551,7 @@ var init_dist3 = __esm({
4422
6551
  return this.protocolName;
4423
6552
  }
4424
6553
  async buildStake(params) {
4425
- const data = encodeFunctionData20({ abi: KINETIQ_ABI, functionName: "stake" });
6554
+ const data = encodeFunctionData24({ abi: KINETIQ_ABI, functionName: "stake" });
4426
6555
  return {
4427
6556
  description: `[${this.protocolName}] Stake ${params.amount} HYPE for kHYPE`,
4428
6557
  to: this.staking,
@@ -4432,7 +6561,7 @@ var init_dist3 = __esm({
4432
6561
  };
4433
6562
  }
4434
6563
  async buildUnstake(params) {
4435
- const data = encodeFunctionData20({
6564
+ const data = encodeFunctionData24({
4436
6565
  abi: KINETIQ_ABI,
4437
6566
  functionName: "requestUnstake",
4438
6567
  args: [params.amount]
@@ -4447,7 +6576,7 @@ var init_dist3 = __esm({
4447
6576
  }
4448
6577
  async getInfo() {
4449
6578
  if (!this.rpcUrl) throw DefiError.rpcError("No RPC URL configured");
4450
- const client = createPublicClient18({ transport: http18(this.rpcUrl) });
6579
+ const client = createPublicClient20({ transport: http20(this.rpcUrl) });
4451
6580
  const totalStaked = await client.readContract({
4452
6581
  address: this.staking,
4453
6582
  abi: KINETIQ_ABI,
@@ -4462,7 +6591,7 @@ var init_dist3 = __esm({
4462
6591
  const rateF64 = hypePrice > 0n && khypePrice > 0n ? Number(khypePrice * 10n ** 18n / hypePrice) / 1e18 : 1;
4463
6592
  return {
4464
6593
  protocol: this.protocolName,
4465
- staked_token: zeroAddress10,
6594
+ staked_token: zeroAddress13,
4466
6595
  liquid_token: this.liquidToken,
4467
6596
  exchange_rate: rateF64,
4468
6597
  total_staked: totalStaked
@@ -4518,7 +6647,7 @@ var init_dist3 = __esm({
4518
6647
  );
4519
6648
  }
4520
6649
  };
4521
- HLP_ABI = parseAbi23([
6650
+ HLP_ABI = parseAbi27([
4522
6651
  "function deposit(uint256 amount) external returns (uint256)",
4523
6652
  "function withdraw(uint256 shares) external returns (uint256)"
4524
6653
  ]);
@@ -4535,7 +6664,7 @@ var init_dist3 = __esm({
4535
6664
  return this.protocolName;
4536
6665
  }
4537
6666
  async buildOpenPosition(params) {
4538
- const data = encodeFunctionData21({
6667
+ const data = encodeFunctionData25({
4539
6668
  abi: HLP_ABI,
4540
6669
  functionName: "deposit",
4541
6670
  args: [params.collateral]
@@ -4549,7 +6678,7 @@ var init_dist3 = __esm({
4549
6678
  };
4550
6679
  }
4551
6680
  async buildClosePosition(params) {
4552
- const data = encodeFunctionData21({
6681
+ const data = encodeFunctionData25({
4553
6682
  abi: HLP_ABI,
4554
6683
  functionName: "withdraw",
4555
6684
  args: [params.size]
@@ -4584,7 +6713,7 @@ var init_dist3 = __esm({
4584
6713
  );
4585
6714
  }
4586
6715
  };
4587
- RYSK_ABI = parseAbi24([
6716
+ RYSK_ABI = parseAbi28([
4588
6717
  "function openOption(address underlying, uint256 strikePrice, uint256 expiry, bool isCall, uint256 amount) external returns (uint256 premium)",
4589
6718
  "function closeOption(address underlying, uint256 strikePrice, uint256 expiry, bool isCall, uint256 amount) external returns (uint256 payout)"
4590
6719
  ]);
@@ -4601,7 +6730,7 @@ var init_dist3 = __esm({
4601
6730
  return this.protocolName;
4602
6731
  }
4603
6732
  async buildBuy(params) {
4604
- const data = encodeFunctionData222({
6733
+ const data = encodeFunctionData26({
4605
6734
  abi: RYSK_ABI,
4606
6735
  functionName: "openOption",
4607
6736
  args: [
@@ -4621,7 +6750,7 @@ var init_dist3 = __esm({
4621
6750
  };
4622
6751
  }
4623
6752
  async buildSell(params) {
4624
- const data = encodeFunctionData222({
6753
+ const data = encodeFunctionData26({
4625
6754
  abi: RYSK_ABI,
4626
6755
  functionName: "closeOption",
4627
6756
  args: [
@@ -4662,7 +6791,7 @@ var init_dist3 = __esm({
4662
6791
  );
4663
6792
  }
4664
6793
  };
4665
- ERC721_ABI = parseAbi25([
6794
+ ERC721_ABI = parseAbi29([
4666
6795
  "function name() returns (string)",
4667
6796
  "function symbol() returns (string)",
4668
6797
  "function totalSupply() returns (uint256)",
@@ -4682,7 +6811,7 @@ var init_dist3 = __esm({
4682
6811
  }
4683
6812
  async getCollectionInfo(collection) {
4684
6813
  if (!this.rpcUrl) throw DefiError.rpcError("No RPC URL configured");
4685
- const client = createPublicClient19({ transport: http19(this.rpcUrl) });
6814
+ const client = createPublicClient21({ transport: http21(this.rpcUrl) });
4686
6815
  const [collectionName, symbol, totalSupply] = await Promise.all([
4687
6816
  client.readContract({ address: collection, abi: ERC721_ABI, functionName: "name" }).catch((e) => {
4688
6817
  throw DefiError.rpcError(`[${this.protocolName}] name failed: ${e}`);
@@ -4701,7 +6830,7 @@ var init_dist3 = __esm({
4701
6830
  }
4702
6831
  async getTokenInfo(collection, tokenId) {
4703
6832
  if (!this.rpcUrl) throw DefiError.rpcError("No RPC URL configured");
4704
- const client = createPublicClient19({ transport: http19(this.rpcUrl) });
6833
+ const client = createPublicClient21({ transport: http21(this.rpcUrl) });
4705
6834
  const [owner, tokenUri] = await Promise.all([
4706
6835
  client.readContract({ address: collection, abi: ERC721_ABI, functionName: "ownerOf", args: [tokenId] }).catch((e) => {
4707
6836
  throw DefiError.rpcError(`[${this.protocolName}] ownerOf failed: ${e}`);
@@ -4717,7 +6846,7 @@ var init_dist3 = __esm({
4717
6846
  }
4718
6847
  async getBalance(owner, collection) {
4719
6848
  if (!this.rpcUrl) throw DefiError.rpcError("No RPC URL configured");
4720
- const client = createPublicClient19({ transport: http19(this.rpcUrl) });
6849
+ const client = createPublicClient21({ transport: http21(this.rpcUrl) });
4721
6850
  return client.readContract({ address: collection, abi: ERC721_ABI, functionName: "balanceOf", args: [owner] }).catch((e) => {
4722
6851
  throw DefiError.rpcError(`[${this.protocolName}] balanceOf failed: ${e}`);
4723
6852
  });
@@ -4773,9 +6902,10 @@ import { z } from "zod";
4773
6902
 
4774
6903
  // src/executor.ts
4775
6904
  init_dist2();
4776
- import { createPublicClient as createPublicClient20, createWalletClient, http as http20, parseAbi as parseAbi26, encodeFunctionData as encodeFunctionData23 } from "viem";
6905
+ init_dist2();
6906
+ import { createPublicClient as createPublicClient23, createWalletClient, http as http23, parseAbi as parseAbi30, encodeFunctionData as encodeFunctionData27 } from "viem";
4777
6907
  import { privateKeyToAccount } from "viem/accounts";
4778
- var ERC20_ABI4 = parseAbi26([
6908
+ var ERC20_ABI4 = parseAbi30([
4779
6909
  "function allowance(address owner, address spender) external view returns (uint256)",
4780
6910
  "function approve(address spender, uint256 amount) external returns (bool)"
4781
6911
  ]);
@@ -4811,7 +6941,7 @@ var Executor = class _Executor {
4811
6941
  ` Approving ${amount} of ${token} for ${spender}...
4812
6942
  `
4813
6943
  );
4814
- const approveData = encodeFunctionData23({
6944
+ const approveData = encodeFunctionData27({
4815
6945
  abi: ERC20_ABI4,
4816
6946
  functionName: "approve",
4817
6947
  args: [spender, amount]
@@ -4854,7 +6984,7 @@ var Executor = class _Executor {
4854
6984
  /** Fetch EIP-1559 fee params from the network. Returns [maxFeePerGas, maxPriorityFeePerGas]. */
4855
6985
  async fetchEip1559Fees(rpcUrl) {
4856
6986
  try {
4857
- const client = createPublicClient20({ transport: http20(rpcUrl) });
6987
+ const client = createPublicClient23({ transport: http23(rpcUrl) });
4858
6988
  const gasPrice = await client.getGasPrice();
4859
6989
  let priorityFee = DEFAULT_PRIORITY_FEE_WEI;
4860
6990
  try {
@@ -4870,7 +7000,7 @@ var Executor = class _Executor {
4870
7000
  /** Estimate gas dynamically with buffer, falling back to a hardcoded estimate */
4871
7001
  async estimateGasWithBuffer(rpcUrl, tx, from) {
4872
7002
  try {
4873
- const client = createPublicClient20({ transport: http20(rpcUrl) });
7003
+ const client = createPublicClient23({ transport: http23(rpcUrl) });
4874
7004
  const estimated = await client.estimateGas({
4875
7005
  to: tx.to,
4876
7006
  data: tx.data,
@@ -4882,8 +7012,11 @@ var Executor = class _Executor {
4882
7012
  return buffered > MAX_GAS_LIMIT ? MAX_GAS_LIMIT : buffered;
4883
7013
  }
4884
7014
  } catch {
7015
+ if (tx.gas_estimate) {
7016
+ return _Executor.applyGasBuffer(BigInt(tx.gas_estimate));
7017
+ }
4885
7018
  }
4886
- return tx.gas_estimate ? BigInt(tx.gas_estimate) : 0n;
7019
+ return 0n;
4887
7020
  }
4888
7021
  /** Simulate a transaction via eth_call + eth_estimateGas */
4889
7022
  async simulate(tx) {
@@ -4891,9 +7024,49 @@ var Executor = class _Executor {
4891
7024
  if (!rpcUrl) {
4892
7025
  throw DefiError.rpcError("No RPC URL \u2014 cannot simulate. Set HYPEREVM_RPC_URL.");
4893
7026
  }
4894
- const client = createPublicClient20({ transport: http20(rpcUrl) });
7027
+ const client = createPublicClient23({ transport: http23(rpcUrl) });
4895
7028
  const privateKey = process.env["DEFI_PRIVATE_KEY"];
4896
7029
  const from = privateKey ? privateKeyToAccount(privateKey).address : "0x0000000000000000000000000000000000000001";
7030
+ if (tx.approvals && tx.approvals.length > 0) {
7031
+ const pendingApprovals = [];
7032
+ for (const approval of tx.approvals) {
7033
+ try {
7034
+ const allowance = await client.readContract({
7035
+ address: approval.token,
7036
+ abi: ERC20_ABI4,
7037
+ functionName: "allowance",
7038
+ args: [from, approval.spender]
7039
+ });
7040
+ if (allowance < approval.amount) {
7041
+ pendingApprovals.push({
7042
+ token: approval.token,
7043
+ spender: approval.spender,
7044
+ needed: approval.amount.toString(),
7045
+ current: allowance.toString()
7046
+ });
7047
+ }
7048
+ } catch {
7049
+ }
7050
+ }
7051
+ if (pendingApprovals.length > 0) {
7052
+ return {
7053
+ tx_hash: void 0,
7054
+ status: TxStatus.NeedsApproval,
7055
+ gas_used: tx.gas_estimate,
7056
+ description: tx.description,
7057
+ details: {
7058
+ to: tx.to,
7059
+ from,
7060
+ data: tx.data,
7061
+ value: tx.value.toString(),
7062
+ mode: "simulated",
7063
+ result: "needs_approval",
7064
+ pending_approvals: pendingApprovals,
7065
+ hint: "Use --broadcast to auto-approve and execute"
7066
+ }
7067
+ };
7068
+ }
7069
+ }
4897
7070
  try {
4898
7071
  await client.call({ to: tx.to, data: tx.data, value: tx.value, account: from });
4899
7072
  const gasEstimate = await this.estimateGasWithBuffer(rpcUrl, tx, from);
@@ -4964,8 +7137,33 @@ var Executor = class _Executor {
4964
7137
  if (!rpcUrl) {
4965
7138
  throw DefiError.rpcError("No RPC URL configured for broadcasting");
4966
7139
  }
4967
- const publicClient = createPublicClient20({ transport: http20(rpcUrl) });
4968
- const walletClient = createWalletClient({ account, transport: http20(rpcUrl) });
7140
+ const publicClient = createPublicClient23({ transport: http23(rpcUrl) });
7141
+ const walletClient = createWalletClient({ account, transport: http23(rpcUrl) });
7142
+ if (tx.pre_txs && tx.pre_txs.length > 0) {
7143
+ for (const preTx of tx.pre_txs) {
7144
+ process.stderr.write(` Pre-tx: ${preTx.description}...
7145
+ `);
7146
+ const preGas = await this.estimateGasWithBuffer(rpcUrl, preTx, account.address);
7147
+ const preTxHash = await walletClient.sendTransaction({
7148
+ chain: null,
7149
+ to: preTx.to,
7150
+ data: preTx.data,
7151
+ value: preTx.value,
7152
+ gas: preGas > 0n ? preGas : void 0
7153
+ });
7154
+ const preTxUrl = this.explorerUrl ? `${this.explorerUrl}/tx/${preTxHash}` : void 0;
7155
+ process.stderr.write(` Pre-tx sent: ${preTxHash}
7156
+ `);
7157
+ if (preTxUrl) process.stderr.write(` Explorer: ${preTxUrl}
7158
+ `);
7159
+ const preReceipt = await publicClient.waitForTransactionReceipt({ hash: preTxHash });
7160
+ if (preReceipt.status !== "success") {
7161
+ throw new DefiError("TX_FAILED", `Pre-transaction failed: ${preTx.description}`);
7162
+ }
7163
+ process.stderr.write(` Pre-tx confirmed
7164
+ `);
7165
+ }
7166
+ }
4969
7167
  if (tx.approvals && tx.approvals.length > 0) {
4970
7168
  for (const approval of tx.approvals) {
4971
7169
  await this.checkAndApprove(
@@ -5003,20 +7201,37 @@ var Executor = class _Executor {
5003
7201
  process.stderr.write("Waiting for confirmation...\n");
5004
7202
  const receipt = await publicClient.waitForTransactionReceipt({ hash: txHash });
5005
7203
  const status = receipt.status === "success" ? "confirmed" : "failed";
7204
+ let mintedTokenId;
7205
+ if (receipt.status === "success" && receipt.logs) {
7206
+ const TRANSFER_TOPIC = "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef";
7207
+ const ZERO_TOPIC = "0x0000000000000000000000000000000000000000000000000000000000000000";
7208
+ for (const log of receipt.logs) {
7209
+ if (log.topics.length >= 4 && log.topics[0] === TRANSFER_TOPIC && log.topics[1] === ZERO_TOPIC) {
7210
+ mintedTokenId = BigInt(log.topics[3]).toString();
7211
+ break;
7212
+ }
7213
+ }
7214
+ }
7215
+ const details = {
7216
+ to: tx.to,
7217
+ from: account.address,
7218
+ block_number: receipt.blockNumber?.toString(),
7219
+ gas_limit: gasLimit.toString(),
7220
+ gas_used: receipt.gasUsed?.toString(),
7221
+ explorer_url: txUrl,
7222
+ mode: "broadcast"
7223
+ };
7224
+ if (mintedTokenId) {
7225
+ details.minted_token_id = mintedTokenId;
7226
+ process.stderr.write(` Minted NFT tokenId: ${mintedTokenId}
7227
+ `);
7228
+ }
5006
7229
  return {
5007
7230
  tx_hash: txHash,
5008
7231
  status,
5009
7232
  gas_used: receipt.gasUsed ? Number(receipt.gasUsed) : void 0,
5010
7233
  description: tx.description,
5011
- details: {
5012
- to: tx.to,
5013
- from: account.address,
5014
- block_number: receipt.blockNumber?.toString(),
5015
- gas_limit: gasLimit.toString(),
5016
- gas_used: receipt.gasUsed?.toString(),
5017
- explorer_url: txUrl,
5018
- mode: "broadcast"
5019
- }
7234
+ details
5020
7235
  };
5021
7236
  }
5022
7237
  };
@@ -5604,8 +7819,8 @@ server.tool(
5604
7819
  const user = address;
5605
7820
  const { ProtocolCategory: ProtocolCategory2, multicallRead: multicallRead2 } = await Promise.resolve().then(() => (init_dist2(), dist_exports));
5606
7821
  const { createLending: _createLending } = await Promise.resolve().then(() => (init_dist3(), dist_exports2));
5607
- const { encodeFunctionData: encodeFunctionData24, parseAbi: parseAbi27 } = await import("viem");
5608
- const POOL_ABI3 = parseAbi27([
7822
+ const { encodeFunctionData: encodeFunctionData28, parseAbi: parseAbi31 } = await import("viem");
7823
+ const POOL_ABI3 = parseAbi31([
5609
7824
  "function getUserAccountData(address user) external view returns (uint256 totalCollateralBase, uint256 totalDebtBase, uint256 availableBorrowsBase, uint256 currentLiquidationThreshold, uint256 ltv, uint256 healthFactor)"
5610
7825
  ]);
5611
7826
  const lendingProtos = registry.getProtocolsForChain(chainName).filter((p) => p.category === ProtocolCategory2.Lending);
@@ -5614,7 +7829,7 @@ server.tool(
5614
7829
  const poolAddr = p.contracts?.pool;
5615
7830
  if (!poolAddr) continue;
5616
7831
  try {
5617
- const callData = encodeFunctionData24({ abi: POOL_ABI3, functionName: "getUserAccountData", args: [user] });
7832
+ const callData = encodeFunctionData28({ abi: POOL_ABI3, functionName: "getUserAccountData", args: [user] });
5618
7833
  const results = await multicallRead2(rpcUrl, [[poolAddr, callData]]);
5619
7834
  const raw = results[0];
5620
7835
  if (!raw || raw.length < 2 + 6 * 64) continue;