@continuumdao/ctm-mpc-defi 0.2.44 → 0.2.45

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.
@@ -22,8 +22,9 @@ The MPC **executor address** (`keyGen.ethereumaddress`) is the Hyperliquid **use
22
22
  - **Spot ↔ Perp:** USDC is one asset split between **spot** and **perp margin** ledgers (not separate ERC20s). Move with `usdClassTransfer`.
23
23
  - **Vaults:** Deposit/withdraw USD into protocol vaults (withdraw includes accrued PnL).
24
24
  - **Staking:** Stake/unstake **HYPE** and delegate to validators.
25
+ - **Borrow / lend:** Manual HyperCore money market. Collateralize **HYPE** / **UBTC**; borrow or supply quote assets (**USDC**, **USDT0**, **USDH**). Current **supply APR** and **borrow APR** come from `ctm_hyperliquid_fetch_lend_markets`.
25
26
 
26
- Trading reads use Hyperliquid **REST `/info`**. Writes use **CoreWriter** on HyperEVM (not the signed `/exchange` API).
27
+ Trading reads use Hyperliquid **REST `/info`**. Most writes use **CoreWriter** on HyperEVM. Leverage, bridge withdraw, TP/SL brackets, and **borrow/lend** use signed **L1 `/exchange`** (EIP-712).
27
28
 
28
29
  ## Getting started (funding)
29
30
 
@@ -45,7 +46,7 @@ Positions and orders from MCP reflect **live HyperCore state** after prior txs a
45
46
  5. `ctm_hyperliquid_fetch_market_snapshot({ chainId, coin: "AAPL" })` — **`livePrice.midUsd`** is the current price; **`funding`** is official hourly HyperCore funding; `latestCandle` is the most recent bar; `candles` is capped (default 48). Throws if live price cannot be fetched.
46
47
  6. `ctm_hyperliquid_fetch_open_context({ chainId, executorAddress, coin: "Apple" })` — same resolution
47
48
  7. `ctm_hyperliquid_fetch_usd_class_balances({ chainId, executorAddress })` — spot vs perp USD if needed
48
- 8. **Gas** — `get_multi_sign_gas_options({ chainId })` + `useCustomGas` for **CoreWriter** tools only (plain limit, close, cancel, transfers, vault, stake). **Skip gas** for `build_update_leverage_multisign`, `build_bridge_withdraw_multisign`, and limit orders **with TP/SL triggers** (EIP-712 `/exchange`).
49
+ 8. **Gas** — `get_multi_sign_gas_options({ chainId })` + `useCustomGas` for **CoreWriter** tools only (plain limit, close, cancel, transfers, vault, stake). **Skip gas** for `build_update_leverage_multisign`, `build_bridge_withdraw_multisign`, `build_lend_multisign`, and limit orders **with TP/SL triggers** (EIP-712 `/exchange`).
49
50
  9. `ctm_hyperliquid_build_limit_order_multisign` → **`{ requestId }`**
50
51
  10. Base MPC lifecycle (shared gas/submit section below)
51
52
 
@@ -69,6 +70,8 @@ Positions and orders from MCP reflect **live HyperCore state** after prior txs a
69
70
  | User vault equity | `ctm_hyperliquid_fetch_user_vault_equities` |
70
71
  | HYPE stake summary | `ctm_hyperliquid_fetch_staking_summary` |
71
72
  | Validator delegations | `ctm_hyperliquid_fetch_delegations` |
73
+ | Core lend markets + **current supply/borrow APR** | `ctm_hyperliquid_fetch_lend_markets` — activate `hyperliquid:lend` |
74
+ | Core lend positions + health + manual-borrow gate | `ctm_hyperliquid_fetch_lend_positions` |
72
75
 
73
76
  ### Multi-sign (writes)
74
77
 
@@ -87,6 +90,7 @@ Positions and orders from MCP reflect **live HyperCore state** after prior txs a
87
90
  | Delegate to validator | `ctm_hyperliquid_build_delegate_multisign` |
88
91
  | Undelegate | `ctm_hyperliquid_build_undelegate_multisign` |
89
92
  | Update per-market leverage | `ctm_hyperliquid_build_update_leverage_multisign` (EIP-712 — no gas) |
93
+ | Supply / withdraw / borrow / repay | `ctm_hyperliquid_build_lend_multisign` (EIP-712 — no gas) |
90
94
 
91
95
  ### EIP-712 vs CoreWriter (critical for agents)
92
96
 
@@ -95,6 +99,7 @@ Positions and orders from MCP reflect **live HyperCore state** after prior txs a
95
99
  | Plain limit / close / cancel / USD transfer / vault / stake | CoreWriter EVM tx | **Yes** — `get_multi_sign_gas_options`, pass `useCustomGas` |
96
100
  | `build_update_leverage_multisign` | EIP-712 → `/exchange` | **No** — trigger without txParams |
97
101
  | `build_bridge_withdraw_multisign` | EIP-712 → `/exchange` | **No** |
102
+ | `build_lend_multisign` | EIP-712 → `/exchange` | **No** — trigger without txParams |
98
103
  | Limit with `takeProfitTriggerPxHuman` and/or `stopLossTriggerPxHuman` | EIP-712 normalTpsl → `/exchange` | **No** — re-build if entry/TP/SL change |
