Diff
checker
Testo
Testo
Immagini
Documenti
Excel
Cartelle
Legal
Enterprise
Applicazione per desktop
Prezzi
Accedi
Scarica Diffchecker Desktop
Confronta il testo
Trova la differenza tra due file di testo
Strumenti
Cronologia
Editor live
Comprimi invariate
Senza a capo
Layout
Diviso
Unificato
Livello di dettaglio
Intelligente
Parola
Carattere
Evidenziazione sintassi
Scegli sintassi
Ignora
Trasforma testo
Vai alla prima modifica
Modifica input
Diffchecker Desktop
Il modo più sicuro per usare Diffchecker. Ottieni l'app Diffchecker Desktop: i tuoi diff non lasciano mai il tuo computer!
Ottieni Desktop
staking-rewards-updates
Creato
3 anni fa
Il diff non scade mai
Eliminare
Esporta
Condividere
Spiegare
73 rimozioni
Linee
Totale
Rimosso
Caratteri
Totale
Rimosso
Per continuare a utilizzare questa funzione, aggiorna a
Diff
checker
Pro
Visualizza prezzi
292 linee
Copia tutti
115 aggiunte
Linee
Totale
Aggiunto
Caratteri
Totale
Aggiunto
Per continuare a utilizzare questa funzione, aggiorna a
Diff
checker
Pro
Visualizza prezzi
340 linee
Copia tutti
Copia
Copiato
Copia
Copiato
pragma solidity ^0.5.16;
// SPDX-FileCopyrightText: Ā© 2019-2021 Synthetix
// SPDX-FileCopyrightText: Ā© 2023 Dai Foundation <www.daifoundation.org>
// Inheritance
// SPDX-License-Identifier: MIT AND AGPL-3.0-or-later
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
pragma solidity 0.8.19;
// https://docs.synthetix.io/contracts/source/interfaces/istakingrewards
// https://docs.synthetix.io/contracts/source/interfaces/istakingrewards
interface IStakingRewards {
interface IStakingRewards {
// Views
// Views
function balanceOf(address account) external view returns (uint256);
function balanceOf(address account) external view returns (uint256);
function earned(address account) external view returns (uint256);
function earned(address account) external view returns (uint256);
function getRewardForDuration() external view returns (uint256);
function getRewardForDuration() external view returns (uint256);
function lastTimeRewardApplicable() external view returns (uint256);
function lastTimeRewardApplicable() external view returns (uint256);
function rewardPerToken() external view returns (uint256);
function rewardPerToken() external view returns (uint256);
function rewardsDistribution() external view returns (address);
function rewardsDistribution() external view returns (address);
Copia
Copiato
Copia
Copiato
function rewardsToken() external view returns (
address
);
function rewardsToken() external view returns (
IERC20);
function stakingToken() external view returns (IERC20
);
function totalSupply() external view returns (uint256);
function totalSupply() external view returns (uint256);
// Mutative
// Mutative
function exit() external;
function exit() external;
function getReward() external;
function getReward() external;
function stake(uint256 amount) external;
function stake(uint256 amount) external;
Copia
Copiato
Copia
Copiato
function stake(uint256 amount, uint16 referral) external;
function withdraw(uint256 amount) external;
function withdraw(uint256 amount) external;
Copia
Copiato
Copia
Copiato
function notifyRewardAmount(uint256 reward) external;
function setRewardsDistribution(address _rewardsDistribution) external;
}
}
Copia
Copiato
Copia
Copiato
// SPDX-FileCopyrightText: Ā© 2019-2021 Synthetix
// SPDX-FileCopyrightText: Ā© 2023 Dai Foundation <www.daifoundation.org>
// SPDX-License-Identifier: MIT AND AGPL-3.0-or-later
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
// Inheritance
// Inheritance
Copia
Copiato
Copia
Copiato
// SPDX-FileCopyrightText: Ā© 2019-2021 Synthetix
// SPDX-FileCopyrightText: Ā© 2023 Dai Foundation <www.daifoundation.org>
// SPDX-License-Identifier: MIT AND AGPL-3.0-or-later
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
// https://docs.synthetix.io/contracts/source/contracts/owned
// https://docs.synthetix.io/contracts/source/contracts/owned
contract Owned {
contract Owned {
address public owner;
address public owner;
address public nominatedOwner;
address public nominatedOwner;
Copia
Copiato
Copia
Copiato
constructor(address _owner)
public
{
constructor(address _owner)
{
require(_owner != address(0), "Owner address cannot be 0");
require(_owner != address(0), "Owner address cannot be 0");
owner = _owner;
owner = _owner;
emit OwnerChanged(address(0), _owner);
emit OwnerChanged(address(0), _owner);
}
}
function nominateNewOwner(address _owner) external onlyOwner {
function nominateNewOwner(address _owner) external onlyOwner {
nominatedOwner = _owner;
nominatedOwner = _owner;
emit OwnerNominated(_owner);
emit OwnerNominated(_owner);
}
}
function acceptOwnership() external {
function acceptOwnership() external {
require(msg.sender == nominatedOwner, "You must be nominated before you can accept ownership");
require(msg.sender == nominatedOwner, "You must be nominated before you can accept ownership");
emit OwnerChanged(owner, nominatedOwner);
emit OwnerChanged(owner, nominatedOwner);
owner = nominatedOwner;
owner = nominatedOwner;
nominatedOwner = address(0);
nominatedOwner = address(0);
}
}
Copia
Copiato
Copia
Copiato
modifier onlyOwner
{
modifier onlyOwner
()
{
_onlyOwner();
_onlyOwner();
_;
_;
}
}
function _onlyOwner() private view {
function _onlyOwner() private view {
require(msg.sender == owner, "Only the contract owner may perform this action");
require(msg.sender == owner, "Only the contract owner may perform this action");
}
}
event OwnerNominated(address newOwner);
event OwnerNominated(address newOwner);
event OwnerChanged(address oldOwner, address newOwner);
event OwnerChanged(address oldOwner, address newOwner);
}
}
Copia
Copiato
Copia
Copiato
// https://docs.synthetix.io/contracts/source/contracts/rewardsdistributionrecipient
contract RewardsDistributionRecipient is Owned {
address public rewardsDistribution;
function notifyRewardAmount(uint256 reward) external;
Text moved to lines 324-328
modifier onlyRewardsDistribution() {
require(msg.sender == rewardsDistribution, "Caller is not RewardsDistribution contract");
_;
}
function setRewardsDistribution(address _rewardsDistribution) external onlyOwner {
rewardsDistribution = _rewardsDistribution;
}
}
// Inheritance
// https://docs.synthetix.io/contracts/source/contracts/pausable
// https://docs.synthetix.io/contracts/source/contracts/pausable
Copia
Copiato
Copia
Copiato
contract Pausable is Owned {
abstract
contract Pausable is Owned {
uint public lastPauseTime;
uint public lastPauseTime;
bool public paused;
bool public paused;
Copia
Copiato
Copia
Copiato
constructor(
) internal {
constructor(
address
_o
wner
) Owned(_owner) {}
// This contract is abstract, and thus cannot be instantiated directly
require(owner !=
address
(0), "O
wner
must be set");
// Paused will be false, and lastPauseTime will be 0 upon initialisation
}
/**
/**
* @notice Change the paused state of the contract
* @notice Change the paused state of the contract
* @dev Only the contract owner may call this.
* @dev Only the contract owner may call this.
*/
*/
function setPaused(bool _paused) external onlyOwner {
function setPaused(bool _paused) external onlyOwner {
// Ensure we're actually changing the state before we do anything
// Ensure we're actually changing the state before we do anything
if (_paused == paused) {
if (_paused == paused) {
return;
return;
}
}
// Set our paused state.
// Set our paused state.
paused = _paused;
paused = _paused;
// If applicable, set the last pause time.
// If applicable, set the last pause time.
if (paused) {
if (paused) {
Copia
Copiato
Copia
Copiato
lastPauseTime =
now
;
lastPauseTime =
block.timestamp
;
}
}
// Let everyone know that our pause state has changed.
// Let everyone know that our pause state has changed.
emit PauseChanged(paused);
emit PauseChanged(paused);
}
}
event PauseChanged(bool isPaused);
event PauseChanged(bool isPaused);
Copia
Copiato
Copia
Copiato
modifier notPaused
{
modifier notPaused
()
{
require(!paused, "This action cannot be performed while the contract is paused");
require(!paused, "This action cannot be performed while the contract is paused");
_;
_;
}
}
}
}
// https://docs.synthetix.io/contracts/source/contracts/stakingrewards
// https://docs.synthetix.io/contracts/source/contracts/stakingrewards
Copia
Copiato
Copia
Copiato
contract StakingRewards is IStakingRewards,
RewardsDistributionRecipient
, ReentrancyGuard
, Pausable {
contract StakingRewards is IStakingRewards,
Pausable
, ReentrancyGuard
{
using SafeMath for uint256;
using SafeERC20 for IERC20;
using SafeERC20 for IERC20;
/* ========== STATE VARIABLES ========== */
/* ========== STATE VARIABLES ========== */
Copia
Copiato
Copia
Copiato
IERC20 public
rewardsToken;
IERC20 public
immutable
rewardsToken;
IERC20 public
stakingToken;
IERC20 public
immutable
stakingToken;
address public rewardsDistribution;
uint256 public periodFinish = 0;
uint256 public periodFinish = 0;
uint256 public rewardRate = 0;
uint256 public rewardRate = 0;
uint256 public rewardsDuration = 7 days;
uint256 public rewardsDuration = 7 days;
uint256 public lastUpdateTime;
uint256 public lastUpdateTime;
uint256 public rewardPerTokenStored;
uint256 public rewardPerTokenStored;
mapping(address => uint256) public userRewardPerTokenPaid;
mapping(address => uint256) public userRewardPerTokenPaid;
mapping(address => uint256) public rewards;
mapping(address => uint256) public rewards;
uint256 private _totalSupply;
uint256 private _totalSupply;
mapping(address => uint256) private _balances;
mapping(address => uint256) private _balances;
/* ========== CONSTRUCTOR ========== */
/* ========== CONSTRUCTOR ========== */
constructor(
constructor(
address _owner,
address _owner,
address _rewardsDistribution,
address _rewardsDistribution,
address _rewardsToken,
address _rewardsToken,
address _stakingToken
address _stakingToken
Copia
Copiato
Copia
Copiato
)
public Owned
(_owner) {
)
Pausable
(_owner) {
rewardsToken = IERC20(_rewardsToken);
rewardsToken = IERC20(_rewardsToken);
stakingToken = IERC20(_stakingToken);
stakingToken = IERC20(_stakingToken);
rewardsDistribution = _rewardsDistribution;
rewardsDistribution = _rewardsDistribution;
}
}
/* ========== VIEWS ========== */
/* ========== VIEWS ========== */
function totalSupply() external view returns (uint256) {
function totalSupply() external view returns (uint256) {
return _totalSupply;
return _totalSupply;
}
}
function balanceOf(address account) external view returns (uint256) {
function balanceOf(address account) external view returns (uint256) {
return _balances[account];
return _balances[account];
}
}
function lastTimeRewardApplicable() public view returns (uint256) {
function lastTimeRewardApplicable() public view returns (uint256) {
return block.timestamp < periodFinish ? block.timestamp : periodFinish;
return block.timestamp < periodFinish ? block.timestamp : periodFinish;
}
}
function rewardPerToken() public view returns (uint256) {
function rewardPerToken() public view returns (uint256) {
if (_totalSupply == 0) {
if (_totalSupply == 0) {
return rewardPerTokenStored;
return rewardPerTokenStored;
}
}
return
return
Copia
Copiato
Copia
Copiato
rewardPerTokenStored
.add(
rewardPerTokenStored
+ (((
lastTimeRewardApplicable()
-
lastUpdateTime)
*
rewardRate
*
1e18)
/
_totalSupply)
;
lastTimeRewardApplicable()
.sub(
lastUpdateTime)
.mul(
rewardRate
).mul(
1e18)
.div(
_totalSupply)
)
;
}
}
function earned(address account) public view returns (uint256) {
function earned(address account) public view returns (uint256) {
Copia
Copiato
Copia
Copiato
return
_balances[account]
.mul
(rewardPerToken()
.sub(
userRewardPerTokenPaid[account]))
.div(
1e18
).add(
rewards[account]
)
;
return
(
_balances[account]
*
(rewardPerToken()
-
userRewardPerTokenPaid[account]))
/
1e18
+
rewards[account]
;
}
}
function getRewardForDuration() external view returns (uint256) {
function getRewardForDuration() external view returns (uint256) {
Copia
Copiato
Copia
Copiato
return rewardRate
.mul(
rewardsDuration
)
;
return rewardRate
*
rewardsDuration
;
}
}
/* ========== MUTATIVE FUNCTIONS ========== */
/* ========== MUTATIVE FUNCTIONS ========== */
Copia
Copiato
Copia
Copiato
function stake(uint256 amount)
external
nonReentrant notPaused updateReward(msg.sender) {
function stake(uint256 amount)
public
nonReentrant notPaused updateReward(msg.sender) {
require(amount > 0, "Cannot stake 0");
require(amount > 0, "Cannot stake 0");
Copia
Copiato
Copia
Copiato
_totalSupply = _totalSupply
.add(
amount
)
;
_totalSupply = _totalSupply
+
amount
;
_balances[msg.sender] = _balances[msg.sender]
.add(
amount
)
;
_balances[msg.sender] = _balances[msg.sender]
+
amount
;
stakingToken.safeTransferFrom(msg.sender, address(this), amount);
stakingToken.safeTransferFrom(msg.sender, address(this), amount);
emit Staked(msg.sender, amount);
emit Staked(msg.sender, amount);
}
}
Copia
Copiato
Copia
Copiato
function stake(uint256 amount, uint16 referral) external {
stake(amount);
emit Referral(referral, msg.sender, amount);
}
function withdraw(uint256 amount) public nonReentrant updateReward(msg.sender) {
function withdraw(uint256 amount) public nonReentrant updateReward(msg.sender) {
require(amount > 0, "Cannot withdraw 0");
require(amount > 0, "Cannot withdraw 0");
Copia
Copiato
Copia
Copiato
_totalSupply = _totalSupply
.sub(
amount
)
;
_totalSupply = _totalSupply
-
amount
;
_balances[msg.sender] = _balances[msg.sender]
.sub(
amount
)
;
_balances[msg.sender] = _balances[msg.sender]
-
amount
;
stakingToken.safeTransfer(msg.sender, amount);
stakingToken.safeTransfer(msg.sender, amount);
emit Withdrawn(msg.sender, amount);
emit Withdrawn(msg.sender, amount);
}
}
function getReward() public nonReentrant updateReward(msg.sender) {
function getReward() public nonReentrant updateReward(msg.sender) {
uint256 reward = rewards[msg.sender];
uint256 reward = rewards[msg.sender];
if (reward > 0) {
if (reward > 0) {
rewards[msg.sender] = 0;
rewards[msg.sender] = 0;
rewardsToken.safeTransfer(msg.sender, reward);
rewardsToken.safeTransfer(msg.sender, reward);
emit RewardPaid(msg.sender, reward);
emit RewardPaid(msg.sender, reward);
}
}
}
}
function exit() external {
function exit() external {
withdraw(_balances[msg.sender]);
withdraw(_balances[msg.sender]);
getReward();
getReward();
}
}
/* ========== RESTRICTED FUNCTIONS ========== */
/* ========== RESTRICTED FUNCTIONS ========== */
Copia
Copiato
Copia
Copiato
function notifyRewardAmount(uint256 reward) external
onlyRewardsDistribution updateReward(address(0)) {
function notifyRewardAmount(uint256 reward) external
override
onlyRewardsDistribution updateReward(address(0)) {
if (block.timestamp >= periodFinish) {
if (block.timestamp >= periodFinish) {
Copia
Copiato
Copia
Copiato
rewardRate = reward
.div(
rewardsDuration
)
;
rewardRate = reward
/
rewardsDuration
;
} else {
} else {
Copia
Copiato
Copia
Copiato
uint256 remaining = periodFinish
.sub(
block.timestamp
)
;
uint256 remaining = periodFinish
-
block.timestamp
;
uint256 leftover = remaining
.mul(
rewardRate
)
;
uint256 leftover = remaining
*
rewardRate
;
rewardRate =
reward
.add(
leftover)
.div(
rewardsDuration
)
;
rewardRate =
(
reward
+
leftover)
/
rewardsDuration
;
}
}
// Ensure the provided reward amount is not more than the balance in the contract.
// Ensure the provided reward amount is not more than the balance in the contract.
// This keeps the reward rate in the right range, preventing overflows due to
// This keeps the reward rate in the right range, preventing overflows due to
// very high values of rewardRate in the earned and rewardsPerToken functions;
// very high values of rewardRate in the earned and rewardsPerToken functions;
// Reward + leftover must be less than 2^256 / 10^18 to avoid overflow.
// Reward + leftover must be less than 2^256 / 10^18 to avoid overflow.
uint balance = rewardsToken.balanceOf(address(this));
uint balance = rewardsToken.balanceOf(address(this));
Copia
Copiato
Copia
Copiato
require(rewardRate <= balance
.div(
rewardsDuration
)
, "Provided reward too high");
require(rewardRate <= balance
/
rewardsDuration
, "Provided reward too high");
lastUpdateTime = block.timestamp;
lastUpdateTime = block.timestamp;
Copia
Copiato
Copia
Copiato
periodFinish = block.timestamp
.add(
rewardsDuration
)
;
periodFinish = block.timestamp
+
rewardsDuration
;
emit RewardAdded(reward);
emit RewardAdded(reward);
}
}
// Added to support recovering LP Rewards from other systems such as BAL to be distributed to holders
// Added to support recovering LP Rewards from other systems such as BAL to be distributed to holders
function recoverERC20(address tokenAddress, uint256 tokenAmount) external onlyOwner {
function recoverERC20(address tokenAddress, uint256 tokenAmount) external onlyOwner {
require(tokenAddress != address(stakingToken), "Cannot withdraw the staking token");
require(tokenAddress != address(stakingToken), "Cannot withdraw the staking token");
IERC20(tokenAddress).safeTransfer(owner, tokenAmount);
IERC20(tokenAddress).safeTransfer(owner, tokenAmount);
emit Recovered(tokenAddress, tokenAmount);
emit Recovered(tokenAddress, tokenAmount);
}
}
function setRewardsDuration(uint256 _rewardsDuration) external onlyOwner {
function setRewardsDuration(uint256 _rewardsDuration) external onlyOwner {
require(
require(
block.timestamp > periodFinish,
block.timestamp > periodFinish,
"Previous rewards period must be complete before changing the duration for the new period"
"Previous rewards period must be complete before changing the duration for the new period"
);
);
rewardsDuration = _rewardsDuration;
rewardsDuration = _rewardsDuration;
emit RewardsDurationUpdated(rewardsDuration);
emit RewardsDurationUpdated(rewardsDuration);
}
}
Copia
Copiato
Copia
Copiato
function setRewardsDistribution(address _rewardsDistribution) external onlyOwner {
rewardsDistribution = _rewardsDistribution;
emit RewardsDistributionUpdated(rewardsDistribution);
}
/* ========== MODIFIERS ========== */
/* ========== MODIFIERS ========== */
modifier updateReward(address account) {
modifier updateReward(address account) {
rewardPerTokenStored = rewardPerToken();
rewardPerTokenStored = rewardPerToken();
lastUpdateTime = lastTimeRewardApplicable();
lastUpdateTime = lastTimeRewardApplicable();
if (account != address(0)) {
if (account != address(0)) {
rewards[account] = earned(account);
rewards[account] = earned(account);
userRewardPerTokenPaid[account] = rewardPerTokenStored;
userRewardPerTokenPaid[account] = rewardPerTokenStored;
}
}
_;
_;
}
}
Copia
Copiato
Copia
Copiato
Text moved from lines 80-84
modifier onlyRewardsDistribution() {
require(msg.sender == rewardsDistribution, "Caller is not RewardsDistribution contract");
_;
}
/* ========== EVENTS ========== */
/* ========== EVENTS ========== */
event RewardAdded(uint256 reward);
event RewardAdded(uint256 reward);
event Staked(address indexed user, uint256 amount);
event Staked(address indexed user, uint256 amount);
Copia
Copiato
Copia
Copiato
event Referral(uint16 indexed referral, address indexed user, uint256 amount);
event Withdrawn(address indexed user, uint256 amount);
event Withdrawn(address indexed user, uint256 amount);
event RewardPaid(address indexed user, uint256 reward);
event RewardPaid(address indexed user, uint256 reward);
event RewardsDurationUpdated(uint256 newDuration);
event RewardsDurationUpdated(uint256 newDuration);
Copia
Copiato
Copia
Copiato
event RewardsDistributionUpdated(address newRewardsDistribution);
event Recovered(address token, uint256 amount);
event Recovered(address token, uint256 amount);
}
}
Copia
Copiato
Copia
Copiato
Diff salvati
Testo originale
Apri file
pragma solidity ^0.5.16; // Inheritance // https://docs.synthetix.io/contracts/source/interfaces/istakingrewards interface IStakingRewards { // Views function balanceOf(address account) external view returns (uint256); function earned(address account) external view returns (uint256); function getRewardForDuration() external view returns (uint256); function lastTimeRewardApplicable() external view returns (uint256); function rewardPerToken() external view returns (uint256); function rewardsDistribution() external view returns (address); function rewardsToken() external view returns (address); function totalSupply() external view returns (uint256); // Mutative function exit() external; function getReward() external; function stake(uint256 amount) external; function withdraw(uint256 amount) external; } // Inheritance // https://docs.synthetix.io/contracts/source/contracts/owned contract Owned { address public owner; address public nominatedOwner; constructor(address _owner) public { require(_owner != address(0), "Owner address cannot be 0"); owner = _owner; emit OwnerChanged(address(0), _owner); } function nominateNewOwner(address _owner) external onlyOwner { nominatedOwner = _owner; emit OwnerNominated(_owner); } function acceptOwnership() external { require(msg.sender == nominatedOwner, "You must be nominated before you can accept ownership"); emit OwnerChanged(owner, nominatedOwner); owner = nominatedOwner; nominatedOwner = address(0); } modifier onlyOwner { _onlyOwner(); _; } function _onlyOwner() private view { require(msg.sender == owner, "Only the contract owner may perform this action"); } event OwnerNominated(address newOwner); event OwnerChanged(address oldOwner, address newOwner); } // https://docs.synthetix.io/contracts/source/contracts/rewardsdistributionrecipient contract RewardsDistributionRecipient is Owned { address public rewardsDistribution; function notifyRewardAmount(uint256 reward) external; modifier onlyRewardsDistribution() { require(msg.sender == rewardsDistribution, "Caller is not RewardsDistribution contract"); _; } function setRewardsDistribution(address _rewardsDistribution) external onlyOwner { rewardsDistribution = _rewardsDistribution; } } // Inheritance // https://docs.synthetix.io/contracts/source/contracts/pausable contract Pausable is Owned { uint public lastPauseTime; bool public paused; constructor() internal { // This contract is abstract, and thus cannot be instantiated directly require(owner != address(0), "Owner must be set"); // Paused will be false, and lastPauseTime will be 0 upon initialisation } /** * @notice Change the paused state of the contract * @dev Only the contract owner may call this. */ function setPaused(bool _paused) external onlyOwner { // Ensure we're actually changing the state before we do anything if (_paused == paused) { return; } // Set our paused state. paused = _paused; // If applicable, set the last pause time. if (paused) { lastPauseTime = now; } // Let everyone know that our pause state has changed. emit PauseChanged(paused); } event PauseChanged(bool isPaused); modifier notPaused { require(!paused, "This action cannot be performed while the contract is paused"); _; } } // https://docs.synthetix.io/contracts/source/contracts/stakingrewards contract StakingRewards is IStakingRewards, RewardsDistributionRecipient, ReentrancyGuard, Pausable { using SafeMath for uint256; using SafeERC20 for IERC20; /* ========== STATE VARIABLES ========== */ IERC20 public rewardsToken; IERC20 public stakingToken; uint256 public periodFinish = 0; uint256 public rewardRate = 0; uint256 public rewardsDuration = 7 days; uint256 public lastUpdateTime; uint256 public rewardPerTokenStored; mapping(address => uint256) public userRewardPerTokenPaid; mapping(address => uint256) public rewards; uint256 private _totalSupply; mapping(address => uint256) private _balances; /* ========== CONSTRUCTOR ========== */ constructor( address _owner, address _rewardsDistribution, address _rewardsToken, address _stakingToken ) public Owned(_owner) { rewardsToken = IERC20(_rewardsToken); stakingToken = IERC20(_stakingToken); rewardsDistribution = _rewardsDistribution; } /* ========== VIEWS ========== */ function totalSupply() external view returns (uint256) { return _totalSupply; } function balanceOf(address account) external view returns (uint256) { return _balances[account]; } function lastTimeRewardApplicable() public view returns (uint256) { return block.timestamp < periodFinish ? block.timestamp : periodFinish; } function rewardPerToken() public view returns (uint256) { if (_totalSupply == 0) { return rewardPerTokenStored; } return rewardPerTokenStored.add( lastTimeRewardApplicable().sub(lastUpdateTime).mul(rewardRate).mul(1e18).div(_totalSupply) ); } function earned(address account) public view returns (uint256) { return _balances[account].mul(rewardPerToken().sub(userRewardPerTokenPaid[account])).div(1e18).add(rewards[account]); } function getRewardForDuration() external view returns (uint256) { return rewardRate.mul(rewardsDuration); } /* ========== MUTATIVE FUNCTIONS ========== */ function stake(uint256 amount) external nonReentrant notPaused updateReward(msg.sender) { require(amount > 0, "Cannot stake 0"); _totalSupply = _totalSupply.add(amount); _balances[msg.sender] = _balances[msg.sender].add(amount); stakingToken.safeTransferFrom(msg.sender, address(this), amount); emit Staked(msg.sender, amount); } function withdraw(uint256 amount) public nonReentrant updateReward(msg.sender) { require(amount > 0, "Cannot withdraw 0"); _totalSupply = _totalSupply.sub(amount); _balances[msg.sender] = _balances[msg.sender].sub(amount); stakingToken.safeTransfer(msg.sender, amount); emit Withdrawn(msg.sender, amount); } function getReward() public nonReentrant updateReward(msg.sender) { uint256 reward = rewards[msg.sender]; if (reward > 0) { rewards[msg.sender] = 0; rewardsToken.safeTransfer(msg.sender, reward); emit RewardPaid(msg.sender, reward); } } function exit() external { withdraw(_balances[msg.sender]); getReward(); } /* ========== RESTRICTED FUNCTIONS ========== */ function notifyRewardAmount(uint256 reward) external onlyRewardsDistribution updateReward(address(0)) { if (block.timestamp >= periodFinish) { rewardRate = reward.div(rewardsDuration); } else { uint256 remaining = periodFinish.sub(block.timestamp); uint256 leftover = remaining.mul(rewardRate); rewardRate = reward.add(leftover).div(rewardsDuration); } // Ensure the provided reward amount is not more than the balance in the contract. // This keeps the reward rate in the right range, preventing overflows due to // very high values of rewardRate in the earned and rewardsPerToken functions; // Reward + leftover must be less than 2^256 / 10^18 to avoid overflow. uint balance = rewardsToken.balanceOf(address(this)); require(rewardRate <= balance.div(rewardsDuration), "Provided reward too high"); lastUpdateTime = block.timestamp; periodFinish = block.timestamp.add(rewardsDuration); emit RewardAdded(reward); } // Added to support recovering LP Rewards from other systems such as BAL to be distributed to holders function recoverERC20(address tokenAddress, uint256 tokenAmount) external onlyOwner { require(tokenAddress != address(stakingToken), "Cannot withdraw the staking token"); IERC20(tokenAddress).safeTransfer(owner, tokenAmount); emit Recovered(tokenAddress, tokenAmount); } function setRewardsDuration(uint256 _rewardsDuration) external onlyOwner { require( block.timestamp > periodFinish, "Previous rewards period must be complete before changing the duration for the new period" ); rewardsDuration = _rewardsDuration; emit RewardsDurationUpdated(rewardsDuration); } /* ========== MODIFIERS ========== */ modifier updateReward(address account) { rewardPerTokenStored = rewardPerToken(); lastUpdateTime = lastTimeRewardApplicable(); if (account != address(0)) { rewards[account] = earned(account); userRewardPerTokenPaid[account] = rewardPerTokenStored; } _; } /* ========== EVENTS ========== */ event RewardAdded(uint256 reward); event Staked(address indexed user, uint256 amount); event Withdrawn(address indexed user, uint256 amount); event RewardPaid(address indexed user, uint256 reward); event RewardsDurationUpdated(uint256 newDuration); event Recovered(address token, uint256 amount); }
Testo modificato
Apri file
// SPDX-FileCopyrightText: Ā© 2019-2021 Synthetix // SPDX-FileCopyrightText: Ā© 2023 Dai Foundation <www.daifoundation.org> // SPDX-License-Identifier: MIT AND AGPL-3.0-or-later // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see <https://www.gnu.org/licenses/>. pragma solidity 0.8.19; // https://docs.synthetix.io/contracts/source/interfaces/istakingrewards interface IStakingRewards { // Views function balanceOf(address account) external view returns (uint256); function earned(address account) external view returns (uint256); function getRewardForDuration() external view returns (uint256); function lastTimeRewardApplicable() external view returns (uint256); function rewardPerToken() external view returns (uint256); function rewardsDistribution() external view returns (address); function rewardsToken() external view returns (IERC20); function stakingToken() external view returns (IERC20); function totalSupply() external view returns (uint256); // Mutative function exit() external; function getReward() external; function stake(uint256 amount) external; function stake(uint256 amount, uint16 referral) external; function withdraw(uint256 amount) external; function notifyRewardAmount(uint256 reward) external; function setRewardsDistribution(address _rewardsDistribution) external; } // SPDX-FileCopyrightText: Ā© 2019-2021 Synthetix // SPDX-FileCopyrightText: Ā© 2023 Dai Foundation <www.daifoundation.org> // SPDX-License-Identifier: MIT AND AGPL-3.0-or-later // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see <https://www.gnu.org/licenses/>. // Inheritance // SPDX-FileCopyrightText: Ā© 2019-2021 Synthetix // SPDX-FileCopyrightText: Ā© 2023 Dai Foundation <www.daifoundation.org> // SPDX-License-Identifier: MIT AND AGPL-3.0-or-later // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see <https://www.gnu.org/licenses/>. // https://docs.synthetix.io/contracts/source/contracts/owned contract Owned { address public owner; address public nominatedOwner; constructor(address _owner) { require(_owner != address(0), "Owner address cannot be 0"); owner = _owner; emit OwnerChanged(address(0), _owner); } function nominateNewOwner(address _owner) external onlyOwner { nominatedOwner = _owner; emit OwnerNominated(_owner); } function acceptOwnership() external { require(msg.sender == nominatedOwner, "You must be nominated before you can accept ownership"); emit OwnerChanged(owner, nominatedOwner); owner = nominatedOwner; nominatedOwner = address(0); } modifier onlyOwner() { _onlyOwner(); _; } function _onlyOwner() private view { require(msg.sender == owner, "Only the contract owner may perform this action"); } event OwnerNominated(address newOwner); event OwnerChanged(address oldOwner, address newOwner); } // https://docs.synthetix.io/contracts/source/contracts/pausable abstract contract Pausable is Owned { uint public lastPauseTime; bool public paused; constructor(address _owner) Owned(_owner) {} /** * @notice Change the paused state of the contract * @dev Only the contract owner may call this. */ function setPaused(bool _paused) external onlyOwner { // Ensure we're actually changing the state before we do anything if (_paused == paused) { return; } // Set our paused state. paused = _paused; // If applicable, set the last pause time. if (paused) { lastPauseTime = block.timestamp; } // Let everyone know that our pause state has changed. emit PauseChanged(paused); } event PauseChanged(bool isPaused); modifier notPaused() { require(!paused, "This action cannot be performed while the contract is paused"); _; } } // https://docs.synthetix.io/contracts/source/contracts/stakingrewards contract StakingRewards is IStakingRewards, Pausable, ReentrancyGuard { using SafeERC20 for IERC20; /* ========== STATE VARIABLES ========== */ IERC20 public immutable rewardsToken; IERC20 public immutable stakingToken; address public rewardsDistribution; uint256 public periodFinish = 0; uint256 public rewardRate = 0; uint256 public rewardsDuration = 7 days; uint256 public lastUpdateTime; uint256 public rewardPerTokenStored; mapping(address => uint256) public userRewardPerTokenPaid; mapping(address => uint256) public rewards; uint256 private _totalSupply; mapping(address => uint256) private _balances; /* ========== CONSTRUCTOR ========== */ constructor( address _owner, address _rewardsDistribution, address _rewardsToken, address _stakingToken ) Pausable(_owner) { rewardsToken = IERC20(_rewardsToken); stakingToken = IERC20(_stakingToken); rewardsDistribution = _rewardsDistribution; } /* ========== VIEWS ========== */ function totalSupply() external view returns (uint256) { return _totalSupply; } function balanceOf(address account) external view returns (uint256) { return _balances[account]; } function lastTimeRewardApplicable() public view returns (uint256) { return block.timestamp < periodFinish ? block.timestamp : periodFinish; } function rewardPerToken() public view returns (uint256) { if (_totalSupply == 0) { return rewardPerTokenStored; } return rewardPerTokenStored + (((lastTimeRewardApplicable() - lastUpdateTime) * rewardRate * 1e18) / _totalSupply); } function earned(address account) public view returns (uint256) { return (_balances[account] * (rewardPerToken() - userRewardPerTokenPaid[account])) / 1e18 + rewards[account]; } function getRewardForDuration() external view returns (uint256) { return rewardRate * rewardsDuration; } /* ========== MUTATIVE FUNCTIONS ========== */ function stake(uint256 amount) public nonReentrant notPaused updateReward(msg.sender) { require(amount > 0, "Cannot stake 0"); _totalSupply = _totalSupply + amount; _balances[msg.sender] = _balances[msg.sender] + amount; stakingToken.safeTransferFrom(msg.sender, address(this), amount); emit Staked(msg.sender, amount); } function stake(uint256 amount, uint16 referral) external { stake(amount); emit Referral(referral, msg.sender, amount); } function withdraw(uint256 amount) public nonReentrant updateReward(msg.sender) { require(amount > 0, "Cannot withdraw 0"); _totalSupply = _totalSupply - amount; _balances[msg.sender] = _balances[msg.sender] - amount; stakingToken.safeTransfer(msg.sender, amount); emit Withdrawn(msg.sender, amount); } function getReward() public nonReentrant updateReward(msg.sender) { uint256 reward = rewards[msg.sender]; if (reward > 0) { rewards[msg.sender] = 0; rewardsToken.safeTransfer(msg.sender, reward); emit RewardPaid(msg.sender, reward); } } function exit() external { withdraw(_balances[msg.sender]); getReward(); } /* ========== RESTRICTED FUNCTIONS ========== */ function notifyRewardAmount(uint256 reward) external override onlyRewardsDistribution updateReward(address(0)) { if (block.timestamp >= periodFinish) { rewardRate = reward / rewardsDuration; } else { uint256 remaining = periodFinish - block.timestamp; uint256 leftover = remaining * rewardRate; rewardRate = (reward + leftover) / rewardsDuration; } // Ensure the provided reward amount is not more than the balance in the contract. // This keeps the reward rate in the right range, preventing overflows due to // very high values of rewardRate in the earned and rewardsPerToken functions; // Reward + leftover must be less than 2^256 / 10^18 to avoid overflow. uint balance = rewardsToken.balanceOf(address(this)); require(rewardRate <= balance / rewardsDuration, "Provided reward too high"); lastUpdateTime = block.timestamp; periodFinish = block.timestamp + rewardsDuration; emit RewardAdded(reward); } // Added to support recovering LP Rewards from other systems such as BAL to be distributed to holders function recoverERC20(address tokenAddress, uint256 tokenAmount) external onlyOwner { require(tokenAddress != address(stakingToken), "Cannot withdraw the staking token"); IERC20(tokenAddress).safeTransfer(owner, tokenAmount); emit Recovered(tokenAddress, tokenAmount); } function setRewardsDuration(uint256 _rewardsDuration) external onlyOwner { require( block.timestamp > periodFinish, "Previous rewards period must be complete before changing the duration for the new period" ); rewardsDuration = _rewardsDuration; emit RewardsDurationUpdated(rewardsDuration); } function setRewardsDistribution(address _rewardsDistribution) external onlyOwner { rewardsDistribution = _rewardsDistribution; emit RewardsDistributionUpdated(rewardsDistribution); } /* ========== MODIFIERS ========== */ modifier updateReward(address account) { rewardPerTokenStored = rewardPerToken(); lastUpdateTime = lastTimeRewardApplicable(); if (account != address(0)) { rewards[account] = earned(account); userRewardPerTokenPaid[account] = rewardPerTokenStored; } _; } modifier onlyRewardsDistribution() { require(msg.sender == rewardsDistribution, "Caller is not RewardsDistribution contract"); _; } /* ========== EVENTS ========== */ event RewardAdded(uint256 reward); event Staked(address indexed user, uint256 amount); event Referral(uint16 indexed referral, address indexed user, uint256 amount); event Withdrawn(address indexed user, uint256 amount); event RewardPaid(address indexed user, uint256 reward); event RewardsDurationUpdated(uint256 newDuration); event RewardsDistributionUpdated(address newRewardsDistribution); event Recovered(address token, uint256 amount); }
Trovare la differenza