@anywalletkit/protocol-staking-lido-evm

中文文档
0.3.11发布于 2026/11/03Apache-2.0TypeScriptESM + CJS构建来源已验证近 30 天下载 2196

A simple package that lets @anywalletkit/wallet-evm wallet accounts stake through the Lido protocol: stake, two-phase queue withdrawals (permit-first), wrap/unwrap, rewards.

原始使用文档
文档目录7 节
  1. Install
  2. Usage
  3. Why the withdrawal path looks the way it does
  4. Configuration
  5. The interface
  6. Tests
  7. Activity

@anywalletkit/protocol-staking-lido-evm

npm

A simple package that lets @anywalletkit/wallet-evm wallet accounts stake through the Lido protocol: stake ETH → stETH, exit through the two-phase withdrawal queue, wrap/unwrap the non-rebasing wstETH form, and read APR and reward history.

Install

npm install @anywalletkit/protocol-staking-lido-evm @anywalletkit/core
# or: pnpm add @anywalletkit/protocol-staking-lido-evm @anywalletkit/core  ·  yarn add @anywalletkit/protocol-staking-lido-evm @anywalletkit/core

On npm: @anywalletkit/protocol-staking-lido-evm, published from the release workflow with provenance.

Built as the first implementation of the StakingProtocol type in @anywalletkit/core. The base class lives in @anywalletkit/core; src/staking-protocol.ts keeps the runtime IStakingProtocol marker and the option / result types this module documents. See "The interface" below for why staking is not lending.

The mechanics are extracted from a production wallet (web + React Native/Hermes) where every flow is exercised with real funds.

Written in TypeScript on viem (the only runtime dependency) and built with tsup to dist/ (ESM + CJS + .d.ts).

Usage

import WalletManagerEvm from '@anywalletkit/wallet-evm'
import LidoProtocolEvm from '@anywalletkit/protocol-staking-lido-evm'

const wallet = new WalletManagerEvm(seed, { provider: 'https://rpc.example.org' })
const account = await wallet.getAccount(0)

const lido = new LidoProtocolEvm(account, {
  referral: '0x…' // optional: Lido Rewards-Share referral, defaults to zero address
})

// Stake — stETH lands on the account 1:1
const { hash, fee } = await lido.stake({ amount: 10n ** 18n })

// Exit, phase 1: queue the withdrawal (permit-first — ONE transaction)
await lido.requestWithdrawal({ amount: 10n ** 18n, token: 'stETH' })

// …days later — exit, phase 2: claim finalized requests as ETH
const { claimableIds } = await lido.getWithdrawalRequests()
if (claimableIds.length) await lido.claimWithdrawals({ ids: claimableIds })

// Views
await lido.getStakedBalance() // { balance, wrappedBalance, rate, total }
await lido.getApr()           // 2.72 (percent, 7d SMA)

Lido-specific extras beyond the interface:

await lido.wrap({ amount })                 // stETH → wstETH (approve awaited + wrap)
await lido.unwrap({ amount })               // wstETH → stETH (single tx)
await lido.getWithdrawalEta(ids)            // Map<id, seconds> from Lido's queue API
await lido.getRewards()                     // lifetime rewards + average APR
await lido.getRewardHistory({ limit: 14 })  // daily rebase events, newest first

Why the withdrawal path looks the way it does

Every one of these choices was paid for in production:

  • Permit-first: requestWithdrawal signs one EIP-2612 permit and rides it inside requestWithdrawalsWithPermit — a single transaction (and on mobile, a single biometric prompt) instead of approve + request.
  • Proven before broadcast: the permit path is simulated with eth_call first. A bad signature must fall back, not burn gas.
  • The fallback awaits its approval: in the approve + request path the approval is waited to a mined receipt, because the request's gas estimate reverts against an unmined allowance.
  • Verified permit domains: stETH signs as version "2", wstETH as version "1" — both checked against the tokens' on-chain DOMAIN_SEPARATOR. A wrong version recovers to a different signer and reverts with no readable reason.
  • Per-request caps: the queue takes at most 1000 stETH per request; over-cap amounts split into several requests inside the same transaction (wstETH capped at 800 per request — 1000 is stETH-equivalent and the rate drifts upward).
  • Up-front guards: stake checks isStakingPaused and getCurrentStakeLimit before estimating gas, because the raw revert carries no readable reason for either.
  • Structural account checks: writability is typeof account.sendTransaction === 'function', not instanceof — a duplicated copy of the account package fails instanceof while the account works fine.
  • No AbortSignal.timeout / AbortSignal.any: Hermes (React Native) ships AbortController but not those statics; nothing here depends on them.
  • REST endpoints are configuration: APR, queue ETAs and reward history come from Lido's public frontend APIs (eth-api.lido.fi, wq-api.lido.fi, reward-history-backend.lido.fi), all overridable via config.endpoints. On-chain flows never depend on them: ETA and rewards are decoration and degrade to empty results, never throws.

Configuration

new LidoProtocolEvm(account, {
  provider,       // RPC url or EIP-1193; defaults to the account's provider
  chainId,        // default 1; other chains must supply the fields below
  referral,       // forwarded to submit() — Lido Rewards-Share integrators earn on stake flow
  addresses,      // { stEth, wstEth, withdrawalQueue }
  permitDomains,  // { stEth: { name, version }, wstEth: { name, version } }
  endpoints       // { apr, withdrawalQueueApi, rewardHistory }
})

