diff --git a/src/BLSApkRegistry.sol b/src/BLSApkRegistry.sol index a732a44a..ea6d318f 100644 --- a/src/BLSApkRegistry.sol +++ b/src/BLSApkRegistry.sol @@ -177,22 +177,6 @@ contract BLSApkRegistry is BLSApkRegistryStorage { } } - // TODO - should this fail if apkUpdate.apkHash == 0? This will be the case for the first entry in each quorum - function _validateApkHashAtBlockNumber(ApkUpdate memory apkUpdate, uint32 blockNumber) internal pure { - require( - blockNumber >= apkUpdate.updateBlockNumber, - "BLSApkRegistry._validateApkHashAtBlockNumber: index too recent" - ); - /** - * if there is a next update, check that the blockNumber is before the next update or if - * there is no next update, then apkUpdate.nextUpdateBlockNumber is 0. - */ - require( - apkUpdate.nextUpdateBlockNumber == 0 || blockNumber < apkUpdate.nextUpdateBlockNumber, - "BLSApkRegistry._validateApkHashAtBlockNumber: not latest apk update" - ); - } - /******************************************************************************* VIEW FUNCTIONS *******************************************************************************/ @@ -264,7 +248,21 @@ contract BLSApkRegistry is BLSApkRegistryStorage { uint256 index ) external view returns (bytes24) { ApkUpdate memory quorumApkUpdate = apkHistory[quorumNumber][index]; - _validateApkHashAtBlockNumber(quorumApkUpdate, blockNumber); + + /** + * Validate that the update is valid for the given blockNumber: + * - blockNumber should be >= the update block number + * - the next update block number should be either 0 or strictly greater than blockNumber + */ + require( + blockNumber >= quorumApkUpdate.updateBlockNumber, + "BLSApkRegistry._validateApkHashAtBlockNumber: index too recent" + ); + require( + quorumApkUpdate.nextUpdateBlockNumber == 0 || blockNumber < quorumApkUpdate.nextUpdateBlockNumber, + "BLSApkRegistry._validateApkHashAtBlockNumber: not latest apk update" + ); + return quorumApkUpdate.apkHash; } diff --git a/src/BLSSignatureChecker.sol b/src/BLSSignatureChecker.sol index accbba81..99d501ba 100644 --- a/src/BLSSignatureChecker.sol +++ b/src/BLSSignatureChecker.sol @@ -54,6 +54,11 @@ contract BLSSignatureChecker is IBLSSignatureChecker { emit StaleStakesForbiddenUpdate(value); } + struct NonSignerInfo { + uint256[] quorumBitmaps; + bytes32[] pubkeyHashes; + } + /** * @notice This function is called by disperser when it has aggregated all the signatures of the operators * that are part of the quorum for a particular taskNumber and is asserting them into onchain. The function @@ -72,7 +77,7 @@ contract BLSSignatureChecker is IBLSSignatureChecker { * @param msgHash is the hash being signed * @param quorumNumbers is the bytes array of quorum numbers that are being signed for * @param referenceBlockNumber is the block number at which the stake information is being verified - * @param nonSignerStakesAndSignature is the struct containing information on nonsigners, stakes, quorum apks, and the aggregate signature + * @param params is the struct containing information on nonsigners, stakes, quorum apks, and the aggregate signature * @return quorumStakeTotals is the struct containing the total and signed stake for each quorum * @return signatoryRecordHash is the hash of the signatory record, which is used for fraud proofs */ @@ -80,7 +85,7 @@ contract BLSSignatureChecker is IBLSSignatureChecker { bytes32 msgHash, bytes calldata quorumNumbers, uint32 referenceBlockNumber, - NonSignerStakesAndSignature memory nonSignerStakesAndSignature + NonSignerStakesAndSignature memory params ) public view @@ -88,101 +93,145 @@ contract BLSSignatureChecker is IBLSSignatureChecker { QuorumStakeTotals memory, bytes32 ) - { - // verify the provided apk was the apk at referenceBlockNumber - // loop through every quorumNumber and keep track of the apk + { + require( + (quorumNumbers.length == params.quorumApks.length) && + (quorumNumbers.length == params.quorumApkIndices.length) && + (quorumNumbers.length == params.totalStakeIndices.length) && + (quorumNumbers.length == params.nonSignerStakeIndices.length), + "BLSSignatureChecker.checkSignatures: input quorum length mismatch" + ); + + require( + params.nonSignerPubkeys.length == params.nonSignerQuorumBitmapIndices.length, + "BLSSignatureChecker.checkSignatures: input nonsigner length mismatch" + ); + + require(referenceBlockNumber <= uint32(block.number), "BLSSignatureChecker.checkSignatures: invalid reference block"); + + // This method needs to calculate the aggregate pubkey for all signing operators across + // all signing quorums. To do that, we can query the aggregate pubkey for each quorum + // and subtract out the pubkey for each nonsigning operator registered to that quorum. + // + // In practice, we do this in reverse - calculating an aggregate pubkey for all nonsigners, + // negating that pubkey, then adding the aggregate pubkey for each quorum. BN254.G1Point memory apk = BN254.G1Point(0, 0); - for (uint i = 0; i < quorumNumbers.length; i++) { - if (staleStakesForbidden) { - require( - registryCoordinator.quorumUpdateBlockNumber(uint8(quorumNumbers[i])) + delegation.withdrawalDelayBlocks() <= block.number, - "BLSSignatureChecker.checkSignatures: StakeRegistry updates must be within withdrawalDelayBlocks window" + + // For each quorum, we're also going to query the total stake for all registered operators + // at the referenceBlockNumber, and derive the stake held by signers by subtracting out + // stakes held by nonsigners. + QuorumStakeTotals memory stakeTotals; + stakeTotals.totalStakeForQuorum = new uint96[](quorumNumbers.length); + stakeTotals.signedStakeForQuorum = new uint96[](quorumNumbers.length); + + NonSignerInfo memory nonSigners; + nonSigners.quorumBitmaps = new uint256[](params.nonSignerPubkeys.length); + nonSigners.pubkeyHashes = new bytes32[](params.nonSignerPubkeys.length); + + { + // Get a bitmap of the quorums signing the message, and validate that + // quorumNumbers contains only unique, valid quorum numbers + uint256 signingQuorumBitmap = BitmapUtils.orderedBytesArrayToBitmap(quorumNumbers, registryCoordinator.quorumCount()); + + for (uint256 j = 0; j < params.nonSignerPubkeys.length; j++) { + // The nonsigner's pubkey hash doubles as their operatorId + // The check below validates that these operatorIds are sorted (and therefore + // free of duplicates) + nonSigners.pubkeyHashes[j] = params.nonSignerPubkeys[j].hashG1Point(); + if (j != 0) { + require( + uint256(nonSigners.pubkeyHashes[j]) > uint256(nonSigners.pubkeyHashes[j - 1]), + "BLSSignatureChecker.checkSignatures: nonSignerPubkeys not sorted" + ); + } + + // Get the quorums the nonsigner was registered for at referenceBlockNumber + nonSigners.quorumBitmaps[j] = + registryCoordinator.getQuorumBitmapAtBlockNumberByIndex({ + operatorId: nonSigners.pubkeyHashes[j], + blockNumber: referenceBlockNumber, + index: params.nonSignerQuorumBitmapIndices[j] + }); + + // Add the nonsigner's pubkey to the total apk, multiplied by the number + // of quorums they have in common with the signing quorums, because their + // public key will be a part of each signing quorum's aggregate pubkey + apk = apk.plus( + params.nonSignerPubkeys[j] + .scalar_mul_tiny( + BitmapUtils.countNumOnes(nonSigners.quorumBitmaps[j] & signingQuorumBitmap) + ) ); } - require( - bytes24(nonSignerStakesAndSignature.quorumApks[i].hashG1Point()) == - blsApkRegistry.getApkHashAtBlockNumberAndIndex( - uint8(quorumNumbers[i]), - referenceBlockNumber, - nonSignerStakesAndSignature.quorumApkIndices[i] - ), - "BLSSignatureChecker.checkSignatures: quorumApk hash in storage does not match provided quorum apk" - ); - apk = apk.plus(nonSignerStakesAndSignature.quorumApks[i]); } - - // initialize memory for the quorumStakeTotals - QuorumStakeTotals memory quorumStakeTotals; - quorumStakeTotals.totalStakeForQuorum = new uint96[](quorumNumbers.length); - quorumStakeTotals.signedStakeForQuorum = new uint96[](quorumNumbers.length); - // the pubkeyHashes of the nonSigners - bytes32[] memory nonSignerPubkeyHashes = new bytes32[](nonSignerStakesAndSignature.nonSignerPubkeys.length); + + // Negate the sum of the nonsigner aggregate pubkeys - from here, we'll add the + // total aggregate pubkey from each quorum. Because the nonsigners' pubkeys are + // in these quorums, this initial negation ensures they're cancelled out + apk = apk.negate(); + + /** + * For each quorum (at referenceBlockNumber): + * - add the apk for all registered operators + * - query the total stake for each quorum + * - subtract the stake for each nonsigner to calculate the stake belonging to signers + */ { - // the quorumBitmaps of the nonSigners - uint256[] memory nonSignerQuorumBitmaps = new uint256[](nonSignerStakesAndSignature.nonSignerPubkeys.length); - { - // the bitmap of the quorumNumbers - uint256 signingQuorumBitmap = BitmapUtils.bytesArrayToBitmap(quorumNumbers); - - for (uint i = 0; i < nonSignerStakesAndSignature.nonSignerPubkeys.length; i++) { - nonSignerPubkeyHashes[i] = nonSignerStakesAndSignature.nonSignerPubkeys[i].hashG1Point(); - - // check that the nonSignerPubkeys are sorted and free of duplicates - if (i != 0) { - require(uint256(nonSignerPubkeyHashes[i]) > uint256(nonSignerPubkeyHashes[i - 1]), "BLSSignatureChecker.checkSignatures: nonSignerPubkeys not sorted"); - } + uint256 withdrawalDelayBlocks = delegation.withdrawalDelayBlocks(); + bool _staleStakesForbidden = staleStakesForbidden; - nonSignerQuorumBitmaps[i] = - registryCoordinator.getQuorumBitmapAtBlockNumberByIndex( - nonSignerPubkeyHashes[i], - referenceBlockNumber, - nonSignerStakesAndSignature.nonSignerQuorumBitmapIndices[i] - ); - - // subtract the nonSignerPubkey from the running apk to get the apk of all signers - apk = apk.plus( - nonSignerStakesAndSignature.nonSignerPubkeys[i] - .negate() - .scalar_mul_tiny( - BitmapUtils.countNumOnes(nonSignerQuorumBitmaps[i] & signingQuorumBitmap) - ) + for (uint256 i = 0; i < quorumNumbers.length; i++) { + // If we're disallowing stale stake updates, check that each quorum's last update block + // is within withdrawalDelayBlocks + if (_staleStakesForbidden) { + require( + registryCoordinator.quorumUpdateBlockNumber(uint8(quorumNumbers[i])) + withdrawalDelayBlocks >= referenceBlockNumber, + "BLSSignatureChecker.checkSignatures: StakeRegistry updates must be within withdrawalDelayBlocks window" ); } - } - // loop through each quorum number - for (uint8 quorumNumberIndex = 0; quorumNumberIndex < quorumNumbers.length;) { - // get the quorum number - uint8 quorumNumber = uint8(quorumNumbers[quorumNumberIndex]); - // get the totalStake for the quorum at the referenceBlockNumber - quorumStakeTotals.totalStakeForQuorum[quorumNumberIndex] = - stakeRegistry.getTotalStakeAtBlockNumberFromIndex(quorumNumber, referenceBlockNumber, nonSignerStakesAndSignature.totalStakeIndices[quorumNumberIndex]); - // copy total stake to signed stake - quorumStakeTotals.signedStakeForQuorum[quorumNumberIndex] = quorumStakeTotals.totalStakeForQuorum[quorumNumberIndex]; - - // keep track of the nonSigners index in the quorum - uint32 nonSignerForQuorumIndex = 0; + + // Validate params.quorumApks is correct for this quorum at the referenceBlockNumber, + // then add it to the total apk + require( + bytes24(params.quorumApks[i].hashG1Point()) == + blsApkRegistry.getApkHashAtBlockNumberAndIndex({ + quorumNumber: uint8(quorumNumbers[i]), + blockNumber: referenceBlockNumber, + index: params.quorumApkIndices[i] + }), + "BLSSignatureChecker.checkSignatures: quorumApk hash in storage does not match provided quorum apk" + ); + apk = apk.plus(params.quorumApks[i]); + + // Get the total and starting signed stake for the quorum at referenceBlockNumber + stakeTotals.totalStakeForQuorum[i] = + stakeRegistry.getTotalStakeAtBlockNumberFromIndex({ + quorumNumber: uint8(quorumNumbers[i]), + blockNumber: referenceBlockNumber, + index: params.totalStakeIndices[i] + }); + stakeTotals.signedStakeForQuorum[i] = stakeTotals.totalStakeForQuorum[i]; + + // Keep track of the nonSigners index in the quorum + uint256 nonSignerForQuorumIndex = 0; // loop through all nonSigners, checking that they are a part of the quorum via their quorumBitmap // if so, load their stake at referenceBlockNumber and subtract it from running stake signed - for (uint32 i = 0; i < nonSignerStakesAndSignature.nonSignerPubkeys.length; i++) { + for (uint256 j = 0; j < params.nonSignerPubkeys.length; j++) { // if the nonSigner is a part of the quorum, subtract their stake from the running total - if (BitmapUtils.numberIsInBitmap(nonSignerQuorumBitmaps[i], quorumNumber)) { - quorumStakeTotals.signedStakeForQuorum[quorumNumberIndex] -= - stakeRegistry.getStakeAtBlockNumberAndIndex( - quorumNumber, - referenceBlockNumber, - nonSignerPubkeyHashes[i], - nonSignerStakesAndSignature.nonSignerStakeIndices[quorumNumberIndex][nonSignerForQuorumIndex] - ); + if (BitmapUtils.numberIsInBitmap(nonSigners.quorumBitmaps[j], uint8(quorumNumbers[i]))) { + stakeTotals.signedStakeForQuorum[i] -= + stakeRegistry.getStakeAtBlockNumberAndIndex({ + quorumNumber: uint8(quorumNumbers[i]), + blockNumber: referenceBlockNumber, + operatorId: nonSigners.pubkeyHashes[j], + index: params.nonSignerStakeIndices[i][nonSignerForQuorumIndex] + }); unchecked { ++nonSignerForQuorumIndex; } } } - - unchecked { - ++quorumNumberIndex; - } } } { @@ -190,17 +239,17 @@ contract BLSSignatureChecker is IBLSSignatureChecker { (bool pairingSuccessful, bool signatureIsValid) = trySignatureAndApkVerification( msgHash, apk, - nonSignerStakesAndSignature.apkG2, - nonSignerStakesAndSignature.sigma + params.apkG2, + params.sigma ); require(pairingSuccessful, "BLSSignatureChecker.checkSignatures: pairing precompile call failed"); require(signatureIsValid, "BLSSignatureChecker.checkSignatures: signature is invalid"); } // set signatoryRecordHash variable used for fraudproofs - bytes32 signatoryRecordHash = keccak256(abi.encodePacked(referenceBlockNumber, nonSignerPubkeyHashes)); + bytes32 signatoryRecordHash = keccak256(abi.encodePacked(referenceBlockNumber, nonSigners.pubkeyHashes)); // return the total stakes that signed for each quorum, and a hash of the information required to prove the exact signers and stake - return (quorumStakeTotals, signatoryRecordHash); + return (stakeTotals, signatoryRecordHash); } /** diff --git a/src/RegistryCoordinator.sol b/src/RegistryCoordinator.sol index b86f9dc6..55b7654f 100644 --- a/src/RegistryCoordinator.sol +++ b/src/RegistryCoordinator.sol @@ -806,16 +806,21 @@ contract RegistryCoordinator is uint256 index ) external view returns (uint192) { QuorumBitmapUpdate memory quorumBitmapUpdate = _operatorBitmapHistory[operatorId][index]; + + /** + * Validate that the update is valid for the given blockNumber: + * - blockNumber should be >= the update block number + * - the next update block number should be either 0 or strictly greater than blockNumber + */ require( - quorumBitmapUpdate.updateBlockNumber <= blockNumber, + blockNumber >= quorumBitmapUpdate.updateBlockNumber, "RegistryCoordinator.getQuorumBitmapAtBlockNumberByIndex: quorumBitmapUpdate is from after blockNumber" ); - // if the next update is at or before the block number, then the quorum provided index is too early - // if the nex update block number is 0, then this is the latest update require( - quorumBitmapUpdate.nextUpdateBlockNumber > blockNumber || quorumBitmapUpdate.nextUpdateBlockNumber == 0, + quorumBitmapUpdate.nextUpdateBlockNumber == 0 || blockNumber < quorumBitmapUpdate.nextUpdateBlockNumber, "RegistryCoordinator.getQuorumBitmapAtBlockNumberByIndex: quorumBitmapUpdate is from before blockNumber" ); + return quorumBitmapUpdate.quorumBitmap; } diff --git a/src/StakeRegistry.sol b/src/StakeRegistry.sol index 6eb09808..d1c66018 100644 --- a/src/StakeRegistry.sol +++ b/src/StakeRegistry.sol @@ -444,12 +444,17 @@ contract StakeRegistry is StakeRegistryStorage { StakeUpdate memory operatorStakeUpdate, uint32 blockNumber ) internal pure { + /** + * Validate that the update is valid for the given blockNumber: + * - blockNumber should be >= the update block number + * - the next update block number should be either 0 or strictly greater than blockNumber + */ require( - operatorStakeUpdate.updateBlockNumber <= blockNumber, + blockNumber >= operatorStakeUpdate.updateBlockNumber, "StakeRegistry._validateOperatorStakeAtBlockNumber: operatorStakeUpdate is from after blockNumber" ); require( - operatorStakeUpdate.nextUpdateBlockNumber == 0 || operatorStakeUpdate.nextUpdateBlockNumber > blockNumber, + operatorStakeUpdate.nextUpdateBlockNumber == 0 || blockNumber < operatorStakeUpdate.nextUpdateBlockNumber, "StakeRegistry._validateOperatorStakeAtBlockNumber: there is a newer operatorStakeUpdate available before blockNumber" ); } diff --git a/src/libraries/BN254.sol b/src/libraries/BN254.sol index 42703bda..9a378ebd 100644 --- a/src/libraries/BN254.sol +++ b/src/libraries/BN254.sol @@ -141,7 +141,7 @@ library BN254 { uint8 i = 0; //loop until we reach the most significant bit - while(s > m){ + while(s >= m){ unchecked { // if the current bit is 1, add the 2^n*p to the accumulated product if ((s >> i) & 1 == 1) { @@ -268,10 +268,14 @@ library BN254 { return (success, out[0] != 0); } - /// @return the keccak256 hash of the G1 Point + /// @return hashedG1 the keccak256 hash of the G1 Point /// @dev used for BLS signatures - function hashG1Point(BN254.G1Point memory pk) internal pure returns (bytes32) { - return keccak256(abi.encodePacked(pk.X, pk.Y)); + function hashG1Point(BN254.G1Point memory pk) internal pure returns (bytes32 hashedG1) { + assembly { + mstore(0, mload(pk)) + mstore(0x20, mload(add(0x20, pk))) + hashedG1 := keccak256(0, 0x40) + } } /// @return the keccak256 hash of the G2 Point diff --git a/test/mocks/DelegationMock.sol b/test/mocks/DelegationMock.sol new file mode 100644 index 00000000..1a737744 --- /dev/null +++ b/test/mocks/DelegationMock.sol @@ -0,0 +1,185 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity =0.8.12; + +import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; + +import {IDelegationManager} from "eigenlayer-contracts/src/contracts/interfaces/IDelegationManager.sol"; +import {IStrategyManager} from "eigenlayer-contracts/src/contracts/interfaces/IStrategyManager.sol"; +import {IStrategy} from "eigenlayer-contracts/src/contracts/interfaces/IStrategy.sol"; +import {ISignatureUtils} from "eigenlayer-contracts/src/contracts/interfaces/ISignatureUtils.sol"; + +contract DelegationMock is IDelegationManager { + mapping(address => bool) public isOperator; + mapping(address => mapping(IStrategy => uint256)) public operatorShares; + + function setIsOperator(address operator, bool _isOperatorReturnValue) external { + isOperator[operator] = _isOperatorReturnValue; + } + + /// @notice returns the total number of shares in `strategy` that are delegated to `operator`. + function setOperatorShares(address operator, IStrategy strategy, uint256 shares) external { + operatorShares[operator][strategy] = shares; + } + + mapping (address => address) public delegatedTo; + + function registerAsOperator(OperatorDetails calldata /*registeringOperatorDetails*/, string calldata /*metadataURI*/) external pure {} + + function updateOperatorMetadataURI(string calldata /*metadataURI*/) external pure {} + + function updateAVSMetadataURI(string calldata /*metadataURI*/) external pure {} + + function delegateTo(address operator, SignatureWithExpiry memory /*approverSignatureAndExpiry*/, bytes32 /*approverSalt*/) external { + delegatedTo[msg.sender] = operator; + } + + function modifyOperatorDetails(OperatorDetails calldata /*newOperatorDetails*/) external pure {} + + function delegateToBySignature( + address /*staker*/, + address /*operator*/, + SignatureWithExpiry memory /*stakerSignatureAndExpiry*/, + SignatureWithExpiry memory /*approverSignatureAndExpiry*/, + bytes32 /*approverSalt*/ + ) external pure {} + + function undelegate(address staker) external returns (bytes32 withdrawalRoot) { + delegatedTo[staker] = address(0); + return withdrawalRoot; + } + + function increaseDelegatedShares(address /*staker*/, IStrategy /*strategy*/, uint256 /*shares*/) external pure {} + + function decreaseDelegatedShares( + address /*staker*/, + IStrategy /*strategy*/, + uint256 /*shares*/ + ) external pure {} + + function operatorDetails(address operator) external pure returns (OperatorDetails memory) { + OperatorDetails memory returnValue = OperatorDetails({ + earningsReceiver: operator, + delegationApprover: operator, + stakerOptOutWindowBlocks: 0 + }); + return returnValue; + } + + function earningsReceiver(address operator) external pure returns (address) { + return operator; + } + + function delegationApprover(address operator) external pure returns (address) { + return operator; + } + + function stakerOptOutWindowBlocks(address /*operator*/) external pure returns (uint256) { + return 0; + } + + function withdrawalDelayBlocks() external pure returns (uint256) { + return 50400; + } + + function isDelegated(address staker) external view returns (bool) { + return (delegatedTo[staker] != address(0)); + } + + function isNotDelegated(address /*staker*/) external pure returns (bool) {} + + // function isOperator(address /*operator*/) external pure returns (bool) {} + + function stakerNonce(address /*staker*/) external pure returns (uint256) {} + + function delegationApproverSaltIsSpent(address /*delegationApprover*/, bytes32 /*salt*/) external pure returns (bool) {} + + function calculateCurrentStakerDelegationDigestHash(address /*staker*/, address /*operator*/, uint256 /*expiry*/) external view returns (bytes32) {} + + function calculateStakerDelegationDigestHash(address /*staker*/, uint256 /*stakerNonce*/, address /*operator*/, uint256 /*expiry*/) external view returns (bytes32) {} + + function calculateDelegationApprovalDigestHash( + address /*staker*/, + address /*operator*/, + address /*_delegationApprover*/, + bytes32 /*approverSalt*/, + uint256 /*expiry*/ + ) external view returns (bytes32) {} + + function calculateStakerDigestHash(address /*staker*/, address /*operator*/, uint256 /*expiry*/) + external pure returns (bytes32 stakerDigestHash) {} + + function calculateApproverDigestHash(address /*staker*/, address /*operator*/, uint256 /*expiry*/) + external pure returns (bytes32 approverDigestHash) {} + + function calculateOperatorAVSRegistrationDigestHash(address /*operator*/, address /*avs*/, bytes32 /*salt*/, uint256 /*expiry*/) + external pure returns (bytes32 digestHash) {} + + function DOMAIN_TYPEHASH() external view returns (bytes32) {} + + function STAKER_DELEGATION_TYPEHASH() external view returns (bytes32) {} + + function DELEGATION_APPROVAL_TYPEHASH() external view returns (bytes32) {} + + function OPERATOR_AVS_REGISTRATION_TYPEHASH() external view returns (bytes32) {} + + function domainSeparator() external view returns (bytes32) {} + + function cumulativeWithdrawalsQueued(address staker) external view returns (uint256) {} + + function calculateWithdrawalRoot(Withdrawal memory withdrawal) external pure returns (bytes32) {} + + function registerOperatorToAVS(address operator, ISignatureUtils.SignatureWithSaltAndExpiry memory operatorSignature) external {} + + function deregisterOperatorFromAVS(address operator) external {} + + function operatorSaltIsSpent(address avs, bytes32 salt) external view returns (bool) {} + + function queueWithdrawals( + QueuedWithdrawalParams[] calldata queuedWithdrawalParams + ) external returns (bytes32[] memory) {} + + function completeQueuedWithdrawal( + Withdrawal calldata withdrawal, + IERC20[] calldata tokens, + uint256 middlewareTimesIndex, + bool receiveAsTokens + ) external {} + + function completeQueuedWithdrawals( + Withdrawal[] calldata withdrawals, + IERC20[][] calldata tokens, + uint256[] calldata middlewareTimesIndexes, + bool[] calldata receiveAsTokens + ) external {} + + function migrateQueuedWithdrawals(IStrategyManager.DeprecatedStruct_QueuedWithdrawal[] memory withdrawalsToQueue) external {} + + // onlyDelegationManager functions in StrategyManager + function addShares( + IStrategyManager strategyManager, + address staker, + IStrategy strategy, + uint256 shares + ) external { + strategyManager.addShares(staker, strategy, shares); + } + + function removeShares( + IStrategyManager strategyManager, + address staker, + IStrategy strategy, + uint256 shares + ) external { + strategyManager.removeShares(staker, strategy, shares); + } + + function withdrawSharesAsTokens( + IStrategyManager strategyManager, + address recipient, + IStrategy strategy, + uint256 shares, + IERC20 token + ) external { + strategyManager.withdrawSharesAsTokens(recipient, strategy, shares, token); + } +} \ No newline at end of file diff --git a/test/utils/MockAVSDeployer.sol b/test/utils/MockAVSDeployer.sol index 118cbd03..9352a413 100644 --- a/test/utils/MockAVSDeployer.sol +++ b/test/utils/MockAVSDeployer.sol @@ -26,7 +26,7 @@ import {IRegistryCoordinator} from "src/interfaces/IRegistryCoordinator.sol"; import {StrategyManagerMock} from "eigenlayer-contracts/src/test/mocks/StrategyManagerMock.sol"; import {EigenPodManagerMock} from "eigenlayer-contracts/src/test/mocks/EigenPodManagerMock.sol"; -import {DelegationManagerMock} from "eigenlayer-contracts/src/test/mocks/DelegationManagerMock.sol"; +import {DelegationMock} from "test/mocks/DelegationMock.sol"; import {BLSApkRegistryHarness} from "test/harnesses/BLSApkRegistryHarness.sol"; import {EmptyContract} from "eigenlayer-contracts/src/test/mocks/EmptyContract.sol"; @@ -59,7 +59,7 @@ contract MockAVSDeployer is Test { IIndexRegistry public indexRegistry; StrategyManagerMock public strategyManagerMock; - DelegationManagerMock public delegationMock; + DelegationMock public delegationMock; EigenPodManagerMock public eigenPodManagerMock; address public proxyAdminOwner = address(uint160(uint256(keccak256("proxyAdminOwner")))); @@ -120,7 +120,7 @@ contract MockAVSDeployer is Test { pausers[0] = pauser; pauserRegistry = new PauserRegistry(pausers, unpauser); - delegationMock = new DelegationManagerMock(); + delegationMock = new DelegationMock(); eigenPodManagerMock = new EigenPodManagerMock(); strategyManagerMock = new StrategyManagerMock(); slasherImplementation = new Slasher(strategyManagerMock, delegationMock);