Skip to content

Commit

Permalink
setRewardConfiguration
Browse files Browse the repository at this point in the history
  • Loading branch information
anajuliabit committed Jun 30, 2024
1 parent f34eabb commit 5750a77
Show file tree
Hide file tree
Showing 5 changed files with 135 additions and 4 deletions.
29 changes: 26 additions & 3 deletions src/RewardsDistributor.sol
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ pragma solidity 0.8.26;

import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import {SafeTransferLib} from "@solmate/utils/SafeTransferLib.sol";
import {Ownable2StepUpgradeable} from "@openzeppelin-upgradeable/contracts/access/Ownable2StepUpgradeable.sol";
import {IRewardsDistributor} from "./interfaces/IRewardsDistributor.sol";

Expand Down Expand Up @@ -49,6 +48,15 @@ contract RewardsDistributor is Ownable2StepUpgradeable, IRewardsDistributor {

event RewardCollected(address indexed receiver, uint256 reward);

event RewardTokenSet(address indexed rewardToken);

/*//////////////////////////////////////////////////////////////
ERRORS
//////////////////////////////////////////////////////////////*/

/// @notice Thrown when address is zero
error ZeroAddress();

/// @notice Initialize the contract
/// @param newOwner The owner of the contract, i.e. the DAO contract address
constructor(address newOwner, address _rewardToken) {
Expand Down Expand Up @@ -93,7 +101,7 @@ contract RewardsDistributor is Ownable2StepUpgradeable, IRewardsDistributor {
address receiver,
uint256 emissionRate
) external override onlyOwner {
require(receiver != address(0), "Invalid receiver");
require(receiver != address(0), ZeroAddress());

rewardConfigurations[receiver] = RewardConfiguration(
emissionRate,
Expand All @@ -103,10 +111,25 @@ contract RewardsDistributor is Ownable2StepUpgradeable, IRewardsDistributor {
emit RewardConfigurationSet(receiver, emissionRate);
}

/// @notice Withdraw funds from the contract
/// @param to The address to withdraw to
/// @param amount The amount to withdraw
function withdrawFunds(
address to,
uint256 amount
) external override onlyOwner {
) public override onlyOwner {
rewardToken.safeTransfer(to, amount);
}

/// @notice Set the reward token
/// @param _rewardToken The reward token
function setRewardToken(address _rewardToken) external onlyOwner {
// withdraw remaining old reward token
withdrawFunds(msg.sender, rewardToken.balanceOf(address(this)));

// set the new reward token
rewardToken = IERC20(_rewardToken);

emit RewardTokenSet(_rewardToken);
}
}
2 changes: 1 addition & 1 deletion src/Staking.sol
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ contract Staking is ERC20VotesUpgradeable, Ownable2StepUpgradeable {
/// amount is less than the minimum stake set by the DAO
error FirstStakeLessThanMinStake();

/// @notice Trownn when amount is zero
/// @notice Trown when amount is zero
error ZeroAmount();

/// @notice Thrown when someone try to unstake a stake that doesn't belong
Expand Down
2 changes: 2 additions & 0 deletions src/interfaces/IRewardsDistributor.sol
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,6 @@ interface IRewardsDistributor {
address receiver,
uint256 emissionRate
) external;

function setRewardToken(address _rewardToken) external;
}
104 changes: 104 additions & 0 deletions test/RewardsDistributor.t.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
// SPDX-License-Identifier: MIT
pragma solidity 0.8.26;

import "@forge-std/Test.sol";
import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol";

import {RewardsDistributor} from "src/RewardsDistributor.sol";
import {MockGovToken} from "test/mocks/MockGovToken.sol";

contract RewardsDistributorTest is Test {
RewardsDistributor public rewardsDistributor;
MockGovToken public govToken;

function setUp() public {
// Set the block timestamp to an arbitrary value to avoid introducing assumptions into tests
// based on a starting timestamp of 0, which is the default.
_jumpAhead(1234);

govToken = new MockGovToken();
govToken.mint(address(this), 1_000_000_000e18);
vm.label(address(govToken), "govToken");

// deploy rewards distributor
rewardsDistributor = new RewardsDistributor(
address(this),
address(govToken)
);
}

function _jumpAhead(uint256 _seconds) public {
vm.warp(vm.getBlockTimestamp() + _seconds);
}

function _setRewardConfiguration(
address receiver,
uint256 emissionRate
) internal {
emissionRate = bound(emissionRate, 0, 1e18);
rewardsDistributor.setRewardConfiguration(receiver, emissionRate);
}
}

contract OwnableFunctions is RewardsDistributorTest {
function test_SetRewardConfigurationEmitEvent(
address _receiver,
uint256 _emissionRate
) public {
vm.expectEmit();
emit RewardsDistributor.RewardConfigurationSet(
_receiver,
_emissionRate
);
rewardsDistributor.setRewardConfiguration(_receiver, _emissionRate);
}

function test_SetRewardConfigurationSetEmissionRate(
address _receiver,
uint256 _emissionRate
) public {
rewardsDistributor.setRewardConfiguration(_receiver, _emissionRate);

(uint256 emissionRate, ) = rewardsDistributor.rewardConfigurations(
_receiver
);

assertEq(emissionRate, _emissionRate);
}

function test_SetRewardConfigurationSetLastUpdate(
address _receiver,
uint256 _emissionRate
) public {
rewardsDistributor.setRewardConfiguration(_receiver, _emissionRate);

(, uint256 lastUpdate) = rewardsDistributor.rewardConfigurations(
_receiver
);
assertEq(lastUpdate, vm.getBlockTimestamp());
}

function test_RevertIf_SetRewardConfigurationZeroAddress(
uint256 _emissionRate
) public {
vm.expectRevert(RewardsDistributor.ZeroAddress.selector);
rewardsDistributor.setRewardConfiguration(address(0), _emissionRate);
}

function test_RevertIf_SetRewardConfigurationNotOwner(
address _anyone,
address _receiver,
uint256 _emissionRate
) public {
vm.assume(_anyone != address(this));

vm.expectRevert(
abi.encodeWithSelector(
Ownable.OwnableUnauthorizedAccount.selector,
_anyone
)
);
vm.prank(_anyone);
rewardsDistributor.setRewardConfiguration(_receiver, _emissionRate);
}
}
2 changes: 2 additions & 0 deletions test/Staking.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -1394,6 +1394,8 @@ contract OwnableFunctions is StakingTest {
uint256[] memory keyperStakeIds = staking.getKeyperStakeIds(_keyper);
assertEq(keyperStakeIds.length, 0, "Wrong stake ids");
}

// TEST CASES FOR NON OWNERS
}

contract ViewFunctions is StakingTest {
Expand Down

0 comments on commit 5750a77

Please sign in to comment.