From 721d02f0d077c84a5a70f1b80ce0f05e9228608b Mon Sep 17 00:00:00 2001 From: bhargav55 Date: Tue, 24 Dec 2024 19:08:12 +0530 Subject: [PATCH] feat: delegate tokens unlock after 21days --- .../validator-manager/PoSValidatorManager.sol | 9 +++++++- .../interfaces/IPoSValidatorManager.sol | 4 ++++ .../ERC721PoSValidatorManagerTests.t.sol | 11 ++++++++-- .../tests/PoSValidatorManagerTests.t.sol | 21 +++++++++++-------- 4 files changed, 33 insertions(+), 12 deletions(-) diff --git a/contracts/validator-manager/PoSValidatorManager.sol b/contracts/validator-manager/PoSValidatorManager.sol index 98775b21a..bf1eeaa58 100644 --- a/contracts/validator-manager/PoSValidatorManager.sol +++ b/contracts/validator-manager/PoSValidatorManager.sol @@ -56,6 +56,7 @@ abstract contract PoSValidatorManager is error InvalidStakeMultiplier(uint8 maximumStakeMultiplier); error MaxWeightExceeded(uint64 newValidatorWeight); error MinStakeDurationNotPassed(uint64 endTime); + error UnlockDelegateDurationNotPassed(uint64 endTime); error UnauthorizedOwner(address sender); error ValidatorNotPoS(bytes32 validationID); error ValidatorIneligibleForRewards(bytes32 validationID); @@ -91,6 +92,7 @@ abstract contract PoSValidatorManager is minimumStakeAmount: settings.minimumStakeAmount, maximumStakeAmount: settings.maximumStakeAmount, minimumStakeDuration: settings.minimumStakeDuration, + unlockDelegateDuration: settings.unlockDelegateDuration, minimumDelegationFeeBips: settings.minimumDelegationFeeBips, maximumStakeMultiplier: settings.maximumStakeMultiplier, weightToValueFactor: settings.weightToValueFactor, @@ -104,6 +106,7 @@ abstract contract PoSValidatorManager is uint256 minimumStakeAmount, uint256 maximumStakeAmount, uint64 minimumStakeDuration, + uint64 unlockDelegateDuration, uint16 minimumDelegationFeeBips, uint8 maximumStakeMultiplier, uint256 weightToValueFactor, @@ -141,6 +144,7 @@ abstract contract PoSValidatorManager is $._weightToValueFactor = weightToValueFactor; $._rewardCalculator = rewardCalculator; $._uptimeBlockchainID = uptimeBlockchainID; + $._unlockDelegateDuration = unlockDelegateDuration; } /** @@ -717,7 +721,7 @@ abstract contract PoSValidatorManager is // the complete step, even if the delivered nonce is greater than the nonce used to // initialize the removal. $._delegatorStakes[delegationID].status = DelegatorStatus.PendingRemoved; - + $._delegatorStakes[delegationID].endedAt = uint64(block.timestamp); ($._delegatorStakes[delegationID].endingNonce,) = _setValidatorWeight(validationID, validator.weight - delegator.weight); @@ -850,6 +854,9 @@ abstract contract PoSValidatorManager is revert InvalidNonce(nonce); } } + if(block.timestamp < delegator.endedAt + $._unlockDelegateDuration) { + revert UnlockDelegateDurationNotPassed(uint64(block.timestamp)); + } _completeEndDelegation(delegationID); } diff --git a/contracts/validator-manager/interfaces/IPoSValidatorManager.sol b/contracts/validator-manager/interfaces/IPoSValidatorManager.sol index a5fa6ba6d..7af81da34 100644 --- a/contracts/validator-manager/interfaces/IPoSValidatorManager.sol +++ b/contracts/validator-manager/interfaces/IPoSValidatorManager.sol @@ -37,6 +37,7 @@ struct PoSValidatorManagerSettings { uint256 minimumStakeAmount; uint256 maximumStakeAmount; uint64 minimumStakeDuration; + uint64 unlockDelegateDuration; uint16 minimumDelegationFeeBips; uint8 maximumStakeMultiplier; uint256 weightToValueFactor; @@ -53,6 +54,7 @@ struct Delegator { bytes32 validationID; uint64 weight; uint64 startedAt; + uint64 endedAt; uint64 startingNonce; uint64 endingNonce; } @@ -82,6 +84,8 @@ struct PoSValidatorManagerStorage { uint64 _minimumStakeDuration; /// @notice The minimum delegation fee percentage, in basis points, required to delegate to a validator. uint16 _minimumDelegationFeeBips; + /// @notice The duration in seconds after a delegator's delegation is ended before the delegator's stake is unlocked. + uint64 _unlockDelegateDuration; /** * @notice A multiplier applied to validator's initial stake amount to determine * the maximum amount of stake a validator can have with delegations. diff --git a/contracts/validator-manager/tests/ERC721/ERC721PoSValidatorManagerTests.t.sol b/contracts/validator-manager/tests/ERC721/ERC721PoSValidatorManagerTests.t.sol index d95024b28..bf24623a6 100644 --- a/contracts/validator-manager/tests/ERC721/ERC721PoSValidatorManagerTests.t.sol +++ b/contracts/validator-manager/tests/ERC721/ERC721PoSValidatorManagerTests.t.sol @@ -41,6 +41,7 @@ abstract contract ERC721PoSValidatorManagerTest is ERC721ValidatorManagerTest { address public constant DEFAULT_VALIDATOR_OWNER_ADDRESS = address(0x2345234523452345234523452345234523452345); uint64 public constant DEFAULT_REWARD_RATE = uint64(60); + uint64 public constant DEFAULT_UNLOCK_DELEGATE_DURATION = 21 days; uint64 public constant DEFAULT_MINIMUM_STAKE_DURATION = 24 hours; uint16 public constant DEFAULT_MINIMUM_DELEGATION_FEE_BIPS = 100; uint16 public constant DEFAULT_DELEGATION_FEE_BIPS = 150; @@ -667,6 +668,7 @@ abstract contract ERC721PoSValidatorManagerTest is ERC721ValidatorManagerTest { _calculateValidatorFeesFromDelegator(expectedTotalReward, DEFAULT_DELEGATION_FEE_BIPS); uint256 expectedDelegatorReward = expectedTotalReward - expectedValidatorFees; + vm.warp(DEFAULT_DELEGATOR_END_DELEGATION_TIMESTAMP + DEFAULT_UNLOCK_DELEGATE_DURATION + 1); _completeEndDelegationWithChecks({ validationID: validationID, delegationID: delegationID, @@ -771,6 +773,7 @@ abstract contract ERC721PoSValidatorManagerTest is ERC721ValidatorManagerTest { _calculateValidatorFeesFromDelegator(expectedTotalReward, DEFAULT_DELEGATION_FEE_BIPS); uint256 expectedDelegatorReward = expectedTotalReward - expectedValidatorFees; + vm.warp(DEFAULT_DELEGATOR_END_DELEGATION_TIMESTAMP + DEFAULT_UNLOCK_DELEGATE_DURATION + 1); _completeEndDelegationWithChecks({ validationID: validationID, delegationID: delegationID, @@ -818,7 +821,7 @@ abstract contract ERC721PoSValidatorManagerTest is ERC721ValidatorManagerTest { uint256 expectedValidatorFees = _calculateValidatorFeesFromDelegator(expectedTotalReward, DEFAULT_DELEGATION_FEE_BIPS); uint256 expectedDelegatorReward = expectedTotalReward - expectedValidatorFees; - + vm.warp(DEFAULT_DELEGATOR_END_DELEGATION_TIMESTAMP + DEFAULT_UNLOCK_DELEGATE_DURATION + 1); _completeEndDelegationWithChecks({ validationID: validationID, delegationID: delegationID, @@ -977,6 +980,7 @@ abstract contract ERC721PoSValidatorManagerTest is ERC721ValidatorManagerTest { address delegator = DEFAULT_DELEGATOR_ADDRESS; + vm.warp(DEFAULT_DELEGATOR_END_DELEGATION_TIMESTAMP + DEFAULT_UNLOCK_DELEGATE_DURATION + 1); _completeEndDelegationWithChecks({ validationID: validationID, delegationID: delegationID, @@ -1112,6 +1116,7 @@ abstract contract ERC721PoSValidatorManagerTest is ERC721ValidatorManagerTest { _expectStakeUnlock(DEFAULT_DELEGATOR_ADDRESS, _weightToValue(DEFAULT_DELEGATOR_TOKEN_ID)); _expectRewardIssuance(DEFAULT_DELEGATOR_ADDRESS, expectedDelegatorReward); + vm.warp(DEFAULT_DELEGATOR_END_DELEGATION_TIMESTAMP + DEFAULT_UNLOCK_DELEGATE_DURATION + 1); posValidatorManager.completeEndDelegation(delegationID, 0); assertEq( _getStakeAssetBalance(DEFAULT_DELEGATOR_ADDRESS), @@ -1245,7 +1250,7 @@ abstract contract ERC721PoSValidatorManagerTest is ERC721ValidatorManagerTest { uint256 expectedDelegatorReward = expectedTotalReward - expectedValidatorFees; address delegator = DEFAULT_DELEGATOR_ADDRESS; - + vm.warp(DEFAULT_DELEGATOR_END_DELEGATION_TIMESTAMP + DEFAULT_UNLOCK_DELEGATE_DURATION + 1); // Complete delegation1 by delivering the weight update from nonce 4 (delegator2's nonce) _completeEndDelegationWithChecks({ validationID: validationID, @@ -2108,6 +2113,7 @@ abstract contract ERC721PoSValidatorManagerTest is ERC721ValidatorManagerTest { uint256 expectedValidatorFees = _calculateValidatorFeesFromDelegator(expectedTotalReward, DEFAULT_DELEGATION_FEE_BIPS); uint256 expectedDelegatorReward = expectedTotalReward - expectedValidatorFees; + vm.warp(DEFAULT_DELEGATOR_END_DELEGATION_TIMESTAMP + DEFAULT_UNLOCK_DELEGATE_DURATION + 1); _completeEndDelegationWithChecks({ validationID: validationID, delegationID: delegationID, @@ -2475,6 +2481,7 @@ abstract contract ERC721PoSValidatorManagerTest is ERC721ValidatorManagerTest { minimumStakeAmount: DEFAULT_MINIMUM_STAKE_AMOUNT, maximumStakeAmount: DEFAULT_MAXIMUM_STAKE_AMOUNT, minimumStakeDuration: DEFAULT_MINIMUM_STAKE_DURATION, + unlockDelegateDuration: DEFAULT_UNLOCK_DELEGATE_DURATION, minimumDelegationFeeBips: DEFAULT_MINIMUM_DELEGATION_FEE_BIPS, maximumStakeMultiplier: DEFAULT_MAXIMUM_STAKE_MULTIPLIER, weightToValueFactor: DEFAULT_WEIGHT_TO_VALUE_FACTOR, diff --git a/contracts/validator-manager/tests/PoSValidatorManagerTests.t.sol b/contracts/validator-manager/tests/PoSValidatorManagerTests.t.sol index 49e22e1e1..11d704f41 100644 --- a/contracts/validator-manager/tests/PoSValidatorManagerTests.t.sol +++ b/contracts/validator-manager/tests/PoSValidatorManagerTests.t.sol @@ -26,6 +26,7 @@ import { abstract contract PoSValidatorManagerTest is ValidatorManagerTest { uint64 public constant DEFAULT_UPTIME = uint64(100); uint64 public constant DEFAULT_DELEGATOR_WEIGHT = uint64(1e5); + uint64 public constant DEFAULT_UNLOCK_DELEGATE_DURATION = 24 days; uint64 public constant DEFAULT_DELEGATOR_INIT_REGISTRATION_TIMESTAMP = DEFAULT_REGISTRATION_TIMESTAMP + DEFAULT_EXPIRY; uint64 public constant DEFAULT_DELEGATOR_COMPLETE_REGISTRATION_TIMESTAMP = @@ -573,9 +574,10 @@ abstract contract PoSValidatorManagerTest is ValidatorManagerTest { bytes32 validationID = _registerDefaultValidator(); bytes32 delegationID = _registerDefaultDelegator(validationID); + vm.warp(DEFAULT_DELEGATOR_END_DELEGATION_TIMESTAMP + DEFAULT_UNLOCK_DELEGATE_DURATION + 1); _completeDefaultDelegator(validationID, delegationID); } -/* + function testClaimDelegationFeesInvalidValidatorStatus() public { bytes32 validationID = _registerDefaultValidator(); bytes32 delegationID = _registerDefaultDelegator(validationID); @@ -665,7 +667,7 @@ abstract contract PoSValidatorManagerTest is ValidatorManagerTest { uint256 expectedValidatorFees = _calculateValidatorFeesFromDelegator(expectedTotalReward, DEFAULT_DELEGATION_FEE_BIPS); uint256 expectedDelegatorReward = expectedTotalReward - expectedValidatorFees; - + vm.warp(DEFAULT_DELEGATOR_END_DELEGATION_TIMESTAMP + DEFAULT_UNLOCK_DELEGATE_DURATION + 1); _completeEndDelegationWithChecks({ validationID: validationID, delegationID: delegationID, @@ -772,7 +774,7 @@ abstract contract PoSValidatorManagerTest is ValidatorManagerTest { uint256 expectedValidatorFees = _calculateValidatorFeesFromDelegator(expectedTotalReward, DEFAULT_DELEGATION_FEE_BIPS); uint256 expectedDelegatorReward = expectedTotalReward - expectedValidatorFees; - + vm.warp(DEFAULT_DELEGATOR_END_DELEGATION_TIMESTAMP + DEFAULT_UNLOCK_DELEGATE_DURATION + 1); _completeEndDelegationWithChecks({ validationID: validationID, delegationID: delegationID, @@ -786,7 +788,7 @@ abstract contract PoSValidatorManagerTest is ValidatorManagerTest { rewardRecipient: DEFAULT_DELEGATOR_ADDRESS }); } -*/ + function testChangeDelegatorRewardRecipient() public { bytes32 validationID = _registerDefaultValidator(); bytes32 delegationID = _registerDefaultDelegator(validationID); @@ -820,7 +822,7 @@ abstract contract PoSValidatorManagerTest is ValidatorManagerTest { uint256 expectedValidatorFees = _calculateValidatorFeesFromDelegator(expectedTotalReward, DEFAULT_DELEGATION_FEE_BIPS); uint256 expectedDelegatorReward = expectedTotalReward - expectedValidatorFees; - + vm.warp(DEFAULT_DELEGATOR_END_DELEGATION_TIMESTAMP + DEFAULT_UNLOCK_DELEGATE_DURATION + 1); _completeEndDelegationWithChecks({ validationID: validationID, delegationID: delegationID, @@ -978,7 +980,7 @@ abstract contract PoSValidatorManagerTest is ValidatorManagerTest { uint256 expectedDelegatorReward = expectedTotalReward - expectedValidatorFees; address delegator = DEFAULT_DELEGATOR_ADDRESS; - + vm.warp(DEFAULT_DELEGATOR_END_DELEGATION_TIMESTAMP + DEFAULT_UNLOCK_DELEGATE_DURATION + 1); _completeEndDelegationWithChecks({ validationID: validationID, delegationID: delegationID, @@ -1107,7 +1109,7 @@ abstract contract PoSValidatorManagerTest is ValidatorManagerTest { _expectStakeUnlock(DEFAULT_DELEGATOR_ADDRESS, _weightToValue(DEFAULT_DELEGATOR_WEIGHT)); _expectRewardIssuance(DEFAULT_DELEGATOR_ADDRESS, expectedDelegatorReward); - + vm.warp(DEFAULT_DELEGATOR_END_DELEGATION_TIMESTAMP + DEFAULT_UNLOCK_DELEGATE_DURATION + 1); posValidatorManager.completeEndDelegation(delegationID, 0); assertEq( @@ -1238,7 +1240,7 @@ abstract contract PoSValidatorManagerTest is ValidatorManagerTest { uint256 expectedDelegatorReward = expectedTotalReward - expectedValidatorFees; address delegator = DEFAULT_DELEGATOR_ADDRESS; - + vm.warp(DEFAULT_DELEGATOR_END_DELEGATION_TIMESTAMP + DEFAULT_UNLOCK_DELEGATE_DURATION + 1); // Complete delegation1 by delivering the weight update from nonce 4 (delegator2's nonce) _completeEndDelegationWithChecks({ validationID: validationID, @@ -2102,7 +2104,7 @@ abstract contract PoSValidatorManagerTest is ValidatorManagerTest { uint256 expectedValidatorFees = _calculateValidatorFeesFromDelegator(expectedTotalReward, DEFAULT_DELEGATION_FEE_BIPS); uint256 expectedDelegatorReward = expectedTotalReward - expectedValidatorFees; - + vm.warp(DEFAULT_DELEGATOR_END_DELEGATION_TIMESTAMP + DEFAULT_UNLOCK_DELEGATE_DURATION + 1); _completeEndDelegationWithChecks({ validationID: validationID, delegationID: delegationID, @@ -2465,6 +2467,7 @@ abstract contract PoSValidatorManagerTest is ValidatorManagerTest { minimumDelegationFeeBips: DEFAULT_MINIMUM_DELEGATION_FEE_BIPS, maximumStakeMultiplier: DEFAULT_MAXIMUM_STAKE_MULTIPLIER, weightToValueFactor: DEFAULT_WEIGHT_TO_VALUE_FACTOR, + unlockDelegateDuration: DEFAULT_UNLOCK_DELEGATE_DURATION, rewardCalculator: IRewardCalculator(address(0)), uptimeBlockchainID: DEFAULT_SOURCE_BLOCKCHAIN_ID });