Logo

dev-resources.site

for different kinds of informations.

How to write dynamic staking smart contract step by step in practice

Published at
12/14/2024
Categories
blockchain
smartcontract
solidity
ethereum
Author
marksantiago02
Author
14 person written this
marksantiago02
open
How to write dynamic staking smart contract step by step in practice

Introduction

In the ever-expanding landscape of decentralized finance (DeFi), staking has emerged as a popular mechanism for users to earn rewards by participating in network security and governance. Unlike traditional financial systems, staking allows cryptocurrency holders to lock up their assets to support blockchain operations, all while earning passive income. However, the conventional staking model often comes with restrictions, such as lock-in periods and fixed reward structures that can limit user flexibility and engagement.

This article provides a detailed, hands-on guide to implementing dynamic staking smart contracts on Ethereum. We'll walk through building a production-ready staking system that enables real-time reward calculations and flexible withdrawals.
This article is the implementation of the Basic understanding of Dynamic Staking.
By following this step-by-step tutorial, you'll learn how to:

  • Create an upgradeable staking contract with role-based access control
  • Implement share-based reward calculations for precise token distribution
  • Build flexible deposit and withdrawal mechanisms without lock-in periods
  • Add essential security features and administrative controls
  • Handle real-time reward tracking and distribution

Whether you're building a DeFi protocol or enhancing an existing platform, this practical guide will equip you with the technical knowledge to implement a robust dynamic staking system. The code examples and implementation patterns shown here are battle-tested and ready for production use, helping you create staking mechanisms that truly serve the needs of modern DeFi users.

Let's dive into the technical implementation and understand how each component works together to create a flexible and secure dynamic staking system.

Implementation Details

Let's break down the key components of the dynamic staking contract:

1. Contract Structure and Inheritance

