@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.
- package/dist/agent/catalog.cjs +130 -0
- package/dist/agent/catalog.cjs.map +1 -1
- package/dist/agent/catalog.d.ts +183 -1
- package/dist/agent/catalog.js +126 -1
- package/dist/agent/catalog.js.map +1 -1
- package/dist/agent/skills/hyperliquid/SKILL.md +32 -2
- package/dist/agent/skills/yield-compare/SKILL.md +4 -1
- package/dist/protocols/evm/hyperliquid/index.cjs +320 -0
- package/dist/protocols/evm/hyperliquid/index.cjs.map +1 -1
- package/dist/protocols/evm/hyperliquid/index.d.ts +153 -1
- package/dist/protocols/evm/hyperliquid/index.js +303 -1
- package/dist/protocols/evm/hyperliquid/index.js.map +1 -1
- package/package.json +1 -1
|
@@ -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`**.
|
|
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
|