99
104
 
100
105
  ## Common multisign inputs (all `build_*` tools)
@@ -203,6 +208,31 @@ Use `isLong: true` for a **long** position (submits sell reduce-only IoC):
203
208
 
204
209
  Check balances first with `ctm_hyperliquid_fetch_usd_class_balances`.
205
210
 
211
+ ## Borrow / lend (HyperCore)
212
+
213
+ Activate **`hyperliquid:lend`** (`activate_tool_group`). Do not fold this into vaults or perp market-data.
214
+
215
+ 1. `ctm_hyperliquid_fetch_lend_markets` — current **`supplyYearlyRate` / `borrowYearlyRate`** are **APR** (decimal; `0.05` = 5%). Also `supplyAprPercent` / `borrowAprPercent`. `role` is `collateral` (LTV > 0) or `quote`.
216
+ 2. `ctm_hyperliquid_fetch_lend_positions` — supplied/borrowed, `health`, `manualBorrowEnabled`. If `userAbstraction` is `portfolioMargin`, **do not** call `operation: "borrow"`.
217
+ 3. `ctm_hyperliquid_build_lend_multisign` with `operation`: `supply` | `withdraw` | `borrow` | `repay`.
218
+
219
+ Rules:
220
+
221
+ - **HYPE / UBTC** (`BTC` aliases to UBTC) supplied as collateral **do not earn interest**.
222
+ - **USDC / USDT0** (`USDT` aliases to USDT0) / **USDH** supplied earn utilization APR but **do not increase borrow capacity**.
223
+ - `amountMax: true` (or `amountHuman: "max"`) sends wire `amount: null` — full withdraw/repay.
224
+ - EIP-712 `/exchange` — **no `useCustomGas`**, trigger without txParams.
225
+
226
+ ```json
227
+ {
228
+ "chainId": 999,
229
+ "purposeText": "HL supply 100 USDC",
230
+ "coin": "USDC",
231
+ "operation": "supply",
232
+ "amountHuman": "100"
233
+ }
234
+ ```
235
+
206
236
  ## Vault / stake
207
237
 
208
238
  - **Vault deposit/withdraw:** `vaultAddress` from `fetch_vaults`; `usdHuman` amount. Mainnet vault catalog fetch can take ~10–15s (large stats feed). Testnet catalog is empty.
@@ -11,10 +11,12 @@ Do **not** web-search rates. Do **not** use DefiLlama. HIP-3 / Arcus stock tradi
11
11
 
12
12
  ## Plan Mode
13
13
 
14
- If the operator started **Best yield** / plan mode `yield`: this thread **authors the plan file**. Ask for the asset first. Then `get_defi_protocol_skill({ protocolId: "yield-compare" })` **once** and write workstreams — do **not** `load_defi_protocol`, search Continuum tools, or spawn specialists on the parent. Execute runs one specialist per listed protocol. Research-only — no `ctm_*_build_*_multisign`. Table categories: `idle` / `lp` / `vault` / `perp_funding`. GMX and Hyperliquid only if they asked. Catalog MCP is context only.
14
+ If the operator started **Best yield** / plan mode `yield`: this thread **authors the plan file**. Ask for the asset first. Then `get_defi_protocol_skill({ protocolId: "yield-compare" })` **once** and write workstreams — do **not** `load_defi_protocol`, search Continuum tools, or spawn specialists on the parent. Execute runs one specialist per listed protocol. Research-only — no `ctm_*_build_*_multisign`. Table categories: `idle` / `lp` / `vault` / `perp_funding`. GMX and Hyperliquid vaults/funding only if they asked. Hyperliquid **Core lend** (USDC/USDT supply APR) is an **optional extra** for stables — mention in plan notes; add an Execute leaf only if they say yes or already asked about Hyperliquid / HL lend / Core lending. Catalog MCP is context only.
15
15
 
16
16
  For **USDC / USDT**, the authored plan notes **must** mention Morpho stock-backed USDC loans as an **optional extra** (isolated Blue/Midnight books against Coinbase B20 collateral such as AAPLc/NVDAc; thin liquidity; 24/5 oracles; Regulation S / non-US). Do **not** add a Morpho stock Execute workstream or call `ctm_morpho_fetch_stock_markets` unless the operator says yes or already asked about stocks / tokenized stocks / stock-backed loans.
17
17
 
