diff --git a/contracts/.solhintignore b/contracts/.solhintignore index 9153096bf..fd24abf8e 100644 --- a/contracts/.solhintignore +++ b/contracts/.solhintignore @@ -1,3 +1,4 @@ lib/ test/ node_modules/ +contracts/validator-registry/ValidatorOptInRouterDummy.sol \ No newline at end of file diff --git a/contracts/contracts/validator-registry/ValidatorOptInRouterDummy.sol b/contracts/contracts/validator-registry/ValidatorOptInRouterDummy.sol new file mode 100644 index 000000000..fc04b860c --- /dev/null +++ b/contracts/contracts/validator-registry/ValidatorOptInRouterDummy.sol @@ -0,0 +1,63 @@ +// SPDX-License-Identifier: BSL 1.1 +pragma solidity 0.8.26; + +import {IValidatorOptInRouter} from "../interfaces/IValidatorOptInRouter.sol"; +import {IVanillaRegistry} from "../interfaces/IVanillaRegistry.sol"; +import {IMevCommitAVS} from "../interfaces/IMevCommitAVS.sol"; +import {IMevCommitMiddleware} from "../interfaces/IMevCommitMiddleware.sol"; + +/// @title ValidatorOptInRouterDummy +/// @notice A dummy implementation of ValidatorOptInRouter that returns true 25% of the time +/// for testing purposes. +contract ValidatorOptInRouterDummy is IValidatorOptInRouter { + + /// @notice Initializes the contract (no-op for dummy implementation) + function initialize( + address _vanillaRegistry, + address _mevCommitAVS, + address _mevCommitMiddleware, + address _owner + ) external { + // No-op + } + + /// @notice Dummy implementation that always reverts + function setVanillaRegistry(IVanillaRegistry _vanillaRegistry) external { + revert("Not implemented"); + } + + /// @notice Dummy implementation that always reverts + function setMevCommitAVS(IMevCommitAVS _mevCommitAVS) external { + revert("Not implemented"); + } + + /// @notice Dummy implementation that always reverts + function setMevCommitMiddleware(IMevCommitMiddleware _mevCommitMiddleware) external { + revert("Not implemented"); + } + + /// @notice Returns an array of OptInStatus structs with 25% probability of being opted in + function areValidatorsOptedIn(bytes[] calldata valBLSPubKeys) external pure returns (OptInStatus[] memory) { + uint256 len = valBLSPubKeys.length; + OptInStatus[] memory optInStatuses = new OptInStatus[](len); + for (uint256 i = 0; i < len; ++i) { + optInStatuses[i] = _isValidatorOptedIn(valBLSPubKeys[i]); + } + return optInStatuses; + } + + /// @notice Internal function that returns true 25% of the time based on the first byte of the pubkey + function _isValidatorOptedIn(bytes calldata valBLSPubKey) internal pure returns (OptInStatus memory) { + OptInStatus memory optInStatus; + + // Use first byte of pubkey to determine opt-in status + // If first byte is < 64 (25% of 256), return true + bool isOptedIn = uint8(valBLSPubKey[1]) < 64; + + optInStatus.isVanillaOptedIn = isOptedIn; + optInStatus.isAvsOptedIn = isOptedIn; + optInStatus.isMiddlewareOptedIn = isOptedIn; + + return optInStatus; + } +} diff --git a/contracts/scripts/validator-registry/DeployValidatorOptInRouterDummy.s.sol b/contracts/scripts/validator-registry/DeployValidatorOptInRouterDummy.s.sol new file mode 100644 index 000000000..dab9caef2 --- /dev/null +++ b/contracts/scripts/validator-registry/DeployValidatorOptInRouterDummy.s.sol @@ -0,0 +1,44 @@ +// SPDX-License-Identifier: BSL 1.1 + +// solhint-disable no-console +// solhint-disable one-contract-per-file + +pragma solidity 0.8.26; + +import {Script} from "forge-std/Script.sol"; +import {console} from "forge-std/console.sol"; +import {ValidatorOptInRouterDummy} from "../../contracts/validator-registry/ValidatorOptInRouterDummy.sol"; + +contract BaseDeploy is Script { + function deployValidatorOptInRouterDummy( + address vanillaRegistry, + address mevCommitAVS, + address mevCommitMiddleware, + address owner + ) public returns (address) { + console.log("Deploying ValidatorOptInRouterDummy on chain:", block.chainid); + ValidatorOptInRouterDummy router = new ValidatorOptInRouterDummy(); + router.initialize(vanillaRegistry, mevCommitAVS, mevCommitMiddleware, owner); + console.log("ValidatorOptInRouterDummy deployed to:", address(router)); + return address(router); + } +} + +contract DeployHolesky is BaseDeploy { + address constant public VANILLA_REGISTRY = address(0); + address constant public MEV_COMMIT_AVS = address(0); + address constant public MEV_COMMIT_MIDDLEWARE = address(0); + address constant public OWNER = address(0); + + function run() external { + require(block.chainid == 17000, "must deploy on Holesky"); + vm.startBroadcast(); + deployValidatorOptInRouterDummy( + VANILLA_REGISTRY, + MEV_COMMIT_AVS, + MEV_COMMIT_MIDDLEWARE, + OWNER + ); + vm.stopBroadcast(); + } +} diff --git a/contracts/test/validator-registry/ValidatorOptInRouterDummyTest.sol b/contracts/test/validator-registry/ValidatorOptInRouterDummyTest.sol new file mode 100644 index 000000000..1a7a3e6a6 --- /dev/null +++ b/contracts/test/validator-registry/ValidatorOptInRouterDummyTest.sol @@ -0,0 +1,78 @@ +// SPDX-License-Identifier: BSL 1.1 +pragma solidity 0.8.26; + +import {Test} from "forge-std/Test.sol"; +import {ValidatorOptInRouterDummy} from "../../contracts/validator-registry/ValidatorOptInRouterDummy.sol"; +import {IValidatorOptInRouter} from "../../contracts/interfaces/IValidatorOptInRouter.sol"; +import {IVanillaRegistry} from "../../contracts/interfaces/IVanillaRegistry.sol"; +import {IMevCommitAVS} from "../../contracts/interfaces/IMevCommitAVS.sol"; +import {IMevCommitMiddleware} from "../../contracts/interfaces/IMevCommitMiddleware.sol"; + +contract ValidatorOptInRouterDummyTest is Test { + ValidatorOptInRouterDummy public validatorOptInRouter; + + address public owner; + address public user1; + address public user2; + + function setUp() public { + owner = address(0x123456); + user1 = address(0x123); + user2 = address(0x456); + + validatorOptInRouter = new ValidatorOptInRouterDummy(); + validatorOptInRouter.initialize(address(0), address(0), address(0), owner); + } + + function testSettersRevert() public { + vm.expectRevert("Not implemented"); + validatorOptInRouter.setVanillaRegistry(IVanillaRegistry(address(0))); + + vm.expectRevert("Not implemented"); + validatorOptInRouter.setMevCommitAVS(IMevCommitAVS(address(0))); + + vm.expectRevert("Not implemented"); + validatorOptInRouter.setMevCommitMiddleware(IMevCommitMiddleware(address(0))); + } + + function testAreValidatorsOptedIn() public { + // Create test pubkeys where first byte is < 64 (opted in) and > 64 (not opted in) + bytes[] memory valPubkeys = new bytes[](2); + valPubkeys[0] = abi.encodePacked(bytes1(0x01)); // First byte 1 - should be opted in + valPubkeys[1] = abi.encodePacked(bytes1(0xFF)); // First byte 255 - should not be opted in + + IValidatorOptInRouter.OptInStatus[] memory optInStatuses = validatorOptInRouter.areValidatorsOptedIn(valPubkeys); + + assertEq(optInStatuses.length, 2); + + // First validator should be opted in (first byte < 64) + assertTrue(optInStatuses[0].isVanillaOptedIn); + assertTrue(optInStatuses[0].isAvsOptedIn); + assertTrue(optInStatuses[0].isMiddlewareOptedIn); + + // Second validator should not be opted in (first byte > 64) + assertFalse(optInStatuses[1].isVanillaOptedIn); + assertFalse(optInStatuses[1].isAvsOptedIn); + assertFalse(optInStatuses[1].isMiddlewareOptedIn); + } + + function testAreValidatorsOptedInBoundary() public { + bytes[] memory valPubkeys = new bytes[](2); + valPubkeys[0] = abi.encodePacked(bytes1(0x3F)); // First byte 63 - should be opted in + valPubkeys[1] = abi.encodePacked(bytes1(0x40)); // First byte 64 - should not be opted in + + IValidatorOptInRouter.OptInStatus[] memory optInStatuses = validatorOptInRouter.areValidatorsOptedIn(valPubkeys); + + assertEq(optInStatuses.length, 2); + + // First validator should be opted in (63 < 64) + assertTrue(optInStatuses[0].isVanillaOptedIn); + assertTrue(optInStatuses[0].isAvsOptedIn); + assertTrue(optInStatuses[0].isMiddlewareOptedIn); + + // Second validator should not be opted in (64 >= 64) + assertFalse(optInStatuses[1].isVanillaOptedIn); + assertFalse(optInStatuses[1].isAvsOptedIn); + assertFalse(optInStatuses[1].isMiddlewareOptedIn); + } +}