Leverage

xyz.spiralstake由 spiralstake.xyz 发布官方发布者v0.1.1更新于 Oct 24, 2026

Leveraged-yield router on Morpho. List strategies, simulate, and build UNSIGNED txs.

已验证Streamable HTTP可网页运行金融开发者工具

概览

AI 生成的概览

Leverage 是 Spiral Stake 在 Morpho 上杠杆收益策略的远程 MCP 服务器:列出策略、查询价格、模拟仓位并构建未签名交易。

可以做什么
按链或按 Morpho 市场 id 列出并查看可用的 Spiral 策略,包含 APY、杠杆阶梯、预言机类型、LTV 和退出流动性等原始风险数据。获取策略所用借款代币和抵押代币的当前美元价格。以只读方式模拟开立杠杆仓位或存入股票加收益的股权金库,无需钱包。从链上状态读取钱包的未平仓和已平仓仓位,包括 LTV、清算余量、杠杆和净值。构建用于开仓、调整、平仓或退出的未签名交易或调用批次,交由用户签名。
适用场景
适合需要研究或比较 Spiral Stake 杠杆收益策略、预览杠杆和股权金库结果,或为用户准备待签名未签名交易的场景。仅需代币价格或与 DeFi 无关的任务则不必使用。
运行要求
远程 streamable HTTP 端点,无需安装软件包。未声明身份验证、环境变量或请求头。服务器读取链上状态及上游价格和 APY 数据源,需要网络访问。签名和广播在用户自己的钱包中完成,不在此服务器。
安装前请注意
构建类工具会生成真正转移资金的交易,涉及借贷和杠杆,用户须在自己的钱包中审阅并签名。仓位存在清算风险,服务器只报告 LTV 和余量,不管理风险。模拟只是预览,不构成保证。价格和 APY 来自第三方来源,可能过期。服务器声明从不签名、发送或持有私钥。

安装

在 SourceWeft 中

  1. 打开 控制台中的 Leverage,将其添加到工作区。
  2. 为需要使用其工具的对话启用该服务。

Web executable,通过 Streamable HTTP。 远程服务在工作区中配置后即可从网页运行时运行。

交给智能体安装

把这段提示词粘贴到 Claude Code、Codex、Cursor 等智能体,或 SourceWeft 对话中。智能体会读取该服务器的安装指南,先向你展示发布者、端点和登录方式,经你同意后再把它添加到你的客户端。密钥不会写进任何命令。

阅读 https://sourceweft.com/mcp/xyz.spiralstake%2Fleverage/install.md,并按其中说明把这个 MCP 服务器接入我的客户端。修改任何配置之前,先告诉我它的发布者、端点和登录方式,等我确认。不要把 API 密钥写进命令或我会提交的文件;问我密钥应从哪里获取。

查看智能体所依据的安装指南

其他 MCP 客户端

把它添加到你客户端的 mcpServers 配置中。

{
  "mcpServers": {
    "leverage": {
      "type": "http",
      "url": "https://api.spiralstake.xyz/mcp"
    }
  }
}

README

Spiral Stake — mcp read-data backbone (Step 1a)

The composition authority + read API for Spiral Stake strategy data. It ports the app's client-side data composition server-side and serves it back as JSON, so three consumers run off one core:

  1. The app — the complete read surface it currently fetches, for a like-for-like Step-2 swap.
  2. Agents — the frozen /strategies contract.
  3. Partners (later) — a clean, versioned, self-documenting REST surface (OpenAPI).

Read-only. No contract writes, no tx building, no signing, no private keys. It composes numbers and serves JSON. The MCP tool layer, execution/build_*, and partner auth are later steps — the seams are pre-cut (core + http) but not built.


Architecture