18
+ For **USDC / USDT**, plan notes **must** also mention Hyperliquid Core lend as an **optional extra**: supply USDC/USDT0 on HyperCore to earn utilization **APR** (`ctm_hyperliquid_fetch_lend_markets`); HYPE/UBTC collateral earns nothing. Do **not** add a Hyperliquid Execute workstream or call `ctm_hyperliquid_fetch_lend_markets` unless the operator says yes or already asked about Hyperliquid / HL lend / Core lending. That leaf is research-only (`toolGroups: ["defi_discovery", "defi:hyperliquid:lend", "keygen", "keygen_messaging"]`) — report quote-token `supplyYearlyRate` as **APR** plus `borrowYearlyRate` as context; skip collateral rows; category `idle`. Do not treat Core lend as vault APR or perp funding.
19
+
18
20
  Each Execute protocol leaf must list `toolGroups: ["defi_discovery", "defi:<protocol>:market-data", "keygen", "keygen_messaging"]` (canonical ids: `aave-v4`, `compound-v3`, `euler-v2`, `morpho`, `maple-syrup`, `curve-dao`, `aerodrome`, `pendle`) and `budget: { maxRounds: 16, maxWallClockMs: 240000 }`. Slim leaves cannot search/activate packs — without `defi_discovery` they never see `load_defi_protocol` or official `ctm_*` fetch tools. Do **not** use `agent_bash` / `agent_read_file` / `agent_grep` on a yield leaf — call the official fetch (`ctm_aave_v4_fetch_markets`, `ctm_compound_v3_fetch_markets`, `ctm_morpho_fetch_earn_vaults`, `ctm_morpho_fetch_blue_markets` with `loan: "USDC"` / `"USDT"`, `ctm_aerodrome_fetch_lp_yields` on Base `8453`, `ctm_pendle_fetch_markets` / `ctm_pendle_search_assets`, …) then post `mpc-task-result`. Ticker filters (`underlying: "USDT"`, Morpho `loan: "USDC"`) are valid on Aave/Maple/Morpho fetches — do not invent ERC-20 addresses. Morpho leaf: report vault `netApy` and Blue `netSupplyApyLabel`; footnote `rewards[]` as variable extras — do not add them on top of net APY a second time. Skip empty Blue books (no supply TVL). `ctm_morpho_fetch_stock_markets` only after the operator says yes. Aave v4 is Ethereum-first (`1`; also 10 / 43114). Maple is Ethereum (`1`). Aerodrome is Base (`8453`) only. Pendle is any Core `chainId` ∩ node registry — research-only fetch, no build.
19
21
 
20
22
  ## Units and caveats
@@ -52,6 +54,7 @@ Call `get_defi_protocol_skill({ protocolId: "yield-compare" })` for this map, th
52
54
  3. `ctm_pendle_fetch_markets` — optional PT / YT / LP implied APY if they asked about Pendle (research-only)
53
55
  4. `ctm_gmx_fetch_gm_apy` / `ctm_hyperliquid_fetch_vault_apys` / perp funding — **only if they asked** about GMX, HL vaults, or funding
54
56
  5. Morpho stock-backed USDC loans — **optional extra in plan notes only**. Call `ctm_morpho_fetch_stock_markets` only if they say yes.
57
+ 6. Hyperliquid Core lend (`ctm_hyperliquid_fetch_lend_markets`) — **optional extra in plan notes**. Call only if they say yes or already asked about Hyperliquid / HL lend. Quote tokens only (USDC / USDT0); **APR** not APY. HYPE/UBTC collateral is not idle yield.
55
58
 
56
59
  ### USDS
57
60
 
@@ -481,6 +481,49 @@ async function hyperliquidFetchStakingSummary(args) {
481
481
  });
482
482
  return { delegated: raw?.delegated ?? "0", undelegated: raw?.undelegated ?? "0" };
483
483
  }
484
+ async function hyperliquidFetchSpotTokens(args) {
485
+ const meta = await hyperliquidInfoPost(args.chainId, { type: "spotMeta" });
486
+ const tokens = (meta.tokens ?? []).map((t) => ({
487
+ name: t.name,
488
+ tokenIndex: t.index,
489
+ szDecimals: t.szDecimals
490
+ }));
491
+ return { tokens };
492
+ }
493
+ async function hyperliquidFetchAllBorrowLendReserveStates(args) {
494
+ const raw = await hyperliquidInfoPost(args.chainId, {
495
+ type: "allBorrowLendReserveStates"
496
+ });
497
+ return { reserves: Array.isArray(raw) ? raw : [] };
498
+ }
499
+ async function hyperliquidFetchBorrowLendReserveState(args) {
500
+ const reserve = await hyperliquidInfoPost(args.chainId, {
501
+ type: "borrowLendReserveState",
502
+ token: args.token
503
+ });
504
+ return { reserve };
505
+ }
506
+ async function hyperliquidFetchBorrowLendUserState(args) {
507
+ const state = await hyperliquidInfoPost(args.chainId, {
508
+ type: "borrowLendUserState",
509
+ user: args.user
510
+ });
511
+ return {
512
+ state: {
513
+ tokenToState: Array.isArray(state?.tokenToState) ? state.tokenToState : [],
514
+ health: String(state?.health ?? "healthy"),
515
+ healthFactor: state?.healthFactor ?? null
516
+ }
517
+ };
518
+ }
519
+ async function hyperliquidFetchUserAbstraction(args) {
520
+ const raw = await hyperliquidInfoPost(args.chainId, {
521
+ type: "userAbstraction",
522
+ user: args.user
523
+ });
524
+ if (typeof raw === "string" && raw.trim()) return { abstraction: raw.trim() };
525
+ return { abstraction: "default" };
526
+ }
484
527
 
485
528
  // src/protocols/evm/hyperliquid/marketSearch.ts
