Skip to content

Commit

Permalink
docs: update lst restaker requirements
Browse files Browse the repository at this point in the history
  • Loading branch information
shaspitz committed Jun 27, 2024
1 parent 092c1ad commit 1b59145
Show file tree
Hide file tree
Showing 3 changed files with 57 additions and 17 deletions.
6 changes: 0 additions & 6 deletions contracts/contracts/validator-registry/avs/MevCommitAVS.sol
Original file line number Diff line number Diff line change
Expand Up @@ -394,14 +394,8 @@ contract MevCommitAVS is IMevCommitAVS, MevCommitAVSStorage,
}

/// @dev Internal function to register an LST restaker.
/// @notice For UX purposes each chosen validator must be "opted-in" when an LST restaker first registers.
/// However a chosen validator may later become not "opted-in" as defined in _isValidatorOptedIn(),
/// which will affect rewards/points earned by the LST restaker.
function _registerLSTRestaker(bytes[] calldata chosenValidators) internal {
require(chosenValidators.length > 0, "LST restaker must choose at least one validator");
for (uint256 i = 0; i < chosenValidators.length; i++) {
require(_isValidatorOptedIn(chosenValidators[i]), "chosen validator must be opted in");
}
uint256 stratLen = _strategyManager.stakerStrategyListLength(msg.sender);
require(stratLen > 0, "LST restaker must have deposited into at least one strategy");
lstRestakerRegistrations[msg.sender] = LSTRestakerRegistrationInfo({
Expand Down
28 changes: 21 additions & 7 deletions contracts/contracts/validator-registry/avs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,25 +40,39 @@ Deregistration requires calling `requestValidatorsDeregistration`, waiting a con

LST restakers are also able to register with our avs by:

1. Delegating to an Operator who's registered with the mev-commit AVS.
2. Calling `registerLSTRestaker` with one or more chosen validator pubkey(s). These chosen validators must be opted-in to the mev-commit protocol as described above.
1. Depositing into at least one strategy with eigenlayer core.
2. Delegating to an Operator who's registered with the mev-commit AVS.
3. Calling `registerLSTRestaker` with one or more chosen validator pubkey(s).

```solidity
function registerLSTRestaker(bytes[] calldata chosenValidators) external onlyNonRegisteredLstRestaker() onlySenderWithRegisteredOperator()
```

LST restakers who register in this way will receive points or rewards commensurate with their chosen validator(s) correctly following the protocol. Further, any one of these chosen validators being frozen will result in a corresponding freeze of points accrual for the LST restaker. When an LST restaker chooses multiple validators, attribution is split evenly between the validators.
LST restakers will receive points/rewards commensurate with their chosen validator(s) being opted-in over time. Nothing enforces that validators chosen by LST restakers must be "opted-in" as described above. That is, responsibility is left up to the LST restaker as to choosing validators that are, and will stay, opted-in. When an LST restaker chooses multiple validators, attribution is split evenly between the validators.

Validator opt-in state can be queried with `isValidatorOptedIn()`. This query offers concrete criteria that must be true for an LST restaker to accrue points/rewards over time from a chosen validator.

```solidity
function isValidatorOptedIn(bytes calldata valPubKey) returns (bool) {
bool isValRegistered = validatorRegistrations[valPubKey].exists;
bool isFrozen = validatorRegistrations[valPubKey].freezeHeight.exists;
bool isDeregRequested = validatorRegistrations[valPubKey].deregRequestHeight.exists;
IEigenPod pod = _eigenPodManager.getPod(validatorRegistrations[valPubKey].podOwner);
bool isValActive = pod.validatorPubkeyToInfo(valPubKey).status == IEigenPod.VALIDATOR_STATUS.ACTIVE;
address delegatedOperator = _delegationManager.delegatedTo(validatorRegistrations[valPubKey].podOwner);
bool isOperatorRegistered = operatorRegistrations[delegatedOperator].exists;
return isValRegistered && !isFrozen && !isDeregRequested && isValActive && isOperatorRegistered;
}
```

Since validators are chosen in sets, an LST restaker can only choose a new set of validators by deregistering, and registering again with the new set. This simplifies contract implementation and enforces an LST restaker is responsible for the actions of its chosen validator(s).

Points/rewards for LST restakers would be computed off-chain, with heavy use of indexed events. As there is not an efficient on-chain mapping from each validator to the set of LST restakers who've chosen that validator. When a rewards/points system is introduced, it may consider the following information (and possibly more):

* Opt-in state over time of the LST restaker's chosen validator(s), as defined above.
* The block height when the LST restaker registered with the AVS, requested deregistration, and/or deregistered.
* The amount and denomination of LST that the restaker has delegated to a mev-commit registered Operator. Changes in LST delegation via the eigenlayer core contracts will affect point/reward accrual.
* The amount and denomination of LST that the restaker delegated to a mev-commit registered Operator over time. Changes in LST delegation via the eigenlayer core contracts will affect point/reward accrual.
* Operator deregistration events, if for example an LST restaker's delegated Operator is deregistered with the mev-commit AVS.
* Validator deregistration events, if for example an LST restaker's chosen validator is deregistered with the mev-commit AVS.
* Validator eigenPod events, if for example an LST restaker's chosen validator's eigenPod status changes from `ACTIVE` to `WITHDRAWN`.
* Freeze/Unfreeze events relevant to an LST restaker's chosen validator(s).
* Correctly proposed blocks by the LST restaker's chosen validator(s).

Deregistration requires the restaker calling `requestLSTRestakerDeregistration`, waiting a configurable amount of blocks, then calling `deregisterLSTRestaker`.
Expand Down
40 changes: 36 additions & 4 deletions contracts/test/validator-registry/avs/MevCommitAVSTest.sol
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ contract MevCommitAVSTest is Test {
testRegisterOperator();

address otherAcct = address(0x777);
vm.expectRevert("sender must be operator or MevCommitAVS owner");
vm.expectRevert("sender must be operator");
vm.prank(otherAcct);
mevCommitAVS.requestOperatorDeregistration(operator);

Expand All @@ -150,7 +150,7 @@ contract MevCommitAVSTest is Test {
assertEq(reg.deregRequestHeight.blockHeight, 108);

vm.expectRevert("operator must not have already requested deregistration");
vm.prank(owner);
vm.prank(operator);
mevCommitAVS.requestOperatorDeregistration(operator);
}

Expand All @@ -165,12 +165,12 @@ contract MevCommitAVSTest is Test {
testRegisterOperator();

address otherAcct = address(0x777);
vm.expectRevert("sender must be operator or MevCommitAVS owner");
vm.expectRevert("sender must be operator");
vm.prank(otherAcct);
mevCommitAVS.deregisterOperator(operator);

vm.expectRevert("operator must have requested deregistration");
vm.prank(owner);
vm.prank(operator);
mevCommitAVS.deregisterOperator(operator);

vm.prank(operator);
Expand Down Expand Up @@ -393,6 +393,38 @@ contract MevCommitAVSTest is Test {

// TODO: test that LST restakers cannot choose validators who're not registered / valid with eigen core
function testRegisterLSTRestaker() public {

address operator = address(0x888);
address lstRestaker = address(0x34443);
address otherAcct = address(0x777);
bytes[] memory chosenVals = new bytes[](0);
vm.expectRevert("sender must be delegated to an operator that is registered with MevCommitAVS");
vm.prank(otherAcct);
mevCommitAVS.registerLSTRestaker(chosenVals);

testRegisterValidatorsByPodOwners();

ISignatureUtils.SignatureWithExpiry memory sig = ISignatureUtils.SignatureWithExpiry({
signature: bytes("signature"),
expiry: 10
});
vm.prank(lstRestaker);
delegationManagerMock.delegateTo(operator, sig, bytes32("salt"));

vm.expectRevert("LST restaker must choose at least one validator");
vm.prank(lstRestaker);
mevCommitAVS.registerLSTRestaker(chosenVals);




// ""LST restaker must choose at least one validator""

// isOpted in stuff

// "LST restaker must have deposited into at least one strategy"

// TODO: "sender must not be registered LST restaker"
}

function testRequestLSTRestakerDeregistration() public {
Expand Down

0 comments on commit 1b59145

Please sign in to comment.