-
Notifications
You must be signed in to change notification settings - Fork 30
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
b386f44
commit ea929c0
Showing
4 changed files
with
185 additions
and
44 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -14,12 +14,14 @@ import { | |
PoSValidatorInfo, | ||
PoSValidatorManagerSettings | ||
} from "./interfaces/IPoSValidatorManager.sol"; | ||
import {Validator, ValidatorStatus, PChainOwner} from "./ACP99Manager.sol"; | ||
import {ACP99Manager, Validator, ValidatorStatus, PChainOwner} from "./ACP99Manager.sol"; | ||
import {IRewardCalculator} from "./interfaces/IRewardCalculator.sol"; | ||
import {WarpMessage} from | ||
import {IWarpMessenger, WarpMessage} from | ||
"@avalabs/[email protected]/contracts/interfaces/IWarpMessenger.sol"; | ||
import {ReentrancyGuardUpgradeable} from | ||
"@openzeppelin/[email protected]/utils/ReentrancyGuardUpgradeable.sol"; | ||
import {ContextUpgradeable} from | ||
"@openzeppelin/[email protected]/utils/ContextUpgradeable.sol"; | ||
|
||
/** | ||
* @dev Implementation of the {IPoSValidatorManager} interface. | ||
|
@@ -28,12 +30,13 @@ import {ReentrancyGuardUpgradeable} from | |
*/ | ||
abstract contract PoSValidatorManager is | ||
IPoSValidatorManager, | ||
ValidatorManager, | ||
ContextUpgradeable, | ||
ReentrancyGuardUpgradeable | ||
{ | ||
// solhint-disable private-vars-leading-underscore | ||
/// @custom:storage-location erc7201:avalanche-icm.storage.PoSValidatorManager | ||
struct PoSValidatorManagerStorage { | ||
ValidatorManager _manager; | ||
/// @notice The minimum amount of stake required to be a validator. | ||
uint256 _minimumStakeAmount; | ||
/// @notice The maximum amount of stake allowed to be a validator. | ||
|
@@ -78,6 +81,11 @@ abstract contract PoSValidatorManager is | |
|
||
uint16 public constant BIPS_CONVERSION_FACTOR = 10000; | ||
|
||
bytes32 public constant P_CHAIN_BLOCKCHAIN_ID = bytes32(0); | ||
|
||
IWarpMessenger public constant WARP_MESSENGER = | ||
IWarpMessenger(0x0200000000000000000000000000000000000005); | ||
|
||
error InvalidDelegationFee(uint16 delegationFeeBips); | ||
error InvalidDelegationID(bytes32 delegationID); | ||
error InvalidDelegatorStatus(DelegatorStatus status); | ||
|
@@ -94,6 +102,27 @@ abstract contract PoSValidatorManager is | |
error ZeroWeightToValueFactor(); | ||
error InvalidUptimeBlockchainID(bytes32 uptimeBlockchainID); | ||
|
||
error InvalidValidatorManagerAddress(address validatorManagerAddress); | ||
error InvalidWarpOriginSenderAddress(address senderAddress); | ||
error InvalidValidatorManagerBlockchainID(bytes32 blockchainID); | ||
error InvalidWarpSourceChainID(bytes32 sourceChainID); | ||
error InvalidRegistrationExpiry(uint64 registrationExpiry); | ||
error InvalidInitializationStatus(); | ||
error InvalidMaximumChurnPercentage(uint8 maximumChurnPercentage); | ||
error InvalidBLSKeyLength(uint256 length); | ||
error InvalidNodeID(bytes nodeID); | ||
error InvalidConversionID(bytes32 encodedConversionID, bytes32 expectedConversionID); | ||
error InvalidTotalWeight(uint64 weight); | ||
error InvalidValidationID(bytes32 validationID); | ||
error InvalidValidatorStatus(ValidatorStatus status); | ||
error InvalidNonce(uint64 nonce); | ||
error InvalidWarpMessage(); | ||
error MaxChurnRateExceeded(uint64 churnAmount); | ||
error NodeAlreadyRegistered(bytes nodeID); | ||
error UnexpectedRegistrationStatus(bool validRegistration); | ||
error InvalidPChainOwnerThreshold(uint256 threshold, uint256 addressesLength); | ||
error PChainOwnerAddressesNotSorted(); | ||
|
||
// solhint-disable ordering | ||
/** | ||
* @dev This storage is visible to child contracts for convenience. | ||
|
@@ -116,9 +145,9 @@ abstract contract PoSValidatorManager is | |
internal | ||
onlyInitializing | ||
{ | ||
__ValidatorManager_init(settings.baseSettings); | ||
__ReentrancyGuard_init(); | ||
__POS_Validator_Manager_init_unchained({ | ||
manager: settings.manager, | ||
minimumStakeAmount: settings.minimumStakeAmount, | ||
maximumStakeAmount: settings.maximumStakeAmount, | ||
minimumStakeDuration: settings.minimumStakeDuration, | ||
|
@@ -132,6 +161,7 @@ abstract contract PoSValidatorManager is | |
|
||
// solhint-disable-next-line func-name-mixedcase | ||
function __POS_Validator_Manager_init_unchained( | ||
ValidatorManager manager, | ||
uint256 minimumStakeAmount, | ||
uint256 maximumStakeAmount, | ||
uint64 minimumStakeDuration, | ||
|
@@ -154,7 +184,7 @@ abstract contract PoSValidatorManager is | |
revert InvalidStakeMultiplier(maximumStakeMultiplier); | ||
} | ||
// Minimum stake duration should be at least one churn period in order to prevent churn tracker abuse. | ||
if (minimumStakeDuration < _getChurnPeriodSeconds()) { | ||
if (minimumStakeDuration < $._manager.getChurnPeriodSeconds()) { | ||
revert InvalidMinStakeDuration(minimumStakeDuration); | ||
} | ||
if (weightToValueFactor == 0) { | ||
|
@@ -164,6 +194,7 @@ abstract contract PoSValidatorManager is | |
revert InvalidUptimeBlockchainID(uptimeBlockchainID); | ||
} | ||
|
||
$._manager = manager; | ||
$._minimumStakeAmount = minimumStakeAmount; | ||
$._maximumStakeAmount = maximumStakeAmount; | ||
$._minimumStakeDuration = minimumStakeDuration; | ||
|
@@ -181,7 +212,7 @@ abstract contract PoSValidatorManager is | |
if (!_isPoSValidator(validationID)) { | ||
revert ValidatorNotPoS(validationID); | ||
} | ||
ValidatorStatus status = getValidator(validationID).status; | ||
ValidatorStatus status = _getPoSValidatorManagerStorage()._manager.getValidator(validationID).status; | ||
if (status != ValidatorStatus.Active) { | ||
revert InvalidValidatorStatus(status); | ||
} | ||
|
@@ -196,7 +227,7 @@ abstract contract PoSValidatorManager is | |
function claimDelegationFees(bytes32 validationID) external { | ||
PoSValidatorManagerStorage storage $ = _getPoSValidatorManagerStorage(); | ||
|
||
ValidatorStatus status = getValidator(validationID).status; | ||
ValidatorStatus status = $._manager.getValidator(validationID).status; | ||
if (status != ValidatorStatus.Completed) { | ||
revert InvalidValidatorStatus(status); | ||
} | ||
|
@@ -324,8 +355,8 @@ abstract contract PoSValidatorManager is | |
) internal returns (bool) { | ||
PoSValidatorManagerStorage storage $ = _getPoSValidatorManagerStorage(); | ||
|
||
_initiateValidatorRemoval(validationID); | ||
Validator memory validator = getValidator(validationID); | ||
$._manager.initiateValidatorRemoval(validationID); | ||
Validator memory validator = $._manager.getValidator(validationID); | ||
|
||
// Non-PoS validators are required to boostrap the network, but are not eligible for rewards. | ||
if (!_isPoSValidator(validationID)) { | ||
|
@@ -376,14 +407,13 @@ abstract contract PoSValidatorManager is | |
*/ | ||
function completeValidatorRemoval(uint32 messageIndex) | ||
public | ||
virtual | ||
override | ||
nonReentrant | ||
returns (bytes32) | ||
{ | ||
PoSValidatorManagerStorage storage $ = _getPoSValidatorManagerStorage(); | ||
|
||
(bytes32 validationID, Validator memory validator) = _completeValidatorRemoval(messageIndex); | ||
bytes32 validationID = $._manager.completeValidatorRemoval(messageIndex); | ||
Validator memory validator = $._manager.getValidator(validationID); | ||
|
||
// Return now if this was originally a PoA validator that was later migrated to this PoS manager, | ||
// or the validator was part of the initial validator set. | ||
|
@@ -485,7 +515,7 @@ abstract contract PoSValidatorManager is | |
uint256 lockedValue = _lock(stakeAmount); | ||
|
||
uint64 weight = valueToWeight(lockedValue); | ||
bytes32 validationID = _initiateValidatorRegistration({ | ||
bytes32 validationID = $._manager.initiateValidatorRegistration({ | ||
nodeID: nodeID, | ||
blsPublicKey: blsPublicKey, | ||
registrationExpiry: registrationExpiry, | ||
|
@@ -547,7 +577,7 @@ abstract contract PoSValidatorManager is | |
uint64 weight = valueToWeight(_lock(delegationAmount)); | ||
|
||
// Ensure the validation period is active | ||
Validator memory validator = getValidator(validationID); | ||
Validator memory validator = $._manager.getValidator(validationID); | ||
// Check that the validation ID is a PoS validator | ||
if (!_isPoSValidator(validationID)) { | ||
revert ValidatorNotPoS(validationID); | ||
|
@@ -563,7 +593,7 @@ abstract contract PoSValidatorManager is | |
} | ||
|
||
(uint64 nonce, bytes32 messageID) = | ||
_initiateValidatorWeightUpdate(validationID, newValidatorWeight); | ||
$._manager.initiateValidatorWeightUpdate(validationID, newValidatorWeight); | ||
|
||
bytes32 delegationID = keccak256(abi.encodePacked(validationID, nonce)); | ||
|
||
|
@@ -598,7 +628,7 @@ abstract contract PoSValidatorManager is | |
|
||
Delegator memory delegator = $._delegatorStakes[delegationID]; | ||
bytes32 validationID = delegator.validationID; | ||
Validator memory validator = getValidator(validationID); | ||
Validator memory validator = $._manager.getValidator(validationID); | ||
|
||
// Ensure the delegator is pending added. Since anybody can call this function once | ||
// delegator registration has been initiated, we need to make sure that this function is only | ||
|
@@ -617,7 +647,7 @@ abstract contract PoSValidatorManager is | |
// then there's no requirement to include an ICM message in this function call. | ||
if (validator.receivedNonce < delegator.startingNonce) { | ||
(bytes32 messageValidationID, uint64 nonce) = | ||
completeValidatorWeightUpdate(messageIndex); | ||
$._manager.completeValidatorWeightUpdate(messageIndex); | ||
if (validationID != messageValidationID) { | ||
revert InvalidValidationID(delegator.validationID); | ||
} | ||
|
@@ -719,7 +749,7 @@ abstract contract PoSValidatorManager is | |
|
||
Delegator memory delegator = $._delegatorStakes[delegationID]; | ||
bytes32 validationID = delegator.validationID; | ||
Validator memory validator = getValidator(validationID); | ||
Validator memory validator = $._manager.getValidator(validationID); | ||
|
||
// Ensure the delegator is active | ||
if (delegator.status != DelegatorStatus.Active) { | ||
|
@@ -758,7 +788,7 @@ abstract contract PoSValidatorManager is | |
$._delegatorStakes[delegationID].status = DelegatorStatus.PendingRemoved; | ||
|
||
($._delegatorStakes[delegationID].endingNonce,) = | ||
_initiateValidatorWeightUpdate(validationID, validator.weight - delegator.weight); | ||
$._manager.initiateValidatorWeightUpdate(validationID, validator.weight - delegator.weight); | ||
|
||
uint256 reward = | ||
_calculateAndSetDelegationReward(delegator, rewardRecipient, delegationID); | ||
|
@@ -785,7 +815,7 @@ abstract contract PoSValidatorManager is | |
) private returns (uint256) { | ||
PoSValidatorManagerStorage storage $ = _getPoSValidatorManagerStorage(); | ||
|
||
Validator memory validator = getValidator(delegator.validationID); | ||
Validator memory validator = $._manager.getValidator(delegator.validationID); | ||
|
||
uint64 delegationEndTime; | ||
if ( | ||
|
@@ -838,7 +868,7 @@ abstract contract PoSValidatorManager is | |
revert InvalidDelegatorStatus(delegator.status); | ||
} | ||
|
||
Validator memory validator = getValidator(delegator.validationID); | ||
Validator memory validator = $._manager.getValidator(delegator.validationID); | ||
if (validator.sentNonce == 0) { | ||
// Should be unreachable. | ||
revert InvalidDelegationID(delegationID); | ||
|
@@ -868,14 +898,14 @@ abstract contract PoSValidatorManager is | |
if (delegator.status != DelegatorStatus.PendingRemoved) { | ||
revert InvalidDelegatorStatus(delegator.status); | ||
} | ||
Validator memory validator = getValidator(delegator.validationID); | ||
Validator memory validator = $._manager.getValidator(delegator.validationID); | ||
|
||
// We only expect an ICM message if we haven't received a weight update with a nonce greater than the delegation's ending nonce | ||
if ( | ||
getValidator(delegator.validationID).status != ValidatorStatus.Completed | ||
$._manager.getValidator(delegator.validationID).status != ValidatorStatus.Completed | ||
&& validator.receivedNonce < delegator.endingNonce | ||
) { | ||
(bytes32 validationID, uint64 nonce) = completeValidatorWeightUpdate(messageIndex); | ||
(bytes32 validationID, uint64 nonce) = $._manager.completeValidatorWeightUpdate(messageIndex); | ||
if (delegator.validationID != validationID) { | ||
revert InvalidValidationID(validationID); | ||
} | ||
|
@@ -900,7 +930,7 @@ abstract contract PoSValidatorManager is | |
|
||
// To prevent churn tracker abuse, check that one full churn period has passed, | ||
// so a delegator may not stake twice in the same churn period. | ||
if (block.timestamp < delegator.startTime + _getChurnPeriodSeconds()) { | ||
if (block.timestamp < delegator.startTime + $._manager.getChurnPeriodSeconds()) { | ||
revert MinStakeDurationNotPassed(uint64(block.timestamp)); | ||
} | ||
|
||
|
@@ -973,4 +1003,36 @@ abstract contract PoSValidatorManager is | |
|
||
return (delegationRewards, validatorFees); | ||
} | ||
|
||
function initiateValidatorWeightUpdate( | ||
bytes32 validationID, | ||
uint64 newWeight | ||
) public returns (uint64, bytes32) { | ||
return _getPoSValidatorManagerStorage()._manager.initiateValidatorWeightUpdate( | ||
validationID, newWeight | ||
); | ||
} | ||
|
||
function initiateValidatorRemoval(bytes32 validationID) public { | ||
_getPoSValidatorManagerStorage()._manager.initiateValidatorRemoval(validationID); | ||
} | ||
|
||
function initiateValidatorRegistration( | ||
bytes memory nodeID, | ||
bytes memory blsPublicKey, | ||
uint64 registrationExpiry, | ||
PChainOwner memory remainingBalanceOwner, | ||
PChainOwner memory disableOwner, | ||
uint64 weight | ||
) public returns (bytes32) { | ||
return _getPoSValidatorManagerStorage()._manager.initiateValidatorRegistration( | ||
nodeID, blsPublicKey, registrationExpiry, remainingBalanceOwner, disableOwner, weight | ||
); | ||
} | ||
|
||
function completeValidatorRegistration(uint32 messageIndex) | ||
public | ||
returns (bytes32) { | ||
return _getPoSValidatorManagerStorage()._manager.completeValidatorRegistration(messageIndex); | ||
} | ||
} |
Oops, something went wrong.