Skip to content

Instantly share code, notes, and snippets.

@Damkols
Created September 4, 2023 13:07
Show Gist options
  • Save Damkols/9d6ba67a2b715ee56733975df9a556d2 to your computer and use it in GitHub Desktop.
Save Damkols/9d6ba67a2b715ee56733975df9a556d2 to your computer and use it in GitHub Desktop.
Staking contract that rewards users
// SPDX-License-Identifier: MIT
pragma solidity 0.8.20;
import {ERC20} from "https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC20/ERC20.sol";
interface IStandardToken {
function balanceOf(address account) external view returns (uint256);
function transferFrom(address from, address to, uint256 value) external returns (bool);
function transfer(address to, uint256 value) external returns (bool);
function withdrawEther() external;
}
contract StakingContract is ERC20{
IStandardToken standardToken;
// IStandardToken constant public standardToken = IStandardToken(0x8Bc4b37aff83FdA8a74d2b5732437037B801183e);
struct Stakings{
uint amountStaked;
uint timeStaked;
uint rewardDuration;
}
uint public rewardPercent = 1;
mapping(address => Stakings) public userStakingsMap;
event Staked(uint amountstake, uint totalAmountStaked, uint time);
event unStaked(uint amountstake, uint totalAmountStaked, uint time, uint rewards);
event claimRewards( uint time, uint rewards);
constructor(address _standardToken) ERC20("RewardToken", "RWT"){
standardToken = IStandardToken(_standardToken);
// rewardPercent = _rewardPercent;
}
function stake(uint amount) external {
uint balance = standardToken.balanceOf(msg.sender);
require(balance >= amount, "ERC20 insuficient balance");
bool status = standardToken.transferFrom(msg.sender, address(this), amount);
require(status == true, "transfer Failed");
Stakings storage _user = userStakingsMap[msg.sender];
_user.amountStaked += amount;
_user.timeStaked = block.timestamp;
_user.rewardDuration += calculateRewards(msg.sender);
emit Staked(amount, _user.amountStaked, block.timestamp);
}
function getStakeAmount(address who) public view returns(uint _staked){
Stakings storage _user = userStakingsMap[who];
_staked = _user.amountStaked;
}
function unStake(uint amount) external {
uint totalStaked = getStakeAmount(msg.sender);
require(totalStaked >= amount, "insufficent stake amount");
Stakings storage _user = userStakingsMap[msg.sender];
uint rewards = _user.rewardDuration + calculateRewards(msg.sender);
require(rewards > 0,"No reward to claim");
_user.rewardDuration = 0;
_user.timeStaked = block.timestamp;
_mint(msg.sender, rewards);
_user.amountStaked -= amount;
standardToken.transfer(msg.sender, amount);
emit unStaked(amount, _user.amountStaked, block.timestamp, rewards);
}
function withdrawEther() external {
standardToken.withdrawEther();
payable(msg.sender).transfer(address(this).balance);
}
function calculateRewards(address user) public view returns (uint256) {
Stakings storage _user = userStakingsMap[user];
uint256 stakingDuration = (block.timestamp - _user.timeStaked)/60; //The timestamp of the current block minus time user staked token divided
return _user.amountStaked * stakingDuration * rewardPercent / 10e4;
}
function claimReward() public {
Stakings storage _user = userStakingsMap[msg.sender];
uint rewards = _user.rewardDuration + calculateRewards(msg.sender);
require(rewards > 0,"No reward to claim");
_user.rewardDuration = 0;
_user.timeStaked = block.timestamp; //The timestamp of the current block.
_mint(msg.sender, rewards);
emit claimRewards(block.timestamp, rewards);
}
// uint256 secondStaked = block.timestamp - stakedFromTs[msg.sender]; //current time minus the time stake was unlocked
// uint256 rewards = staked[msg.sender] * secondStaked / 3.154e7;
fallback() external payable{}
receive() external payable {}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment