Skip to content

Commit

Permalink
Merge pull request #24 from blockful-io/test/integration
Browse files Browse the repository at this point in the history
Test/integration
  • Loading branch information
anajuliabit authored Jul 8, 2024
2 parents 4ab7395 + b21101a commit d44a3b6
Show file tree
Hide file tree
Showing 9 changed files with 411 additions and 46 deletions.
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

0 comments on commit d44a3b6

Please sign in to comment.