stakingverse-ethereum

Stake ETH on StakeWise (Ethereum liquid staking). Use when the user wants to stake ETH, unstake ETH, or check staked positions on StakeWise V3 vaults. Supports state updates via keeper and harvest proofs from subgraph.

Safety Notice

This listing is from the official public ClawHub registry. Review SKILL.md and referenced scripts before running.

Copy this and send it to your AI assistant to learn

Install skill "stakingverse-ethereum" with this command: npx skills add LUKSOAgent/stakingverse-ethereum

StakeWise Ethereum Staking Skill

Stake ETH on StakeWise V3 and receive osETH (liquid staking token). Earn staking rewards while keeping your ETH liquid.

What This Skill Does

  • Stake ETH → Receive osETH tokens (handles state updates automatically)
  • Unstake ETH → Burn osETH for ETH
  • Check staked position → View vault shares and earned rewards
  • Monitor vault state → Check if keeper state update is required
  • Query harvest proofs → Get Merkle proofs from subgraph for deposits

Required Credentials

Set these environment variables or edit the scripts:

export STAKEWISE_VAULT="0x8A93A876912c9F03F88Bc9114847cf5b63c89f56"
export KEEPER="0x6B5815467da09DaA7DC83Db21c9239d98Bb487b5"
export PRIVATE_KEY="your_private_key"
export MY_ADDRESS="your_address"
export RPC_URL="https://ethereum-rpc.publicnode.com"

Quick Start

# Stake 0.1 ETH (auto-handles state updates)
node scripts/stake.mjs 0.1

# Check staked position
node scripts/position.js

# Unstake 0.05 osETH
node scripts/unstake.js 0.05

# Check if state update required
node scripts/check-state.js

How StakeWise V3 Works

Architecture Overview

StakeWise V3 uses a keeper-oracle pattern for state updates:

User (EOA/UP)
    ↓
Vault Contract
    ↓
Keeper (Oracle) - Validates and processes rewards
    ↓
osETH Token - Liquid staking token

Key Components

ComponentAddressPurpose
Vault0x8A93A876912c9F03F88Bc9114847cf5b63c89f56Staking/unstaking logic
Keeper0x6B5815467da09DaA7DC83Db21c9239d98Bb487b5Oracle for state updates
osETH TokenDynamic per vaultLiquid staking token
Subgraphhttps://graphs.stakewise.io/mainnet-a/subgraphs/name/stakewise/prodHarvest proofs and data

The State Update Mechanism

Why state updates?

  • StakeWise accumulates rewards off-chain via validators
  • Keeper periodically "harvests" and posts state on-chain
  • Users can only deposit when state is current

When is state update required?

const vault = new ethers.Contract(vaultAddress, vaultAbi, provider);
const needsUpdate = await vault.isStateUpdateRequired();
// true = must update state before depositing

Staking Flow (With State Update)

Step 1: Check State
    User
      ↓
    vault.isStateUpdateRequired()
      ↓
    Returns: true (update needed)

Step 2: Query Subgraph for Harvest Params
    User
      ↓
    POST to StakeWise subgraph
      ↓
    Returns: rewardsRoot, reward, unlockedMevReward, proof[]

Step 3: Update State and Deposit
    User
      ↓
    vault.updateStateAndDeposit(harvestParams, receiver, referrer)
      ↓
    Keeper validates harvest
      ↓
    Vault mints osETH to receiver
      ↓
    User receives osETH

Detailed Usage

Stake ETH (Full Flow with State Update)

import { ethers } from 'ethers';
import fetch from 'node-fetch';

// Setup
const provider = new ethers.JsonRpcProvider(process.env.RPC_URL);
const wallet = new ethers.Wallet(process.env.PRIVATE_KEY, provider);

// Vault ABI (minimal)
const VAULT_ABI = [
  'function isStateUpdateRequired() view returns (bool)',
  'function updateStateAndDeposit(tuple(bytes32 rewardsRoot, uint256 reward, uint256 unlockedMevReward, bytes32[] proof) harvestParams, address receiver, address referrer) external payable',
  'function deposit(address receiver, address referrer) external payable'
];

const vault = new ethers.Contract(
  process.env.STAKEWISE_VAULT,
  VAULT_ABI,
  wallet
);

// Amount to stake
const stakeAmount = ethers.parseEther('0.1'); // 0.1 ETH

// Step 1: Check if state update required
const needsUpdate = await vault.isStateUpdateRequired();
console.log('State update required:', needsUpdate);

