From 0864b83d37070123c673f2ce603a6e0aa3aa8980 Mon Sep 17 00:00:00 2001 From: cam-schultz Date: Tue, 3 Dec 2024 09:18:04 -0600 Subject: [PATCH 1/4] register validator building --- .../ACP99ValidatorManager.sol | 48 +++++++++++ .../validator-manager/ERC20ACP99Manager.sol | 77 +++++++++++++++++ .../validator-manager/PoSValidatorManager.sol | 33 ++++++++ .../validator-manager/ValidatorManager.sol | 7 +- .../interfaces/IACP99SecurityModule.sol | 20 +++++ .../interfaces/IValidatorManager.sol | 82 +++++++++---------- 6 files changed, 223 insertions(+), 44 deletions(-) create mode 100644 contracts/validator-manager/ACP99ValidatorManager.sol create mode 100644 contracts/validator-manager/ERC20ACP99Manager.sol create mode 100644 contracts/validator-manager/interfaces/IACP99SecurityModule.sol diff --git a/contracts/validator-manager/ACP99ValidatorManager.sol b/contracts/validator-manager/ACP99ValidatorManager.sol new file mode 100644 index 000000000..ffa8a5f04 --- /dev/null +++ b/contracts/validator-manager/ACP99ValidatorManager.sol @@ -0,0 +1,48 @@ +// (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 {ConversionData,ValidatorRegistrationInput} from "./interfaces/IValidatorManager.sol"; + +pragma solidity 0.8.25; + +contract ACP99ValidatorManager is 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.handleValidatorRegistration(validationID, weight, args); + return validationID; + } + + function completeValidatorRegistration(uint32 messageIndex) external{ + _completeValidatorRegistration(messageIndex); + } + + function initializeEndValidation() external{} + + function completeEndValidation() external{} + + function initializeValidatorWeightChange() external{} + + function completeValidatorWeightChange() external{} +} \ No newline at end of file diff --git a/contracts/validator-manager/ERC20ACP99Manager.sol b/contracts/validator-manager/ERC20ACP99Manager.sol new file mode 100644 index 000000000..d1309151c --- /dev/null +++ b/contracts/validator-manager/ERC20ACP99Manager.sol @@ -0,0 +1,77 @@ +// (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 {PoSValidatorManager} from "./PoSValidatorManager.sol"; +import {IERC20Mintable} from "./interfaces/IERC20Mintable.sol"; +import {SafeERC20TransferFrom} from "@utilities/SafeERC20TransferFrom.sol"; +import {SafeERC20} from "@openzeppelin/contracts@5.0.2/token/ERC20/utils/SafeERC20.sol"; +import {ValidatorRegistrationInput} from "./interfaces/IValidatorManager.sol"; + + + +pragma solidity 0.8.25; + +contract ERC20ACP99Manager is IACP99SecurityModule, PoSValidatorManager { + using SafeERC20 for IERC20Mintable; + using SafeERC20TransferFrom for IERC20Mintable; + + IERC20Mintable public token; + uint8 public tokenDecimals; + + constructor(IERC20Mintable token_, uint8 tokenDecimals_) { + token = token_; + tokenDecimals = tokenDecimals_; + } + + function handleValidatorRegistration(bytes32 validationID, uint64 weight, bytes calldata args) external { + uint256 stakeAmount = weightToValue(weight); + (uint16 delegationFeeBips, uint64 minStakeDuration) = abi.decode(args, (uint16, uint64)); + _acp99InitValidatorRegistration(validationID, stakeAmount, delegationFeeBips, minStakeDuration); + } + + function handleEndValidation() external { + } + + function handleValidatorWeightChange() external { + } + + // unused + function initializeValidatorRegistration( + ValidatorRegistrationInput calldata registrationInput, + uint16 delegationFeeBips, + uint64 minStakeDuration, + uint256 stakeAmount + ) external nonReentrant returns (bytes32 validationID) { + return _initializeValidatorRegistration( + registrationInput, delegationFeeBips, minStakeDuration, stakeAmount + ); + } + + /** + * @notice See {PoSValidatorManager-_lock} + * Note: Must be guarded with reentrancy guard for safe transfer from. + */ + function _lock(uint256 value) internal virtual override returns (uint256) { + return token.safeTransferFrom(value); + } + + /** + * @notice See {PoSValidatorManager-_unlock} + * Note: Must be guarded with reentrancy guard for safe transfer. + */ + function _unlock(address to, uint256 value) internal virtual override { + token.safeTransfer(to, value); + } + + /** + * @notice See {PoSValidatorManager-_reward} + */ + function _reward(address account, uint256 amount) internal virtual override { + token.mint(account, amount); + } + + +} \ No newline at end of file diff --git a/contracts/validator-manager/PoSValidatorManager.sol b/contracts/validator-manager/PoSValidatorManager.sol index 4243b850b..927bf51e7 100644 --- a/contracts/validator-manager/PoSValidatorManager.sol +++ b/contracts/validator-manager/PoSValidatorManager.sol @@ -486,6 +486,39 @@ abstract contract PoSValidatorManager is return validationID; } + function _acp99InitValidatorRegistration( + bytes32 validationID, + uint256 stakeAmount, + uint16 delegationFeeBips, + uint64 minStakeDuration + ) internal { + PoSValidatorManagerStorage storage $ = _getPoSValidatorManagerStorage(); + // Validate and save the validator requirements + if ( + delegationFeeBips < $._minimumDelegationFeeBips + || delegationFeeBips > MAXIMUM_DELEGATION_FEE_BIPS + ) { + revert InvalidDelegationFee(delegationFeeBips); + } + + if (minStakeDuration < $._minimumStakeDuration) { + revert InvalidMinStakeDuration(minStakeDuration); + } + + // Ensure the weight is within the valid range. + if (stakeAmount < $._minimumStakeAmount || stakeAmount > $._maximumStakeAmount) { + revert InvalidStakeAmount(stakeAmount); + } + + // Lock the stake in the contract. + _lock(stakeAmount); + + $._posValidatorInfo[validationID].owner = _msgSender(); + $._posValidatorInfo[validationID].delegationFeeBips = delegationFeeBips; + $._posValidatorInfo[validationID].minStakeDuration = minStakeDuration; + $._posValidatorInfo[validationID].uptimeSeconds = 0; + } + /** * @notice Converts a token value to a weight. * @param value Token value to convert. diff --git a/contracts/validator-manager/ValidatorManager.sol b/contracts/validator-manager/ValidatorManager.sol index b6d6070f3..859acc27e 100644 --- a/contracts/validator-manager/ValidatorManager.sol +++ b/contracts/validator-manager/ValidatorManager.sol @@ -25,6 +25,7 @@ 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"; /** * @dev Implementation of the {IValidatorManager} interface. @@ -141,10 +142,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 +322,7 @@ abstract contract ValidatorManager is Initializable, ContextUpgradeable, IValida /** * @notice See {IValidatorManager-completeValidatorRegistration}. */ - function completeValidatorRegistration(uint32 messageIndex) external { + function _completeValidatorRegistration(uint32 messageIndex) internal { ValidatorManagerStorage storage $ = _getValidatorManagerStorage(); (bytes32 validationID, bool validRegistration) = ValidatorMessages .unpackL1ValidatorRegistrationMessage(_getPChainWarpMessage(messageIndex).payload); diff --git a/contracts/validator-manager/interfaces/IACP99SecurityModule.sol b/contracts/validator-manager/interfaces/IACP99SecurityModule.sol new file mode 100644 index 000000000..26546bcd1 --- /dev/null +++ b/contracts/validator-manager/interfaces/IACP99SecurityModule.sol @@ -0,0 +1,20 @@ +// (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 { + // Called by the ValidatorManager on initializeRegisterValidator + function handleValidatorRegistration( + bytes32 validationID, + uint64 weight, + bytes calldata args + ) external; + + function handleEndValidation() external; + + // Called by the ValidatorManager on initializeSetValidatorWeight + function handleValidatorWeightChange() external; +} \ No newline at end of file diff --git a/contracts/validator-manager/interfaces/IValidatorManager.sol b/contracts/validator-manager/interfaces/IValidatorManager.sol index f04629bf5..b83e124f5 100644 --- a/contracts/validator-manager/interfaces/IValidatorManager.sol +++ b/contracts/validator-manager/interfaces/IValidatorManager.sol @@ -171,45 +171,45 @@ 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. - * @param validationID The ID of the validation period being registered. - */ - 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; + // /** + // * @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. + // * @param validationID The ID of the validation period being registered. + // */ + // 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; } From 510f5fedf93a5698a1ecc9b72595a572b5266142 Mon Sep 17 00:00:00 2001 From: cam-schultz Date: Tue, 3 Dec 2024 13:34:44 -0600 Subject: [PATCH 2/4] acp99 validator management --- .../ACP99ValidatorManager.sol | 17 +- .../validator-manager/ERC20ACP99Manager.sol | 77 --------- .../ERC20TokenStakingManager.sol | 18 +-- .../NativeTokenStakingManager.sol | 16 +- .../validator-manager/PoAValidatorManager.sol | 43 ++--- .../validator-manager/PoSValidatorManager.sol | 152 +++++------------- .../validator-manager/ValidatorManager.sol | 7 +- .../interfaces/IACP99SecurityModule.sol | 12 +- .../interfaces/IPoSValidatorManager.sol | 56 ------- .../interfaces/IValidatorManager.sol | 82 +++++----- 10 files changed, 134 insertions(+), 346 deletions(-) delete mode 100644 contracts/validator-manager/ERC20ACP99Manager.sol diff --git a/contracts/validator-manager/ACP99ValidatorManager.sol b/contracts/validator-manager/ACP99ValidatorManager.sol index ffa8a5f04..9a4078d40 100644 --- a/contracts/validator-manager/ACP99ValidatorManager.sol +++ b/contracts/validator-manager/ACP99ValidatorManager.sol @@ -9,7 +9,7 @@ import {ConversionData,ValidatorRegistrationInput} from "./interfaces/IValidator pragma solidity 0.8.25; -contract ACP99ValidatorManager is ValidatorManager{ +abstract contract ACP99ValidatorManager is ValidatorManager { IACP99SecurityModule public securityModule; // TODO: calling this should be restricted to...who? @@ -30,17 +30,24 @@ contract ACP99ValidatorManager is ValidatorManager{ bytes calldata args ) external returns (bytes32){ bytes32 validationID = _initializeValidatorRegistration(input, weight); - securityModule.handleValidatorRegistration(validationID, weight, args); + securityModule.handleInitializeValidatorRegistration(validationID, weight, args); return validationID; } function completeValidatorRegistration(uint32 messageIndex) external{ - _completeValidatorRegistration(messageIndex); + bytes32 validationID = _completeValidatorRegistration(messageIndex); + securityModule.handleCompleteValidatorRegistration(validationID); } - function initializeEndValidation() external{} + function initializeEndValidation(bytes32 validationID, bytes calldata args) external{ + _initializeEndValidation(validationID); + securityModule.handleInitializeEndValidation(validationID, args); + } - function completeEndValidation() external{} + function completeEndValidation(uint32 messageIndex) external{ + bytes32 validationID = _completeEndValidation(messageIndex); + securityModule.handleCompleteEndValidation(validationID); + } function initializeValidatorWeightChange() external{} diff --git a/contracts/validator-manager/ERC20ACP99Manager.sol b/contracts/validator-manager/ERC20ACP99Manager.sol deleted file mode 100644 index d1309151c..000000000 --- a/contracts/validator-manager/ERC20ACP99Manager.sol +++ /dev/null @@ -1,77 +0,0 @@ -// (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 {PoSValidatorManager} from "./PoSValidatorManager.sol"; -import {IERC20Mintable} from "./interfaces/IERC20Mintable.sol"; -import {SafeERC20TransferFrom} from "@utilities/SafeERC20TransferFrom.sol"; -import {SafeERC20} from "@openzeppelin/contracts@5.0.2/token/ERC20/utils/SafeERC20.sol"; -import {ValidatorRegistrationInput} from "./interfaces/IValidatorManager.sol"; - - - -pragma solidity 0.8.25; - -contract ERC20ACP99Manager is IACP99SecurityModule, PoSValidatorManager { - using SafeERC20 for IERC20Mintable; - using SafeERC20TransferFrom for IERC20Mintable; - - IERC20Mintable public token; - uint8 public tokenDecimals; - - constructor(IERC20Mintable token_, uint8 tokenDecimals_) { - token = token_; - tokenDecimals = tokenDecimals_; - } - - function handleValidatorRegistration(bytes32 validationID, uint64 weight, bytes calldata args) external { - uint256 stakeAmount = weightToValue(weight); - (uint16 delegationFeeBips, uint64 minStakeDuration) = abi.decode(args, (uint16, uint64)); - _acp99InitValidatorRegistration(validationID, stakeAmount, delegationFeeBips, minStakeDuration); - } - - function handleEndValidation() external { - } - - function handleValidatorWeightChange() external { - } - - // unused - function initializeValidatorRegistration( - ValidatorRegistrationInput calldata registrationInput, - uint16 delegationFeeBips, - uint64 minStakeDuration, - uint256 stakeAmount - ) external nonReentrant returns (bytes32 validationID) { - return _initializeValidatorRegistration( - registrationInput, delegationFeeBips, minStakeDuration, stakeAmount - ); - } - - /** - * @notice See {PoSValidatorManager-_lock} - * Note: Must be guarded with reentrancy guard for safe transfer from. - */ - function _lock(uint256 value) internal virtual override returns (uint256) { - return token.safeTransferFrom(value); - } - - /** - * @notice See {PoSValidatorManager-_unlock} - * Note: Must be guarded with reentrancy guard for safe transfer. - */ - function _unlock(address to, uint256 value) internal virtual override { - token.safeTransfer(to, value); - } - - /** - * @notice See {PoSValidatorManager-_reward} - */ - function _reward(address account, uint256 amount) internal virtual override { - token.mint(account, amount); - } - - -} \ No newline at end of file diff --git a/contracts/validator-manager/ERC20TokenStakingManager.sol b/contracts/validator-manager/ERC20TokenStakingManager.sol index a5e6af656..fa8cef2dd 100644 --- a/contracts/validator-manager/ERC20TokenStakingManager.sol +++ b/contracts/validator-manager/ERC20TokenStakingManager.sol @@ -16,6 +16,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 +24,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 +95,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..3cce186a1 100644 --- a/contracts/validator-manager/NativeTokenStakingManager.sol +++ b/contracts/validator-manager/NativeTokenStakingManager.sol @@ -23,8 +23,7 @@ import {Initializable} from */ contract NativeTokenStakingManager is Initializable, - PoSValidatorManager, - INativeTokenStakingManager + PoSValidatorManager { using Address for address payable; @@ -58,19 +57,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..22a1b7379 100644 --- a/contracts/validator-manager/PoAValidatorManager.sol +++ b/contracts/validator-manager/PoAValidatorManager.sol @@ -5,7 +5,6 @@ pragma solidity 0.8.25; -import {ValidatorManager} from "./ValidatorManager.sol"; import { ValidatorManagerSettings, ValidatorRegistrationInput @@ -14,13 +13,15 @@ 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 +47,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() external { + // No-op + } + + function handleCompleteValidatorWeightChange() external { + // No-op } } diff --git a/contracts/validator-manager/PoSValidatorManager.sol b/contracts/validator-manager/PoSValidatorManager.sol index 927bf51e7..29079e7b2 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, @@ -24,6 +24,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 +33,8 @@ import {ReentrancyGuardUpgradeable} from */ abstract contract PoSValidatorManager is IPoSValidatorManager, - ValidatorManager, + IACP99SecurityModule, + ACP99ValidatorManager, ReentrancyGuardUpgradeable { // solhint-disable private-vars-leading-underscore @@ -174,6 +176,41 @@ 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() external { + } + + function handleCompleteValidatorWeightChange() external { + } + /** * @notice See {IPoSValidatorManager-submitUptimeProof}. */ @@ -208,73 +245,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 +344,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,43 +417,6 @@ abstract contract PoSValidatorManager is } function _initializeValidatorRegistration( - ValidatorRegistrationInput calldata registrationInput, - uint16 delegationFeeBips, - uint64 minStakeDuration, - uint256 stakeAmount - ) internal virtual returns (bytes32) { - PoSValidatorManagerStorage storage $ = _getPoSValidatorManagerStorage(); - // Validate and save the validator requirements - if ( - delegationFeeBips < $._minimumDelegationFeeBips - || delegationFeeBips > MAXIMUM_DELEGATION_FEE_BIPS - ) { - revert InvalidDelegationFee(delegationFeeBips); - } - - if (minStakeDuration < $._minimumStakeDuration) { - revert InvalidMinStakeDuration(minStakeDuration); - } - - // Ensure the weight is within the valid range. - if (stakeAmount < $._minimumStakeAmount || stakeAmount > $._maximumStakeAmount) { - revert InvalidStakeAmount(stakeAmount); - } - - // Lock the stake in the contract. - uint256 lockedValue = _lock(stakeAmount); - - uint64 weight = valueToWeight(lockedValue); - bytes32 validationID = _initializeValidatorRegistration(registrationInput, weight); - - $._posValidatorInfo[validationID].owner = _msgSender(); - $._posValidatorInfo[validationID].delegationFeeBips = delegationFeeBips; - $._posValidatorInfo[validationID].minStakeDuration = minStakeDuration; - $._posValidatorInfo[validationID].uptimeSeconds = 0; - return validationID; - } - - function _acp99InitValidatorRegistration( bytes32 validationID, uint256 stakeAmount, uint16 delegationFeeBips, diff --git a/contracts/validator-manager/ValidatorManager.sol b/contracts/validator-manager/ValidatorManager.sol index 859acc27e..c6888ef50 100644 --- a/contracts/validator-manager/ValidatorManager.sol +++ b/contracts/validator-manager/ValidatorManager.sol @@ -322,7 +322,7 @@ abstract contract ValidatorManager is Initializable, ContextUpgradeable, IValida /** * @notice See {IValidatorManager-completeValidatorRegistration}. */ - function _completeValidatorRegistration(uint32 messageIndex) internal { + function _completeValidatorRegistration(uint32 messageIndex) internal returns (bytes32) { ValidatorManagerStorage storage $ = _getValidatorManagerStorage(); (bytes32 validationID, bool validRegistration) = ValidatorMessages .unpackL1ValidatorRegistrationMessage(_getPChainWarpMessage(messageIndex).payload); @@ -344,6 +344,7 @@ abstract contract ValidatorManager is Initializable, ContextUpgradeable, IValida emit ValidationPeriodRegistered( validationID, $._validationPeriods[validationID].weight, block.timestamp ); + return validationID; } /** @@ -430,7 +431,7 @@ abstract contract ValidatorManager is Initializable, ContextUpgradeable, IValida */ function _completeEndValidation(uint32 messageIndex) internal - returns (bytes32, Validator memory) + returns (bytes32) { ValidatorManagerStorage storage $ = _getValidatorManagerStorage(); @@ -467,7 +468,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/interfaces/IACP99SecurityModule.sol b/contracts/validator-manager/interfaces/IACP99SecurityModule.sol index 26546bcd1..d5073e034 100644 --- a/contracts/validator-manager/interfaces/IACP99SecurityModule.sol +++ b/contracts/validator-manager/interfaces/IACP99SecurityModule.sol @@ -7,14 +7,20 @@ pragma solidity 0.8.25; interface IACP99SecurityModule { // Called by the ValidatorManager on initializeRegisterValidator - function handleValidatorRegistration( + function handleInitializeValidatorRegistration( bytes32 validationID, uint64 weight, bytes calldata args ) external; - function handleEndValidation() external; + function handleCompleteValidatorRegistration(bytes32 validationID) external; + + function handleInitializeEndValidation(bytes32 validationID, bytes calldata args) external; + + function handleCompleteEndValidation(bytes32 validationID) external; // Called by the ValidatorManager on initializeSetValidatorWeight - function handleValidatorWeightChange() external; + function handleInitializeValidatorWeightChange() external; + + function handleCompleteValidatorWeightChange() external; } \ No newline at end of file diff --git a/contracts/validator-manager/interfaces/IPoSValidatorManager.sol b/contracts/validator-manager/interfaces/IPoSValidatorManager.sol index c4c5b7bb4..80f03975b 100644 --- a/contracts/validator-manager/interfaces/IPoSValidatorManager.sol +++ b/contracts/validator-manager/interfaces/IPoSValidatorManager.sol @@ -134,62 +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. diff --git a/contracts/validator-manager/interfaces/IValidatorManager.sol b/contracts/validator-manager/interfaces/IValidatorManager.sol index b83e124f5..f04629bf5 100644 --- a/contracts/validator-manager/interfaces/IValidatorManager.sol +++ b/contracts/validator-manager/interfaces/IValidatorManager.sol @@ -171,45 +171,45 @@ 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. - // * @param validationID The ID of the validation period being registered. - // */ - // 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; + /** + * @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. + * @param validationID The ID of the validation period being registered. + */ + 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; } From d5b5b935f841c5766923ec5f31161e8d5c98f42c Mon Sep 17 00:00:00 2001 From: cam-schultz Date: Tue, 3 Dec 2024 13:56:03 -0600 Subject: [PATCH 3/4] acp99 delegation handling --- .../validator-manager/PoAValidatorManager.sol | 4 +- .../validator-manager/PoSValidatorManager.sol | 106 +++++------------- .../interfaces/IACP99SecurityModule.sol | 6 +- .../interfaces/IPoSValidatorManager.sol | 89 --------------- 4 files changed, 34 insertions(+), 171 deletions(-) diff --git a/contracts/validator-manager/PoAValidatorManager.sol b/contracts/validator-manager/PoAValidatorManager.sol index 22a1b7379..9f786e6a3 100644 --- a/contracts/validator-manager/PoAValidatorManager.sol +++ b/contracts/validator-manager/PoAValidatorManager.sol @@ -70,11 +70,11 @@ contract PoAValidatorManager is IACP99SecurityModule, ACP99ValidatorManager, Own // No-op } - function handleInitializeValidatorWeightChange() external { + function handleInitializeValidatorWeightChange(bytes32 validationID, uint64 weight, bytes calldata args) external { // No-op } - function handleCompleteValidatorWeightChange() external { + 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 29079e7b2..15ba9041b 100644 --- a/contracts/validator-manager/PoSValidatorManager.sol +++ b/contracts/validator-manager/PoSValidatorManager.sol @@ -205,10 +205,31 @@ abstract contract PoSValidatorManager is _completeEndValidation(validationID); } - function handleInitializeValidatorWeightChange() external { + 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() external { + 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); + } } /** @@ -536,7 +557,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]; @@ -553,7 +574,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 @@ -583,73 +604,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. @@ -716,7 +670,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; @@ -803,10 +757,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]; @@ -836,10 +790,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/interfaces/IACP99SecurityModule.sol b/contracts/validator-manager/interfaces/IACP99SecurityModule.sol index d5073e034..afc32ed56 100644 --- a/contracts/validator-manager/interfaces/IACP99SecurityModule.sol +++ b/contracts/validator-manager/interfaces/IACP99SecurityModule.sol @@ -6,7 +6,6 @@ pragma solidity 0.8.25; interface IACP99SecurityModule { - // Called by the ValidatorManager on initializeRegisterValidator function handleInitializeValidatorRegistration( bytes32 validationID, uint64 weight, @@ -19,8 +18,7 @@ interface IACP99SecurityModule { function handleCompleteEndValidation(bytes32 validationID) external; - // Called by the ValidatorManager on initializeSetValidatorWeight - function handleInitializeValidatorWeightChange() external; + function handleInitializeValidatorWeightChange(bytes32 validationID, uint64 weight, bytes calldata args) external; - function handleCompleteValidatorWeightChange() external; + function handleCompleteValidatorWeightChange(bytes32 validationID, bytes calldata args) external; } \ No newline at end of file diff --git a/contracts/validator-manager/interfaces/IPoSValidatorManager.sol b/contracts/validator-manager/interfaces/IPoSValidatorManager.sol index 80f03975b..5bb80ff55 100644 --- a/contracts/validator-manager/interfaces/IPoSValidatorManager.sol +++ b/contracts/validator-manager/interfaces/IPoSValidatorManager.sol @@ -134,82 +134,6 @@ interface IPoSValidatorManager is IValidatorManager { */ function submitUptimeProof(bytes32 validationID, uint32 messageIndex) 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. @@ -217,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. From c77a4809d0e087c396fb021d076049507d4646f3 Mon Sep 17 00:00:00 2001 From: cam-schultz Date: Tue, 3 Dec 2024 14:08:55 -0600 Subject: [PATCH 4/4] IACP99ValidatorManager interface --- .../ACP99ValidatorManager.sol | 12 ++-- .../ERC20TokenStakingManager.sol | 2 - .../NativeTokenStakingManager.sol | 2 - .../validator-manager/PoAValidatorManager.sol | 4 +- .../validator-manager/PoSValidatorManager.sol | 1 - .../validator-manager/ValidatorManager.sol | 5 +- .../validator-manager/ValidatorMessages.sol | 2 +- .../interfaces/IACP99ValidatorManager.sol | 71 ++++++++++++++++++ .../interfaces/IERC20TokenStakingManager.sol | 38 ---------- .../interfaces/INativeTokenStakingManager.sol | 35 --------- .../interfaces/IPoAValidatorManager.sol | 30 -------- .../interfaces/IValidatorManager.sol | 72 +------------------ 12 files changed, 84 insertions(+), 190 deletions(-) create mode 100644 contracts/validator-manager/interfaces/IACP99ValidatorManager.sol delete mode 100644 contracts/validator-manager/interfaces/IERC20TokenStakingManager.sol delete mode 100644 contracts/validator-manager/interfaces/INativeTokenStakingManager.sol delete mode 100644 contracts/validator-manager/interfaces/IPoAValidatorManager.sol diff --git a/contracts/validator-manager/ACP99ValidatorManager.sol b/contracts/validator-manager/ACP99ValidatorManager.sol index 9a4078d40..711b7991b 100644 --- a/contracts/validator-manager/ACP99ValidatorManager.sol +++ b/contracts/validator-manager/ACP99ValidatorManager.sol @@ -5,11 +5,11 @@ import {IACP99SecurityModule} from "./interfaces/IACP99SecurityModule.sol"; import {ValidatorManager} from "./ValidatorManager.sol"; -import {ConversionData,ValidatorRegistrationInput} from "./interfaces/IValidatorManager.sol"; +import {IACP99ValidatorManager, ConversionData, ValidatorRegistrationInput} from "./interfaces/IACP99ValidatorManager.sol"; pragma solidity 0.8.25; -abstract contract ACP99ValidatorManager is ValidatorManager { +abstract contract ACP99ValidatorManager is IACP99ValidatorManager, ValidatorManager { IACP99SecurityModule public securityModule; // TODO: calling this should be restricted to...who? @@ -49,7 +49,11 @@ abstract contract ACP99ValidatorManager is ValidatorManager { securityModule.handleCompleteEndValidation(validationID); } - function initializeValidatorWeightChange() external{} + function initializeValidatorWeightChange(bytes32 validationID, uint64 weight, bytes calldata args) external{ + securityModule.handleInitializeValidatorWeightChange(validationID, weight, args); + } - function completeValidatorWeightChange() external{} + 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 fa8cef2dd..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"; diff --git a/contracts/validator-manager/NativeTokenStakingManager.sol b/contracts/validator-manager/NativeTokenStakingManager.sol index 3cce186a1..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"; diff --git a/contracts/validator-manager/PoAValidatorManager.sol b/contracts/validator-manager/PoAValidatorManager.sol index 9f786e6a3..c20ea1079 100644 --- a/contracts/validator-manager/PoAValidatorManager.sol +++ b/contracts/validator-manager/PoAValidatorManager.sol @@ -6,10 +6,8 @@ pragma solidity 0.8.25; 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"; diff --git a/contracts/validator-manager/PoSValidatorManager.sol b/contracts/validator-manager/PoSValidatorManager.sol index 15ba9041b..bb577323f 100644 --- a/contracts/validator-manager/PoSValidatorManager.sol +++ b/contracts/validator-manager/PoSValidatorManager.sol @@ -16,7 +16,6 @@ import { } from "./interfaces/IPoSValidatorManager.sol"; import { Validator, - ValidatorRegistrationInput, ValidatorStatus } from "./interfaces/IValidatorManager.sol"; import {IRewardCalculator} from "./interfaces/IRewardCalculator.sol"; diff --git a/contracts/validator-manager/ValidatorManager.sol b/contracts/validator-manager/ValidatorManager.sol index c6888ef50..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 { @@ -26,6 +22,7 @@ import {ContextUpgradeable} from 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. 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/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/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; }