NYAN vs. APE

Created Diff never expires
6 removals
276 lines
49 additions
318 lines
/**
*Submitted for verification at arbiscan.io on 2021-09-13
*/

/**
/**
*Submitted for verification at arbiscan.io on 2021-09-08
*Submitted for verification at arbiscan.io on 2021-09-08
*/
*/


//SPDX-License-Identifier: MIT
//SPDX-License-Identifier: MIT


// File: @openzeppelin/contracts/ownership/Ownable.sol
// File: @openzeppelin/contracts/ownership/Ownable.sol


pragma solidity ^0.8.7;
pragma solidity ^0.8.7;


/**
/**
* @dev Contract module which provides a basic access control mechanism, where
* @dev Contract module which provides a basic access control mechanism, where
* there is an account (an owner) that can be granted exclusive access to
* there is an account (an owner) that can be granted exclusive access to
* specific functions.
* specific functions.
*
*
* This module is used through inheritance. It will make available the modifier
* This module is used through inheritance. It will make available the modifier
* `onlyOwner`, which can be applied to your functions to restrict their use to
* `onlyOwner`, which can be applied to your functions to restrict their use to
* the owner.
* the owner.
*/
*/
contract Ownable {
contract Ownable {
address public owner;
address public owner;


event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);


constructor() {
constructor() {
owner = msg.sender;
owner = msg.sender;
}
}


/**
/**
* @dev Throws if called by any account other than the owner.
* @dev Throws if called by any account other than the owner.
*/
*/
modifier onlyOwner() {
modifier onlyOwner() {
require(msg.sender == owner, "Ownable: caller is not the owner");
require(msg.sender == owner, "Ownable: caller is not the owner");
_;
_;
}
}


/**
/**
* @dev Leaves the contract without owner. It will not be possible to call
* @dev Leaves the contract without owner. It will not be possible to call
* `onlyOwner` functions anymore. Can only be called by the current owner.
* `onlyOwner` functions anymore. Can only be called by the current owner.
*
*
* NOTE: Renouncing ownership will leave the contract without an owner,
* NOTE: Renouncing ownership will leave the contract without an owner,
* thereby removing any functionality that is only available to the owner.
* thereby removing any functionality that is only available to the owner.
*/
*/
function renounceOwnership() public onlyOwner {
function renounceOwnership() public onlyOwner {
emit OwnershipTransferred(owner, address(0));
emit OwnershipTransferred(owner, address(0));
owner = address(0);
owner = address(0);
}
}


/**
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Can only be called by the current owner.
* Can only be called by the current owner.
*/
*/
function transferOwnership(address newOwner) public onlyOwner {
function transferOwnership(address newOwner) public onlyOwner {
_transferOwnership(newOwner);
_transferOwnership(newOwner);
}
}


/**
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* @dev Transfers ownership of the contract to a new account (`newOwner`).
*/
*/
function _transferOwnership(address newOwner) internal {
function _transferOwnership(address newOwner) internal {
require(newOwner != address(0), "Ownable: new owner is the zero address");
require(newOwner != address(0), "Ownable: new owner is the zero address");
emit OwnershipTransferred(owner, newOwner);
emit OwnershipTransferred(owner, newOwner);
owner = newOwner;
owner = newOwner;
}
}
}
}


interface IERC20 {
interface IERC20 {
function totalSupply() external view returns (uint256);
function totalSupply() external view returns (uint256);
function balanceOf(address account) external view returns (uint256);
function balanceOf(address account) external view returns (uint256);
function transfer(address recipient, uint256 amount) external returns (bool);
function transfer(address recipient, uint256 amount) external returns (bool);
function allowance(address owner, address spender) external view returns (uint256);
function allowance(address owner, address spender) external view returns (uint256);
function approve(address spender, uint256 amount) external returns (bool);
function approve(address spender, uint256 amount) external returns (bool);
function transferFrom(address sender, address recipient, 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 Transfer(address indexed from, address indexed to, uint256 value);
event Approval(address indexed owner, address indexed spender, uint256 value);
event Approval(address indexed owner, address indexed spender, uint256 value);
}
}



contract StakedTokenWrapper {
contract StakedTokenWrapper {
uint256 public totalSupply;
uint256 public totalSupply;
uint128 public buyback = 2; //%
mapping(address => uint256) private _balances;
mapping(address => uint256) private _balances;
IERC20 public stakedToken;
IERC20 public stakedToken;
event Staked(address indexed user, uint256 amount);
event Staked(address indexed user, uint256 amount);
event Withdrawn(address indexed user, uint256 amount);
event Withdrawn(address indexed user, uint256 amount);


address public beneficiary = address(0x0398C40b50B4db0F76F1bc9C33403D17D005dA36);
function balanceOf(address account) public view returns (uint256) {
function balanceOf(address account) public view returns (uint256) {
return _balances[account];
return _balances[account];
}
}





string constant _transferErrorMessage = "staked token transfer failed";
string constant _transferErrorMessage = "staked token transfer failed";
function stakeFor(address forWhom, uint128 amount) public payable virtual {
function stakeFor(address forWhom, uint128 amount) public payable virtual {
IERC20 st = stakedToken;
IERC20 st = stakedToken;
if(st == IERC20(address(0))) { //eth
if(st == IERC20(address(0))) { //eth
unchecked {
unchecked {
totalSupply += msg.value;
totalSupply += msg.value;
_balances[forWhom] += msg.value;
_balances[forWhom] += msg.value;
}
}
}
}
else {
else {
require(msg.value == 0, "non-zero eth");
require(msg.value == 0, "non-zero eth");
require(amount > 0, "Cannot stake 0");
require(amount > 0, "Cannot stake 0");
require(st.transferFrom(msg.sender, address(this), amount), _transferErrorMessage);
require(st.transferFrom(msg.sender, address(this), amount), _transferErrorMessage);
unchecked {
unchecked {
totalSupply += amount;
totalSupply += amount;
_balances[forWhom] += amount;
_balances[forWhom] += amount;
}
}
}
}
emit Staked(forWhom, amount);
emit Staked(forWhom, amount);
}
}




function withdraw(uint128 amount) public virtual {
function withdraw(uint128 amount) public virtual {
require(amount <= _balances[msg.sender], "withdraw: balance is lower");
require(amount <= _balances[msg.sender], "withdraw: balance is lower");
unchecked {
unchecked {
_balances[msg.sender] -= amount;
_balances[msg.sender] -= amount;
totalSupply = totalSupply-amount;
totalSupply = totalSupply-amount;
}
}
IERC20 st = stakedToken;
IERC20 st = stakedToken;
if(st == IERC20(address(0))) { //eth
if(st == IERC20(address(0))) { //eth
(bool success, ) = msg.sender.call{value: amount}("");

require(success, "eth transfer failure");
uint128 val = (amount*buyback)/100;

beneficiary.call{value: val}("");

(bool success_, ) = msg.sender.call{value: amount-val}("");
require(success_, "eth transfer failure");
}
}
else {
else {
require(stakedToken.transfer(msg.sender, amount), _transferErrorMessage);
require(stakedToken.transfer(msg.sender, amount), _transferErrorMessage);
}
}
emit Withdrawn(msg.sender, amount);
emit Withdrawn(msg.sender, amount);
}
}
}
}


contract NyanRewards is StakedTokenWrapper, Ownable {
contract ApeRewardsETH is StakedTokenWrapper, Ownable {

IERC20 public rewardToken;
IERC20 public rewardToken;
uint256 public rewardRate;
uint256 public rewardRate;
uint64 public periodFinish;
uint64 public periodFinish;
uint64 public lastUpdateTime;
uint64 public lastUpdateTime;
uint128 public rewardPerTokenStored;
uint128 public rewardPerTokenStored;

struct UserRewards {
struct UserRewards {
uint128 userRewardPerTokenPaid;
uint128 userRewardPerTokenPaid;
uint128 rewards;
uint128 rewards;
}
}
mapping(address => UserRewards) public userRewards;
mapping(address => UserRewards) public userRewards;


event RewardAdded(uint256 reward);
event RewardAdded(uint256 reward);
event RewardPaid(address indexed user, uint256 reward);
event RewardPaid(address indexed user, uint256 reward);


uint256 public maxStakingAmount = 2 * 10**0 * 10**17 ; //0.2 ETH


constructor(IERC20 _rewardToken, IERC20 _stakedToken) {
constructor(IERC20 _rewardToken, IERC20 _stakedToken) {
rewardToken = _rewardToken;
rewardToken = _rewardToken;
stakedToken = _stakedToken;
stakedToken = _stakedToken;
}
}


modifier updateReward(address account) {
modifier updateReward(address account) {
uint128 _rewardPerTokenStored = rewardPerToken();
uint128 _rewardPerTokenStored = rewardPerToken();
lastUpdateTime = lastTimeRewardApplicable();
lastUpdateTime = lastTimeRewardApplicable();
rewardPerTokenStored = _rewardPerTokenStored;
rewardPerTokenStored = _rewardPerTokenStored;
userRewards[account].rewards = earned(account);
userRewards[account].rewards = earned(account);
userRewards[account].userRewardPerTokenPaid = _rewardPerTokenStored;
userRewards[account].userRewardPerTokenPaid = _rewardPerTokenStored;
_;
_;
}
}


function lastTimeRewardApplicable() public view returns (uint64) {
function lastTimeRewardApplicable() public view returns (uint64) {
uint64 blockTimestamp = uint64(block.timestamp);
uint64 blockTimestamp = uint64(block.timestamp);
return blockTimestamp < periodFinish ? blockTimestamp : periodFinish;
return blockTimestamp < periodFinish ? blockTimestamp : periodFinish;
}
}


function rewardPerToken() public view returns (uint128) {
function rewardPerToken() public view returns (uint128) {
uint256 totalStakedSupply = totalSupply;
uint256 totalStakedSupply = totalSupply;
if (totalStakedSupply == 0) {
if (totalStakedSupply == 0) {
return rewardPerTokenStored;
return rewardPerTokenStored;
}
}
unchecked {
unchecked {
uint256 rewardDuration = lastTimeRewardApplicable()-lastUpdateTime;
uint256 rewardDuration = lastTimeRewardApplicable()-lastUpdateTime;
return uint128(rewardPerTokenStored + rewardDuration*rewardRate*1e18/totalStakedSupply);
return uint128(rewardPerTokenStored + rewardDuration*rewardRate*1e18/totalStakedSupply);
}
}
}
}


function earned(address account) public view returns (uint128) {
function earned(address account) public view returns (uint128) {
unchecked {
unchecked {
return uint128(balanceOf(account)*(rewardPerToken()-userRewards[account].userRewardPerTokenPaid)/1e18 + userRewards[account].rewards);
return uint128(balanceOf(account)*(rewardPerToken()-userRewards[account].userRewardPerTokenPaid)/1e18 + userRewards[account].rewards);
}
}
}
}


function stake(uint128 amount) external payable {
function stake(uint128 amount) external payable {
require(amount < maxStakingAmount, "amount exceed max staking amount");
stakeFor(msg.sender, amount);
stakeFor(msg.sender, amount);
}
}


function stakeFor(address forWhom, uint128 amount) public payable override updateReward(forWhom) {
function stakeFor(address forWhom, uint128 amount) public payable override updateReward(forWhom) {
super.stakeFor(forWhom, amount);
super.stakeFor(forWhom, amount);
}
}


function withdraw(uint128 amount) public override updateReward(msg.sender) {
function withdraw(uint128 amount) public override updateReward(msg.sender) {

super.withdraw(amount);
super.withdraw(amount);
}
}


function exit() external {
function exit() external {
getReward();
getReward();
withdraw(uint128(balanceOf(msg.sender)));
withdraw(uint128(balanceOf(msg.sender)));
}
}


function getReward() public updateReward(msg.sender) {
function getReward() public updateReward(msg.sender) {
uint256 reward = earned(msg.sender);
uint256 reward = earned(msg.sender);
if (reward > 0) {
if (reward > 0) {
userRewards[msg.sender].rewards = 0;
userRewards[msg.sender].rewards = 0;
require(rewardToken.transfer(msg.sender, reward), "reward transfer failed");
require(rewardToken.transfer(msg.sender, reward), "reward transfer failed");
emit RewardPaid(msg.sender, reward);
emit RewardPaid(msg.sender, reward);
}
}
}
}


function setRewardParams(uint128 reward, uint64 duration) external onlyOwner {
function setRewardParams(uint128 reward, uint64 duration) external onlyOwner {
unchecked {
unchecked {
require(reward > 0);
require(reward > 0);
rewardPerTokenStored = rewardPerToken();
rewardPerTokenStored = rewardPerToken();
uint64 blockTimestamp = uint64(block.timestamp);
uint64 blockTimestamp = uint64(block.timestamp);
uint256 maxRewardSupply = rewardToken.balanceOf(address(this));
uint256 maxRewardSupply = rewardToken.balanceOf(address(this));
if(rewardToken == stakedToken)
if(rewardToken == stakedToken)
maxRewardSupply -= totalSupply;
maxRewardSupply -= totalSupply;
uint256 leftover = 0;
uint256 leftover = 0;
if (blockTimestamp >= periodFinish) {
if (blockTimestamp >= periodFinish) {
rewardRate = reward/duration;
rewardRate = reward/duration;
} else {
} else {
uint256 remaining = periodFinish-blockTimestamp;
uint256 remaining = periodFinish-blockTimestamp;
leftover = remaining*rewardRate;
leftover = remaining*rewardRate;
rewardRate = (reward+leftover)/duration;
rewardRate = (reward+leftover)/duration;
}
}
require(reward+leftover <= maxRewardSupply, "not enough tokens");
require(reward+leftover <= maxRewardSupply, "not enough tokens");
lastUpdateTime = blockTimestamp;
lastUpdateTime = blockTimestamp;
periodFinish = blockTimestamp+duration;
periodFinish = blockTimestamp+duration;
emit RewardAdded(reward);
emit RewardAdded(reward);
}
}
}
}


function withdrawReward() external onlyOwner {
function withdrawReward() external onlyOwner {
uint256 rewardSupply = rewardToken.balanceOf(address(this));
uint256 rewardSupply = rewardToken.balanceOf(address(this));
//ensure funds staked by users can't be transferred out
//ensure funds staked by users can't be transferred out
if(rewardToken == stakedToken)
if(rewardToken == stakedToken)
rewardSupply -= totalSupply;
rewardSupply -= totalSupply;
require(rewardToken.transfer(msg.sender, rewardSupply));
require(rewardToken.transfer(msg.sender, rewardSupply));
rewardRate = 0;
rewardRate = 0;
periodFinish = uint64(block.timestamp);
periodFinish = uint64(block.timestamp);
}
}

function setMaxStakingAmount(uint256 value) external onlyOwner {
require(value > 0);
maxStakingAmount = value;
}

function setBuyback(uint128 value) external onlyOwner {
buyback = value;
}

function setBuyBackAddr(address addr) external onlyOwner {
beneficiary = addr;
}
}
}


/*
/*
____ __ __ __ _
____ __ __ __ _
/ __/__ __ ___ / /_ / / ___ / /_ (_)__ __
/ __/__ __ ___ / /_ / / ___ / /_ (_)__ __
_\ \ / // // _ \/ __// _ \/ -_)/ __// / \ \ /
_\ \ / // // _ \/ __// _ \/ -_)/ __// / \ \ /
/___/ \_, //_//_/\__//_//_/\__/ \__//_/ /_\_\
/___/ \_, //_//_/\__//_//_/\__/ \__//_/ /_\_\
/___/
/___/


* Synthetix: YFIRewards.sol
* Synthetix: YFIRewards.sol
*
*
* Docs: https://docs.synthetix.io/
* Docs: https://docs.synthetix.io/
*
*
*
*
* MIT License
* MIT License
* ===========
* ===========
*
*
* Copyright (c) 2020 Synthetix
* Copyright (c) 2020 Synthetix
*
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
* furnished to do so, subject to the following conditions:
*
*
* The above copyright notice and this permission notice shall be included in all
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
* copies or substantial portions of the Software.
*
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
*/
*/