Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Test/integration #24

Merged
merged 20 commits into from
Jul 8, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ jobs:
)" >> $GITHUB_ENV

- name: Run tests
run: forge test
run: forge test --no-match-contract Integration

coverage:
runs-on: ubuntu-latest
Expand All @@ -59,7 +59,7 @@ jobs:
)" >> $GITHUB_ENV

- name: Run coverage
run: forge coverage --report summary --report lcov --ir-minimum
run: forge coverage --report summary --report lcov --ir-minimum --no-match-contract Integration

# To ignore coverage for certain directories modify the paths in this step as needed. The
# below default ignores coverage results for the test and script directories. Alternatively,
Expand Down
3 changes: 3 additions & 0 deletions foundry.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,6 @@
# Speed up compilation and tests during development.
optimizer = false

[rpc_endpoints]
mainnet = "${MAINNET_RPC_URL}"

7 changes: 7 additions & 0 deletions script/Constants.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
pragma solidity 0.8.26;

address constant STAKING_TOKEN = 0xe485E2f1bab389C08721B291f6b59780feC83Fd7; // shutter token
address constant CONTRACT_OWNER = 0x36bD3044ab68f600f6d3e081056F34f2a58432c4; // shuter multisig
uint256 constant LOCK_PERIOD = 182 days;
uint256 constant MIN_STAKE = 50_000e18;
uint256 constant REWARD_RATE = 0.1333333333e18;
42 changes: 42 additions & 0 deletions script/Deploy.s.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
// SPDX-License-Identifier: MIT
pragma solidity 0.8.26;

import "@forge-std/Script.sol";
import {TransparentUpgradeableProxy} from "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol";
import {RewardsDistributor} from "src/RewardsDistributor.sol";
import {Staking} from "src/Staking.sol";
import "./Constants.sol";

