Skip to content

Instantly share code, notes, and snippets.

@xtpor
Created April 1, 2022 06:46
Show Gist options
  • Save xtpor/88f15dcc7e7c6123c2d10b1e4ef56887 to your computer and use it in GitHub Desktop.
Save xtpor/88f15dcc7e7c6123c2d10b1e4ef56887 to your computer and use it in GitHub Desktop.
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import "@openzeppelin/contracts/token/ERC20/extensions/ERC20Burnable.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
contract StakableToken is ERC20, Ownable {
constructor() ERC20("TestToken", "TT") {
_mint(msg.sender, 1000000 * 10 ** decimals());
_lastUpdateTime = block.timestamp;
}
function mint(address to, uint256 amount) public onlyOwner {
_mint(to, amount);
}
struct Stake {
uint256 stakedAmount;
uint256 unclaimedReward;
uint256 cumulativeReturn;
}
uint256 _cumulativeReturn;
uint256 _lastUpdateTime;
mapping(address => Stake) _stakes;
function rate() public pure returns (uint256) {
return 1e18 * 1 / uint256(1 hours);
}
function stakeToken(uint256 amount) public {
_updateStakeReward(msg.sender);
Stake storage stake = _stakes[msg.sender];
stake.stakedAmount += amount;
_transfer(msg.sender, address(this), amount);
}
function unstakeToken(uint256 amount) public {
_updateStakeReward(msg.sender);
Stake storage stake = _stakes[msg.sender];
stake.stakedAmount -= amount;
_transfer(address(this), msg.sender, amount);
}
function claimReward() public {
_updateStakeReward(msg.sender);
Stake storage stake = _stakes[msg.sender];
_mint(msg.sender, stake.unclaimedReward);
stake.unclaimedReward = 0;
}
function stakedAmount(address account) public view returns (uint256 reward) {
return _stakes[account].stakedAmount;
}
function unclaimedReward(address account) public view returns (uint256 reward) {
uint256 currentCumulativeReturn = _cumulativeReturn + (block.timestamp - _lastUpdateTime) * rate();
Stake storage stake = _stakes[account];
return stake.unclaimedReward + stake.stakedAmount * (currentCumulativeReturn - stake.cumulativeReturn) / 1e18;
}
function _updateCumulativeReturn() internal {
_cumulativeReturn += (block.timestamp - _lastUpdateTime) * rate();
_lastUpdateTime = block.timestamp;
}
function _updateStakeReward(address account) internal {
_updateCumulativeReturn();
Stake storage stake = _stakes[account];
stake.unclaimedReward += stake.stakedAmount * (_cumulativeReturn - stake.cumulativeReturn) / 1e18;
stake.cumulativeReturn = _cumulativeReturn;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment