From 310eaf6ea54bf30bbe938ff6a9aecef41d1dc079 Mon Sep 17 00:00:00 2001 From: "Eugene Y. Q. Shen" Date: Sat, 9 Nov 2024 20:15:46 -0500 Subject: [PATCH] [PDE-14] update staking tests with 100% test coverage --- staking/script/DeployStakingContracts.s.sol | 4 +- staking/test/RWAStaking.t.sol | 49 ++++++++++++++++++--- staking/test/ReserveStaking.t.sol | 38 +++++++++++++++- 3 files changed, 82 insertions(+), 9 deletions(-) diff --git a/staking/script/DeployStakingContracts.s.sol b/staking/script/DeployStakingContracts.s.sol index 4149101..7f38838 100644 --- a/staking/script/DeployStakingContracts.s.sol +++ b/staking/script/DeployStakingContracts.s.sol @@ -35,7 +35,7 @@ contract DeployStakingContracts is Script { RWAStaking rwaStaking = new RWAStaking(); PlumePreStaking plumePreStaking = new PlumePreStaking( - address(rwaStaking), abi.encodeCall(RWAStaking.initialize, (timelock, DEPLOYER_ADDRESS)) + address(rwaStaking), abi.encodeCall(RWAStaking.initialize, (timelock, MULTISIG_ADDRESS)) ); RWAStaking(address(plumePreStaking)).allowStablecoin(IERC20(USDC_ADDRESS)); RWAStaking(address(plumePreStaking)).allowStablecoin(IERC20(USDT_ADDRESS)); @@ -45,7 +45,7 @@ contract DeployStakingContracts is Script { PlumePreReserveFund plumePreReserveFund = new PlumePreReserveFund( address(sbtcStaking), abi.encodeCall( - ReserveStaking.initialize, (timelock, DEPLOYER_ADDRESS, IERC20(SBTC_ADDRESS), IERC20(STONE_ADDRESS)) + ReserveStaking.initialize, (timelock, MULTISIG_ADDRESS, IERC20(SBTC_ADDRESS), IERC20(STONE_ADDRESS)) ) ); console2.log("Plume Pre-Reserve Fund Proxy deployed to:", address(plumePreReserveFund)); diff --git a/staking/test/RWAStaking.t.sol b/staking/test/RWAStaking.t.sol index 3cd135c..e45c968 100644 --- a/staking/test/RWAStaking.t.sol +++ b/staking/test/RWAStaking.t.sol @@ -6,7 +6,6 @@ import { IAccessControl } from "@openzeppelin/contracts/access/IAccessControl.so import { TimelockController } from "@openzeppelin/contracts/governance/TimelockController.sol"; import { IERC20Errors } from "@openzeppelin/contracts/interfaces/draft-IERC6093.sol"; import { ERC1967Proxy } from "@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol"; - import { ERC20 } from "@openzeppelin/contracts/token/ERC20/ERC20.sol"; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import { Test } from "forge-std/Test.sol"; @@ -17,8 +16,7 @@ import { PlumePreStaking } from "../src/proxy/PlumePreStaking.sol"; contract MockPlumePreStaking is PlumePreStaking { constructor(address logic, bytes memory data) PlumePreStaking(logic, data) { } - - function test() public { } + function test() public override { } function exposed_implementation() public view returns (address) { return _implementation(); @@ -67,6 +65,8 @@ contract RWAStakingTest is Test { uint256 constant INITIAL_BALANCE = 1000 ether; function setUp() public { + vm.startPrank(owner); + MockERC20 usdcMock = new MockERC20(18); usdcMock.mint(user1, INITIAL_BALANCE); usdcMock.mint(user2, INITIAL_BALANCE); @@ -77,6 +77,8 @@ contract RWAStakingTest is Test { pusdMock.mint(user2, INITIAL_BALANCE); pusd = IERC20(pusdMock); + vm.stopPrank(); + address[] memory proposers = new address[](1); address[] memory executors = new address[](1); proposers[0] = owner; @@ -95,14 +97,18 @@ contract RWAStakingTest is Test { function helper_initialStake(address user, uint256 stakeAmount) public { vm.startPrank(owner); + rwaStaking.allowStablecoin(usdc); + vm.stopPrank(); vm.startPrank(user); + usdc.approve(address(rwaStaking), stakeAmount); vm.expectEmit(true, true, false, true, address(rwaStaking)); emit RWAStaking.Staked(user, usdc, stakeAmount); rwaStaking.stake(stakeAmount, usdc); + vm.stopPrank(); assertEq(usdc.balanceOf(address(rwaStaking)), stakeAmount); @@ -146,6 +152,39 @@ contract RWAStakingTest is Test { assertEq(pusd.balanceOf(user2), INITIAL_BALANCE); } + function test_reinitializeFail() public { + vm.startPrank(user1); + + vm.expectRevert( + abi.encodeWithSelector( + IAccessControl.AccessControlUnauthorizedAccount.selector, user1, rwaStaking.ADMIN_ROLE() + ) + ); + rwaStaking.reinitialize(user1, timelock); + + vm.stopPrank(); + + vm.startPrank(owner); + + rwaStaking.reinitialize(owner, timelock); + vm.expectRevert(abi.encodeWithSelector(Initializable.InvalidInitialization.selector)); + rwaStaking.reinitialize(user1, timelock); + + vm.stopPrank(); + } + + function test_reinitialize() public { + vm.startPrank(owner); + + assertEq(rwaStaking.getMultisig(), owner); + assertEq(address(rwaStaking.getTimelock()), address(timelock)); + rwaStaking.reinitialize(user1, TimelockController(payable(user2))); + assertEq(rwaStaking.getMultisig(), user1); + assertEq(address(rwaStaking.getTimelock()), address(user2)); + + vm.stopPrank(); + } + function test_stakingEnded() public { vm.startPrank(address(timelock)); rwaStaking.adminWithdraw(); @@ -201,11 +240,11 @@ contract RWAStakingTest is Test { IERC20 tooManyDecimalsToken = IERC20(tooManyDecimalsMock); vm.startPrank(owner); - + // Attempt to allow the token with too many decimals vm.expectRevert(abi.encodeWithSelector(RWAStaking.TooManyDecimals.selector)); rwaStaking.allowStablecoin(tooManyDecimalsToken); - + vm.stopPrank(); // Verify the token was not added diff --git a/staking/test/ReserveStaking.t.sol b/staking/test/ReserveStaking.t.sol index 4926f85..12bd40c 100644 --- a/staking/test/ReserveStaking.t.sol +++ b/staking/test/ReserveStaking.t.sol @@ -3,7 +3,6 @@ pragma solidity ^0.8.25; import { Initializable } from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; import { IAccessControl } from "@openzeppelin/contracts/access/IAccessControl.sol"; - import { TimelockController } from "@openzeppelin/contracts/governance/TimelockController.sol"; import { IERC20Errors } from "@openzeppelin/contracts/interfaces/draft-IERC6093.sol"; import { ERC20Mock } from "@openzeppelin/contracts/mocks/token/ERC20Mock.sol"; @@ -19,7 +18,7 @@ import { PlumePreReserveFund } from "../src/proxy/PlumePreReserveFund.sol"; contract MockPlumePreReserveFund is PlumePreReserveFund { constructor(address logic, bytes memory data) PlumePreReserveFund(logic, data) { } - function test() public { } + function test() public override { } function exposed_implementation() public view returns (address) { return _implementation(); @@ -73,11 +72,13 @@ contract ReserveStakingTest is Test { function helper_initialStake(address user, uint256 sbtcAmount, uint256 stoneAmount) public { vm.startPrank(user); + sbtc.approve(address(staking), sbtcAmount); stone.approve(address(staking), stoneAmount); vm.expectEmit(true, false, false, true, address(staking)); emit ReserveStaking.Staked(user, sbtcAmount, stoneAmount); staking.stake(sbtcAmount, stoneAmount); + vm.stopPrank(); assertEq(sbtc.balanceOf(address(staking)), sbtcAmount); @@ -146,6 +147,39 @@ contract ReserveStakingTest is Test { assertEq(stone.balanceOf(user2), INITIAL_BALANCE); } + function test_reinitializeFail() public { + vm.startPrank(user1); + + vm.expectRevert( + abi.encodeWithSelector( + IAccessControl.AccessControlUnauthorizedAccount.selector, user1, staking.ADMIN_ROLE() + ) + ); + staking.reinitialize(user1, timelock); + + vm.stopPrank(); + + vm.startPrank(owner); + + staking.reinitialize(owner, timelock); + vm.expectRevert(abi.encodeWithSelector(Initializable.InvalidInitialization.selector)); + staking.reinitialize(user1, timelock); + + vm.stopPrank(); + } + + function test_reinitialize() public { + vm.startPrank(owner); + + assertEq(staking.getMultisig(), owner); + assertEq(address(staking.getTimelock()), address(timelock)); + staking.reinitialize(user1, TimelockController(payable(user2))); + assertEq(staking.getMultisig(), user1); + assertEq(address(staking.getTimelock()), address(user2)); + + vm.stopPrank(); + } + function test_stakingEnded() public { vm.startPrank(address(timelock)); staking.adminWithdraw();