Created
April 26, 2022 13:38
-
-
Save eMarchenko/e773b49bf9a60ef12d91823706b5b185 to your computer and use it in GitHub Desktop.
Prototype of an efficient staking smart contract
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
/* | |
Warning! The code is not production ready. It is provided for educational purposes only. | |
*/ | |
pragma solidity ^0.8.12; | |
import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; | |
import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; | |
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; | |
contract Staking is ERC20 { | |
using SafeERC20 for IERC20; | |
// the contract lacks over- and underflow checks on type casts. | |
// we recommend using a library to safely switch between signed and unsigned integers. | |
// potentially the same token | |
IERC20 public immutable stakedToken; | |
IERC20 public immutable rewardToken; | |
uint public rewardPerToken; | |
mapping(address => int256) private corrections; | |
constructor(IERC20 s, IERC20 r) ERC20("StakingToken", "stkn") { | |
stakedToken = s; | |
rewardToken = r; | |
} | |
function deposit(uint amount) external { | |
_mint(msg.sender, amount); | |
stakedToken.safeTransferFrom(msg.sender, address(this), amount); | |
} | |
function withdraw(uint amount) external { | |
_burn(msg.sender, amount); | |
stakedToken.safeTransfer(msg.sender, amount); | |
} | |
function addReward(uint amount) external { | |
// do smth if totalSupply == 0 | |
rewardPerToken += amount * 1e18 / totalSupply(); // 1e18 prevents rounding to 0 for smaller rewards | |
rewardToken.safeTransferFrom(msg.sender, address(this), amount); | |
} | |
function reward() public view returns (int) { | |
return (int(rewardPerToken * balanceOf(msg.sender)) + corrections[msg.sender]) ; | |
} | |
function claimReward() external { | |
int reward = reward(); | |
corrections[msg.sender] -= reward; | |
rewardToken.safeTransfer(msg.sender, uint(reward / 1e18)); | |
} | |
// the function is called from `_mint`, `_burn`, and `_transfer` | |
// we use it to manage reward corrections | |
function _beforeTokenTransfer(address from, address to, uint256 amount ) internal override virtual { | |
if (from != address(0)) { | |
corrections[from] += int(rewardPerToken*amount); | |
} | |
if (to != address(0)) { | |
corrections[to] -= int(rewardPerToken*amount); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment