diff --git a/contracts/validator-manager/ACP99ValidatorManager.sol b/contracts/validator-manager/ACP99ValidatorManager.sol new file mode 100644 index 000000000..711b7991b --- /dev/null +++ b/contracts/validator-manager/ACP99ValidatorManager.sol @@ -0,0 +1,59 @@ +// (c) 2024, Ava Labs, Inc. All rights reserved. +// See the file LICENSE for licensing terms. + +// SPDX-License-Identifier: Ecosystem + +import {IACP99SecurityModule} from "./interfaces/IACP99SecurityModule.sol"; +import {ValidatorManager} from "./ValidatorManager.sol"; +import {IACP99ValidatorManager, ConversionData, ValidatorRegistrationInput} from "./interfaces/IACP99ValidatorManager.sol"; + +pragma solidity 0.8.25; + +abstract contract ACP99ValidatorManager is IACP99ValidatorManager, ValidatorManager { + IACP99SecurityModule public securityModule; + + // TODO: calling this should be restricted to...who? + function setSecurityModule(IACP99SecurityModule _securityModule) external { + securityModule = _securityModule; + } + + function initializeValidatorSet( + ConversionData calldata conversionData, + uint32 messageIndex + ) external { + _initializeValidatorSet(conversionData, messageIndex); + } + + function initializeValidatorRegistration( + ValidatorRegistrationInput calldata input, + uint64 weight, + bytes calldata args + ) external returns (bytes32){ + bytes32 validationID = _initializeValidatorRegistration(input, weight); + securityModule.handleInitializeValidatorRegistration(validationID, weight, args); + return validationID; + } + + function completeValidatorRegistration(uint32 messageIndex) external{ + bytes32 validationID = _completeValidatorRegistration(messageIndex); + securityModule.handleCompleteValidatorRegistration(validationID); + } + + function initializeEndValidation(bytes32 validationID, bytes calldata args) external{ + _initializeEndValidation(validationID); + securityModule.handleInitializeEndValidation(validationID, args); + } + + function completeEndValidation(uint32 messageIndex) external{ + bytes32 validationID = _completeEndValidation(messageIndex); + securityModule.handleCompleteEndValidation(validationID); + } + + function initializeValidatorWeightChange(bytes32 validationID, uint64 weight, bytes calldata args) external{ + securityModule.handleInitializeValidatorWeightChange(validationID, weight, args); + } + + function completeValidatorWeightChange(bytes32 validationID, bytes calldata args) external{ + securityModule.handleCompleteValidatorWeightChange(validationID, args); + } +} \ No newline at end of file diff --git a/contracts/validator-manager/ERC20TokenStakingManager.sol b/contracts/validator-manager/ERC20TokenStakingManager.sol index a5e6af656..8a637c544 100644 --- a/contracts/validator-manager/ERC20TokenStakingManager.sol +++ b/contracts/validator-manager/ERC20TokenStakingManager.sol @@ -7,8 +7,6 @@ pragma solidity 0.8.25; import {PoSValidatorManager} from "./PoSValidatorManager.sol"; import {PoSValidatorManagerSettings} from "./interfaces/IPoSValidatorManager.sol"; -import {ValidatorRegistrationInput} from "./interfaces/IValidatorManager.sol"; -import {IERC20TokenStakingManager} from "./interfaces/IERC20TokenStakingManager.sol"; import {IERC20Mintable} from "./interfaces/IERC20Mintable.sol"; import {ICMInitializable} from "@utilities/ICMInitializable.sol"; import {SafeERC20TransferFrom} from "@utilities/SafeERC20TransferFrom.sol"; @@ -16,6 +14,7 @@ import {Initializable} from "@openzeppelin/contracts-upgradeable@5.0.2/proxy/utils/Initializable.sol"; import {SafeERC20} from "@openzeppelin/contracts@5.0.2/token/ERC20/utils/SafeERC20.sol"; + /** * @dev Implementation of the {IERC20TokenStakingManager} interface. * @@ -23,8 +22,7 @@ import {SafeERC20} from "@openzeppelin/contracts@5.0.2/token/ERC20/utils/SafeERC */ contract ERC20TokenStakingManager is Initializable, - PoSValidatorManager, - IERC20TokenStakingManager + PoSValidatorManager { using SafeERC20 for IERC20Mintable; using SafeERC20TransferFrom for IERC20Mintable; @@ -95,20 +93,6 @@ contract ERC20TokenStakingManager is $._token = token; } - /** - * @notice See {IERC20TokenStakingManager-initializeValidatorRegistration} - */ - function initializeValidatorRegistration( - ValidatorRegistrationInput calldata registrationInput, - uint16 delegationFeeBips, - uint64 minStakeDuration, - uint256 stakeAmount - ) external nonReentrant returns (bytes32 validationID) { - return _initializeValidatorRegistration( - registrationInput, delegationFeeBips, minStakeDuration, stakeAmount - ); - } - /** * @notice See {IERC20TokenStakingManager-initializeDelegatorRegistration} */ diff --git a/contracts/validator-manager/NativeTokenStakingManager.sol b/contracts/validator-manager/NativeTokenStakingManager.sol index b641a94b5..4d7f567e5 100644 --- a/contracts/validator-manager/NativeTokenStakingManager.sol +++ b/contracts/validator-manager/NativeTokenStakingManager.sol @@ -7,8 +7,6 @@ pragma solidity 0.8.25; import {PoSValidatorManager} from "./PoSValidatorManager.sol"; import {PoSValidatorManagerSettings} from "./interfaces/IPoSValidatorManager.sol"; -import {ValidatorRegistrationInput} from "./interfaces/IValidatorManager.sol"; -import {INativeTokenStakingManager} from "./interfaces/INativeTokenStakingManager.sol"; import {INativeMinter} from "@avalabs/subnet-evm-contracts@1.2.0/contracts/interfaces/INativeMinter.sol"; import {ICMInitializable} from "@utilities/ICMInitializable.sol"; @@ -23,8 +21,7 @@ import {Initializable} from */ contract NativeTokenStakingManager is Initializable, - PoSValidatorManager, - INativeTokenStakingManager + PoSValidatorManager { using Address for address payable; @@ -58,19 +55,6 @@ contract NativeTokenStakingManager is // solhint-disable-next-line func-name-mixedcase, no-empty-blocks function __NativeTokenStakingManager_init_unchained() internal onlyInitializing {} - /** - * @notice See {INativeTokenStakingManager-initializeValidatorRegistration}. - */ - function initializeValidatorRegistration( - ValidatorRegistrationInput calldata registrationInput, - uint16 delegationFeeBips, - uint64 minStakeDuration - ) external payable nonReentrant returns (bytes32) { - return _initializeValidatorRegistration( - registrationInput, delegationFeeBips, minStakeDuration, msg.value - ); - } - /** * @notice See {INativeTokenStakingManager-initializeDelegatorRegistration}. */ diff --git a/contracts/validator-manager/PoAValidatorManager.sol b/contracts/validator-manager/PoAValidatorManager.sol index ad38db6eb..c20ea1079 100644 --- a/contracts/validator-manager/PoAValidatorManager.sol +++ b/contracts/validator-manager/PoAValidatorManager.sol @@ -5,22 +5,21 @@ pragma solidity 0.8.25; -import {ValidatorManager} from "./ValidatorManager.sol"; import { - ValidatorManagerSettings, - ValidatorRegistrationInput + ValidatorManagerSettings } from "./interfaces/IValidatorManager.sol"; -import {IPoAValidatorManager} from "./interfaces/IPoAValidatorManager.sol"; import {ICMInitializable} from "@utilities/ICMInitializable.sol"; import {OwnableUpgradeable} from "@openzeppelin/contracts-upgradeable@5.0.2/access/OwnableUpgradeable.sol"; +import {IACP99SecurityModule} from "./interfaces/IACP99SecurityModule.sol"; +import {ACP99ValidatorManager} from "./ACP99ValidatorManager.sol"; /** * @dev Implementation of the {IPoAValidatorManager} interface. * * @custom:security-contact https://github.com/ava-labs/teleporter/blob/main/SECURITY.md */ -contract PoAValidatorManager is IPoAValidatorManager, ValidatorManager, OwnableUpgradeable { +contract PoAValidatorManager is IACP99SecurityModule, ACP99ValidatorManager, OwnableUpgradeable { constructor(ICMInitializable init) { if (init == ICMInitializable.Disallowed) { _disableInitializers(); @@ -46,30 +45,34 @@ contract PoAValidatorManager is IPoAValidatorManager, ValidatorManager, OwnableU // solhint-disable-next-line no-empty-blocks function __PoAValidatorManager_init_unchained() internal onlyInitializing {} - // solhint-enable func-name-mixedcase - - /** - * @notice See {IPoAValidatorManager-initializeValidatorRegistration}. - */ - function initializeValidatorRegistration( - ValidatorRegistrationInput calldata registrationInput, - uint64 weight - ) external onlyOwner returns (bytes32 validationID) { - return _initializeValidatorRegistration(registrationInput, weight); - } - // solhint-enable ordering /** * @notice See {IPoAValidatorManager-initializeEndValidation}. */ - function initializeEndValidation(bytes32 validationID) external override onlyOwner { - _initializeEndValidation(validationID); - } /** * @notice See {IValidatorManager-completeEndValidation}. */ - function completeEndValidation(uint32 messageIndex) external { - _completeEndValidation(messageIndex); + function handleInitializeValidatorRegistration(bytes32 validationID, uint64 weight, bytes calldata args) external { + } + + function handleCompleteValidatorRegistration(bytes32 validationID) external { + // No-op + } + + function handleInitializeEndValidation(bytes32 validationID, bytes calldata args) external { + // No-op + } + + function handleCompleteEndValidation(bytes32 validationID) external { + // No-op + } + + function handleInitializeValidatorWeightChange(bytes32 validationID, uint64 weight, bytes calldata args) external { + // No-op + } + + function handleCompleteValidatorWeightChange(bytes32 validationID, bytes calldata args) external { + // No-op } } diff --git a/contracts/validator-manager/PoSValidatorManager.sol b/contracts/validator-manager/PoSValidatorManager.sol index 4243b850b..bb577323f 100644 --- a/contracts/validator-manager/PoSValidatorManager.sol +++ b/contracts/validator-manager/PoSValidatorManager.sol @@ -5,7 +5,7 @@ pragma solidity 0.8.25; -import {ValidatorManager} from "./ValidatorManager.sol"; +import {ACP99ValidatorManager} from "./ACP99ValidatorManager.sol"; import {ValidatorMessages} from "./ValidatorMessages.sol"; import { Delegator, @@ -16,7 +16,6 @@ import { } from "./interfaces/IPoSValidatorManager.sol"; import { Validator, - ValidatorRegistrationInput, ValidatorStatus } from "./interfaces/IValidatorManager.sol"; import {IRewardCalculator} from "./interfaces/IRewardCalculator.sol"; @@ -24,6 +23,7 @@ import {WarpMessage} from "@avalabs/subnet-evm-contracts@1.2.0/contracts/interfaces/IWarpMessenger.sol"; import {ReentrancyGuardUpgradeable} from "@openzeppelin/contracts-upgradeable@5.0.2/utils/ReentrancyGuardUpgradeable.sol"; +import {IACP99SecurityModule} from "./interfaces/IACP99SecurityModule.sol"; /** * @dev Implementation of the {IPoSValidatorManager} interface. @@ -32,7 +32,8 @@ import {ReentrancyGuardUpgradeable} from */ abstract contract PoSValidatorManager is IPoSValidatorManager, - ValidatorManager, + IACP99SecurityModule, + ACP99ValidatorManager, ReentrancyGuardUpgradeable { // solhint-disable private-vars-leading-underscore @@ -174,6 +175,62 @@ abstract contract PoSValidatorManager is $._uptimeBlockchainID = uptimeBlockchainID; } + function handleInitializeValidatorRegistration(bytes32 validationID, uint64 weight, bytes calldata args) external { + uint256 stakeAmount = weightToValue(weight); + (uint16 delegationFeeBips, uint64 minStakeDuration) = abi.decode(args, (uint16, uint64)); + _initializeValidatorRegistration(validationID, stakeAmount, delegationFeeBips, minStakeDuration); + } + + function handleCompleteValidatorRegistration(bytes32 validationID) external { + // No-op + } + + function handleInitializeEndValidation(bytes32 validationID, bytes calldata args) external { + (bool force, bool includeUptimeProof, uint32 messageIndex, address rewardRecipient) = abi.decode(args, (bool, bool, uint32, address)); + + bool success = _initializeEndPoSValidation( + validationID, includeUptimeProof, messageIndex, rewardRecipient + ); + if (force) { + return; + } + + if (!success) { + revert ValidatorIneligibleForRewards(validationID); + } + } + + function handleCompleteEndValidation(bytes32 validationID) external { + _completeEndValidation(validationID); + } + + function handleInitializeValidatorWeightChange(bytes32 validationID, uint64 weight, bytes calldata args) external { + (bytes32 delegationID, bytes memory innerArgs) = abi.decode(args, (bytes32, bytes)); + if (_getPoSValidatorManagerStorage()._delegatorStakes[delegationID].status == DelegatorStatus.Unknown) { + address delegatorAddress = abi.decode(innerArgs, (address)); + uint64 delegatorWeight = getValidator(validationID).weight - weight; + _initializeDelegatorRegistration(validationID, delegatorAddress, weightToValue(delegatorWeight)); + } else { + (bool force, bool includeUptimeProof, uint32 messageIndex, address rewardRecipient) = abi.decode(innerArgs, (bool, bool, uint32, address)); + bool success = _initializeEndDelegation(delegationID, includeUptimeProof, messageIndex, rewardRecipient); + if (force) { + return; + } + if (!success) { + revert DelegatorIneligibleForRewards(delegationID); + } + } + } + + function handleCompleteValidatorWeightChange(bytes32, bytes calldata args) external { + (bytes32 delegationID, uint32 messageIndex) = abi.decode(args, (bytes32, uint32)); + if (_getPoSValidatorManagerStorage()._delegatorStakes[delegationID].status == DelegatorStatus.PendingAdded) { + _completeDelegatorRegistration(delegationID, messageIndex); + } else { + _completeEndDelegation(delegationID, messageIndex); + } + } + /** * @notice See {IPoSValidatorManager-submitUptimeProof}. */ @@ -208,73 +265,6 @@ abstract contract PoSValidatorManager is _withdrawValidationRewards($._posValidatorInfo[validationID].owner, validationID); } - /** - * @notice See {IPoSValidatorManager-initializeEndValidation}. - */ - function initializeEndValidation( - bytes32 validationID, - bool includeUptimeProof, - uint32 messageIndex - ) external { - _initializeEndValidationWithCheck( - validationID, includeUptimeProof, messageIndex, address(0) - ); - } - - /** - * @notice See {IPoSValidatorManager-initializeEndValidation}. - */ - function initializeEndValidation( - bytes32 validationID, - bool includeUptimeProof, - uint32 messageIndex, - address rewardRecipient - ) external { - _initializeEndValidationWithCheck( - validationID, includeUptimeProof, messageIndex, rewardRecipient - ); - } - - function _initializeEndValidationWithCheck( - bytes32 validationID, - bool includeUptimeProof, - uint32 messageIndex, - address rewardRecipient - ) internal { - if ( - !_initializeEndPoSValidation( - validationID, includeUptimeProof, messageIndex, rewardRecipient - ) - ) { - revert ValidatorIneligibleForRewards(validationID); - } - } - - /** - * @notice See {IPoSValidatorManager-forceInitializeEndValidation}. - */ - function forceInitializeEndValidation( - bytes32 validationID, - bool includeUptimeProof, - uint32 messageIndex - ) external { - // Ignore the return value here to force end validation, regardless of possible missed rewards - _initializeEndPoSValidation(validationID, includeUptimeProof, messageIndex, address(0)); - } - - /** - * @notice See {IPoSValidatorManager-forceInitializeEndValidation}. - */ - function forceInitializeEndValidation( - bytes32 validationID, - bool includeUptimeProof, - uint32 messageIndex, - address rewardRecipient - ) external { - // Ignore the return value here to force end validation, regardless of possible missed rewards - _initializeEndPoSValidation(validationID, includeUptimeProof, messageIndex, rewardRecipient); - } - function changeValidatorRewardRecipient( bytes32 validationID, address rewardRecipient @@ -374,13 +364,10 @@ abstract contract PoSValidatorManager is return (reward > 0); } - /** - * @notice See {IValidatorManager-completeEndValidation}. - */ - function completeEndValidation(uint32 messageIndex) external nonReentrant { + function _completeEndValidation(bytes32 validationID) internal { PoSValidatorManagerStorage storage $ = _getPoSValidatorManagerStorage(); - (bytes32 validationID, Validator memory validator) = _completeEndValidation(messageIndex); + Validator memory validator = 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. @@ -450,11 +437,11 @@ abstract contract PoSValidatorManager is } function _initializeValidatorRegistration( - ValidatorRegistrationInput calldata registrationInput, + bytes32 validationID, + uint256 stakeAmount, uint16 delegationFeeBips, - uint64 minStakeDuration, - uint256 stakeAmount - ) internal virtual returns (bytes32) { + uint64 minStakeDuration + ) internal { PoSValidatorManagerStorage storage $ = _getPoSValidatorManagerStorage(); // Validate and save the validator requirements if ( @@ -474,16 +461,12 @@ abstract contract PoSValidatorManager is } // Lock the stake in the contract. - uint256 lockedValue = _lock(stakeAmount); - - uint64 weight = valueToWeight(lockedValue); - bytes32 validationID = _initializeValidatorRegistration(registrationInput, weight); + _lock(stakeAmount); $._posValidatorInfo[validationID].owner = _msgSender(); $._posValidatorInfo[validationID].delegationFeeBips = delegationFeeBips; $._posValidatorInfo[validationID].minStakeDuration = minStakeDuration; $._posValidatorInfo[validationID].uptimeSeconds = 0; - return validationID; } /** @@ -573,7 +556,7 @@ abstract contract PoSValidatorManager is /** * @notice See {IPoSValidatorManager-completeDelegatorRegistration}. */ - function completeDelegatorRegistration(bytes32 delegationID, uint32 messageIndex) external { + function _completeDelegatorRegistration(bytes32 delegationID, uint32 messageIndex) internal { PoSValidatorManagerStorage storage $ = _getPoSValidatorManagerStorage(); Delegator memory delegator = $._delegatorStakes[delegationID]; @@ -590,7 +573,7 @@ abstract contract PoSValidatorManager is // In the case where the validator has completed its validation period, we can no // longer stake and should move our status directly to completed and return the stake. if (validator.status == ValidatorStatus.Completed) { - return _completeEndDelegation(delegationID); + return _endDelegation(delegationID); } // Unpack the Warp message @@ -620,73 +603,6 @@ abstract contract PoSValidatorManager is }); } - /** - * @notice See {IPoSValidatorManager-initializeEndDelegation}. - */ - function initializeEndDelegation( - bytes32 delegationID, - bool includeUptimeProof, - uint32 messageIndex - ) external { - _initializeEndDelegationWithCheck( - delegationID, includeUptimeProof, messageIndex, address(0) - ); - } - - /** - * @notice See {IPoSValidatorManager-initializeEndDelegation}. - */ - function initializeEndDelegation( - bytes32 delegationID, - bool includeUptimeProof, - uint32 messageIndex, - address rewardRecipient - ) external { - _initializeEndDelegationWithCheck( - delegationID, includeUptimeProof, messageIndex, rewardRecipient - ); - } - - function _initializeEndDelegationWithCheck( - bytes32 delegationID, - bool includeUptimeProof, - uint32 messageIndex, - address rewardRecipient - ) internal { - if ( - !_initializeEndDelegation( - delegationID, includeUptimeProof, messageIndex, rewardRecipient - ) - ) { - revert DelegatorIneligibleForRewards(delegationID); - } - } - - /** - * @notice See {IPoSValidatorManager-forceInitializeEndDelegation}. - */ - function forceInitializeEndDelegation( - bytes32 delegationID, - bool includeUptimeProof, - uint32 messageIndex - ) external { - // Ignore the return value here to force end delegation, regardless of possible missed rewards - _initializeEndDelegation(delegationID, includeUptimeProof, messageIndex, address(0)); - } - - /** - * @notice See {IPoSValidatorManager-forceInitializeEndDelegation}. - */ - function forceInitializeEndDelegation( - bytes32 delegationID, - bool includeUptimeProof, - uint32 messageIndex, - address rewardRecipient - ) external { - // Ignore the return value here to force end delegation, regardless of possible missed rewards - _initializeEndDelegation(delegationID, includeUptimeProof, messageIndex, rewardRecipient); - } - /** * @dev Helper function that initializes the end of a PoS delegation period. * Returns false if it is possible for the delegator to claim rewards, but it is not eligible. @@ -753,7 +669,7 @@ abstract contract PoSValidatorManager is return (reward > 0); } else if (validator.status == ValidatorStatus.Completed) { _calculateAndSetDelegationReward(delegator, rewardRecipient, delegationID); - _completeEndDelegation(delegationID); + _endDelegation(delegationID); // If the validator has completed, then no further uptimes may be submitted, so we always // end the delegation. return true; @@ -840,10 +756,10 @@ abstract contract PoSValidatorManager is /** * @notice See {IPoSValidatorManager-completeEndDelegation}. */ - function completeEndDelegation( + function _completeEndDelegation( bytes32 delegationID, uint32 messageIndex - ) external nonReentrant { + ) internal nonReentrant { PoSValidatorManagerStorage storage $ = _getPoSValidatorManagerStorage(); Delegator memory delegator = $._delegatorStakes[delegationID]; @@ -873,10 +789,10 @@ abstract contract PoSValidatorManager is } } - _completeEndDelegation(delegationID); + _endDelegation(delegationID); } - function _completeEndDelegation(bytes32 delegationID) internal { + function _endDelegation(bytes32 delegationID) internal { PoSValidatorManagerStorage storage $ = _getPoSValidatorManagerStorage(); Delegator memory delegator = $._delegatorStakes[delegationID]; diff --git a/contracts/validator-manager/ValidatorManager.sol b/contracts/validator-manager/ValidatorManager.sol index b6d6070f3..7880abd26 100644 --- a/contracts/validator-manager/ValidatorManager.sol +++ b/contracts/validator-manager/ValidatorManager.sol @@ -7,14 +7,10 @@ pragma solidity 0.8.25; import {ValidatorMessages} from "./ValidatorMessages.sol"; import { - InitialValidator, IValidatorManager, - PChainOwner, - ConversionData, Validator, ValidatorChurnPeriod, ValidatorManagerSettings, - ValidatorRegistrationInput, ValidatorStatus } from "./interfaces/IValidatorManager.sol"; import { @@ -25,6 +21,8 @@ import {ContextUpgradeable} from "@openzeppelin/contracts-upgradeable@5.0.2/utils/ContextUpgradeable.sol"; import {Initializable} from "@openzeppelin/contracts-upgradeable@5.0.2/proxy/utils/Initializable.sol"; +import {IACP99SecurityModule} from "./interfaces/IACP99SecurityModule.sol"; +import {ValidatorRegistrationInput, ConversionData, PChainOwner, InitialValidator} from "./interfaces/IACP99ValidatorManager.sol"; /** * @dev Implementation of the {IValidatorManager} interface. @@ -141,10 +139,10 @@ abstract contract ValidatorManager is Initializable, ContextUpgradeable, IValida /** * @notice See {IValidatorManager-initializeValidatorSet}. */ - function initializeValidatorSet( + function _initializeValidatorSet( ConversionData calldata conversionData, uint32 messageIndex - ) external { + ) internal { ValidatorManagerStorage storage $ = _getValidatorManagerStorage(); if ($._initializedValidatorSet) { revert InvalidInitializationStatus(); @@ -321,7 +319,7 @@ abstract contract ValidatorManager is Initializable, ContextUpgradeable, IValida /** * @notice See {IValidatorManager-completeValidatorRegistration}. */ - function completeValidatorRegistration(uint32 messageIndex) external { + function _completeValidatorRegistration(uint32 messageIndex) internal returns (bytes32) { ValidatorManagerStorage storage $ = _getValidatorManagerStorage(); (bytes32 validationID, bool validRegistration) = ValidatorMessages .unpackL1ValidatorRegistrationMessage(_getPChainWarpMessage(messageIndex).payload); @@ -343,6 +341,7 @@ abstract contract ValidatorManager is Initializable, ContextUpgradeable, IValida emit ValidationPeriodRegistered( validationID, $._validationPeriods[validationID].weight, block.timestamp ); + return validationID; } /** @@ -429,7 +428,7 @@ abstract contract ValidatorManager is Initializable, ContextUpgradeable, IValida */ function _completeEndValidation(uint32 messageIndex) internal - returns (bytes32, Validator memory) + returns (bytes32) { ValidatorManagerStorage storage $ = _getValidatorManagerStorage(); @@ -466,7 +465,7 @@ abstract contract ValidatorManager is Initializable, ContextUpgradeable, IValida // Emit event. emit ValidationPeriodEnded(validationID, validator.status); - return (validationID, validator); + return validationID; } /** diff --git a/contracts/validator-manager/ValidatorMessages.sol b/contracts/validator-manager/ValidatorMessages.sol index 9adcdc8aa..0d39c479e 100644 --- a/contracts/validator-manager/ValidatorMessages.sol +++ b/contracts/validator-manager/ValidatorMessages.sol @@ -4,7 +4,7 @@ // SPDX-License-Identifier: Ecosystem pragma solidity 0.8.25; -import {PChainOwner, ConversionData} from "./interfaces/IValidatorManager.sol"; +import {PChainOwner, ConversionData} from "./interfaces/IACP99ValidatorManager.sol"; /** * @dev Packing utilities for the Warp message types used by the Validator Manager contracts, as specified in ACP-77: diff --git a/contracts/validator-manager/interfaces/IACP99SecurityModule.sol b/contracts/validator-manager/interfaces/IACP99SecurityModule.sol new file mode 100644 index 000000000..afc32ed56 --- /dev/null +++ b/contracts/validator-manager/interfaces/IACP99SecurityModule.sol @@ -0,0 +1,24 @@ +// (c) 2024, Ava Labs, Inc. All rights reserved. +// See the file LICENSE for licensing terms. + +// SPDX-License-Identifier: Ecosystem + +pragma solidity 0.8.25; + +interface IACP99SecurityModule { + function handleInitializeValidatorRegistration( + bytes32 validationID, + uint64 weight, + bytes calldata args + ) external; + + function handleCompleteValidatorRegistration(bytes32 validationID) external; + + function handleInitializeEndValidation(bytes32 validationID, bytes calldata args) external; + + function handleCompleteEndValidation(bytes32 validationID) external; + + function handleInitializeValidatorWeightChange(bytes32 validationID, uint64 weight, bytes calldata args) external; + + function handleCompleteValidatorWeightChange(bytes32 validationID, bytes calldata args) external; +} \ No newline at end of file diff --git a/contracts/validator-manager/interfaces/IACP99ValidatorManager.sol b/contracts/validator-manager/interfaces/IACP99ValidatorManager.sol new file mode 100644 index 000000000..cc9d1ce89 --- /dev/null +++ b/contracts/validator-manager/interfaces/IACP99ValidatorManager.sol @@ -0,0 +1,71 @@ +// (c) 2024, Ava Labs, Inc. All rights reserved. +// See the file LICENSE for licensing terms. + +// SPDX-License-Identifier: Ecosystem + +pragma solidity 0.8.25; + +/** + * @dev Specifies the owner of a validator's remaining balance or disable owner on the P-Chain. + * P-Chain addresses are also 20-bytes, so we use the address type to represent them. + */ +struct PChainOwner { + uint32 threshold; + address[] addresses; +} + +/** + * @dev Specifies an initial validator, used in the conversion data. + */ +struct InitialValidator { + bytes nodeID; + bytes blsPublicKey; + uint64 weight; +} + +/** + * @dev Description of the conversion data used to convert + * a subnet to an L1 on the P-Chain. + * This data is the pre-image of a hash that is authenticated by the P-Chain + * and verified by the Validator Manager. + */ +struct ConversionData { + bytes32 subnetID; + bytes32 validatorManagerBlockchainID; + address validatorManagerAddress; + InitialValidator[] initialValidators; +} + +/** + * @dev Specifies a validator to register. + */ +struct ValidatorRegistrationInput { + bytes nodeID; + bytes blsPublicKey; + uint64 registrationExpiry; + PChainOwner remainingBalanceOwner; + PChainOwner disableOwner; +} + +interface IACP99ValidatorManager { + function initializeValidatorSet( + ConversionData calldata conversionData, + uint32 messageIndex + ) external; + + function initializeValidatorRegistration( + ValidatorRegistrationInput calldata input, + uint64 weight, + bytes calldata args + ) external returns (bytes32); + + function completeValidatorRegistration(uint32 messageIndex) external; + + function initializeEndValidation(bytes32 validationID, bytes calldata args) external; + + function completeEndValidation(uint32 messageIndex) external; + + function initializeValidatorWeightChange(bytes32 validationID, uint64 weight, bytes calldata args) external; + + function completeValidatorWeightChange(bytes32 validationID, bytes calldata args) external; +} \ No newline at end of file diff --git a/contracts/validator-manager/interfaces/IERC20TokenStakingManager.sol b/contracts/validator-manager/interfaces/IERC20TokenStakingManager.sol deleted file mode 100644 index eb1b56a32..000000000 --- a/contracts/validator-manager/interfaces/IERC20TokenStakingManager.sol +++ /dev/null @@ -1,38 +0,0 @@ -// (c) 2024, Ava Labs, Inc. All rights reserved. -// See the file LICENSE for licensing terms. - -// SPDX-License-Identifier: Ecosystem - -pragma solidity 0.8.25; - -import {ValidatorRegistrationInput} from "./IValidatorManager.sol"; -import {IPoSValidatorManager} from "./IPoSValidatorManager.sol"; - -/** - * Proof of Stake Validator Manager that stakes ERC20 tokens. - */ -interface IERC20TokenStakingManager is IPoSValidatorManager { - /** - * @notice Begins the validator registration process. Locks the specified ERC20 tokens in the contract as the stake. - * @param registrationInput The inputs for a validator registration. - * @param delegationFeeBips The fee that delegators must pay to delegate to this validator. - * @param minStakeDuration The minimum amount of time this validator must be staked for in seconds. - * @param stakeAmount The amount of tokens to stake. - */ - function initializeValidatorRegistration( - ValidatorRegistrationInput calldata registrationInput, - uint16 delegationFeeBips, - uint64 minStakeDuration, - uint256 stakeAmount - ) external returns (bytes32 validationID); - - /** - * @notice Begins the delegator registration process. Locks the specified ERC20 tokens in the contract as the stake. - * @param validationID The ID of the validator to stake to. - * @param stakeAmount The amount of tokens to stake. - */ - function initializeDelegatorRegistration( - bytes32 validationID, - uint256 stakeAmount - ) external returns (bytes32); -} diff --git a/contracts/validator-manager/interfaces/INativeTokenStakingManager.sol b/contracts/validator-manager/interfaces/INativeTokenStakingManager.sol deleted file mode 100644 index c1cc4a2c9..000000000 --- a/contracts/validator-manager/interfaces/INativeTokenStakingManager.sol +++ /dev/null @@ -1,35 +0,0 @@ -// (c) 2024, Ava Labs, Inc. All rights reserved. -// See the file LICENSE for licensing terms. - -// SPDX-License-Identifier: Ecosystem - -pragma solidity 0.8.25; - -import {ValidatorRegistrationInput} from "./IValidatorManager.sol"; -import {IPoSValidatorManager} from "./IPoSValidatorManager.sol"; - -/** - * Proof of Stake Validator Manager that stakes the blockchain's native tokens. - */ -interface INativeTokenStakingManager is IPoSValidatorManager { - /** - * @notice Begins the validator registration process. Locks the provided native asset in the contract as the stake. - * @param registrationInput The inputs for a validator registration. - * @param delegationFeeBips The fee that delegators must pay to delegate to this validator. - * @param minStakeDuration The minimum amount of time this validator must be staked for in seconds. - */ - function initializeValidatorRegistration( - ValidatorRegistrationInput calldata registrationInput, - uint16 delegationFeeBips, - uint64 minStakeDuration - ) external payable returns (bytes32 validationID); - - /** - * @notice Begins the delegator registration process. Locks the provided native asset in the contract as the stake. - * @param validationID The ID of the validator to stake to. - */ - function initializeDelegatorRegistration(bytes32 validationID) - external - payable - returns (bytes32); -} diff --git a/contracts/validator-manager/interfaces/IPoAValidatorManager.sol b/contracts/validator-manager/interfaces/IPoAValidatorManager.sol deleted file mode 100644 index 94c1663d3..000000000 --- a/contracts/validator-manager/interfaces/IPoAValidatorManager.sol +++ /dev/null @@ -1,30 +0,0 @@ -// (c) 2024, Ava Labs, Inc. All rights reserved. -// See the file LICENSE for licensing terms. - -// SPDX-License-Identifier: Ecosystem - -pragma solidity 0.8.25; - -import {IValidatorManager, ValidatorRegistrationInput} from "./IValidatorManager.sol"; - -/** - * @notice Interface for Proof of Authority Validator Manager contracts - */ -interface IPoAValidatorManager is IValidatorManager { - /** - * @notice Begins the validator registration process, and sets the {weight} of the validator. - * @param registrationInput The inputs for a validator registration. - * @param weight The weight of the validator being registered. - */ - function initializeValidatorRegistration( - ValidatorRegistrationInput calldata registrationInput, - uint64 weight - ) external returns (bytes32 validationID); - - /** - * @notice Begins the process of ending an active validation period. The validation period must have been previously - * started by a successful call to {completeValidatorRegistration} with the given validationID. - * @param validationID The ID of the validation period being ended. - */ - function initializeEndValidation(bytes32 validationID) external; -} diff --git a/contracts/validator-manager/interfaces/IPoSValidatorManager.sol b/contracts/validator-manager/interfaces/IPoSValidatorManager.sol index c4c5b7bb4..5bb80ff55 100644 --- a/contracts/validator-manager/interfaces/IPoSValidatorManager.sol +++ b/contracts/validator-manager/interfaces/IPoSValidatorManager.sol @@ -134,138 +134,6 @@ interface IPoSValidatorManager is IValidatorManager { */ function submitUptimeProof(bytes32 validationID, uint32 messageIndex) external; - /** - * @notice Begins the process of ending an active validation period, and reverts if the validation period is not eligible - * for uptime-based rewards. This function is used to exit the validator set when rewards are expected. - * The validation period must have been previously started by a successful call to {completeValidatorRegistration} with the given validationID. - * Any rewards for this validation period will stop accruing when this function is called. - * Note: Reverts if the uptime is not eligible for rewards. - * @param validationID The ID of the validation period being ended. - * @param includeUptimeProof Whether or not an uptime proof is provided for the validation period. If no uptime proof is provided, - * the latest known uptime will be used. - * @param messageIndex The index of the Warp message to be received providing the uptime proof. - */ - function initializeEndValidation( - bytes32 validationID, - bool includeUptimeProof, - uint32 messageIndex - ) external; - - /** - * @notice See {IPoSValidatorManager-initializeEndValidation} for details of the first three parameters - * @param recipientAddress The address to receive the rewards - */ - function initializeEndValidation( - bytes32 validationID, - bool includeUptimeProof, - uint32 messageIndex, - address recipientAddress - ) external; - - /** - * @notice Begins the process of ending an active validation period, but does not revert if the latest known uptime - * is not sufficient to collect uptime-based rewards. This function is used to exit the validator set when rewards are - * not expected. - * The validation period must have been previously started by a successful call to {completeValidatorRegistration} with the given validationID. - * Any rewards for this validation period will stop accruing when this function is called. - * @param validationID The ID of the validation period being ended. - * @param includeUptimeProof Whether or not an uptime proof is provided for the validation period. If no uptime proof is provided, - * the latest known uptime will be used. - * @param messageIndex The index of the Warp message to be received providing the uptime proof. - */ - function forceInitializeEndValidation( - bytes32 validationID, - bool includeUptimeProof, - uint32 messageIndex - ) external; - - /** - * @notice See {IPoSValidatorManager-forceInitializeEndValidation} for details of the first three parameters - * @param recipientAddress Address to receive the rewards. - */ - function forceInitializeEndValidation( - bytes32 validationID, - bool includeUptimeProof, - uint32 messageIndex, - address recipientAddress - ) external; - - /** - * @notice Completes the delegator registration process by submitting an acknowledgement of the registration of a - * validationID from the P-Chain. After this function is called, the validator's weight is updated in the contract state. - * Any P-Chain acknowledgement with a nonce greater than or equal to the nonce used to initialize registration of the - * delegator is valid, as long as that nonce has been sent by the contract. For the purposes of computing delegation rewards, - * the delegation is considered active after this function is completed. - * Note: Only the specified delegation will be marked as registered, even if the validator weight update - * message implicitly includes multiple weight changes. - * @param delegationID The ID of the delegation being registered. - * @param messageIndex The index of the Warp message to be received providing the acknowledgement. - */ - function completeDelegatorRegistration(bytes32 delegationID, uint32 messageIndex) external; - - /** - * @notice Begins the process of removing a delegator from a validation period, and reverts if the delegation is not eligible for rewards. - * The delegator must have been previously registered with the given validationID. For the purposes of computing delegation rewards, - * the delegation period is considered ended when this function is called. Uses the supplied uptime proof to calculate rewards. - * If none is provided in the call, the latest known uptime will be used. Reverts if the uptime is not eligible for rewards. - * Note: This function can only be called by the address that registered the delegation. - * Note: Reverts if the uptime is not eligible for rewards. - * @param delegationID The ID of the delegation being removed. - * @param includeUptimeProof Whether or not an uptime proof is provided for the validation period. - * If the validator has completed its validation period, it has already provided an uptime proof, so {includeUptimeProof} - * will be ignored and can be set to false. If the validator has not completed its validation period and no uptime proof - * is provided, the latest known uptime will be used. - * @param messageIndex If {includeUptimeProof} is true, the index of the Warp message to be received providing the - * uptime proof. - */ - function initializeEndDelegation( - bytes32 delegationID, - bool includeUptimeProof, - uint32 messageIndex - ) external; - - /** - * @notice See {IPoSValidatorManager-initializeEndDelegation} for details of the first three parameters - * @param recipientAddress The address to receive the rewards. - */ - function initializeEndDelegation( - bytes32 delegationID, - bool includeUptimeProof, - uint32 messageIndex, - address recipientAddress - ) external; - - /** - * @notice Begins the process of removing a delegator from a validation period, but does not revert if the delegation is not eligible for rewards. - * The delegator must have been previously registered with the given validationID. For the purposes of computing delegation rewards, - * the delegation period is considered ended when this function is called. Uses the supplied uptime proof to calculate rewards. - * If none is provided in the call, the latest known uptime will be used. Reverts if the uptime is not eligible for rewards. - * Note: This function can only be called by the address that registered the delegation. - * @param delegationID The ID of the delegation being removed. - * @param includeUptimeProof Whether or not an uptime proof is provided for the validation period. - * If the validator has completed its validation period, it has already provided an uptime proof, so {includeUptimeProof} - * will be ignored and can be set to false. If the validator has not completed its validation period and no uptime proof - * is provided, the latest known uptime will be used. - * @param messageIndex If {includeUptimeProof} is true, the index of the Warp message to be received providing the - * uptime proof. - */ - function forceInitializeEndDelegation( - bytes32 delegationID, - bool includeUptimeProof, - uint32 messageIndex - ) external; - - /** - * @notice See {IPoSValidatorManager-forceInitializeEndDelegation} for details of the first three parameters - * @param recipientAddress The address to receive the rewards. - */ - function forceInitializeEndDelegation( - bytes32 delegationID, - bool includeUptimeProof, - uint32 messageIndex, - address recipientAddress - ) external; - /** * @notice Resubmits a delegator registration or delegator end message to be sent to the P-Chain. * Only necessary if the original message can't be delivered due to validator churn. @@ -273,19 +141,6 @@ interface IPoSValidatorManager is IValidatorManager { */ function resendUpdateDelegation(bytes32 delegationID) external; - /** - * @notice Completes the process of ending a delegation by receiving an acknowledgement from the P-Chain. - * After this function is called, the validator's weight is updated in the contract state. - * Any P-Chain acknowledgement with a nonce greater than or equal to the nonce used to initialize the end of the - * delegator's delegation is valid, as long as that nonce has been sent by the contract. This is because the validator - * weight change pertaining to the delegation ending is included in any subsequent validator weight update messages. - * Note: Only the specified delegation will be marked as completed, even if the validator weight update - * message implicitly includes multiple weight changes. - * @param delegationID The ID of the delegation being removed. - * @param messageIndex The index of the Warp message to be received providing the acknowledgement. - */ - function completeEndDelegation(bytes32 delegationID, uint32 messageIndex) external; - /** * @notice Withdraws the delegation fees from completed delegations to the owner of the validator. * @param validationID The ID of the validation period being ended. diff --git a/contracts/validator-manager/interfaces/IValidatorManager.sol b/contracts/validator-manager/interfaces/IValidatorManager.sol index f04629bf5..a24d3bc22 100644 --- a/contracts/validator-manager/interfaces/IValidatorManager.sol +++ b/contracts/validator-manager/interfaces/IValidatorManager.sol @@ -5,6 +5,8 @@ pragma solidity 0.8.25; +import {ConversionData} from "./IACP99ValidatorManager.sol"; + /** * @dev Validator status */ @@ -17,15 +19,6 @@ enum ValidatorStatus { Invalidated } -/** - * @dev Specifies the owner of a validator's remaining balance or disable owner on the P-Chain. - * P-Chain addresses are also 20-bytes, so we use the address type to represent them. - */ -struct PChainOwner { - uint32 threshold; - address[] addresses; -} - /** * @dev Contains the active state of a Validator */ @@ -61,39 +54,6 @@ struct ValidatorManagerSettings { uint8 maximumChurnPercentage; } -/** - * @dev Description of the conversion data used to convert - * a subnet to an L1 on the P-Chain. - * This data is the pre-image of a hash that is authenticated by the P-Chain - * and verified by the Validator Manager. - */ -struct ConversionData { - bytes32 subnetID; - bytes32 validatorManagerBlockchainID; - address validatorManagerAddress; - InitialValidator[] initialValidators; -} - -/** - * @dev Specifies an initial validator, used in the conversion data. - */ -struct InitialValidator { - bytes nodeID; - bytes blsPublicKey; - uint64 weight; -} - -/** - * @dev Specifies a validator to register. - */ -struct ValidatorRegistrationInput { - bytes nodeID; - bytes blsPublicKey; - uint64 registrationExpiry; - PChainOwner remainingBalanceOwner; - PChainOwner disableOwner; -} - /** * @notice Interface for Validator Manager contracts that implement Subnet-only Validator management. */ @@ -171,16 +131,6 @@ interface IValidatorManager { bytes32 setWeightMessageID ); - /** - * @notice Verifies and sets the initial validator set for the chain through a P-Chain SubnetToL1ConversionMessage. - * @param conversionData The subnet conversion message data used to recompute and verify against the conversionID. - * @param messsageIndex The index that contains the SubnetToL1ConversionMessage Warp message containing the conversionID to be verified against the provided {ConversionData} - */ - function initializeValidatorSet( - ConversionData calldata conversionData, - uint32 messsageIndex - ) external; - /** * @notice Resubmits a validator registration message to be sent to the P-Chain. * Only necessary if the original message can't be delivered due to validator churn. @@ -188,28 +138,10 @@ interface IValidatorManager { */ function resendRegisterValidatorMessage(bytes32 validationID) external; - /** - * @notice Completes the validator registration process by returning an acknowledgement of the registration of a - * validationID from the P-Chain. - * @param messageIndex The index of the Warp message to be received providing the acknowledgement. - */ - function completeValidatorRegistration(uint32 messageIndex) external; - /** * @notice Resubmits a validator end message to be sent to the P-Chain. * Only necessary if the original message can't be delivered due to validator churn. * @param validationID The ID of the validation period being ended. */ function resendEndValidatorMessage(bytes32 validationID) external; - - /** - * @notice Completes the process of ending a validation period by receiving an acknowledgement from the P-Chain - * that the validation ID is not active and will never be active in the future. Returns the the stake associated - * with the validation. - * Note: This function can be used for successful validation periods that have been explicitly ended by calling - * {initializeEndValidation} or for validation periods that never began on the P-Chain due to the {registrationExpiry} being reached. - * @param messageIndex The index of the Warp message to be received providing the proof the validation is not active - * and never will be active on the P-Chain. - */ - function completeEndValidation(uint32 messageIndex) external; }