Skip to content
Closed
42 changes: 0 additions & 42 deletions src/script/Deploy.s.sol

This file was deleted.

66 changes: 66 additions & 0 deletions src/script/DeployBase.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
// SPDX-License-Identifier: AGPL-3.0-only
// slither-disable-start reentrancy-benign

pragma solidity ^0.8.23;

import {Script} from "forge-std/Script.sol";
import {IEarningPowerCalculator} from "../interfaces/IEarningPowerCalculator.sol";
import {Staker} from "../Staker.sol";

abstract contract DeployBase is Script {
/// @notice An array of initial reward notifiers for Staker.
address[] internal rewardNotifiers;
/// @notice The address deploying the staking system.
address deployer;

/// @notice The configuration needed for this base script.
/// @param admin The final admin of the staker contract.
struct BaseConfiguration {
address admin;
}

/// @notice An interface method that returns a set configuration for the base script.
/// @return The base configuration for the staking system.
function _baseConfiguration() internal virtual returns (BaseConfiguration memory);

/// @notice An interface method that deploys the Staker contract for the staking system.
/// @param _earningPowerCalculator The address of the deployed earning power calculator.
/// @return The Staker contract for the staking system.
function _deployStaker(IEarningPowerCalculator _earningPowerCalculator)
internal
virtual
returns (Staker);

/// @notice An interface method that deploys the earning power contract for the staking system.
/// @return The earning power calculator contract.
function _deployEarningPowerCalculator() internal virtual returns (IEarningPowerCalculator);

/// @notice An interface method that deploys the reward notifiers.
/// @param _staker The Staker for the staking system.
function _deployRewardNotifiers(Staker _staker) internal virtual;

/// @notice The method that is executed when the script runs which deploys the entire staking
/// system.
/// @return The Staker contract, earning power calculator, and array of reward notifiers.
function run() public returns (IEarningPowerCalculator, Staker, address[] memory) {
uint256 deployerPrivateKey = vm.envOr(
"DEPLOYER_PRIVATE_KEY",
uint256(0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80)
);

deployer = vm.rememberKey(deployerPrivateKey);
vm.startBroadcast(deployer);
IEarningPowerCalculator _earningPowerCalculator = _deployEarningPowerCalculator();
Staker _staker = _deployStaker(_earningPowerCalculator);

_deployRewardNotifiers(_staker);
for (uint256 i = 0; i < rewardNotifiers.length; i++) {
_staker.setRewardNotifier(rewardNotifiers[i], true);
}

BaseConfiguration memory _baseConfig = _baseConfiguration();
_staker.setAdmin(_baseConfig.admin);
vm.stopBroadcast();
return (_earningPowerCalculator, _staker, rewardNotifiers);
}
}
12 changes: 0 additions & 12 deletions src/script/DeployInput.sol

This file was deleted.

30 changes: 30 additions & 0 deletions src/script/DeployStaker.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity ^0.8.23;

import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";

import {DeployBase} from "./DeployBase.sol";
import {IEarningPowerCalculator} from "../interfaces/IEarningPowerCalculator.sol";
import {Staker} from "../Staker.sol";

abstract contract DeployStaker is DeployBase {
/// @notice The configuration for the Staker contract.
/// @param rewardToken The reward token for Staker.
/// @param stakeToken The stake token for Staker.
/// @param earningPowerCalculator The earning power calculator for Staker.
/// @param maxBumpTip The max bump tip for Staker.
struct StakerConfiguration {
IERC20 rewardToken;
IERC20 stakeToken;
IEarningPowerCalculator earningPowerCalculator;
uint256 maxBumpTip;
}

/// @notice An interface method that returns a the configuration for the Staker contract.
/// @param _earningPowerCalculator The deployed earning power calculator.
/// @return The staker configration.
function _stakerConfiguration(IEarningPowerCalculator _earningPowerCalculator)
internal
virtual
returns (StakerConfiguration memory);
}
19 changes: 19 additions & 0 deletions src/script/calculators/DeployIdentityEarningPowerCalculator.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity ^0.8.23;

import {DeployBase} from "../DeployBase.sol";
import {IdentityEarningPowerCalculator} from "../../calculators/IdentityEarningPowerCalculator.sol";
import {IEarningPowerCalculator} from "../../interfaces/IEarningPowerCalculator.sol";

abstract contract DeployIdentityEarningPowerCalculator is DeployBase {
/// @notice Deploys an identitiy earning power calculator.
/// @inheritdoc DeployBase
function _deployEarningPowerCalculator()
internal
virtual
override
returns (IEarningPowerCalculator)
{
return new IdentityEarningPowerCalculator();
}
}
48 changes: 48 additions & 0 deletions src/script/notifiers/DeployMinterRewardNotifier.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity ^0.8.23;

