Skip to content

Instantly share code, notes, and snippets.

@barchef
Created August 6, 2023 22:26
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save barchef/bb45ae3124cee992c3117818e4ffe388 to your computer and use it in GitHub Desktop.
Save barchef/bb45ae3124cee992c3117818e4ffe388 to your computer and use it in GitHub Desktop.
LockerStaking.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.13;
pragma experimental ABIEncoderV2;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/utils/math/SafeMath.sol";
import "@openzeppelin/contracts/utils/Address.sol";
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/security/ReentrancyGuard.sol";
contract LockerStaking is ReentrancyGuard, Ownable {
using SafeMath for uint256;
using Address for address;
using SafeERC20 for IERC20;
IERC20 public lockerToken;
event Staked(address indexed from, uint256 amount);
event Unstaked(address indexed from, uint256 amount);
struct AccountInfo {
uint256 balance;
uint256 lastStakedTimestamp;
uint256 lastUnstakedTimestamp;
}
mapping(address => AccountInfo) public accountInfos;
uint256[] public burnFees = [1000, 700, 500, 200, 50];
uint256[] public feeCycle = [3 days, 7 days, 14 days, 30 days];
constructor(address _lockerToken) public {
lockerToken = IERC20(_lockerToken);
}
function stake(uint256 _amount) public nonReentrant {
require(_amount > 0, "Invalid amount");
require(lockerToken.balanceOf(msg.sender) >= _amount, "Invalid balance");
AccountInfo storage account = accountInfos[msg.sender];
lockerToken.transferFrom(msg.sender, address(this), _amount);
account.balance = account.balance.add(_amount);
if (account.lastUnstakedTimestamp == 0) {
account.lastUnstakedTimestamp = block.timestamp;
}
account.lastStakedTimestamp = block.timestamp;
emit Staked(msg.sender, _amount);
}
function unstake(uint256 _amount) external nonReentrant {
AccountInfo storage account = accountInfos[msg.sender];
require(
!address(msg.sender).isContract(),
"Please use your individual account"
);
require(account.balance > 0, "Nothing to unstake");
require(_amount > 0, "Invalid amount");
if (account.balance < _amount) {
_amount = account.balance;
}
account.balance = account.balance.sub(_amount);
uint256 burnAmount = _amount.mul(getBurnFee(msg.sender)).div(10000);
if (burnAmount > 0) {
_amount = _amount.sub(burnAmount);
lockerToken.transfer(
address(0x000000000000000000000000000000000000dEaD),
burnAmount
);
}
account.lastUnstakedTimestamp = block.timestamp;
if (account.balance == 0) {
account.lastStakedTimestamp = 0;
account.lastUnstakedTimestamp = 0;
}
lockerToken.transfer(msg.sender, _amount);
emit Unstaked(msg.sender, _amount);
}
function getBurnFee(address _staker) public view returns (uint256) {
AccountInfo memory account = accountInfos[_staker];
for (uint256 i = 0; i < feeCycle.length; i++) {
if (block.timestamp < account.lastUnstakedTimestamp + feeCycle[i]) {
return burnFees[i];
}
}
return burnFees[feeCycle.length];
}
function setBurnFee(uint256 _index, uint256 fee) external onlyOwner {
require (fee <= 1000, "fee cannot exceed 1000");
burnFees[_index] = fee;
}
function setBurnCycle(uint256 _index, uint256 _cycle) external onlyOwner {
feeCycle[_index] = _cycle;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment