LogoLogo
WalletsEcosystemStart BuildingJoin the Community
  • Welcome to IoTeX 2.0
    • 💡Why IoTeX
    • 🪙Tokenomics
      • IOTX Utility in IoTeX 2.0
      • IOTX Emission, Deflation, and Re-Staking
    • 📖Whitepaper
    • ⚡Get Started
  • DePIN Infra Modules (DIM)
    • DIMs Overview
    • [IoTeX L1] DePIN Blockchain
      • Core Concepts
        • Consensus Mechanism
        • Voters and Delegates
        • Ethereum Virtual Machine
        • Accounts & Identities
        • Blockchain Actions
        • ERC20 and NFT Tokens
        • Smart Contracts
        • Interoperability
        • Governance
      • The IOTX Token
        • IOTX Token Exchange Support
        • Different Formats of the IOTX Token
        • IOTX Token Contracts
      • Wallets
        • Supported Wallet Apps
          • ioPay Mobile
          • IoTeX Web Wallet
          • OKX Wallet
          • Rabby Wallet
          • Metamask Desktop
          • Ledger Nano S & X
            • Use Ledger with Metamask
            • Use Ledger with Rabby Walet
            • Use Ledger with IoTeX Hub Portal
            • Migrate to the Ethereum Ledger App
          • IoTeX Desktop Wallet
          • 👩‍💻IoTeX HD Derivation Path
        • Buy IOTX Tokens
        • Execute Transactions
          • Transfer IOTX Tokens
          • Transfer ERC20 Tokens
          • Interact with Dapps
          • Explore transactions
        • Migrate Assets to a different wallet
      • Staking & Governance
        • About IoTeX Staking
        • IoTeX Staking Guide
          • Native staking
          • Staking as NFT
        • Join the Governance
          • Marshall DAO
          • Improvement Proposals
      • Exchange Integration
      • 👨‍💻Deploy Dapps on IoTeX
    • [ioID] DePIN Identities
      • ioID Specification
      • Overview of ioID
      • Registering Identities
      • 👩‍💻Integration Guide
        • Register a DePIN Project
        • Bind your Device NFT
        • Reserve Device ioIDs
        • Query Project Status
        • Register a Device
        • ioID Smart contracts quick reference
    • [W3bstream] DePIN Verification
      • Overview of W3bstream
      • Multi-Prover Architecture
      • 👨‍💻Build with W3bstream
        • Get Started
          • Sequencer Options
        • Build the Prover Code
          • Risc Zero
          • Halo2
          • zkWASM
        • Deploy to W3bstream
          • Create the Project File
          • W3bstream Outputs
          • Deploying Projects
          • Interacting with Projects
        • On-chain integration
          • Verify Risc0 Proofs
          • Verify Halo2 Proofs
          • Verify zkWASM profs
        • Sending Messages
      • 👩‍💻Node Operators
        • Configure a ZK Prover Node
        • Register your Node
    • [ioID-SDK] Hardware SDK
      • ioID-SDK Overview
      • Layered Architecture
      • Compatibility
      • Current Development Status
    • [MSP] Modular Security Pool
    • Third-Party DIMs
      • Data Sequencer Infras
      • Data Availability Infras
      • 👨‍💻W3bstream Tasks
  • Ecosystem
    • Assets on IoTeX
      • Mainstream Assets
      • IOTX and Derivatives
      • DePIN Tokens
      • MEME Coins
    • iotube Bridge
    • iotexscan Explorer
    • Ecosystem Apps
      • DePINScan
      • mimo DEX
      • ecosystem.iotex.io
    • "Powered by IoTeX" Devices
      • Pebble Tracker
        • Quick Start
        • Device Registration
        • Online Firmware Update
        • USB Firmware Update
        • Migrating to Pebble v2.0
          • 1.0 Device Registration
        • Tech Specs
        • Network Selection
        • Pebble Configuration
        • Query Pebble Data
        • Troubleshooting
        • Firmware Development
          • Hardware Setup
          • Build the Firmware
          • Flash the firmware
      • SenseCAP Indicator
      • UCam Home Camera
  • Builders
    • IoTeX Developer Portal
    • Dev Chat on Discord
    • Web3 Development
      • RPC Endpoints
      • Set up your Environment
      • Get Testnet IOTX Tokens
      • ioctl CLI
        • Installation
        • Create Accounts
        • Blockchain interaction
          • ioctl command reference
      • Chain Indexing
        • The Graph
        • SubQuery
        • IoTeX Analytics API
      • IoTeXscan API
      • Deterministic Deployment
      • Account Abstraction
        • Components of AA
        • 👩‍💻Creating new Accounts
        • 👨‍💻P256Account Example
      • Blob Transactions (EIP-4844)
      • Multicall3
      • EVM Precompiled Contracts
    • Building DePINs
      • ioID Step by Step Tutorial
        • Integrate ioID in the Device Firmware
        • Integrate ioID in your cloud
      • Decentralized WiFi Connectivity (DeWi)
        • Project Specification
        • The choice of Hardware
        • The Data API Service
        • DePIN Incentives Contract
    • Building DeFi
      • Deploy Tokens
        • Deploy an ERC20 Token
        • Deploy an NFT Token
      • Price Oracles
        • Chainlink Relayer
        • SupraOracles
      • Integrate IoTeX Staking
      • Liquid staking Dapps
    • Launch Dapps on IoTeX
      • Submit Tokens to the IoTeX Ecosystem
      • Submit tokens to the iotube bridge
      • Verify Smart Contracts
      • Audit your Contracts
      • Submit your Dapp to Portals
      • Useful tools
    • Node Operators
      • Fastblocks (Node as a Service)
      • Setup an IoTeX RPC Node
      • Run a Delegate Node
      • Rosetta API
    • Reference Docs
      • ioctl client
        • Accounts
        • HD Wallets
        • Aliases
        • Actions
        • Queries
        • Smart Contracts
        • Staking & Voting
        • Tokens
        • ioID Identities
        • W3bstream
        • Decentralized Identifiers (DID)
        • JWT Auth Tokens
      • Native IoTeX Development
        • IoTeX gRPC API
        • Account Cryptography
        • Address Conversion
        • Create Accounts
        • Estimate Gas Price
        • Make IOTX Transfers
        • Manage ERC20 Tokens
        • Smart Contract Interactions
        • ioPay Desktop
        • DID JWT Tokens
        • Calling any RPC method
      • Embedded Blockchain Clients
        • Arduino IDE
        • Linux Systems
        • PlatformIO
        • Examples
        • Tutorials
  • Participate
    • Crypto's Got Talent (CGT)
      • IoTeX x Polygon DePIN Grant
    • Governance
      • IoTeX Improvement Proposals
      • The Marshall DAO
    • Join the Community
    • Get in Touch
