Skip to content
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

Custom errors #566

Merged
merged 12 commits into from
Sep 20, 2024

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

4 changes: 3 additions & 1 deletion contracts/validator-manager/ERC20TokenStakingManager.sol
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,9 @@ contract ERC20TokenStakingManager is
onlyInitializing
{
ERC20TokenStakingManagerStorage storage $ = _getERC20StakingManagerStorage();
require(address(token) != address(0), "ERC20TokenStakingManager: zero token address");
if (address(token) == address(0)) {
revert InvalidAddress();
}
$._token = token;
}

Expand Down
218 changes: 109 additions & 109 deletions contracts/validator-manager/PoSValidatorManager.sol
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ abstract contract PoSValidatorManager is
/// @notice The minimum amount of time a validator must be staked for.
uint64 _minimumStakeDuration;
/// @notice The minimum delegation fee percentage, in basis points, required to delegate to a validator.
uint256 _minimumDelegationFeeBips;
uint16 _minimumDelegationFeeBips;
/**
* @notice A multiplier applied to validator's initial stake amount to determine
* the maximum amount of stake a validator can have with delegations.
Expand Down Expand Up @@ -74,6 +74,16 @@ abstract contract PoSValidatorManager is

uint16 public constant MAXIMUM_DELEGATION_FEE_BIPS = 10000;

error InvalidDelegatorStatus();
error InvalidNonce();
error InvalidDelegationID();
error ValidatorNotPoS();
error MaxWeightExceeded();
error InvalidDelegationFee();
error InvalidStakeDuration();
error InvalidStakeAmount();
error InvalidStakeMultiplier();
Comment on lines +77 to +85
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thoughts on adding parameters to a some of these custom errors? For instance:

error InvalidDelegatorStatus(ValidatorStatus status);

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oh that could perhaps also help distinguish between too low / too high for cases like InvalidDelegationFee

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yup we should try to use parameters here


// solhint-disable ordering
function _getPoSValidatorManagerStorage()
private
Expand Down Expand Up @@ -108,25 +118,22 @@ abstract contract PoSValidatorManager is
uint256 minimumStakeAmount,
uint256 maximumStakeAmount,
uint64 minimumStakeDuration,
uint256 minimumDelegationFeeBips,
uint16 minimumDelegationFeeBips,
uint8 maximumStakeMultiplier,
IRewardCalculator rewardCalculator
) internal onlyInitializing {
PoSValidatorManagerStorage storage $ = _getPoSValidatorManagerStorage();
require(minimumDelegationFeeBips > 0, "PoSValidatorManager: zero delegation fee");
require(
minimumDelegationFeeBips <= MAXIMUM_DELEGATION_FEE_BIPS,
"PoSValidatorManager: invalid delegation fee"
);
require(
minimumStakeAmount <= maximumStakeAmount,
"PoSValidatorManager: invalid stake amount range"
);
require(maximumStakeMultiplier > 0, "PoSValidatorManager: zero maximum stake multiplier");
require(
maximumStakeMultiplier <= MAXIMUM_STAKE_MULTIPLIER_LIMIT,
"PoSValidatorManager: invalid maximum stake multiplier"
);
if (minimumDelegationFeeBips == 0 || minimumDelegationFeeBips > MAXIMUM_DELEGATION_FEE_BIPS)
{
revert InvalidDelegationFee();
}
if (minimumStakeAmount > maximumStakeAmount) {
revert InvalidStakeAmount();
}
if (maximumStakeMultiplier == 0 || maximumStakeMultiplier > MAXIMUM_STAKE_MULTIPLIER_LIMIT)
{
revert InvalidStakeMultiplier();
}

$._minimumStakeAmount = minimumStakeAmount;
$._maximumStakeAmount = maximumStakeAmount;
Expand All @@ -141,14 +148,13 @@ abstract contract PoSValidatorManager is

Validator memory validator = getValidator(validationID);

require(
validator.status == ValidatorStatus.Completed,
"PoSValidatorManager: validation period not completed"
);
require(
$._validatorRequirements[validationID].owner == _msgSender(),
"PoSValidatorManager: validator not owned by sender"
);
if (validator.status != ValidatorStatus.Completed) {
revert InvalidValidatorStatus();
}

if ($._validatorRequirements[validationID].owner != _msgSender()) {
revert InvalidAddress();
}

uint256 rewards = $._redeemableValidatorRewards[validationID];
delete $._redeemableValidatorRewards[validationID];
Expand All @@ -170,17 +176,17 @@ abstract contract PoSValidatorManager is
}

// PoS validations can only be ended by their owners.
require(
$._validatorRequirements[validationID].owner == _msgSender(),
"PoSValidatorManager: validator not owned by sender"
);
if ($._validatorRequirements[validationID].owner != _msgSender()) {
revert InvalidAddress();
}

// Check that minimum stake duration has passed.
require(
if (
validator.endedAt
>= validator.startedAt + $._validatorRequirements[validationID].minStakeDuration,
"PoSValidatorManager: minimum stake duration not met"
);
< validator.startedAt + $._validatorRequirements[validationID].minStakeDuration
) {
revert InvalidStakeDuration();
}

if (includeUptimeProof) {
// Uptime proofs include the absolute number of seconds the validator has been active.
Expand Down Expand Up @@ -226,22 +232,22 @@ abstract contract PoSValidatorManager is
function _getUptime(bytes32 validationID, uint32 messageIndex) internal view returns (uint64) {
(WarpMessage memory warpMessage, bool valid) =
WARP_MESSENGER.getVerifiedWarpMessage(messageIndex);
require(valid, "PoSValidatorManager: invalid warp message");
if (!valid) {
revert InvalidWarpMessage();
}

require(
warpMessage.sourceChainID == WARP_MESSENGER.getBlockchainID(),
"PoSValidatorManager: invalid source chain ID"
);
require(
warpMessage.originSenderAddress == address(0),
"PoSValidatorManager: invalid origin sender address"
);
if (warpMessage.sourceChainID != WARP_MESSENGER.getBlockchainID()) {
revert InvalidBlockchainID();
}
if (warpMessage.originSenderAddress != address(0)) {
revert InvalidAddress();
}

(bytes32 uptimeValidationID, uint64 uptime) =
ValidatorMessages.unpackValidationUptimeMessage(warpMessage.payload);
require(
validationID == uptimeValidationID, "PoSValidatorManager: invalid uptime validation ID"
);
if (validationID != uptimeValidationID) {
revert InvalidValidationID();
}

return uptime;
}
Expand All @@ -254,19 +260,21 @@ abstract contract PoSValidatorManager is
) internal virtual returns (bytes32) {
PoSValidatorManagerStorage storage $ = _getPoSValidatorManagerStorage();
// Validate and save the validator requirements
require(
delegationFeeBips >= $._minimumDelegationFeeBips
&& delegationFeeBips <= MAXIMUM_DELEGATION_FEE_BIPS,
"PoSValidatorManager: invalid delegation fee"
);
require(
minStakeDuration >= $._minimumStakeDuration,
"PoSValidatorManager: invalid min stake duration"
);
if (
delegationFeeBips < $._minimumDelegationFeeBips
|| delegationFeeBips > MAXIMUM_DELEGATION_FEE_BIPS
) {
revert InvalidDelegationFee();
}

if (minStakeDuration < $._minimumStakeDuration) {
revert InvalidStakeDuration();
}

// Ensure the weight is within the valid range.
require(stakeAmount >= $._minimumStakeAmount, "PoSValidatorManager: stake amount too low");
require(stakeAmount <= $._maximumStakeAmount, "PoSValidatorManager: stake amount too high");
if (stakeAmount < $._minimumStakeAmount || stakeAmount > $._maximumStakeAmount) {
revert InvalidStakeAmount();
}

// Lock the stake in the contract.
uint256 lockedValue = _lock(stakeAmount);
Expand Down Expand Up @@ -304,17 +312,18 @@ abstract contract PoSValidatorManager is
// Ensure the validation period is active
Validator memory validator = getValidator(validationID);
// Check that the validation ID is a PoS validator
require(_isPoSValidator(validationID), "PoSValidatorManager: not a PoS validator");
require(
validator.status == ValidatorStatus.Active, "PoSValidatorManager: validator not active"
);
if (!_isPoSValidator(validationID)) {
revert ValidatorNotPoS();
}
if (validator.status != ValidatorStatus.Active) {
revert InvalidValidatorStatus();
}

// Update the validator weight
uint64 newValidatorWeight = validator.weight + weight;
require(
newValidatorWeight <= validator.startingWeight * $._maximumStakeMultiplier,
"PoSValidatorManager: maximum validator weight reached"
);
if (newValidatorWeight > validator.startingWeight * $._maximumStakeMultiplier) {
revert MaxWeightExceeded();
}

(uint64 nonce, bytes32 messageID) = _setValidatorWeight(validationID, newValidatorWeight);

Expand Down Expand Up @@ -356,27 +365,22 @@ abstract contract PoSValidatorManager is

Validator memory validator = getValidator(validationID);

// The received nonce should be no greater than the highest sent nonce. This should never
// happen since the staking manager is the only entity that can trigger a weight update
// on the P-Chain.
require(validator.messageNonce >= nonce, "PoSValidatorManager: invalid nonce");

// The nonce should also be greater than or equal to the delegationID's starting nonce. This allows
// a weight update using a higher nonce (which implicitly includes the delegation's weight update)
// to be used to complete registration for an earlier delegation. This is necessary because the P-Chain
// is only willing to sign the latest weight update.
require(
$._delegatorStakes[delegationID].startingNonce <= nonce,
"PoSValidatorManager: nonce does not match"
);
// The received nonce should be no greater than the highest sent nonce, and at least as high as
// the delegation's starting nonce. This allows a weight update using a higher nonce
// (which implicitly includes the delegation's weight update) to be used to complete delisting
// for an earlier delegation. This is necessary because the P-Chain is only willing to sign the latest weight update.
if (
validator.messageNonce < nonce || $._delegatorStakes[delegationID].startingNonce > nonce
) {
revert InvalidNonce();
}

// Ensure the delegator is pending added. Since anybody can call this function once
// delegator registration has been initialized, we need to make sure that this function is only
// callable after that has been done.
require(
$._delegatorStakes[delegationID].status == DelegatorStatus.PendingAdded,
"PoSValidatorManager: delegationID not pending added"
);
if ($._delegatorStakes[delegationID].status != DelegatorStatus.PendingAdded) {
revert InvalidDelegatorStatus();
}
// Update the delegation status
$._delegatorStakes[delegationID].status = DelegatorStatus.Active;
$._delegatorStakes[delegationID].startedAt = uint64(block.timestamp);
Expand Down Expand Up @@ -404,13 +408,13 @@ abstract contract PoSValidatorManager is
Validator memory validator = getValidator(validationID);

// Ensure the delegator is active
require(
delegator.status == DelegatorStatus.Active, "PoSValidatorManager: delegation not active"
);
if (delegator.status != DelegatorStatus.Active) {
revert InvalidDelegatorStatus();
}
// Only the delegation owner can end the delegation.
require(
delegator.owner == _msgSender(), "PoSValidatorManager: delegation not owned by sender"
);
if (delegator.owner != _msgSender()) {
revert InvalidAddress();
}

// Set the delegator status to pending removed, so that it can be properly removed in
// the complete step, even if the delivered nonce is greater than the nonce used to
Expand Down Expand Up @@ -463,17 +467,17 @@ abstract contract PoSValidatorManager is
function resendUpdateDelegation(bytes32 delegationID) external {
PoSValidatorManagerStorage storage $ = _getPoSValidatorManagerStorage();
Delegator memory delegator = $._delegatorStakes[delegationID];
require(
delegator.status == DelegatorStatus.PendingAdded
|| delegator.status == DelegatorStatus.PendingRemoved,
"PoSValidatorManager: delegation status not pending"
);
if (
delegator.status != DelegatorStatus.PendingAdded
&& delegator.status != DelegatorStatus.PendingRemoved
) {
revert InvalidDelegatorStatus();
}

Validator memory validator = getValidator(delegator.validationID);
require(
validator.messageNonce != 0,
"PoSValidatorManager: could not find validator for delegation ID"
);
if (validator.messageNonce == 0) {
revert InvalidDelegationID();
}

// Submit the message to the Warp precompile.
WARP_MESSENGER.sendWarpMessage(
Expand All @@ -499,24 +503,20 @@ abstract contract PoSValidatorManager is
// Once this function completes, the delegation is completed and we can clear it from state.
delete $._delegatorStakes[delegationID];

// The received nonce should be no greater than the highest sent nonce. This should never
// happen since the staking manager is the only entity that can trigger a weight update
// on the P-Chain.
require(validator.messageNonce >= nonce, "PoSValidatorManager: invalid nonce");

// The nonce should also be greater than or equal to the delegationID's ending nonce. This allows
// a weight update using a higher nonce (which implicitly includes the delegation's weight update)
// to be used to complete delisting for an earlier delegation. This is necessary because the P-Chain
// is only willing to sign the latest weight update.
require(delegator.endingNonce <= nonce, "PoSValidatorManager: nonce does not match");
// The received nonce should be no greater than the highest sent nonce, and at least as high as
// the delegation's ending nonce. This allows a weight update using a higher nonce
// (which implicitly includes the delegation's weight update) to be used to complete delisting
// for an earlier delegation. This is necessary because the P-Chain is only willing to sign the latest weight update.
if (validator.messageNonce < nonce || delegator.endingNonce > nonce) {
revert InvalidNonce();
}

// Ensure the delegator is pending removed. Since anybody can call this function once
// end delegation has been initialized, we need to make sure that this function is only
// callable after that has been done.
require(
delegator.status == DelegatorStatus.PendingRemoved,
"PoSValidatorManager: delegation not pending added"
);
if (delegator.status != DelegatorStatus.PendingRemoved) {
revert InvalidDelegatorStatus();
}

uint256 rewards = $._redeemableDelegatorRewards[delegationID];
delete $._redeemableDelegatorRewards[delegationID];
Expand Down
Loading