From a072a547aada9bf16ebccb1307158a5acf76cc5f Mon Sep 17 00:00:00 2001 From: Roman Kolpakov Date: Fri, 9 Feb 2024 18:42:00 +0700 Subject: [PATCH 1/8] feat: remove rage quit accumulation --- contracts/Configuration.sol | 1 - contracts/Escrow.sol | 1 - contracts/GovernanceState.sol | 26 +++----------------------- 3 files changed, 3 insertions(+), 25 deletions(-) diff --git a/contracts/Configuration.sol b/contracts/Configuration.sol index 4fc4ddff..0f8a27bf 100644 --- a/contracts/Configuration.sol +++ b/contracts/Configuration.sol @@ -13,7 +13,6 @@ contract Configuration { uint256 public immutable signallingMaxDuration = 30 * DAY; uint256 public immutable signallingDeactivationDuration = 5 * DAY; uint256 public immutable signallingCooldownDuration = 4 * DAY; - uint256 public immutable rageQuitAccumulationDuration = 15 * DAY; uint256 public immutable rageQuitEthWithdrawalTimelock = 30 * DAY; constructor(address adminProposer_) { diff --git a/contracts/Escrow.sol b/contracts/Escrow.sol index 272f2126..61b05490 100644 --- a/contracts/Escrow.sol +++ b/contracts/Escrow.sol @@ -76,7 +76,6 @@ contract Escrow { error FinalizedRequest(uint256); error RequestNotFound(uint256 id); - event RageQuitAccumulationStarted(); event RageQuitStarted(); event WithdrawalsBatchRequested( uint256 indexed firstRequestId, uint256 indexed lastRequestId, uint256 wstEthLeftToRequest diff --git a/contracts/GovernanceState.sol b/contracts/GovernanceState.sol index 42f537ff..d9fd5cfb 100644 --- a/contracts/GovernanceState.sol +++ b/contracts/GovernanceState.sol @@ -17,7 +17,6 @@ contract GovernanceState { VetoSignalling, VetoSignallingDeactivation, VetoCooldown, - RageQuitAccumulation, RageQuit } @@ -91,8 +90,6 @@ contract GovernanceState { _activateNextStateFromVetoSignallingDeactivation(); } else if (state == State.VetoCooldown) { _activateNextStateFromVetoCooldown(); - } else if (state == State.RageQuitAccumulation) { - _activateNextStateFromRageQuitAccumulation(); } else if (state == State.RageQuit) { _activateNextStateFromRageQuit(); } else { @@ -178,7 +175,7 @@ contract GovernanceState { } if (rageQuitSupport >= CONFIG.secondSealThreshold()) { - _transitionVetoSignallingToRageQuitAccumulation(); + _activateRageQuit(); } else { _enterVetoSignallingDeactivationSubState(); } @@ -199,7 +196,7 @@ contract GovernanceState { if (currentSignallingDuration >= targetSignallingDuration) { if (rageQuitSupport >= CONFIG.secondSealThreshold()) { - _transitionVetoSignallingToRageQuitAccumulation(); + _activateRageQuit(); } } else if (totalSupport >= CONFIG.firstSealThreshold()) { _exitVetoSignallingDeactivationSubState(); @@ -253,27 +250,10 @@ contract GovernanceState { } } - // - // State: RageQuitAccumulation - // - function _transitionVetoSignallingToRageQuitAccumulation() internal { - _setState(State.RageQuitAccumulation); - // _signallingEscrow.startRageQuitAccumulation(); - _rageQuitEscrow = _signallingEscrow; - _deployNewSignallingEscrow(); - } - - function _activateNextStateFromRageQuitAccumulation() internal { - uint256 accumulationDuration = _getTime() - _stateEnteredAt; - if (accumulationDuration >= CONFIG.rageQuitAccumulationDuration()) { - _transitionRageQuitAccumulationToRageQuit(); - } - } - // // State: RageQuit // - function _transitionRageQuitAccumulationToRageQuit() internal { + function _activateRageQuit() internal { _setState(State.RageQuit); _rageQuitEscrow.startRageQuit(); } From 00a48181b40ef562ce85b4e3a4a908dd97a023ec Mon Sep 17 00:00:00 2001 From: Roman Kolpakov Date: Fri, 9 Feb 2024 18:52:24 +0700 Subject: [PATCH 2/8] feat: add view modifier to view functions --- contracts/GovernanceState.sol | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/contracts/GovernanceState.sol b/contracts/GovernanceState.sol index d9fd5cfb..b364b983 100644 --- a/contracts/GovernanceState.sol +++ b/contracts/GovernanceState.sol @@ -42,15 +42,15 @@ contract GovernanceState { _stateEnteredAt = _getTime(); } - function currentState() external returns (State) { + function currentState() external view returns (State) { return _state; } - function signallingEscrow() external returns (address) { + function signallingEscrow() external view returns (address) { return address(_signallingEscrow); } - function rageQuitEscrow() external returns (address) { + function rageQuitEscrow() external view returns (address) { return address(_rageQuitEscrow); } From 9a99f9338c4a0fa5e071c421d3aad6fce33c6c15 Mon Sep 17 00:00:00 2001 From: Roman Kolpakov Date: Fri, 9 Feb 2024 19:13:58 +0700 Subject: [PATCH 3/8] feat: state from rage quit --- contracts/GovernanceState.sol | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/contracts/GovernanceState.sol b/contracts/GovernanceState.sol index b364b983..24e20d5a 100644 --- a/contracts/GovernanceState.sol +++ b/contracts/GovernanceState.sol @@ -262,11 +262,8 @@ contract GovernanceState { if (!_rageQuitEscrow.isRageQuitFinalized()) { return; } - if (_isFirstThresholdReached()) { - _transitionRageQuitToVetoSignalling(); - } else { - _transitionRageQuitToNormal(); - } + _deployNewSignallingEscrow(); + _transitionRageQuitToNormal(); } // From 5d406d559780439d0b11a053db92257ded3a3f7c Mon Sep 17 00:00:00 2001 From: Roman Kolpakov Date: Tue, 13 Feb 2024 12:06:46 +0700 Subject: [PATCH 4/8] feat: gov state improvements --- contracts/Configuration.sol | 15 +++- contracts/DualGovernance.sol | 4 - contracts/GovernanceState.sol | 29 ++++--- test/scenario/gov-state-transitions.t.sol | 97 +++++++++++++++++++++++ test/utils/utils.sol | 2 +- 5 files changed, 123 insertions(+), 24 deletions(-) create mode 100644 test/scenario/gov-state-transitions.t.sol diff --git a/contracts/Configuration.sol b/contracts/Configuration.sol index 0f8a27bf..8a2ec534 100644 --- a/contracts/Configuration.sol +++ b/contracts/Configuration.sol @@ -6,16 +6,23 @@ contract Configuration { uint256 internal constant PERCENT = 10 ** 16; address public immutable adminProposer; + uint256 public immutable minProposalExecutionTimelock = 3 * DAY; - uint256 public immutable firstSealThreshold = 3 * PERCENT; - uint256 public immutable secondSealThreshold = 15 * PERCENT; - uint256 public immutable signallingMinDuration = 3 * DAY; - uint256 public immutable signallingMaxDuration = 30 * DAY; + uint256 public immutable signallingDeactivationDuration = 5 * DAY; uint256 public immutable signallingCooldownDuration = 4 * DAY; uint256 public immutable rageQuitEthWithdrawalTimelock = 30 * DAY; + uint256 public immutable firstSealThreshold = 3 * PERCENT; + uint256 public immutable secondSealThreshold = 15 * PERCENT; + uint256 public immutable signallingMinDuration = 3 days; + uint256 public immutable signallingMaxDuration = 30 days; + constructor(address adminProposer_) { adminProposer = adminProposer_; } + + function getSignallingThresholdData() external view returns (uint256, uint256, uint256, uint256) { + return (firstSealThreshold, secondSealThreshold, signallingMinDuration, signallingMaxDuration); + } } diff --git a/contracts/DualGovernance.sol b/contracts/DualGovernance.sol index 29ae253b..1ed1bf7b 100644 --- a/contracts/DualGovernance.sol +++ b/contracts/DualGovernance.sol @@ -47,10 +47,6 @@ contract DualGovernance { return GOV_STATE.signallingEscrow(); } - function rageQuitEscrow() external returns (address) { - return GOV_STATE.rageQuitEscrow(); - } - function currentState() external returns (GovernanceState.State) { return GOV_STATE.currentState(); } diff --git a/contracts/GovernanceState.sol b/contracts/GovernanceState.sol index 24e20d5a..c50cc5c1 100644 --- a/contracts/GovernanceState.sol +++ b/contracts/GovernanceState.sol @@ -6,6 +6,12 @@ import {Clones} from "@openzeppelin/contracts/proxy/Clones.sol"; import {Configuration} from "./Configuration.sol"; import {Escrow} from "./Escrow.sol"; +import "forge-std/console.sol"; + +interface IERC20 { + function totalSupply() external view returns (uint256); +} + contract GovernanceState { error Unauthorized(); @@ -26,7 +32,6 @@ contract GovernanceState { uint256 internal _escrowIndex; Escrow internal _signallingEscrow; - Escrow internal _rageQuitEscrow; State internal _state; uint256 internal _stateEnteredAt; @@ -34,6 +39,8 @@ contract GovernanceState { uint256 internal _proposalsKilledUntil; + uint16 internal constant MAX_BASIS_POINTS = 10_000; + constructor(address config, address governance, address escrowImpl) { CONFIG = Configuration(config); GOVERNANCE = governance; @@ -50,10 +57,6 @@ contract GovernanceState { return address(_signallingEscrow); } - function rageQuitEscrow() external view returns (address) { - return address(_rageQuitEscrow); - } - function killAllPendingProposals() external { if (msg.sender != GOVERNANCE) { revert Unauthorized(); @@ -203,23 +206,19 @@ contract GovernanceState { } } - function _calcVetoSignallingTargetDuration(uint256 totalSupport) internal view returns (uint256) { - uint256 firstSealThreshold = CONFIG.firstSealThreshold(); - uint256 secondSealThreshold = CONFIG.secondSealThreshold(); + function _calcVetoSignallingTargetDuration(uint256 totalSupport) internal view returns (uint256 duration) { + (uint256 firstSealThreshold, uint256 secondSealThreshold, uint256 minDuration, uint256 maxDuration) = + CONFIG.getSignallingThresholdData(); if (totalSupport < firstSealThreshold) { return 0; } - uint256 maxDuration = CONFIG.signallingMaxDuration(); - if (totalSupport >= secondSealThreshold) { return maxDuration; } - uint256 minDuration = CONFIG.signallingMinDuration(); - - return minDuration + duration = minDuration + (totalSupport - firstSealThreshold) * (maxDuration - minDuration) / (secondSealThreshold - firstSealThreshold); } @@ -255,11 +254,11 @@ contract GovernanceState { // function _activateRageQuit() internal { _setState(State.RageQuit); - _rageQuitEscrow.startRageQuit(); + _signallingEscrow.startRageQuit(); } function _activateNextStateFromRageQuit() internal { - if (!_rageQuitEscrow.isRageQuitFinalized()) { + if (!_signallingEscrow.isRageQuitFinalized()) { return; } _deployNewSignallingEscrow(); diff --git a/test/scenario/gov-state-transitions.t.sol b/test/scenario/gov-state-transitions.t.sol new file mode 100644 index 00000000..240513bf --- /dev/null +++ b/test/scenario/gov-state-transitions.t.sol @@ -0,0 +1,97 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.23; + +import "forge-std/Test.sol"; + +import {DualGovernance} from "contracts/DualGovernance.sol"; +import {Escrow} from "contracts/Escrow.sol"; + +import {DualGovernanceSetup} from "./setup.sol"; +import {DualGovernanceUtils} from "./happy-path.t.sol"; +import "../utils/utils.sol"; + +contract GovernanceStateTransitions is DualGovernanceSetup { + DualGovernance internal dualGov; + + address internal ldoWhale; + address internal stEthWhale; + + function setUp() external { + Utils.selectFork(); + Utils.removeLidoStakingLimit(); + + ldoWhale = makeAddr("ldo_whale"); + Utils.setupLdoWhale(ldoWhale); + + stEthWhale = makeAddr("steth_whale"); + Utils.setupStEthWhale(stEthWhale); + + uint256 timelockDuration = 0; + address timelockEmergencyMultisig = address(0); + uint256 timelockEmergencyMultisigActiveFor = 0; + + DualGovernanceSetup.Deployed memory deployed = deployDG( + ST_ETH, + WST_ETH, + WITHDRAWAL_QUEUE, + BURNER, + timelockDuration, + timelockEmergencyMultisig, + timelockEmergencyMultisigActiveFor + ); + + dualGov = deployed.dualGov; + } + + function test_normal_to_signalling_transition() public { + assertEq(dualGov.currentState(), GovernanceState.State.Normal); + + updateVetoSupportInBps(300); + updateVetoSupport(1); + + assertEq(dualGov.currentState(), GovernanceState.State.VetoSignalling); + + + uint256 minProposalExecutionTimelock = dualGov.CONFIG().signallingMinDuration(); + + vm.warp(block.timestamp + (minProposalExecutionTimelock / 2)); + updateVetoSupport(1); + + assertEq(dualGov.currentState(), GovernanceState.State.VetoSignalling); + + // vm.warp(block.timestamp + minProposalExecutionTimelock / 2); + // updateVetoSupport(1); + + // assertEq(dualGov.currentState(), GovernanceState.State.VetoSignallingDeactivation); + } + + function updateVetoSupportInBps(uint256 supportInBps) internal { + Escrow signallingEscrow = Escrow(dualGov.signallingEscrow()); + + uint256 newVetoSupport = (supportInBps * IERC20(ST_ETH).totalSupply()) / 10_000; + (uint256 currentVetoSupport,) = signallingEscrow.getSignallingState(); + + if (newVetoSupport > currentVetoSupport) { + updateVetoSupport(newVetoSupport - currentVetoSupport); + } else if (newVetoSupport < currentVetoSupport) { + vm.prank(stEthWhale); + signallingEscrow.unlockStEth(); + updateVetoSupport(newVetoSupport); + } + + vm.stopPrank(); + + (uint256 totalSupport, uint256 rageQuitSupport) = signallingEscrow.getSignallingState(); + // solhint-disable-next-line + console.log("veto totalSupport %d, rageQuitSupport %d", totalSupport, rageQuitSupport); + } + + function updateVetoSupport(uint256 amount) internal { + Escrow signallingEscrow = Escrow(dualGov.signallingEscrow()); + vm.startPrank(stEthWhale); + IERC20(ST_ETH).approve(address(signallingEscrow), amount); + console.log('steth locked:', amount); + signallingEscrow.lockStEth(amount); + vm.stopPrank(); + } +} diff --git a/test/utils/utils.sol b/test/utils/utils.sol index 4e413f7f..25bc3dcc 100644 --- a/test/utils/utils.sol +++ b/test/utils/utils.sol @@ -93,7 +93,7 @@ library Utils { function setupStEthWhale(address addr) internal { // 15% of total stETH supply - setupStEthWhale(addr, 15 * 10 ** 16); + setupStEthWhale(addr, 30 * 10 ** 16); } function setupStEthWhale(address addr, uint256 totalSupplyPercentage) internal { From 61d046e2a6495476ac8358ca9fe88c96431d9d79 Mon Sep 17 00:00:00 2001 From: Roman Kolpakov Date: Tue, 13 Feb 2024 16:40:54 +0700 Subject: [PATCH 5/8] feat: veto signalling test --- test/scenario/gov-state-transitions.t.sol | 52 ++++++++++++++--------- 1 file changed, 33 insertions(+), 19 deletions(-) diff --git a/test/scenario/gov-state-transitions.t.sol b/test/scenario/gov-state-transitions.t.sol index 240513bf..93047d6e 100644 --- a/test/scenario/gov-state-transitions.t.sol +++ b/test/scenario/gov-state-transitions.t.sol @@ -2,6 +2,7 @@ pragma solidity 0.8.23; import "forge-std/Test.sol"; +import "forge-std/console.sol"; import {DualGovernance} from "contracts/DualGovernance.sol"; import {Escrow} from "contracts/Escrow.sol"; @@ -35,6 +36,7 @@ contract GovernanceStateTransitions is DualGovernanceSetup { WST_ETH, WITHDRAWAL_QUEUE, BURNER, + DAO_VOTING, timelockDuration, timelockEmergencyMultisig, timelockEmergencyMultisigActiveFor @@ -43,42 +45,55 @@ contract GovernanceStateTransitions is DualGovernanceSetup { dualGov = deployed.dualGov; } - function test_normal_to_signalling_transition() public { + function test_signalling_state_min_duration() public { assertEq(dualGov.currentState(), GovernanceState.State.Normal); - updateVetoSupportInBps(300); + updateVetoSupportInPercent(3 * 10 ** 16); updateVetoSupport(1); assertEq(dualGov.currentState(), GovernanceState.State.VetoSignalling); + uint256 signallingDuration = dualGov.CONFIG().signallingMinDuration(); - uint256 minProposalExecutionTimelock = dualGov.CONFIG().signallingMinDuration(); + vm.warp(block.timestamp + (signallingDuration / 2)); + updateVetoSupport(1); + + assertEq(dualGov.currentState(), GovernanceState.State.VetoSignalling); - vm.warp(block.timestamp + (minProposalExecutionTimelock / 2)); + vm.warp(block.timestamp + signallingDuration / 2); updateVetoSupport(1); + assertEq(dualGov.currentState(), GovernanceState.State.VetoSignallingDeactivation); + } + + function test_signalling_state_max_duration() public { + assertEq(dualGov.currentState(), GovernanceState.State.Normal); + + updateVetoSupportInPercent(15 * 10 ** 16 + 1); + + assertEq(dualGov.currentState(), GovernanceState.State.VetoSignalling); + + uint256 signallingDuration = dualGov.CONFIG().signallingMaxDuration(); + + vm.warp(block.timestamp + (signallingDuration / 2)); + dualGov.activateNextState(); + assertEq(dualGov.currentState(), GovernanceState.State.VetoSignalling); - // vm.warp(block.timestamp + minProposalExecutionTimelock / 2); - // updateVetoSupport(1); + vm.warp(block.timestamp + signallingDuration / 2 + 1000); + dualGov.activateNextState(); - // assertEq(dualGov.currentState(), GovernanceState.State.VetoSignallingDeactivation); + assertEq(dualGov.currentState(), GovernanceState.State.RageQuit); } - function updateVetoSupportInBps(uint256 supportInBps) internal { + function updateVetoSupportInPercent(uint256 supportInPercent) internal { Escrow signallingEscrow = Escrow(dualGov.signallingEscrow()); + uint256 newVetoSupport = (supportInPercent * IERC20(ST_ETH).totalSupply()) / 10 ** 18; - uint256 newVetoSupport = (supportInBps * IERC20(ST_ETH).totalSupply()) / 10_000; - (uint256 currentVetoSupport,) = signallingEscrow.getSignallingState(); - - if (newVetoSupport > currentVetoSupport) { - updateVetoSupport(newVetoSupport - currentVetoSupport); - } else if (newVetoSupport < currentVetoSupport) { - vm.prank(stEthWhale); - signallingEscrow.unlockStEth(); - updateVetoSupport(newVetoSupport); - } + vm.prank(stEthWhale); + // signallingEscrow.unlockStEth(); + updateVetoSupport(newVetoSupport); vm.stopPrank(); (uint256 totalSupport, uint256 rageQuitSupport) = signallingEscrow.getSignallingState(); @@ -90,7 +105,6 @@ contract GovernanceStateTransitions is DualGovernanceSetup { Escrow signallingEscrow = Escrow(dualGov.signallingEscrow()); vm.startPrank(stEthWhale); IERC20(ST_ETH).approve(address(signallingEscrow), amount); - console.log('steth locked:', amount); signallingEscrow.lockStEth(amount); vm.stopPrank(); } From 31f148707410d6e10a7e0ab6570375a8f05a0cc8 Mon Sep 17 00:00:00 2001 From: Roman Kolpakov Date: Tue, 13 Feb 2024 18:12:20 +0700 Subject: [PATCH 6/8] fix: escrow behaviour fix --- contracts/DualGovernance.sol | 4 ++++ contracts/GovernanceState.sol | 19 +++++++++++++++---- 2 files changed, 19 insertions(+), 4 deletions(-) diff --git a/contracts/DualGovernance.sol b/contracts/DualGovernance.sol index 1ed1bf7b..29ae253b 100644 --- a/contracts/DualGovernance.sol +++ b/contracts/DualGovernance.sol @@ -47,6 +47,10 @@ contract DualGovernance { return GOV_STATE.signallingEscrow(); } + function rageQuitEscrow() external returns (address) { + return GOV_STATE.rageQuitEscrow(); + } + function currentState() external returns (GovernanceState.State) { return GOV_STATE.currentState(); } diff --git a/contracts/GovernanceState.sol b/contracts/GovernanceState.sol index 7150663f..f582b06f 100644 --- a/contracts/GovernanceState.sol +++ b/contracts/GovernanceState.sol @@ -32,6 +32,7 @@ contract GovernanceState { uint256 internal _escrowIndex; Escrow internal _signallingEscrow; + Escrow internal _rageQuitEscrow; State internal _state; uint256 internal _stateEnteredAt; @@ -57,6 +58,10 @@ contract GovernanceState { return address(_signallingEscrow); } + function rageQuitEscrow() external view returns (address) { + return address(_rageQuitEscrow); + } + function killAllPendingProposals() external { if (msg.sender != GOVERNANCE) { revert Unauthorized(); @@ -254,15 +259,21 @@ contract GovernanceState { // function _activateRageQuit() internal { _setState(State.RageQuit); - _signallingEscrow.startRageQuit(); + _rageQuitEscrow = _signallingEscrow; + _rageQuitEscrow.startRageQuit(); + _deployNewSignallingEscrow(); } function _activateNextStateFromRageQuit() internal { - if (!_signallingEscrow.isRageQuitFinalized()) { + if (!_rageQuitEscrow.isRageQuitFinalized()) { return; } - _deployNewSignallingEscrow(); - _transitionRageQuitToNormal(); + + if (_isFirstThresholdReached()) { + _transitionRageQuitToVetoSignalling(); + } else { + _transitionRageQuitToNormal(); + } } // From 53cbe8f44a97bf08123e498de585cc3abe0bcfd1 Mon Sep 17 00:00:00 2001 From: Roman Kolpakov Date: Wed, 14 Feb 2024 15:51:45 +0700 Subject: [PATCH 7/8] fix: test fix --- test/scenario/gov-state-transitions.t.sol | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/scenario/gov-state-transitions.t.sol b/test/scenario/gov-state-transitions.t.sol index 93047d6e..37047a23 100644 --- a/test/scenario/gov-state-transitions.t.sol +++ b/test/scenario/gov-state-transitions.t.sol @@ -69,7 +69,7 @@ contract GovernanceStateTransitions is DualGovernanceSetup { function test_signalling_state_max_duration() public { assertEq(dualGov.currentState(), GovernanceState.State.Normal); - updateVetoSupportInPercent(15 * 10 ** 16 + 1); + updateVetoSupportInPercent(15 * 10 ** 16); assertEq(dualGov.currentState(), GovernanceState.State.VetoSignalling); @@ -87,7 +87,7 @@ contract GovernanceStateTransitions is DualGovernanceSetup { } function updateVetoSupportInPercent(uint256 supportInPercent) internal { - Escrow signallingEscrow = Escrow(dualGov.signallingEscrow()); + Escrow signallingEscrow = Escrow(payable(dualGov.signallingEscrow())); uint256 newVetoSupport = (supportInPercent * IERC20(ST_ETH).totalSupply()) / 10 ** 18; vm.prank(stEthWhale); @@ -102,7 +102,7 @@ contract GovernanceStateTransitions is DualGovernanceSetup { } function updateVetoSupport(uint256 amount) internal { - Escrow signallingEscrow = Escrow(dualGov.signallingEscrow()); + Escrow signallingEscrow = Escrow(payable(dualGov.signallingEscrow())); vm.startPrank(stEthWhale); IERC20(ST_ETH).approve(address(signallingEscrow), amount); signallingEscrow.lockStEth(amount); From 14c79c3225b53746a010270df8c697b1afe07d76 Mon Sep 17 00:00:00 2001 From: Roman Kolpakov Date: Wed, 14 Feb 2024 17:18:25 +0700 Subject: [PATCH 8/8] feat: test improvements --- test/scenario/gov-state-transitions.t.sol | 81 ++++++++++++++++++++++- 1 file changed, 80 insertions(+), 1 deletion(-) diff --git a/test/scenario/gov-state-transitions.t.sol b/test/scenario/gov-state-transitions.t.sol index 37047a23..34e28529 100644 --- a/test/scenario/gov-state-transitions.t.sol +++ b/test/scenario/gov-state-transitions.t.sol @@ -9,9 +9,10 @@ import {Escrow} from "contracts/Escrow.sol"; import {DualGovernanceSetup} from "./setup.sol"; import {DualGovernanceUtils} from "./happy-path.t.sol"; +import {TestHelpers} from './escrow.t.sol'; import "../utils/utils.sol"; -contract GovernanceStateTransitions is DualGovernanceSetup { +contract GovernanceStateTransitions is TestHelpers { DualGovernance internal dualGov; address internal ldoWhale; @@ -86,6 +87,84 @@ contract GovernanceStateTransitions is DualGovernanceSetup { assertEq(dualGov.currentState(), GovernanceState.State.RageQuit); } + function test_signalling_to_normal() public { + assertEq(dualGov.currentState(), GovernanceState.State.Normal); + + updateVetoSupportInPercent(3 * 10 ** 16 + 1); + + assertEq(dualGov.currentState(), GovernanceState.State.VetoSignalling); + + uint256 signallingDuration = dualGov.CONFIG().signallingMinDuration(); + + vm.warp(block.timestamp + signallingDuration); + dualGov.activateNextState(); + + assertEq(dualGov.currentState(), GovernanceState.State.VetoSignallingDeactivation); + + uint256 signallingDeactivationDuration = dualGov.CONFIG().signallingDeactivationDuration(); + + vm.warp(block.timestamp + signallingDeactivationDuration); + dualGov.activateNextState(); + + assertEq(dualGov.currentState(), GovernanceState.State.VetoCooldown); + + uint256 signallingCooldownDuration = dualGov.CONFIG().signallingCooldownDuration(); + + Escrow signallingEscrow = Escrow(payable(dualGov.signallingEscrow())); + vm.prank(stEthWhale); + signallingEscrow.unlockStEth(); + + vm.warp(block.timestamp + signallingCooldownDuration); + dualGov.activateNextState(); + + assertEq(dualGov.currentState(), GovernanceState.State.Normal); + } + + function test_signalling_non_stop() public { + assertEq(dualGov.currentState(), GovernanceState.State.Normal); + + updateVetoSupportInPercent(3 * 10 ** 16 + 1); + + assertEq(dualGov.currentState(), GovernanceState.State.VetoSignalling); + + uint256 signallingDuration = dualGov.CONFIG().signallingMinDuration(); + + vm.warp(block.timestamp + signallingDuration); + dualGov.activateNextState(); + + assertEq(dualGov.currentState(), GovernanceState.State.VetoSignallingDeactivation); + + uint256 signallingDeactivationDuration = dualGov.CONFIG().signallingDeactivationDuration(); + + vm.warp(block.timestamp + signallingDeactivationDuration); + dualGov.activateNextState(); + + assertEq(dualGov.currentState(), GovernanceState.State.VetoCooldown); + + uint256 signallingCooldownDuration = dualGov.CONFIG().signallingCooldownDuration(); + + vm.warp(block.timestamp + signallingCooldownDuration); + dualGov.activateNextState(); + + assertEq(dualGov.currentState(), GovernanceState.State.VetoSignalling); + } + + function test_signalling_to_rage_quit() public { + assertEq(dualGov.currentState(), GovernanceState.State.Normal); + + updateVetoSupportInPercent(15 * 10 ** 16); + + assertEq(dualGov.currentState(), GovernanceState.State.VetoSignalling); + + uint256 signallingDuration = dualGov.CONFIG().signallingMaxDuration(); + + vm.warp(block.timestamp + signallingDuration); + dualGov.activateNextState(); + + assertEq(dualGov.currentState(), GovernanceState.State.RageQuit); + } + + function updateVetoSupportInPercent(uint256 supportInPercent) internal { Escrow signallingEscrow = Escrow(payable(dualGov.signallingEscrow())); uint256 newVetoSupport = (supportInPercent * IERC20(ST_ETH).totalSupply()) / 10 ** 18;