Posted By : Rahul
Creating a multi-level staking contract on Ethereum using smart contract development opens up exciting possibilities for decentralized finance projects by enabling layered rewards and incentives for users. Using Solidity, Ethereum's native programming language, developers can build secure and scalable staking solutions that allow participants to earn rewards based on their staking levels. In this guide, we'll walk through the process of developing a multi-level staking contract, covering everything from setup to implementation, so you can leverage Ethereum's blockchain for advanced staking functionality.
In this article, we will discuss the basics of staking contracts, and the characteristics of multi-level staking contracts.
Familiar with Remix IDE
You may also like | Creating a Token Vesting Contract on Solana Blockchain
To maintain the security of a blockchain network, confirm transactions, and generate rewards, cryptocurrency holders stake or lock up their assets. Staking, particularly on Proof-of-Stake (PoS) blockchains and their variations, entails actively taking part in the network's functioning as opposed to conventional bank savings or investments.
Multi-level staking is an advanced staking model where users can earn different levels of rewards based on various criteria, such as the amount of assets they stake or the duration they choose to lock their funds.
Also, Explore | How to Implement a Merkle Tree for Secure Data Verification
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.24;
interface ERC20 {
function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);
function transfer(address recipient, uint256 amount) external returns (bool);
}
contract MultiLevelStaking {
struct Stake {
uint256 amount;
uint256 startTime;
uint256 level;
}
mapping(address => Stake[]) public stakes;
mapping(uint256 => uint256) public rewardRates;
uint256 constant LEVEL_ONE_MIN = 10 * 10**18;
uint256 constant LEVEL_TWO_MIN = 20 * 10**18;
uint256 constant LEVEL_THREE_MIN = 50 * 10**18;
address public tokenAddress;
constructor(address _tokenAddress) {
tokenAddress = _tokenAddress;
rewardRates[1] = 5;
rewardRates[2] = 10;
rewardRates[3] = 15;
}
function stake(uint256 amount) public {
require(amount > 0, 'Amount should be greater than 0');
require(ERC20(tokenAddress).transferFrom(msg.sender, address(this), amount), 'Transfer failed');
uint256 level = getStakeLevel(amount);
// Add new stake to the user's array of stakes
stakes[msg.sender].push(Stake({
amount: amount,
startTime: block.timestamp,
level: level
}));
}
function getStakeLevel(uint256 amount) internal pure returns (uint256) {
if (amount >= LEVEL_THREE_MIN) {
return 3;
} else if (amount >= LEVEL_TWO_MIN) {
return 2;
} else if (amount >= LEVEL_ONE_MIN) {
return 1;
}
return 0;
}
function calculateReward(address staker) public view returns (uint256) {
Stake[] memory userStakes = stakes[staker];
require(userStakes.length > 0, 'No active stakes');
uint256 totalReward = 0;
for (uint256 i = 0; i < userStakes.length; i++) {
Stake memory stakeInfo = userStakes[i];
uint256 stakingDuration = block.timestamp - stakeInfo.startTime;
uint256 rate = rewardRates[stakeInfo.level];
uint256 reward = (stakeInfo.amount * rate * stakingDuration) / (365 days * 100);
totalReward += reward;
}
return totalReward;
}
function unstakeAll() public {
Stake[] memory userStakes = stakes[msg.sender];
require(userStakes.length > 0, 'No active stakes');
uint256 totalAmount = 0;
// Loop through each stake, calculate reward, and add to total amount
for (uint256 i = 0; i < userStakes.length; i++) {
uint256 reward = calculateSingleStakeReward(userStakes[i]);
totalAmount += userStakes[i].amount + reward;
}
// Clear all stakes for the user
delete stakes[msg.sender];
// Transfer the total amount back to the user
require(ERC20(tokenAddress).transfer(msg.sender, totalAmount), 'Transfer failed');
}
function unstake(uint256 index) public {
require(index < stakes[msg.sender].length, 'Invalid index');
Stake memory stakeInfo = stakes[msg.sender][index];
uint256 reward = calculateSingleStakeReward(stakeInfo);
uint256 totalAmount = stakeInfo.amount + reward;
// Remove the stake from the array by swapping and popping
stakes[msg.sender][index] = stakes[msg.sender][stakes[msg.sender].length - 1];
stakes[msg.sender].pop();
// Transfer the unstaked amount plus reward back to the user
require(ERC20(tokenAddress).transfer(msg.sender, totalAmount), 'Transfer failed');
}
function calculateSingleStakeReward(Stake memory stakeInfo) internal view returns (uint256) {
uint256 stakingDuration = block.timestamp - stakeInfo.startTime;
uint256 rate = rewardRates[stakeInfo.level];
return (stakeInfo.amount * rate * stakingDuration) / (365 days * 100);
}
}
Also, Read | Smart Contract Upgradability | Proxy Patterns in Solidity
The Constructor Initializes the contract with the token address and sets reward rates for each staking level.
constructor(address _tokenAddress) {
tokenAddress = _tokenAddress;
rewardRates[1] = 5;
rewardRates[2] = 10;
rewardRates[3] = 15;
}
The stake function allows users to stake a specified amount of tokens, recording the staking level, amount, and start time.
function stake(uint256 amount) public {
require(amount > 0, 'Amount should be greater than 0');
require(ERC20(tokenAddress).transferFrom(msg.sender, address(this), amount), 'Transfer failed');
uint256 level = getStakeLevel(amount);
stakes[msg.sender].push(Stake({
amount: amount,
startTime: block.timestamp,
level: level
}));
}
This method calculates the total rewards earned for all stakes of a particular user and returns the rewards.
function calculateReward(address staker) public view returns (uint256) {
Stake[] memory userStakes = stakes[staker];
require(userStakes.length > 0, 'No active stakes');
uint256 totalReward = 0;
for (uint256 i = 0; i < userStakes.length; i++) {
Stake memory stakeInfo = userStakes[i];
uint256 stakingDuration = block.timestamp - stakeInfo.startTime;
uint256 rate = rewardRates[stakeInfo.level];
uint256 reward = (stakeInfo.amount * rate * stakingDuration) / (365 days * 100);
totalReward += reward;
}
return totalReward;
}
The unstake all function allows a user to unstake all of their stakes and receive the total staked amount plus all rewards.
function unstakeAll() public {
Stake[] memory userStakes = stakes[msg.sender];
require(userStakes.length > 0, 'No active stakes');
uint256 totalAmount = 0;
for (uint256 i = 0; i < userStakes.length; i++) {
uint256 reward = calculateSingleStakeReward(userStakes[i]);
totalAmount += userStakes[i].amount + reward;
}
delete stakes[msg.sender];
require(ERC20(tokenAddress).transfer(msg.sender, totalAmount), 'Transfer failed');
}
The unstake function allows users to unstake a specific stake by index and receive the principal plus rewards for that specific stake.
function unstake(uint256 index) public {
require(index < stakes[msg.sender].length, 'Invalid index');
Stake memory stakeInfo = stakes[msg.sender][index];
uint256 reward = calculateSingleStakeReward(stakeInfo);
uint256 totalAmount = stakeInfo.amount + reward;
stakes[msg.sender][index] = stakes[msg.sender][stakes[msg.sender].length - 1];
stakes[msg.sender].pop();
require(ERC20(tokenAddress).transfer(msg.sender, totalAmount), 'Transfer failed');
}
Also, Explore | How to Write and Deploy Modular Smart Contracts
Click the Compile MultiLevelStaking.sol button.
Go to the 'Deploy & Run Transactions' tab.
Click Deploy, and MetaMask will prompt you to confirm the transaction. Confirm and pay for the gas fee.
Verify Deployment:
After deployment, the contract instance will appear under the Deployed Contracts section in Remix.
Building a multi-level staking contract on Ethereum with Solidity allows you to harness the power of decentralized finance while providing enhanced incentives for your users. With layered rewards and flexible staking options, these contracts not only boost user engagement but also promote long-term participation in your ecosystem. By implementing a secure and scalable staking model, you're positioned to offer a competitive, feature-rich staking solution that can adapt as the DeFi landscape continues to evolve. Now, you're equipped to launch a robust staking contract that meets the needs of today's crypto users. If you are looking to create crypto-staking solutions, connect with our skilled crypto/token developers to get started.
November 8, 2024 at 08:25 pm
Your comment is awaiting moderation.