Skip to content

Commit

Permalink
contracts building
Browse files Browse the repository at this point in the history
  • Loading branch information
cam-schultz committed Jan 17, 2025
1 parent b386f44 commit ea929c0
Show file tree
Hide file tree
Showing 4 changed files with 185 additions and 44 deletions.
48 changes: 36 additions & 12 deletions contracts/validator-manager/PoAValidatorManager.sol
Original file line number Diff line number Diff line change
Expand Up @@ -16,31 +16,54 @@ import {OwnableUpgradeable} from
*
* @custom:security-contact https://github.com/ava-labs/icm-contracts/blob/main/SECURITY.md
*/
contract PoAValidatorManager is IPoAValidatorManager, ValidatorManager, OwnableUpgradeable {
contract PoAValidatorManager is IPoAValidatorManager, OwnableUpgradeable {
// solhint-disable private-vars-leading-underscore
struct PoAValidatorManagerStorage {
ValidatorManager _manager;
}

// keccak256(abi.encode(uint256(keccak256("avalanche-icm.storage.PoAValidatorManager")) - 1)) & ~bytes32(uint256(0xff));
bytes32 public constant POA_VALIDATOR_MANAGER_STORAGE_LOCATION =
0x81773fca73a14ca21edf1cadc6ec0b26d6a44966f6e97607e90422658d423500;

function _getPoAValidatorManagerStorage()
private
pure
returns (PoAValidatorManagerStorage storage $)
{
// solhint-disable-next-line no-inline-assembly
assembly {
$.slot := POA_VALIDATOR_MANAGER_STORAGE_LOCATION
}
}

constructor(ICMInitializable init) {
if (init == ICMInitializable.Disallowed) {
_disableInitializers();
}
}

function initialize(
ValidatorManagerSettings calldata settings,
ValidatorManager manager,
address initialOwner
) external initializer {
__PoAValidatorManager_init(settings, initialOwner);
__PoAValidatorManager_init(manager, initialOwner);
}

// solhint-disable func-name-mixedcase, ordering
function __PoAValidatorManager_init(
ValidatorManagerSettings calldata settings,
ValidatorManager manager,
address initialOwner
) internal onlyInitializing {
__ValidatorManager_init(settings);
__Ownable_init(initialOwner);
__PoAValidatorManager_init_unchained(manager);
}

// solhint-disable-next-line no-empty-blocks
function __PoAValidatorManager_init_unchained() internal onlyInitializing {}
function __PoAValidatorManager_init_unchained(ValidatorManager manager) internal onlyInitializing {
PoAValidatorManagerStorage storage $ = _getPoAValidatorManagerStorage();
$._manager = manager;
}

// solhint-enable func-name-mixedcase

Expand All @@ -55,7 +78,7 @@ contract PoAValidatorManager is IPoAValidatorManager, ValidatorManager, OwnableU
PChainOwner memory disableOwner,
uint64 weight
) external onlyOwner returns (bytes32 validationID) {
return _initiateValidatorRegistration({
return _getPoAValidatorManagerStorage()._manager.initiateValidatorRegistration({
nodeID: nodeID,
blsPublicKey: blsPublicKey,
registrationExpiry: registrationExpiry,
Expand All @@ -70,19 +93,20 @@ contract PoAValidatorManager is IPoAValidatorManager, ValidatorManager, OwnableU
* @notice See {IPoAValidatorManager-initiateValidatorRemoval}.
*/
function initiateValidatorRemoval(bytes32 validationID) external override onlyOwner {
_initiateValidatorRemoval(validationID);
_getPoAValidatorManagerStorage()._manager.initiateValidatorRemoval(validationID);
}

/**
* @notice See {ACP99Manager-completeValidatorRemoval}.
*/
function completeValidatorRemoval(uint32 messageIndex)
public
virtual
override
returns (bytes32)
{
(bytes32 validationID,) = _completeValidatorRemoval(messageIndex);
return validationID;
return _getPoAValidatorManagerStorage()._manager.completeValidatorRemoval(messageIndex);
}

function completeValidatorRegistration(uint32 messageIndex) public returns (bytes32) {
return _getPoAValidatorManagerStorage()._manager.completeValidatorRegistration(messageIndex);
}
}
112 changes: 87 additions & 25 deletions contracts/validator-manager/PoSValidatorManager.sol
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -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.
Expand Down Expand Up @@ -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);
Expand All @@ -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.
Expand All @@ -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,
Expand All @@ -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,
Expand All @@ -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) {
Expand All @@ -164,6 +194,7 @@ abstract contract PoSValidatorManager is
revert InvalidUptimeBlockchainID(uptimeBlockchainID);
}

$._manager = manager;
$._minimumStakeAmount = minimumStakeAmount;
$._maximumStakeAmount = maximumStakeAmount;
$._minimumStakeDuration = minimumStakeDuration;
Expand All @@ -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);
}
Expand All @@ -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);
}
Expand Down Expand Up @@ -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)) {
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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);
Expand All @@ -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));

Expand Down Expand Up @@ -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
Expand All @@ -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);
}
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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);
Expand All @@ -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 (
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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);
}
Expand All @@ -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));
}

Expand Down Expand Up @@ -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);
}
}
Loading

0 comments on commit ea929c0

Please sign in to comment.