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 分

    請在儲存庫或註冊中心條目中宣告授權條款。