Powered by GitBook
LogoLogo

This documentation portal is currently undergoing updates to align with the IoTeX 2.0 Whitepaper release. Information provided here may be incomplete, or out-of-date. Please use this portal for preliminary reference only, and check out the official IoTeX 2.0 Whitepaper for updated information.

  • .

2025 | IoTeX

On this page
  • Overview
  • How it works
  • The System Staking Contract
  • Bucket Types
  • Examples
  • Setting up the Environment
  • Staking IOTX from your Contract
  • Changing the StakeLock status
  • Unstaking a bucket
  • Withdrawing a bucket
  • More operations
  • Conclusion

Was this helpful?

Export as PDF
  1. Builders
  2. Building DeFi

Liquid staking Dapps

PreviousIntegrate IoTeX StakingNextLaunch Dapps on IoTeX

Last updated 9 months ago

Was this helpful?

Overview

With the adoption of IIP13, that allows representing IoTeX staking buckets as Non-fungible Tokens (NFTs), liquid staking solutions that rely on smart contracts to manage their stakes via system-level smart contracts can now be developed on IoTeX.

Read more

Staking in the IoTeX blockchain was originally implemented as part of the protocol, which prevents direct interaction of smart contracts with staking functionalities. While IIP12 addressed the the possibility of from the Ethereum JSON API by means of a virtual contract, that one is not an actual EVM smart contract, and thus it is not visible and cannot be called by other smart contracts.