486
529
  function normalizeQuery(value) {
@@ -636,6 +679,21 @@ async function hyperliquidResolvePerpMarket(args) {
636
679
  }
637
680
 
638
681
  // src/protocols/evm/hyperliquid/assets.ts
682
+ var HYPERLIQUID_LEND_TOKEN_ALIASES = {
683
+ btc: "UBTC",
684
+ ubtc: "UBTC",
685
+ usdt: "USDT0",
686
+ usdt0: "USDT0",
687
+ usdc: "USDC",
688
+ hype: "HYPE",
689
+ usdh: "USDH"
690
+ };
691
+ function hyperliquidCanonicalLendCoin(coin) {
692
+ const trimmed = coin.trim();
693
+ if (!trimmed) return trimmed;
694
+ const aliased = HYPERLIQUID_LEND_TOKEN_ALIASES[trimmed.toLowerCase()];
695
+ return aliased ?? trimmed;
696
+ }
639
697
  async function hyperliquidResolvePerpAsset(args) {
640
698
  const resolved = await hyperliquidResolvePerpMarket(args);
641
699
  return { asset: resolved.asset, szDecimals: resolved.szDecimals, maxLeverage: resolved.maxLeverage };
@@ -657,6 +715,21 @@ async function hyperliquidResolveAsset(args) {
657
715
  function hyperliquidIsSpotAssetId(asset) {
658
716
  return asset >= HYPERLIQUID_SPOT_ASSET_OFFSET;
659
717
  }
718
+ async function hyperliquidResolveSpotToken(args) {
719
+ const raw = args.coin.trim();
720
+ if (!raw) throw new Error("Hyperliquid lend token is required.");
721
+ const asIndex = Number.parseInt(raw, 10);
722
+ const { tokens } = await hyperliquidFetchSpotTokens({ chainId: args.chainId });
723
+ if (/^\d+$/.test(raw) && Number.isFinite(asIndex)) {
724
+ const hit2 = tokens.find((t) => t.tokenIndex === asIndex);
725
+ if (!hit2) throw new Error(`Unknown Hyperliquid spot token index: ${raw}`);
726
+ return { tokenIndex: hit2.tokenIndex, coin: hit2.name, szDecimals: hit2.szDecimals };
727
+ }
728
+ const canonical = hyperliquidCanonicalLendCoin(raw);
729
+ const hit = tokens.find((t) => t.name.toLowerCase() === canonical.toLowerCase());
730
+ if (!hit) throw new Error(`Unknown Hyperliquid spot token: ${raw}`);
731
+ return { tokenIndex: hit.tokenIndex, coin: hit.name, szDecimals: hit.szDecimals };
732
+ }
660
733
 
661
734
  // src/protocols/evm/hyperliquid/reads.ts
662
735
  function hyperliquidUsdAmountString(value) {
@@ -868,6 +941,149 @@ async function hyperliquidFetchOhlcvSummary(args) {
868
941
  });
869
942
  return { ohlcv, resolvedCoin: resolved.name, dex: resolved.dex ?? null };
870
943
  }
944
+
945
+ // src/protocols/evm/hyperliquid/lendReads.ts
946
+ function yearlyRateToAprPercent(raw) {
947
+ const n = Number.parseFloat(String(raw ?? "").trim());
948
+ if (!Number.isFinite(n)) return null;
949
+ return n * 100;
950
+ }
951
+ function decimalGtZero(raw) {
952
+ const n = Number.parseFloat(String(raw ?? "").trim());
953
+ return Number.isFinite(n) && n > 0;
954
+ }
955
+ function hyperliquidLendRoleFromLtv(ltv) {
956
+ return decimalGtZero(ltv) ? "collateral" : "quote";
957
+ }
958
+ function parseHyperliquidBorrowLendReserveTuples(raw) {
959
+ if (!Array.isArray(raw)) return [];
960
+ const out = [];
961
+ for (const entry of raw) {
962
+ if (!Array.isArray(entry) || entry.length < 2) continue;
963
+ const tokenIndex = Number(entry[0]);
964
+ const state = entry[1];
965
+ if (!Number.isFinite(tokenIndex) || !state || typeof state !== "object") continue;
966
+ out.push([
967
+ tokenIndex,
968
+ {
969
+ borrowYearlyRate: String(state.borrowYearlyRate ?? "0"),
970
+ supplyYearlyRate: String(state.supplyYearlyRate ?? "0"),
971
+ balance: String(state.balance ?? "0"),
972
+ utilization: String(state.utilization ?? "0"),
973
+ oraclePx: String(state.oraclePx ?? "0"),
974
+ ltv: String(state.ltv ?? "0"),
975
+ totalSupplied: String(state.totalSupplied ?? "0"),
976
+ totalBorrowed: String(state.totalBorrowed ?? "0")
977
+ }
978
+ ]);
979
+ }
980
+ return out;
981
+ }
982
+ function parseHyperliquidBorrowLendUserState(raw) {
983
+ const o = raw && typeof raw === "object" ? raw : {};
984
+ const tokenToState = [];
985
+ const rows = Array.isArray(o.tokenToState) ? o.tokenToState : [];
986
+ for (const entry of rows) {
987
+ if (!Array.isArray(entry) || entry.length < 2) continue;
988
+ const tokenIndex = Number(entry[0]);
989
+ const state = entry[1];
990
+ if (!Number.isFinite(tokenIndex) || !state || typeof state !== "object") continue;
991
+ tokenToState.push([
992
+ tokenIndex,
993
+ {
994
+ borrow: {
995
+ basis: String(state.borrow?.basis ?? "0.0"),
996
+ value: String(state.borrow?.value ?? "0.0")
997
+ },
998
+ supply: {
999
+ basis: String(state.supply?.basis ?? "0.0"),
1000
+ value: String(state.supply?.value ?? "0.0")
1001
+ }
1002
+ }
1003
+ ]);
1004
+ }
1005
+ return {
1006
+ tokenToState,
1007
+ health: String(o.health ?? "healthy"),
1008
+ healthFactor: o.healthFactor == null ? null : String(o.healthFactor)
1009
+ };
1010
+ }
1011
+ function mapHyperliquidLendMarketRows(args) {
1012
+ const tokenByIndex = new Map(args.tokens.map((t) => [t.tokenIndex, t]));
1013
+ return args.reserves.map(([tokenIndex, state]) => {
1014
+ const token = tokenByIndex.get(tokenIndex);
1015
+ const role = hyperliquidLendRoleFromLtv(state.ltv);
1016
+ return {
1017
+ tokenIndex,
1018
+ coin: token?.name ?? `token:${tokenIndex}`,
1019
+ role,
1020
+ szDecimals: token?.szDecimals ?? null,
1021
+ supplyYearlyRate: state.supplyYearlyRate,
1022
+ borrowYearlyRate: state.borrowYearlyRate,
1023
+ supplyAprPercent: yearlyRateToAprPercent(state.supplyYearlyRate),
1024
+ borrowAprPercent: yearlyRateToAprPercent(state.borrowYearlyRate),
1025
+ utilization: state.utilization,
1026
+ oraclePx: state.oraclePx,
1027
+ ltv: state.ltv,
1028
+ totalSupplied: state.totalSupplied,
1029
+ totalBorrowed: state.totalBorrowed,
1030
+ balance: state.balance
1031
+ };
1032
+ });
1033
+ }
1034
+ function hyperliquidManualBorrowEnabled(abstraction) {
1035
+ return abstraction.trim() !== "portfolioMargin";
1036
+ }
1037
+ async function hyperliquidFetchLendMarketsSummary(args) {
1038
+ const [{ reserves }, { tokens }] = await Promise.all([
1039
+ hyperliquidFetchAllBorrowLendReserveStates({ chainId: args.chainId }),
1040
+ hyperliquidFetchSpotTokens({ chainId: args.chainId })
1041
+ ]);
1042
+ const markets = mapHyperliquidLendMarketRows({
1043
+ reserves: parseHyperliquidBorrowLendReserveTuples(reserves),
1044
+ tokens
1045
+ });
1046
+ return {
1047
+ markets,
1048
+ notes: "Hyperliquid Core lend yearly rates are APR (supplyYearlyRate / borrowYearlyRate), not APY. Collateral (HYPE, UBTC) does not earn supply interest. Quote supply (USDC, USDT0, USDH) earns utilization APR but does not increase borrow capacity. Rates update hourly."
1049
+ };
1050
+ }
1051
+ async function hyperliquidFetchLendPositionsSummary(args) {
1052
+ const user = args.executorAddress.trim().toLowerCase();
1053
+ const [{ state }, { abstraction }, { tokens }, { reserves }] = await Promise.all([
1054
+ hyperliquidFetchBorrowLendUserState({ chainId: args.chainId, user }),
1055
+ hyperliquidFetchUserAbstraction({ chainId: args.chainId, user }),
1056
+ hyperliquidFetchSpotTokens({ chainId: args.chainId }),
1057
+ hyperliquidFetchAllBorrowLendReserveStates({ chainId: args.chainId })
1058
+ ]);
1059
+ const parsed = parseHyperliquidBorrowLendUserState(state);
1060
+ const tokenByIndex = new Map(tokens.map((t) => [t.tokenIndex, t]));
1061
+ const roleByIndex = new Map(
1062
+ parseHyperliquidBorrowLendReserveTuples(reserves).map(([idx, s]) => [idx, hyperliquidLendRoleFromLtv(s.ltv)])
1063
+ );
1064
+ const positions = parsed.tokenToState.filter(([, s]) => decimalGtZero(s.supply.value) || decimalGtZero(s.borrow.value)).map(([tokenIndex, s]) => ({
1065
+ tokenIndex,
1066
+ coin: tokenByIndex.get(tokenIndex)?.name ?? `token:${tokenIndex}`,
1067
+ role: roleByIndex.get(tokenIndex) ?? null,
1068
+ suppliedBasis: s.supply.basis,
1069
+ suppliedValue: s.supply.value,
1070
+ borrowedBasis: s.borrow.basis,
1071
+ borrowedValue: s.borrow.value
1072
+ }));
1073
+ const manualBorrowEnabled = hyperliquidManualBorrowEnabled(abstraction);
1074
+ const summary = {
1075
+ positions,
1076
+ health: parsed.health,
1077
+ healthFactor: parsed.healthFactor,
1078
+ userAbstraction: abstraction,
1079
+ manualBorrowEnabled,
1080
+ notes: manualBorrowEnabled ? "Manual borrow is available on this account. Portfolio-margin accounts use automated borrow instead." : "Portfolio-margin account: borrowing is automated and the manual borrow action is disabled. Supply/withdraw/repay may still apply."
1081
+ };
1082
+ return summary;
1083
+ }
1084
+ async function hyperliquidResolveLendTokenForChain(args) {
1085
+ return hyperliquidResolveSpotToken({ chainId: args.chainId, coin: args.coin });
1086
+ }
871
1087
  var coreWriterAbi = viem.parseAbi(["function sendRawAction(bytes data) external"]);
872
1088
  var ACTION_LIMIT_ORDER = 1;
873
1089
  var ACTION_VAULT_TRANSFER = 2;
@@ -1380,6 +1596,28 @@ function buildHyperliquidUpdateLeverageAction(args) {
1380
1596
  leverage
1381
1597
  };
1382
1598
  }
1599
+ function parseHyperliquidBorrowLendAmount(amountHuman) {
1600
+ if (amountHuman == null) return null;
1601
+ const trimmed = String(amountHuman).trim();
1602
+ if (!trimmed || trimmed.toLowerCase() === "max") return null;
1603
+ return hyperliquidFloatToWire(trimmed);
1604
+ }
1605
+ function buildHyperliquidBorrowLendAction(args) {
1606
+ const operation = args.operation;
1607
+ if (operation !== "supply" && operation !== "withdraw" && operation !== "repay" && operation !== "borrow") {
1608
+ throw new Error("operation must be supply, withdraw, repay, or borrow");
1609
+ }
1610
+ const token = Math.trunc(args.token);
1611
+ if (!Number.isFinite(token) || token < 0) {
1612
+ throw new Error("token must be a non-negative integer token index");
1613
+ }
1614
+ return {
1615
+ type: "borrowLend",
1616
+ operation,
1617
+ token,
1618
+ amount: args.amount
1619
+ };
1620
+ }
1383
1621
  function hyperliquidFloatToWire(value) {
1384
1622
  const n = typeof value === "number" ? value : Number.parseFloat(String(value).trim());
1385
1623
  if (!Number.isFinite(n)) throw new Error("Invalid Hyperliquid wire number.");
@@ -1625,6 +1863,57 @@ async function buildHyperliquidUpdateLeverageMultisign(args) {
1625
1863
  ]
1626
1864
  });
