Skip to content
This repository has been archived by the owner on Jul 7, 2023. It is now read-only.

Commit

Permalink
C4-519: Fix cancelMinipool to be on minipool creation not rewards sta…
Browse files Browse the repository at this point in the history
…rt time (#215)

* added creation time for cancel fix

* added this back because recreateMinipool uses it

* review comments

* missed this
  • Loading branch information
0xju1ie authored Feb 5, 2023
1 parent 8b92375 commit 7138ae3
Show file tree
Hide file tree
Showing 2 changed files with 16 additions and 4 deletions.
17 changes: 14 additions & 3 deletions contracts/contract/MinipoolManager.sol
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ import {SafeTransferLib} from "@rari-capital/solmate/src/utils/SafeTransferLib.s
minipool.item<index>.avaxNodeOpAmt = avax deposited by node operator (for this cycle)
minipool.item<index>.avaxNodeOpInitialAmt = avax deposited by node operator for the **first** validation cycle
minipool.item<index>.avaxLiquidStakerAmt = avax deposited by users and assigned to this nodeID
minipool.item<index>.creationTime = actual time the minipool was created
// Submitted by the Rialto oracle
minipool.item<index>.txID = transaction id of the AddValidatorTx
Expand Down Expand Up @@ -95,6 +96,7 @@ contract MinipoolManager is Base, ReentrancyGuard, IWithdrawer {
uint256 avaxLiquidStakerAmt;
// Submitted by the Rialto Oracle
bytes32 txID;
uint256 creationTime;
uint256 initialStartTime;
uint256 startTime;
uint256 endTime;
Expand Down Expand Up @@ -272,6 +274,7 @@ contract MinipoolManager is Base, ReentrancyGuard, IWithdrawer {
setUint(keccak256(abi.encodePacked("minipool.item", minipoolIndex, ".avaxNodeOpInitialAmt")), msg.value);
setUint(keccak256(abi.encodePacked("minipool.item", minipoolIndex, ".avaxNodeOpAmt")), msg.value);
setUint(keccak256(abi.encodePacked("minipool.item", minipoolIndex, ".avaxLiquidStakerAmt")), avaxAssignmentRequest);
setUint(keccak256(abi.encodePacked("minipool.item", minipoolIndex, ".creationTime")), block.timestamp);

emit MinipoolStatusChanged(nodeID, MinipoolStatus.Prelaunch);

Expand All @@ -282,12 +285,12 @@ contract MinipoolManager is Base, ReentrancyGuard, IWithdrawer {
/// @notice Owner of a minipool can cancel the (prelaunch) minipool
/// @param nodeID 20-byte Avalanche node ID the Owner registered with
function cancelMinipool(address nodeID) external nonReentrant {
Staking staking = Staking(getContractAddress("Staking"));
ProtocolDAO dao = ProtocolDAO(getContractAddress("ProtocolDAO"));
int256 index = requireValidMinipool(nodeID);
onlyOwner(index);
// make sure they meet the wait period requirement
if (block.timestamp - staking.getRewardsStartTime(msg.sender) < dao.getMinipoolCancelMoratoriumSeconds()) {
// make sure the minipool meets the wait period requirement
uint256 creationTime = getUint(keccak256(abi.encodePacked("minipool.item", index, ".creationTime")));
if (block.timestamp - creationTime < dao.getMinipoolCancelMoratoriumSeconds()) {
revert CancellationTooEarly();
}
_cancelMinipoolAndReturnFunds(nodeID, index);
Expand Down Expand Up @@ -503,6 +506,12 @@ contract MinipoolManager is Base, ReentrancyGuard, IWithdrawer {
staking.increaseAVAXAssigned(mp.owner, compoundedAvaxNodeOpAmt);
staking.increaseMinipoolCount(mp.owner);

if (staking.getRewardsStartTime(mp.owner) == 0) {
// Edge case where calculateAndDistributeRewards has reset their rewards time even though they are still cycling
// So we re-set it here to their initial start time for this minipool
staking.setRewardsStartTime(mp.owner, mp.initialStartTime);
}

ProtocolDAO dao = ProtocolDAO(getContractAddress("ProtocolDAO"));
uint256 ratio = staking.getCollateralizationRatio(mp.owner);
if (ratio < dao.getMinCollateralizationRatio()) {
Expand Down Expand Up @@ -618,6 +627,7 @@ contract MinipoolManager is Base, ReentrancyGuard, IWithdrawer {
mp.avaxNodeOpAmt = getUint(keccak256(abi.encodePacked("minipool.item", index, ".avaxNodeOpAmt")));
mp.avaxLiquidStakerAmt = getUint(keccak256(abi.encodePacked("minipool.item", index, ".avaxLiquidStakerAmt")));
mp.txID = getBytes32(keccak256(abi.encodePacked("minipool.item", index, ".txID")));
mp.creationTime = getUint(keccak256(abi.encodePacked("minipool.item", index, ".creationTime")));
mp.initialStartTime = getUint(keccak256(abi.encodePacked("minipool.item", index, ".initialStartTime")));
mp.startTime = getUint(keccak256(abi.encodePacked("minipool.item", index, ".startTime")));
mp.endTime = getUint(keccak256(abi.encodePacked("minipool.item", index, ".endTime")));
Expand Down Expand Up @@ -721,6 +731,7 @@ contract MinipoolManager is Base, ReentrancyGuard, IWithdrawer {
/// @param index Index of the minipool
function resetMinipoolData(int256 index) private {
setBytes32(keccak256(abi.encodePacked("minipool.item", index, ".txID")), 0);
setUint(keccak256(abi.encodePacked("minipool.item", index, ".creationTime")), 0);
setUint(keccak256(abi.encodePacked("minipool.item", index, ".startTime")), 0);
setUint(keccak256(abi.encodePacked("minipool.item", index, ".endTime")), 0);
setUint(keccak256(abi.encodePacked("minipool.item", index, ".avaxTotalRewardAmt")), 0);
Expand Down
3 changes: 2 additions & 1 deletion test/unit/Scenarios.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -495,7 +495,8 @@ contract ScenariosTest is BaseTest {

vm.startPrank(nodeOp1);
MinipoolManager.Minipool memory mp2 = createMinipool(depositAmt, depositAmt, duration);
assertEq(staking.getAVAXValidatingHighWater(nodeOp1), depositAmt);
assertEq(staking.getAVAXAssignedHighWater(nodeOp1), depositAmt);
skip(5 seconds); //cancel min time
minipoolMgr.cancelMinipool(mp2.nodeID);
vm.stopPrank();

Expand Down

0 comments on commit 7138ae3

Please sign in to comment.