Skip to content

Commit

Permalink
Merge pull request #528 from ava-labs/delegation-id
Browse files Browse the repository at this point in the history
Delegation ID
  • Loading branch information
cam-schultz authored Sep 5, 2024
2 parents 666f5d7 + aed4ed7 commit 9930e65
Show file tree
Hide file tree
Showing 15 changed files with 623 additions and 594 deletions.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion contracts/staking/ERC20TokenStakingManager.sol
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ contract ERC20TokenStakingManager is
function initializeDelegatorRegistration(
bytes32 validationID,
uint256 delegationAmount
) external {
) external returns (bytes32) {
return _initializeDelegatorRegistration(validationID, _msgSender(), delegationAmount);
}

Expand Down
6 changes: 5 additions & 1 deletion contracts/staking/NativeTokenStakingManager.sol
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,11 @@ contract NativeTokenStakingManager is
* @notice Begins the delegator registration process. Locks the provided native asset in the contract as the delegated stake.
* @param validationID The ID of the validation period being delegated to.
*/
function initializeDelegatorRegistration(bytes32 validationID) external payable {
function initializeDelegatorRegistration(bytes32 validationID)
external
payable
returns (bytes32)
{
return _initializeDelegatorRegistration(validationID, _msgSender(), msg.value);
}

Expand Down
160 changes: 78 additions & 82 deletions contracts/staking/PoSValidatorManager.sol
Original file line number Diff line number Diff line change
Expand Up @@ -28,14 +28,12 @@ abstract contract PoSValidatorManager is IPoSValidatorManager, ValidatorManager
uint64 _minimumStakeDuration;
/// @notice The reward calculator for this validator manager.
IRewardCalculator _rewardCalculator;
/// @notice Maps the validationID to a mapping of delegator address to delegator information.
mapping(bytes32 validationID => mapping(address delegator => Delegator)) _delegatorStakes;
/// @notice Maps the validationID to a mapping of delegator address to pending register delegator messages.
mapping(bytes32 validationID => mapping(address delegator => bytes))
_pendingRegisterDelegatorMessages;
/// @notice Maps the validationID to a mapping of delegator address to pending end delegator messages.
mapping(bytes32 validationID => mapping(address delegator => bytes))
_pendingEndDelegatorMessages;
/// @notice Maps the delegationID to the delegator information.
mapping(bytes32 delegationID => Delegator) _delegatorStakes;
/// @notice Maps the delegationID to pending register delegator messages.
mapping(bytes32 delegationID => bytes) _pendingRegisterDelegatorMessages;
/// @notice Maps the delegationID to pending end delegator messages.
mapping(bytes32 delegationID => bytes) _pendingEndDelegatorMessages;
}
// solhint-enable private-vars-leading-underscore

Expand Down Expand Up @@ -147,9 +145,9 @@ abstract contract PoSValidatorManager is IPoSValidatorManager, ValidatorManager