if (needsUpdate) {
  // Step 2: Query subgraph for harvest params
  const subgraphQuery = {
    query: `
      query getHarvestProofs($vault: String!) {
        harvestProofs(
          where: { vault: $vault }
          orderBy: blockNumber
          orderDirection: desc
          first: 1
        ) {
          rewardsRoot
          reward
          unlockedMevReward
          proof
        }
      }
    `,
    variables: {
      vault: process.env.STAKEWISE_VAULT.toLowerCase()
    }
  };

  const response = await fetch('https://graphs.stakewise.io/mainnet-a/subgraphs/name/stakewise/prod', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify(subgraphQuery)
  });

  const data = await response.json();
  const harvestProof = data.data.harvestProofs[0];

  // Step 3: Call updateStateAndDeposit
  const harvestParams = {
    rewardsRoot: harvestProof.rewardsRoot,
    reward: BigInt(harvestProof.reward),
    unlockedMevReward: BigInt(harvestProof.unlockedMevReward),
    proof: harvestProof.proof
  };

  const tx = await vault.updateStateAndDeposit(
    harvestParams,
    process.env.MY_ADDRESS,  // receiver
    ethers.ZeroAddress,       // referrer (optional)
    { value: stakeAmount }
  );

  const receipt = await tx.wait();
  console.log(`Staked ${ethers.formatEther(stakeAmount)} ETH with state update`);
  console.log(`Transaction: ${receipt.hash}`);
} else {
  // Simple deposit (no state update needed)
  const tx = await vault.deposit(
    process.env.MY_ADDRESS,
    ethers.ZeroAddress,
    { value: stakeAmount }
  );

  const receipt = await tx.wait();
  console.log(`Staked ${ethers.formatEther(stakeAmount)} ETH`);
  console.log(`Transaction: ${receipt.hash}`);
}

Check Staked Position

const OSETH_ABI = [
  'function balanceOf(address) view returns (uint256)',
  'function convertToAssets(uint256 shares) view returns (uint256)'
];

// Get osETH token address from vault
const osEthAddress = await vault.osToken();
const osEth = new ethers.Contract(osEthAddress, OSETH_ABI, provider);

const osEthBalance = await osEth.balanceOf(process.env.MY_ADDRESS);
const underlyingEth = await osEth.convertToAssets(osEthBalance);

console.log(`osETH Balance: ${ethers.formatEther(osEthBalance)}`);
console.log(`Equivalent ETH: ${ethers.formatEther(underlyingEth)}`);

Unstake ETH

const VAULT_FULL_ABI = [
  'function redeem(uint256 shares, address receiver, address owner) returns (uint256 assets)',
  'function maxRedeem(address owner) view returns (uint256)'
];

const vaultFull = new ethers.Contract(
  process.env.STAKEWISE_VAULT,
  VAULT_FULL_ABI,
  wallet
);

// Check max redeemable
const maxShares = await vaultFull.maxRedeem(process.env.MY_ADDRESS);
console.log(`Max redeemable: ${ethers.formatEther(maxShares)} osETH`);

// Redeem shares for ETH
const sharesToRedeem = ethers.parseEther('0.05');
const tx = await vaultFull.redeem(
  sharesToRedeem,
  process.env.MY_ADDRESS,  // receiver
  process.env.MY_ADDRESS   // owner
);

const receipt = await tx.wait();
console.log(`Redeemed ${ethers.formatEther(sharesToRedeem)} osETH for ETH`);
console.log(`Transaction: ${receipt.hash}`);

Subgraph Queries

Get Latest Harvest Proof

const query = {
  query: `
    query {
      harvestProofs(
        orderBy: blockNumber
        orderDirection: desc
        first: 1
      ) {
        id
        vault
        rewardsRoot
        reward
        unlockedMevReward
        proof
        blockNumber
      }
    }
  `
};

const response = await fetch('https://graphs.stakewise.io/mainnet-a/subgraphs/name/stakewise/prod', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify(query)
});

const data = await response.json();
console.log(data.data.harvestProofs[0]);

Get Vault State

const query = {
  query: `
    query {
      vaults(first: 1) {
        id
        address
        totalAssets
        totalShares
        apr
      }
    }
  `
};

Common Issues

"State update required"

  • The keeper hasn't posted recent rewards
  • Query subgraph for latest harvest proof
  • Use updateStateAndDeposit() instead of deposit()

"Invalid harvest proof"

  • Proof may be outdated
  • Always query subgraph immediately before depositing
  • Proofs are block-specific

"Insufficient shares"

  • Trying to redeem more osETH than you have
  • Check balance: osETH.balanceOf(yourAddress)

"Vault is paused"

  • Emergency pause may be active
  • Check: vault.paused()
  • Wait for StakeWise team to unpause

Important Notes

  • APY varies: Based on Ethereum validator rewards, typically 3-5%
  • osETH is rebasing: Balance increases automatically as rewards accrue
  • Keeper dependency: Deposits require valid state (keeper must be active)
  • Gas costs: State updates cost more gas than simple deposits
  • MEV rewards: Part of harvest includes MEV extraction rewards

Resources

Source Transparency

This detail page is rendered from real SKILL.md content. Trust labels are metadata-based hints, not a safety guarantee.

Related Skills

Related by shared tags or category signals.

General

Session-Memory Enhanced

Session-Memory Enhanced v4.0 - 统一增强版。融合 session-memory + memu-engine 核心功能。特性:结构化提取 + 向量检索 + 不可变分片 + 三位一体自动化 + 多代理隔离 + AI 摘要 + 零配置启动。

Registry SourceRecently Updated
General

PRISM-GEN-DEMO

English: Retrieve, filter, sort, merge, and visualize multiple CSV result files from PRISM-Gen molecular generation/screening. Provides portable query-based...

Registry SourceRecently Updated
General

Video Pro by cza999

专业AI视频生成器,支持文本转高质量短视频,批量处理、多模板和高级自定义语音功能,适合创作者和企业。

Registry SourceRecently Updated
0133
cza999