Skip to content

Instantly share code, notes, and snippets.

@devtosxn
Created August 17, 2022 01:29
Show Gist options
  • Save devtosxn/f0fa5aaa5cca3a95c6ef75bdfe66a6aa to your computer and use it in GitHub Desktop.
Save devtosxn/f0fa5aaa5cca3a95c6ef75bdfe66a6aa to your computer and use it in GitHub Desktop.
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.9;
// Import this file to use console.log
import "hardhat/console.sol";
import "@openzeppelin/contracts/security/Pausable.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/security/ReentrancyGuard.sol";
import "@openzeppelin/contracts/utils/Context.sol";
interface CustomToken {
function transfer(address recipient, uint256 amount)
external
returns (bool);
function balanceOf(address account) external view returns (uint256);
function transferFrom(
address sender,
address recipient,
uint256 amount
) external returns (uint256);
}
// ANNUAL YIELD = 20%.
contract StakingContract is Pausable, Ownable, ReentrancyGuard {
// User deposits $ETH and specifies period for locking to the staking contract to earn a yield.
// This yield is paid out in $ETH.
// After depositing ETH, contract mints placeholder tokens (ERC20 - DEG) to the user.
// After specified period, user can trigger withdraw by depositing initial placeholder token back to the contract in the same transacctio
// Then they recieve their $ETH + yield.
// ***** If user withdraws before the specified period, they lose their yield. *****
// The staking yield can be calculated according to this formula:
// 14: Staking duration in days
// 100: Number of $ETH Staked
// 14÷365≈0.0384 → 0.0384×100≡3.84 $ETH Staking yield
CustomToken public token;
struct StakeInfo {
uint256 amount;
uint256 unlockTime;
uint256 yield;
}
mapping(address => StakeInfo) public stakers;
event Deposit(address indexed from, uint256 amount, uint256 unlockTime);
event Withdraw(address indexed from, uint256 amount);
constructor(address _token) {
token = CustomToken(_token);
}
function deposit(uint256 _amount, uint256 _unlockTime)
public
payable
whenNotPaused
nonReentrant
{
require(_amount > 0, "Amount must be greater than 0");
require(
_unlockTime > block.timestamp,
"Unlock time must be greater than current time"
);
// require(msg.value == _amount, "Amount must be equal to msg.value");
// uint256 unlockTime = block.timestamp + _unlockTime;
uint256 yield = calculateYield(_amount, _unlockTime);
stakers[msg.sender] = StakeInfo(_amount, _unlockTime, yield);
// Mint equivalent placeholder tokens to the user
token.transfer(msg.sender, _amount);
emit Deposit(msg.sender, _amount, _unlockTime);
}
function withdraw(uint256 _amount) public whenNotPaused nonReentrant {
require(_amount > 0, "Amount must be greater than 0");
require(stakers[msg.sender].amount >= _amount, "Insufficient balance");
uint256 unlockTime = stakers[msg.sender].unlockTime;
uint256 yield = stakers[msg.sender].yield;
require(block.timestamp >= unlockTime, "Stake is locked");
// Burn placeholder tokens
token.transferFrom(msg.sender, address(this), _amount);
// Send $ETH + yield to the user
stakers[msg.sender].amount -= _amount;
uint256 totalAmount = _amount + yield;
payable(msg.sender).transfer(totalAmount);
emit Withdraw(msg.sender, totalAmount);
}
function calculateYield(uint256 _amount, uint256 _unlockTime)
public
view
returns (uint256)
{
uint256 stakingDuration = _unlockTime - block.timestamp;
uint256 yield = (stakingDuration / 365) * _amount;
return yield;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment