-
Notifications
You must be signed in to change notification settings - Fork 27
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[Proposed] ACP-99: Implement using composition - ValidatorManager as single entry point #668
base: main
Are you sure you want to change the base?
Changes from all commits
0864b83
510f5fe
d5b5b93
c77a480
0e57f27
ed87a6d
05d07ba
da6f676
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
package argumentsexternal | ||
|
||
import "github.com/ava-labs/subnet-evm/accounts/abi" | ||
|
||
var ( | ||
initializeValidatorRegistrationArgsType abi.Type | ||
initializeEndValidationArgsType abi.Type | ||
) | ||
|
||
func init() { | ||
var err error | ||
initializeValidatorRegistrationArgsType, err = abi.NewType("tuple", "struct Overloader.F", []abi.ArgumentMarshaling{ | ||
{Name: "delegationFeeBips", Type: "uint16"}, | ||
{Name: "minStakeDuration", Type: "uint64"}, | ||
}) | ||
if err != nil { | ||
panic("failed to create InitializeValidatorRegistrationArgs ABI type") | ||
} | ||
|
||
initializeEndValidationArgsType, err = abi.NewType("tuple", "struct Overloader.F", []abi.ArgumentMarshaling{ | ||
{Name: "force", Type: "bool"}, | ||
{Name: "includeUptimeProof", Type: "bool"}, | ||
{Name: "messageIndex", Type: "uint32"}, | ||
{Name: "rewardRecipient", Type: "address"}, | ||
}) | ||
if err != nil { | ||
panic("failed to create InitializeEndValidationArgs ABI type") | ||
} | ||
} | ||
|
||
func (a *InitializeValidatorRegistrationArgs) Pack() ([]byte, error) { | ||
args := abi.Arguments{ | ||
{ | ||
Name: "initializeValidatorRegistrationArgs", | ||
Type: initializeValidatorRegistrationArgsType, | ||
}, | ||
} | ||
return args.Pack(a) | ||
} | ||
|
||
func (a *InitializeEndValidationArgs) Pack() ([]byte, error) { | ||
args := abi.Arguments{ | ||
{ | ||
Name: "initializeEndValidationArgs", | ||
Type: initializeEndValidationArgsType, | ||
}, | ||
} | ||
return args.Pack(a) | ||
} |
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,115 @@ | ||
// (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"; | ||
import {ICMInitializable} from "@utilities/ICMInitializable.sol"; | ||
import {ValidatorManagerSettings} from "./interfaces/IValidatorManager.sol"; | ||
|
||
pragma solidity 0.8.25; | ||
|
||
contract ACP99ValidatorManager is IACP99ValidatorManager, ValidatorManager { | ||
struct ACP99ValidatorManagerStorage { | ||
IACP99SecurityModule securityModule; | ||
} | ||
// keccak256(abi.encode(uint256(keccak256("avalanche-icm.storage.ACP99ValidatorManager")) - 1)) & ~bytes32(uint256(0xff)); | ||
bytes32 public constant ACP_99_VALIDATOR_MANAGER_STORAGE_LOCATION = | ||
0x6d7896c90f86967e463241c430aa4c1ef638639857cb8d4f18c905fa5443d600; | ||
|
||
function _getACP99ValidatorManagerStorage() | ||
private | ||
pure | ||
returns (ACP99ValidatorManagerStorage storage $) | ||
{ | ||
// solhint-disable-next-line no-inline-assembly | ||
assembly { | ||
$.slot := ACP_99_VALIDATOR_MANAGER_STORAGE_LOCATION | ||
} | ||
} | ||
|
||
constructor(ICMInitializable init) { | ||
if (init == ICMInitializable.Disallowed) { | ||
_disableInitializers(); | ||
} | ||
} | ||
|
||
function initialize(ValidatorManagerSettings calldata settings, IACP99SecurityModule securityModule) external initializer { | ||
__ACP99ValidatorManager_init(settings, securityModule); | ||
} | ||
|
||
// TODO: calling this should be restricted to...who? | ||
function setSecurityModule(IACP99SecurityModule securityModule) external { | ||
_getACP99ValidatorManagerStorage().securityModule = securityModule; | ||
} | ||
|
||
function getSecurityModule() external view returns (IACP99SecurityModule) { | ||
return _getACP99ValidatorManagerStorage().securityModule; | ||
} | ||
|
||
function __ACP99ValidatorManager_init(ValidatorManagerSettings calldata settings, IACP99SecurityModule securityModule) internal onlyInitializing { | ||
__ValidatorManager_init(settings); | ||
__ACP99ValidatorManager_init_unchained(securityModule); | ||
} | ||
|
||
function __ACP99ValidatorManager_init_unchained(IACP99SecurityModule securityModule) internal onlyInitializing { | ||
ACP99ValidatorManagerStorage storage $ = _getACP99ValidatorManagerStorage(); | ||
$.securityModule = securityModule; | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should the security module itself control its own upgrades? If not, should there be a |
||
|
||
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); | ||
ACP99ValidatorManagerStorage storage $ = _getACP99ValidatorManagerStorage(); | ||
// address securityModule = address($.securityModule); | ||
|
||
// // Delegate call so that the sender can approval ERC20 transfers by the validator manager | ||
// (bool success, bytes memory data) = securityModule.delegatecall(abi.encodeWithSelector($.securityModule.handleInitializeValidatorRegistration.selector, validationID, weight, args)); | ||
// require(success, string(data)); | ||
|
||
$.securityModule.handleInitializeValidatorRegistration(validationID, _msgSender(), weight, args); | ||
return validationID; | ||
} | ||
|
||
function completeValidatorRegistration(uint32 messageIndex) external{ | ||
bytes32 validationID = _completeValidatorRegistration(messageIndex); | ||
_getACP99ValidatorManagerStorage().securityModule.handleCompleteValidatorRegistration(validationID); | ||
} | ||
|
||
function initializeEndValidation(bytes32 validationID, bytes calldata args) external{ | ||
_initializeEndValidation(validationID); | ||
_getACP99ValidatorManagerStorage().securityModule.handleInitializeEndValidation(validationID, args); | ||
} | ||
|
||
function completeEndValidation(uint32 messageIndex) external{ | ||
bytes32 validationID = _completeEndValidation(messageIndex); | ||
ACP99ValidatorManagerStorage storage $ = _getACP99ValidatorManagerStorage(); | ||
// address securityModule = address($.securityModule); | ||
|
||
// (bool success, bytes memory data) = securityModule.delegatecall(abi.encodeWithSelector($.securityModule.handleCompleteEndValidation.selector, validationID)); | ||
// require(success, string(data)); | ||
|
||
$.securityModule.handleCompleteEndValidation(validationID); | ||
} | ||
|
||
function initializeValidatorWeightChange(bytes32 validationID, uint64 weight, bytes calldata args) external{ | ||
(uint64 nonce, ) = _setValidatorWeight(validationID, weight); | ||
_getACP99ValidatorManagerStorage().securityModule.handleInitializeValidatorWeightChange(validationID, weight, nonce, args); | ||
} | ||
|
||
function completeValidatorWeightChange(bytes32 validationID, bytes calldata args) external{ | ||
_getACP99ValidatorManagerStorage().securityModule.handleCompleteValidatorWeightChange(validationID, args); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
// (c) 2024, Ava Labs, Inc. All rights reserved. | ||
// See the file LICENSE for licensing terms. | ||
|
||
// SPDX-License-Identifier: Ecosystem | ||
|
||
pragma solidity 0.8.25; | ||
|
||
struct InitializeValidatorRegistrationArgs { | ||
uint16 delegationFeeBips; | ||
uint64 minStakeDuration; | ||
} | ||
|
||
struct InitializeEndValidationArgs { | ||
bool force; | ||
bool includeUptimeProof; | ||
uint32 messageIndex; | ||
address rewardRecipient; | ||
} | ||
|
||
library Arguments { | ||
function decodeInitializeValidatorRegistrationArgs(bytes calldata args) internal pure returns (InitializeValidatorRegistrationArgs memory) { | ||
return abi.decode(args, (InitializeValidatorRegistrationArgs)); | ||
} | ||
|
||
function decodeInitializeEndValidationArgs(bytes calldata args) internal pure returns (InitializeEndValidationArgs memory) { | ||
return abi.decode(args, (InitializeEndValidationArgs)); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
// (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 {InitializeEndValidationArgs, InitializeValidatorRegistrationArgs} from "./Arguments.sol"; | ||
|
||
contract ArgumentsExternal { | ||
function decodeInitializeEndValidationArgs(bytes calldata args) external pure returns (InitializeEndValidationArgs memory) { | ||
return abi.decode(args, (InitializeEndValidationArgs)); | ||
} | ||
|
||
function decodeInitializeValidatorRegistrationArgs(bytes calldata args) external pure returns (InitializeValidatorRegistrationArgs memory) { | ||
return abi.decode(args, (InitializeValidatorRegistrationArgs)); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -7,24 +7,22 @@ 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"; | ||
import {Initializable} from | ||
"@openzeppelin/[email protected]/proxy/utils/Initializable.sol"; | ||
import {SafeERC20} from "@openzeppelin/[email protected]/token/ERC20/utils/SafeERC20.sol"; | ||
|
||
|
||
/** | ||
* @dev Implementation of the {IERC20TokenStakingManager} interface. | ||
* | ||
* @custom:security-contact https://github.com/ava-labs/teleporter/blob/main/SECURITY.md | ||
*/ | ||
contract ERC20TokenStakingManager is | ||
Initializable, | ||
PoSValidatorManager, | ||
IERC20TokenStakingManager | ||
PoSValidatorManager | ||
{ | ||
using SafeERC20 for IERC20Mintable; | ||
using SafeERC20TransferFrom for IERC20Mintable; | ||
|
@@ -95,30 +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} | ||
*/ | ||
function initializeDelegatorRegistration( | ||
bytes32 validationID, | ||
uint256 delegationAmount | ||
) external nonReentrant returns (bytes32) { | ||
return _initializeDelegatorRegistration(validationID, _msgSender(), delegationAmount); | ||
} | ||
|
||
/** | ||
* @notice Returns the ERC20 token being staked | ||
*/ | ||
|
@@ -130,8 +104,8 @@ contract ERC20TokenStakingManager is | |
* @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 _getERC20StakingManagerStorage()._token.safeTransferFrom(value); | ||
function _lock(address sender, uint256 value) internal virtual override returns (uint256) { | ||
return _getERC20StakingManagerStorage()._token.safeTransferFrom(sender, value); | ||
} | ||
|
||
/** | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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/[email protected]/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,35 +55,10 @@ 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}. | ||
*/ | ||
function initializeDelegatorRegistration(bytes32 validationID) | ||
external | ||
payable | ||
nonReentrant | ||
returns (bytes32) | ||
{ | ||
return _initializeDelegatorRegistration(validationID, _msgSender(), msg.value); | ||
} | ||
|
||
/** | ||
* @notice See {PoSValidatorManager-_lock} | ||
*/ | ||
function _lock(uint256 value) internal virtual override returns (uint256) { | ||
function _lock(address, uint256 value) internal virtual override returns (uint256) { | ||
return value; | ||
} | ||
|
||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
😜