From 515e0be30974103511095a253e816570da57905f Mon Sep 17 00:00:00 2001 From: keating Date: Sat, 8 Mar 2025 14:01:56 -0500 Subject: [PATCH 01/12] WIP --- src/script/DeployBase.s.sol | 81 +++++++++++++++++++++++++++++++++++++ 1 file changed, 81 insertions(+) create mode 100644 src/script/DeployBase.s.sol diff --git a/src/script/DeployBase.s.sol b/src/script/DeployBase.s.sol new file mode 100644 index 0000000..d7183f6 --- /dev/null +++ b/src/script/DeployBase.s.sol @@ -0,0 +1,81 @@ +// SPDX-License-Identifier: AGPL-3.0-only +// slither-disable-start reentrancy-benign + +pragma solidity ^0.8.23; + +import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import {Script} from "forge-std/Script.sol"; + +import {DeployInput} from "./DeployInput.sol"; +import {StakerHarness} from "../../test/harnesses/StakerHarness.sol"; +import {IERC20Staking} from "../interfaces/IERC20Staking.sol"; +import {IEarningPowerCalculator} from "../interfaces/IEarningPowerCalculator.sol"; +import {Staker} from "../Staker.sol"; + +// base config +// What if constructor has different args? +// - Script per script, should be handled via composition +// - typing to handle specific args +// base base +// - Deploy staker +// - Deploy earning power calculator +// - Deploy and add reward notifiers +// - Set Admin +abstract contract StakerBaseDeploy is Script, DeployInput { + uint256 deployerPrivateKey; + RewardNotifier[] rewardNotifiers; + + struct BaseConfiguration { + address admin; + } + + struct RewardNotifier { + address rewardNotifier; + bool isEnabled; + } + + function setUp() public { + deployerPrivateKey = vm.envOr( + "DEPLOYER_PRIVATE_KEY", + uint256(0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80) + ); + } + + function _deployBaseConfiguration() internal virtual returns (BaseConfiguration memory); + + function _deployStaker() internal virtual returns (Staker); + + function _deployEarningPowerCalculator() internal virtual returns (IEarningPowerCalculator); + + // + function _deployRewardNotifiers() internal virtual; + + function run() public { + Staker _staker = _deployStaker(); + + for (uint256 i = 0; i < rewardNotifiers.length; i++) { + _staker.setRewardNotifier(rewardNotifiers[i], ); + } + + BaseConfiguration memory _baseConfig = _deployBaseConfiguration(); + vm.broadcast(deployerPrivateKey); + _staker.setAdmin(_baseConfig.admin); + + // vm.startBroadcast(deployerPrivateKey); + // // Deploy the staking contract + // StakerHarness govStaker = new StakerHarness( + // IERC20(PAYOUT_TOKEN_ADDRESS), + // IERC20Staking(STAKE_TOKEN_ADDRESS), + // IEarningPowerCalculator(address(0)), + // MAX_BUMP_TIP, + // vm.addr(deployerPrivateKey), + // "StakerHarness" + // ); + + // // Change Staker admin from `msg.sender` to the Governor timelock + // govStaker.setAdmin(GOVERNOR_TIMELOCK); + // vm.stopBroadcast(); + + // return govStaker; + } +} From 7ed94d8c04f719596711bb381a71c63c6ed3dc44 Mon Sep 17 00:00:00 2001 From: Keating Date: Mon, 10 Mar 2025 14:56:57 -0400 Subject: [PATCH 02/12] WIP --- src/script/Deploy.s.sol | 42 --------- src/script/DeployBase.s.sol | 81 ----------------- src/script/DeployBase.sol | 55 ++++++++++++ src/script/DeployInput.sol | 12 --- src/script/DeployStaker.sol | 23 +++++ .../DeployIdentityEarningPowerCalculator.sol | 17 ++++ .../notifiers/DeployMinterRewardNotifier.sol | 35 ++++++++ test/DeployBase.t.sol | 39 +++++++++ test/harnesses/DeployBaseHarness.sol | 86 +++++++++++++++++++ 9 files changed, 255 insertions(+), 135 deletions(-) delete mode 100644 src/script/Deploy.s.sol delete mode 100644 src/script/DeployBase.s.sol create mode 100644 src/script/DeployBase.sol delete mode 100644 src/script/DeployInput.sol create mode 100644 src/script/DeployStaker.sol create mode 100644 src/script/calculators/DeployIdentityEarningPowerCalculator.sol create mode 100644 src/script/notifiers/DeployMinterRewardNotifier.sol create mode 100644 test/DeployBase.t.sol create mode 100644 test/harnesses/DeployBaseHarness.sol diff --git a/src/script/Deploy.s.sol b/src/script/Deploy.s.sol deleted file mode 100644 index 33403a2..0000000 --- a/src/script/Deploy.s.sol +++ /dev/null @@ -1,42 +0,0 @@ -// SPDX-License-Identifier: AGPL-3.0-only -// slither-disable-start reentrancy-benign - -pragma solidity ^0.8.23; - -import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; -import {Script} from "forge-std/Script.sol"; - -import {DeployInput} from "./DeployInput.sol"; -import {StakerHarness} from "../../test/harnesses/StakerHarness.sol"; -import {IERC20Staking} from "../interfaces/IERC20Staking.sol"; -import {IEarningPowerCalculator} from "../interfaces/IEarningPowerCalculator.sol"; - -contract Deploy is Script, DeployInput { - uint256 deployerPrivateKey; - - function setUp() public { - deployerPrivateKey = vm.envOr( - "DEPLOYER_PRIVATE_KEY", - uint256(0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80) - ); - } - - function run() public returns (StakerHarness) { - vm.startBroadcast(deployerPrivateKey); - // Deploy the staking contract - StakerHarness govStaker = new StakerHarness( - IERC20(PAYOUT_TOKEN_ADDRESS), - IERC20Staking(STAKE_TOKEN_ADDRESS), - IEarningPowerCalculator(address(0)), - MAX_BUMP_TIP, - vm.addr(deployerPrivateKey), - "StakerHarness" - ); - - // Change Staker admin from `msg.sender` to the Governor timelock - govStaker.setAdmin(GOVERNOR_TIMELOCK); - vm.stopBroadcast(); - - return govStaker; - } -} diff --git a/src/script/DeployBase.s.sol b/src/script/DeployBase.s.sol deleted file mode 100644 index d7183f6..0000000 --- a/src/script/DeployBase.s.sol +++ /dev/null @@ -1,81 +0,0 @@ -// SPDX-License-Identifier: AGPL-3.0-only -// slither-disable-start reentrancy-benign - -pragma solidity ^0.8.23; - -import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; -import {Script} from "forge-std/Script.sol"; - -import {DeployInput} from "./DeployInput.sol"; -import {StakerHarness} from "../../test/harnesses/StakerHarness.sol"; -import {IERC20Staking} from "../interfaces/IERC20Staking.sol"; -import {IEarningPowerCalculator} from "../interfaces/IEarningPowerCalculator.sol"; -import {Staker} from "../Staker.sol"; - -// base config -// What if constructor has different args? -// - Script per script, should be handled via composition -// - typing to handle specific args -// base base -// - Deploy staker -// - Deploy earning power calculator -// - Deploy and add reward notifiers -// - Set Admin -abstract contract StakerBaseDeploy is Script, DeployInput { - uint256 deployerPrivateKey; - RewardNotifier[] rewardNotifiers; - - struct BaseConfiguration { - address admin; - } - - struct RewardNotifier { - address rewardNotifier; - bool isEnabled; - } - - function setUp() public { - deployerPrivateKey = vm.envOr( - "DEPLOYER_PRIVATE_KEY", - uint256(0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80) - ); - } - - function _deployBaseConfiguration() internal virtual returns (BaseConfiguration memory); - - function _deployStaker() internal virtual returns (Staker); - - function _deployEarningPowerCalculator() internal virtual returns (IEarningPowerCalculator); - - // - function _deployRewardNotifiers() internal virtual; - - function run() public { - Staker _staker = _deployStaker(); - - for (uint256 i = 0; i < rewardNotifiers.length; i++) { - _staker.setRewardNotifier(rewardNotifiers[i], ); - } - - BaseConfiguration memory _baseConfig = _deployBaseConfiguration(); - vm.broadcast(deployerPrivateKey); - _staker.setAdmin(_baseConfig.admin); - - // vm.startBroadcast(deployerPrivateKey); - // // Deploy the staking contract - // StakerHarness govStaker = new StakerHarness( - // IERC20(PAYOUT_TOKEN_ADDRESS), - // IERC20Staking(STAKE_TOKEN_ADDRESS), - // IEarningPowerCalculator(address(0)), - // MAX_BUMP_TIP, - // vm.addr(deployerPrivateKey), - // "StakerHarness" - // ); - - // // Change Staker admin from `msg.sender` to the Governor timelock - // govStaker.setAdmin(GOVERNOR_TIMELOCK); - // vm.stopBroadcast(); - - // return govStaker; - } -} diff --git a/src/script/DeployBase.sol b/src/script/DeployBase.sol new file mode 100644 index 0000000..be0c2dc --- /dev/null +++ b/src/script/DeployBase.sol @@ -0,0 +1,55 @@ +// 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 { + uint256 deployerPrivateKey; + RewardNotifier[] internal rewardNotifiers; + + struct BaseConfiguration { + address admin; + } + + struct RewardNotifier { + address rewardNotifier; + bool isEnabled; + } + + function setUp() public { + deployerPrivateKey = vm.envOr( + "DEPLOYER_PRIVATE_KEY", + uint256(0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80) + ); + } + + function _deployBaseConfiguration() internal virtual returns (BaseConfiguration memory); + + function _deployStaker(IEarningPowerCalculator _earningPowerCalculator) + internal + virtual + returns (Staker); + + function _deployEarningPowerCalculator() internal virtual returns (IEarningPowerCalculator); + + // + function _deployRewardNotifiers() internal virtual; + + function run() public { + IEarningPowerCalculator _earningPowerCalculator = _deployEarningPowerCalculator(); + Staker _staker = _deployStaker(_earningPowerCalculator); + + for (uint256 i = 0; i < rewardNotifiers.length; i++) { + _staker.setRewardNotifier(rewardNotifiers[i].rewardNotifier, rewardNotifiers[i].isEnabled); + } + + BaseConfiguration memory _baseConfig = _deployBaseConfiguration(); + vm.broadcast(deployerPrivateKey); + _staker.setAdmin(_baseConfig.admin); + } +} diff --git a/src/script/DeployInput.sol b/src/script/DeployInput.sol deleted file mode 100644 index 61addff..0000000 --- a/src/script/DeployInput.sol +++ /dev/null @@ -1,12 +0,0 @@ -// SPDX-License-Identifier: AGPL-3.0-only -// slither-disable-start reentrancy-benign - -pragma solidity ^0.8.23; - -contract DeployInput { - address constant GOVERNOR_TIMELOCK = 0x1a9C8182C09F50C8318d769245beA52c32BE35BC; - address constant PAYOUT_TOKEN_ADDRESS = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2; // WETH - uint256 constant PAYOUT_AMOUNT = 10e18; // 10 (WETH) - address constant STAKE_TOKEN_ADDRESS = 0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984; // UNI - uint256 constant MAX_BUMP_TIP = 100_000e18; // TODO this should be updated before deployment -} diff --git a/src/script/DeployStaker.sol b/src/script/DeployStaker.sol new file mode 100644 index 0000000..1f3f25a --- /dev/null +++ b/src/script/DeployStaker.sol @@ -0,0 +1,23 @@ +// 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 { + struct StakerConfiguration { + IERC20 rewardToken; + IERC20 stakeToken; + IEarningPowerCalculator earningPowerCalculator; + uint256 maxBumpTip; + address admin; + } + + function _deployStakerConfiguration(IEarningPowerCalculator _earningPowerCalculator) + internal + virtual + returns (StakerConfiguration memory); +} diff --git a/src/script/calculators/DeployIdentityEarningPowerCalculator.sol b/src/script/calculators/DeployIdentityEarningPowerCalculator.sol new file mode 100644 index 0000000..1652965 --- /dev/null +++ b/src/script/calculators/DeployIdentityEarningPowerCalculator.sol @@ -0,0 +1,17 @@ +// 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 { + function _deployEarningPowerCalculator() + internal + virtual + override + returns (IEarningPowerCalculator) + { + return new IdentityEarningPowerCalculator(); + } +} diff --git a/src/script/notifiers/DeployMinterRewardNotifier.sol b/src/script/notifiers/DeployMinterRewardNotifier.sol new file mode 100644 index 0000000..18f62e6 --- /dev/null +++ b/src/script/notifiers/DeployMinterRewardNotifier.sol @@ -0,0 +1,35 @@ +// 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"; + +abstract contract DeployMinterRewardNotifier is DeployBase { + struct MinterRewardNotifierConfiguration { + INotifiableRewardReceiver receiver; + uint256 initialRewardAmount; + uint256 initialRewardInterval; + address initialOwner; + IMintable minter; + } + + function _deployMinterRewardNotifierConfiguration() + internal + virtual + returns (MinterRewardNotifierConfiguration memory); + + function _deployRewardNotifiers() internal virtual override { + MinterRewardNotifierConfiguration memory _config = _deployMinterRewardNotifierConfiguration(); + MintRewardNotifier _notifier = new MintRewardNotifier( + _config.receiver, + _config.initialRewardAmount, + _config.initialRewardInterval, + _config.initialOwner, + _config.minter + ); + rewardNotifiers[rewardNotifiers.length] = + RewardNotifier({rewardNotifier: address(_notifier), isEnabled: true}); + } +} diff --git a/test/DeployBase.t.sol b/test/DeployBase.t.sol new file mode 100644 index 0000000..cf3daf1 --- /dev/null +++ b/test/DeployBase.t.sol @@ -0,0 +1,39 @@ +// SPDX-License-Identifier: AGPL-3.0-only +pragma solidity ^0.8.23; + +import {Test} from "forge-std/Test.sol"; +import {DeployBaseHarness} from "./harnesses/DeployBaseHarness.sol"; +import {ERC20Fake} from "./fakes/ERC20Fake.sol"; +import {ERC20VotesMock} from "./mocks/MockERC20Votes.sol"; + +// Setup harness +contract DeployBaseTest is Test { + ERC20Fake rewardToken; + ERC20VotesMock govToken; + DeployBaseHarness deployScript; + + function setUp() public { + rewardToken = new ERC20Fake(); + vm.label(address(rewardToken), "Reward Token"); + + govToken = new ERC20VotesMock(); + vm.label(address(govToken), "Governance Token"); + + + deployScript = new DeployBaseHarness(rewardToken, govToken); + } +} + +// test run, mock configuration that is fuzzed +// check byte code matches + +contract Run is DeployBaseTest { + + function test_StakingSystemDeploy() public { + deployScript.run(); + // staker + // earning power calculator + // reward notifiers + + } +} diff --git a/test/harnesses/DeployBaseHarness.sol b/test/harnesses/DeployBaseHarness.sol new file mode 100644 index 0000000..f5c59d2 --- /dev/null +++ b/test/harnesses/DeployBaseHarness.sol @@ -0,0 +1,86 @@ +// SPDX-License-Identifier: AGPL-3.0-only +pragma solidity ^0.8.23; + +import {DeployBase} from "../../src/script/DeployBase.sol"; +import {DeployStaker} from "../../src/script/DeployStaker.sol"; +import {DeployMinterRewardNotifier} from "../../src/script/notifiers/DeployMinterRewardNotifier.sol"; +import {DeployIdentityEarningPowerCalculator} from + "../../src/script/calculators/DeployIdentityEarningPowerCalculator.sol"; +import {IMintable} from "../../src/interfaces/IMintable.sol"; +import {INotifiableRewardReceiver} from "../../src/interfaces/INotifiableRewardReceiver.sol"; + +import {IEarningPowerCalculator} from "../../src/interfaces/IEarningPowerCalculator.sol"; +import {Staker} from "../../src/Staker.sol"; +import {StakerHarness} from "./StakerHarness.sol"; +import {IERC20Staking} from "../../src/interfaces/IERC20Staking.sol"; +import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; + +contract DeployBaseHarness is + DeployBase, + DeployStaker, + DeployMinterRewardNotifier, + DeployIdentityEarningPowerCalculator +{ + address admin = makeAddr("Staker admin"); + address notifierReceiver = makeAddr("Notifier receiver"); + address notifierOwner = makeAddr("Notifier owner"); + address notifierMinter = makeAddr("Notifier minter"); + IERC20 rewardToken; + IERC20 stakeToken; + + constructor(IERC20 _rewardToken, IERC20 _stakeToken) { + rewardToken = _rewardToken; + stakeToken = _stakeToken; + } + + function _deployBaseConfiguration() internal virtual override returns (BaseConfiguration memory) { + return BaseConfiguration({admin: admin}); + } + + function _deployMinterRewardNotifierConfiguration() + internal + virtual + override + returns (MinterRewardNotifierConfiguration memory) + { + return MinterRewardNotifierConfiguration({ + receiver: INotifiableRewardReceiver(notifierReceiver), + initialRewardAmount: 10e18, + initialRewardInterval: 30 days, + initialOwner: notifierOwner, + minter: IMintable(notifierMinter) + }); + } + + function _deployStakerConfiguration(IEarningPowerCalculator _earningPowerCalculator) + internal + virtual + override + returns (StakerConfiguration memory) + { + return StakerConfiguration({ + rewardToken: rewardToken, + stakeToken: stakeToken, + earningPowerCalculator: _earningPowerCalculator, + maxBumpTip: 1e18, + admin: makeAddr("Admin") + }); + } + + function _deployStaker(IEarningPowerCalculator _earningPowerCalculator) + internal + virtual + override + returns (Staker) + { + StakerConfiguration memory _config = _deployStakerConfiguration(_earningPowerCalculator); + return new StakerHarness( + _config.rewardToken, + IERC20Staking(address(_config.stakeToken)), + _config.earningPowerCalculator, + _config.maxBumpTip, + _config.admin, + "Harness" + ); + } +} From 954918d63ffd66f3a4e166cef218a21257e8d447 Mon Sep 17 00:00:00 2001 From: keating Date: Mon, 10 Mar 2025 18:15:23 -0400 Subject: [PATCH 03/12] WIP --- src/script/DeployBase.sol | 2 +- test/DeployBase.t.sol | 31 +++++++++++++++++++------------ 2 files changed, 20 insertions(+), 13 deletions(-) diff --git a/src/script/DeployBase.sol b/src/script/DeployBase.sol index be0c2dc..ecf64e6 100644 --- a/src/script/DeployBase.sol +++ b/src/script/DeployBase.sol @@ -40,7 +40,7 @@ abstract contract DeployBase is Script { // function _deployRewardNotifiers() internal virtual; - function run() public { + function run() public returns (IEarningPowerCalculator, Staker, RewardNotifier[] memory) { IEarningPowerCalculator _earningPowerCalculator = _deployEarningPowerCalculator(); Staker _staker = _deployStaker(_earningPowerCalculator); diff --git a/test/DeployBase.t.sol b/test/DeployBase.t.sol index cf3daf1..e84cd70 100644 --- a/test/DeployBase.t.sol +++ b/test/DeployBase.t.sol @@ -2,6 +2,9 @@ pragma solidity ^0.8.23; import {Test} from "forge-std/Test.sol"; +import {IEarningPowerCalculator} from "../src/interfaces/IEarningPowerCalculator.sol"; +import {DeployBase} from "../src/script/DeployBase.sol"; +import {Staker} from "../../src/Staker.sol"; import {DeployBaseHarness} from "./harnesses/DeployBaseHarness.sol"; import {ERC20Fake} from "./fakes/ERC20Fake.sol"; import {ERC20VotesMock} from "./mocks/MockERC20Votes.sol"; @@ -12,28 +15,32 @@ contract DeployBaseTest is Test { ERC20VotesMock govToken; DeployBaseHarness deployScript; - function setUp() public { + function setUp() public { rewardToken = new ERC20Fake(); vm.label(address(rewardToken), "Reward Token"); govToken = new ERC20VotesMock(); vm.label(address(govToken), "Governance Token"); - - deployScript = new DeployBaseHarness(rewardToken, govToken); - } + deployScript = new DeployBaseHarness(rewardToken, govToken); + } } // test run, mock configuration that is fuzzed // check byte code matches contract Run is DeployBaseTest { - - function test_StakingSystemDeploy() public { - deployScript.run(); - // staker - // earning power calculator - // reward notifiers - - } + function test_StakingSystemDeploy() public { + (IEarningPowerCalculator _calculator, Staker _staker, DeployBase.RewardNotifier[] memory _notifiers) = deployScript.run(); + assertEq(address(_calculator), address(_staker.earningPowerCalculator())); + assertTrue(_staker.isRewardNotifier(_notifiers[0].rewardNotifier)); + assertEq(address(rewardToken), address(_staker.REWARD_TOKEN())); + assertEq(address(govToken), address(_staker.STAKE_TOKEN())); + assertEq(address(govToken), _staker.admin()); + + + // staker + // earning power calculator + // reward notifiers + } } From 312c578c58d61585c8344e135202e56848a76d55 Mon Sep 17 00:00:00 2001 From: Keating Date: Tue, 11 Mar 2025 21:54:33 -0400 Subject: [PATCH 04/12] Working tests --- src/script/DeployBase.sol | 33 +++++++++---------- src/script/DeployStaker.sol | 1 - .../notifiers/DeployMinterRewardNotifier.sol | 9 +++-- test/DeployBase.t.sol | 33 ++++++++++++++----- test/harnesses/DeployBaseHarness.sol | 18 +++++----- 5 files changed, 53 insertions(+), 41 deletions(-) diff --git a/src/script/DeployBase.sol b/src/script/DeployBase.sol index ecf64e6..73fb254 100644 --- a/src/script/DeployBase.sol +++ b/src/script/DeployBase.sol @@ -3,6 +3,7 @@ pragma solidity ^0.8.23; +import {Vm, Test, stdStorage, StdStorage, console2, console, stdError} from "forge-std/Test.sol"; import {Script} from "forge-std/Script.sol"; import {IEarningPowerCalculator} from "../interfaces/IEarningPowerCalculator.sol"; @@ -10,24 +11,13 @@ import {Staker} from "../Staker.sol"; abstract contract DeployBase is Script { uint256 deployerPrivateKey; - RewardNotifier[] internal rewardNotifiers; + address[] internal rewardNotifiers; + address deployer; struct BaseConfiguration { address admin; } - struct RewardNotifier { - address rewardNotifier; - bool isEnabled; - } - - function setUp() public { - deployerPrivateKey = vm.envOr( - "DEPLOYER_PRIVATE_KEY", - uint256(0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80) - ); - } - function _deployBaseConfiguration() internal virtual returns (BaseConfiguration memory); function _deployStaker(IEarningPowerCalculator _earningPowerCalculator) @@ -38,18 +28,27 @@ abstract contract DeployBase is Script { function _deployEarningPowerCalculator() internal virtual returns (IEarningPowerCalculator); // - function _deployRewardNotifiers() internal virtual; + function _deployRewardNotifiers(Staker _staker) internal virtual; + + function run() public returns (IEarningPowerCalculator, Staker, address[] memory) { + deployerPrivateKey = vm.envOr( + "DEPLOYER_PRIVATE_KEY", + uint256(0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80) + ); - function run() public returns (IEarningPowerCalculator, Staker, RewardNotifier[] memory) { + 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].rewardNotifier, rewardNotifiers[i].isEnabled); + _staker.setRewardNotifier(rewardNotifiers[i], true); } BaseConfiguration memory _baseConfig = _deployBaseConfiguration(); - vm.broadcast(deployerPrivateKey); _staker.setAdmin(_baseConfig.admin); + vm.stopBroadcast(); + return (_earningPowerCalculator, _staker, rewardNotifiers); } } diff --git a/src/script/DeployStaker.sol b/src/script/DeployStaker.sol index 1f3f25a..509a56f 100644 --- a/src/script/DeployStaker.sol +++ b/src/script/DeployStaker.sol @@ -13,7 +13,6 @@ abstract contract DeployStaker is DeployBase { IERC20 stakeToken; IEarningPowerCalculator earningPowerCalculator; uint256 maxBumpTip; - address admin; } function _deployStakerConfiguration(IEarningPowerCalculator _earningPowerCalculator) diff --git a/src/script/notifiers/DeployMinterRewardNotifier.sol b/src/script/notifiers/DeployMinterRewardNotifier.sol index 18f62e6..0169db2 100644 --- a/src/script/notifiers/DeployMinterRewardNotifier.sol +++ b/src/script/notifiers/DeployMinterRewardNotifier.sol @@ -5,10 +5,10 @@ import {INotifiableRewardReceiver} from "../../interfaces/INotifiableRewardRecei 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 { struct MinterRewardNotifierConfiguration { - INotifiableRewardReceiver receiver; uint256 initialRewardAmount; uint256 initialRewardInterval; address initialOwner; @@ -20,16 +20,15 @@ abstract contract DeployMinterRewardNotifier is DeployBase { virtual returns (MinterRewardNotifierConfiguration memory); - function _deployRewardNotifiers() internal virtual override { + function _deployRewardNotifiers(Staker _staker) internal virtual override { MinterRewardNotifierConfiguration memory _config = _deployMinterRewardNotifierConfiguration(); MintRewardNotifier _notifier = new MintRewardNotifier( - _config.receiver, + INotifiableRewardReceiver(address(_staker)), _config.initialRewardAmount, _config.initialRewardInterval, _config.initialOwner, _config.minter ); - rewardNotifiers[rewardNotifiers.length] = - RewardNotifier({rewardNotifier: address(_notifier), isEnabled: true}); + rewardNotifiers.push(address(_notifier)); } } diff --git a/test/DeployBase.t.sol b/test/DeployBase.t.sol index e84cd70..1fcb59f 100644 --- a/test/DeployBase.t.sol +++ b/test/DeployBase.t.sol @@ -1,10 +1,12 @@ // SPDX-License-Identifier: AGPL-3.0-only pragma solidity ^0.8.23; +import {Vm, Test, stdStorage, StdStorage, console2, stdError} from "forge-std/Test.sol"; import {Test} from "forge-std/Test.sol"; import {IEarningPowerCalculator} from "../src/interfaces/IEarningPowerCalculator.sol"; +import {MintRewardNotifier} from "../src/notifiers/MintRewardNotifier.sol"; import {DeployBase} from "../src/script/DeployBase.sol"; -import {Staker} from "../../src/Staker.sol"; +import {Staker} from "../src/Staker.sol"; import {DeployBaseHarness} from "./harnesses/DeployBaseHarness.sol"; import {ERC20Fake} from "./fakes/ERC20Fake.sol"; import {ERC20VotesMock} from "./mocks/MockERC20Votes.sol"; @@ -31,16 +33,31 @@ contract DeployBaseTest is Test { contract Run is DeployBaseTest { function test_StakingSystemDeploy() public { - (IEarningPowerCalculator _calculator, Staker _staker, DeployBase.RewardNotifier[] memory _notifiers) = deployScript.run(); + (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())); - assertTrue(_staker.isRewardNotifier(_notifiers[0].rewardNotifier)); assertEq(address(rewardToken), address(_staker.REWARD_TOKEN())); assertEq(address(govToken), address(_staker.STAKE_TOKEN())); - assertEq(address(govToken), _staker.admin()); - + assertEq(address(deployScript.admin()), _staker.admin()); + } - // staker - // earning power calculator - // reward notifiers + function testfuzz_StakingSystemDeployWithMockStakerConfiguration() public { + // + (IEarningPowerCalculator _calculator, Staker _staker, address[] memory _notifiers) = deployScript.run(); + console2.logUint(_notifiers.length); + assertEq(address(_calculator), address(_staker.earningPowerCalculator())); + assertTrue(_staker.isRewardNotifier(_notifiers[0])); + assertEq(address(rewardToken), address(_staker.REWARD_TOKEN())); + assertEq(address(govToken), address(_staker.STAKE_TOKEN())); + assertEq(address(deployScript.admin()), _staker.admin()); } + } diff --git a/test/harnesses/DeployBaseHarness.sol b/test/harnesses/DeployBaseHarness.sol index f5c59d2..701039d 100644 --- a/test/harnesses/DeployBaseHarness.sol +++ b/test/harnesses/DeployBaseHarness.sol @@ -21,12 +21,12 @@ contract DeployBaseHarness is DeployMinterRewardNotifier, DeployIdentityEarningPowerCalculator { - address admin = makeAddr("Staker admin"); - address notifierReceiver = makeAddr("Notifier receiver"); - address notifierOwner = makeAddr("Notifier owner"); - address notifierMinter = makeAddr("Notifier minter"); - IERC20 rewardToken; - IERC20 stakeToken; + address public admin = makeAddr("Staker admin"); + address public notifierReceiver = makeAddr("Notifier receiver"); + address public notifierOwner = makeAddr("Notifier owner"); + address public notifierMinter = makeAddr("Notifier minter"); + IERC20 public rewardToken; + IERC20 public stakeToken; constructor(IERC20 _rewardToken, IERC20 _stakeToken) { rewardToken = _rewardToken; @@ -44,7 +44,6 @@ contract DeployBaseHarness is returns (MinterRewardNotifierConfiguration memory) { return MinterRewardNotifierConfiguration({ - receiver: INotifiableRewardReceiver(notifierReceiver), initialRewardAmount: 10e18, initialRewardInterval: 30 days, initialOwner: notifierOwner, @@ -62,8 +61,7 @@ contract DeployBaseHarness is rewardToken: rewardToken, stakeToken: stakeToken, earningPowerCalculator: _earningPowerCalculator, - maxBumpTip: 1e18, - admin: makeAddr("Admin") + maxBumpTip: 1e18 }); } @@ -79,7 +77,7 @@ contract DeployBaseHarness is IERC20Staking(address(_config.stakeToken)), _config.earningPowerCalculator, _config.maxBumpTip, - _config.admin, + deployer, "Harness" ); } From f6a2cca4cd84a9a8c1b8df5affeed4d755a65728 Mon Sep 17 00:00:00 2001 From: Keating Date: Tue, 11 Mar 2025 21:59:20 -0400 Subject: [PATCH 05/12] Fix lint --- src/script/DeployBase.sol | 8 ++++---- test/DeployBase.t.sol | 35 ++++++++++++++++++----------------- 2 files changed, 22 insertions(+), 21 deletions(-) diff --git a/src/script/DeployBase.sol b/src/script/DeployBase.sol index 73fb254..71e2df6 100644 --- a/src/script/DeployBase.sol +++ b/src/script/DeployBase.sol @@ -37,18 +37,18 @@ abstract contract DeployBase is Script { ); deployer = vm.rememberKey(deployerPrivateKey); - vm.startBroadcast(deployer); + vm.startBroadcast(deployer); IEarningPowerCalculator _earningPowerCalculator = _deployEarningPowerCalculator(); Staker _staker = _deployStaker(_earningPowerCalculator); - _deployRewardNotifiers(_staker); + _deployRewardNotifiers(_staker); for (uint256 i = 0; i < rewardNotifiers.length; i++) { _staker.setRewardNotifier(rewardNotifiers[i], true); } BaseConfiguration memory _baseConfig = _deployBaseConfiguration(); _staker.setAdmin(_baseConfig.admin); - vm.stopBroadcast(); - return (_earningPowerCalculator, _staker, rewardNotifiers); + vm.stopBroadcast(); + return (_earningPowerCalculator, _staker, rewardNotifiers); } } diff --git a/test/DeployBase.t.sol b/test/DeployBase.t.sol index 1fcb59f..e92a41b 100644 --- a/test/DeployBase.t.sol +++ b/test/DeployBase.t.sol @@ -33,25 +33,27 @@ contract DeployBaseTest is Test { 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()); + (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()); } function testfuzz_StakingSystemDeployWithMockStakerConfiguration() public { - // - (IEarningPowerCalculator _calculator, Staker _staker, address[] memory _notifiers) = deployScript.run(); + // + (IEarningPowerCalculator _calculator, Staker _staker, address[] memory _notifiers) = + deployScript.run(); console2.logUint(_notifiers.length); assertEq(address(_calculator), address(_staker.earningPowerCalculator())); assertTrue(_staker.isRewardNotifier(_notifiers[0])); @@ -59,5 +61,4 @@ contract Run is DeployBaseTest { assertEq(address(govToken), address(_staker.STAKE_TOKEN())); assertEq(address(deployScript.admin()), _staker.admin()); } - } From 9a13ea6ce68c0a738e6592ffc0f1c9dab02e6629 Mon Sep 17 00:00:00 2001 From: keating Date: Wed, 12 Mar 2025 21:09:29 -0400 Subject: [PATCH 06/12] Cleanup a little --- test/DeployBase.t.sol | 20 +------------------- 1 file changed, 1 insertion(+), 19 deletions(-) diff --git a/test/DeployBase.t.sol b/test/DeployBase.t.sol index e92a41b..a863b1c 100644 --- a/test/DeployBase.t.sol +++ b/test/DeployBase.t.sol @@ -1,17 +1,14 @@ // SPDX-License-Identifier: AGPL-3.0-only pragma solidity ^0.8.23; -import {Vm, Test, stdStorage, StdStorage, console2, stdError} from "forge-std/Test.sol"; import {Test} from "forge-std/Test.sol"; import {IEarningPowerCalculator} from "../src/interfaces/IEarningPowerCalculator.sol"; import {MintRewardNotifier} from "../src/notifiers/MintRewardNotifier.sol"; -import {DeployBase} from "../src/script/DeployBase.sol"; import {Staker} from "../src/Staker.sol"; import {DeployBaseHarness} from "./harnesses/DeployBaseHarness.sol"; import {ERC20Fake} from "./fakes/ERC20Fake.sol"; import {ERC20VotesMock} from "./mocks/MockERC20Votes.sol"; -// Setup harness contract DeployBaseTest is Test { ERC20Fake rewardToken; ERC20VotesMock govToken; @@ -28,9 +25,6 @@ contract DeployBaseTest is Test { } } -// test run, mock configuration that is fuzzed -// check byte code matches - contract Run is DeployBaseTest { function test_StakingSystemDeploy() public { (IEarningPowerCalculator _calculator, Staker _staker, address[] memory _notifiers) = @@ -49,16 +43,4 @@ contract Run is DeployBaseTest { assertEq(address(govToken), address(_staker.STAKE_TOKEN())); assertEq(address(deployScript.admin()), _staker.admin()); } - - function testfuzz_StakingSystemDeployWithMockStakerConfiguration() public { - // - (IEarningPowerCalculator _calculator, Staker _staker, address[] memory _notifiers) = - deployScript.run(); - console2.logUint(_notifiers.length); - assertEq(address(_calculator), address(_staker.earningPowerCalculator())); - assertTrue(_staker.isRewardNotifier(_notifiers[0])); - assertEq(address(rewardToken), address(_staker.REWARD_TOKEN())); - assertEq(address(govToken), address(_staker.STAKE_TOKEN())); - assertEq(address(deployScript.admin()), _staker.admin()); - } -} + } From 6d26118b2c44d8f8bd9bbb42d4774e87dab43052 Mon Sep 17 00:00:00 2001 From: keating Date: Wed, 12 Mar 2025 21:46:12 -0400 Subject: [PATCH 07/12] Add natspec --- src/script/DeployBase.sol | 22 ++++++++++++++----- src/script/DeployStaker.sol | 8 +++++++ .../DeployIdentityEarningPowerCalculator.sol | 2 ++ .../notifiers/DeployMinterRewardNotifier.sol | 14 ++++++++++++ test/DeployBase.t.sol | 2 +- 5 files changed, 42 insertions(+), 6 deletions(-) diff --git a/src/script/DeployBase.sol b/src/script/DeployBase.sol index 71e2df6..10c3307 100644 --- a/src/script/DeployBase.sol +++ b/src/script/DeployBase.sol @@ -3,35 +3,47 @@ pragma solidity ^0.8.23; -import {Vm, Test, stdStorage, StdStorage, console2, console, stdError} from "forge-std/Test.sol"; import {Script} from "forge-std/Script.sol"; - import {IEarningPowerCalculator} from "../interfaces/IEarningPowerCalculator.sol"; import {Staker} from "../Staker.sol"; abstract contract DeployBase is Script { - uint256 deployerPrivateKey; + /// @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 _deployBaseConfiguration() 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) { - deployerPrivateKey = vm.envOr( + uint256 deployerPrivateKey = vm.envOr( "DEPLOYER_PRIVATE_KEY", uint256(0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80) ); diff --git a/src/script/DeployStaker.sol b/src/script/DeployStaker.sol index 509a56f..9acafb6 100644 --- a/src/script/DeployStaker.sol +++ b/src/script/DeployStaker.sol @@ -8,6 +8,11 @@ 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; @@ -15,6 +20,9 @@ abstract contract DeployStaker is DeployBase { 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 _deployStakerConfiguration(IEarningPowerCalculator _earningPowerCalculator) internal virtual diff --git a/src/script/calculators/DeployIdentityEarningPowerCalculator.sol b/src/script/calculators/DeployIdentityEarningPowerCalculator.sol index 1652965..40ac89e 100644 --- a/src/script/calculators/DeployIdentityEarningPowerCalculator.sol +++ b/src/script/calculators/DeployIdentityEarningPowerCalculator.sol @@ -6,6 +6,8 @@ import {IdentityEarningPowerCalculator} from "../../calculators/IdentityEarningP import {IEarningPowerCalculator} from "../../interfaces/IEarningPowerCalculator.sol"; abstract contract DeployIdentityEarningPowerCalculator is DeployBase { + /// @notice Deploys an identitiy earning power calculator. + /// @inheritdoc DeployBase function _deployEarningPowerCalculator() internal virtual diff --git a/src/script/notifiers/DeployMinterRewardNotifier.sol b/src/script/notifiers/DeployMinterRewardNotifier.sol index 0169db2..38b908f 100644 --- a/src/script/notifiers/DeployMinterRewardNotifier.sol +++ b/src/script/notifiers/DeployMinterRewardNotifier.sol @@ -8,6 +8,15 @@ 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; @@ -15,11 +24,16 @@ abstract contract DeployMinterRewardNotifier is DeployBase { IMintable minter; } + /// @notice An interface method that returns the configuration for the minter reward notifier. function _deployMinterRewardNotifierConfiguration() 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 = _deployMinterRewardNotifierConfiguration(); MintRewardNotifier _notifier = new MintRewardNotifier( diff --git a/test/DeployBase.t.sol b/test/DeployBase.t.sol index a863b1c..e464dc5 100644 --- a/test/DeployBase.t.sol +++ b/test/DeployBase.t.sol @@ -43,4 +43,4 @@ contract Run is DeployBaseTest { assertEq(address(govToken), address(_staker.STAKE_TOKEN())); assertEq(address(deployScript.admin()), _staker.admin()); } - } +} From 3155f5dc927bd873cbd6235bba49171d16b91666 Mon Sep 17 00:00:00 2001 From: keating Date: Thu, 20 Mar 2025 10:40:07 -0400 Subject: [PATCH 08/12] Rename some things --- src/script/DeployBase.sol | 4 ++-- src/script/DeployStaker.sol | 2 +- src/script/notifiers/DeployMinterRewardNotifier.sol | 4 ++-- test/DeployBase.t.sol | 6 +++--- .../DeployBaseFake.sol} | 12 ++++++------ 5 files changed, 14 insertions(+), 14 deletions(-) rename test/{harnesses/DeployBaseHarness.sol => fakes/DeployBaseFake.sol} (84%) diff --git a/src/script/DeployBase.sol b/src/script/DeployBase.sol index 10c3307..2d9858f 100644 --- a/src/script/DeployBase.sol +++ b/src/script/DeployBase.sol @@ -21,7 +21,7 @@ abstract contract DeployBase is Script { /// @notice An interface method that returns a set configuration for the base script. /// @return The base configuration for the staking system. - function _deployBaseConfiguration() internal virtual returns (BaseConfiguration memory); + 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. @@ -58,7 +58,7 @@ abstract contract DeployBase is Script { _staker.setRewardNotifier(rewardNotifiers[i], true); } - BaseConfiguration memory _baseConfig = _deployBaseConfiguration(); + BaseConfiguration memory _baseConfig = _baseConfiguration(); _staker.setAdmin(_baseConfig.admin); vm.stopBroadcast(); return (_earningPowerCalculator, _staker, rewardNotifiers); diff --git a/src/script/DeployStaker.sol b/src/script/DeployStaker.sol index 9acafb6..85d8f11 100644 --- a/src/script/DeployStaker.sol +++ b/src/script/DeployStaker.sol @@ -23,7 +23,7 @@ abstract contract DeployStaker is DeployBase { /// @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 _deployStakerConfiguration(IEarningPowerCalculator _earningPowerCalculator) + function _stakerConfiguration(IEarningPowerCalculator _earningPowerCalculator) internal virtual returns (StakerConfiguration memory); diff --git a/src/script/notifiers/DeployMinterRewardNotifier.sol b/src/script/notifiers/DeployMinterRewardNotifier.sol index 38b908f..d7d70b1 100644 --- a/src/script/notifiers/DeployMinterRewardNotifier.sol +++ b/src/script/notifiers/DeployMinterRewardNotifier.sol @@ -25,7 +25,7 @@ abstract contract DeployMinterRewardNotifier is DeployBase { } /// @notice An interface method that returns the configuration for the minter reward notifier. - function _deployMinterRewardNotifierConfiguration() + function _minterRewardNotifierConfiguration() internal virtual returns (MinterRewardNotifierConfiguration memory); @@ -35,7 +35,7 @@ abstract contract DeployMinterRewardNotifier is 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 = _deployMinterRewardNotifierConfiguration(); + MinterRewardNotifierConfiguration memory _config = _minterRewardNotifierConfiguration(); MintRewardNotifier _notifier = new MintRewardNotifier( INotifiableRewardReceiver(address(_staker)), _config.initialRewardAmount, diff --git a/test/DeployBase.t.sol b/test/DeployBase.t.sol index e464dc5..62e5fe1 100644 --- a/test/DeployBase.t.sol +++ b/test/DeployBase.t.sol @@ -5,14 +5,14 @@ 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 {DeployBaseHarness} from "./harnesses/DeployBaseHarness.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; - DeployBaseHarness deployScript; + DeployBaseFake deployScript; function setUp() public { rewardToken = new ERC20Fake(); @@ -21,7 +21,7 @@ contract DeployBaseTest is Test { govToken = new ERC20VotesMock(); vm.label(address(govToken), "Governance Token"); - deployScript = new DeployBaseHarness(rewardToken, govToken); + deployScript = new DeployBaseFake(rewardToken, govToken); } } diff --git a/test/harnesses/DeployBaseHarness.sol b/test/fakes/DeployBaseFake.sol similarity index 84% rename from test/harnesses/DeployBaseHarness.sol rename to test/fakes/DeployBaseFake.sol index 701039d..722c7b3 100644 --- a/test/harnesses/DeployBaseHarness.sol +++ b/test/fakes/DeployBaseFake.sol @@ -11,11 +11,11 @@ import {INotifiableRewardReceiver} from "../../src/interfaces/INotifiableRewardR import {IEarningPowerCalculator} from "../../src/interfaces/IEarningPowerCalculator.sol"; import {Staker} from "../../src/Staker.sol"; -import {StakerHarness} from "./StakerHarness.sol"; +import {StakerHarness} from "../harnesses/StakerHarness.sol"; import {IERC20Staking} from "../../src/interfaces/IERC20Staking.sol"; import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; -contract DeployBaseHarness is +contract DeployBaseFake is DeployBase, DeployStaker, DeployMinterRewardNotifier, @@ -33,11 +33,11 @@ contract DeployBaseHarness is stakeToken = _stakeToken; } - function _deployBaseConfiguration() internal virtual override returns (BaseConfiguration memory) { + function _baseConfiguration() internal virtual override returns (BaseConfiguration memory) { return BaseConfiguration({admin: admin}); } - function _deployMinterRewardNotifierConfiguration() + function _minterRewardNotifierConfiguration() internal virtual override @@ -51,7 +51,7 @@ contract DeployBaseHarness is }); } - function _deployStakerConfiguration(IEarningPowerCalculator _earningPowerCalculator) + function _stakerConfiguration(IEarningPowerCalculator _earningPowerCalculator) internal virtual override @@ -71,7 +71,7 @@ contract DeployBaseHarness is override returns (Staker) { - StakerConfiguration memory _config = _deployStakerConfiguration(_earningPowerCalculator); + StakerConfiguration memory _config = _stakerConfiguration(_earningPowerCalculator); return new StakerHarness( _config.rewardToken, IERC20Staking(address(_config.stakeToken)), From e41d4d88929e169a02db219d16b4e173763b6209 Mon Sep 17 00:00:00 2001 From: funkyenough <14842981+funkyenough@users.noreply.github.com> Date: Fri, 14 Mar 2025 21:27:37 +0900 Subject: [PATCH 09/12] feat: add deploy script for TransferFromRewardNotifier --- .../DeployTransferFromRewardNotifier.sol | 49 +++++++++++ test/DeployTransferFromRewardNotifier.t.sol | 41 +++++++++ ...eployTransferFromRewardNotifierHarness.sol | 87 +++++++++++++++++++ 3 files changed, 177 insertions(+) create mode 100644 src/script/notifiers/DeployTransferFromRewardNotifier.sol create mode 100644 test/DeployTransferFromRewardNotifier.t.sol create mode 100644 test/harnesses/DeployTransferFromRewardNotifierHarness.sol diff --git a/src/script/notifiers/DeployTransferFromRewardNotifier.sol b/src/script/notifiers/DeployTransferFromRewardNotifier.sol new file mode 100644 index 0000000..f71c0ee --- /dev/null +++ b/src/script/notifiers/DeployTransferFromRewardNotifier.sol @@ -0,0 +1,49 @@ +// 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 _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 _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 _deployTransferFromRewardNotifierConfiguration() + 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 = + _deployTransferFromRewardNotifierConfiguration(); + TransferFromRewardNotifier _notifier = new TransferFromRewardNotifier( + INotifiableRewardReceiver(address(_staker)), + _config.initialRewardAmount, + _config.initialRewardInterval, + _config.initialOwner, + _config.initialRewardSource + ); + rewardNotifiers.push(address(_notifier)); + } +} diff --git a/test/DeployTransferFromRewardNotifier.t.sol b/test/DeployTransferFromRewardNotifier.t.sol new file mode 100644 index 0000000..bc1900e --- /dev/null +++ b/test/DeployTransferFromRewardNotifier.t.sol @@ -0,0 +1,41 @@ +// 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 {IEarningPowerCalculator} from "../src/interfaces/IEarningPowerCalculator.sol"; +import {INotifiableRewardReceiver} from "../src/interfaces/INotifiableRewardReceiver.sol"; +import {TransferFromRewardNotifier} from "../src/notifiers/TransferFromRewardNotifier.sol"; +import {DeployTransferFromRewardNotifierHarness} from + "./harnesses/DeployTransferFromRewardNotifierHarness.sol"; +import {ERC20Fake} from "./fakes/ERC20Fake.sol"; +import {ERC20VotesMock} from "./mocks/MockERC20Votes.sol"; + +contract DeployTransferFromRewardNotifierTest is Test { + ERC20Fake rewardToken; + ERC20VotesMock govToken; + DeployTransferFromRewardNotifierHarness deployScript; + + function setUp() public { + rewardToken = new ERC20Fake(); + vm.label(address(rewardToken), "Reward Token"); + + govToken = new ERC20VotesMock(); + vm.label(address(govToken), "Governance Token"); + + deployScript = new DeployTransferFromRewardNotifierHarness(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())); + } +} diff --git a/test/harnesses/DeployTransferFromRewardNotifierHarness.sol b/test/harnesses/DeployTransferFromRewardNotifierHarness.sol new file mode 100644 index 0000000..1fa47f2 --- /dev/null +++ b/test/harnesses/DeployTransferFromRewardNotifierHarness.sol @@ -0,0 +1,87 @@ +// SPDX-License-Identifier: AGPL-3.0-only +pragma solidity ^0.8.23; + +import {DeployBase} from "../../src/script/DeployBase.sol"; +import {DeployStaker} from "../../src/script/DeployStaker.sol"; +import {DeployTransferFromRewardNotifier} from + "../../src/script/notifiers/DeployTransferFromRewardNotifier.sol"; +import {DeployIdentityEarningPowerCalculator} from + "../../src/script/calculators/DeployIdentityEarningPowerCalculator.sol"; +import {IEarningPowerCalculator} from "../../src/interfaces/IEarningPowerCalculator.sol"; +import {INotifiableRewardReceiver} from "../../src/interfaces/INotifiableRewardReceiver.sol"; +import {Staker} from "../../src/Staker.sol"; +import {StakerHarness} from "./StakerHarness.sol"; +import {IERC20Staking} from "../../src/interfaces/IERC20Staking.sol"; +import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; + +contract DeployTransferFromRewardNotifierHarness is + DeployBase, + DeployStaker, + DeployTransferFromRewardNotifier, + DeployIdentityEarningPowerCalculator +{ + address public admin = makeAddr("Staker admin"); + address public notifierOwner = makeAddr("Notifier owner"); + address public notifierRewardSource = makeAddr("Notifier reward source"); + + IERC20 rewardToken; + IERC20 stakeToken; + + constructor(IERC20 _rewardToken, IERC20 _stakeToken) { + rewardToken = _rewardToken; + stakeToken = _stakeToken; + } + + function _deployBaseConfiguration() internal virtual override returns (BaseConfiguration memory) { + return BaseConfiguration({admin: admin}); + } + + function deployTransferFromRewardNotifierConfiguration() public { + _deployTransferFromRewardNotifierConfiguration(); + } + + function _deployTransferFromRewardNotifierConfiguration() + internal + virtual + override + returns (TransferFromRewardNotifierConfiguration memory) + { + return TransferFromRewardNotifierConfiguration({ + initialRewardAmount: 10e18, + initialRewardInterval: 30 days, + initialOwner: notifierOwner, + initialRewardSource: notifierRewardSource + }); + } + + function _deployStakerConfiguration(IEarningPowerCalculator _earningPowerCalculator) + internal + virtual + override + returns (StakerConfiguration memory) + { + return StakerConfiguration({ + rewardToken: rewardToken, + stakeToken: stakeToken, + earningPowerCalculator: _earningPowerCalculator, + maxBumpTip: 1e18 + }); + } + + function _deployStaker(IEarningPowerCalculator _earningPowerCalculator) + internal + virtual + override + returns (Staker) + { + StakerConfiguration memory _config = _deployStakerConfiguration(_earningPowerCalculator); + return new StakerHarness( + _config.rewardToken, + IERC20Staking(address(_config.stakeToken)), + _config.earningPowerCalculator, + _config.maxBumpTip, + deployer, + "Harness" + ); + } +} From 950d620e9ec2588c15746ba94071c25b6e614a45 Mon Sep 17 00:00:00 2001 From: funkyenough <14842981+funkyenough@users.noreply.github.com> Date: Thu, 20 Mar 2025 22:06:32 +0900 Subject: [PATCH 10/12] Renaming file, contract, function, and fix comments 1. Rename DeployTransferFromRewardNotifierHarness to FakeDeployTranfserFromRewardNotifier 2. Rename _deployTransferFromRewardNotifierConfiguration to _transferFromRewardNotifierConfiguration 3. Fix TransferFromRewardNotifierConfiguration comments 4. Update imports --- .../notifiers/DeployTransferFromRewardNotifier.sol | 14 ++++++-------- test/DeployTransferFromRewardNotifier.t.sol | 12 +++++++----- .../FakeDeployTransferFromRewardNotifier.sol} | 8 ++++---- 3 files changed, 17 insertions(+), 17 deletions(-) rename test/{harnesses/DeployTransferFromRewardNotifierHarness.sol => fakes/FakeDeployTransferFromRewardNotifier.sol} (92%) diff --git a/src/script/notifiers/DeployTransferFromRewardNotifier.sol b/src/script/notifiers/DeployTransferFromRewardNotifier.sol index f71c0ee..c9cac0a 100644 --- a/src/script/notifiers/DeployTransferFromRewardNotifier.sol +++ b/src/script/notifiers/DeployTransferFromRewardNotifier.sol @@ -8,14 +8,12 @@ import {Staker} from "../../Staker.sol"; abstract contract DeployTransferFromRewardNotifier is DeployBase { /// @notice The configuration for the transferFrom 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 + /// @param initialRewardAmount The initial amount of reward tokens to be distributed per /// notification. - /// @param _initialRewardInterval The initial minimum time that must elapse between + /// @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. + /// @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; @@ -25,7 +23,7 @@ abstract contract DeployTransferFromRewardNotifier is DeployBase { /// @notice An interface method that returns the configuration for the transferFrom reward /// notifier. - function _deployTransferFromRewardNotifierConfiguration() + function _transferFromRewardNotifierConfiguration() internal virtual returns (TransferFromRewardNotifierConfiguration memory); @@ -36,7 +34,7 @@ abstract contract DeployTransferFromRewardNotifier is DeployBase { /// notifiers array. function _deployRewardNotifiers(Staker _staker) internal virtual override { TransferFromRewardNotifierConfiguration memory _config = - _deployTransferFromRewardNotifierConfiguration(); + _transferFromRewardNotifierConfiguration(); TransferFromRewardNotifier _notifier = new TransferFromRewardNotifier( INotifiableRewardReceiver(address(_staker)), _config.initialRewardAmount, diff --git a/test/DeployTransferFromRewardNotifier.t.sol b/test/DeployTransferFromRewardNotifier.t.sol index bc1900e..9552e67 100644 --- a/test/DeployTransferFromRewardNotifier.t.sol +++ b/test/DeployTransferFromRewardNotifier.t.sol @@ -6,15 +6,15 @@ import {Staker} from "../src/Staker.sol"; import {IEarningPowerCalculator} from "../src/interfaces/IEarningPowerCalculator.sol"; import {INotifiableRewardReceiver} from "../src/interfaces/INotifiableRewardReceiver.sol"; import {TransferFromRewardNotifier} from "../src/notifiers/TransferFromRewardNotifier.sol"; -import {DeployTransferFromRewardNotifierHarness} from - "./harnesses/DeployTransferFromRewardNotifierHarness.sol"; +import {FakeDeployTransferFromRewardNotifier} from + "./fakes/FakeDeployTransferFromRewardNotifier.sol"; import {ERC20Fake} from "./fakes/ERC20Fake.sol"; import {ERC20VotesMock} from "./mocks/MockERC20Votes.sol"; contract DeployTransferFromRewardNotifierTest is Test { ERC20Fake rewardToken; ERC20VotesMock govToken; - DeployTransferFromRewardNotifierHarness deployScript; + FakeDeployTransferFromRewardNotifier deployScript; function setUp() public { rewardToken = new ERC20Fake(); @@ -23,7 +23,7 @@ contract DeployTransferFromRewardNotifierTest is Test { govToken = new ERC20VotesMock(); vm.label(address(govToken), "Governance Token"); - deployScript = new DeployTransferFromRewardNotifierHarness(rewardToken, govToken); + deployScript = new FakeDeployTransferFromRewardNotifier(rewardToken, govToken); } } @@ -36,6 +36,8 @@ contract run is DeployTransferFromRewardNotifierTest { assertEq(10e18, _transferFromNotifier.rewardAmount()); assertEq(30 days, _transferFromNotifier.rewardInterval()); assertEq(deployScript.notifierOwner(), _transferFromNotifier.owner()); - assertEq(address(deployScript.notifierRewardSource()), address(_transferFromNotifier.rewardSource())); + assertEq( + address(deployScript.notifierRewardSource()), address(_transferFromNotifier.rewardSource()) + ); } } diff --git a/test/harnesses/DeployTransferFromRewardNotifierHarness.sol b/test/fakes/FakeDeployTransferFromRewardNotifier.sol similarity index 92% rename from test/harnesses/DeployTransferFromRewardNotifierHarness.sol rename to test/fakes/FakeDeployTransferFromRewardNotifier.sol index 1fa47f2..2de6bb5 100644 --- a/test/harnesses/DeployTransferFromRewardNotifierHarness.sol +++ b/test/fakes/FakeDeployTransferFromRewardNotifier.sol @@ -10,11 +10,11 @@ import {DeployIdentityEarningPowerCalculator} from import {IEarningPowerCalculator} from "../../src/interfaces/IEarningPowerCalculator.sol"; import {INotifiableRewardReceiver} from "../../src/interfaces/INotifiableRewardReceiver.sol"; import {Staker} from "../../src/Staker.sol"; -import {StakerHarness} from "./StakerHarness.sol"; +import {StakerHarness} from "../harnesses/StakerHarness.sol"; import {IERC20Staking} from "../../src/interfaces/IERC20Staking.sol"; import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; -contract DeployTransferFromRewardNotifierHarness is +contract FakeDeployTransferFromRewardNotifier is DeployBase, DeployStaker, DeployTransferFromRewardNotifier, @@ -37,10 +37,10 @@ contract DeployTransferFromRewardNotifierHarness is } function deployTransferFromRewardNotifierConfiguration() public { - _deployTransferFromRewardNotifierConfiguration(); + _transferFromRewardNotifierConfiguration(); } - function _deployTransferFromRewardNotifierConfiguration() + function _transferFromRewardNotifierConfiguration() internal virtual override From 37d53a0e74aabc4ecbf45ed3e94d4f9886e8c3ab Mon Sep 17 00:00:00 2001 From: funkyenough <14842981+funkyenough@users.noreply.github.com> Date: Fri, 21 Mar 2025 14:12:42 +0900 Subject: [PATCH 11/12] rename file and contract, remove unused imports and functions --- test/DeployTransferFromRewardNotifier.t.sol | 10 ++++------ ...sol => DeployTransferFromRewardNotifierFake.sol} | 13 ++++--------- 2 files changed, 8 insertions(+), 15 deletions(-) rename test/fakes/{FakeDeployTransferFromRewardNotifier.sol => DeployTransferFromRewardNotifierFake.sol} (80%) diff --git a/test/DeployTransferFromRewardNotifier.t.sol b/test/DeployTransferFromRewardNotifier.t.sol index 9552e67..ce77b82 100644 --- a/test/DeployTransferFromRewardNotifier.t.sol +++ b/test/DeployTransferFromRewardNotifier.t.sol @@ -3,18 +3,16 @@ pragma solidity ^0.8.23; import {Test} from "forge-std/Test.sol"; import {Staker} from "../src/Staker.sol"; -import {IEarningPowerCalculator} from "../src/interfaces/IEarningPowerCalculator.sol"; -import {INotifiableRewardReceiver} from "../src/interfaces/INotifiableRewardReceiver.sol"; import {TransferFromRewardNotifier} from "../src/notifiers/TransferFromRewardNotifier.sol"; -import {FakeDeployTransferFromRewardNotifier} from - "./fakes/FakeDeployTransferFromRewardNotifier.sol"; +import {DeployTransferFromRewardNotifierFake} from + "./fakes/DeployTransferFromRewardNotifierFake.sol"; import {ERC20Fake} from "./fakes/ERC20Fake.sol"; import {ERC20VotesMock} from "./mocks/MockERC20Votes.sol"; contract DeployTransferFromRewardNotifierTest is Test { ERC20Fake rewardToken; ERC20VotesMock govToken; - FakeDeployTransferFromRewardNotifier deployScript; + DeployTransferFromRewardNotifierFake deployScript; function setUp() public { rewardToken = new ERC20Fake(); @@ -23,7 +21,7 @@ contract DeployTransferFromRewardNotifierTest is Test { govToken = new ERC20VotesMock(); vm.label(address(govToken), "Governance Token"); - deployScript = new FakeDeployTransferFromRewardNotifier(rewardToken, govToken); + deployScript = new DeployTransferFromRewardNotifierFake(rewardToken, govToken); } } diff --git a/test/fakes/FakeDeployTransferFromRewardNotifier.sol b/test/fakes/DeployTransferFromRewardNotifierFake.sol similarity index 80% rename from test/fakes/FakeDeployTransferFromRewardNotifier.sol rename to test/fakes/DeployTransferFromRewardNotifierFake.sol index 2de6bb5..62afad8 100644 --- a/test/fakes/FakeDeployTransferFromRewardNotifier.sol +++ b/test/fakes/DeployTransferFromRewardNotifierFake.sol @@ -8,13 +8,12 @@ import {DeployTransferFromRewardNotifier} from import {DeployIdentityEarningPowerCalculator} from "../../src/script/calculators/DeployIdentityEarningPowerCalculator.sol"; import {IEarningPowerCalculator} from "../../src/interfaces/IEarningPowerCalculator.sol"; -import {INotifiableRewardReceiver} from "../../src/interfaces/INotifiableRewardReceiver.sol"; import {Staker} from "../../src/Staker.sol"; import {StakerHarness} from "../harnesses/StakerHarness.sol"; import {IERC20Staking} from "../../src/interfaces/IERC20Staking.sol"; import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; -contract FakeDeployTransferFromRewardNotifier is +contract DeployTransferFromRewardNotifierFake is DeployBase, DeployStaker, DeployTransferFromRewardNotifier, @@ -32,14 +31,10 @@ contract FakeDeployTransferFromRewardNotifier is stakeToken = _stakeToken; } - function _deployBaseConfiguration() internal virtual override returns (BaseConfiguration memory) { + function _baseConfiguration() internal virtual override returns (BaseConfiguration memory) { return BaseConfiguration({admin: admin}); } - function deployTransferFromRewardNotifierConfiguration() public { - _transferFromRewardNotifierConfiguration(); - } - function _transferFromRewardNotifierConfiguration() internal virtual @@ -54,7 +49,7 @@ contract FakeDeployTransferFromRewardNotifier is }); } - function _deployStakerConfiguration(IEarningPowerCalculator _earningPowerCalculator) + function _stakerConfiguration(IEarningPowerCalculator _earningPowerCalculator) internal virtual override @@ -74,7 +69,7 @@ contract FakeDeployTransferFromRewardNotifier is override returns (Staker) { - StakerConfiguration memory _config = _deployStakerConfiguration(_earningPowerCalculator); + StakerConfiguration memory _config = _stakerConfiguration(_earningPowerCalculator); return new StakerHarness( _config.rewardToken, IERC20Staking(address(_config.stakeToken)), From dcf0e5a4c31a5825a2e46efcdc587d4fc931ed33 Mon Sep 17 00:00:00 2001 From: funkyenough <14842981+funkyenough@users.noreply.github.com> Date: Fri, 21 Mar 2025 22:45:37 +0900 Subject: [PATCH 12/12] add test for set reward source --- test/DeployTransferFromRewardNotifier.t.sol | 37 +++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/test/DeployTransferFromRewardNotifier.t.sol b/test/DeployTransferFromRewardNotifier.t.sol index ce77b82..2db867e 100644 --- a/test/DeployTransferFromRewardNotifier.t.sol +++ b/test/DeployTransferFromRewardNotifier.t.sol @@ -8,6 +8,7 @@ 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; @@ -39,3 +40,39 @@ contract run is DeployTransferFromRewardNotifierTest { ); } } + +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); + } +}