@@ -5,8 +5,11 @@ pragma abicoder v2;
5
5
import "@openzeppelin/contracts/math/SafeMath.sol " ;
6
6
7
7
import "../RocketBase.sol " ;
8
- import "./RocketMinipoolDelegate .sol " ;
8
+ import "../../interface/minipool/RocketMinipoolInterface .sol " ;
9
9
import "../../interface/minipool/RocketMinipoolBondReducerInterface.sol " ;
10
+ import "../../interface/node/RocketNodeDepositInterface.sol " ;
11
+ import "../../interface/dao/node/settings/RocketDAONodeTrustedSettingsMinipoolInterface.sol " ;
12
+ import "../../interface/dao/node/RocketDAONodeTrustedInterface.sol " ;
10
13
11
14
/// @notice Handles bond reduction window and trusted node cancellation
12
15
contract RocketMinipoolBondReducer is RocketBase , RocketMinipoolBondReducerInterface {
@@ -15,7 +18,7 @@ contract RocketMinipoolBondReducer is RocketBase, RocketMinipoolBondReducerInter
15
18
using SafeMath for uint ;
16
19
17
20
// Events
18
- event BeginBondReduction (address indexed minipool , uint256 time );
21
+ event BeginBondReduction (address indexed minipool , uint256 newBondAmount , uint256 time );
19
22
event CancelReductionVoted (address indexed minipool , address indexed member , uint256 time );
20
23
event ReductionCancelled (address indexed minipool , uint256 time );
21
24
@@ -26,21 +29,47 @@ contract RocketMinipoolBondReducer is RocketBase, RocketMinipoolBondReducerInter
26
29
/// @notice Flags a minipool as wanting to reduce collateral, owner can then call `reduceBondAmount` once waiting
27
30
/// period has elapsed
28
31
/// @param _minipoolAddress Address of the minipool
29
- function beginReduceBondAmount (address _minipoolAddress ) override external onlyLatestContract ("rocketMinipoolBondReducer " , address (this )) {
30
- RocketMinipoolDelegate minipool = RocketMinipoolDelegate (_minipoolAddress);
32
+ /// @param _newBondAmount The new bond amount
33
+ function beginReduceBondAmount (address _minipoolAddress , uint256 _newBondAmount ) override external onlyLatestContract ("rocketMinipoolBondReducer " , address (this )) {
34
+ RocketMinipoolInterface minipool = RocketMinipoolInterface (_minipoolAddress);
35
+ RocketNodeDepositInterface rocketNodeDeposit = RocketNodeDepositInterface (getContractAddress ("rocketNodeDeposit " ));
31
36
require (msg .sender == minipool.getNodeAddress (), "Only minipool owner " );
32
37
// Check if has been previously cancelled
33
38
bool reductionCancelled = getBool (keccak256 (abi.encodePacked ("minipool.bond.reduction.cancelled " , address (minipool))));
34
39
require (! reductionCancelled, "This minipool is not allowed to reduce bond " );
35
40
require (minipool.getStatus () == MinipoolStatus.Staking, "Minipool must be staking " );
41
+ // Check if new bond amount is valid
42
+ require (rocketNodeDeposit.isValidDepositAmount (_newBondAmount), "Invalid bond amount " );
43
+ uint256 existing = minipool.getNodeDepositBalance ();
44
+ require (_newBondAmount < existing, "Bond must be lower than current amount " );
45
+ // Store time and new bond amount
36
46
setUint (keccak256 (abi.encodePacked ("minipool.bond.reduction.time " , _minipoolAddress)), block .timestamp );
37
- emit BeginBondReduction (_minipoolAddress, block .timestamp );
47
+ setUint (keccak256 (abi.encodePacked ("minipool.bond.reduction.value " , _minipoolAddress)), _newBondAmount);
48
+ emit BeginBondReduction (_minipoolAddress, _newBondAmount, block .timestamp );
49
+ }
50
+
51
+ /// @notice Returns the timestamp of when a given minipool began their bond reduction waiting period
52
+ /// @param _minipoolAddress Address of the minipool to query
53
+ function getReduceBondTime (address _minipoolAddress ) override external view returns (uint256 ) {
54
+ return getUint (keccak256 (abi.encodePacked ("minipool.bond.reduction.time " , _minipoolAddress)));
55
+ }
56
+
57
+ /// @notice Returns the new bond that a given minipool has indicated they are reducing to
58
+ /// @param _minipoolAddress Address of the minipool to query
59
+ function getReduceBondValue (address _minipoolAddress ) override external view returns (uint256 ) {
60
+ return getUint (keccak256 (abi.encodePacked ("minipool.bond.reduction.value " , _minipoolAddress)));
61
+ }
62
+
63
+ /// @notice Returns true if the given minipool has had it's bond reduction cancelled by the oDAO
64
+ /// @param _minipoolAddress Address of the minipool to query
65
+ function getReduceBondCancelled (address _minipoolAddress ) override public view returns (bool ) {
66
+ return getBool (keccak256 (abi.encodePacked ("minipool.bond.reduction.cancelled " , address (_minipoolAddress))));
38
67
}
39
68
40
69
/// @notice Returns whether owner of given minipool can reduce bond amount given the waiting period constraint
41
70
/// @param _minipoolAddress Address of the minipool
42
71
function canReduceBondAmount (address _minipoolAddress ) override public view returns (bool ) {
43
- RocketMinipoolDelegate minipool = RocketMinipoolDelegate (_minipoolAddress);
72
+ RocketMinipoolInterface minipool = RocketMinipoolInterface (_minipoolAddress);
44
73
RocketDAONodeTrustedSettingsMinipoolInterface rocketDAONodeTrustedSettingsMinipool = RocketDAONodeTrustedSettingsMinipoolInterface (getContractAddress ("rocketDAONodeTrustedSettingsMinipool " ));
45
74
uint256 reduceBondTime = getUint (keccak256 (abi.encodePacked ("minipool.bond.reduction.time " , _minipoolAddress)));
46
75
return rocketDAONodeTrustedSettingsMinipool.isWithinBondReductionWindow (block .timestamp .sub (reduceBondTime));
@@ -49,8 +78,10 @@ contract RocketMinipoolBondReducer is RocketBase, RocketMinipoolBondReducerInter
49
78
/// @notice Can be called by trusted nodes to cancel a reduction in bond if the validator has too low of a balance
50
79
/// @param _minipoolAddress Address of the minipool
51
80
function voteCancelReduction (address _minipoolAddress ) override external onlyTrustedNode (msg .sender ) onlyLatestContract ("rocketMinipoolBondReducer " , address (this )) {
52
- RocketMinipoolDelegate minipool = RocketMinipoolDelegate (_minipoolAddress);
81
+ // Prevent calling if consensus has already been reached
82
+ require (! getReduceBondCancelled (_minipoolAddress), "Already cancelled " );
53
83
// Get contracts
84
+ RocketMinipoolInterface minipool = RocketMinipoolInterface (_minipoolAddress);
54
85
RocketDAONodeTrustedInterface rocketDAONode = RocketDAONodeTrustedInterface (getContractAddress ("rocketDAONodeTrusted " ));
55
86
// Check for multiple votes
56
87
bytes32 memberVotedKey = keccak256 (abi.encodePacked ("minipool.bond.reduction.member.voted " , _minipoolAddress, msg .sender ));
@@ -69,33 +100,39 @@ contract RocketMinipoolBondReducer is RocketBase, RocketMinipoolBondReducerInter
69
100
emit ReductionCancelled (_minipoolAddress, block .timestamp );
70
101
setBool (keccak256 (abi.encodePacked ("minipool.bond.reduction.cancelled " , _minipoolAddress)), true );
71
102
deleteUint (keccak256 (abi.encodePacked ("minipool.bond.reduction.time " , _minipoolAddress)));
103
+ deleteUint (keccak256 (abi.encodePacked ("minipool.bond.reduction.value " , msg .sender )));
72
104
} else {
73
105
// Increment total
74
106
setUint (totalCancelVotesKey, totalCancelVotes);
75
107
}
76
108
}
77
109
78
110
/// @notice Called by minipools when they are reducing bond to handle state changes outside the minipool
79
- /// @param _from The previous bond amount
80
- /// @param _to The new bond amount
81
- function reduceBondAmount (uint256 _from , uint256 _to ) override external onlyRegisteredMinipool (msg .sender ) onlyLatestContract ("rocketMinipoolBondReducer " , address (this )) {
111
+ function reduceBondAmount () override external onlyRegisteredMinipool (msg .sender ) onlyLatestContract ("rocketMinipoolBondReducer " , address (this )) returns (uint256 ) {
112
+ // Get contracts
113
+ RocketNodeDepositInterface rocketNodeDeposit = RocketNodeDepositInterface (getContractAddress ("rocketNodeDeposit " ));
114
+ RocketMinipoolInterface minipool = RocketMinipoolInterface (msg .sender );
82
115
// Check if has been cancelled
83
116
bool reductionCancelled = getBool (keccak256 (abi.encodePacked ("minipool.bond.reduction.cancelled " , address (msg .sender ))));
84
117
require (! reductionCancelled, "This minipool is not allowed to reduce bond " );
85
118
// Check wait period is satisfied
86
119
require (canReduceBondAmount (msg .sender ), "Wait period not satisfied " );
87
- // Get contracts
88
- RocketNodeDepositInterface rocketNodeDeposit = RocketNodeDepositInterface (getContractAddress ("rocketNodeDeposit " ));
89
- RocketMinipoolDelegate minipool = RocketMinipoolDelegate (msg .sender );
90
- // Check the new bond amount is valid
91
- require (rocketNodeDeposit.isValidDepositAmount (_to), "Invalid bond amount " );
120
+ // Get desired to amount
121
+ uint256 newBondAmount = getUint (keccak256 (abi.encodePacked ("minipool.bond.reduction.value " , msg .sender )));
122
+ require (rocketNodeDeposit.isValidDepositAmount (newBondAmount), "Invalid bond amount " );
92
123
// Calculate difference
93
- uint256 delta = _from.sub (_to);
124
+ uint256 existingBondAmount = minipool.getNodeDepositBalance ();
125
+ uint256 delta = existingBondAmount.sub (newBondAmount);
94
126
// Get node address
95
127
address nodeAddress = minipool.getNodeAddress ();
96
128
// Increase ETH matched or revert if exceeds limit based on current RPL stake
97
129
rocketNodeDeposit.increaseEthMatched (nodeAddress, delta);
98
130
// Increase node operator's deposit credit
99
131
rocketNodeDeposit.increaseDepositCreditBalance (nodeAddress, delta);
132
+ // Clean up state
133
+ deleteUint (keccak256 (abi.encodePacked ("minipool.bond.reduction.time " , msg .sender )));
134
+ deleteUint (keccak256 (abi.encodePacked ("minipool.bond.reduction.value " , msg .sender )));
135
+ // Return
136
+ return newBondAmount;
100
137
}
101
138
}
0 commit comments