src/  core/        pure composition — no I/O, unit-testable    leverage.ts        ← VERBATIM copy of v2-client/src/utils/leverage.ts (byte-diff gated)    apy.ts             collateral-APY resolution (Pendle/DeFiLlama/Royco/StableWatch/on-chain)    leverageApy.ts     30/60/90d leveraged-APY windows + lumpy-token smoothing    compose.ts         Market assembly from warm raw (port of FlashLeverage.createInstance)    strategy.ts        Market → frozen /strategies contract (ladder, freshness, spiralHints)    exitLiquidity.ts   exit-liquidity tier (the single verdict) + thresholds  sources/     one adapter per upstream (fetch + parse). native fetch + viem; no axios/wagmi  cache/       two-layer cache — RAW store (last-good) + warming policy (CONTRACT cadences)  warmer/      background scheduler (stale-while-revalidate); reads NEVER fetch  http/        thin hono REST layer (the only thing that knows about requests)  data/        static market config (copied from the app) + readMarkets port  config/      env (validated) + structured logger with correlation ids

Data flow: warmer fetches upstreams on the CONTRACT cadence → writes raw to the cache (last-good on failure) → core composes strategies from warm raw only → http serves them. A stale/failed upstream serves last-good with a visible stale age per field-group — never dropped, never coerced to 0.


Run

bash
cp .env.example .env      # fill in RPC + API keys (secrets via env only)npm installnpm run dev               # tsx watch; serves on :$PORT (default 8787)npm test                  # golden + parity gatesnpm run typecheck         # tsc --noEmitnpm run openapi           # (re)emit openapi.jsonnode --import tsx scripts/smoke.ts   # live: prime + print one composed strategy

/health (liveness + cache diagnostics) and /ready (503 until the warmer primes the required data) are available immediately on boot.


Endpoints — app-read inventory → endpoint mapping

