Skip to content

Commit

Permalink
Merge pull request #566 from ava-labs/custom-errors
Browse files Browse the repository at this point in the history
Custom errors
  • Loading branch information
cam-schultz committed Sep 20, 2024
2 parents 4149155 + f73d2d0 commit c54321c
Show file tree
Hide file tree
Showing 11 changed files with 305 additions and 266 deletions.

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();

// 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

0 comments on commit c54321c

Please sign in to comment.