Created
August 17, 2022 01:29
-
-
Save devtosxn/f0fa5aaa5cca3a95c6ef75bdfe66a6aa to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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