Only mainnet ships as a default deployment — deliberately. Testnets (e.g. Hoodi) must be configured explicitly so nobody stakes against an unverified address a default quietly supplied.

The interface

IStakingProtocol: stake / quoteStake, requestWithdrawal / quoteRequestWithdrawal, getWithdrawalRequests, claimWithdrawals / quoteClaimWithdrawals, getStakedBalance, getApr.

Staking is not lending: a lending withdraw is synchronous, while unstaking is a two-phase exchange — a request enters a queue, finalizes out of band (usually days), and only then can be claimed for the native token. Modelling that as ILendingProtocol.withdraw would produce a method that returns with no money received, and would stub out borrow/repay as unsupported. The honest interface names the queue. Wrap/unwrap, ETAs and reward history stay provider-specific extras so the core stays implementable by other liquid staking protocols.

Tests

pnpm build            # tsup → dist/
pnpm test             # offline unit + conformance tests (vitest, stubbed EIP-1193 provider)
pnpm verify:live      # read-only checks against mainnet (views, REST, eth_call simulation; needs dist/)

Activity

describeActivity(tx, { own }) labels Lido transactions for a wallet's history, offline and synchronously. A transaction is Lido's when it calls one of the three contracts the instance is configured with (stEth, wstEth, withdrawalQueue — mainnet by default) on that chain, and the selector is: stETH submit → stake "Staked ETH"; wstETH wrap → wrap "Wrapped stETH", unwrap → unwrap "Unwrapped wstETH"; WithdrawalQueue requestWithdrawals / …WithPermit / …WstETH / …WstETHWithPermit → unstake "Requested withdrawal", claimWithdrawals / claimWithdrawalsTo / claimWithdrawal → claim "Claimed ETH". Selectors are computed from the signatures at module load (LIDO_ACTIONS). approve / transfer on stETH or wstETH are not Lido operations and yield null, as does everything else. Subtitle "Lido · Ethereum", counterparty the contract called; assetsIn / assetsOut are the wallet's net movements from the receipt with stETH / wstETH / unstETH labelled by the module.

Fixtures in fixtures/activity/ are the test wallet's funded run (submit, wrap, unwrap, requestWithdrawalsWithPermit, claimWithdrawals; 2026-08-31 … 09-04); negatives/ holds an SSV stake and a USDT approve.

版本与发布记录

@anywalletkit/protocol-staking-lido-evm 共发布 12 个版本,首次发布于 2026/10/25;过去 12 个月发布了 12 个版本。最新版本附带 npm provenance 构建来源证明,可追溯到公开的 CI 构建记录。

版本发布日期距今
0.3.11latest2026/11/035 天前
0.3.102026/10/309 天前
0.3.92026/10/2910 天前
0.3.82026/10/2811 天前
0.3.72026/10/2712 天前
0.3.62026/10/2612 天前

关于 @anywalletkit/protocol-staking-lido-evm 的常见问题

@anywalletkit/protocol-staking-lido-evm 是什么?

A simple package that lets @anywalletkit/wallet-evm wallet accounts stake through the Lido protocol: stake, two-phase queue withdrawals (permit-first), wrap/unwrap, rewards.

如何安装 @anywalletkit/protocol-staking-lido-evm?

在项目目录运行 npm install @anywalletkit/protocol-staking-lido-evm,或使用 pnpm add / yarn add / bun add。它还需要宿主项目提供 peer 依赖:@anywalletkit/core(0.8.0)。npm 7 及以上与 pnpm 8 及以上默认会自动安装必需的 peer 依赖,Yarn 需要手动安装。

@anywalletkit/protocol-staking-lido-evm 支持 TypeScript 吗?

支持。包内自带 TypeScript 类型声明(package.json 声明了 types 入口),安装后即可获得类型提示,无需再安装 @types 包。

@anywalletkit/protocol-staking-lido-evm 支持 ESM 还是 CommonJS?

同时提供 ES Module 与 CommonJS 入口,import 和 require() 都可以使用,打包工具会自动选择合适的版本。

@anywalletkit/protocol-staking-lido-evm 需要什么版本的 Node.js?

package.json 的 engines 字段要求 Node.js >=22。版本不符时 npm 默认只给出警告,开启 engine-strict 后会拒绝安装。

@anywalletkit/protocol-staking-lido-evm 可以商用吗?

@anywalletkit/protocol-staking-lido-evm 使用 Apache-2.0 许可。宽松许可:允许商业使用、修改和再分发,并附带明确的专利授权;分发时需保留许可与 NOTICE 文件,修改过的文件要注明改动。以上为概括,不构成法律意见,请以许可原文为准。

@anywalletkit/protocol-staking-lido-evm 的下载量有多少?

根据 npm 官方下载统计,@anywalletkit/protocol-staking-lido-evm 在 2026/10/06 – 2026/11/04 这 30 天内被下载 2,196 次,日均约 73 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入,适合横向比较热度,不能直接等同于使用人数。

@anywalletkit/protocol-staking-lido-evm 还在维护吗?

最新版本 0.3.11 发布于 2026/11/03(5 天前);至今共发布 12 个版本,其中过去 12 个月发布了 12 个;首次发布于 2026/10/25。发布频率只是参考信号:功能稳定的工具可能很少需要更新,建议结合源码仓库的 issue 和提交记录判断。