contract Deploy is Script {
function run()
public
returns (Staking stakingProxy, RewardsDistributor rewardsDistributor)
{
vm.startBroadcast();

rewardsDistributor = new RewardsDistributor(
CONTRACT_OWNER,
STAKING_TOKEN
);

stakingProxy = Staking(
address(
new TransparentUpgradeableProxy(
address(new Staking()),
address(CONTRACT_OWNER),
""
)
)
);

stakingProxy.initialize(
CONTRACT_OWNER,
STAKING_TOKEN,
address(rewardsDistributor),
LOCK_PERIOD,
MIN_STAKE
);

vm.stopBroadcast();
}
}
19 changes: 14 additions & 5 deletions src/RewardsDistributor.sol
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,15 @@ contract RewardsDistributor is Ownable2Step, IRewardsDistributor {
// difference in time since last update
uint256 timeDelta = block.timestamp - rewardConfiguration.lastUpdate;

if (rewardConfiguration.emissionRate != 0 && timeDelta != 0) {
// the contract must have funds to distribute
// we don't want to revert in case its zero to not block the staking contract
uint256 funds = rewardToken.balanceOf(address(this));

if (
rewardConfiguration.emissionRate != 0 &&
timeDelta != 0 &&
funds != 0
) {
rewards = rewardConfiguration.emissionRate * timeDelta;

// update the last update timestamp
Expand All @@ -98,10 +106,11 @@ contract RewardsDistributor is Ownable2Step, IRewardsDistributor {
) external override onlyOwner {
require(receiver != address(0), ZeroAddress());

rewardConfigurations[receiver] = RewardConfiguration(
emissionRate,
block.timestamp
);
// only update last update if it's the first time
if (rewardConfigurations[receiver].lastUpdate == 0) {
rewardConfigurations[receiver].lastUpdate = block.timestamp;
}
rewardConfigurations[receiver].emissionRate = emissionRate;

emit RewardConfigurationSet(receiver, emissionRate);
}
Expand Down
23 changes: 8 additions & 15 deletions src/Staking.sol
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import {FixedPointMathLib} from "@solmate/utils/FixedPointMathLib.sol";
import {IRewardsDistributor} from "./interfaces/IRewardsDistributor.sol";

// TODO is this vulnerable to first deposit attack?
// TODO check calculations
contract Staking is ERC20VotesUpgradeable, Ownable2StepUpgradeable {
/*//////////////////////////////////////////////////////////////
LIBRARIES
Expand Down Expand Up @@ -177,7 +176,7 @@ contract Staking is ERC20VotesUpgradeable, Ownable2StepUpgradeable {
uint256 _lockPeriod,
uint256 _minStake
) public initializer {
// TODO set name and symbol
__ERC20_init("Staked SHU", "sSHU");

// Transfer ownership to the DAO contract
_transferOwnership(newOwner);
Expand All @@ -198,7 +197,6 @@ contract Staking is ERC20VotesUpgradeable, Ownable2StepUpgradeable {
/// - Only keypers can stake
/// @param amount The amount of SHU to stake
/// @return stakeId The index of the stake
/// TODO slippage protection
function stake(
uint256 amount
) external onlyKeyper updateRewards returns (uint256 stakeId) {
Expand Down Expand Up @@ -263,7 +261,6 @@ contract Staking is ERC20VotesUpgradeable, Ownable2StepUpgradeable {
/// @param stakeId The stake index
/// @param amount The amount
/// TODO check for reentrancy
/// TODO slippage protection
function unstake(
address keyper,
uint256 stakeId,
Expand Down Expand Up @@ -374,17 +371,15 @@ contract Staking is ERC20VotesUpgradeable, Ownable2StepUpgradeable {
/// @param _rewardsDistributor The address of the rewards distributor contract
function setRewardsDistributor(
address _rewardsDistributor
) external onlyOwner updateRewards {
) external onlyOwner {
rewardsDistributor = IRewardsDistributor(_rewardsDistributor);

emit NewRewardsDistributor(_rewardsDistributor);
}

/// @notice Set the lock period
/// @param _lockPeriod The lock period in seconds
function setLockPeriod(
uint256 _lockPeriod
) external onlyOwner updateRewards {
function setLockPeriod(uint256 _lockPeriod) external onlyOwner {
lockPeriod = _lockPeriod;

emit NewLockPeriod(_lockPeriod);
Expand All @@ -401,10 +396,7 @@ contract Staking is ERC20VotesUpgradeable, Ownable2StepUpgradeable {
/// @notice Set a keyper
/// @param keyper The keyper address
/// @param isKeyper Whether the keyper is a keyper or not
function setKeyper(
address keyper,
bool isKeyper
) external onlyOwner updateRewards {
function setKeyper(address keyper, bool isKeyper) external onlyOwner {
_setKeyper(keyper, isKeyper);
}

Expand All @@ -414,7 +406,7 @@ contract Staking is ERC20VotesUpgradeable, Ownable2StepUpgradeable {
function setKeypers(
address[] memory _keypers,
bool isKeyper
) external onlyOwner updateRewards {
) external onlyOwner {
for (uint256 i = 0; i < _keypers.length; i++) {
_setKeyper(_keypers[i], isKeyper);
}
Expand Down Expand Up @@ -452,6 +444,7 @@ contract Staking is ERC20VotesUpgradeable, Ownable2StepUpgradeable {
/// @return The maximum amount of assets that a keyper can withdraw
function maxWithdraw(address keyper) public view virtual returns (uint256) {
uint256 shares = balanceOf(keyper);

require(shares > 0, KeyperHasNoShares());

uint256 assets = convertToAssets(shares);
Expand All @@ -461,7 +454,7 @@ contract Staking is ERC20VotesUpgradeable, Ownable2StepUpgradeable {
: minStake;

if (assets < compare) {
// TODO check this
// need this branch as convertToAssets rounds down
return 0;
} else {
return assets - compare;
Expand All @@ -481,7 +474,7 @@ contract Staking is ERC20VotesUpgradeable, Ownable2StepUpgradeable {
uint256 compare = locked >= minStake ? locked : minStake;

if (assets < compare) {
// TODO check this
// need this branch as convertToAssets rounds down
return 0;
} else {
return assets - compare;
Expand Down
4 changes: 3 additions & 1 deletion test/RewardsDistributor.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -266,7 +266,9 @@ contract CollectRewards is RewardsDistributorTest {
uint256 _jump,
uint256 _emissionRate
) public {
vm.assume(address(_receiver) != address(0));
vm.assume(
_receiver != address(0) && _receiver != address(rewardsDistributor)
);

_emissionRate = bound(_emissionRate, 1, 1e18);
rewardsDistributor.setRewardConfiguration(_receiver, _emissionRate);
Expand Down
Loading
Loading