Day 92/100 : Exploring DeFi Staking Rewards 🚀

#100DaysOfSolidity 092 DeFi : “Staking Rewards”

Solidity Academy
8 min readSep 6, 2023

Welcome back to Day 92 of our #100DaysOfSolidity series! Today, we’re diving deep into the world of decentralized finance (DeFi) to discuss a hot topic: Staking Rewards. 🌐💰

#100DaysOfSolidity 092 DeFi : “Staking Rewards”

What are Staking Rewards?

Staking rewards are at the heart of many DeFi protocols. They provide an incentive for users to lock up their cryptocurrency holdings in a smart contract, thus contributing to the network’s security and governance. In return, participants earn rewards in the form of additional tokens or a share of transaction fees. This concept has gained immense popularity in recent years, revolutionizing the way we think about passive income in the crypto space. 🔄💸

How Staking Rewards Work

Staking rewards are typically generated through a process called Proof of Stake (PoS) or Delegated Proof of Stake (DPoS). Here’s a simplified breakdown of how it works:

1. Locking Tokens: Users lock a certain amount of cryptocurrency tokens in a staking smart contract.

2. Validation: Validators or nodes are responsible for validating transactions and maintaining the network. These validators are chosen based on their stake and, in some cases, reputation.

3. Reward Distribution: Over time, as validators participate in block creation and validation, they earn rewards. These rewards are distributed among users who have staked their tokens in proportion to their stake.

4. Unstaking and Rewards Withdrawal: Users can unstake their tokens at any time, but there may be a waiting period before they can access their rewards to prevent network instability.

Now, let’s dive into some technical details and explore how you can implement a basic staking rewards system in Solidity. 🔍👨‍💻

Implementing a Simple Staking Rewards Smart Contract

In this section, we’ll create a simplified Solidity smart contract that allows users to stake tokens and earn rewards. We’ll use Ethereum as our blockchain of choice.

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
contract StakingRewards {
mapping(address => uint256) public stakedBalance;
mapping(address => uint256) public rewardsBalance;
uint256 public totalStaked;
uint256 public rewardRate;
constructor(uint256 _rewardRate) {
rewardRate = _rewardRate;
}
function stake(uint256 amount) external {
require(amount > 0, "Amount must be greater than 0");
// Transfer tokens from the sender to this contract
// Ensure you have the necessary approval mechanism in place
// Update stakedBalance and totalStaked
// Emit an event for staking
}
function unstake(uint256 amount) external {
require(amount > 0, "Amount must be greater than 0");
// Check if the user has enough staked tokens
// Calculate and transfer the user's rewards
// Update stakedBalance and totalStaked
// Emit an event for unstaking
}
function getReward() external {
// Calculate and transfer rewards to the sender
// Update rewardsBalance
// Emit an event for reward claiming
}
// Add any additional functions for managing rewards and the reward rate
}

Please note that this is a simplified example for educational purposes. In a real-world scenario, you would need to consider factors like locking periods, withdrawal fees, and more.

Ensuring Security and Trustworthiness

When dealing with DeFi and staking, security is paramount. Here are some tips to make your staking rewards smart contract secure:

1. Use Verified Contracts: Ensure your contract is well-audited and verified on platforms like Etherscan.

2. Implement Proper Access Control: Use access control mechanisms to limit who can stake, unstake, and withdraw rewards.

3. Test Extensively: Test your contract rigorously, including edge cases, before deploying it to the mainnet.

4. Avoid Reentrancy Vulnerabilities: Be cautious when interacting with external contracts to prevent reentrancy attacks.

5. Emergency Withdrawal: Consider adding an emergency withdrawal feature in case of unexpected issues.

DeFi Staking Rewards in the Real World

The DeFi space is dynamic and constantly evolving. Many projects have implemented staking rewards, each with its own unique twist. Some popular DeFi protocols that offer staking rewards include:

1. Compound (COMP): Allows users to earn COMP tokens by supplying assets to the Compound protocol.

2. Aave (AAVE): Users can stake AAVE tokens in the Aave protocol to earn staking rewards.

3. Synthetix (SNX): Stakers in Synthetix can earn rewards by helping to secure the network and minting synthetic assets.

