@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.
- package/config/protocols/dex/hybra.toml +91 -0
- package/config/protocols/dex/kittenswap.toml +21 -0
- package/config/protocols/dex/nest.toml +97 -0
- package/config/protocols/dex/ramses_cl.toml +56 -0
- package/config/protocols/dex/ramses_hl.toml +40 -0
- package/dist/index.js +3173 -683
- package/dist/index.js.map +1 -1
- package/dist/main.js +3160 -672
- package/dist/main.js.map +1 -1
- package/dist/mcp-server.js +2796 -581
- package/dist/mcp-server.js.map +1 -1
- package/package.json +1 -1
- package/config/protocols/dex/balancer.toml +0 -14
- package/config/protocols/dex/curve.toml +0 -12
- package/config/protocols/dex/hyperswap.toml +0 -14
- package/config/protocols/dex/hyperswap_v2.toml +0 -14
- package/config/protocols/dex/ring_few.toml +0 -14
- package/config/protocols/dex/woofi.toml +0 -12
- package/config/protocols/liquid_staking/kinetiq.toml +0 -12
- package/config/protocols/liquid_staking/sthype.toml +0 -13
package/dist/mcp-server.js
CHANGED
|
@@ -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,
|
|
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,
|
|
1270
|
-
import { createPublicClient as
|
|
1271
|
-
import {
|
|
1272
|
-
import {
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
import {
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
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 =
|
|
1584
|
+
function defaultMarketParams(loanToken = zeroAddress10) {
|
|
1297
1585
|
return {
|
|
1298
1586
|
loanToken,
|
|
1299
|
-
collateralToken:
|
|
1300
|
-
oracle:
|
|
1301
|
-
irm:
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
2085
|
-
|
|
2086
|
-
const
|
|
2087
|
-
|
|
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
|
-
|
|
2092
|
-
|
|
2093
|
-
|
|
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
|
|
2331
|
-
|
|
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 <
|
|
2336
|
-
const
|
|
2337
|
-
if (
|
|
2338
|
-
|
|
2339
|
-
|
|
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
|
-
|
|
2406
|
-
"
|
|
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
|
-
|
|
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
|
-
|
|
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:
|
|
2426
|
-
functionName: "
|
|
2427
|
-
args: [
|
|
2428
|
-
params.token_in,
|
|
2429
|
-
params.token_out,
|
|
2430
|
-
|
|
2431
|
-
|
|
2432
|
-
params.
|
|
2433
|
-
|
|
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
|
|
2823
|
+
description: `[${this.protocolName}] Swap`,
|
|
2438
2824
|
to: this.router,
|
|
2439
2825
|
data,
|
|
2440
2826
|
value: 0n,
|
|
2441
|
-
gas_estimate:
|
|
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
|
|
2832
|
+
throw DefiError.unsupported(`[${this.protocolName}] quote not yet implemented \u2014 use swap router`);
|
|
2446
2833
|
}
|
|
2447
|
-
async buildAddLiquidity(
|
|
2448
|
-
|
|
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}]
|
|
2916
|
+
throw DefiError.unsupported(`[${this.protocolName}] remove_liquidity requires tokenId`);
|
|
2452
2917
|
}
|
|
2453
2918
|
};
|
|
2454
|
-
|
|
2455
|
-
|
|
2456
|
-
|
|
2457
|
-
"function
|
|
2458
|
-
"function
|
|
2459
|
-
"function
|
|
2460
|
-
"function
|
|
2461
|
-
|
|
2462
|
-
|
|
2463
|
-
"function
|
|
2464
|
-
"function
|
|
2465
|
-
"function
|
|
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[]
|
|
2477
|
-
"function claimBribes(address[]
|
|
2478
|
-
"function claimFees(address[]
|
|
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
|
-
|
|
2949
|
+
HybraGaugeAdapter = class {
|
|
2482
2950
|
protocolName;
|
|
2483
|
-
|
|
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
|
|
2489
|
-
if (!
|
|
2490
|
-
|
|
2491
|
-
|
|
2492
|
-
|
|
2493
|
-
|
|
2494
|
-
|
|
2495
|
-
|
|
2496
|
-
this.
|
|
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
|
-
//
|
|
2504
|
-
async
|
|
2505
|
-
if (
|
|
2506
|
-
|
|
2507
|
-
|
|
2508
|
-
|
|
2509
|
-
|
|
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
|
-
|
|
2512
|
-
|
|
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
|
|
2521
|
-
|
|
2522
|
-
|
|
2523
|
-
|
|
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
|
-
|
|
2526
|
-
|
|
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:
|
|
2531
|
-
|
|
3089
|
+
gas_estimate: 5e5,
|
|
3090
|
+
pre_txs: [approveTx]
|
|
2532
3091
|
};
|
|
2533
3092
|
}
|
|
2534
|
-
async buildWithdraw(gauge,
|
|
2535
|
-
|
|
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
|
|
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:
|
|
3100
|
+
gas_estimate: 1e6
|
|
2546
3101
|
};
|
|
2547
3102
|
}
|
|
2548
|
-
|
|
2549
|
-
|
|
2550
|
-
|
|
2551
|
-
|
|
2552
|
-
|
|
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
|
|
2581
|
-
to:
|
|
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:
|
|
3118
|
+
gas_estimate: 1e6
|
|
2585
3119
|
};
|
|
2586
3120
|
}
|
|
2587
|
-
|
|
2588
|
-
|
|
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
|
-
//
|
|
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
|
|
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}
|
|
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
|
|
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
|
-
//
|
|
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
|
|
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
|
-
|
|
2694
|
-
"function
|
|
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
|
-
|
|
3206
|
+
WooFiAdapter = class {
|
|
2702
3207
|
protocolName;
|
|
2703
|
-
|
|
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
|
|
2708
|
-
if (!
|
|
2709
|
-
throw new DefiError("CONTRACT_ERROR", "Missing '
|
|
3313
|
+
const voter = entry.contracts?.["voter"];
|
|
3314
|
+
if (!voter) {
|
|
3315
|
+
throw new DefiError("CONTRACT_ERROR", "Missing 'voter' contract");
|
|
2710
3316
|
}
|
|
2711
|
-
|
|
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
|
-
|
|
2719
|
-
|
|
2720
|
-
|
|
2721
|
-
|
|
2722
|
-
|
|
2723
|
-
|
|
2724
|
-
|
|
2725
|
-
|
|
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: [
|
|
3584
|
+
args: [amount]
|
|
2728
3585
|
});
|
|
2729
3586
|
return {
|
|
2730
|
-
description: `[${this.protocolName}] Deposit ${amount} LP to
|
|
2731
|
-
to:
|
|
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
|
-
|
|
2739
|
-
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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}]
|
|
2783
|
-
to: this.
|
|
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:
|
|
4834
|
+
gas_estimate: 4e5
|
|
2787
4835
|
};
|
|
2788
4836
|
}
|
|
2789
|
-
/**
|
|
2790
|
-
|
|
2791
|
-
|
|
2792
|
-
|
|
2793
|
-
|
|
2794
|
-
|
|
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
|
|
2798
|
-
to: this.
|
|
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
|
-
/**
|
|
2805
|
-
|
|
2806
|
-
|
|
2807
|
-
|
|
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 =
|
|
2810
|
-
const
|
|
2811
|
-
address: this.
|
|
2812
|
-
abi:
|
|
2813
|
-
functionName: "
|
|
2814
|
-
args: [
|
|
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
|
|
2817
|
-
|
|
2818
|
-
|
|
2819
|
-
|
|
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 =
|
|
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 =
|
|
4995
|
+
ERC20_ABI = parseAbi14([
|
|
2832
4996
|
"function totalSupply() external view returns (uint256)"
|
|
2833
4997
|
]);
|
|
2834
|
-
INCENTIVES_ABI =
|
|
4998
|
+
INCENTIVES_ABI = parseAbi14([
|
|
2835
4999
|
"function getIncentivesController() external view returns (address)"
|
|
2836
5000
|
]);
|
|
2837
|
-
REWARDS_CONTROLLER_ABI =
|
|
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 =
|
|
5005
|
+
POOL_PROVIDER_ABI = parseAbi14([
|
|
2842
5006
|
"function ADDRESSES_PROVIDER() external view returns (address)"
|
|
2843
5007
|
]);
|
|
2844
|
-
ADDRESSES_PROVIDER_ABI =
|
|
5008
|
+
ADDRESSES_PROVIDER_ABI = parseAbi14([
|
|
2845
5009
|
"function getPriceOracle() external view returns (address)"
|
|
2846
5010
|
]);
|
|
2847
|
-
ORACLE_ABI =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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
|
|
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
|
-
})
|
|
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 [
|
|
2951
|
-
|
|
2952
|
-
|
|
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
|
|
2969
|
-
|
|
2970
|
-
|
|
2971
|
-
|
|
2972
|
-
|
|
2973
|
-
|
|
2974
|
-
|
|
2975
|
-
|
|
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
|
|
2989
|
-
|
|
2990
|
-
|
|
2991
|
-
|
|
2992
|
-
|
|
2993
|
-
args: [aTokenAddress, reward]
|
|
2994
|
-
|
|
2995
|
-
|
|
2996
|
-
|
|
2997
|
-
|
|
2998
|
-
|
|
2999
|
-
|
|
3000
|
-
|
|
3001
|
-
|
|
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
|
-
|
|
3005
|
-
|
|
3006
|
-
|
|
3007
|
-
|
|
3008
|
-
|
|
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
|
|
3030
|
-
|
|
3031
|
-
|
|
3032
|
-
|
|
3033
|
-
|
|
3034
|
-
const
|
|
3035
|
-
|
|
3036
|
-
|
|
3037
|
-
|
|
3038
|
-
|
|
3039
|
-
const [
|
|
3040
|
-
|
|
3041
|
-
|
|
3042
|
-
|
|
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
|
|
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
|
|
3066
|
-
|
|
3067
|
-
|
|
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
|
|
3094
|
-
|
|
3095
|
-
|
|
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 =
|
|
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:
|
|
3158
|
-
const borrows = debtUsd > 0 ? [{ asset:
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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:
|
|
3323
|
-
const borrows = debtUsd > 0 ? [{ asset:
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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
|
|
3869
|
-
|
|
3870
|
-
|
|
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
|
|
3888
|
-
|
|
3889
|
-
|
|
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
|
-
|
|
3896
|
-
|
|
3897
|
-
|
|
3898
|
-
|
|
3899
|
-
|
|
3900
|
-
|
|
3901
|
-
|
|
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
|
|
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
|
|
3919
|
-
|
|
3920
|
-
|
|
3921
|
-
|
|
3922
|
-
|
|
3923
|
-
|
|
3924
|
-
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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:
|
|
6223
|
+
token: zeroAddress11,
|
|
4095
6224
|
symbol: "WHYPE",
|
|
4096
6225
|
amount: entireColl,
|
|
4097
6226
|
decimals: 18
|
|
4098
6227
|
},
|
|
4099
6228
|
debt: {
|
|
4100
|
-
token:
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
6480
|
+
const data = encodeFunctionData23({
|
|
4352
6481
|
abi: STHYPE_ABI,
|
|
4353
6482
|
functionName: "submit",
|
|
4354
|
-
args: [
|
|
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 =
|
|
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 =
|
|
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:
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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:
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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
|
-
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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
|
|
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 =
|
|
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 =
|
|
4968
|
-
const walletClient = createWalletClient({ account, transport:
|
|
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:
|
|
5608
|
-
const POOL_ABI3 =
|
|
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 =
|
|
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;
|