diff --git a/contracts/staking/RewardRouter.sol b/contracts/staking/RewardRouter.sol index 3323337..0feb00d 100644 --- a/contracts/staking/RewardRouter.sol +++ b/contracts/staking/RewardRouter.sol @@ -10,188 +10,197 @@ import {IVester} from "./interfaces/IVester.sol"; import {Governable} from "../core/Governable.sol"; contract RewardRouter is ReentrancyGuard, Governable { - using SafeERC20 for IERC20; + using SafeERC20 for IERC20; - address public gmx; - address public esGmx; + address public gmx; + address public esGmx; - address public stakedGmxTracker; - address public gmxVester; + address public stakedGmxTracker; + address public gmxVester; - mapping (address sender=> address receiver) public pendingReceivers; + mapping(address sender => address receiver) public pendingReceivers; - event StakeGmx(address account, address token, uint256 amount); - event UnstakeGmx(address account, address token, uint256 amount); + event StakeGmx(address account, address token, uint256 amount); + event UnstakeGmx(address account, address token, uint256 amount); - constructor( - address _gmx, - address _esGmx, - address _stakedGmxTracker, - address _gmxVester - ) { - gmx = _gmx; - esGmx = _esGmx; - stakedGmxTracker = _stakedGmxTracker; - gmxVester = _gmxVester; + constructor(address _gmx, address _esGmx, address _stakedGmxTracker, address _gmxVester) { + gmx = _gmx; + esGmx = _esGmx; + stakedGmxTracker = _stakedGmxTracker; + gmxVester = _gmxVester; + } + + // to help users who accidentally send their tokens to this contract + function withdrawToken(address _token, address _account, uint256 _amount) external onlyGov { + IERC20(_token).safeTransfer(_account, _amount); + } + + function batchStakeGmxForAccount( + address[] memory _accounts, + uint256[] memory _amounts + ) external nonReentrant onlyGov { + address _gmx = gmx; + for (uint256 i = 0; i < _accounts.length; i++) { + _stakeGmx(msg.sender, _accounts[i], _gmx, _amounts[i]); + } + } + + function stakeGmxForAccount(address _account, uint256 _amount) external nonReentrant onlyGov { + _stakeGmx(msg.sender, _account, gmx, _amount); + } + + function stakeGmx(uint256 _amount) external nonReentrant { + _stakeGmx(msg.sender, msg.sender, gmx, _amount); + } + + function stakeEsGmx(uint256 _amount) external nonReentrant { + _stakeGmx(msg.sender, msg.sender, esGmx, _amount); + } + + function unstakeGmx(uint256 _amount) external nonReentrant { + _unstakeGmx(msg.sender, gmx, _amount); + } + + function unstakeEsGmx(uint256 _amount) external nonReentrant { + _unstakeGmx(msg.sender, esGmx, _amount); + } + + function claim() external nonReentrant { + address account = msg.sender; + + IRewardTracker(stakedGmxTracker).claimForAccount(account, account); + } + + function claimEsGmx() external nonReentrant { + address account = msg.sender; + IRewardTracker(stakedGmxTracker).claimForAccount(account, account); + } + + function compound() external nonReentrant { + _compound(msg.sender); + } + + function compoundForAccount(address _account) external nonReentrant onlyGov { + _compound(_account); + } + + function handleRewards( + bool _shouldClaimGmx, + bool _shouldStakeGmx, + bool _shouldClaimEsGmx, + bool _shouldStakeEsGmx + ) external nonReentrant { + address account = msg.sender; + + uint256 gmxAmount = 0; + if (_shouldClaimGmx) { + gmxAmount = IVester(gmxVester).claimForAccount(account, account); } - // to help users who accidentally send their tokens to this contract - function withdrawToken(address _token, address _account, uint256 _amount) external onlyGov { - IERC20(_token).safeTransfer(_account, _amount); + if (_shouldStakeGmx && gmxAmount > 0) { + _stakeGmx(account, account, gmx, gmxAmount); } - function batchStakeGmxForAccount(address[] memory _accounts, uint256[] memory _amounts) external nonReentrant onlyGov { - address _gmx = gmx; - for (uint256 i = 0; i < _accounts.length; i++) { - _stakeGmx(msg.sender, _accounts[i], _gmx, _amounts[i]); - } + uint256 esGmxAmount = 0; + if (_shouldClaimEsGmx) { + esGmxAmount = IRewardTracker(stakedGmxTracker).claimForAccount(account, account); } - function stakeGmxForAccount(address _account, uint256 _amount) external nonReentrant onlyGov { - _stakeGmx(msg.sender, _account, gmx, _amount); + if (_shouldStakeEsGmx && esGmxAmount > 0) { + _stakeGmx(account, account, esGmx, esGmxAmount); + } + } + + function batchCompoundForAccounts(address[] memory _accounts) external nonReentrant onlyGov { + for (uint256 i = 0; i < _accounts.length; i++) { + _compound(_accounts[i]); + } + } + + function signalTransfer(address _receiver) external nonReentrant { + require(IERC20(gmxVester).balanceOf(msg.sender) == 0, "sender has vested tokens"); + + _validateReceiver(_receiver); + + pendingReceivers[msg.sender] = _receiver; + } + + function acceptTransfer(address _sender) external nonReentrant { + require(IERC20(gmxVester).balanceOf(_sender) == 0, "sender has vested tokens"); + + address receiver = msg.sender; + require(pendingReceivers[_sender] == receiver, "transfer not signalled"); + delete pendingReceivers[_sender]; + + _validateReceiver(receiver); + _compound(_sender); + + uint256 stakedGmx = IRewardTracker(stakedGmxTracker).depositBalances(_sender, gmx); + if (stakedGmx > 0) { + _unstakeGmx(_sender, gmx, stakedGmx); + _stakeGmx(_sender, receiver, gmx, stakedGmx); } - function stakeGmx(uint256 _amount) external nonReentrant { - _stakeGmx(msg.sender, msg.sender, gmx, _amount); + uint256 stakedEsGmx = IRewardTracker(stakedGmxTracker).depositBalances(_sender, esGmx); + if (stakedEsGmx > 0) { + _unstakeGmx(_sender, esGmx, stakedEsGmx); + _stakeGmx(_sender, receiver, esGmx, stakedEsGmx); } - function stakeEsGmx(uint256 _amount) external nonReentrant { - _stakeGmx(msg.sender, msg.sender, esGmx, _amount); + uint256 esGmxBalance = IERC20(esGmx).balanceOf(_sender); + if (esGmxBalance > 0) { + IERC20(esGmx).transferFrom(_sender, receiver, esGmxBalance); } - function unstakeGmx(uint256 _amount) external nonReentrant { - _unstakeGmx(msg.sender, gmx, _amount); + IVester(gmxVester).transferStakeValues(_sender, receiver); + } + + function _validateReceiver(address _receiver) private view { + require( + IRewardTracker(stakedGmxTracker).averageStakedAmounts(_receiver) == 0, + "stakedGmxTracker.averageStakedAmounts > 0" + ); + require( + IRewardTracker(stakedGmxTracker).cumulativeRewards(_receiver) == 0, + "stakedGmxTracker.cumulativeRewards > 0" + ); + + require( + IVester(gmxVester).transferredAverageStakedAmounts(_receiver) == 0, + "gmxVester.transferredAverageStakedAmounts > 0" + ); + require( + IVester(gmxVester).transferredCumulativeRewards(_receiver) == 0, + "gmxVester.transferredCumulativeRewards > 0" + ); + + require(IERC20(gmxVester).balanceOf(_receiver) == 0, "gmxVester.balance > 0"); + } + + function _compound(address _account) private { + _compoundGmx(_account); + } + + function _compoundGmx(address _account) private { + uint256 esGmxAmount = IRewardTracker(stakedGmxTracker).claimForAccount(_account, _account); + if (esGmxAmount > 0) { + _stakeGmx(_account, _account, esGmx, esGmxAmount); } + } - function unstakeEsGmx(uint256 _amount) external nonReentrant { - _unstakeGmx(msg.sender, esGmx, _amount); - } + function _stakeGmx(address _fundingAccount, address _account, address _token, uint256 _amount) private { + require(_amount > 0, "invalid _amount"); - function claim() external nonReentrant { - address account = msg.sender; + IRewardTracker(stakedGmxTracker).stakeForAccount(_fundingAccount, _account, _token, _amount); - IRewardTracker(stakedGmxTracker).claimForAccount(account, account); - } + emit StakeGmx(_account, _token, _amount); + } - function claimEsGmx() external nonReentrant { - address account = msg.sender; - IRewardTracker(stakedGmxTracker).claimForAccount(account, account); - } + function _unstakeGmx(address _account, address _token, uint256 _amount) private { + require(_amount > 0, "invalid _amount"); + // uint256 balance = IRewardTracker(stakedGmxTracker).stakedAmounts(_account); + IRewardTracker(stakedGmxTracker).unstakeForAccount(_account, _token, _amount, _account); - function compound() external nonReentrant { - _compound(msg.sender); - } - - function compoundForAccount(address _account) external nonReentrant onlyGov { - _compound(_account); - } - - function handleRewards( - bool _shouldClaimGmx, - bool _shouldStakeGmx, - bool _shouldClaimEsGmx, - bool _shouldStakeEsGmx - ) external nonReentrant { - address account = msg.sender; - - uint256 gmxAmount = 0; - if (_shouldClaimGmx) { - gmxAmount = IVester(gmxVester).claimForAccount(account, account); - } - - if (_shouldStakeGmx && gmxAmount > 0) { - _stakeGmx(account, account, gmx, gmxAmount); - } - - uint256 esGmxAmount = 0; - if (_shouldClaimEsGmx) { - esGmxAmount = IRewardTracker(stakedGmxTracker).claimForAccount(account, account); - } - - if (_shouldStakeEsGmx && esGmxAmount > 0) { - _stakeGmx(account, account, esGmx, esGmxAmount); - } - } - - function batchCompoundForAccounts(address[] memory _accounts) external nonReentrant onlyGov { - for (uint256 i = 0; i < _accounts.length; i++) { - _compound(_accounts[i]); - } - } - - function signalTransfer(address _receiver) external nonReentrant { - require(IERC20(gmxVester).balanceOf(msg.sender) == 0, "sender has vested tokens"); - - _validateReceiver(_receiver); - - pendingReceivers[msg.sender] = _receiver; - } - - function acceptTransfer(address _sender) external nonReentrant { - require(IERC20(gmxVester).balanceOf(_sender) == 0, "sender has vested tokens"); - - address receiver = msg.sender; - require(pendingReceivers[_sender] == receiver, "transfer not signalled"); - delete pendingReceivers[_sender]; - - _validateReceiver(receiver); - _compound(_sender); - - uint256 stakedGmx = IRewardTracker(stakedGmxTracker).depositBalances(_sender, gmx); - if (stakedGmx > 0) { - _unstakeGmx(_sender, gmx, stakedGmx); - _stakeGmx(_sender, receiver, gmx, stakedGmx); - } - - uint256 stakedEsGmx = IRewardTracker(stakedGmxTracker).depositBalances(_sender, esGmx); - if (stakedEsGmx > 0) { - _unstakeGmx(_sender, esGmx, stakedEsGmx); - _stakeGmx(_sender, receiver, esGmx, stakedEsGmx); - } - - uint256 esGmxBalance = IERC20(esGmx).balanceOf(_sender); - if (esGmxBalance > 0) { - IERC20(esGmx).transferFrom(_sender, receiver, esGmxBalance); - } - - IVester(gmxVester).transferStakeValues(_sender, receiver); - } - - function _validateReceiver(address _receiver) private view { - require(IRewardTracker(stakedGmxTracker).averageStakedAmounts(_receiver) == 0, "stakedGmxTracker.averageStakedAmounts > 0"); - require(IRewardTracker(stakedGmxTracker).cumulativeRewards(_receiver) == 0, "stakedGmxTracker.cumulativeRewards > 0"); - - require(IVester(gmxVester).transferredAverageStakedAmounts(_receiver) == 0, "gmxVester.transferredAverageStakedAmounts > 0"); - require(IVester(gmxVester).transferredCumulativeRewards(_receiver) == 0, "gmxVester.transferredCumulativeRewards > 0"); - - require(IERC20(gmxVester).balanceOf(_receiver) == 0, "gmxVester.balance > 0"); - } - - function _compound(address _account) private { - _compoundGmx(_account); - } - - function _compoundGmx(address _account) private { - uint256 esGmxAmount = IRewardTracker(stakedGmxTracker).claimForAccount(_account, _account); - if (esGmxAmount > 0) { - _stakeGmx(_account, _account, esGmx, esGmxAmount); - } - } - - - function _stakeGmx(address _fundingAccount, address _account, address _token, uint256 _amount) private { - require(_amount > 0, "invalid _amount"); - - IRewardTracker(stakedGmxTracker).stakeForAccount(_fundingAccount, _account, _token, _amount); - - emit StakeGmx(_account, _token, _amount); - } - - function _unstakeGmx(address _account, address _token, uint256 _amount) private { - require(_amount > 0, "invalid _amount"); - // uint256 balance = IRewardTracker(stakedGmxTracker).stakedAmounts(_account); - IRewardTracker(stakedGmxTracker).unstakeForAccount(_account, _token, _amount, _account); - - emit UnstakeGmx(_account, _token, _amount); - } + emit UnstakeGmx(_account, _token, _amount); + } }