4. Balancer (BAL): Balancer Liquidity Providers can stake their liquidity pool tokens to earn trading fees and BAL rewards.

5. Yearn Finance (YFI): Yearn offers various vaults where users can stake their assets to earn YFI and other tokens.

Remember that investing in DeFi protocols involves risks, including smart contract vulnerabilities and market volatility. Always do your research and consider seeking professional advice.

📊 Staking Rewards Contract Report 🚀

// SPDX-License-Identifier: MIT
pragma solidity ^0.8;

contract StakingRewards {
IERC20 public immutable stakingToken;
IERC20 public immutable rewardsToken;

address public owner;

// Duration of rewards to be paid out (in seconds)
uint public duration;
// Timestamp of when the rewards finish
uint public finishAt;
// Minimum of last updated time and reward finish time
uint public updatedAt;
// Reward to be paid out per second
uint public rewardRate;
// Sum of (reward rate * dt * 1e18 / total supply)
uint public rewardPerTokenStored;
// User address => rewardPerTokenStored
mapping(address => uint) public userRewardPerTokenPaid;
// User address => rewards to be claimed
mapping(address => uint) public rewards;

// Total staked
uint public totalSupply;
// User address => staked amount
mapping(address => uint) public balanceOf;

constructor(address _stakingToken, address _rewardToken) {
owner = msg.sender;
stakingToken = IERC20(_stakingToken);
rewardsToken = IERC20(_rewardToken);
}

modifier onlyOwner() {
require(msg.sender == owner, "not authorized");
_;
}

modifier updateReward(address _account) {
rewardPerTokenStored = rewardPerToken();
updatedAt = lastTimeRewardApplicable();

if (_account != address(0)) {
rewards[_account] = earned(_account);
userRewardPerTokenPaid[_account] = rewardPerTokenStored;
}

_;
}

function lastTimeRewardApplicable() public view returns (uint) {
return _min(finishAt, block.timestamp);
}

function rewardPerToken() public view returns (uint) {
if (totalSupply == 0) {
return rewardPerTokenStored;
}

return
rewardPerTokenStored +
(rewardRate * (lastTimeRewardApplicable() - updatedAt) * 1e18) /
totalSupply;
}

function stake(uint _amount) external updateReward(msg.sender) {
require(_amount > 0, "amount = 0");
stakingToken.transferFrom(msg.sender, address(this), _amount);
balanceOf[msg.sender] += _amount;
totalSupply += _amount;
}

function withdraw(uint _amount) external updateReward(msg.sender) {
require(_amount > 0, "amount = 0");
balanceOf[msg.sender] -= _amount;
totalSupply -= _amount;
stakingToken.transfer(msg.sender, _amount);
}

function earned(address _account) public view returns (uint) {
return
((balanceOf[_account] *
(rewardPerToken() - userRewardPerTokenPaid[_account])) / 1e18) +
rewards[_account];
}

function getReward() external updateReward(msg.sender) {
uint reward = rewards[msg.sender];
if (reward > 0) {
rewards[msg.sender] = 0;
rewardsToken.transfer(msg.sender, reward);
}
}

function setRewardsDuration(uint _duration) external onlyOwner {
require(finishAt < block.timestamp, "reward duration not finished");
duration = _duration;
}

function notifyRewardAmount(
uint _amount
) external onlyOwner updateReward(address(0)) {
if (block.timestamp >= finishAt) {
rewardRate = _amount / duration;
} else {
uint remainingRewards = (finishAt - block.timestamp) * rewardRate;
rewardRate = (_amount + remainingRewards) / duration;
}

require(rewardRate > 0, "reward rate = 0");
require(
rewardRate * duration <= rewardsToken.balanceOf(address(this)),
"reward amount > balance"
);

finishAt = block.timestamp + duration;
updatedAt = block.timestamp;
}

function _min(uint x, uint y) private pure returns (uint) {
return x <= y ? x : y;
}
}