In this section we will highlight the details of how Staking as NFT works and provide documentation on how to engage with staking buckets to offer liquid staking solutions on IoTeX.

How it works

Liquid Staking has been enabled with the implementation of a so called "System Staking Contract". This is the primary contract responsible for providing the functionalities laid out in IIP-13. It manages tasks such as creating, modifying, transferring, and querying staking Buckets and their associated NFT tokens.

The System Staking Contract

|

Network
Address

Testnet

0x52ab0fe2c3a94644de0888a3ba9ea1443672e61f

Mainnet

0x68db92a6a78a39dcaff1745da9e89e230ef49d3d

Bucket Types

In the context of staking as NFT, a "Bucket Type" represent a specific staking configuration, including the deposit amount, the preset lock duration, and the status of the StakeLock option. Currently, three bucket types are supported in the implementation, that are listed below:

Amount (IOTX)
Duration (Days)
Duration (Blocks)
StakeLock

10,000

91

1,572,480

ON by default

100,000

91

1,572,480

ON by default

1,000,000

91

1,572,480

ON by default

Examples

In this section we explore in details how to interact with the SystemStaking contract from another contract to enable liquid staking functionalities.

Setting up the Environment

import "./ISystemStaking.sol"; 
import "@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol";

contract MyLiquidStaking is IERC721Receiver {
    // Holds the System staking contract address
    ISystemStaking public SystemStakingContract;

    // Constructor
    // Address for IoTeX Testnet: 0x52ab0fe2c3a94644de0888a3ba9ea1443672e61f
    // Address for IoTeX Mainnet: 0x68db92a6a78a39dcaff1745da9e89e230ef49d3d
    constructor(address _SystemStakingContractAddress) {
        // Set the System staking contract address
        SystemStakingContract = ISystemStaking(_SystemStakingContractAddress);
    ...

Staking IOTX from your Contract

The SystemStaking contract provides three stake functions that enable the creation of a new staking bucket in different scenarios. Each of them returns the id assigned to the newly created bucket, which coincides with the NFT token id:

// Create a single staking bucket with a specific duration and delegate
function stake(uint256 _duration, address _delegate) external payable returns (uint256);

// Create multiple staking buckets, each with the same amount and duration, for different delegates:
function stake(uint256 _amount, uint256 _duration, address[] memory _delegates) external payable returns (uint256);

// Create several staking buckets, each with the same amount and duration, all assigned to a single delegate
function stake(uint256 _amount, uint256 _duration, address _delegate, uint256 _count) external payable returns (uint256);

For instance, to generate a new NFT bucket with a 100 IOTX deposit, assigned to an eligible IoTeX delegate, you would use:

uint256 tokenId = 
    SystemStakingContract.stake{value: msg.value}(
    1572480, // 91 days in IoTeX blocks
    0xCD397ac1364676d8553D9ce78e4B0d27f236926d // Owner address of the delegate
    );
Note on Staking Amount and Duration

When creating a new staking bucket, it's important to ensure that the chosen stake amount and duration match one of the combinations the SystemStaking contract supports, otherwise the action will revert. These combinations are called "Bucket Types". For the best user experience, consider fetching the list of all supported bucket types from your dApp frontend to guide users during the staking process.

To obtain the current list of bucket types, use the following methods from the SystemStaking contract:

Copy

// Get the total number of bucket types
function numOfBucketTypes() external view returns (uint256);

// Retrieve the paginated list of supported bucket types
function bucketTypes(uint256 _offset, uint256 _size) external view returns (BucketType[] memory);
Note on Delegate Owner Addresses

When creating a new staking bucket or changing the delegate of an existing bucket, it's important to input the delegate's "owner address," also referred to as the delegate's "profile address." This address uniquely identifies each IoTeX delegate. Ensure that the addresses you utilize actually belong to delegates and that they are eligible (meaning their self-stake amount is at least 1.2M IOTX). Failing to do so will cause a contract action revert.

function candidates(uint32 offset, uint32 limit) external view returns (IStaking.Candidate[] memory);

Changing the StakeLock status

When a new staking bucket is created using the SystemStaking contract, the StakeLock option is enabled by default. In this state, the bucket remains locked for its designated lock duration, and this duration does not decrease over time. While the activated StakeLock option ensures higher rewards, if you plan to unstake a bucket at a specific time, you must deactivate the StakeLock option for that bucket well in advance, specifically the same number of days as the lock duration.

// Disables StakeLock for a bucket
function unlock(uint256 _tokenId) external

// Disables StakeLock for multiple buckets (must be owned by the same owner)
function unlock(uint256[] calldata _tokenIds) external

// Enables StakeLock for a bucket and sets a new lock duration (must be >= to the remaining lock time)
function lock(uint256 _tokenId, uint256 _duration) external;

// Enables StakeLock for multiple bucket and sets a new lock duration (same for all)
function lock(uint256[] calldata _tokenIds, uint256 _duration) external;

Unstaking a bucket

Before you can withdraw the IOTX deposit, unstaking a bucket is a prerequisite. For a bucket to qualify for unstaking, it must be in the "unlocked" status. This indicates that the StakeLock option for that specific bucket must have remained deactivated throughout the entire lock duration of the bucket. Once initiated, the unstaking process lasts 3 days (equivalent to 51,840 IoTeX blocks). During this period, the bucket remains locked, does not generate staking rewards, and is immune to any operations.

// Unstakes a bucket
function unstake(uint256 _tokenId) external;

// Unstakes multiple buckets
function unstake(uint256[] calldata _tokenIds) external;

Withdrawing a bucket

Before you can withdraw a deposit, it must have completed the unstaking process.

// Withdraws a staking bucket deposit to a certain recipient address
function withdraw(uint256 _tokenId, address payable _recipient) external;

// Withdraws multiple staking bucket deposits to a certain recipient address
function withdraw(uint256[] calldata _tokenIds, address payable _recipient) external;

More operations

function blocksToUnstake(uint256 _tokenId) external view returns (uint256);
function blocksToWithdraw(uint256 _tokenId) external view returns (uint256);
function bucketOf(uint256 _tokenId) external view returns (uint256, uint256, uint256, uint256, address);
function merge(uint256[] calldata tokenIds, uint256 _newDuration) external payable;
function expandBucket(uint256 _tokenId, uint256 _newAmount, uint256 _newDuration) external payable;
function changeDelegate(uint256 _tokenId, address _delegate) external;
function changeDelegates(uint256[] calldata _tokenIds, address _delegate) external;
function lockedVotesTo(address[] calldata _delegates) external view returns (uint256[][] memory counts_);
function unlockedVotesTo(address[] calldata _delegates) external view returns (uint256[][] memory counts_);

Conclusion

These are the foundational steps for interacting with IIP-13 contracts, that allows the creation of Liquid Staking solutions. Liquid staking allows users to access the benefits of staking in a blockchain network while still maintaining liquidity and flexibility over their staked assets, which create a more attractive and versatile staking experience.

For more advanced operations and deeper insights, please refer to

When developing your Liquid Staking contract, ensure you include the contract interface from the .

Ensure your client contract implements , as it will receive the NFT Bucket from the SystemStaking contract upon staking creation.

To facilitate this process in your frontend, leverage the IoTeX Staking virtual contract to access details regarding delegate names, addresses, and self-staking data. The relevant method is listed below, but for comprehensive details, please

.

->
Visit the original IIP-13 Proposal
accessing the full staking protocol
Visit the original IIP-13 Proposal ->
Source Code
ABI
ISystemStaking
IIP13 repository
IERC721Receiver
refer to the IoTeX Staking Integration section ->
→ IIP-13 proposal
-> Contract's source code