function _initializeDelegatorRegistration(
bytes32 validationID,
address delegator,
address delegatorAddress,
uint256 delegationAmount
) internal nonReentrant {
) internal nonReentrant returns (bytes32) {
uint64 weight = valueToWeight(_lock(delegationAmount));
PoSValidatorManagerStorage storage $ = _getPoSValidatorManagerStorage();

Expand All @@ -158,29 +156,28 @@ abstract contract PoSValidatorManager is IPoSValidatorManager, ValidatorManager
require(
validator.status == ValidatorStatus.Active, "PoSValidatorManager: validator not active"
);
// Update the validator weight
uint64 newValidatorWeight = validator.weight + weight;
_setValidatorWeight(validationID, newValidatorWeight);

// Ensure the delegator is not already registered
require(
$._delegatorStakes[validationID][delegator].weight == 0,
"PoSValidatorManager: delegator already registered"
);
// Construct the delegation ID. This is guaranteed to be unique since it is
// constructed using a new nonce.
uint64 nonce = _getAndIncrementNonce(validationID);
bytes32 delegationID = keccak256(abi.encodePacked(validationID, delegatorAddress, nonce));

_checkAndUpdateChurnTracker(weight);

// Update the validator weight
validator.weight += weight;
_setValidator(validationID, validator);

// Submit the message to the Warp precompile.
uint64 nonce = _getAndIncrementNonce(validationID);
bytes memory setValidatorWeightPayload = ValidatorMessages
.packSetSubnetValidatorWeightMessage(validationID, nonce, validator.weight);
$._pendingRegisterDelegatorMessages[validationID][delegator] = setValidatorWeightPayload;
.packSetSubnetValidatorWeightMessage(validationID, nonce, newValidatorWeight);
$._pendingRegisterDelegatorMessages[delegationID] = setValidatorWeightPayload;
bytes32 messageID = WARP_MESSENGER.sendWarpMessage(setValidatorWeightPayload);

// Store the delegator information
$._delegatorStakes[validationID][delegator] = Delegator({
// Store the delegation information
$._delegatorStakes[delegationID] = Delegator({
status: DelegatorStatus.PendingAdded,
owner: delegatorAddress,
validationID: validationID,
weight: weight,
startedAt: 0,
endedAt: 0,
Expand All @@ -189,164 +186,163 @@ abstract contract PoSValidatorManager is IPoSValidatorManager, ValidatorManager
});

emit DelegatorAdded({
delegationID: delegationID,
validationID: validationID,
setWeightMessageID: messageID,
delegator: delegator,
delegatorAddress: delegatorAddress,
nonce: nonce,
validatorWeight: newValidatorWeight,
delegatorWeight: weight,
validatorWeight: validator.weight,
nonce: nonce
setWeightMessageID: messageID
});
return delegationID;
}

function resendDelegatorRegistration(bytes32 validationID, address delegator) external {
_checkPendingRegisterDelegatorMessages(validationID, delegator);
function resendDelegatorRegistration(bytes32 delegationID) external {
_checkPendingRegisterDelegatorMessages(delegationID);
PoSValidatorManagerStorage storage $ = _getPoSValidatorManagerStorage();
// Submit the message to the Warp precompile.
WARP_MESSENGER.sendWarpMessage($._pendingRegisterDelegatorMessages[validationID][delegator]);
WARP_MESSENGER.sendWarpMessage($._pendingRegisterDelegatorMessages[delegationID]);
}

function completeDelegatorRegistration(uint32 messageIndex, address delegator) external {
function completeDelegatorRegistration(uint32 messageIndex, bytes32 delegationID) external {
PoSValidatorManagerStorage storage $ = _getPoSValidatorManagerStorage();

// Unpack the Warp message
WarpMessage memory warpMessage = _getPChainWarpMessage(messageIndex);
(bytes32 validationID, uint64 nonce,) =
ValidatorMessages.unpackSubnetValidatorWeightUpdateMessage(warpMessage.payload);
_checkPendingRegisterDelegatorMessages(validationID, delegator);
delete $._pendingRegisterDelegatorMessages[validationID][delegator];
_checkPendingRegisterDelegatorMessages(delegationID);
delete $._pendingRegisterDelegatorMessages[delegationID];

Validator memory validator = _getValidator(validationID);

// The received nonce should be no greater than the highest sent nonce
require(validator.messageNonce >= nonce, "PoSValidatorManager: invalid nonce");
// It should also be greater than or equal to the delegator's starting nonce
// It should also be greater than or equal to the delegationID's starting nonce
require(
$._delegatorStakes[validationID][delegator].startingNonce <= nonce,
$._delegatorStakes[delegationID].startingNonce <= nonce,
"PoSValidatorManager: nonce does not match"
);

require(
$._delegatorStakes[validationID][delegator].status == DelegatorStatus.PendingAdded,
"PoSValidatorManager: delegator not pending added"
$._delegatorStakes[delegationID].status == DelegatorStatus.PendingAdded,
"PoSValidatorManager: delegationID not pending added"
);
// Update the delegator status
$._delegatorStakes[validationID][delegator].status = DelegatorStatus.Active;
$._delegatorStakes[validationID][delegator].startedAt = uint64(block.timestamp);

// Update the delegation status
$._delegatorStakes[delegationID].status = DelegatorStatus.Active;
$._delegatorStakes[delegationID].startedAt = uint64(block.timestamp);
emit DelegatorRegistered({
delegationID: delegationID,
validationID: validationID,
delegator: delegator,
nonce: nonce,
startTime: block.timestamp
});
}

function initializeEndDelegation(
bytes32 validationID,
bytes32 delegationID,
bool includeUptimeProof,
uint32 messageIndex
) external {
PoSValidatorManagerStorage storage $ = _getPoSValidatorManagerStorage();
bytes32 validationID = $._delegatorStakes[delegationID].validationID;

uint64 uptime;
if (includeUptimeProof) {
uptime = _getUptime(validationID, messageIndex);
}

// TODO: Calculate the delegator's reward, but do not unlock it

PoSValidatorManagerStorage storage $ = _getPoSValidatorManagerStorage();

// Ensure the delegator is active
Delegator memory delegator = $._delegatorStakes[validationID][_msgSender()];
Delegator memory delegator = $._delegatorStakes[delegationID];
require(
delegator.owner == _msgSender(), "PoSValidatorManager: delegation not owned by sender"
);
require(
delegator.status == DelegatorStatus.Active, "PoSValidatorManager: delegator not active"
delegator.status == DelegatorStatus.Active, "PoSValidatorManager: delegation not active"
);
uint64 nonce = _getAndIncrementNonce(validationID);
delegator.status = DelegatorStatus.PendingRemoved;
delegator.endedAt = uint64(block.timestamp);
delegator.endingNonce = nonce;

$._delegatorStakes[validationID][_msgSender()] = delegator;
$._delegatorStakes[delegationID] = delegator;

Validator memory validator = _getValidator(validationID);
require(validator.weight > delegator.weight, "PoSValidatorManager: Invalid weight");
validator.weight -= delegator.weight;
_setValidator(validationID, validator);
uint64 newValidatorWeight = validator.weight - delegator.weight;
_setValidatorWeight(validationID, newValidatorWeight);

// Submit the message to the Warp precompile.
bytes memory setValidatorWeightPayload = ValidatorMessages
.packSetSubnetValidatorWeightMessage(validationID, nonce, validator.weight);
$._pendingEndDelegatorMessages[validationID][_msgSender()] = setValidatorWeightPayload;
.packSetSubnetValidatorWeightMessage(validationID, nonce, newValidatorWeight);
$._pendingEndDelegatorMessages[delegationID] = setValidatorWeightPayload;
bytes32 messageID = WARP_MESSENGER.sendWarpMessage(setValidatorWeightPayload);

emit DelegatorRemovalInitialized({
delegationID: delegationID,
validationID: validationID,
setWeightMessageID: messageID,
delegator: _msgSender(),
validatorWeight: validator.weight,
nonce: nonce,
endTime: block.timestamp
validatorWeight: newValidatorWeight,
endTime: block.timestamp,
setWeightMessageID: messageID
});
}

function resendEndDelegation(bytes32 validationID, address delegator) external {
_checkPendingEndDelegatorMessage(validationID, delegator);
function resendEndDelegation(bytes32 delegationID) external {
_checkPendingEndDelegatorMessage(delegationID);
PoSValidatorManagerStorage storage $ = _getPoSValidatorManagerStorage();
WARP_MESSENGER.sendWarpMessage($._pendingEndDelegatorMessages[validationID][delegator]);
WARP_MESSENGER.sendWarpMessage($._pendingEndDelegatorMessages[delegationID]);
}

Check warning

Code scanning / Slither

Unused return Medium


function completeEndDelegation(uint32 messageIndex, address delegator) external {
function completeEndDelegation(uint32 messageIndex, bytes32 delegationID) external {
PoSValidatorManagerStorage storage $ = _getPoSValidatorManagerStorage();

// Unpack the Warp message
WarpMessage memory warpMessage = _getPChainWarpMessage(messageIndex);
(bytes32 validationID, uint64 nonce,) =
ValidatorMessages.unpackSubnetValidatorWeightUpdateMessage(warpMessage.payload);
_checkPendingEndDelegatorMessage(validationID, delegator);
delete $._pendingEndDelegatorMessages[validationID][delegator];
_checkPendingEndDelegatorMessage(delegationID);
delete $._pendingEndDelegatorMessages[delegationID];

Validator memory validator = _getValidator(validationID);
// The received nonce should be no greater than the highest sent nonce
require(validator.messageNonce >= nonce, "PoSValidatorManager: invalid nonce");
// It should also be greater than or equal to the delegator's ending nonce
require(
$._delegatorStakes[validationID][delegator].endingNonce <= nonce,
$._delegatorStakes[delegationID].endingNonce <= nonce,
"PoSValidatorManager: nonce does not match"
);

require(
$._delegatorStakes[validationID][delegator].status == DelegatorStatus.PendingRemoved,
"PoSValidatorManager: delegator not pending added"
$._delegatorStakes[delegationID].status == DelegatorStatus.PendingRemoved,
"PoSValidatorManager: delegation not pending added"
);

// Update the delegator status
$._delegatorStakes[validationID][delegator].status = DelegatorStatus.Completed;
$._delegatorStakes[delegationID].status = DelegatorStatus.Completed;

// TODO: Unlock the delegator's stake and their reward

emit DelegationEnded(validationID, delegator, nonce);
emit DelegationEnded(delegationID, validationID, nonce);
}

function _checkPendingEndDelegatorMessage(
bytes32 validationID,
address delegator
) private view {
function _checkPendingEndDelegatorMessage(bytes32 delegationID) private view {
PoSValidatorManagerStorage storage $ = _getPoSValidatorManagerStorage();
require(
$._pendingEndDelegatorMessages[validationID][delegator].length > 0
&& $._delegatorStakes[validationID][delegator].status == DelegatorStatus.PendingRemoved,
"PoSValidatorManager: delegator removal not pending"
$._pendingEndDelegatorMessages[delegationID].length > 0
&& $._delegatorStakes[delegationID].status == DelegatorStatus.PendingRemoved,
"PoSValidatorManager: delegation removal not pending"
);
}

function _checkPendingRegisterDelegatorMessages(
bytes32 validationID,
address delegator
) private view {
function _checkPendingRegisterDelegatorMessages(bytes32 delegationID) private view {
PoSValidatorManagerStorage storage $ = _getPoSValidatorManagerStorage();
require(
$._pendingRegisterDelegatorMessages[validationID][delegator].length > 0
&& $._delegatorStakes[validationID][delegator].status == DelegatorStatus.PendingAdded,
"PoSValidatorManager: delegator registration not pending"
$._pendingRegisterDelegatorMessages[delegationID].length > 0
&& $._delegatorStakes[delegationID].status == DelegatorStatus.PendingAdded,
"PoSValidatorManager: delegation registration not pending"
);
}
}
4 changes: 2 additions & 2 deletions contracts/staking/ValidatorManager.sol
Original file line number Diff line number Diff line change
Expand Up @@ -379,8 +379,8 @@ abstract contract ValidatorManager is
return $._validationPeriods[validationID];
}

function _setValidator(bytes32 validationID, Validator memory validator) internal {
function _setValidatorWeight(bytes32 validationID, uint64 weight) internal {
ValidatorManagerStorage storage $ = _getValidatorManagerStorage();
$._validationPeriods[validationID] = validator;
$._validationPeriods[validationID].weight = weight;
}
}
5 changes: 4 additions & 1 deletion contracts/staking/interfaces/IERC20TokenStakingManager.sol
Original file line number Diff line number Diff line change
Expand Up @@ -21,5 +21,8 @@ interface IERC20TokenStakingManager is IPoSValidatorManager {
bytes memory blsPublicKey
) external returns (bytes32 validationID);

function initializeDelegatorRegistration(bytes32 validationID, uint256 stakeAmount) external;
function initializeDelegatorRegistration(
bytes32 validationID,
uint256 stakeAmount
) external returns (bytes32);
}
5 changes: 4 additions & 1 deletion contracts/staking/interfaces/INativeTokenStakingManager.sol
Original file line number Diff line number Diff line change
Expand Up @@ -20,5 +20,8 @@ interface INativeTokenStakingManager is IPoSValidatorManager {
bytes memory blsPublicKey
) external payable returns (bytes32 validationID);

function initializeDelegatorRegistration(bytes32 validationID) external payable;
function initializeDelegatorRegistration(bytes32 validationID)
external
payable
returns (bytes32);
}
Loading

0 comments on commit 9930e65

Please sign in to comment.