import {INotifiableRewardReceiver} from "../../interfaces/INotifiableRewardReceiver.sol";
import {IMintable} from "../../interfaces/IMintable.sol";
import {DeployBase} from "../DeployBase.sol";
import {MintRewardNotifier} from "../../notifiers/MintRewardNotifier.sol";
import {Staker} from "../../Staker.sol";

abstract contract DeployMinterRewardNotifier is DeployBase {
/// @notice The configuration for the minter reward notifier.
/// @param _receiver The contract that will receive reward notifications, typically an instance
/// of Staker.
/// @param _initialRewardAmount The initial amount of reward tokens to be distributed per
/// notification.
/// @param _initialRewardInterval The initial minimum time that must elapse between
/// notifications.
/// @param _initialOwner The address that will have permission to update contract parameters.
/// @param _minter The initial contract authorized to mint reward tokens.
struct MinterRewardNotifierConfiguration {
uint256 initialRewardAmount;
uint256 initialRewardInterval;
address initialOwner;
IMintable minter;
}

/// @notice An interface method that returns the configuration for the minter reward notifier.
function _minterRewardNotifierConfiguration()
internal
virtual
returns (MinterRewardNotifierConfiguration memory);

/// @notice Deploys a minter reward notifier.
/// @inheritdoc DeployBase
/// @dev When this method is overridden make sure to call super so it is added to the reward
/// notifiers array.
function _deployRewardNotifiers(Staker _staker) internal virtual override {
MinterRewardNotifierConfiguration memory _config = _minterRewardNotifierConfiguration();
MintRewardNotifier _notifier = new MintRewardNotifier(
INotifiableRewardReceiver(address(_staker)),
_config.initialRewardAmount,
_config.initialRewardInterval,
_config.initialOwner,
_config.minter
);
rewardNotifiers.push(address(_notifier));
}
}
47 changes: 47 additions & 0 deletions src/script/notifiers/DeployTransferFromRewardNotifier.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity ^0.8.23;

import {INotifiableRewardReceiver, IERC20} from "../../interfaces/INotifiableRewardReceiver.sol";
import {TransferFromRewardNotifier} from "../../notifiers/TransferFromRewardNotifier.sol";
import {DeployBase} from "../DeployBase.sol";
import {Staker} from "../../Staker.sol";

abstract contract DeployTransferFromRewardNotifier is DeployBase {
/// @notice The configuration for the transferFrom reward notifier.
/// @param initialRewardAmount The initial amount of reward tokens to be distributed per
/// notification.
/// @param initialRewardInterval The initial minimum time that must elapse between
/// notifications.
/// @param initialOwner The address that will have permission to update contract parameters.
/// @param initialRewardSource The initial source of reward tokens.
struct TransferFromRewardNotifierConfiguration {
uint256 initialRewardAmount;
uint256 initialRewardInterval;
address initialOwner;
address initialRewardSource;
}

/// @notice An interface method that returns the configuration for the transferFrom reward
/// notifier.
function _transferFromRewardNotifierConfiguration()
internal
virtual
returns (TransferFromRewardNotifierConfiguration memory);

/// @notice Deploys a transferFrom reward notifier.
/// @inheritdoc DeployBase
/// @dev When this method is overridden make sure to call super so it is added to the reward
/// notifiers array.
function _deployRewardNotifiers(Staker _staker) internal virtual override {
TransferFromRewardNotifierConfiguration memory _config =
_transferFromRewardNotifierConfiguration();
TransferFromRewardNotifier _notifier = new TransferFromRewardNotifier(
INotifiableRewardReceiver(address(_staker)),
_config.initialRewardAmount,
_config.initialRewardInterval,
_config.initialOwner,
_config.initialRewardSource
);
rewardNotifiers.push(address(_notifier));
}
}
46 changes: 46 additions & 0 deletions test/DeployBase.t.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity ^0.8.23;

import {Test} from "forge-std/Test.sol";
import {IEarningPowerCalculator} from "../src/interfaces/IEarningPowerCalculator.sol";
import {MintRewardNotifier} from "../src/notifiers/MintRewardNotifier.sol";
import {Staker} from "../src/Staker.sol";
import {DeployBaseFake} from "./fakes/DeployBaseFake.sol";
import {ERC20Fake} from "./fakes/ERC20Fake.sol";
import {ERC20VotesMock} from "./mocks/MockERC20Votes.sol";

contract DeployBaseTest is Test {
ERC20Fake rewardToken;
ERC20VotesMock govToken;
DeployBaseFake deployScript;

function setUp() public {
rewardToken = new ERC20Fake();
vm.label(address(rewardToken), "Reward Token");

govToken = new ERC20VotesMock();
vm.label(address(govToken), "Governance Token");

deployScript = new DeployBaseFake(rewardToken, govToken);
}
}