Every data read the app performs in v2-client/src/api-services/* maps to an endpoint here (positions stay on the dashboard backend and are not reimplemented):

App read (api-services/*)mcp endpoint
getTokenApy, getAllMorphoMarketsData, fetchMerklSpotIncentives, prices, on-chain value → composed marketsGET /v1/strategies, GET /v1/strategies/:id
FlashLeverage.createInstance → the app's full client-side Market[] compositionGET /v1/app/markets (raw domain model; BigNumber→{"$bn":…}, bigint→{"$bigint":…} — revive before use)
morpho.ts getAllBorrowApyHistories / getBorrowApyHistoryGET /v1/markets/borrow-apy-history, GET /v1/markets/:id/borrow-apy-history
apy.ts resolveTokenApyHistory (DeFiLlama/Royco/StableWatch history), chart.ts getApyChartGET /v1/collateral/apy-history, GET /v1/collateral/:id/apy-history
merkl.ts fetchMerklIncentiveData (borrow-incentive APR history)GET /v1/markets/:id/incentive-history
token.ts getAllLoanTokenPrices / getTokenPriceGET /v1/prices
chart.ts getMarketChart (CoinGecko price chart)GET /v1/prices/chart?coinId=&days=&currency= (on-demand proxy)
chart.ts getDexOhlcv (DEX price chart for tokens with no CoinGecko/TradingView chart, e.g. CASHCAT/PONS on Robinhood)GET /v1/prices/ohlcv?chainId=&token=&timeframe=&aggregate=&limit= (on-demand GeckoTerminal proxy, 30s cache, last-good on failure; COINGECKO_PRO_API_KEY lifts the rate limit)
dashboard.ts getApySnapshot (StableWatch stable APY)GET /v1/stable-apy — fetched directly from StableWatch as a warmed upstream; the mcp owns this data now and no longer depends on the dashboard /apy endpoint
— (protocol-level, not an app read)GET /v1/tvl — protocol TVL across all supported chains, warmed every 5m from on-chain positions: tvlUsd = net user equity (collateral − debt, the DefiLlama TVL), grossTvlUsd = total looped collateral, borrowedUsd = total debt, plus positions/users; 503 until the first chain is computed
swap/meta-dex aggregators, referral, positionsout of scope (execution / backend domains)

Cross-cutting: /v1 versioning, CORS limited to CORS_ORIGINS, a consistent error envelope ({ error: { code, message, correlationId } }), a correlation id per request (echoed as x-correlation-id), structured JSON logs, and an OpenAPI 3.1 spec at /openapi.json (+ committed openapi.json).


Parity gates

  1. leverage.ts golden-vector — test/golden/leverage.golden.test.ts freezes fixed inputs → exact outputs; leverage.parity.test.ts asserts the file is a byte-for-byte copy of the app's leverage.ts. This locks every APY/LTV/ladder number to the app.
  2. /strategies composition — test/parity/strategies.compose.test.ts seeds the raw cache with a controlled fixture and asserts the composed contract field-by-field (sourcing, LTV math, ladder via the verbatim leverage.ts, freshness cadences, null-vs-absent, spiralHints isolation). Runs offline in CI.
  3. Live golden-set + app-surface parity — scripts/capture-parity.ts primes the warmer against real upstreams and writes the composed /strategies (+ apy/borrow histories) for a fixed market set to test/fixtures/. The parity diff vs the app is produced by feeding the same fixed inputs to the app's client-side composition and comparing (the app logs its composed markets); the PR commits the fixtures and the empty diff. This is the gate that lets us offload TVL safely.

Frozen decisions (parity-critical)

  • bignumber.js pinned to the app's 9.3.1; no global BigNumber.config change → toFixed(2) / rounding (ROUND_HALF_UP) identical.
  • On-chain reads via viem replace wagmi: getCollateralValueInLoanToken (multicall3), stUSDS str(), spUSDG vsr() (chain 4663). The app's (intentionally lossy) BigInt(liqLtv) from the JSON number is matched exactly, not "fixed".
  • maxLeverage = calcLeverage(maxLtv); defaultLeverage = calcLeverage(safeLtv), safeLtv = maxLtv% − 0.75 — exactly as the app derives them. Ladder = integer steps 1x … ⌊maxLeverage⌋ (LTV =(1 − 1/lev)·100) then the exact max.
  • Exit slippage is baked into collateralTokens.json by the app's weekly refresh script; its file mtime is the exitLiquidity.asOf. The tier (the only verdict) lives in spiralHints with its thresholds; raw slippagePct stays under exitLiquidity, null (no route) preserved.

来源:README.md,提交 914e845

工具

10

list_strategies

List Strategies

List eligible Spiral strategies on a chain with raw risk facts (collateral/borrow APY, leverage ladder, oracle type, exit liquidity, LTVs, curator). Mainnet (1): correlated yield loops on stables, ETH, BTC and Pendle PTs. Robinhood Chain (4663): stable loops on USDG, directional perps (spiralHints.profile 'leveraged_perp' — APYs are financing carry only) and stock + yield equity vaults (profile 'equity_yield_vault', ids start with 'equity-'). Optionally filter by collateral category.

输入参数chainIdcategory

get_strategy

Get Strategy

Get one eligible strategy's full raw facts by its Morpho market id.

输入参数id必填chainId

get_prices

Get Prices

Current USD prices of every loan and collateral token the chain's strategies use (token address -> USD), including equity-vault stocks. Loan tokens are priced from CoinGecko; collateral from the market oracle × its loan token's price — the same figures the strategies' priceUsd fields carry.

输入参数chainId

simulate_leverage

Simulate Leverage

Preview opening a leveraged position — deterministic, read-only, no wallet needed. Returns the resulting leverage, effective LTV, leveraged collateral, expected leveraged APY, price impact, the auto-selected execution path, flash-loan size, and (if the flash loan exceeds direct market liquidity) the public-allocator reallocation fee. Numbers move with market prices.

输入参数amount必填chainIdleveragepayToken必填slippagedesiredLtvstrategyId必填

build_leverage_tx

Build Leverage Transaction

Build the UNSIGNED transaction to open a leveraged position, for the given wallet to sign. Non-custodial: this server never signs, sends, or holds keys. The canonical output is the executable { approvals[], tx{to,data,value} } — sign and broadcast it directly (approvals first), plus the same position preview as simulate_leverage. meta.signingUrl is an optional one-click link for a human to sign in their own wallet. The embedded swap calldata is time-sensitive (see meta.expiresAt) — rebuild if stale.

输入参数amount必填chainIdleveragepayToken必填slippagedesiredLtvstrategyId必填userAddress必填

get_positions

Get Positions

Read a wallet's open/closed Spiral leverage positions from chain state (read-only). For each: collateral/loan, leveraged collateral, net equity, debt, current LTV vs liquidation LTV (with headroom), current leverage, net USD value, and current leveraged APY. No cost-basis / realized P&L (those need off-chain history). Newest first. `equityPositions` lists the wallet's open equity vaults (stock leg + the yield loop(s) it funds); those loops are excluded from `positions`.

输入参数chainIduserAddress必填

build_manage_tx

Build Manage Transaction

Build the UNSIGNED transaction to adjust or close an OPEN position, for the given wallet to sign. Non-custodial (never signs/holds keys). Canonical output is the executable { approvals[], tx{to,data,value} } (sign/broadcast directly); meta.signingUrl is an optional link for a human to sign in their own wallet. Actions: 'close' (unwind fully), 'increase_leverage' (borrow to a higher LTV), 'add_collateral' (top up — pay in collateral or any token), 'remove_collateral' (withdraw), 'repay' (pay down debt; set full=true to clear it), 'borrow' (draw more loan token). Get the position `id` from get_positions. Swap calldata (close/increase/zap paths) is time-sensitive — see meta.expiresAt.

输入参数id必填fullaction必填amountchainIdleveragepayTokenslippagedesiredLtvuserAddress必填

simulate_equity_deposit

Simulate Equity Vault Deposit

Preview depositing USDG into a stock + yield equity vault — deterministic, read-only, no wallet. You end up 1x long the stock (held as your own Morpho collateral), with `stockLtvPct` of its value borrowed as USDG and flash-looped into the vault's yield strategy. Returns the stock received, the borrow, the stock liquidation price and headroom, the yield leg's size/leverage/APY, the net APY at that LTV, fees and price impact per leg.

输入参数amount必填chainIdslippagestrategyId必填stockLtvPct

build_equity_deposit_tx

Build Equity Vault Deposit

Build the UNSIGNED call batch to deposit into a stock + yield equity vault, for the given wallet to sign. Non-custodial. Returns `calls[]` (approve USDG → router, authorize the router on Morpho, the one-call equityEntry, revoke) to submit as ONE atomic batch (EIP-5792 wallet_sendCalls / Safe), plus the same preview as simulate_equity_deposit. meta.signingUrl is a one-click link for a human to sign in the app. Swap calldata is time-sensitive (meta.expiresAt).

输入参数amount必填chainIdslippagestrategyId必填stockLtvPctuserAddress必填

build_equity_exit_tx

Build Equity Vault Exit

Build the UNSIGNED call batch to fully unwind an OPEN equity vault (from get_positions.equityPositions): close each of its yield loops, then one self-funded router call repays the stock debt, withdraws the stock, swaps it to USDG and returns the proceeds. Submit as ONE atomic batch. Non-custodial; the vault's yield loop cannot be closed alone through build_manage_tx. Only the vault's own loop(s) are closed: those get_positions attributes unambiguously, or exactly the ones you pass in yieldPositionIds. Always read meta.closedYieldPositionIds.

输入参数chainIdslippagestrategyId必填userAddress必填yieldPositionIds

版本历史

1
  1. v0.1.1最新Sep 16, 2026

评分

已满足适用检查项的 90%

该评分衡量此收录条目的完整程度,依据注册中心条目、端点与公开来源计算得出。它不是对服务器本身的评价,也不表示服务器安全或当前可用:可连通性是带日期的检查结果,评分也不包含安装量或用户评价。

  • 近 30 天内可连通必需25 分
  • 已声明认证方式必需10 分
  • 已列出工具必需15 分
  • 描述必需15 分
  • 图标10 分
  • 文档15 分
  • 许可证10 分

    请在仓库或注册中心条目中声明许可证。