1627
1865
  }
1866
+ async function buildHyperliquidBorrowLendMultisign(args) {
1867
+ const { tokenIndex, coin } = await hyperliquidResolveSpotToken({
1868
+ chainId: args.chainId,
1869
+ coin: args.coin
1870
+ });
1871
+ const amount = args.amountMax === true ? null : parseHyperliquidBorrowLendAmount(args.amountHuman);
1872
+ if (amount == null && args.operation !== "withdraw" && args.operation !== "repay" && args.amountMax !== true) {
1873
+ throw new Error("amountHuman is required unless amountMax is true (full withdraw/repay).");
1874
+ }
1875
+ const action = buildHyperliquidBorrowLendAction({
1876
+ operation: args.operation,
1877
+ token: tokenIndex,
1878
+ amount
1879
+ });
1880
+ const nonce = args.nonce ?? Date.now();
1881
+ const isTestnet = args.chainId === 998;
1882
+ const typed = buildHyperliquidAgentTypedData({ action, nonce, isTestnet });
1883
+ return buildEip712Multisign({
1884
+ keyGen: args.keyGen,
1885
+ purposeText: args.purposeText,
1886
+ destinationChainID: String(args.chainId),
1887
+ destinationAddress: ZERO_ADDRESS,
1888
+ legs: [
1889
+ {
1890
+ typedData: {
1891
+ domain: typed.domain,
1892
+ types: typed.types,
1893
+ primaryType: typed.primaryType,
1894
+ message: typed.message
1895
+ },
1896
+ delivery: {
1897
+ kind: "hyperliquid_exchange",
1898
+ chainId: args.chainId,
1899
+ isTestnet,
1900
+ action,
1901
+ nonce
1902
+ },
1903
+ audit: {
1904
+ protocol: "hyperliquid",
1905
+ action: "borrowLend",
1906
+ operation: args.operation,
1907
+ coin,
1908
+ token: tokenIndex,
1909
+ amount,
1910
+ nonce,
1911
+ connectionId: typed.connectionId
1912
+ }
1913
+ }
1914
+ ]
1915
+ });
1916
+ }
1628
1917
 
