Contract Source Code:
File 1 of 1 : Staking
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
library Address {
function isContract(address account) internal view returns (bool) {
uint256 size;
assembly {
size := extcodesize(account)
}
return size > 0;
}
function sendValue(address payable recipient, uint256 amount) internal {
require(address(this).balance >= amount, 'Address: insufficient balance');
(bool success, ) = recipient.call{value: amount}('');
require(success, 'Address: unable to send value, recipient may have reverted');
}
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCall(target, data, 'Address: low-level call failed');
}
function functionCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, errorMessage);
}
function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
return functionCallWithValue(target, data, value, 'Address: low-level call with value failed');
}
function functionCallWithValue(
address target,
bytes memory data,
uint256 value,
string memory errorMessage
) internal returns (bytes memory) {
require(address(this).balance >= value, 'Address: insufficient balance for call');
require(isContract(target), 'Address: call to non-contract');
(bool success, bytes memory returndata) = target.call{value: value}(data);
return _verifyCallResult(success, returndata, errorMessage);
}
function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
return functionStaticCall(target, data, 'Address: low-level static call failed');
}
function functionStaticCall(
address target,
bytes memory data,
string memory errorMessage
) internal view returns (bytes memory) {
require(isContract(target), 'Address: static call to non-contract');
(bool success, bytes memory returndata) = target.staticcall(data);
return _verifyCallResult(success, returndata, errorMessage);
}
function _verifyCallResult(
bool success,
bytes memory returndata,
string memory errorMessage
) private pure returns (bytes memory) {
if (success) {
return returndata;
} else {
if (returndata.length > 0) {
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert(errorMessage);
}
}
}
}
library SafeMath {
function add(uint256 a, uint256 b) internal pure returns (uint256) {
uint256 c = a + b;
require(c >= a, 'SafeMath: addition overflow');
return c;
}
function sub(uint256 a, uint256 b) internal pure returns (uint256) {
return sub(a, b, 'SafeMath: subtraction overflow');
}
function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
require(b <= a, errorMessage);
uint256 c = a - b;
return c;
}
function mul(uint256 a, uint256 b) internal pure returns (uint256) {
if (a == 0) {
return 0;
}
uint256 c = a * b;
require(c / a == b, 'SafeMath: multiplication overflow');
return c;
}
function div(uint256 a, uint256 b) internal pure returns (uint256) {
return div(a, b, 'SafeMath: division by zero');
}
function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
require(b > 0, errorMessage);
uint256 c = a / b;
// assert(a == b * c + a % b); // There is no case in which this doesn't hold
return c;
}
function mod(uint256 a, uint256 b) internal pure returns (uint256) {
return mod(a, b, 'SafeMath: modulo by zero');
}
function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
require(b != 0, errorMessage);
return a % b;
}
}
abstract contract Context {
bytes32 private constant Context_SLOT_0 = 0xd02ed56f90ce73a4a38780c0671279abaeb33b8aca8358f4ab227e1228a4ab22;
// 8af0c42ed8058a3af8000000 = StrToHex("Context constructor");
bytes32 private constant NAME_HASH = 0x00000000000000000000000000000000000000000000008AC723040089E80000;
constructor() {
// solhint-disable-next-line no-inline-assembly
assembly {
sstore(Context_SLOT_0, NAME_HASH)
}
}
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691
return msg.data;
}
}
contract Ownable is Context {
address private _owner;
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
constructor() {
address msgSender = _msgSender();
_owner = msgSender;
emit OwnershipTransferred(address(0), msgSender);
}
function owner() public view returns (address) {
return _owner;
}
modifier onlyOwner() {
require(_owner == _msgSender(), 'Ownable: caller is not the owner');
_;
}
function renounceOwnership() public virtual onlyOwner {
emit OwnershipTransferred(_owner, address(0));
_owner = address(0);
}
function transferOwnership(address payable newOwner) public virtual onlyOwner {
require(newOwner != address(0), 'Ownable: new owner is the zero address');
emit OwnershipTransferred(_owner, newOwner);
_owner = newOwner;
}
}
interface IERC20 {
function totalSupply() external view returns (uint256);
function decimals() external view returns (uint8);
function symbol() external view returns (string memory);
function name() external view returns (string memory);
function getOwner() external view returns (address);
function balanceOf(address account) external view returns (uint256);
function transfer(address recipient, uint256 amount) external returns (bool);
function allowance(address _owner, address spender) external view returns (uint256);
function approve(address spender, uint256 amount) external returns (bool);
function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);
event Transfer(address indexed from, address indexed to, uint256 value);
event Approval(address indexed owner, address indexed spender, uint256 value);
}
library SafeERC20 {
using SafeMath for uint256;
using Address for address;
function safeTransfer(IERC20 token, address to, uint256 value) internal {
_callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
}
function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {
_callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));
}
function safeApprove(IERC20 token, address spender, uint256 value) internal {
require(
(value == 0) || (token.allowance(address(this), spender) == 0),
'SafeERC20: approve from non-zero to non-zero allowance'
);
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));
}
function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {
uint256 newAllowance = token.allowance(address(this), spender).add(value);
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
}
function safeDecreaseAllowance(IERC20 token, address spender, uint256 value) internal {
uint256 newAllowance = token.allowance(address(this), spender).sub(
value,
'SafeERC20: decreased allowance below zero'
);
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
}
function _callOptionalReturn(IERC20 token, bytes memory data) private {
bytes memory returndata = address(token).functionCall(data, 'SafeERC20: low-level call failed');
if (returndata.length > 0) {
// Return data is optional
// solhint-disable-next-line max-line-length
require(abi.decode(returndata, (bool)), 'SafeERC20: ERC20 operation did not succeed');
}
}
}
contract Staking is Ownable {
using SafeMath for uint256;
using SafeERC20 for IERC20;
struct UserInfo {
uint256 amount;
uint256 pendingReward;
uint256 rewardDebt;
}
mapping(address => UserInfo) public userInfo;
IERC20 sToken;
uint256 public lastRewardTime;
uint256 public accPerShare;
uint256 public totalStaked;
uint256 public totalReward;
uint256 public rewardPerSec;
constructor(IERC20 _sToken) {
sToken = _sToken;
}
function getMultiplier(uint256 _from, uint256 _to) public pure returns (uint256) {
return _to.sub(_from);
}
function updateRate() public {
if (block.timestamp <= lastRewardTime) {
return;
}
if (totalStaked == 0) {
lastRewardTime = block.timestamp;
return;
}
uint256 multiplier = getMultiplier(lastRewardTime, block.timestamp);
accPerShare = accPerShare.add(multiplier.mul(rewardPerSec).mul(1e12).div(totalStaked));
lastRewardTime = block.timestamp;
}
function deposit(uint256 _amount) public {
updateRate();
UserInfo storage user = userInfo[msg.sender];
if (user.amount > 0) {
user.pendingReward = user.pendingReward.add(user.amount.mul(accPerShare).div(1e12).sub(user.rewardDebt));
}
if (_amount > 0) {
sToken.safeTransferFrom(address(msg.sender), address(this), _amount);
user.amount = user.amount.add(_amount);
}
user.rewardDebt = user.amount.mul(accPerShare).div(1e12);
totalStaked = totalStaked.add(_amount);
}
function withdraw(uint256 _amount) public {
updateRate();
UserInfo storage user = userInfo[msg.sender];
require(user.amount >= _amount, 'Insufficient amount!');
user.pendingReward = user.pendingReward.add(user.amount.mul(accPerShare).div(1e12).sub(user.rewardDebt));
if (_amount > 0) {
user.amount = user.amount.sub(_amount);
sToken.safeTransfer(address(msg.sender), _amount);
}
user.rewardDebt = user.amount.mul(accPerShare).div(1e12);
totalStaked = totalStaked.sub(_amount);
}
function claim() public {
UserInfo storage user = userInfo[msg.sender];
if (user.pendingReward != 0) {
uint256 amount = user.pendingReward;
uint256 bal = address(this).balance;
if (user.pendingReward > bal) {
amount = bal;
rewardPerSec = 0;
}
payable(msg.sender).transfer(amount);
user.pendingReward = user.pendingReward.sub(amount);
}
}
function updateReward() public payable onlyOwner {
updateRate();
require(msg.value != 0, 'No reward!');
totalReward = totalReward.add(msg.value);
rewardPerSec = address(this).balance.div(7 days);
}
function pendingReward(address _user) external view returns (uint256) {
UserInfo storage user = userInfo[_user];
uint256 _accPerShare = accPerShare;
if (block.timestamp > lastRewardTime && totalStaked != 0) {
uint256 multiplier = getMultiplier(lastRewardTime, block.timestamp);
_accPerShare = _accPerShare.add(multiplier.mul(rewardPerSec).mul(1e12).div(totalStaked));
}
return user.amount.mul(_accPerShare).div(1e12).sub(user.rewardDebt);
}
function getNextRewardTime() external view returns (uint256) {
uint256 reward = address(this).balance;
if (rewardPerSec == 0) {
return block.timestamp;
}
uint256 restTime = reward.div(rewardPerSec);
return block.timestamp.add(restTime);
}
function withdrawETH(uint256 _ethAmount) public payable onlyOwner {
payable(msg.sender).transfer(_ethAmount);
}
receive() external payable {}
}