contract Run is DeployBaseTest {
function test_StakingSystemDeploy() public {
(IEarningPowerCalculator _calculator, Staker _staker, address[] memory _notifiers) =
deployScript.run();
MintRewardNotifier _mintNotifier = MintRewardNotifier(_notifiers[0]);
assertEq(address(_staker), address(_mintNotifier.RECEIVER()));
assertEq(10e18, _mintNotifier.rewardAmount());
assertEq(30 days, _mintNotifier.rewardInterval());
assertEq(deployScript.notifierOwner(), _mintNotifier.owner());
assertEq(address(deployScript.notifierMinter()), address(_mintNotifier.minter()));

// Staker params
assertTrue(_staker.isRewardNotifier(_notifiers[0]));
assertEq(address(_calculator), address(_staker.earningPowerCalculator()));
assertEq(address(rewardToken), address(_staker.REWARD_TOKEN()));
assertEq(address(govToken), address(_staker.STAKE_TOKEN()));
assertEq(address(deployScript.admin()), _staker.admin());
}
}
78 changes: 78 additions & 0 deletions test/DeployTransferFromRewardNotifier.t.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity ^0.8.23;

import {Test} from "forge-std/Test.sol";
import {Staker} from "../src/Staker.sol";
import {TransferFromRewardNotifier} from "../src/notifiers/TransferFromRewardNotifier.sol";
import {DeployTransferFromRewardNotifierFake} from
"./fakes/DeployTransferFromRewardNotifierFake.sol";
import {ERC20Fake} from "./fakes/ERC20Fake.sol";
import {ERC20VotesMock} from "./mocks/MockERC20Votes.sol";
import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol";

contract DeployTransferFromRewardNotifierTest is Test {
ERC20Fake rewardToken;
ERC20VotesMock govToken;
DeployTransferFromRewardNotifierFake deployScript;

function setUp() public {
rewardToken = new ERC20Fake();
vm.label(address(rewardToken), "Reward Token");

govToken = new ERC20VotesMock();
vm.label(address(govToken), "Governance Token");

deployScript = new DeployTransferFromRewardNotifierFake(rewardToken, govToken);
}
}

contract run is DeployTransferFromRewardNotifierTest {
function test_DeployTransferFromRewardNotifier() public {
(, Staker _staker, address[] memory _notifiers) = deployScript.run();

TransferFromRewardNotifier _transferFromNotifier = TransferFromRewardNotifier(_notifiers[0]);
assertEq(address(_staker), address(_transferFromNotifier.RECEIVER()));
assertEq(10e18, _transferFromNotifier.rewardAmount());
assertEq(30 days, _transferFromNotifier.rewardInterval());
assertEq(deployScript.notifierOwner(), _transferFromNotifier.owner());
assertEq(
address(deployScript.notifierRewardSource()), address(_transferFromNotifier.rewardSource())
);
}
}

contract SetRewardSource is DeployTransferFromRewardNotifierTest {
function testFuzz_UpdatesTheRewardSource(address _newRewardSource) public {
(,, address[] memory _notifiers) = deployScript.run();
TransferFromRewardNotifier _transferFromNotifier = TransferFromRewardNotifier(_notifiers[0]);
address owner = deployScript.notifierOwner();

vm.prank(owner);
_transferFromNotifier.setRewardSource(_newRewardSource);

assertEq(_transferFromNotifier.rewardSource(), _newRewardSource);
}

function testFuzz_EmitsAnEventForSettingTheRewardSource(address _newRewardSource) public {
(,, address[] memory _notifiers) = deployScript.run();
TransferFromRewardNotifier _transferFromNotifier = TransferFromRewardNotifier(_notifiers[0]);
address owner = deployScript.notifierOwner();
address _oldRewardSource = deployScript.notifierRewardSource();

vm.expectEmit();
emit TransferFromRewardNotifier.RewardSourceSet(_oldRewardSource, _newRewardSource);
vm.prank(owner);
_transferFromNotifier.setRewardSource(_newRewardSource);
}

function testFuzz_RevertIf_CallerIsNotOwner(address _newRewardSource, address _notOwner) public {
(,, address[] memory _notifiers) = deployScript.run();
TransferFromRewardNotifier _transferFromNotifier = TransferFromRewardNotifier(_notifiers[0]);
address owner = deployScript.notifierOwner();

vm.assume(_notOwner != owner);
vm.expectRevert(abi.encodeWithSelector(Ownable.OwnableUnauthorizedAccount.selector, _notOwner));
vm.prank(_notOwner);
_transferFromNotifier.setRewardSource(_newRewardSource);
}
}
Loading
Loading