diff --git a/.github/workflows/contracts-tests.yml b/.github/workflows/contracts-tests.yml index 1bbf76dc..717d2924 100644 --- a/.github/workflows/contracts-tests.yml +++ b/.github/workflows/contracts-tests.yml @@ -25,3 +25,8 @@ jobs: - name: Run tests run: forge test -vvv working-directory: ./contracts + + + - name: Enforce Formatting + run: forge fmt --check + working-directory: ./contracts diff --git a/.github/workflows/daily-test.yaml b/.github/workflows/daily-test.yaml new file mode 100644 index 00000000..d01e9281 --- /dev/null +++ b/.github/workflows/daily-test.yaml @@ -0,0 +1,36 @@ +name: Daily Build And Test Dev + +on: + workflow_dispatch: + schedule: + - cron: '0 0 * * *' +jobs: + check: + strategy: + fail-fast: true + defaults: + run: + working-directory: ./contracts + + name: Foundry project + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + submodules: recursive + + - name: Install Foundry + uses: foundry-rs/foundry-toolchain@v1 + with: + version: nightly + + - name: Run Forge build + run: | + forge --version + forge build --sizes + id: build + + - name: Run Forge tests + run: | + forge test -vvv + id: test \ No newline at end of file diff --git a/.github/workflows/storage-checker.yaml b/.github/workflows/storage-checker.yaml new file mode 100644 index 00000000..4f41b61a --- /dev/null +++ b/.github/workflows/storage-checker.yaml @@ -0,0 +1,46 @@ +name: Check Storage Layout +on: + pull_request: + branches: + - master +jobs: + check_storage: + runs-on: "ubuntu-latest" + steps: + - uses: actions/checkout@v4 + with: + submodules: recursive + - name: Install Foundry + uses: foundry-rs/foundry-toolchain@v1 + with: + version: nightly + + - name: "Generate and prepare the contract artifacts" + run: | + cd contracts && mkdir pr + for file in $(find src -name '*.sol'); do + contract_name=$(basename "$file" .sol) + forge inspect "$contract_name" storage --pretty > pr/"$contract_name".md + done + + - name: Checkout Base Branch + env: + BASE: ${{ github.event.pull_request.base.sha }} + run: | + git fetch origin $BASE + git checkout $BASE + + - name: "Generate and prepare the contract artifacts" + run: | + cd contracts && mkdir base + for file in $(find src -name '*.sol'); do + contract_name=$(basename "$file" .sol) + forge inspect "$contract_name" storage --pretty > base/"$contract_name".md + done + - name: Compare outputs + run: | + if ! diff --unified contracts/pr contracts/base; then + # Note: We are only creating a warning because storage changes might be intentional but should be looked into + # reach out to steven if you see a warning on this workflow and need help validating if it is expected or not + echo "::warning::Differences found between PR and base storage layouts" + fi \ No newline at end of file diff --git a/README.md b/README.md index 6d9a80ce..aded9ac5 100644 --- a/README.md +++ b/README.md @@ -18,6 +18,10 @@ You will also need to [install docker](https://docs.docker.com/get-docker/), and ``` make build-contracts ``` +You will also need to [install abigen](https://geth.ethereum.org/docs/tools/abigen) if you want to make changes to the smart contracts and then generate the go bindings +``` +make bindings +``` ## Running via make @@ -114,4 +118,4 @@ When running on anvil, a typical log for the operator is [2024-04-09 18:25:10.679 PDT] INFO (logging/zap_logger.go:49) Signed task response header accepted by aggregator. {"reply":false} ``` -The error `task 2 not initialized or already completed` is expected behavior. This is because the aggregator needs to setup its data structures before it can accept responses. But on a local anvil setup, the operator had time to receive the websocket event for the new task, square the number, sign the response, and send it to the aggregator process before the aggregator has finalized its setup. Hence, the operator retries sending the response 2 seconds later and it is accepted. \ No newline at end of file +The error `task 2 not initialized or already completed` is expected behavior. This is because the aggregator needs to setup its data structures before it can accept responses. But on a local anvil setup, the operator had time to receive the websocket event for the new task, square the number, sign the response, and send it to the aggregator process before the aggregator has finalized its setup. Hence, the operator retries sending the response 2 seconds later and it is accepted. diff --git a/contracts/foundry.toml b/contracts/foundry.toml index 28f209a3..eec24e51 100644 --- a/contracts/foundry.toml +++ b/contracts/foundry.toml @@ -2,7 +2,7 @@ src = "src" out = "out" libs = ["lib"] -fs_permissions = [{ access = "read-write", path = "./"}] +fs_permissions = [{ access = "read-write", path = "./" }] remappings = [ "@eigenlayer/=lib/eigenlayer-middleware/lib/eigenlayer-contracts/src/", @@ -12,7 +12,7 @@ remappings = [ "@openzeppelin/=lib/eigenlayer-middleware/lib/eigenlayer-contracts/lib/openzeppelin-contracts/", "@openzeppelin-upgrades/=lib/eigenlayer-middleware/lib/eigenlayer-contracts/lib/openzeppelin-contracts-upgradeable/", "forge-std/=lib/forge-std/src/", - "ds-test/=lib/forge-std/lib/ds-test/src/" + "ds-test/=lib/forge-std/lib/ds-test/src/", ] gas_reports = ["*"] @@ -28,4 +28,13 @@ via_ir = false # Override the Solidity version (this overrides `auto_detect_solc`) solc_version = '0.8.12' +[fmt] +bracket_spacing = false +int_types = "long" +line_length = 100 +multiline_func_header = "params_first" +number_underscore = "thousands" +quote_style = "double" +tab_width = 4 + # See more config options https://github.com/foundry-rs/foundry/tree/master/config diff --git a/contracts/lib/eigenlayer-middleware b/contracts/lib/eigenlayer-middleware index deebd4ba..74438b79 160000 --- a/contracts/lib/eigenlayer-middleware +++ b/contracts/lib/eigenlayer-middleware @@ -1 +1 @@ -Subproject commit deebd4bafb14fffea54e15c7ba0b3cb95945e7db +Subproject commit 74438b7915c35ca5a0d312654716160c2499169d diff --git a/contracts/script/IncredibleSquaringDeployer.s.sol b/contracts/script/IncredibleSquaringDeployer.s.sol index e455112c..1d5af207 100644 --- a/contracts/script/IncredibleSquaringDeployer.s.sol +++ b/contracts/script/IncredibleSquaringDeployer.s.sol @@ -12,13 +12,20 @@ import {StrategyBaseTVLLimits} from "@eigenlayer/contracts/strategies/StrategyBa import "@eigenlayer/test/mocks/EmptyContract.sol"; import "@eigenlayer-middleware/src/RegistryCoordinator.sol" as regcoord; -import {IBLSApkRegistry, IIndexRegistry, IStakeRegistry} from "@eigenlayer-middleware/src/RegistryCoordinator.sol"; +import { + IBLSApkRegistry, + IIndexRegistry, + IStakeRegistry +} from "@eigenlayer-middleware/src/RegistryCoordinator.sol"; import {BLSApkRegistry} from "@eigenlayer-middleware/src/BLSApkRegistry.sol"; import {IndexRegistry} from "@eigenlayer-middleware/src/IndexRegistry.sol"; import {StakeRegistry} from "@eigenlayer-middleware/src/StakeRegistry.sol"; import "@eigenlayer-middleware/src/OperatorStateRetriever.sol"; - -import {IncredibleSquaringServiceManager, IServiceManager} from "../src/IncredibleSquaringServiceManager.sol"; +import {IRewardsCoordinator} from "@eigenlayer/contracts/interfaces/IRewardsCoordinator.sol"; +import { + IncredibleSquaringServiceManager, + IServiceManager +} from "../src/IncredibleSquaringServiceManager.sol"; import {IncredibleSquaringTaskManager} from "../src/IncredibleSquaringTaskManager.sol"; import {IIncredibleSquaringTaskManager} from "../src/IIncredibleSquaringTaskManager.sol"; import "../src/ERC20Mock.sol"; @@ -31,24 +38,22 @@ import "forge-std/StdJson.sol"; import "forge-std/console.sol"; // # To deploy and verify our contract -// forge script script/CredibleSquaringDeployer.s.sol:CredibleSquaringDeployer --rpc-url $RPC_URL --private-key $PRIVATE_KEY --broadcast -vvvv +// forge script script/IncredibleSquaringDeployer.s.sol:IncredibleSquaringDeployer --rpc-url $RPC_URL --private-key $PRIVATE_KEY --broadcast -vvvv contract IncredibleSquaringDeployer is Script, Utils { // DEPLOYMENT CONSTANTS uint256 public constant QUORUM_THRESHOLD_PERCENTAGE = 100; uint32 public constant TASK_RESPONSE_WINDOW_BLOCK = 30; uint32 public constant TASK_DURATION_BLOCKS = 0; // TODO: right now hardcoding these (this address is anvil's default address 9) - address public constant AGGREGATOR_ADDR = - 0xa0Ee7A142d267C1f36714E4a8F75612F20a79720; - address public constant TASK_GENERATOR_ADDR = - 0xa0Ee7A142d267C1f36714E4a8F75612F20a79720; + address public constant AGGREGATOR_ADDR = 0xa0Ee7A142d267C1f36714E4a8F75612F20a79720; + address public constant TASK_GENERATOR_ADDR = 0xa0Ee7A142d267C1f36714E4a8F75612F20a79720; - // ERC20 and Strategy: we need to deploy this erc20, create a strategy for it, and whitelist this strategy in the strategymanager + // ERC20 and Strategy: we need to deploy this ERC20, create a strategy for it, and whitelist this strategy in the strategymanager ERC20Mock public erc20Mock; StrategyBaseTVLLimits public erc20MockStrategy; - // Credible Squaring contracts + // Incredible Squaring contracts ProxyAdmin public incredibleSquaringProxyAdmin; PauserRegistry public incredibleSquaringPauserReg; @@ -70,67 +75,49 @@ contract IncredibleSquaringDeployer is Script, Utils { IServiceManager public incredibleSquaringServiceManagerImplementation; IncredibleSquaringTaskManager public incredibleSquaringTaskManager; - IIncredibleSquaringTaskManager - public incredibleSquaringTaskManagerImplementation; + IIncredibleSquaringTaskManager public incredibleSquaringTaskManagerImplementation; function run() external { // Eigenlayer contracts - string memory eigenlayerDeployedContracts = readOutput( - "eigenlayer_deployment_output" - ); + string memory eigenlayerDeployedContracts = readOutput("eigenlayer_deployment_output"); IStrategyManager strategyManager = IStrategyManager( - stdJson.readAddress( - eigenlayerDeployedContracts, - ".addresses.strategyManager" - ) + stdJson.readAddress(eigenlayerDeployedContracts, ".addresses.strategyManager") ); IDelegationManager delegationManager = IDelegationManager( - stdJson.readAddress( - eigenlayerDeployedContracts, - ".addresses.delegation" - ) + stdJson.readAddress(eigenlayerDeployedContracts, ".addresses.delegation") ); IAVSDirectory avsDirectory = IAVSDirectory( - stdJson.readAddress( - eigenlayerDeployedContracts, - ".addresses.avsDirectory" - ) + stdJson.readAddress(eigenlayerDeployedContracts, ".addresses.avsDirectory") ); ProxyAdmin eigenLayerProxyAdmin = ProxyAdmin( - stdJson.readAddress( - eigenlayerDeployedContracts, - ".addresses.eigenLayerProxyAdmin" - ) + stdJson.readAddress(eigenlayerDeployedContracts, ".addresses.eigenLayerProxyAdmin") ); PauserRegistry eigenLayerPauserReg = PauserRegistry( + stdJson.readAddress(eigenlayerDeployedContracts, ".addresses.eigenLayerPauserReg") + ); + StrategyBaseTVLLimits baseStrategyImplementation = StrategyBaseTVLLimits( stdJson.readAddress( - eigenlayerDeployedContracts, - ".addresses.eigenLayerPauserReg" + eigenlayerDeployedContracts, ".addresses.baseStrategyImplementation" ) ); - StrategyBaseTVLLimits baseStrategyImplementation = StrategyBaseTVLLimits( - stdJson.readAddress( - eigenlayerDeployedContracts, - ".addresses.baseStrategyImplementation" - ) - ); + IRewardsCoordinator rewardsCoordinator = IRewardsCoordinator( + stdJson.readAddress(eigenlayerDeployedContracts, ".addresses.rewardsCoordinator") + ); - address credibleSquaringCommunityMultisig = msg.sender; - address credibleSquaringPauser = msg.sender; + address incredibleSquaringCommunityMultisig = msg.sender; + address incredibleSquaringPauser = msg.sender; vm.startBroadcast(); _deployErc20AndStrategyAndWhitelistStrategy( - eigenLayerProxyAdmin, - eigenLayerPauserReg, - baseStrategyImplementation, - strategyManager + eigenLayerProxyAdmin, eigenLayerPauserReg, baseStrategyImplementation, strategyManager ); - _deployCredibleSquaringContracts( + _deployIncredibleSquaringContracts( delegationManager, avsDirectory, + rewardsCoordinator, erc20MockStrategy, - credibleSquaringCommunityMultisig, - credibleSquaringPauser + incredibleSquaringCommunityMultisig, + incredibleSquaringPauser ); vm.stopBroadcast(); } @@ -163,23 +150,21 @@ contract IncredibleSquaringDeployer is Script, Utils { strats[0] = erc20MockStrategy; bool[] memory thirdPartyTransfersForbiddenValues = new bool[](1); thirdPartyTransfersForbiddenValues[0] = false; - strategyManager.addStrategiesToDepositWhitelist( - strats, - thirdPartyTransfersForbiddenValues - ); + strategyManager.addStrategiesToDepositWhitelist(strats, thirdPartyTransfersForbiddenValues); } - function _deployCredibleSquaringContracts( + function _deployIncredibleSquaringContracts( IDelegationManager delegationManager, IAVSDirectory avsDirectory, + IRewardsCoordinator rewardsCoordinator, IStrategy strat, address incredibleSquaringCommunityMultisig, - address credibleSquaringPauser + address incredibleSquaringPauser ) internal { // Adding this as a temporary fix to make the rest of the script work with a single strategy // since it was originally written to work with an array of strategies IStrategy[1] memory deployedStrategyArray = [strat]; - uint numStrategies = deployedStrategyArray.length; + uint256 numStrategies = deployedStrategyArray.length; // deploy proxy admin for ability to upgrade proxy contracts incredibleSquaringProxyAdmin = new ProxyAdmin(); @@ -187,12 +172,10 @@ contract IncredibleSquaringDeployer is Script, Utils { // deploy pauser registry { address[] memory pausers = new address[](2); - pausers[0] = credibleSquaringPauser; + pausers[0] = incredibleSquaringPauser; pausers[1] = incredibleSquaringCommunityMultisig; - incredibleSquaringPauserReg = new PauserRegistry( - pausers, - incredibleSquaringCommunityMultisig - ); + incredibleSquaringPauserReg = + new PauserRegistry(pausers, incredibleSquaringCommunityMultisig); } EmptyContract emptyContract = new EmptyContract(); @@ -206,54 +189,42 @@ contract IncredibleSquaringDeployer is Script, Utils { incredibleSquaringServiceManager = IncredibleSquaringServiceManager( address( new TransparentUpgradeableProxy( - address(emptyContract), - address(incredibleSquaringProxyAdmin), - "" + address(emptyContract), address(incredibleSquaringProxyAdmin), "" ) ) ); incredibleSquaringTaskManager = IncredibleSquaringTaskManager( address( new TransparentUpgradeableProxy( - address(emptyContract), - address(incredibleSquaringProxyAdmin), - "" + address(emptyContract), address(incredibleSquaringProxyAdmin), "" ) ) ); registryCoordinator = regcoord.RegistryCoordinator( address( new TransparentUpgradeableProxy( - address(emptyContract), - address(incredibleSquaringProxyAdmin), - "" + address(emptyContract), address(incredibleSquaringProxyAdmin), "" ) ) ); blsApkRegistry = IBLSApkRegistry( address( new TransparentUpgradeableProxy( - address(emptyContract), - address(incredibleSquaringProxyAdmin), - "" + address(emptyContract), address(incredibleSquaringProxyAdmin), "" ) ) ); indexRegistry = IIndexRegistry( address( new TransparentUpgradeableProxy( - address(emptyContract), - address(incredibleSquaringProxyAdmin), - "" + address(emptyContract), address(incredibleSquaringProxyAdmin), "" ) ) ); stakeRegistry = IStakeRegistry( address( new TransparentUpgradeableProxy( - address(emptyContract), - address(incredibleSquaringProxyAdmin), - "" + address(emptyContract), address(incredibleSquaringProxyAdmin), "" ) ) ); @@ -262,28 +233,21 @@ contract IncredibleSquaringDeployer is Script, Utils { // Second, deploy the *implementation* contracts, using the *proxy contracts* as inputs { - stakeRegistryImplementation = new StakeRegistry( - registryCoordinator, - delegationManager - ); + stakeRegistryImplementation = new StakeRegistry(registryCoordinator, delegationManager); incredibleSquaringProxyAdmin.upgrade( TransparentUpgradeableProxy(payable(address(stakeRegistry))), address(stakeRegistryImplementation) ); - blsApkRegistryImplementation = new BLSApkRegistry( - registryCoordinator - ); + blsApkRegistryImplementation = new BLSApkRegistry(registryCoordinator); incredibleSquaringProxyAdmin.upgrade( TransparentUpgradeableProxy(payable(address(blsApkRegistry))), address(blsApkRegistryImplementation) ); - indexRegistryImplementation = new IndexRegistry( - registryCoordinator - ); + indexRegistryImplementation = new IndexRegistry(registryCoordinator); incredibleSquaringProxyAdmin.upgrade( TransparentUpgradeableProxy(payable(address(indexRegistry))), @@ -299,49 +263,38 @@ contract IncredibleSquaringDeployer is Script, Utils { ); { - uint numQuorums = 1; - // for each quorum to setup, we need to define + uint256 numQuorums = 1; + // for each quorum to set up, we need to define // QuorumOperatorSetParam, minimumStakeForQuorum, and strategyParams - regcoord.IRegistryCoordinator.OperatorSetParam[] - memory quorumsOperatorSetParams = new regcoord.IRegistryCoordinator.OperatorSetParam[]( - numQuorums - ); - for (uint i = 0; i < numQuorums; i++) { + regcoord.IRegistryCoordinator.OperatorSetParam[] memory quorumsOperatorSetParams = + new regcoord.IRegistryCoordinator.OperatorSetParam[](numQuorums); + for (uint256 i = 0; i < numQuorums; i++) { // hard code these for now - quorumsOperatorSetParams[i] = regcoord - .IRegistryCoordinator - .OperatorSetParam({ - maxOperatorCount: 10000, - kickBIPsOfOperatorStake: 15000, - kickBIPsOfTotalStake: 100 - }); + quorumsOperatorSetParams[i] = regcoord.IRegistryCoordinator.OperatorSetParam({ + maxOperatorCount: 10_000, + kickBIPsOfOperatorStake: 15_000, + kickBIPsOfTotalStake: 100 + }); } // set to 0 for every quorum uint96[] memory quorumsMinimumStake = new uint96[](numQuorums); - IStakeRegistry.StrategyParams[][] - memory quorumsStrategyParams = new IStakeRegistry.StrategyParams[][]( - numQuorums - ); - for (uint i = 0; i < numQuorums; i++) { - quorumsStrategyParams[i] = new IStakeRegistry.StrategyParams[]( - numStrategies - ); - for (uint j = 0; j < numStrategies; j++) { - quorumsStrategyParams[i][j] = IStakeRegistry - .StrategyParams({ - strategy: deployedStrategyArray[j], - // setting this to 1 ether since the divisor is also 1 ether - // therefore this allows an operator to register with even just 1 token - // see https://github.com/Layr-Labs/eigenlayer-middleware/blob/m2-mainnet/src/StakeRegistry.sol#L484 - // weight += uint96(sharesAmount * strategyAndMultiplier.multiplier / WEIGHTING_DIVISOR); - multiplier: 1 ether - }); + IStakeRegistry.StrategyParams[][] memory quorumsStrategyParams = + new IStakeRegistry.StrategyParams[][](numQuorums); + for (uint256 i = 0; i < numQuorums; i++) { + quorumsStrategyParams[i] = new IStakeRegistry.StrategyParams[](numStrategies); + for (uint256 j = 0; j < numStrategies; j++) { + quorumsStrategyParams[i][j] = IStakeRegistry.StrategyParams({ + strategy: deployedStrategyArray[j], + // setting this to 1 ether since the divisor is also 1 ether + // therefore this allows an operator to register with even just 1 token + // see https://github.com/Layr-Labs/eigenlayer-middleware/blob/m2-mainnet/src/StakeRegistry.sol#L484 + // weight += uint96(sharesAmount * strategyAndMultiplier.multiplier / WEIGHTING_DIVISOR); + multiplier: 1 ether + }); } } incredibleSquaringProxyAdmin.upgradeAndCall( - TransparentUpgradeableProxy( - payable(address(registryCoordinator)) - ), + TransparentUpgradeableProxy(payable(address(registryCoordinator))), address(registryCoordinatorImplementation), abi.encodeWithSelector( regcoord.RegistryCoordinator.initialize.selector, @@ -360,28 +313,23 @@ contract IncredibleSquaringDeployer is Script, Utils { incredibleSquaringServiceManagerImplementation = new IncredibleSquaringServiceManager( avsDirectory, + rewardsCoordinator, registryCoordinator, stakeRegistry, incredibleSquaringTaskManager ); // Third, upgrade the proxy contracts to use the correct implementation contracts and initialize them. incredibleSquaringProxyAdmin.upgrade( - TransparentUpgradeableProxy( - payable(address(incredibleSquaringServiceManager)) - ), + TransparentUpgradeableProxy(payable(address(incredibleSquaringServiceManager))), address(incredibleSquaringServiceManagerImplementation) ); - incredibleSquaringTaskManagerImplementation = new IncredibleSquaringTaskManager( - registryCoordinator, - TASK_RESPONSE_WINDOW_BLOCK - ); + incredibleSquaringTaskManagerImplementation = + new IncredibleSquaringTaskManager(registryCoordinator, TASK_RESPONSE_WINDOW_BLOCK); // Third, upgrade the proxy contracts to use the correct implementation contracts and initialize them. incredibleSquaringProxyAdmin.upgradeAndCall( - TransparentUpgradeableProxy( - payable(address(incredibleSquaringTaskManager)) - ), + TransparentUpgradeableProxy(payable(address(incredibleSquaringTaskManager))), address(incredibleSquaringTaskManagerImplementation), abi.encodeWithSelector( incredibleSquaringTaskManager.initialize.selector, @@ -396,16 +344,8 @@ contract IncredibleSquaringDeployer is Script, Utils { string memory parent_object = "parent object"; string memory deployed_addresses = "addresses"; - vm.serializeAddress( - deployed_addresses, - "erc20Mock", - address(erc20Mock) - ); - vm.serializeAddress( - deployed_addresses, - "erc20MockStrategy", - address(erc20MockStrategy) - ); + vm.serializeAddress(deployed_addresses, "erc20Mock", address(erc20Mock)); + vm.serializeAddress(deployed_addresses, "erc20MockStrategy", address(erc20MockStrategy)); vm.serializeAddress( deployed_addresses, "credibleSquaringServiceManager", @@ -426,28 +366,19 @@ contract IncredibleSquaringDeployer is Script, Utils { "credibleSquaringTaskManagerImplementation", address(incredibleSquaringTaskManagerImplementation) ); - vm.serializeAddress( - deployed_addresses, - "registryCoordinator", - address(registryCoordinator) - ); + vm.serializeAddress(deployed_addresses, "registryCoordinator", address(registryCoordinator)); vm.serializeAddress( deployed_addresses, "registryCoordinatorImplementation", address(registryCoordinatorImplementation) ); string memory deployed_addresses_output = vm.serializeAddress( - deployed_addresses, - "operatorStateRetriever", - address(operatorStateRetriever) + deployed_addresses, "operatorStateRetriever", address(operatorStateRetriever) ); // serialize all the data - string memory finalJson = vm.serializeString( - parent_object, - deployed_addresses, - deployed_addresses_output - ); + string memory finalJson = + vm.serializeString(parent_object, deployed_addresses, deployed_addresses_output); writeOutput(finalJson, "credible_squaring_avs_deployment_output"); } diff --git a/contracts/script/utils/Utils.sol b/contracts/script/utils/Utils.sol index 9310c761..52b518a7 100644 --- a/contracts/script/utils/Utils.sol +++ b/contracts/script/utils/Utils.sol @@ -9,16 +9,15 @@ import "forge-std/Script.sol"; import "forge-std/StdJson.sol"; contract Utils is Script { - // Note that this fct will only work for the ERC20Mock that has a public mint function + // Note that this function will only work for the ERC20Mock that has a public mint function function _mintTokens( address strategyAddress, address[] memory tos, uint256[] memory amounts ) internal { for (uint256 i = 0; i < tos.length; i++) { - ERC20Mock underlyingToken = ERC20Mock( - address(StrategyBase(strategyAddress).underlyingToken()) - ); + ERC20Mock underlyingToken = + ERC20Mock(address(StrategyBase(strategyAddress).underlyingToken())); underlyingToken.mint(tos[i], amounts[i]); } } @@ -36,18 +35,11 @@ contract Utils is Script { function convertOperatorStatusToString( IRegistryCoordinator.OperatorStatus operatorStatus ) public pure returns (string memory) { - if ( - operatorStatus == - IRegistryCoordinator.OperatorStatus.NEVER_REGISTERED - ) { + if (operatorStatus == IRegistryCoordinator.OperatorStatus.NEVER_REGISTERED) { return "NEVER_REGISTERED"; - } else if ( - operatorStatus == IRegistryCoordinator.OperatorStatus.REGISTERED - ) { + } else if (operatorStatus == IRegistryCoordinator.OperatorStatus.REGISTERED) { return "REGISTERED"; - } else if ( - operatorStatus == IRegistryCoordinator.OperatorStatus.DEREGISTERED - ) { + } else if (operatorStatus == IRegistryCoordinator.OperatorStatus.DEREGISTERED) { return "DEREGISTERED"; } else { return "UNKNOWN"; @@ -58,10 +50,7 @@ contract Utils is Script { function readInput( string memory inputFileName ) internal view returns (string memory) { - string memory inputDir = string.concat( - vm.projectRoot(), - "/script/input/" - ); + string memory inputDir = string.concat(vm.projectRoot(), "/script/input/"); string memory chainDir = string.concat(vm.toString(block.chainid), "/"); string memory file = string.concat(inputFileName, ".json"); return vm.readFile(string.concat(inputDir, chainDir, file)); @@ -70,30 +59,16 @@ contract Utils is Script { function readOutput( string memory outputFileName ) internal view returns (string memory) { - string memory inputDir = string.concat( - vm.projectRoot(), - "/script/output/" - ); + string memory inputDir = string.concat(vm.projectRoot(), "/script/output/"); string memory chainDir = string.concat(vm.toString(block.chainid), "/"); string memory file = string.concat(outputFileName, ".json"); return vm.readFile(string.concat(inputDir, chainDir, file)); } - function writeOutput( - string memory outputJson, - string memory outputFileName - ) internal { - string memory outputDir = string.concat( - vm.projectRoot(), - "/script/output/" - ); + function writeOutput(string memory outputJson, string memory outputFileName) internal { + string memory outputDir = string.concat(vm.projectRoot(), "/script/output/"); string memory chainDir = string.concat(vm.toString(block.chainid), "/"); - string memory outputFilePath = string.concat( - outputDir, - chainDir, - outputFileName, - ".json" - ); + string memory outputFilePath = string.concat(outputDir, chainDir, outputFileName, ".json"); vm.writeJson(outputJson, outputFilePath); } } diff --git a/contracts/src/ERC20Mock.sol b/contracts/src/ERC20Mock.sol index de379fce..f7b8b29e 100644 --- a/contracts/src/ERC20Mock.sol +++ b/contracts/src/ERC20Mock.sol @@ -1,308 +1,12 @@ // SPDX-License-Identifier: MIT -// OpenZeppelin Contracts (last updated v4.8.0) (token/ERC20/ERC20.sol) +pragma solidity ^0.8.12; -pragma solidity =0.8.12; +import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; -import "@openzeppelin/contracts/interfaces/IERC20.sol"; -import "@openzeppelin/contracts/utils/Context.sol"; - -/** - * @dev Implementation of the {IERC20} interface. - * - * This implementation is agnostic to the way tokens are created. This means - * that a supply mechanism has to be added in a derived contract using {_mint}. - * For a generic mechanism see {ERC20PresetMinterPauser}. - * - * TIP: For a detailed writeup see our guide - * https://forum.openzeppelin.com/t/how-to-implement-erc20-supply-mechanisms/226[How - * to implement supply mechanisms]. - * - * The default value of {decimals} is 18. To change this, you should override - * this function so it returns a different value. - * - * We have followed general OpenZeppelin Contracts guidelines: functions revert - * instead returning `false` on failure. This behavior is nonetheless - * conventional and does not conflict with the expectations of ERC20 - * applications. - * - * Additionally, an {Approval} event is emitted on calls to {transferFrom}. - * This allows applications to reconstruct the allowance for all accounts just - * by listening to said events. Other implementations of the EIP may not emit - * these events, as it isn't required by the specification. - * - * Finally, the non-standard {decreaseAllowance} and {increaseAllowance} - * functions have been added to mitigate the well-known issues around setting - * allowances. See {IERC20-approve}. - */ -contract ERC20Mock is Context, IERC20 { - mapping(address => uint256) private _balances; - - mapping(address => mapping(address => uint256)) private _allowances; - - uint256 private _totalSupply; - - /** - * @dev See {IERC20-totalSupply}. - */ - function totalSupply() public view virtual override returns (uint256) { - return _totalSupply; - } - - /** - * @dev See {IERC20-balanceOf}. - */ - function balanceOf( - address account - ) public view virtual override returns (uint256) { - return _balances[account]; - } +contract ERC20Mock is ERC20 { + constructor() ERC20("", "") {} function mint(address account, uint256 amount) public { _mint(account, amount); } - - /** - * @dev See {IERC20-transfer}. - * - * Requirements: - * - * - `to` cannot be the zero address. - * - the caller must have a balance of at least `amount`. - */ - function transfer( - address to, - uint256 amount - ) public virtual override returns (bool) { - address owner = _msgSender(); - _transfer(owner, to, amount); - return true; - } - - /** - * @dev See {IERC20-allowance}. - */ - function allowance( - address owner, - address spender - ) public view virtual override returns (uint256) { - return _allowances[owner][spender]; - } - - /** - * @dev See {IERC20-approve}. - * - * NOTE: If `amount` is the maximum `uint256`, the allowance is not updated on - * `transferFrom`. This is semantically equivalent to an infinite approval. - * - * Requirements: - * - * - `spender` cannot be the zero address. - */ - function approve( - address /*spender*/, - uint256 /*amount*/ - ) public virtual override returns (bool) { - return true; - } - - /** - * @dev See {IERC20-transferFrom}. - * - * Emits an {Approval} event indicating the updated allowance. This is not - * required by the EIP. See the note at the beginning of {ERC20}. - * - * NOTE: Does not update the allowance if the current allowance - * is the maximum `uint256`. - * - * Requirements: - * - * - `from` and `to` cannot be the zero address. - * - `from` must have a balance of at least `amount`. - * - the caller must have allowance for ``from``'s tokens of at least - * `amount`. - */ - function transferFrom( - address from, - address to, - uint256 amount - ) public virtual override returns (bool) { - _transfer(from, to, amount); - return true; - } - - /** - * @dev Moves `amount` of tokens from `from` to `to`. - * - * This internal function is equivalent to {transfer}, and can be used to - * e.g. implement automatic token fees, slashing mechanisms, etc. - * - * Emits a {Transfer} event. - * - * Requirements: - * - * - `from` cannot be the zero address. - * - `to` cannot be the zero address. - * - `from` must have a balance of at least `amount`. - */ - function _transfer( - address from, - address to, - uint256 amount - ) internal virtual { - require(from != address(0), "ERC20: transfer from the zero address"); - require(to != address(0), "ERC20: transfer to the zero address"); - - _beforeTokenTransfer(from, to, amount); - - require( - _balances[from] >= amount, - "ERC20: transfer amount exceeds balance" - ); - unchecked { - _balances[from] = _balances[from] - amount; - // Overflow not possible: the sum of all balances is capped by totalSupply, and the sum is preserved by - // decrementing then incrementing. - _balances[to] += amount; - } - - emit Transfer(from, to, amount); - - _afterTokenTransfer(from, to, amount); - } - - /** @dev Creates `amount` tokens and assigns them to `account`, increasing - * the total supply. - * - * Emits a {Transfer} event with `from` set to the zero address. - * - * Requirements: - * - * - `account` cannot be the zero address. - */ - function _mint(address account, uint256 amount) internal virtual { - require(account != address(0), "ERC20: mint to the zero address"); - - _totalSupply += amount; - unchecked { - // Overflow not possible: balance + amount is at most totalSupply + amount, which is checked above. - _balances[account] += amount; - } - emit Transfer(address(0), account, amount); - } - - /** - * @dev Destroys `amount` tokens from `account`, reducing the - * total supply. - * - * Emits a {Transfer} event with `to` set to the zero address. - * - * Requirements: - * - * - `account` cannot be the zero address. - * - `account` must have at least `amount` tokens. - */ - function _burn(address account, uint256 amount) internal virtual { - require(account != address(0), "ERC20: burn from the zero address"); - - _beforeTokenTransfer(account, address(0), amount); - - uint256 accountBalance = _balances[account]; - require(accountBalance >= amount, "ERC20: burn amount exceeds balance"); - unchecked { - _balances[account] = accountBalance - amount; - // Overflow not possible: amount <= accountBalance <= totalSupply. - _totalSupply -= amount; - } - - emit Transfer(account, address(0), amount); - - _afterTokenTransfer(account, address(0), amount); - } - - /** - * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens. - * - * This internal function is equivalent to `approve`, and can be used to - * e.g. set automatic allowances for certain subsystems, etc. - * - * Emits an {Approval} event. - * - * Requirements: - * - * - `owner` cannot be the zero address. - * - `spender` cannot be the zero address. - */ - function _approve( - address owner, - address spender, - uint256 amount - ) internal virtual { - require(owner != address(0), "ERC20: approve from the zero address"); - require(spender != address(0), "ERC20: approve to the zero address"); - - _allowances[owner][spender] = amount; - emit Approval(owner, spender, amount); - } - - /** - * @dev Updates `owner` s allowance for `spender` based on spent `amount`. - * - * Does not update the allowance amount in case of infinite allowance. - * Revert if not enough allowance is available. - * - * Might emit an {Approval} event. - */ - function _spendAllowance( - address owner, - address spender, - uint256 amount - ) internal virtual { - uint256 currentAllowance = allowance(owner, spender); - if (currentAllowance != type(uint256).max) { - require( - currentAllowance >= amount, - "ERC20: insufficient allowance" - ); - } - } - - /** - * @dev Hook that is called before any transfer of tokens. This includes - * minting and burning. - * - * Calling conditions: - * - * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens - * will be transferred to `to`. - * - when `from` is zero, `amount` tokens will be minted for `to`. - * - when `to` is zero, `amount` of ``from``'s tokens will be burned. - * - `from` and `to` are never both zero. - * - * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks]. - */ - function _beforeTokenTransfer( - address from, - address to, - uint256 amount - ) internal virtual {} - - /** - * @dev Hook that is called after any transfer of tokens. This includes - * minting and burning. - * - * Calling conditions: - * - * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens - * has been transferred to `to`. - * - when `from` is zero, `amount` tokens have been minted for `to`. - * - when `to` is zero, `amount` of ``from``'s tokens have been burned. - * - `from` and `to` are never both zero. - * - * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks]. - */ - function _afterTokenTransfer( - address from, - address to, - uint256 amount - ) internal virtual {} } diff --git a/contracts/src/IIncredibleSquaringTaskManager.sol b/contracts/src/IIncredibleSquaringTaskManager.sol index f57faa36..d6dc7c01 100644 --- a/contracts/src/IIncredibleSquaringTaskManager.sol +++ b/contracts/src/IIncredibleSquaringTaskManager.sol @@ -7,25 +7,16 @@ interface IIncredibleSquaringTaskManager { // EVENTS event NewTaskCreated(uint32 indexed taskIndex, Task task); - event TaskResponded( - TaskResponse taskResponse, - TaskResponseMetadata taskResponseMetadata - ); + event TaskResponded(TaskResponse taskResponse, TaskResponseMetadata taskResponseMetadata); event TaskCompleted(uint32 indexed taskIndex); - event TaskChallengedSuccessfully( - uint32 indexed taskIndex, - address indexed challenger - ); + event TaskChallengedSuccessfully(uint32 indexed taskIndex, address indexed challenger); - event TaskChallengedUnsuccessfully( - uint32 indexed taskIndex, - address indexed challenger - ); + event TaskChallengedUnsuccessfully(uint32 indexed taskIndex, address indexed challenger); event AggregatorUpdated(address indexed oldAggregator, address indexed newAggregator); - + event GeneratorUpdated(address indexed oldGenerator, address indexed newGenerator); // STRUCTS @@ -43,7 +34,7 @@ interface IIncredibleSquaringTaskManager { } // Task response is hashed and signed by operators. - // these signatures are aggregated and sent to the contract as response. + // These signatures are aggregated and sent to the contract as response. struct TaskResponse { // Can be obtained by the operator from the event NewTaskCreated. uint32 referenceTaskIndex; @@ -55,12 +46,12 @@ interface IIncredibleSquaringTaskManager { // It thus cannot be signed by operators, so we keep it in a separate struct than TaskResponse // This metadata is needed by the challenger, so we emit it in the TaskResponded event struct TaskResponseMetadata { - uint32 taskResponsedBlock; + uint32 taskRespondedBlock; bytes32 hashOfNonSigners; } // FUNCTIONS - // NOTE: this function creates new task. + // NOTE: this function creates a new task. function createNewTask( uint256 numberToBeSquared, uint32 quorumThresholdPercentage, @@ -70,7 +61,7 @@ interface IIncredibleSquaringTaskManager { /// @notice Returns the current 'taskNumber' for the middleware function taskNumber() external view returns (uint32); - // // NOTE: this function raises challenge to existing tasks. + // NOTE: this function raises a challenge to existing tasks. function raiseAndResolveChallenge( Task calldata task, TaskResponse calldata taskResponse, diff --git a/contracts/src/IncredibleSquaringServiceManager.sol b/contracts/src/IncredibleSquaringServiceManager.sol index aaf2bfea..1f33eae1 100644 --- a/contracts/src/IncredibleSquaringServiceManager.sol +++ b/contracts/src/IncredibleSquaringServiceManager.sol @@ -6,42 +6,37 @@ import "./IIncredibleSquaringTaskManager.sol"; import "@eigenlayer-middleware/src/ServiceManagerBase.sol"; /** - * @title Primary entrypoint for procuring services from IncredibleSquaring. + * @title Primary entry point for procuring services from IncredibleSquaring. * @author Layr Labs, Inc. */ contract IncredibleSquaringServiceManager is ServiceManagerBase { using BytesLib for bytes; - IIncredibleSquaringTaskManager - public immutable incredibleSquaringTaskManager; + IIncredibleSquaringTaskManager public immutable incredibleSquaringTaskManager; - /// @notice when applied to a function, ensures that the function is only callable by the `registryCoordinator`. + /// @notice When applied to a function, ensures that the function is only callable by the `incredibleSquaringTaskManager`. modifier onlyIncredibleSquaringTaskManager() { require( msg.sender == address(incredibleSquaringTaskManager), - "onlyIncredibleSquaringTaskManager: not from credible squaring task manager" + "onlyIncredibleSquaringTaskManager: not from incredible squaring task manager" ); _; } constructor( IAVSDirectory _avsDirectory, + IRewardsCoordinator _rewardsCoordinator, IRegistryCoordinator _registryCoordinator, IStakeRegistry _stakeRegistry, IIncredibleSquaringTaskManager _incredibleSquaringTaskManager ) - ServiceManagerBase( - _avsDirectory, - IPaymentCoordinator(address(0)), // inc-sq doesn't need to deal with payments - _registryCoordinator, - _stakeRegistry - ) + ServiceManagerBase(_avsDirectory, _rewardsCoordinator, _registryCoordinator, _stakeRegistry) { incredibleSquaringTaskManager = _incredibleSquaringTaskManager; } /// @notice Called in the event of challenge resolution, in order to forward a call to the Slasher, which 'freezes' the `operator`. - /// @dev The Slasher contract is under active development and its interface expected to change. + /// @dev The Slasher contract is under active development and its interface is expected to change. /// We recommend writing slashing logic without integrating with the Slasher at this point in time. function freezeOperator( address operatorAddr diff --git a/contracts/src/IncredibleSquaringTaskManager.sol b/contracts/src/IncredibleSquaringTaskManager.sol index 85fbefd0..7dcf4da6 100644 --- a/contracts/src/IncredibleSquaringTaskManager.sol +++ b/contracts/src/IncredibleSquaringTaskManager.sol @@ -7,7 +7,10 @@ import "@eigenlayer/contracts/permissions/Pausable.sol"; import "@eigenlayer-middleware/src/interfaces/IServiceManager.sol"; import {BLSApkRegistry} from "@eigenlayer-middleware/src/BLSApkRegistry.sol"; import {RegistryCoordinator} from "@eigenlayer-middleware/src/RegistryCoordinator.sol"; -import {BLSSignatureChecker, IRegistryCoordinator} from "@eigenlayer-middleware/src/BLSSignatureChecker.sol"; +import { + BLSSignatureChecker, + IRegistryCoordinator +} from "@eigenlayer-middleware/src/BLSSignatureChecker.sol"; import {OperatorStateRetriever} from "@eigenlayer-middleware/src/OperatorStateRetriever.sol"; import "@eigenlayer-middleware/src/libraries/BN254.sol"; import "./IIncredibleSquaringTaskManager.sol"; @@ -26,7 +29,7 @@ contract IncredibleSquaringTaskManager is // The number of blocks from the task initialization within which the aggregator has to respond to uint32 public immutable TASK_RESPONSE_WINDOW_BLOCK; uint32 public constant TASK_CHALLENGE_WINDOW_BLOCK = 100; - uint256 internal constant _THRESHOLD_DENOMINATOR = 100; + uint256 internal constant THRESHOLD_DENOMINATOR = 100; /* STORAGE */ // The latest task index @@ -41,12 +44,11 @@ contract IncredibleSquaringTaskManager is // mapping of task indices to hash of abi.encode(taskResponse, taskResponseMetadata) mapping(uint32 => bytes32) public allTaskResponses; - mapping(uint32 => bool) public taskSuccesfullyChallenged; + mapping(uint32 => bool) public taskSuccessfullyChallenged; address public aggregator; address public generator; - modifier onlyAggregator() { require(msg.sender == aggregator, "Aggregator must be the caller"); _; @@ -78,11 +80,15 @@ contract IncredibleSquaringTaskManager is _setGenerator(_generator); } - function setGenerator(address newGenerator) external onlyOwner { + function setGenerator( + address newGenerator + ) external onlyOwner { _setGenerator(newGenerator); } - function setAggregator(address newAggregator) external onlyOwner { + function setAggregator( + address newAggregator + ) external onlyOwner { _setAggregator(newAggregator); } @@ -116,10 +122,9 @@ contract IncredibleSquaringTaskManager is bytes calldata quorumNumbers = task.quorumNumbers; uint32 quorumThresholdPercentage = task.quorumThresholdPercentage; - // check that the task is valid, hasn't been responsed yet, and is being responsed in time + // check that the task is valid, hasn't been responded to yet, and is being responded to in time require( - keccak256(abi.encode(task)) == - allTaskHashes[taskResponse.referenceTaskIndex], + keccak256(abi.encode(task)) == allTaskHashes[taskResponse.referenceTaskIndex], "supplied task does not match the one recorded in the contract" ); // some logical checks @@ -128,8 +133,7 @@ contract IncredibleSquaringTaskManager is "Aggregator has already responded to the task" ); require( - uint32(block.number) <= - taskCreatedBlock + TASK_RESPONSE_WINDOW_BLOCK, + uint32(block.number) <= taskCreatedBlock + TASK_RESPONSE_WINDOW_BLOCK, "Aggregator has responded to the task too late" ); @@ -138,37 +142,25 @@ contract IncredibleSquaringTaskManager is bytes32 message = keccak256(abi.encode(taskResponse)); // check the BLS signature - ( - QuorumStakeTotals memory quorumStakeTotals, - bytes32 hashOfNonSigners - ) = checkSignatures( - message, - quorumNumbers, - taskCreatedBlock, - nonSignerStakesAndSignature - ); + (QuorumStakeTotals memory quorumStakeTotals, bytes32 hashOfNonSigners) = + checkSignatures(message, quorumNumbers, taskCreatedBlock, nonSignerStakesAndSignature); - // check that signatories own at least a threshold percentage of each quourm - for (uint i = 0; i < quorumNumbers.length; i++) { + // check that signatories own at least a threshold percentage of each quorum + for (uint256 i = 0; i < quorumNumbers.length; i++) { // we don't check that the quorumThresholdPercentages are not >100 because a greater value would trivially fail the check, implying // signed stake > total stake require( - quorumStakeTotals.signedStakeForQuorum[i] * - _THRESHOLD_DENOMINATOR >= - quorumStakeTotals.totalStakeForQuorum[i] * - uint8(quorumThresholdPercentage), + quorumStakeTotals.signedStakeForQuorum[i] * THRESHOLD_DENOMINATOR + >= quorumStakeTotals.totalStakeForQuorum[i] * uint8(quorumThresholdPercentage), "Signatories do not own at least threshold percentage of a quorum" ); } - TaskResponseMetadata memory taskResponseMetadata = TaskResponseMetadata( - uint32(block.number), - hashOfNonSigners - ); - // updating the storage with task responsea - allTaskResponses[taskResponse.referenceTaskIndex] = keccak256( - abi.encode(taskResponse, taskResponseMetadata) - ); + TaskResponseMetadata memory taskResponseMetadata = + TaskResponseMetadata(uint32(block.number), hashOfNonSigners); + // updating the storage with task response + allTaskResponses[taskResponse.referenceTaskIndex] = + keccak256(abi.encode(taskResponse, taskResponseMetadata)); // emitting event emit TaskResponded(taskResponse, taskResponseMetadata); @@ -191,30 +183,27 @@ contract IncredibleSquaringTaskManager is uint256 numberToBeSquared = task.numberToBeSquared; // some logical checks require( - allTaskResponses[referenceTaskIndex] != bytes32(0), - "Task hasn't been responded to yet" + allTaskResponses[referenceTaskIndex] != bytes32(0), "Task hasn't been responded to yet" ); require( - allTaskResponses[referenceTaskIndex] == - keccak256(abi.encode(taskResponse, taskResponseMetadata)), + allTaskResponses[referenceTaskIndex] + == keccak256(abi.encode(taskResponse, taskResponseMetadata)), "Task response does not match the one recorded in the contract" ); require( - taskSuccesfullyChallenged[referenceTaskIndex] == false, + taskSuccessfullyChallenged[referenceTaskIndex] == false, "The response to this task has already been challenged successfully." ); require( - uint32(block.number) <= - taskResponseMetadata.taskResponsedBlock + - TASK_CHALLENGE_WINDOW_BLOCK, + uint32(block.number) + <= taskResponseMetadata.taskRespondedBlock + TASK_CHALLENGE_WINDOW_BLOCK, "The challenge period for this task has already expired." ); // logic for checking whether challenge is valid or not uint256 actualSquaredOutput = numberToBeSquared * numberToBeSquared; - bool isResponseCorrect = (actualSquaredOutput == - taskResponse.numberSquared); + bool isResponseCorrect = (actualSquaredOutput == taskResponse.numberSquared); // if response was correct, no slashing happens so we return if (isResponseCorrect == true) { @@ -223,13 +212,10 @@ contract IncredibleSquaringTaskManager is } // get the list of hash of pubkeys of operators who weren't part of the task response submitted by the aggregator - bytes32[] memory hashesOfPubkeysOfNonSigningOperators = new bytes32[]( - pubkeysOfNonSigningOperators.length - ); - for (uint i = 0; i < pubkeysOfNonSigningOperators.length; i++) { - hashesOfPubkeysOfNonSigningOperators[ - i - ] = pubkeysOfNonSigningOperators[i].hashG1Point(); + bytes32[] memory hashesOfPubkeysOfNonSigningOperators = + new bytes32[](pubkeysOfNonSigningOperators.length); + for (uint256 i = 0; i < pubkeysOfNonSigningOperators.length; i++) { + hashesOfPubkeysOfNonSigningOperators[i] = pubkeysOfNonSigningOperators[i].hashG1Point(); } // verify whether the pubkeys of "claimed" non-signers supplied by challenger are actually non-signers as recorded before @@ -237,25 +223,19 @@ contract IncredibleSquaringTaskManager is // currently inlined, as the MiddlewareUtils.computeSignatoryRecordHash function was removed from BLSSignatureChecker // in this PR: https://github.com/Layr-Labs/eigenlayer-contracts/commit/c836178bf57adaedff37262dff1def18310f3dce#diff-8ab29af002b60fc80e3d6564e37419017c804ae4e788f4c5ff468ce2249b4386L155-L158 // TODO(samlaf): contracts team will add this function back in the BLSSignatureChecker, which we should use to prevent potential bugs from code duplication - bytes32 signatoryRecordHash = keccak256( - abi.encodePacked( - task.taskCreatedBlock, - hashesOfPubkeysOfNonSigningOperators - ) - ); + bytes32 signatoryRecordHash = + keccak256(abi.encodePacked(task.taskCreatedBlock, hashesOfPubkeysOfNonSigningOperators)); require( signatoryRecordHash == taskResponseMetadata.hashOfNonSigners, "The pubkeys of non-signing operators supplied by the challenger are not correct." ); // get the address of operators who didn't sign - address[] memory addresssOfNonSigningOperators = new address[]( - pubkeysOfNonSigningOperators.length - ); - for (uint i = 0; i < pubkeysOfNonSigningOperators.length; i++) { - addresssOfNonSigningOperators[i] = BLSApkRegistry( - address(blsApkRegistry) - ).pubkeyHashToOperator(hashesOfPubkeysOfNonSigningOperators[i]); + address[] memory addressesOfNonSigningOperators = + new address[](pubkeysOfNonSigningOperators.length); + for (uint256 i = 0; i < pubkeysOfNonSigningOperators.length; i++) { + addressesOfNonSigningOperators[i] = BLSApkRegistry(address(blsApkRegistry)) + .pubkeyHashToOperator(hashesOfPubkeysOfNonSigningOperators[i]); } // @dev the below code is commented out for the upcoming M2 release @@ -295,14 +275,14 @@ contract IncredibleSquaringTaskManager is // bool wasSigningOperator = true; // for ( // uint k = 0; - // k < addresssOfNonSigningOperators.length; + // k < addressesOfNonSigningOperators.length; // k++ // ) { // if ( - // operatorAddress == addresssOfNonSigningOperators[k] + // operatorAddress == addressesOfNonSigningOperators[k] // ) { // // if the operator was a non-signer, then we set the flag to false - // wasSigningOperator == false; + // wasSigningOperator = false; // break; // } // } @@ -317,7 +297,7 @@ contract IncredibleSquaringTaskManager is // } // the task response has been challenged successfully - taskSuccesfullyChallenged[referenceTaskIndex] = true; + taskSuccessfullyChallenged[referenceTaskIndex] = true; emit TaskChallengedSuccessfully(referenceTaskIndex, msg.sender); } @@ -326,17 +306,19 @@ contract IncredibleSquaringTaskManager is return TASK_RESPONSE_WINDOW_BLOCK; } - function _setGenerator(address newGenerator) internal { + function _setGenerator( + address newGenerator + ) internal { address oldGenerator = generator; generator = newGenerator; emit GeneratorUpdated(oldGenerator, newGenerator); } - function _setAggregator(address newAggregator) internal { + function _setAggregator( + address newAggregator + ) internal { address oldAggregator = aggregator; aggregator = newAggregator; emit AggregatorUpdated(oldAggregator, newAggregator); } - - } diff --git a/contracts/test/CredibleSquaringTaskManager.t.sol b/contracts/test/CredibleSquaringTaskManager.t.sol index 2022adf3..a1f37529 100644 --- a/contracts/test/CredibleSquaringTaskManager.t.sol +++ b/contracts/test/CredibleSquaringTaskManager.t.sol @@ -4,7 +4,8 @@ pragma solidity ^0.8.12; import "../src/IncredibleSquaringServiceManager.sol" as incsqsm; import {IncredibleSquaringTaskManager} from "../src/IncredibleSquaringTaskManager.sol"; import {BLSMockAVSDeployer} from "@eigenlayer-middleware/test/utils/BLSMockAVSDeployer.sol"; -import {TransparentUpgradeableProxy} from "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol"; +import {TransparentUpgradeableProxy} from + "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol"; contract IncredibleSquaringTaskManagerTest is BLSMockAVSDeployer { incsqsm.IncredibleSquaringServiceManager sm; @@ -13,17 +14,14 @@ contract IncredibleSquaringTaskManagerTest is BLSMockAVSDeployer { IncredibleSquaringTaskManager tmImplementation; uint32 public constant TASK_RESPONSE_WINDOW_BLOCK = 30; - address aggregator = - address(uint160(uint256(keccak256(abi.encodePacked("aggregator"))))); - address generator = - address(uint160(uint256(keccak256(abi.encodePacked("generator"))))); + address aggregator = address(uint160(uint256(keccak256(abi.encodePacked("aggregator"))))); + address generator = address(uint160(uint256(keccak256(abi.encodePacked("generator"))))); function setUp() public { _setUpBLSMockAVSDeployer(); tmImplementation = new IncredibleSquaringTaskManager( - incsqsm.IRegistryCoordinator(address(registryCoordinator)), - TASK_RESPONSE_WINDOW_BLOCK + incsqsm.IRegistryCoordinator(address(registryCoordinator)), TASK_RESPONSE_WINDOW_BLOCK ); // Third, upgrade the proxy contracts to use the correct implementation contracts and initialize them.