interface IERC20 {
function totalSupply() external view returns (uint);

function balanceOf(address account) external view returns (uint);

function transfer(address recipient, uint amount) external returns (bool);

function allowance(address owner, address spender) external view returns (uint);

function approve(address spender, uint amount) external returns (bool);

function transferFrom(
address sender,
address recipient,
uint amount
) external returns (bool);

event Transfer(address indexed from, address indexed to, uint value);
event Approval(address indexed owner, address indexed spender, uint value);
}

In this report, we’ll provide an in-depth analysis of the Solidity smart contract named “StakingRewards.” This contract facilitates staking of tokens and rewards distribution to users in the field of decentralized finance (DeFi).

🔍 Contract Overview:

- Staking Token: Users can stake tokens of a specific ERC-20 token.
- Rewards Token: Rewards are distributed in another ERC-20 token.
- Owner: The contract creator, who has control over contract adjustments.
- Duration: Specifies the duration (in seconds) during which rewards are to be paid.
- Finish Time: Timestamp indicating when the reward period concludes.
- Last Update Time: Timestamp of the last reward update.
- Reward Rate: Rate at which rewards are distributed per second.
- Reward Per Token Stored: Cumulative rewards per token stored.
- User Balances: Mapping of user addresses to their staked amounts and rewards.
- Total Supply: Total amount of tokens staked in the contract.

⚙️ Contract Functions:

1. Constructor: Initializes the contract with staking and rewards token addresses.

2. onlyOwner Modifier: Ensures that only the contract owner can execute specific functions.

3. updateReward Modifier: Updates user rewards when interacting with staking functions.

4. lastTimeRewardApplicable: Determines the latest applicable reward time based on the finish time.

5. rewardPerToken: Calculates the reward per token based on staking duration and rates.

6. stake: Allows users to stake tokens in the contract.

7. withdraw: Allows users to withdraw their staked tokens.

8. earned: Calculates the total rewards earned by a user.

9. getReward: Allows users to claim their earned rewards.

10. setRewardsDuration: Adjusts the duration of rewards distribution (only by the owner).

11. notifyRewardAmount: Notifies the contract about the amount of rewards to be distributed (only by the owner).

12. _min: Internal function to determine the minimum of two values.

🛡️ Security and Unique Features:

- Proper Access Control: The “onlyOwner” modifier ensures that only authorized parties can modify critical contract parameters.

- Updated Rewards: The contract automatically updates user rewards when they interact with staking functions, maintaining transparency and fairness.

- Flexibility: The contract owner can adjust the rewards distribution duration and notify about reward amounts, providing adaptability.

- Careful Token Handling: Token transfers and balances are handled securely, minimizing potential vulnerabilities.

👩‍💻 Development Considerations:

Developers should exercise caution and perform thorough testing when deploying and interacting with this contract. Security audits and code reviews are crucial steps in ensuring the contract’s safety and reliability.

💼 Real-World Use Cases:

Contracts like “StakingRewards” serve as the backbone of DeFi platforms, enabling users to earn rewards by contributing their assets. Such contracts are used in various DeFi protocols, including yield farming and liquidity provision.

🔑 In Conclusion; The “StakingRewards” contract is a fundamental building block in the world of decentralized finance, enabling users to stake tokens and earn rewards. It offers flexibility and security measures to ensure safe and fair rewards distribution.

As with any DeFi contract, users and developers should exercise caution, conduct thorough research, and seek professional advice when participating in or deploying such contracts.

🚀 Happy Staking in the World of DeFi! 🌐💰

Conclusion

Staking rewards are a fascinating aspect of DeFi that has changed the way we think about earning passive income in the crypto space. In this article, we’ve explored the concept of staking rewards, discussed their technical implementation in a simplified Solidity smart contract, and highlighted some best practices for security.

As the DeFi landscape continues to evolve, staking rewards are likely to play an even more significant role in shaping the future of finance. So, stay tuned, keep learning, and happy coding in Solidity! 🚀📚

Remember, this article is just the tip of the iceberg when it comes to DeFi and Solidity development. Dive deeper, experiment, and explore the ever-expanding world of decentralized finance. Good luck, and happy staking! 💪💎

📚 Resources 📚

--

--

Solidity Academy

Your go-to resource for mastering Solidity programming. Learn smart contract development and blockchain integration in depth. https://heylink.me/solidity/