1629
1918
  // src/protocols/evm/hyperliquid/multisign.ts
1630
1919
  function hasHyperliquidBracketTpsl(args) {
@@ -2217,6 +2506,19 @@ var hyperliquidProtocolModule = {
2217
2506
  marketKind: { type: "string", required: false, description: "perp (default) or spot" }
2218
2507
  }
2219
2508
  },
2509
+ {
2510
+ id: "hyperliquid.lend",
2511
+ protocolId: HYPERLIQUID_PROTOCOL_ID,
2512
+ chainCategory: "evm",
2513
+ description: "Hyperliquid Core borrow/lend via L1 /exchange EIP-712 (supply, withdraw, borrow, repay). Not CoreWriter.",
2514
+ commonParams: ["keyGen", "purposeText"],
2515
+ params: {
2516
+ coin: { type: "string", required: true, description: "Spot token e.g. USDC, USDT, HYPE, BTC/UBTC" },
2517
+ operation: { type: "string", required: true, description: "supply | withdraw | borrow | repay" },
2518
+ amountHuman: { type: "string", required: false, description: "Amount; omit or max for full withdraw/repay" },
2519
+ amountMax: { type: "boolean", required: false, description: "true = full amount (amount null on wire)" }
2520
+ }
2521
+ },
2220
2522
  {
2221
2523
  id: "hyperliquid.undelegate",
2222
2524
  protocolId: HYPERLIQUID_PROTOCOL_ID,
@@ -2276,6 +2578,8 @@ exports.buildEvmMultisignBodyHyperliquidUsdClassTransferBatch = buildEvmMultisig
2276
2578
  exports.buildEvmMultisignBodyHyperliquidVaultDepositBatch = buildEvmMultisignBodyHyperliquidVaultDepositBatch;
2277
2579
  exports.buildEvmMultisignBodyHyperliquidVaultWithdrawBatch = buildEvmMultisignBodyHyperliquidVaultWithdrawBatch;
2278
2580
  exports.buildHyperliquidAgentTypedData = buildHyperliquidAgentTypedData;
2581
+ exports.buildHyperliquidBorrowLendAction = buildHyperliquidBorrowLendAction;
2582
+ exports.buildHyperliquidBorrowLendMultisign = buildHyperliquidBorrowLendMultisign;
2279
2583
  exports.buildHyperliquidBridgeWithdrawMultisign = buildHyperliquidBridgeWithdrawMultisign;
2280
2584
  exports.buildHyperliquidLimitOrderWire = buildHyperliquidLimitOrderWire;
2281
2585
  exports.buildHyperliquidLimitOrderWithTpslMultisign = buildHyperliquidLimitOrderWithTpslMultisign;
@@ -2291,6 +2595,7 @@ exports.createHyperliquidL1ActionHash = createHyperliquidL1ActionHash;
2291
2595
  exports.hyperliquidApiBaseUrl = hyperliquidApiBaseUrl;
2292
2596
  exports.hyperliquidBridgeArbitrumChainId = hyperliquidBridgeArbitrumChainId;
2293
2597
  exports.hyperliquidBridgeConfig = hyperliquidBridgeConfig;
2598
+ exports.hyperliquidCanonicalLendCoin = hyperliquidCanonicalLendCoin;
2294
2599
  exports.hyperliquidCollectAllPerpMarkets = hyperliquidCollectAllPerpMarkets;
2295
2600
  exports.hyperliquidCollectHip3StockMarkets = hyperliquidCollectHip3StockMarkets;
2296
2601
  exports.hyperliquidCollectNativePerpMarkets = hyperliquidCollectNativePerpMarkets;
@@ -2298,13 +2603,18 @@ exports.hyperliquidEncodePx8 = hyperliquidEncodePx8;
2298
2603
  exports.hyperliquidEncodeUsd6 = hyperliquidEncodeUsd6;
2299
2604
  exports.hyperliquidEncodeWei8 = hyperliquidEncodeWei8;
2300
2605
  exports.hyperliquidFetchActiveAssetData = hyperliquidFetchActiveAssetData;
2606
+ exports.hyperliquidFetchAllBorrowLendReserveStates = hyperliquidFetchAllBorrowLendReserveStates;
2301
2607
  exports.hyperliquidFetchAllMids = hyperliquidFetchAllMids;
2608
+ exports.hyperliquidFetchBorrowLendReserveState = hyperliquidFetchBorrowLendReserveState;
2609
+ exports.hyperliquidFetchBorrowLendUserState = hyperliquidFetchBorrowLendUserState;
2302
2610
  exports.hyperliquidFetchCandles = hyperliquidFetchCandles;
2303
2611
  exports.hyperliquidFetchClearinghouseState = hyperliquidFetchClearinghouseState;
2304
2612
  exports.hyperliquidFetchDelegations = hyperliquidFetchDelegations;
2305
2613
  exports.hyperliquidFetchDelegationsForExecutor = hyperliquidFetchDelegationsForExecutor;
2306
2614
  exports.hyperliquidFetchDexList = hyperliquidFetchDexList;
2307
2615
  exports.hyperliquidFetchFrontendOpenOrders = hyperliquidFetchFrontendOpenOrders;
2616
+ exports.hyperliquidFetchLendMarketsSummary = hyperliquidFetchLendMarketsSummary;
2617
+ exports.hyperliquidFetchLendPositionsSummary = hyperliquidFetchLendPositionsSummary;
2308
2618
  exports.hyperliquidFetchMarketSnapshot = hyperliquidFetchMarketSnapshot;
2309
2619
  exports.hyperliquidFetchMarketSnapshotSummary = hyperliquidFetchMarketSnapshotSummary;
2310
2620
  exports.hyperliquidFetchMarketsSummary = hyperliquidFetchMarketsSummary;
@@ -2322,11 +2632,13 @@ exports.hyperliquidFetchPositionDisplayRows = hyperliquidFetchPositionDisplayRow
2322
2632
  exports.hyperliquidFetchPositionsForExecutor = hyperliquidFetchPositionsForExecutor;
2323
2633
  exports.hyperliquidFetchSpotClearinghouseState = hyperliquidFetchSpotClearinghouseState;
2324
2634
  exports.hyperliquidFetchSpotMeta = hyperliquidFetchSpotMeta;
2635
+ exports.hyperliquidFetchSpotTokens = hyperliquidFetchSpotTokens;
2325
2636
  exports.hyperliquidFetchStakingSummary = hyperliquidFetchStakingSummary;
2326
2637
  exports.hyperliquidFetchStakingSummaryForExecutor = hyperliquidFetchStakingSummaryForExecutor;
2327
2638
  exports.hyperliquidFetchStockMarketsSummary = hyperliquidFetchStockMarketsSummary;
2328
2639
  exports.hyperliquidFetchUsdClassBalances = hyperliquidFetchUsdClassBalances;
2329
2640
  exports.hyperliquidFetchUsdClassBalancesSummary = hyperliquidFetchUsdClassBalancesSummary;
2641
+ exports.hyperliquidFetchUserAbstraction = hyperliquidFetchUserAbstraction;
2330
2642
  exports.hyperliquidFetchUserVaultEquities = hyperliquidFetchUserVaultEquities;
2331
2643
  exports.hyperliquidFetchUserVaultEquitiesSummary = hyperliquidFetchUserVaultEquitiesSummary;
2332
2644
  exports.hyperliquidFetchVaultApysSummary = hyperliquidFetchVaultApysSummary;
@@ -2336,6 +2648,8 @@ exports.hyperliquidFloatToWire = hyperliquidFloatToWire;
2336
2648
  exports.hyperliquidInferDexFromCoin = hyperliquidInferDexFromCoin;
2337
2649
  exports.hyperliquidIsSpotAssetId = hyperliquidIsSpotAssetId;
2338
2650
  exports.hyperliquidL1TifFromKey = hyperliquidL1TifFromKey;
2651
+ exports.hyperliquidLendRoleFromLtv = hyperliquidLendRoleFromLtv;
2652
+ exports.hyperliquidManualBorrowEnabled = hyperliquidManualBorrowEnabled;
2339
2653
  exports.hyperliquidMarketSymbol = hyperliquidMarketSymbol;
2340
2654
  exports.hyperliquidOrderClosesPosition = hyperliquidOrderClosesPosition;
2341
2655
  exports.hyperliquidOrderCountsAsPendingClose = hyperliquidOrderCountsAsPendingClose;
@@ -2343,10 +2657,12 @@ exports.hyperliquidPendingCloseByCoin = hyperliquidPendingCloseByCoin;
2343
2657
  exports.hyperliquidPendingCloseForPosition = hyperliquidPendingCloseForPosition;
2344
2658
  exports.hyperliquidProtocolModule = hyperliquidProtocolModule;
2345
2659
  exports.hyperliquidResolveAsset = hyperliquidResolveAsset;
2660
+ exports.hyperliquidResolveLendTokenForChain = hyperliquidResolveLendTokenForChain;
2346
2661
  exports.hyperliquidResolveOhlcvWindow = hyperliquidResolveOhlcvWindow;
2347
2662
  exports.hyperliquidResolvePerpAsset = hyperliquidResolvePerpAsset;
2348
2663
  exports.hyperliquidResolvePerpMarket = hyperliquidResolvePerpMarket;
2349
2664
  exports.hyperliquidResolveSpotAsset = hyperliquidResolveSpotAsset;
2665
+ exports.hyperliquidResolveSpotToken = hyperliquidResolveSpotToken;
2350
2666
  exports.hyperliquidResolveTif = hyperliquidResolveTif;
2351
2667
  exports.hyperliquidSearchMarkets = hyperliquidSearchMarkets;
2352
2668
  exports.hyperliquidSearchMarketsSummary = hyperliquidSearchMarketsSummary;
@@ -2355,6 +2671,10 @@ exports.isHyperliquidBridgeArbitrumChainSupported = isHyperliquidBridgeArbitrumC
2355
2671
  exports.isHyperliquidBridgeArbitrumUsdcRow = isHyperliquidBridgeArbitrumUsdcRow;
2356
2672
  exports.isHyperliquidChainSupported = isHyperliquidChainSupported;
2357
2673
  exports.isHyperliquidHyperEvmUsdcRow = isHyperliquidHyperEvmUsdcRow;
2674
+ exports.mapHyperliquidLendMarketRows = mapHyperliquidLendMarketRows;
2675
+ exports.parseHyperliquidBorrowLendAmount = parseHyperliquidBorrowLendAmount;
2676
+ exports.parseHyperliquidBorrowLendReserveTuples = parseHyperliquidBorrowLendReserveTuples;
2677
+ exports.parseHyperliquidBorrowLendUserState = parseHyperliquidBorrowLendUserState;
2358
2678
  exports.validateHyperliquidTpslGeometry = validateHyperliquidTpslGeometry;
2359
2679
  //# sourceMappingURL=index.cjs.map
2360
2680
  //# sourceMappingURL=index.cjs.map