contract Staking is
    Initializable,
    UUPSUpgradeable,
    AccessControlUpgradeable,
    PausableUpgradeable
{
    using EnumerableSet for EnumerableSet.AddressSet;
Enter fullscreen mode Exit fullscreen mode

The contract inherits from:

  • Initializable: For upgradeable contract initialization
  • UUPSUpgradeable: For upgrade functionality
  • AccessControlUpgradeable: For role-based access control
  • PausableUpgradeable: For emergency pause functionality

2. State Variables and Data Structures

struct Stake {
    uint256 stakedMRKST;
    uint256 shares;
}

IERC20 private MRKST;
EnumerableSet.AddressSet private stakeholders;
uint256 private totalStakes;
uint256 private totalShares;
mapping(address => Stake) private stakeholderToStake;
Enter fullscreen mode Exit fullscreen mode

3. Key Functions

Initialization

function initialize(
    address admin1,
    address admin2,
    address _MRKST
) public initializer {
    AccessControlUpgradeable.__AccessControl_init();
    PausableUpgradeable.__Pausable_init();
    ADMIN_ROLE = keccak256("ADMIN_ROLE");
    _setupRole(ADMIN_ROLE, admin1);
    _setupRole(ADMIN_ROLE, admin2);
    MRKST = IERC20(_MRKST);
    base = 10**18;
}
Enter fullscreen mode Exit fullscreen mode

This function initializes the contracts. It

  • Sets up the initial contract state
  • Assigns two administrators for enhanced security
  • Links the staking token contract
  • Establishes the base unit (10^18) for precise calculations
  • Initializes access control and pause functionality

Staking Implementation

function createStake(uint256 stakeAmount) public whenNotPaused isInitialRatioSet {
    uint256 shares = (stakeAmount * totalShares) / MRKST.balanceOf(address(this));

    require(MRKST.transferFrom(msg.sender, address(this), stakeAmount), "MRKST transfer failed");

    stakeholders.add(msg.sender);
    stakeholderToStake[msg.sender].stakedMRKST += stakeAmount;
    stakeholderToStake[msg.sender].shares += shares;
    totalStakes += stakeAmount;
    totalShares += shares;
}
Enter fullscreen mode Exit fullscreen mode

This function

  • Accepts user deposits
  • Calculates shares based on current token/share ratio
  • Transfers tokens from user to contract
  • Records stake details in storage
  • Updates global totals
  • Adds user to stakeholder list

Withdrawal Implementation

function removeStake(uint256 stakeAmount) public whenNotPaused {
    uint256 stakeholderStake = stakeholderToStake[msg.sender].stakedMRKST;
    uint256 stakeholderShares = stakeholderToStake[msg.sender].shares;

    require(stakeholderStake >= stakeAmount, "Not enough staked!");

    uint256 sharesToWithdraw = (stakeAmount * stakeholderShares) / stakeholderStake;
    uint256 rewards = calculateRewards(stakeAmount, stakeholderStake, stakeholderShares);

    updateStakeAndShares(msg.sender, stakeAmount, sharesToWithdraw);
    transferRewards(msg.sender, stakeAmount, rewards);
}
Enter fullscreen mode Exit fullscreen mode

This function

  • Processes withdrawal requests
  • Calculates earned rewards
  • Determines shares to burn
  • Updates user's stake balance
  • Transfers principal plus rewards
  • Removes user from stakeholder list if fully withdrawn

Reward Calculation

function rewardOf(address stakeholder) public view returns (uint256) {
    uint256 stakeholderStake = stakeholderToStake[stakeholder].stakedMRKST;
    uint256 stakeholderShares = stakeholderToStake[stakeholder].shares;

    if (stakeholderShares == 0) {
      return 0;
    }

    uint256 stakedRatio = (stakeholderStake * base) / stakeholderShares;
    uint256 currentRatio = (MRKST.balanceOf(address(this)) * base) /
      totalShares;

    if (currentRatio <= stakedRatio) {
      return 0;
    }

    uint256 rewards = (stakeholderShares * (currentRatio - stakedRatio)) / base;

    return rewards;
  }
Enter fullscreen mode Exit fullscreen mode

This function

  • Calculates total pending rewards for a stakeholder
  • Uses ratio comparison between initial stake and current value
  • Accounts for all accumulated rewards
  • Returns total claimable reward amount

Reward Distribution

function rewardForStake(address stakeholder, uint256 stakeAmount)
    public
    view
    returns (uint256)
  {
    uint256 stakeholderStake = stakeholderToStake[stakeholder].stakedMRKST;
    uint256 stakeholderShares = stakeholderToStake[stakeholder].shares;

    require(stakeholderStake >= stakeAmount, "Not enough staked!");

    uint256 stakedRatio = (stakeholderStake * base) / stakeholderShares;
    uint256 currentRatio = (MRKST.balanceOf(address(this)) * base) /
      totalShares;
    uint256 sharesToWithdraw = (stakeAmount * stakeholderShares) /
      stakeholderStake;

    if (currentRatio <= stakedRatio) {
      return 0;
    }

    uint256 rewards = (sharesToWithdraw * (currentRatio - stakedRatio)) / base;

    return rewards;
  }
Enter fullscreen mode Exit fullscreen mode

This function

  • Calculates rewards for partial withdrawal
  • Determines proportional share of rewards
  • Validates withdrawal amount
  • Returns specific reward amount for requested withdrawal

Refund Locking Implementation

  function refundLockedStake(uint256 from, uint256 to) public hasAdminRole {
    require(to <= stakeholders.length(), "Invalid `to` param");
    uint256 s;

    for (s = from; s < to; s += 1) {
      totalStakes -= stakeholderToStake[stakeholders.at(s)].stakedMRKST;

      require(
        MRKST.transfer(
          stakeholders.at(s),
          stakeholderToStake[stakeholders.at(s)].stakedMRKST
        ),
        "MRKST transfer failed"
      );

      stakeholderToStake[stakeholders.at(s)].stakedMRKST = 0;
    }
  }
Enter fullscreen mode Exit fullscreen mode

This function

  • Emergency withdrawal mechanism
  • Processes refunds in batches
  • Returns original stake amounts
  • Clears stake records

Conclusion

This dynamic staking implementation provides a flexible and secure way to manage token staking with real-time reward calculations. The share-based system ensures fair distribution of rewards while maintaining precision in calculations.

Future Possibilities

  • Multiple token support
  • Tiered reward systems
  • Governance integration
  • Advanced reward strategies
  • Enhanced analytics and reporting

This implementation serves as a robust foundation for building more sophisticated staking mechanisms in DeFi applications.

For more detailed information, please refer to the source code.

Thank you! Happy coding! 😍

smartcontract Article's
30 articles in total
Favicon
Vyper Data Types (Series 2)
Favicon
Vyper is redefining smart contract development with its focus on simplicity, security, and efficiency. With its rapidly growing community of developers, Vyper is becoming the go-to for smart contract development, creating a thriving ecosystem.
Favicon
Have You Fallen for a Phishing Scam? Let’s Talk About It πŸ‘€
Favicon
How much does smart contract development cost?
Favicon
OverFlow and UnderFlow causes in Solidity
Favicon
INTEGRATION OF DAPPS WITH MODE: WALLET AND SMART CONTRACTS | PART 2: CONNECTING SMART CONTRACTS TO THE FRONT-END
Favicon
Web3 and Blockchain Development: Unlocking the Power of Decentralized Applications
Favicon
OverFlow and UnderFlow causes in Solidity
Favicon
Need some help for getting Web3 internship
Favicon
The Danger of Randomness in Smart Contracts and its solution
Favicon
What is Reentrancy?
Favicon
Smart Contract Upgrades: Enhance Next-Level Blockchain Security
Favicon
Smart Contract Audits: Ensuring Safe Blockchain Migration
Favicon
Send Tokens in Bulk with Low Fees and Fast Delivery: The Ultimate Airdrop Tool for 2024
Favicon
πŸ›‘οΈ Why Using OpenZeppelin in Smart Contracts Is Essential
Favicon
A Walkthrough of Solidity Custom Errors
Favicon
How to write dynamic staking smart contract step by step in practice
Favicon
How to migrate smart contracts to a blockchain?
Favicon
Every Blockchain Developer Must Know About This Scam!
Favicon
Smart Contract Migration: Essential Steps for Secure Upgrades
Favicon
Basic understanding of Dynamic Staking
Favicon
INTEGRATION OF DAPPS WITH MODE: WALLET AND SMART CONTRACTS | PART 1: CONNECTING THE WALLET
Favicon
A Step-by-Step Guide to Automating Smart Contract Upgrades with Deep Storage Data
Favicon
Blockchain-based FinTech Solution
Favicon
How Deep Storage Data Transforms Smart Contract Migration
Favicon
How to Move Smart Contracts From Existing Blockchain Platforms to New Ones?
Favicon
How to Write a Token Price Oracle Smart Contract
Favicon
Future of Smart Contract development: Trends and Predictions forΒ 2025
Favicon
Smart Contract Safety: How to Verify Before You Interact
Favicon
Smart Contract Security Audit using Deep Storage Data

Featured ones: