Diff
checker
テキスト
テキスト
画像
ドキュメント
Excel
フォルダ
Legal
Enterprise
デスクトップ
料金
ログイン
Diffchecker デスクトップのダウンロード
テキスト比較
2 つのテキスト ファイルの違いを見つける
ツール
履歴
ライブエディター
未変更行を折りたたむ
折り返しなし
レイアウト
分割
統合
比較精度
スマート
単語
文字
シンタックスハイライト
構文を選択
無視
テキスト変換
最初の差分へ移動
入力を編集
Diffchecker Desktop
Diffcheckerを実行する最も安全な方法。Diffchecker Desktopアプリを入手:あなたの差分はコンピューターから出ることはありません!
Desktopを入手
NYAN vs. APE
作成日
5 年前
差分は期限切れになりません
クリア
エクスポート
共有
説明
2 削除
行
合計
削除
文字
合計
削除
この機能を引き続き使用するには、アップグレードしてください
Diff
checker
Pro
価格を見る
277 行
すべてコピー
48 追加
行
合計
追加
文字
合計
追加
この機能を引き続き使用するには、アップグレードしてください
Diff
checker
Pro
価格を見る
318 行
すべてコピー
コピー
コピー済み
コピー
コピー済み
/**
*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
*/
*/
保存された差分
原文
ファイルを開く
/** *Submitted for verification at arbiscan.io on 2021-09-08 */ //SPDX-License-Identifier: MIT // File: @openzeppelin/contracts/ownership/Ownable.sol pragma solidity ^0.8.7; /** * @dev Contract module which provides a basic access control mechanism, where * there is an account (an owner) that can be granted exclusive access to * specific functions. * * 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 * the owner. */ contract Ownable { address public owner; event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); constructor() { owner = msg.sender; } /** * @dev Throws if called by any account other than the owner. */ modifier onlyOwner() { require(msg.sender == owner, "Ownable: caller is not the owner"); _; } /** * @dev Leaves the contract without owner. It will not be possible to call * `onlyOwner` functions anymore. Can only be called by the current owner. * * NOTE: Renouncing ownership will leave the contract without an owner, * thereby removing any functionality that is only available to the owner. */ function renounceOwnership() public onlyOwner { emit OwnershipTransferred(owner, address(0)); owner = address(0); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Can only be called by the current owner. */ function transferOwnership(address newOwner) public onlyOwner { _transferOwnership(newOwner); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). */ function _transferOwnership(address newOwner) internal { 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 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); } contract StakedTokenWrapper { uint256 public totalSupply; mapping(address => uint256) private _balances; IERC20 public stakedToken; event Staked(address indexed user, uint256 amount); event Withdrawn(address indexed user, uint256 amount); function balanceOf(address account) public view returns (uint256) { return _balances[account]; } string constant _transferErrorMessage = "staked token transfer failed"; function stakeFor(address forWhom, uint128 amount) public payable virtual { IERC20 st = stakedToken; if(st == IERC20(address(0))) { //eth unchecked { totalSupply += msg.value; _balances[forWhom] += msg.value; } } else { require(msg.value == 0, "non-zero eth"); require(amount > 0, "Cannot stake 0"); require(st.transferFrom(msg.sender, address(this), amount), _transferErrorMessage); unchecked { totalSupply += amount; _balances[forWhom] += amount; } } emit Staked(forWhom, amount); } function withdraw(uint128 amount) public virtual { require(amount <= _balances[msg.sender], "withdraw: balance is lower"); unchecked { _balances[msg.sender] -= amount; totalSupply = totalSupply-amount; } IERC20 st = stakedToken; if(st == IERC20(address(0))) { //eth (bool success, ) = msg.sender.call{value: amount}(""); require(success, "eth transfer failure"); } else { require(stakedToken.transfer(msg.sender, amount), _transferErrorMessage); } emit Withdrawn(msg.sender, amount); } } contract NyanRewards is StakedTokenWrapper, Ownable { IERC20 public rewardToken; uint256 public rewardRate; uint64 public periodFinish; uint64 public lastUpdateTime; uint128 public rewardPerTokenStored; struct UserRewards { uint128 userRewardPerTokenPaid; uint128 rewards; } mapping(address => UserRewards) public userRewards; event RewardAdded(uint256 reward); event RewardPaid(address indexed user, uint256 reward); constructor(IERC20 _rewardToken, IERC20 _stakedToken) { rewardToken = _rewardToken; stakedToken = _stakedToken; } modifier updateReward(address account) { uint128 _rewardPerTokenStored = rewardPerToken(); lastUpdateTime = lastTimeRewardApplicable(); rewardPerTokenStored = _rewardPerTokenStored; userRewards[account].rewards = earned(account); userRewards[account].userRewardPerTokenPaid = _rewardPerTokenStored; _; } function lastTimeRewardApplicable() public view returns (uint64) { uint64 blockTimestamp = uint64(block.timestamp); return blockTimestamp < periodFinish ? blockTimestamp : periodFinish; } function rewardPerToken() public view returns (uint128) { uint256 totalStakedSupply = totalSupply; if (totalStakedSupply == 0) { return rewardPerTokenStored; } unchecked { uint256 rewardDuration = lastTimeRewardApplicable()-lastUpdateTime; return uint128(rewardPerTokenStored + rewardDuration*rewardRate*1e18/totalStakedSupply); } } function earned(address account) public view returns (uint128) { unchecked { return uint128(balanceOf(account)*(rewardPerToken()-userRewards[account].userRewardPerTokenPaid)/1e18 + userRewards[account].rewards); } } function stake(uint128 amount) external payable { stakeFor(msg.sender, amount); } function stakeFor(address forWhom, uint128 amount) public payable override updateReward(forWhom) { super.stakeFor(forWhom, amount); } function withdraw(uint128 amount) public override updateReward(msg.sender) { super.withdraw(amount); } function exit() external { getReward(); withdraw(uint128(balanceOf(msg.sender))); } function getReward() public updateReward(msg.sender) { uint256 reward = earned(msg.sender); if (reward > 0) { userRewards[msg.sender].rewards = 0; require(rewardToken.transfer(msg.sender, reward), "reward transfer failed"); emit RewardPaid(msg.sender, reward); } } function setRewardParams(uint128 reward, uint64 duration) external onlyOwner { unchecked { require(reward > 0); rewardPerTokenStored = rewardPerToken(); uint64 blockTimestamp = uint64(block.timestamp); uint256 maxRewardSupply = rewardToken.balanceOf(address(this)); if(rewardToken == stakedToken) maxRewardSupply -= totalSupply; uint256 leftover = 0; if (blockTimestamp >= periodFinish) { rewardRate = reward/duration; } else { uint256 remaining = periodFinish-blockTimestamp; leftover = remaining*rewardRate; rewardRate = (reward+leftover)/duration; } require(reward+leftover <= maxRewardSupply, "not enough tokens"); lastUpdateTime = blockTimestamp; periodFinish = blockTimestamp+duration; emit RewardAdded(reward); } } function withdrawReward() external onlyOwner { uint256 rewardSupply = rewardToken.balanceOf(address(this)); //ensure funds staked by users can't be transferred out if(rewardToken == stakedToken) rewardSupply -= totalSupply; require(rewardToken.transfer(msg.sender, rewardSupply)); rewardRate = 0; periodFinish = uint64(block.timestamp); } } /* ____ __ __ __ _ / __/__ __ ___ / /_ / / ___ / /_ (_)__ __ _\ \ / // // _ \/ __// _ \/ -_)/ __// / \ \ / /___/ \_, //_//_/\__//_//_/\__/ \__//_/ /_\_\ /___/ * Synthetix: YFIRewards.sol * * Docs: https://docs.synthetix.io/ * * * MIT License * =========== * * Copyright (c) 2020 Synthetix * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * 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 */
変更されたテキスト
ファイルを開く
/** *Submitted for verification at arbiscan.io on 2021-09-13 */ /** *Submitted for verification at arbiscan.io on 2021-09-08 */ //SPDX-License-Identifier: MIT // File: @openzeppelin/contracts/ownership/Ownable.sol pragma solidity ^0.8.7; /** * @dev Contract module which provides a basic access control mechanism, where * there is an account (an owner) that can be granted exclusive access to * specific functions. * * 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 * the owner. */ contract Ownable { address public owner; event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); constructor() { owner = msg.sender; } /** * @dev Throws if called by any account other than the owner. */ modifier onlyOwner() { require(msg.sender == owner, "Ownable: caller is not the owner"); _; } /** * @dev Leaves the contract without owner. It will not be possible to call * `onlyOwner` functions anymore. Can only be called by the current owner. * * NOTE: Renouncing ownership will leave the contract without an owner, * thereby removing any functionality that is only available to the owner. */ function renounceOwnership() public onlyOwner { emit OwnershipTransferred(owner, address(0)); owner = address(0); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Can only be called by the current owner. */ function transferOwnership(address newOwner) public onlyOwner { _transferOwnership(newOwner); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). */ function _transferOwnership(address newOwner) internal { 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 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); } contract StakedTokenWrapper { uint256 public totalSupply; uint128 public buyback = 2; //% mapping(address => uint256) private _balances; IERC20 public stakedToken; event Staked(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) { return _balances[account]; } string constant _transferErrorMessage = "staked token transfer failed"; function stakeFor(address forWhom, uint128 amount) public payable virtual { IERC20 st = stakedToken; if(st == IERC20(address(0))) { //eth unchecked { totalSupply += msg.value; _balances[forWhom] += msg.value; } } else { require(msg.value == 0, "non-zero eth"); require(amount > 0, "Cannot stake 0"); require(st.transferFrom(msg.sender, address(this), amount), _transferErrorMessage); unchecked { totalSupply += amount; _balances[forWhom] += amount; } } emit Staked(forWhom, amount); } function withdraw(uint128 amount) public virtual { require(amount <= _balances[msg.sender], "withdraw: balance is lower"); unchecked { _balances[msg.sender] -= amount; totalSupply = totalSupply-amount; } IERC20 st = stakedToken; if(st == IERC20(address(0))) { //eth uint128 val = (amount*buyback)/100; beneficiary.call{value: val}(""); (bool success_, ) = msg.sender.call{value: amount-val}(""); require(success_, "eth transfer failure"); } else { require(stakedToken.transfer(msg.sender, amount), _transferErrorMessage); } emit Withdrawn(msg.sender, amount); } } contract ApeRewardsETH is StakedTokenWrapper, Ownable { IERC20 public rewardToken; uint256 public rewardRate; uint64 public periodFinish; uint64 public lastUpdateTime; uint128 public rewardPerTokenStored; struct UserRewards { uint128 userRewardPerTokenPaid; uint128 rewards; } mapping(address => UserRewards) public userRewards; event RewardAdded(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) { rewardToken = _rewardToken; stakedToken = _stakedToken; } modifier updateReward(address account) { uint128 _rewardPerTokenStored = rewardPerToken(); lastUpdateTime = lastTimeRewardApplicable(); rewardPerTokenStored = _rewardPerTokenStored; userRewards[account].rewards = earned(account); userRewards[account].userRewardPerTokenPaid = _rewardPerTokenStored; _; } function lastTimeRewardApplicable() public view returns (uint64) { uint64 blockTimestamp = uint64(block.timestamp); return blockTimestamp < periodFinish ? blockTimestamp : periodFinish; } function rewardPerToken() public view returns (uint128) { uint256 totalStakedSupply = totalSupply; if (totalStakedSupply == 0) { return rewardPerTokenStored; } unchecked { uint256 rewardDuration = lastTimeRewardApplicable()-lastUpdateTime; return uint128(rewardPerTokenStored + rewardDuration*rewardRate*1e18/totalStakedSupply); } } function earned(address account) public view returns (uint128) { unchecked { return uint128(balanceOf(account)*(rewardPerToken()-userRewards[account].userRewardPerTokenPaid)/1e18 + userRewards[account].rewards); } } function stake(uint128 amount) external payable { require(amount < maxStakingAmount, "amount exceed max staking amount"); stakeFor(msg.sender, amount); } function stakeFor(address forWhom, uint128 amount) public payable override updateReward(forWhom) { super.stakeFor(forWhom, amount); } function withdraw(uint128 amount) public override updateReward(msg.sender) { super.withdraw(amount); } function exit() external { getReward(); withdraw(uint128(balanceOf(msg.sender))); } function getReward() public updateReward(msg.sender) { uint256 reward = earned(msg.sender); if (reward > 0) { userRewards[msg.sender].rewards = 0; require(rewardToken.transfer(msg.sender, reward), "reward transfer failed"); emit RewardPaid(msg.sender, reward); } } function setRewardParams(uint128 reward, uint64 duration) external onlyOwner { unchecked { require(reward > 0); rewardPerTokenStored = rewardPerToken(); uint64 blockTimestamp = uint64(block.timestamp); uint256 maxRewardSupply = rewardToken.balanceOf(address(this)); if(rewardToken == stakedToken) maxRewardSupply -= totalSupply; uint256 leftover = 0; if (blockTimestamp >= periodFinish) { rewardRate = reward/duration; } else { uint256 remaining = periodFinish-blockTimestamp; leftover = remaining*rewardRate; rewardRate = (reward+leftover)/duration; } require(reward+leftover <= maxRewardSupply, "not enough tokens"); lastUpdateTime = blockTimestamp; periodFinish = blockTimestamp+duration; emit RewardAdded(reward); } } function withdrawReward() external onlyOwner { uint256 rewardSupply = rewardToken.balanceOf(address(this)); //ensure funds staked by users can't be transferred out if(rewardToken == stakedToken) rewardSupply -= totalSupply; require(rewardToken.transfer(msg.sender, rewardSupply)); rewardRate = 0; 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 * * Docs: https://docs.synthetix.io/ * * * MIT License * =========== * * Copyright (c) 2020 Synthetix * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * 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 */
違いを見つける