From 88577757e91230f480879cfe1207d167a0272267 Mon Sep 17 00:00:00 2001 From: gpsanant Date: Tue, 3 Dec 2024 12:05:08 -0800 Subject: [PATCH 1/9] diffs --- lib/forge-std | 2 +- .../rewards_testing/ServiceManagerMock.sol | 159 ++++ .../utils/rewards_testing/StrategyToken.sol | 16 + .../SubmitRewardsForAllEarners.s.sol | 367 ++++++++ .../utils/rewards_testing/TestRewardsV2.sol | 334 ++++++++ .../rewards_testing/TransactionBuilder.s.sol | 787 ++++++++++++++++++ .../rewards_testing/TransactionSubmitter.sol | 215 +++++ script/utils/rewards_testing/addresses.json | 13 + script/utils/rewards_testing/notes.sh | 4 + .../utils/rewards_testing/preprod_state.json | 5 + 10 files changed, 1901 insertions(+), 1 deletion(-) create mode 100644 script/utils/rewards_testing/ServiceManagerMock.sol create mode 100644 script/utils/rewards_testing/StrategyToken.sol create mode 100644 script/utils/rewards_testing/SubmitRewardsForAllEarners.s.sol create mode 100644 script/utils/rewards_testing/TestRewardsV2.sol create mode 100644 script/utils/rewards_testing/TransactionBuilder.s.sol create mode 100644 script/utils/rewards_testing/TransactionSubmitter.sol create mode 100644 script/utils/rewards_testing/addresses.json create mode 100644 script/utils/rewards_testing/notes.sh create mode 100644 script/utils/rewards_testing/preprod_state.json diff --git a/lib/forge-std b/lib/forge-std index fc560fa34..1714bee72 160000 --- a/lib/forge-std +++ b/lib/forge-std @@ -1 +1 @@ -Subproject commit fc560fa34fa12a335a50c35d92e55a6628ca467c +Subproject commit 1714bee72e286e73f76e320d110e0eaf5c4e649d diff --git a/script/utils/rewards_testing/ServiceManagerMock.sol b/script/utils/rewards_testing/ServiceManagerMock.sol new file mode 100644 index 000000000..819635130 --- /dev/null +++ b/script/utils/rewards_testing/ServiceManagerMock.sol @@ -0,0 +1,159 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity ^0.8.12; + +import {OwnableUpgradeable} from "@openzeppelin-upgrades/contracts/access/OwnableUpgradeable.sol"; +import {ISignatureUtils} from "src/contracts/interfaces/ISignatureUtils.sol"; +import {IAVSDirectory} from "src/contracts/interfaces/IAVSDirectory.sol"; +import {IRewardsCoordinator} from "src/contracts/interfaces/IRewardsCoordinator.sol"; + +/** + * @title Minimal implementation of a ServiceManager-type contract. + * This contract can be inherited from or simply used as a point-of-reference. + * @author Layr Labs, Inc. + */ +contract ServiceManagerMock is OwnableUpgradeable { + + IAVSDirectory internal immutable _avsDirectory; + IRewardsCoordinator internal immutable _rewardsCoordinator; + + address[] public restakeableStrategies; + mapping(address => address[]) public operatorRestakedStrategies; + + /// @notice Sets the (immutable) `_registryCoordinator` address + constructor( + IAVSDirectory __avsDirectory, + IRewardsCoordinator ___rewardsCoordinator + ) { + _avsDirectory = __avsDirectory; + _rewardsCoordinator = ___rewardsCoordinator; + _disableInitializers(); + } + + function initialize(address _initialOwner) public initializer { + _transferOwnership(_initialOwner); + } + + function __ServiceManagerBase_init(address initialOwner) internal virtual onlyInitializing { + _transferOwnership(initialOwner); + } + + /** + * @notice Updates the metadata URI for the AVS + * @param _metadataURI is the metadata URI for the AVS + * @dev only callable by the owner + */ + function updateAVSMetadataURI(string memory _metadataURI) public virtual onlyOwner { + _avsDirectory.updateAVSMetadataURI(_metadataURI); + } + + /** + * @notice Creates a new range payment on behalf of an AVS, to be split amongst the + * set of stakers delegated to operators who are registered to the `avs`. + * Note that the owner calling this function must have approved the tokens to be transferred to the ServiceManager + * and of course has the required balances. + * @param rewardsSubmissions The range payments being created + * @dev Expected to be called by the ServiceManager of the AVS on behalf of which the payment is being made + * @dev The duration of the `rangePayment` cannot exceed `rewardsCoordinator.MAX_PAYMENT_DURATION()` + * @dev The tokens are sent to the `PaymentCoordinator` contract + * @dev Strategies must be in ascending order of addresses to check for duplicates + * @dev This function will revert if the `rangePayment` is malformed, + * e.g. if the `strategies` and `weights` arrays are of non-equal lengths + */ + function createAVSRewardsSubmission( + IRewardsCoordinator.RewardsSubmission[] calldata rewardsSubmissions + ) public virtual onlyOwner { + for (uint256 i = 0; i < rewardsSubmissions.length; ++i) { + // transfer token to ServiceManager and approve PaymentCoordinator to transfer again + // in createAVSRewardsSubmission() call + rewardsSubmissions[i].token.transferFrom(msg.sender, address(this), rewardsSubmissions[i].amount); + uint256 allowance = rewardsSubmissions[i].token.allowance(address(this), address(_rewardsCoordinator)); + rewardsSubmissions[i].token.approve(address(_rewardsCoordinator), rewardsSubmissions[i].amount + allowance); + } + + _rewardsCoordinator.createAVSRewardsSubmission(rewardsSubmissions); + } + + function createOperatorDirectedAVSRewardsSubmission( + IRewardsCoordinator.OperatorDirectedRewardsSubmission[] calldata rewardsSubmissions + ) public virtual onlyOwner { + for (uint256 i = 0; i < rewardsSubmissions.length; ++i) { + uint256 amount = 0; + for (uint256 j = 0; j < rewardsSubmissions[i].operatorRewards.length; ++j) { + amount += rewardsSubmissions[i].operatorRewards[j].amount; + } + rewardsSubmissions[i].token.transferFrom(msg.sender, address(this), amount); + uint256 allowance = rewardsSubmissions[i].token.allowance(address(this), address(_rewardsCoordinator)); + rewardsSubmissions[i].token.approve(address(_rewardsCoordinator), amount + allowance); + } + + _rewardsCoordinator.createOperatorDirectedAVSRewardsSubmission(address(this), rewardsSubmissions); + } + + /** + * @notice Forwards a call to EigenLayer's AVSDirectory contract to confirm operator registration with the AVS + * @param operator The address of the operator to register. + * @param operatorSignature The signature, salt, and expiry of the operator's signature. + */ + function registerOperatorToAVS( + address operator, + ISignatureUtils.SignatureWithSaltAndExpiry memory operatorSignature + ) public virtual { + _avsDirectory.registerOperatorToAVS(operator, operatorSignature); + } + + /** + * @notice Forwards a call to EigenLayer's AVSDirectory contract to confirm operator deregistration from the AVS + * @param operator The address of the operator to deregister. + */ + function deregisterOperatorFromAVS(address operator) public virtual { + _avsDirectory.deregisterOperatorFromAVS(operator); + } + + /** + * @notice Returns the list of strategies that the AVS supports for restaking + * @dev This function is intended to be called off-chain + * @dev No guarantee is made on uniqueness of each element in the returned array. + * The off-chain service should do that validation separately + */ + function getRestakeableStrategies() external view returns (address[] memory) { + return restakeableStrategies; + } + + /** + * @notice Returns the list of strategies that the operator has potentially restaked on the AVS + * @param operator The address of the operator to get restaked strategies for + * @dev This function is intended to be called off-chain + * @dev No guarantee is made on whether the operator has shares for a strategy in a quorum or uniqueness + * of each element in the returned array. The off-chain service should do that validation separately + */ + function getOperatorRestakedStrategies(address operator) external view returns (address[] memory) { + return operatorRestakedStrategies[operator]; + } + + function setRestakeableStrategies(address[] memory strategies) external { + delete restakeableStrategies; + for (uint256 i = 0; i < strategies.length; ++i) { + restakeableStrategies.push(strategies[i]); + } + } + + function setOperatorRestakedStrategies(address operator, address[] memory strategies) external { + delete operatorRestakedStrategies[operator]; + for (uint256 i = 0; i < strategies.length; ++i) { + operatorRestakedStrategies[operator].push(strategies[i]); + } + } + + /// @notice Returns the EigenLayer AVSDirectory contract. + function avsDirectory() external view returns (address) { + return address(_avsDirectory); + } + + function rewardsCoordinator() external view returns (address) { + return address(_rewardsCoordinator); + } + + // storage gap for upgradeability + // slither-disable-next-line shadowing-state + uint256[48] private __GAP; +} \ No newline at end of file diff --git a/script/utils/rewards_testing/StrategyToken.sol b/script/utils/rewards_testing/StrategyToken.sol new file mode 100644 index 000000000..fdab41535 --- /dev/null +++ b/script/utils/rewards_testing/StrategyToken.sol @@ -0,0 +1,16 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity ^0.8.12; + +import "@openzeppelin/contracts/token/ERC20/extensions/draft-ERC20Permit.sol"; +import "@openzeppelin/contracts/token/ERC20/presets/ERC20PresetFixedSupply.sol"; + +contract StrategyToken is ERC20PresetFixedSupply, ERC20Permit { + constructor( + string memory name, + string memory symbol, + uint256 initialSupply, + address owner + ) ERC20PresetFixedSupply(name, symbol, initialSupply, owner) ERC20Permit(name) { + // solhint-disable-previous-line no-empty-blocks + } +} \ No newline at end of file diff --git a/script/utils/rewards_testing/SubmitRewardsForAllEarners.s.sol b/script/utils/rewards_testing/SubmitRewardsForAllEarners.s.sol new file mode 100644 index 000000000..e7fe65fc9 --- /dev/null +++ b/script/utils/rewards_testing/SubmitRewardsForAllEarners.s.sol @@ -0,0 +1,367 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity ^0.8.12; + +import "script/utils/ExistingDeploymentParser.sol"; +import "./TransactionSubmitter.sol"; +import "@openzeppelin/contracts/utils/Strings.sol"; +import "@openzeppelin/contracts/token/ERC20/presets/ERC20PresetFixedSupply.sol"; + + +contract SubmitRewardsForAllEarners is ExistingDeploymentParser { + string contractsPath = "script/configs/holesky/eigenlayer_addresses_preprod.config.json"; + + function tx_1() public parseState { + // Deploy token + string memory name = "RewardForAllEarner_Test_1"; + string memory symbol = "RFA_1"; + IERC20 rewardToken = IERC20(_deployStablecoin(name, symbol)); + IRewardsCoordinator.RewardsSubmission[] memory rewardsSubmission = new IRewardsCoordinator.RewardsSubmission[](1); + + // Format strategies and multipliers + IStrategy[] memory strategies = _getOldStrategies(); + IRewardsCoordinator.StrategyAndMultiplier[] memory strategyAndMultipliers = new IRewardsCoordinator.StrategyAndMultiplier[](strategies.length); + for (uint256 i = 0; i < strategies.length; i++) { + strategyAndMultipliers[i] = IRewardsCoordinator.StrategyAndMultiplier({ + strategy: strategies[i], + multiplier: 1 + }); + } + + // Format Range + uint32 moddedCurrTimestamp = uint32(block.timestamp) - (uint32(block.timestamp) % rewardsCoordinator.CALCULATION_INTERVAL_SECONDS()); + uint32 startTimestamp = moddedCurrTimestamp - rewardsCoordinator.MAX_REWARDS_DURATION(); + uint32 duration = rewardsCoordinator.MAX_REWARDS_DURATION(); + + rewardsSubmission[0] = IRewardsCoordinator.RewardsSubmission({ + strategiesAndMultipliers: strategyAndMultipliers, + token: rewardToken, + amount: 10_000e6, + startTimestamp: startTimestamp, + duration: duration + }); + + _submitRewardsForAllEarners(rewardsSubmission); + } + + function tx_2() public parseState { + // Deploy token + string memory name = "RewardForAllEarner_Test_2"; + string memory symbol = "RFA_2"; + IERC20 rewardToken = IERC20(_deployToken(name, symbol)); + IRewardsCoordinator.RewardsSubmission[] memory rewardsSubmission = new IRewardsCoordinator.RewardsSubmission[](1); + + // Format strategies and multipliers + IStrategy[] memory strategies = _getOldStrategies(); + IRewardsCoordinator.StrategyAndMultiplier[] memory strategyAndMultipliers = new IRewardsCoordinator.StrategyAndMultiplier[](strategies.length); + for (uint256 i = 0; i < strategies.length; i++) { + strategyAndMultipliers[i] = IRewardsCoordinator.StrategyAndMultiplier({ + strategy: strategies[i], + multiplier: type(uint96).max + }); + } + + // Format Range + uint32 moddedCurrTimestamp = uint32(block.timestamp) - (uint32(block.timestamp) % rewardsCoordinator.CALCULATION_INTERVAL_SECONDS()); + uint32 startTimestamp = moddedCurrTimestamp - (rewardsCoordinator.MAX_REWARDS_DURATION()/2); + uint32 duration = rewardsCoordinator.MAX_REWARDS_DURATION(); + + rewardsSubmission[0] = IRewardsCoordinator.RewardsSubmission({ + strategiesAndMultipliers: strategyAndMultipliers, + token: rewardToken, + amount: 10_000e18, + startTimestamp: startTimestamp, + duration: duration + }); + + _submitRewardsForAllEarners(rewardsSubmission); + } + + function tx_3() public parseState { + // Deploy token + string memory name = "RewardForAllEarner_Test_3"; + string memory symbol = "RFA_3"; + IERC20 rewardToken = IERC20(_deployToken(name, symbol)); + IRewardsCoordinator.RewardsSubmission[] memory rewardsSubmission = new IRewardsCoordinator.RewardsSubmission[](1); + + // Format strategies and multipliers + IStrategy[] memory strategies = _getAllStrategies(); + IRewardsCoordinator.StrategyAndMultiplier[] memory strategyAndMultipliers = new IRewardsCoordinator.StrategyAndMultiplier[](strategies.length); + for (uint256 i = 0; i < strategies.length; i++) { + strategyAndMultipliers[i] = IRewardsCoordinator.StrategyAndMultiplier({ + strategy: strategies[i], + multiplier: uint96(vm.randomUint(1e18, 10e18)) + }); + } + + // Format Range + uint32 moddedCurrTimestamp = uint32(block.timestamp) - (uint32(block.timestamp) % rewardsCoordinator.CALCULATION_INTERVAL_SECONDS()); + uint32 startTimestamp = moddedCurrTimestamp - 1 weeks; + uint32 duration = 1 weeks; + + rewardsSubmission[0] = IRewardsCoordinator.RewardsSubmission({ + strategiesAndMultipliers: strategyAndMultipliers, + token: rewardToken, + amount: 1_000_000e18, + startTimestamp: startTimestamp, + duration: duration + }); + + _submitRewardsForAllEarners(rewardsSubmission); + } + + function tx_4() public parseState { + // Deploy token + string memory name = "RewardForAllEarner_Test_4"; + string memory symbol = "RFA_4"; + IERC20 rewardToken = IERC20(_deployToken(name, symbol)); + IRewardsCoordinator.RewardsSubmission[] memory rewardsSubmission = new IRewardsCoordinator.RewardsSubmission[](1); + + // Format strategies and multipliers + IStrategy[] memory strategies = _getOldStrategies(); + uint96[] memory multipliers = _getEigenDAMultipliers(); + IRewardsCoordinator.StrategyAndMultiplier[] memory strategyAndMultipliers = new IRewardsCoordinator.StrategyAndMultiplier[](strategies.length); + for (uint256 i = 0; i < strategies.length; i++) { + strategyAndMultipliers[i] = IRewardsCoordinator.StrategyAndMultiplier({ + strategy: strategies[i], + multiplier: multipliers[i] + }); + } + + // Format Range + uint32 moddedCurrTimestamp = uint32(block.timestamp) - (uint32(block.timestamp) % rewardsCoordinator.CALCULATION_INTERVAL_SECONDS()); + uint32 startTimestamp = moddedCurrTimestamp - 1 weeks; + uint32 duration = 2 weeks; + + rewardsSubmission[0] = IRewardsCoordinator.RewardsSubmission({ + strategiesAndMultipliers: strategyAndMultipliers, + token: rewardToken, + amount: 100_000e18, + startTimestamp: startTimestamp, + duration: duration + }); + + _submitRewardsForAllEarners(rewardsSubmission); + } + + function tx_8() public parseState { + // Deploy token + string memory name = "RewardForAllEarner_Test_8"; + string memory symbol = "RFA_8"; + IERC20 rewardToken = IERC20(_deployToken(name, symbol)); + IRewardsCoordinator.RewardsSubmission[] memory rewardsSubmission = new IRewardsCoordinator.RewardsSubmission[](1); + + // Format strategies and multipliers + IStrategy[] memory strategies = _getTxSubmitterStrategies(); + IRewardsCoordinator.StrategyAndMultiplier[] memory strategyAndMultipliers = new IRewardsCoordinator.StrategyAndMultiplier[](strategies.length); + for (uint256 i = 0; i < strategies.length; i++) { + strategyAndMultipliers[i] = IRewardsCoordinator.StrategyAndMultiplier({ + strategy: strategies[i], + multiplier: uint96(vm.randomUint(1e18, 10e18)) + }); + } + + // Format Range + uint32 moddedCurrTimestamp = uint32(block.timestamp) - (uint32(block.timestamp) % rewardsCoordinator.CALCULATION_INTERVAL_SECONDS()); + uint32 startTimestamp = 1724889600; + uint32 duration = 6 weeks; + + rewardsSubmission[0] = IRewardsCoordinator.RewardsSubmission({ + strategiesAndMultipliers: strategyAndMultipliers, + token: rewardToken, + amount: 1_000_000e18, + startTimestamp: startTimestamp, + duration: duration + }); + + _submitRewardsForAllEarners(rewardsSubmission); + } + + function tx_4_and_5() public parseState { + IRewardsCoordinator.RewardsSubmission[] memory rewardsSubmission = new IRewardsCoordinator.RewardsSubmission[](2); + + // Tx 4 + IERC20 transaction4RewardToken = IERC20(0x826FaE505F3652eD85A5Fa9cB9ab98AD1AE434de); + IStrategy[] memory strategies = _getOldStrategies(); + uint96[] memory multipliers = _getEigenDAMultipliers(); + IRewardsCoordinator.StrategyAndMultiplier[] memory strategyAndMultipliers = new IRewardsCoordinator.StrategyAndMultiplier[](strategies.length); + for (uint256 i = 0; i < strategies.length; i++) { + strategyAndMultipliers[i] = IRewardsCoordinator.StrategyAndMultiplier({ + strategy: strategies[i], + multiplier: multipliers[i] + }); + } + + // Format Range + uint32 moddedCurrTimestamp = uint32(block.timestamp) - (uint32(block.timestamp) % rewardsCoordinator.CALCULATION_INTERVAL_SECONDS()); + uint32 startTimestamp = moddedCurrTimestamp - 1 weeks; + uint32 duration = 2 weeks; + + rewardsSubmission[0] = IRewardsCoordinator.RewardsSubmission({ + strategiesAndMultipliers: strategyAndMultipliers, + token: transaction4RewardToken, + amount: 100_000e18, + startTimestamp: startTimestamp, + duration: duration + }); + + + // Tx 5 + IERC20 transaction5RewardToken = IERC20(0x23bC9Db0e7976B68835C12338715C2DB0ebC9C1e); + strategies = _getTxSubmitterStrategies(); + IRewardsCoordinator.StrategyAndMultiplier[] memory strategyAndMultipliersTx5 = new IRewardsCoordinator.StrategyAndMultiplier[](strategies.length); + for (uint256 i = 0; i < strategies.length; i++) { + strategyAndMultipliersTx5[i] = IRewardsCoordinator.StrategyAndMultiplier({ + strategy: strategies[i], + multiplier: uint96(vm.randomUint(1e18, 10e18)) + }); + } + + // Format Range + moddedCurrTimestamp = uint32(block.timestamp) - (uint32(block.timestamp) % rewardsCoordinator.CALCULATION_INTERVAL_SECONDS()); + startTimestamp = moddedCurrTimestamp - 1 weeks; + duration = 2 weeks; + + rewardsSubmission[1] = IRewardsCoordinator.RewardsSubmission({ + strategiesAndMultipliers: strategyAndMultipliersTx5, + token: transaction5RewardToken, + amount: 1_000_000e18, + startTimestamp: startTimestamp, + duration: duration + }); + + _submitRewardsForAllEarners(rewardsSubmission); + } + + + function _deployToken(string memory name, string memory symbol) public returns (address) { + uint256 tokenInitialSupply = 1e36; + vm.startBroadcast(); + ERC20PresetFixedSupply rewardToken = new ERC20PresetFixedSupply( + name, + symbol, + tokenInitialSupply, + msg.sender + ); + rewardToken.approve(address(rewardsCoordinator), tokenInitialSupply); + vm.stopBroadcast(); + return address(rewardToken); + } + + function _deployStablecoin(string memory name, string memory symbol) public returns (address) { + uint256 tokenInitialSupply = 1_000_000_000e6; + vm.startBroadcast(); + TestStablecoin rewardToken = new TestStablecoin( + name, + symbol, + tokenInitialSupply, + msg.sender + ); + rewardToken.approve(address(rewardsCoordinator), tokenInitialSupply); + vm.stopBroadcast(); + return address(rewardToken); + } + + function _submitRewardsForAllEarners( + IRewardsCoordinator.RewardsSubmission[] memory rewardsSubmissions + ) internal { + vm.startBroadcast(); + rewardsCoordinator.createRewardsForAllEarners(rewardsSubmissions); + vm.stopBroadcast(); + } + + function _getTxSubmitterStrategies() public view returns (IStrategy[] memory) { + TransactionSubmitter txSubmitter = TransactionSubmitter(payable(0x5a80a187a159A5d8dfC5bD16236E5657e945ec3d)); + IStrategy[] memory strategies = txSubmitter.getAllStrategies(); + + // Sort strategies by address + for (uint256 i = 0; i < strategies.length; i++) { + for (uint256 j = i + 1; j < strategies.length; j++) { + if (address(strategies[i]) > address(strategies[j])) { + IStrategy temp = strategies[i]; + strategies[i] = strategies[j]; + strategies[j] = temp; + } + } + } + return strategies; + } + + /// @notice Strategies that are previously used in the system + function _getOldStrategies() internal pure returns (IStrategy[] memory) { + IStrategy[] memory strategies = new IStrategy[](6); + strategies[0] = IStrategy(0x5C8b55722f421556a2AAfb7A3EA63d4c3e514312); + strategies[1] = IStrategy(0x6E5D5060B33ca2090A78E9cb74Fe207453b30E49); + strategies[2] = IStrategy(0x7fA77c321bf66e42eaBC9b10129304F7f90c5585); + strategies[3] = IStrategy(0xbeaC0eeEeeeeEEeEeEEEEeeEEeEeeeEeeEEBEaC0); + strategies[4] = IStrategy(0xD523267698C81a372191136e477fdebFa33D9FB4); + strategies[5] = IStrategy(0xdcCF401fD121d8C542E96BC1d0078884422aFAD2); + + return strategies; + } + + function _getEigenDAMultipliers() internal pure returns (uint96[] memory) { + uint96[] memory multipliers = new uint96[](6); + + multipliers[0] = 1152393415227598758; + multipliers[1] = 1102456657360376283; + multipliers[2] = 1028802524926876401; + multipliers[3] = 1000000000000000000; + multipliers[4] = 1012495275290785447; + multipliers[5] = 1035345726488000000; + + return multipliers; + } + + function _getAllStrategies() internal view returns (IStrategy[] memory) { + IStrategy[] memory oldStrategies = _getOldStrategies(); + IStrategy[] memory newStrategies = _getTxSubmitterStrategies(); + IStrategy[] memory allStrategies = new IStrategy[](oldStrategies.length + newStrategies.length); + + // Create a sorted array, allStrategies, that returns the concatenation of old and new strateiges but in sorted order + uint256 i = 0; + uint256 j = 0; + uint256 k = 0; + while (i < oldStrategies.length && j < newStrategies.length) { + if (address(oldStrategies[i]) < address(newStrategies[j])) { + allStrategies[k] = oldStrategies[i]; + i++; + } else { + allStrategies[k] = newStrategies[j]; + j++; + } + k++; + } + + while (i < oldStrategies.length) { + allStrategies[k] = oldStrategies[i]; + i++; + k++; + } + + while (j < newStrategies.length) { + allStrategies[k] = newStrategies[j]; + j++; + k++; + } + + return allStrategies; + } + + modifier parseState() { + _parseDeployedContracts(contractsPath); + _; + } +} + +contract TestStablecoin is ERC20PresetFixedSupply { + constructor( + string memory name, + string memory symbol, + uint256 initialSupply, + address owner + ) ERC20PresetFixedSupply(name, symbol, initialSupply, owner) {} + + function decimals() public pure override returns (uint8) { + return 6; + } +} \ No newline at end of file diff --git a/script/utils/rewards_testing/TestRewardsV2.sol b/script/utils/rewards_testing/TestRewardsV2.sol new file mode 100644 index 000000000..74fd1c575 --- /dev/null +++ b/script/utils/rewards_testing/TestRewardsV2.sol @@ -0,0 +1,334 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity ^0.8.12; + +import "./TransactionSubmitter.sol"; +import "script/utils/ExistingDeploymentParser.sol"; + +import "@openzeppelin/contracts/token/ERC20/presets/ERC20PresetFixedSupply.sol"; +import "zeus-templates/utils/ZeusScript.sol"; + +contract TestRewardsV2 is ZeusScript { + uint256 maxOperatorIndex = 80; + string MNEMONIC; + TransactionSubmitter transactionSubmitter; + string statePath = "script/utils/rewards_testing/preprod_state.json"; + + + function tx_prep() public parseState { + // Deploy token + (address[] memory operatorsRegisteredToAVS, uint256[] memory privateKeys) = _getAllOperatorsRegisteredToAVS(address(_rewardingServiceManager())); + + // for the first 3/5 of the operators, set the AVS split to random values + for (uint256 i = 0; i < operatorsRegisteredToAVS.length*3/5; i++) { + vm.startBroadcast(privateKeys[i]); + _rewardsCoordinator().setOperatorAVSSplit(operatorsRegisteredToAVS[i], address(_rewardingServiceManager()), uint16(vm.randomUint(1, 10000))); + vm.stopBroadcast(); + } + + // for 1/5 through 4/5 of the operators, set the PI split to random values + for (uint256 i = operatorsRegisteredToAVS.length*1/5; i < operatorsRegisteredToAVS.length*4/5; i++) { + vm.startBroadcast(privateKeys[i]); + _rewardsCoordinator().setOperatorPISplit(operatorsRegisteredToAVS[i], uint16(vm.randomUint(1, 10000))); + vm.stopBroadcast(); + } + + // this leaves 1/5 of the operators with no splits set + } + + function tx_1() public parseState { + // Deploy token + string memory name = "RewardsV2_OperatorDirectedRewards_Test_1"; + string memory symbol = "R2_ODR_1"; + IERC20 rewardToken = IERC20(_deployToken(name, symbol)); + IRewardsCoordinator.OperatorDirectedRewardsSubmission[] memory rewardsSubmission = new IRewardsCoordinator.OperatorDirectedRewardsSubmission[](1); + + // Format strategies and multipliers + IStrategy[] memory strategies = _getAVStrategies(); + IRewardsCoordinator.StrategyAndMultiplier[] memory strategyAndMultipliers = new IRewardsCoordinator.StrategyAndMultiplier[](strategies.length); + for (uint256 i = 0; i < strategies.length; i++) { + strategyAndMultipliers[i] = IRewardsCoordinator.StrategyAndMultiplier({ + strategy: strategies[i], + multiplier: 1e18 + }); + } + + // Format Range + uint32 moddedCurrTimestamp = uint32(block.timestamp) - (uint32(block.timestamp) % _rewardsCoordinator().CALCULATION_INTERVAL_SECONDS()); + uint32 startTimestamp = moddedCurrTimestamp - _rewardsCoordinator().MAX_REWARDS_DURATION(); + uint32 duration = _rewardsCoordinator().MAX_REWARDS_DURATION(); + + (address[] memory operatorsRegisteredToAVS,) = _getAllOperatorsRegisteredToAVS(address(_rewardingServiceManager())); + + rewardsSubmission[0] = IRewardsCoordinator.OperatorDirectedRewardsSubmission({ + strategiesAndMultipliers: strategyAndMultipliers, + token: rewardToken, + operatorRewards: _getRandomOperatorRewards(operatorsRegisteredToAVS, 1e18), + startTimestamp: startTimestamp, + duration: duration, + description: "Test 1" + }); + + _submitOperatorDirectedRewards(rewardsSubmission); + } + + // Send a regular rewards submission + function tx_2() public parseState { + // Deploy token + string memory name = "RewardsV2_AVSRewardsSubmission_Test_2"; + string memory symbol = "R2_AVSR_2"; + IERC20 rewardToken = IERC20(_deployToken(name, symbol)); + IRewardsCoordinator.RewardsSubmission[] memory rewardsSubmission = new IRewardsCoordinator.RewardsSubmission[](1); + + // TODO: replace + IStrategy[] memory strategies = _getAVStrategies(); + IRewardsCoordinator.StrategyAndMultiplier[] memory strategyAndMultipliers = new IRewardsCoordinator.StrategyAndMultiplier[](strategies.length); + for (uint256 i = 0; i < strategies.length; i++) { + strategyAndMultipliers[i] = IRewardsCoordinator.StrategyAndMultiplier({ + strategy: strategies[i], + multiplier: 1e18 + }); + } + + // Format Range + uint32 moddedCurrTimestamp = uint32(block.timestamp) - (uint32(block.timestamp) % _rewardsCoordinator().CALCULATION_INTERVAL_SECONDS()); + uint32 startTimestamp = moddedCurrTimestamp - 1 weeks; + uint32 duration = 1 weeks; + + rewardsSubmission[0] = IRewardsCoordinator.RewardsSubmission({ + strategiesAndMultipliers: strategyAndMultipliers, + token: rewardToken, + amount: 1e36, + startTimestamp: startTimestamp, + duration: duration + }); + + _submitAVSRewardsSubmission(rewardsSubmission); + } + + // Send a PI submission + function tx_3() public parseState { + // Deploy token + string memory name = "RewardsV2_RFA_Test_3"; + string memory symbol = "R2_RFA_3"; + IERC20 rewardToken = IERC20(_deployToken(name, symbol)); + IRewardsCoordinator.RewardsSubmission[] memory rewardsSubmission = new IRewardsCoordinator.RewardsSubmission[](1); + + // Format strategies and multipliers + // This is to all the other old stakers on preprod, so use the old strategies + IStrategy[] memory strategies = _getAVStrategies(); + IRewardsCoordinator.StrategyAndMultiplier[] memory strategyAndMultipliers = new IRewardsCoordinator.StrategyAndMultiplier[](strategies.length); + for (uint256 i = 0; i < strategies.length; i++) { + strategyAndMultipliers[i] = IRewardsCoordinator.StrategyAndMultiplier({ + strategy: strategies[i], + multiplier: 1e18 + }); + } + + // Format Range + uint32 calculationIntervalSeconds = _rewardsCoordinator().CALCULATION_INTERVAL_SECONDS(); + uint32 moddedCurrTimestamp = uint32(block.timestamp) - (uint32(block.timestamp) % calculationIntervalSeconds); + uint32 startTimestamp = moddedCurrTimestamp; + uint32 duration = calculationIntervalSeconds; + + rewardsSubmission[0] = IRewardsCoordinator.RewardsSubmission({ + strategiesAndMultipliers: strategyAndMultipliers, + token: rewardToken, + amount: 1e36, + startTimestamp: startTimestamp, + duration: duration + }); + + _submitRewardsForAllEarners(rewardsSubmission); + } + + function _deployToken(string memory name, string memory symbol) public returns (address) { + uint256 tokenInitialSupply = 1e36; + vm.startBroadcast(); + ERC20PresetFixedSupply rewardToken = new ERC20PresetFixedSupply( + name, + symbol, + tokenInitialSupply, + msg.sender + ); + rewardToken.approve(address(_rewardsCoordinator()), tokenInitialSupply); + vm.stopBroadcast(); + return address(rewardToken); + } + + function _submitOperatorDirectedRewards( + IRewardsCoordinator.OperatorDirectedRewardsSubmission[] memory rewardsSubmissions + ) internal { + ServiceManagerMock serviceManager = _rewardingServiceManager(); + vm.startBroadcast(); + for (uint256 i = 0; i < rewardsSubmissions.length; i++) { + rewardsSubmissions[i].token.approve(address(serviceManager), type(uint256).max); + } + serviceManager.createOperatorDirectedAVSRewardsSubmission(rewardsSubmissions); + vm.stopBroadcast(); + } + + function _submitAVSRewardsSubmission( + IRewardsCoordinator.RewardsSubmission[] memory rewardsSubmissions + ) internal { + ServiceManagerMock serviceManager = _rewardingServiceManager(); + vm.startBroadcast(); + serviceManager.createAVSRewardsSubmission(rewardsSubmissions); + vm.stopBroadcast(); + } + + function _submitRewardsForAllEarners( + IRewardsCoordinator.RewardsSubmission[] memory rewardsSubmissions + ) internal { + vm.startBroadcast(); + _rewardsCoordinator().createRewardsForAllEarners(rewardsSubmissions); + vm.stopBroadcast(); + } + + function _getAllOperatorsRegisteredToAVS(address avs) internal returns (address[] memory, uint256[] memory) { + AVSDirectory avsDirectory = AVSDirectory(zDeployedProxy(type(AVSDirectory).name)); + + // Get all operators + (address[] memory allOperators, uint256[] memory privateKeys) = _getAllRegisteredOperators(); + + // Get which operators are registered to the AVS + bool[] memory isRegisteredToAVS = new bool[](allOperators.length); + uint256 numOperatorsRegisteredToAVS = 0; + for (uint256 i = 0; i < allOperators.length; i++) { + isRegisteredToAVS[i] = avsDirectory.avsOperatorStatus(avs, allOperators[i]) == IAVSDirectory.OperatorAVSRegistrationStatus.REGISTERED; + if (isRegisteredToAVS[i]) { + numOperatorsRegisteredToAVS++; + } + } + + // Filter the operators that are registered to the AVS + address[] memory operatorsRegisteredToAVS = new address[](numOperatorsRegisteredToAVS); + uint256 numRegistered = 0; + for (uint256 i = 0; i < allOperators.length; i++) { + if (isRegisteredToAVS[i]) { + operatorsRegisteredToAVS[numRegistered] = allOperators[i]; + numRegistered++; + } + if (numRegistered == numOperatorsRegisteredToAVS) { + break; + } + } + + // sort the operators by address + for (uint256 i = 0; i < operatorsRegisteredToAVS.length; i++) { + for (uint256 j = i + 1; j < operatorsRegisteredToAVS.length; j++) { + if (operatorsRegisteredToAVS[i] > operatorsRegisteredToAVS[j]) { + address temp = operatorsRegisteredToAVS[i]; + operatorsRegisteredToAVS[i] = operatorsRegisteredToAVS[j]; + operatorsRegisteredToAVS[j] = temp; + } + } + } + return (operatorsRegisteredToAVS, privateKeys); + } + + modifier parseState() { + _parseState(statePath); + _; + } + + function _parseState(string memory statePathToParse) internal { + // READ JSON CONFIG DATA + string memory stateData = vm.readFile(statePathToParse); + emit log_named_string("Using state file", statePathToParse); + + transactionSubmitter = TransactionSubmitter(payable(stdJson.readAddress(stateData, ".submitterProxy"))); + MNEMONIC = vm.envString("MNEMONIC"); + } + + function _rewardingServiceManager() internal view returns (ServiceManagerMock) { + address[] memory avss = transactionSubmitter.getAllAVSs(); + + return ServiceManagerMock(avss[0]); + } + + function _rewardsCoordinator() internal view returns (IRewardsCoordinator) { + return IRewardsCoordinator(zDeployedProxy(type(RewardsCoordinator).name)); + } + + /// @notice Strategies that are previously used in the system + function _getOldStrategies() internal pure returns (IStrategy[] memory) { + IStrategy[] memory strategies = new IStrategy[](6); + strategies[0] = IStrategy(0x5C8b55722f421556a2AAfb7A3EA63d4c3e514312); + strategies[1] = IStrategy(0x6E5D5060B33ca2090A78E9cb74Fe207453b30E49); + strategies[2] = IStrategy(0x7fA77c321bf66e42eaBC9b10129304F7f90c5585); + strategies[3] = IStrategy(0xbeaC0eeEeeeeEEeEeEEEEeeEEeEeeeEeeEEBEaC0); + strategies[4] = IStrategy(0xD523267698C81a372191136e477fdebFa33D9FB4); + strategies[5] = IStrategy(0xdcCF401fD121d8C542E96BC1d0078884422aFAD2); + + return strategies; + } + + function _getAVStrategies() internal pure returns (IStrategy[] memory) { + IStrategy[] memory strategies = new IStrategy[](15); + + strategies[0] = IStrategy(0x08f8544E61Ebfa22e7c6ef9af9eFd428091b27AF); + strategies[1] = IStrategy(0x31741340ab31e90f0624d2C843B323a97755f43a); + strategies[2] = IStrategy(0x845aDA440F3BA5652e6f7c6Bbcd8fCAd068Be9c9); + strategies[3] = IStrategy(0xcD6EDf68a5Fc79BBc14A0eCa1C8bbDe495fB1a5f); + strategies[4] = IStrategy(0x77335a08a877cd874165bDC766feeD951a0d84c8); + strategies[5] = IStrategy(0x53C916338FcA4f5541bc2eA5E5f7F0Ca6f0dAf6a); + strategies[6] = IStrategy(0x77335a08a877cd874165bDC766feeD951a0d84c8); + strategies[7] = IStrategy(0x51366AEf35475e82B864f2E7867B293c3BC61D86); + strategies[8] = IStrategy(0x5803f7D0D273aa0B9774C0aDAB98A23ec348Ea77); + strategies[9] = IStrategy(0xe5e8BcBd1DDD07460fA67f617a2D018ce0f5b7bf); + strategies[10] = IStrategy(0x419B6Ba569169826d9A45565E651F03B8DdfA332); + strategies[11] = IStrategy(0x9b5F92ed40e1436Ac8E31fd7f7bc6083edBd5E71); + strategies[12] = IStrategy(0xE34b1Da874E6B9f091540c850095b99B4D3B475D); + strategies[13] = IStrategy(0x8EF42562E9F1b81010a54615673739dd91E10016); + strategies[14] = IStrategy(0xdE2788cb747b51a1747Bd59342b6214652Ddeb10); + + // sort strategies by address + for (uint256 i = 0; i < strategies.length; i++) { + for (uint256 j = i + 1; j < strategies.length; j++) { + if (address(strategies[i]) > address(strategies[j])) { + IStrategy temp = strategies[i]; + strategies[i] = strategies[j]; + strategies[j] = temp; + } + } + } + + return strategies; + } + + function _getAllRegisteredOperators() internal returns(address[] memory, uint256[] memory){ + address[] memory operators = new address[](maxOperatorIndex); + uint256[] memory privateKeys = new uint256[](maxOperatorIndex); + for(uint256 i = 0; i < operators.length; i++){ + (address operator, uint256 privateKey) = deriveRememberKey(MNEMONIC, uint32(i)); + operators[i] = operator; + privateKeys[i] = privateKey; + } + return (operators, privateKeys); + } + + function _getRandomOperatorRewards(address[] memory operators, uint256 max) internal returns (IRewardsCoordinator.OperatorReward[] memory) { + IRewardsCoordinator.OperatorReward[] memory operatorRewards = new IRewardsCoordinator.OperatorReward[](operators.length); + for (uint256 i = 0; i < operators.length; i++) { + operatorRewards[i] = IRewardsCoordinator.OperatorReward({ + operator: operators[i], + amount: vm.randomUint(1, max) + }); + } + return operatorRewards; + } + +} + +contract TestStablecoin is ERC20PresetFixedSupply { + constructor( + string memory name, + string memory symbol, + uint256 initialSupply, + address owner + ) ERC20PresetFixedSupply(name, symbol, initialSupply, owner) {} + + function decimals() public pure override returns (uint8) { + return 6; + } +} \ No newline at end of file diff --git a/script/utils/rewards_testing/TransactionBuilder.s.sol b/script/utils/rewards_testing/TransactionBuilder.s.sol new file mode 100644 index 000000000..60fb7bd51 --- /dev/null +++ b/script/utils/rewards_testing/TransactionBuilder.s.sol @@ -0,0 +1,787 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity ^0.8.12; + +import "./TransactionSubmitter.sol"; +import "script/utils/ExistingDeploymentParser.sol"; +import "@openzeppelin/contracts/utils/Strings.sol"; +import "zeus-templates/utils/ZeusScript.sol"; +/** + * Operator Indices: Derived from `MNEMONIC`. Indices 0-1000 + * AVS Indices: Contract 0-10 in `transaction_submitter` + * Strategy Indices: Contract 0-15 in `transaction_submitter` + * Staker Indices: Derived from `MNEMONIC`. Indices 750-100_000 (500 operators have also deposited) + * AVS Indices: Contract 0-5 in `transaction_submitter` + */ +contract TransactionBuilder is ZeusScript { + Vm cheats = Vm(VM_ADDRESS); + using Strings for uint256; + + // Addresses set by _parseState function + ProxyAdmin proxyAdmin; + TransactionSubmitter transactionSubmitter; + uint256 operatorsRegistered; + string MNEMONIC; + + // Path to state so we do not duplicate transactions deployed directly from this contract + string statePath = "script/utils/rewards_testing/preprod_state.json"; + + // Operator Indices + uint256 minOperatorIndex = 0; + uint256 maxOperatorIndex = 1000; + uint256 numOperatorsRegisteredToAVSs = 80; + + // Staker Indices + uint256 minStakerIndex = 750; + uint256 stakerNonOperatorStartIndex = 1001; + uint256 maxStakerIndex = 51_000; // 50000 pure stakers. 250 opStakers + uint256 firstHalfStakerIndex = 26_000; + + // AVS Indices + uint16 minAVSIndex = 0; + uint16 maxAVSIndex = 5; + + + /** + * @notice Seeds operators with 0.0003 ETH + */ + function seedOperators() external parseState { + address[] memory operators = _getAllOperators(); + uint256 amountToSend = 0.0003 ether; + + uint256 batchSize = 100; + + // Split up operators into batches of `batchSize` + for(uint256 i = 0; i < operators.length; i += batchSize){ + address[] memory batch = new address[](batchSize); + for(uint256 j = 0; j < batchSize; j++){ + batch[j] = operators[i + j]; + } + + vm.startBroadcast(); + // todo: make this payable + address(transactionSubmitter).call{value: amountToSend * batch.length}(""); + transactionSubmitter.sendEth(batch, amountToSend); + vm.stopBroadcast(); + } + } + + /** + * @notice Registers operators with the DelegationManager + * @dev This function is not deployed by the Submitter contract since we save no gas by doing so + */ + function registerOperators() external parseState { + IDelegationManager.OperatorDetails memory operatorDetails = IDelegationManager.OperatorDetails({ + __deprecated_earningsReceiver: address(0x000000000000000000000000000000000000dEaD), + delegationApprover: address(0), + stakerOptOutWindowBlocks: 0 + }); + + for(uint256 i = operatorsRegistered; i < maxOperatorIndex; i++){ + (address operator, uint256 privateKey) = deriveRememberKey(MNEMONIC, uint32(i)); + + vm.startBroadcast(operator); + _delegationManager().registerAsOperator(operatorDetails, ""); + vm.stopBroadcast(); + + operatorsRegistered++; + } + + emit log_named_uint("Operators Deployed", operatorsRegistered); + } + + /** + * @notice Registers operators to AVSs + * @dev A random number of AVSs are registered to for each operator + */ + function registerOperatorsToAVSs() external parseState { + address[] memory avss = transactionSubmitter.getAllAVSs(); + uint256 batchSize = 40; + + for (uint256 i = 0; i < numOperatorsRegisteredToAVSs; i += batchSize) { + TransactionSubmitter.OperatorAVSRegistration[] memory registrations = new TransactionSubmitter.OperatorAVSRegistration[](batchSize); + + for (uint256 j = 0; j < batchSize; j++) { + // Get operator + (address operator, uint256 privateKey) = deriveRememberKey(MNEMONIC, uint32(i + j)); + + // Get number of avss to register + address[] memory avssToRegister = _getRandomAVSs(avss); + ISignatureUtils.SignatureWithSaltAndExpiry[] memory signatures = _getOperatorSignatures(privateKey, operator, avssToRegister); + + // Push currRegistration to registrations + registrations[j] = TransactionSubmitter.OperatorAVSRegistration({ + operator: operator, + avss: avssToRegister, + sigs: signatures + }); + } + + vm.startBroadcast(); + transactionSubmitter.registerOperatorsToAVSs(registrations); + vm.stopBroadcast(); + } + } + + function registerOperatorsToAVSsByIndex(uint32 operatorIndex) external parseState { + address[] memory avss = transactionSubmitter.getAllAVSs(); + + (address operator, uint256 privateKey) = deriveRememberKey(MNEMONIC, uint32(operatorIndex)); + + // Get number of avss to register + address[] memory avssToRegister = _getRandomAVSs(avss); + ISignatureUtils.SignatureWithSaltAndExpiry[] memory signatures = _getOperatorSignatures(privateKey, operator, avssToRegister); + + // Push currRegistration to registrations + TransactionSubmitter.OperatorAVSRegistration[] memory registrations = new TransactionSubmitter.OperatorAVSRegistration[](1); + registrations[0] = TransactionSubmitter.OperatorAVSRegistration({ + operator: operator, + avss: avssToRegister, + sigs: signatures + }); + + vm.startBroadcast(); + transactionSubmitter.registerOperatorsToAVSs(registrations); + vm.stopBroadcast(); + } + + /** + * @notice Deploys TransactionSubmitter contract based on existing network config file + */ + function deployTransactionSubmitter() external parseState { + vm.startBroadcast(); + + // Deploy TransactionSubmitterImpl + TransactionSubmitter transactionSubmitterImpl = new TransactionSubmitter( + _delegationManager(), + _avsDirectory(), + _strategyManager(), + IRewardsCoordinator(zDeployedProxy(type(RewardsCoordinator).name)), + _strategyFactory() + ); + + // Deploy ProxyAdmin + ProxyAdmin transactionSubmitterProxyAdmin = new ProxyAdmin(); + + // Deploy Proxy + TransparentUpgradeableProxy transactionSubmitterProxy = new TransparentUpgradeableProxy( + address(transactionSubmitterImpl), + address(proxyAdmin), + "" + ); + + vm.stopBroadcast(); + + + console.log("ProxyAdmin deployed at: ", address(transactionSubmitterProxyAdmin)); + console.log("TransactionSubmitterProxy deployed at: ", address(transactionSubmitterProxy)); + console.log("TransactionSubmitterImpl deployed at: ", address(transactionSubmitterImpl)); + } + + /** + * @notice Upgrades TransactionSubmitter contract based on existing network config file + * @dev Expects `transactionSubmitter` and `proxyAdmin` to be set locally + */ + function upgradeTransactionSubmitter() external parseState { + + vm.startBroadcast(); + + // Deploy new TransactionSubmitterImpl + TransactionSubmitter transactionSubmitterImpl = new TransactionSubmitter( + _delegationManager(), + _avsDirectory(), + _strategyManager(), + IRewardsCoordinator(zDeployedProxy(type(RewardsCoordinator).name)), + _strategyFactory() + ); + + // Upgrade Proxy + proxyAdmin.upgrade(TransparentUpgradeableProxy(payable(address(transactionSubmitter))), address(transactionSubmitterImpl)); + + vm.stopBroadcast(); + + console.log("TransactionSubmitterProxy upgraded to: ", address(transactionSubmitterImpl)); + } + + function deployCustomStrategies() external parseState { + string[] memory names = new string[](14); + string[] memory symbols = new string[](14); + uint256 startIndex = 1; + + for (uint256 i = 0; i < 14; i++) { + names[i] = string.concat("StrategyToken_", startIndex.toString()); + symbols[i] = string.concat("ST_", startIndex.toString()); + startIndex++; + } + vm.startBroadcast(); + transactionSubmitter.deployCustomStrategies(names, symbols); + vm.stopBroadcast(); + } + + function delegateFirstHalfOfStakers() external parseState { + uint256 firstStaker = stakerNonOperatorStartIndex; + uint256 lastStaker = firstHalfStakerIndex; + + uint256 batchSize = 40; + + for (uint256 i = firstStaker; i < lastStaker; i += batchSize) { + TransactionSubmitter.StakerDelegation[] memory delegations = new TransactionSubmitter.StakerDelegation[](batchSize); + + for (uint256 j = 0; j < batchSize; j++) { + uint256 stakerPrivateKey = vm.deriveKey(MNEMONIC, uint32(i + j)); + address staker = vm.addr(stakerPrivateKey); + + address operator = vm.addr(vm.deriveKey(MNEMONIC, uint32(_getOperatorIndexFirstHalf(i + j)))); + + ISignatureUtils.SignatureWithExpiry memory stakerSignature = _getStakerDelegationSignature(stakerPrivateKey, staker, operator); + + delegations[j] = TransactionSubmitter.StakerDelegation({ + staker: staker, + operator: operator, + stakerSignatureAndExpiry: stakerSignature, + approverSignatureAndExpiry: ISignatureUtils.SignatureWithExpiry({ + signature: "", + expiry: 0 + }), + approverSalt: bytes32(0) + }); + } + + vm.startBroadcast(); + transactionSubmitter.delegateStakers(delegations); + vm.stopBroadcast(); + } + } + + function registerOperatorByIndex(uint32 operatorIndex) public parseState { + IDelegationManager.OperatorDetails memory operatorDetails = IDelegationManager.OperatorDetails({ + __deprecated_earningsReceiver: address(0x000000000000000000000000000000000000dEaD), + delegationApprover: address(0), + stakerOptOutWindowBlocks: 0 + }); + + uint256 opKey = vm.deriveKey(MNEMONIC, uint32(operatorIndex)); + address operator = vm.addr(opKey); + + vm.startBroadcast(); + operator.call{value: 0.0003 ether}(""); + vm.stopBroadcast(); + + (address operatorSame, uint256 privateKey) = deriveRememberKey(MNEMONIC, operatorIndex); + + vm.startBroadcast(operatorSame); + _delegationManager().registerAsOperator(operatorDetails, ""); + vm.stopBroadcast(); + } + + function undelegateStakers(uint32 startIndex, uint32 endIndex) external parseState { + for (uint32 i = startIndex; i <= endIndex; i++) { + (address staker, uint256 stakerPrivateKey) = deriveRememberKey(MNEMONIC, i); + + if (!_delegationManager().isDelegated(staker)) { + continue; + } + + vm.startBroadcast(); + staker.call{value: 0.0003 ether}(""); + vm.stopBroadcast(); + + vm.startBroadcast(staker); + _delegationManager().undelegate(staker); + vm.stopBroadcast(); + } + } + + function delegateSecondHalfOfStakers() external parseState { + uint256 firstStaker = firstHalfStakerIndex + 1 + 2080; + uint256 lastStaker = maxStakerIndex; + + uint256 batchSize = 40; + + for (uint256 i = firstStaker; i < lastStaker; i += batchSize) { + TransactionSubmitter.StakerDelegation[] memory delegations = new TransactionSubmitter.StakerDelegation[](batchSize); + + for (uint256 j = 0; j < batchSize; j++) { + uint256 stakerPrivateKey = vm.deriveKey(MNEMONIC, uint32(i + j)); + address staker = vm.addr(stakerPrivateKey); + + uint256 operatorIndex = vm.randomUint(5, 1000); + + address operator = vm.addr(vm.deriveKey(MNEMONIC, uint32(operatorIndex))); + + if(_delegationManager().isDelegated(staker)) { + continue; + } + + if(!_delegationManager().isOperator(operator)){ + registerOperatorByIndex(uint32(operatorIndex)); + } + + ISignatureUtils.SignatureWithExpiry memory stakerSignature = _getStakerDelegationSignature(stakerPrivateKey, staker, operator); + + delegations[j] = TransactionSubmitter.StakerDelegation({ + staker: staker, + operator: operator, + stakerSignatureAndExpiry: stakerSignature, + approverSignatureAndExpiry: ISignatureUtils.SignatureWithExpiry({ + signature: "", + expiry: 0 + }), + approverSalt: bytes32(0) + }); + } + + vm.startBroadcast(); + transactionSubmitter.delegateStakers(delegations); + vm.stopBroadcast(); + } + } + + function depositStakersSingleStrat(uint256 startStaker, uint256 endStaker) external parseState { + uint256 batchSize = 20; + require ((endStaker - startStaker) % batchSize == 0, "Batch size must be a factor of the total stakers"); + + // Get strategies + IStrategy[] memory strategies = transactionSubmitter.getAllStrategies(); + IERC20[] memory tokens = new IERC20[](strategies.length); + for(uint256 i = 0; i < strategies.length; i++){ + tokens[i] = IERC20(strategies[i].underlyingToken()); + } + + for(uint256 i = startStaker; i < endStaker; i += batchSize) { + TransactionSubmitter.StakerDeposit[] memory deposits = new TransactionSubmitter.StakerDeposit[](batchSize); + + for(uint256 j = 0; j < batchSize; j++){ + // Initialize struct params + TransactionSubmitter.StrategyInfo[] memory strategyInfo = new TransactionSubmitter.StrategyInfo[](1); + + // Get key/address + uint256 stakerPrivateKey = vm.deriveKey(MNEMONIC, uint32(i + j)); + address staker = vm.addr(stakerPrivateKey); + + // Get random strategy + uint256 strategyIndex = vm.randomUint(1, strategies.length - 1); + IStrategy strategy = strategies[strategyIndex]; + IERC20 token = tokens[strategyIndex]; + + // Get random amount + uint256 amount = vm.randomUint(1, 25_000_000e18); + + // Get StakerInfo + strategyInfo[0] = _getStakerStrategyInfo( + stakerPrivateKey, + staker, + strategy, + token, + amount + ); + + deposits[j] = TransactionSubmitter.StakerDeposit({ + strategyInfos: strategyInfo + }); + } + + vm.startBroadcast(); + transactionSubmitter.depositStakers(deposits); + vm.stopBroadcast(); + } + } + + function depositStakersMultiStrat(uint256 startStaker, uint256 endStaker) external parseState { + uint256 batchSize = 1; + // require ((endStaker - startStaker) % batchSize == 0, "Batch size must be a factor of the total stakers"); + + // Get strategies + IStrategy[] memory strategies = transactionSubmitter.getAllStrategies(); + IERC20[] memory tokens = new IERC20[](strategies.length); + for(uint256 i = 0; i < strategies.length; i++){ + tokens[i] = IERC20(strategies[i].underlyingToken()); + } + + for(uint256 i = startStaker; i < endStaker; i += batchSize) { + TransactionSubmitter.StakerDeposit[] memory deposits = new TransactionSubmitter.StakerDeposit[](batchSize); + + for(uint256 j = 0; j < batchSize; j++){ + // Get key/address + uint256 stakerPrivateKey = vm.deriveKey(MNEMONIC, uint32(i + j)); + address staker = vm.addr(stakerPrivateKey); + + // Get random number of strategies to deposit for staker + uint256 numStrategies = vm.randomUint(2, 4); + + // Initialize struct params + TransactionSubmitter.StrategyInfo[] memory strategyInfos = new TransactionSubmitter.StrategyInfo[](numStrategies); + + uint256 nonce = StrategyManager(address(_strategyManager())).nonces(staker); + + for (uint256 k = 0; k < numStrategies; k++) { + // Get random strategy + uint256 strategyIndex = vm.randomUint(1, strategies.length - 1); + IStrategy strategy = strategies[strategyIndex]; + IERC20 token = tokens[strategyIndex]; + + // Get random amount + uint256 amount = vm.randomUint(1, 25_000_000e18); + + // Get StakerInfo + strategyInfos[k] = _getStakerStrategyInfoManualNonce( + stakerPrivateKey, + staker, + strategy, + token, + amount, + nonce + ); + + nonce++; + } + + deposits[j] = TransactionSubmitter.StakerDeposit({ + strategyInfos: strategyInfos + }); + } + + vm.startBroadcast(); + transactionSubmitter.depositStakers(deposits); + vm.stopBroadcast(); + } + } + + function depositStakerByIndex(uint32 index) external parseState { + // Get strategies + IStrategy[] memory strategies = transactionSubmitter.getAllStrategies(); + IERC20[] memory tokens = new IERC20[](strategies.length); + for(uint256 i = 0; i < strategies.length; i++){ + tokens[i] = IERC20(strategies[i].underlyingToken()); + } + + // Initialize struct params + TransactionSubmitter.StrategyInfo[] memory strategyInfo = new TransactionSubmitter.StrategyInfo[](1); + + // Get key/address + uint256 stakerPrivateKey = vm.deriveKey(MNEMONIC, uint32(index)); + address staker = vm.addr(stakerPrivateKey); + + // Get random strategy + uint256 strategyIndex = vm.randomUint(1, strategies.length - 1); + IStrategy strategy = strategies[strategyIndex]; + IERC20 token = tokens[strategyIndex]; + + // Get random amount + uint256 amount = vm.randomUint(1, 25_000_000e18); + + // Get StakerInfo + strategyInfo[0] = _getStakerStrategyInfo( + stakerPrivateKey, + staker, + strategy, + token, + amount + ); + + TransactionSubmitter.StakerDeposit[] memory deposits = new TransactionSubmitter.StakerDeposit[](1); + + deposits[0] = TransactionSubmitter.StakerDeposit({ + strategyInfos: strategyInfo + }); + + vm.startBroadcast(); + transactionSubmitter.depositStakers(deposits); + vm.stopBroadcast(); + } + + function deployAVSs() external parseState { + vm.startBroadcast(); + transactionSubmitter.deployAVSs(maxAVSIndex); + vm.stopBroadcast(); + } + + function delegateByIndex(uint32 stakerIndex, uint32 operatorIndex) public parseState { + (address staker, uint256 stakerPrivateKey) = deriveRememberKey(MNEMONIC, stakerIndex); + + if (_delegationManager().isDelegated(staker)) { + return; + } + + vm.startBroadcast(); + staker.call{value: 0.0003 ether}(""); + vm.stopBroadcast(); + + address operator = vm.addr(vm.deriveKey(MNEMONIC, operatorIndex)); + ISignatureUtils.SignatureWithExpiry memory approverSignatureAndExpiry; + + vm.startBroadcast(staker); + _delegationManager().delegateTo(operator, approverSignatureAndExpiry, ""); + vm.stopBroadcast(); + } + + function delegateByIndexMultiple(uint32 stakerIndex, uint32 numberStaker, uint32 operatorIndex) public parseState { + for(uint32 i = 0; i < numberStaker; i++){ + + delegateByIndex(stakerIndex + i, operatorIndex); + } + } + + function completeAndDelegate(uint32 stakerIndex, uint32 operatorIndex) public parseState { + IStrategy[] memory strategies = new IStrategy[](1); + uint256[] memory shares = new uint256[](1); + IERC20[] memory tokens = new IERC20[](1); + strategies[0] = IStrategy(0x77335a08a877cd874165bDC766feeD951a0d84c8); + shares[0] = 4157021384921519315796965; + tokens[0] = IERC20(0x4Ce198f835e3f0bb18D4775946fd87f5654B0b49); + + IDelegationManager.Withdrawal memory withdrawal = IDelegationManager.Withdrawal({ + staker: 0xc17e7649c237013603BeD09Be3647d23575a1042, + delegatedTo: 0x4e1Efdbb25446Aa7C9fAc4731BE159b650E9eE5f, + withdrawer: 0xc17e7649c237013603BeD09Be3647d23575a1042, + nonce: 0, + startBlock: 2329626, + strategies: strategies, + shares: shares + }); + + + (address staker, uint256 stakerPrivateKey) = deriveRememberKey(MNEMONIC, stakerIndex); + + vm.startBroadcast(staker); + _delegationManager().completeQueuedWithdrawal( + withdrawal, + tokens, + 0, + false + ); + _delegationManager().delegateTo( + vm.addr(vm.deriveKey(MNEMONIC, operatorIndex)), + ISignatureUtils.SignatureWithExpiry({ + signature: "", + expiry: 0 + }), + "" + ); + vm.stopBroadcast(); + } + + /** + * + * HELPER FUNCTIONS + * + */ + + modifier parseState() { + _parseState(statePath); + _; + } + + function _parseState(string memory statePathToParse) internal { + // READ JSON CONFIG DATA + string memory stateData = vm.readFile(statePathToParse); + emit log_named_string("Using state file", statePathToParse); + + transactionSubmitter = TransactionSubmitter(payable(stdJson.readAddress(stateData, ".submitterProxy"))); + proxyAdmin = ProxyAdmin(stdJson.readAddress(stateData, ".submitterProxyAdmin")); + operatorsRegistered = stdJson.readUint(stateData, ".operatorsRegistered"); + MNEMONIC = vm.envString("MNEMONIC"); + } + + function _getAllOperators() internal returns(address[] memory){ + address[] memory operators = new address[](maxOperatorIndex); + for(uint256 i = 0; i < operators.length; i++){ + (address operator, /* privateKey */) = deriveRememberKey(MNEMONIC, uint32(i)); + operators[i] = operator; + } + return operators; + } + + /// @notice helper to get operator Signature + function _getOperatorSignature( + uint256 _operatorPrivateKey, + address operator, + address avs + ) internal returns (ISignatureUtils.SignatureWithSaltAndExpiry memory operatorSignature) { + operatorSignature.expiry = type(uint32).max; + operatorSignature.salt = bytes32(vm.randomUint()); + { + bytes32 digestHash = _avsDirectory().calculateOperatorAVSRegistrationDigestHash(operator, avs, operatorSignature.salt, operatorSignature.expiry); + (uint8 v, bytes32 r, bytes32 s) = vm.sign(_operatorPrivateKey, digestHash); + operatorSignature.signature = abi.encodePacked(r, s, v); + } + return operatorSignature; + } + + function _getStakerDelegationSignature( + uint256 _stakerPrivateKey, + address staker, + address operator + ) internal returns (ISignatureUtils.SignatureWithExpiry memory stakerSignature) { + stakerSignature.expiry = type(uint32).max; + { + bytes32 digestHash = _delegationManager().calculateCurrentStakerDelegationDigestHash(staker, operator, stakerSignature.expiry); + (uint8 v, bytes32 r, bytes32 s) = vm.sign(_stakerPrivateKey, digestHash); + stakerSignature.signature = abi.encodePacked(r, s, v); + } + return stakerSignature; + } + + function _getRandomAVSs(address[] memory avss) internal returns (address[] memory) { + uint256 min = 1; + uint256 max = 5; + uint256 randomNumber = vm.randomUint(min, max); + + address[] memory randomAVSs = new address[](randomNumber); + + for (uint256 i = 0; i < randomNumber; i++) { + randomAVSs[i] = avss[i]; + } + + return randomAVSs; + } + + function _getOperatorSignatures( + uint256 _operatorPrivateKey, + address operator, + address[] memory avss + ) internal returns (ISignatureUtils.SignatureWithSaltAndExpiry[] memory operatorSignatures) { + ISignatureUtils.SignatureWithSaltAndExpiry[] memory signatures = new ISignatureUtils.SignatureWithSaltAndExpiry[](avss.length); + for (uint256 i = 0; i < avss.length; i++) { + signatures[i] = _getOperatorSignature(_operatorPrivateKey, operator, avss[i]); + } + return signatures; + } + + bytes32 private constant PERMIT_TYPEHASH = + keccak256("Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)"); + + function _getStakerPermitInfo( + uint256 stakerPrivateKey, + address staker, + IERC20 token, + address spender, + uint256 value + ) internal returns (TransactionSubmitter.PermitInfo memory permitInfo) { + uint256 nonce = StrategyToken(address(token)).nonces(staker); + (uint8 v, bytes32 r, bytes32 s) = vm.sign( + stakerPrivateKey, + keccak256( + abi.encodePacked( + "\x19\x01", + StrategyToken(address(token)).DOMAIN_SEPARATOR(), + keccak256(abi.encode(PERMIT_TYPEHASH, staker, spender, value, nonce, type(uint256).max)) + ) + ) + ); + + return TransactionSubmitter.PermitInfo({ + owner: staker, + spender: spender, + value: value, + deadline: type(uint256).max, + v: v, + r: r, + s: s + }); + } + + bytes32 public constant DEPOSIT_TYPEHASH = + keccak256("Deposit(address staker,address strategy,address token,uint256 amount,uint256 nonce,uint256 expiry)"); + + bytes32 public constant DOMAIN_SEPARATOR_SM = 0xcd2248fa45cb388d7d043522f71c7934b72e935295a7e04afdf7794a7bf18df2; + + function _getStakerStrategyInfoManualNonce( + uint256 stakerPrivateKey, + address staker, + IStrategy strategy, + IERC20 token, + uint256 amount, + uint256 nonce + ) internal view returns (TransactionSubmitter.StrategyInfo memory strategyInfo) { + uint256 expiry = type(uint32).max; + bytes memory signature; + { + bytes32 structHash = keccak256( + abi.encode(DEPOSIT_TYPEHASH, staker, strategy, address(token), amount, nonce, expiry) + ); + bytes32 digestHash = keccak256(abi.encodePacked("\x19\x01", DOMAIN_SEPARATOR_SM, structHash)); + + (uint8 v, bytes32 r, bytes32 s) = cheats.sign(stakerPrivateKey, digestHash); + + signature = abi.encodePacked(r, s, v); + } + + return TransactionSubmitter.StrategyInfo({ + strategy: strategy, + token: token, + amount: amount, + staker: staker, + expiry: expiry, + signature: signature + }); + } + + function _getStakerStrategyInfo( + uint256 stakerPrivateKey, + address staker, + IStrategy strategy, + IERC20 token, + uint256 amount + ) internal view returns (TransactionSubmitter.StrategyInfo memory strategyInfo) { + return _getStakerStrategyInfoManualNonce(stakerPrivateKey, staker, strategy, token, amount, StrategyManager(address(_strategyManager())).nonces(staker)); + } + + function _getOperatorIndexFirstHalf(uint256 stakerIndex) internal returns (uint256) { + uint256 lastIndex = firstHalfStakerIndex; + if (stakerIndex < 11_000) { + return 0; + } else if (stakerIndex < 16_000) { + return 1; + } else if (stakerIndex < 21_000) { + return 2; + } else if (stakerIndex < 23_500) { + return 3; + } else if (stakerIndex < 26_000) { + return 4; + } else { + return 5; + } + } + + function _delegationManager() internal view returns (IDelegationManager) { + return IDelegationManager(zDeployedProxy(type(DelegationManager).name)); + } + + function _strategyManager() internal view returns (IStrategyManager) { + return IStrategyManager(zDeployedProxy(type(StrategyManager).name)); + } + + function _avsDirectory() internal view returns (IAVSDirectory) { + return IAVSDirectory(zDeployedProxy(type(AVSDirectory).name)); + } + + function _strategyFactory() internal returns (IStrategyFactory) { + return IStrategyFactory(zDeployedProxy(type(StrategyFactory).name)); + } + + function setWhitelistedStrategies() external parseState { + IStrategy[] memory strategies = transactionSubmitter.getAllStrategies(); + bool[] memory thirdPartyTransfersForbiddenValues = new bool[](strategies.length); + vm.startBroadcast(); + _strategyFactory().whitelistStrategies(strategies, thirdPartyTransfersForbiddenValues); + vm.stopBroadcast(); + } + + function addAddressToJSON() external parseState { + // string memory key = "addresses"; + for (uint256 i = 0; i < 51021; i++) { + address staker = vm.addr(vm.deriveKey(MNEMONIC, uint32(i))); + // Add to JSON file + emit log_named_address("Staker", staker); + } + // vm.writeJson(vm.serializeString(key, "", ""), "script/utils/rewards_testing/addresses.json"); + } + + function printPrivateKey(uint256 index) external parseState { + (address addr, uint256 privateKey) = deriveRememberKey(MNEMONIC, uint32(index)); + emit log_named_uint("Private Key", privateKey); + emit log_named_address("Address", addr); + // Encoded private key (in hex) + // emit log_named_string("Private Key (hex)", abi.encodePacked(privateKey).toHexString()); + } +} \ No newline at end of file diff --git a/script/utils/rewards_testing/TransactionSubmitter.sol b/script/utils/rewards_testing/TransactionSubmitter.sol new file mode 100644 index 000000000..b2eae2642 --- /dev/null +++ b/script/utils/rewards_testing/TransactionSubmitter.sol @@ -0,0 +1,215 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity ^0.8.12; + +import "src/contracts/interfaces/IDelegationManager.sol"; +import "src/contracts/interfaces/IStrategyManager.sol"; +import "src/contracts/interfaces/IRewardsCoordinator.sol"; +import "src/contracts/interfaces/IAVSDirectory.sol"; +import "src/contracts/interfaces/IStrategyFactory.sol"; +import "./ServiceManagerMock.sol"; +import {ISignatureUtils} from "src/contracts/interfaces/ISignatureUtils.sol"; +import "./StrategyToken.sol"; + + +/** + * @title TransactionSubmitter + * @notice A contract that batch submits transactions to seed EL core contracts + * @notice We cannot seed + */ +contract TransactionSubmitter { + // Pointers to Core Contracts + IDelegationManager public immutable delegation; + IStrategyManager public immutable strategyManager; + IAVSDirectory public immutable avsDirectory; + IRewardsCoordinator public immutable rewardsCoordinator; + IStrategyFactory public immutable strategyFactory; + + // Configs + uint256 immutable MAX_TOKEN_SUPPLY = 1e37; + + // AVS Info + mapping(uint256 => address) public avss; + uint256 public numAVSs; + + // Strategy Info + mapping(uint256 => IStrategy) public deprecated_customStrats; + uint256 public deprecated_numCustomStrats; + + mapping(uint256 => IStrategy) public customStrats; + uint256 public numCustomStrats; + + + // Registration Utils + struct OperatorAVSRegistration { + address operator; + address[] avss; + ISignatureUtils.SignatureWithSaltAndExpiry[] sigs; + } + + struct StakerDelegation { + address staker; + address operator; + ISignatureUtils.SignatureWithExpiry stakerSignatureAndExpiry; + ISignatureUtils.SignatureWithExpiry approverSignatureAndExpiry; + bytes32 approverSalt; + } + + struct PermitInfo { + address owner; + address spender; + uint256 value; + uint256 deadline; + uint8 v; + bytes32 r; + bytes32 s; + } + + struct StrategyInfo { + IStrategy strategy; + IERC20 token; + uint256 amount; + address staker; + uint256 expiry; + bytes signature; + } + + struct StakerDeposit { + StrategyInfo[] strategyInfos; + } + + constructor(IDelegationManager _delegation, IAVSDirectory _avsDirectory, IStrategyManager _strategyManager, IRewardsCoordinator _rewardsCoordinator, IStrategyFactory _strategyFactory) { + delegation = _delegation; + avsDirectory = _avsDirectory; + strategyManager = _strategyManager; + rewardsCoordinator = _rewardsCoordinator; + strategyFactory = _strategyFactory; + } + + /** + * @notice Deploys `numAVSsToDeploy` AVSs by deploy a ServiceManagerMock contract + * @param numAVSsToDeploy The number of AVSs to deploy + */ + function deployAVSs(uint16 numAVSsToDeploy) external { + for (uint16 i = 0; i < numAVSsToDeploy; i++) { + address avs = address(new ServiceManagerMock(avsDirectory, rewardsCoordinator)); + avss[numAVSs] = avs; + numAVSs++; + } + } + + /** + * @notice Registers a list of operators to a list of AVSs + * @param operatorAVSRegistrations A list of operators and their corresponding AVSs to register for + */ + function registerOperatorsToAVSs(OperatorAVSRegistration[] memory operatorAVSRegistrations) external { + for (uint256 i = 0; i < operatorAVSRegistrations.length; i++) { + OperatorAVSRegistration memory operatorAVSRegistration = operatorAVSRegistrations[i]; + for (uint256 j = 0; j < operatorAVSRegistration.avss.length; j++) { + ServiceManagerMock(operatorAVSRegistration.avss[j]).registerOperatorToAVS(operatorAVSRegistration.operator, operatorAVSRegistration.sigs[j]); + } + } + } + + /** + * @notice Deploys `numCustomStratsToDeploy` custom strategies by calling the `StrategyFactory` + * @param names The names of tokens to deploy + * @param symbols The symbols of tokens to deploy + * @dev A new token is deployed for each custom strategy and the entire supply is transferred to the TransactionSubmitter + */ + function deployCustomStrategies(string[] memory names, string[] memory symbols) external { + for (uint16 i = 0; i < names.length; i++) { + // Deploy Strategy Token + // Create a token name based on numCustomStrats + StrategyToken token = new StrategyToken( + names[i], + symbols[i], + MAX_TOKEN_SUPPLY, + address(this) + ); + + // Deploy Custom Strategy + IStrategy customStrat = strategyFactory.deployNewStrategy(IERC20(token)); + customStrats[numCustomStrats] = customStrat; + numCustomStrats++; + } + } + + /** + * @notice Delegates a list of stakers by signature + * @param stakerDelegations A list of calldatas for staker to delegate + */ + function delegateStakers(StakerDelegation[] memory stakerDelegations) external { + for (uint256 i = 0; i < stakerDelegations.length; i++) { + StakerDelegation memory stakerDelegation = stakerDelegations[i]; + delegation.delegateToBySignature( + stakerDelegation.staker, + stakerDelegation.operator, + stakerDelegation.stakerSignatureAndExpiry, + stakerDelegation.approverSignatureAndExpiry, + stakerDelegation.approverSalt + ); + } + } + + function depositStakers(StakerDeposit[] memory stakerDeposits) external { + for (uint256 i = 0; i < stakerDeposits.length; i++) { + for(uint256 j = 0; j < stakerDeposits[i].strategyInfos.length; j++) { + StrategyInfo memory strategyInfo = stakerDeposits[i].strategyInfos[j]; + + // Approve + strategyInfo.token.approve(address(strategyManager), strategyInfo.amount); + + // Deposit + strategyManager.depositIntoStrategyWithSignature( + strategyInfo.strategy, + strategyInfo.token, + strategyInfo.amount, + strategyInfo.staker, + strategyInfo.expiry, + strategyInfo.signature + ); + } + } + } + + /** + * Sends `amount` of ETH to each address in `tos` + * @param tos List of addresses to send ETH to + * @param amount of ETH to send + */ + function sendEth(address[] memory tos, uint256 amount) external { + for (uint256 i = 0; i < tos.length; i++) { + (bool success, ) = payable(tos[i]).call{value: amount}(""); + require(success, "TransactionSubmitter: sendEth failed"); + } + } + + /** + * + * VIEW FUNCTIONS + * + */ + + /** + * @notice Returns all AVSs that have been deployed by this contract + */ + function getAllAVSs() external view returns (address[] memory) { + address[] memory allAVSs = new address[](numAVSs); + for (uint256 i = 0; i < numAVSs; i++) { + allAVSs[i] = avss[i]; + } + return allAVSs; + } + + function getAllStrategies() external view returns(IStrategy[] memory) { + IStrategy[] memory allStrategies = new IStrategy[](numCustomStrats); + for (uint256 i = 0; i < numCustomStrats; i++) { + allStrategies[i] = customStrats[i]; + } + return allStrategies; + } + + fallback() external {} + + receive() external payable {} +} \ No newline at end of file diff --git a/script/utils/rewards_testing/addresses.json b/script/utils/rewards_testing/addresses.json new file mode 100644 index 000000000..2dbea8eaf --- /dev/null +++ b/script/utils/rewards_testing/addresses.json @@ -0,0 +1,13 @@ +{ + "": "", + "0": "0x5E90eF3A3cf11e59e2E750955eDf4CF4Bd862cdB", + "1": "0x4e1Efdbb25446Aa7C9fAc4731BE159b650E9eE5f", + "2": "0xCf2aEd1f5Cfe4eD51502cb308BC1f98fBb0d80Bc", + "3": "0xb6DeF07A0814Cf058D0E9762d1f9AF38ff140c02", + "4": "0x1E596cE30D9BaB7fE6D39E1D438e4d98941100c0", + "5": "0xcF4f3453828f09f5B526101B81d0199D2DE39Ec5", + "6": "0x2595687d1fD54a390a2A96aF326e001370F4b06b", + "7": "0x3E9421a64Ae9ba3c694143f7cBe6f8AD8caE6036", + "8": "0x6B26E74aAEB159B7a28724B99b188adBCC436744", + "9": "0xaFF71569D30ED876987088a62E0EA881EBc761E6" +} \ No newline at end of file diff --git a/script/utils/rewards_testing/notes.sh b/script/utils/rewards_testing/notes.sh new file mode 100644 index 000000000..ee38e6e49 --- /dev/null +++ b/script/utils/rewards_testing/notes.sh @@ -0,0 +1,4 @@ +zeus run --env preprod -c "forge script --rpc-url $ETH_RPC_URL --private-key $PRIVATE_KEY --broadcast script/utils/rewards_testing/TransactionBuilder.s.sol:TransactionBuilder --sig \"deployTransactionSubmitter()\"" +zeus run --env preprod -c "forge script --rpc-url $ETH_RPC_URL --private-key $PRIVATE_KEY --broadcast script/utils/rewards_testing/TransactionBuilder.s.sol:TransactionBuilder --sig \"seedOperators()\"" +zeus run --env preprod -c "forge script --rpc-url $ETH_RPC_URL --private-key $PRIVATE_KEY --broadcast script/utils/rewards_testing/TransactionBuilder.s.sol:TransactionBuilder --sig \"deployAVSs()\"" +zeus run --env preprod -c "forge script --rpc-url $ETH_RPC_URL --private-key $PRIVATE_KEY --broadcast script/utils/rewards_testing/TransactionBuilder.s.sol:TransactionBuilder --sig \"registerOperatorsToAVSs()\"" \ No newline at end of file diff --git a/script/utils/rewards_testing/preprod_state.json b/script/utils/rewards_testing/preprod_state.json new file mode 100644 index 000000000..ca3dbc9fe --- /dev/null +++ b/script/utils/rewards_testing/preprod_state.json @@ -0,0 +1,5 @@ +{ + "operatorsRegistered": 1000, + "submitterProxyAdmin": "0x1460d60Af5BE04A7B44362b535ae3DF28d3579ee", + "submitterProxy": "0xb7D6fa9c96cfcc437B7B1345e5cfe00773Ebcb94" +} \ No newline at end of file From e29569e07da781eff3529df6ce954f5e2eb187e7 Mon Sep 17 00:00:00 2001 From: gpsanant Date: Tue, 3 Dec 2024 13:24:46 -0800 Subject: [PATCH 2/9] add approvals --- script/utils/rewards_testing/TestRewardsV2.sol | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/script/utils/rewards_testing/TestRewardsV2.sol b/script/utils/rewards_testing/TestRewardsV2.sol index 74fd1c575..6d9c139c1 100644 --- a/script/utils/rewards_testing/TestRewardsV2.sol +++ b/script/utils/rewards_testing/TestRewardsV2.sol @@ -172,6 +172,9 @@ contract TestRewardsV2 is ZeusScript { ) internal { ServiceManagerMock serviceManager = _rewardingServiceManager(); vm.startBroadcast(); + for (uint256 i = 0; i < rewardsSubmissions.length; i++) { + rewardsSubmissions[i].token.approve(address(serviceManager), type(uint256).max); + } serviceManager.createAVSRewardsSubmission(rewardsSubmissions); vm.stopBroadcast(); } @@ -180,6 +183,9 @@ contract TestRewardsV2 is ZeusScript { IRewardsCoordinator.RewardsSubmission[] memory rewardsSubmissions ) internal { vm.startBroadcast(); + for (uint256 i = 0; i < rewardsSubmissions.length; i++) { + rewardsSubmissions[i].token.approve(address(_rewardsCoordinator()), type(uint256).max); + } _rewardsCoordinator().createRewardsForAllEarners(rewardsSubmissions); vm.stopBroadcast(); } From dfc18a3db37cf0569bc9b378bf8af002b69b4a01 Mon Sep 17 00:00:00 2001 From: gpsanant Date: Tue, 3 Dec 2024 14:17:07 -0800 Subject: [PATCH 3/9] fix: add to mock --- script/utils/rewards_testing/ServiceManagerMock.sol | 9 +++++++++ .../{TestRewardsV2.sol => TestRewardsV2.s.sol} | 0 2 files changed, 9 insertions(+) rename script/utils/rewards_testing/{TestRewardsV2.sol => TestRewardsV2.s.sol} (100%) diff --git a/script/utils/rewards_testing/ServiceManagerMock.sol b/script/utils/rewards_testing/ServiceManagerMock.sol index 819635130..88c9bb73a 100644 --- a/script/utils/rewards_testing/ServiceManagerMock.sol +++ b/script/utils/rewards_testing/ServiceManagerMock.sol @@ -119,6 +119,15 @@ contract ServiceManagerMock is OwnableUpgradeable { return restakeableStrategies; } + /** + * @notice Forwards a call to Eigenlayer's RewardsCoordinator contract to set the address of the entity that can call `processClaim` on behalf of this contract. + * @param claimer The address of the entity that can call `processClaim` on behalf of the earner + * @dev Only callabe by the owner. + */ + function setClaimerFor(address claimer) public virtual onlyOwner { + _rewardsCoordinator.setClaimerFor(claimer); + } + /** * @notice Returns the list of strategies that the operator has potentially restaked on the AVS * @param operator The address of the operator to get restaked strategies for diff --git a/script/utils/rewards_testing/TestRewardsV2.sol b/script/utils/rewards_testing/TestRewardsV2.s.sol similarity index 100% rename from script/utils/rewards_testing/TestRewardsV2.sol rename to script/utils/rewards_testing/TestRewardsV2.s.sol From 8e9924de59c048645ec0a1aef3d0b568f06d4519 Mon Sep 17 00:00:00 2001 From: gpsanant Date: Tue, 3 Dec 2024 22:33:36 -0800 Subject: [PATCH 4/9] feat: make rewardsv1 work --- .../rewards_testing/ServiceManagerMock.sol | 13 +++--------- .../utils/rewards_testing/TestRewardsV2.s.sol | 21 +++++++++---------- .../rewards_testing/TransactionSubmitter.sol | 2 +- script/utils/rewards_testing/notes.sh | 1 - .../utils/rewards_testing/preprod_state.json | 4 ++-- 5 files changed, 16 insertions(+), 25 deletions(-) diff --git a/script/utils/rewards_testing/ServiceManagerMock.sol b/script/utils/rewards_testing/ServiceManagerMock.sol index 88c9bb73a..bd9581efe 100644 --- a/script/utils/rewards_testing/ServiceManagerMock.sol +++ b/script/utils/rewards_testing/ServiceManagerMock.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.12; -import {OwnableUpgradeable} from "@openzeppelin-upgrades/contracts/access/OwnableUpgradeable.sol"; +import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol"; import {ISignatureUtils} from "src/contracts/interfaces/ISignatureUtils.sol"; import {IAVSDirectory} from "src/contracts/interfaces/IAVSDirectory.sol"; import {IRewardsCoordinator} from "src/contracts/interfaces/IRewardsCoordinator.sol"; @@ -11,7 +11,7 @@ import {IRewardsCoordinator} from "src/contracts/interfaces/IRewardsCoordinator. * This contract can be inherited from or simply used as a point-of-reference. * @author Layr Labs, Inc. */ -contract ServiceManagerMock is OwnableUpgradeable { +contract ServiceManagerMock is Ownable { IAVSDirectory internal immutable _avsDirectory; IRewardsCoordinator internal immutable _rewardsCoordinator; @@ -21,19 +21,12 @@ contract ServiceManagerMock is OwnableUpgradeable { /// @notice Sets the (immutable) `_registryCoordinator` address constructor( + address initialOwner, IAVSDirectory __avsDirectory, IRewardsCoordinator ___rewardsCoordinator ) { _avsDirectory = __avsDirectory; _rewardsCoordinator = ___rewardsCoordinator; - _disableInitializers(); - } - - function initialize(address _initialOwner) public initializer { - _transferOwnership(_initialOwner); - } - - function __ServiceManagerBase_init(address initialOwner) internal virtual onlyInitializing { _transferOwnership(initialOwner); } diff --git a/script/utils/rewards_testing/TestRewardsV2.s.sol b/script/utils/rewards_testing/TestRewardsV2.s.sol index 6d9c139c1..c127afbfa 100644 --- a/script/utils/rewards_testing/TestRewardsV2.s.sol +++ b/script/utils/rewards_testing/TestRewardsV2.s.sol @@ -128,7 +128,7 @@ contract TestRewardsV2 is ZeusScript { uint32 calculationIntervalSeconds = _rewardsCoordinator().CALCULATION_INTERVAL_SECONDS(); uint32 moddedCurrTimestamp = uint32(block.timestamp) - (uint32(block.timestamp) % calculationIntervalSeconds); uint32 startTimestamp = moddedCurrTimestamp; - uint32 duration = calculationIntervalSeconds; + uint32 duration = 2 weeks; rewardsSubmission[0] = IRewardsCoordinator.RewardsSubmission({ strategiesAndMultipliers: strategyAndMultipliers, @@ -270,7 +270,7 @@ contract TestRewardsV2 is ZeusScript { } function _getAVStrategies() internal pure returns (IStrategy[] memory) { - IStrategy[] memory strategies = new IStrategy[](15); + IStrategy[] memory strategies = new IStrategy[](14); strategies[0] = IStrategy(0x08f8544E61Ebfa22e7c6ef9af9eFd428091b27AF); strategies[1] = IStrategy(0x31741340ab31e90f0624d2C843B323a97755f43a); @@ -278,15 +278,14 @@ contract TestRewardsV2 is ZeusScript { strategies[3] = IStrategy(0xcD6EDf68a5Fc79BBc14A0eCa1C8bbDe495fB1a5f); strategies[4] = IStrategy(0x77335a08a877cd874165bDC766feeD951a0d84c8); strategies[5] = IStrategy(0x53C916338FcA4f5541bc2eA5E5f7F0Ca6f0dAf6a); - strategies[6] = IStrategy(0x77335a08a877cd874165bDC766feeD951a0d84c8); - strategies[7] = IStrategy(0x51366AEf35475e82B864f2E7867B293c3BC61D86); - strategies[8] = IStrategy(0x5803f7D0D273aa0B9774C0aDAB98A23ec348Ea77); - strategies[9] = IStrategy(0xe5e8BcBd1DDD07460fA67f617a2D018ce0f5b7bf); - strategies[10] = IStrategy(0x419B6Ba569169826d9A45565E651F03B8DdfA332); - strategies[11] = IStrategy(0x9b5F92ed40e1436Ac8E31fd7f7bc6083edBd5E71); - strategies[12] = IStrategy(0xE34b1Da874E6B9f091540c850095b99B4D3B475D); - strategies[13] = IStrategy(0x8EF42562E9F1b81010a54615673739dd91E10016); - strategies[14] = IStrategy(0xdE2788cb747b51a1747Bd59342b6214652Ddeb10); + strategies[6] = IStrategy(0x51366AEf35475e82B864f2E7867B293c3BC61D86); + strategies[7] = IStrategy(0x5803f7D0D273aa0B9774C0aDAB98A23ec348Ea77); + strategies[8] = IStrategy(0xe5e8BcBd1DDD07460fA67f617a2D018ce0f5b7bf); + strategies[9] = IStrategy(0x419B6Ba569169826d9A45565E651F03B8DdfA332); + strategies[10] = IStrategy(0x9b5F92ed40e1436Ac8E31fd7f7bc6083edBd5E71); + strategies[11] = IStrategy(0xE34b1Da874E6B9f091540c850095b99B4D3B475D); + strategies[12] = IStrategy(0x8EF42562E9F1b81010a54615673739dd91E10016); + strategies[13] = IStrategy(0xdE2788cb747b51a1747Bd59342b6214652Ddeb10); // sort strategies by address for (uint256 i = 0; i < strategies.length; i++) { diff --git a/script/utils/rewards_testing/TransactionSubmitter.sol b/script/utils/rewards_testing/TransactionSubmitter.sol index b2eae2642..7e2615d62 100644 --- a/script/utils/rewards_testing/TransactionSubmitter.sol +++ b/script/utils/rewards_testing/TransactionSubmitter.sol @@ -91,7 +91,7 @@ contract TransactionSubmitter { */ function deployAVSs(uint16 numAVSsToDeploy) external { for (uint16 i = 0; i < numAVSsToDeploy; i++) { - address avs = address(new ServiceManagerMock(avsDirectory, rewardsCoordinator)); + address avs = address(new ServiceManagerMock(msg.sender, avsDirectory, rewardsCoordinator)); avss[numAVSs] = avs; numAVSs++; } diff --git a/script/utils/rewards_testing/notes.sh b/script/utils/rewards_testing/notes.sh index ee38e6e49..3eced270b 100644 --- a/script/utils/rewards_testing/notes.sh +++ b/script/utils/rewards_testing/notes.sh @@ -1,4 +1,3 @@ zeus run --env preprod -c "forge script --rpc-url $ETH_RPC_URL --private-key $PRIVATE_KEY --broadcast script/utils/rewards_testing/TransactionBuilder.s.sol:TransactionBuilder --sig \"deployTransactionSubmitter()\"" -zeus run --env preprod -c "forge script --rpc-url $ETH_RPC_URL --private-key $PRIVATE_KEY --broadcast script/utils/rewards_testing/TransactionBuilder.s.sol:TransactionBuilder --sig \"seedOperators()\"" zeus run --env preprod -c "forge script --rpc-url $ETH_RPC_URL --private-key $PRIVATE_KEY --broadcast script/utils/rewards_testing/TransactionBuilder.s.sol:TransactionBuilder --sig \"deployAVSs()\"" zeus run --env preprod -c "forge script --rpc-url $ETH_RPC_URL --private-key $PRIVATE_KEY --broadcast script/utils/rewards_testing/TransactionBuilder.s.sol:TransactionBuilder --sig \"registerOperatorsToAVSs()\"" \ No newline at end of file diff --git a/script/utils/rewards_testing/preprod_state.json b/script/utils/rewards_testing/preprod_state.json index ca3dbc9fe..cad745d7f 100644 --- a/script/utils/rewards_testing/preprod_state.json +++ b/script/utils/rewards_testing/preprod_state.json @@ -1,5 +1,5 @@ { "operatorsRegistered": 1000, - "submitterProxyAdmin": "0x1460d60Af5BE04A7B44362b535ae3DF28d3579ee", - "submitterProxy": "0xb7D6fa9c96cfcc437B7B1345e5cfe00773Ebcb94" + "submitterProxyAdmin": "0xD32112bBd74127F9727CfB02Fe1bfF6Ce7D9bD68", + "submitterProxy": "0x42389347aeFBb2802C4C0a5C680DBD0a616fc096" } \ No newline at end of file From 1d94126d35308b33ae37f5c63086e766dc3af2ef Mon Sep 17 00:00:00 2001 From: gpsanant Date: Wed, 4 Dec 2024 13:02:51 -0800 Subject: [PATCH 5/9] feat: did it --- script/utils/rewards_testing/TestRewardsV2.s.sol | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/script/utils/rewards_testing/TestRewardsV2.s.sol b/script/utils/rewards_testing/TestRewardsV2.s.sol index c127afbfa..8586167d7 100644 --- a/script/utils/rewards_testing/TestRewardsV2.s.sol +++ b/script/utils/rewards_testing/TestRewardsV2.s.sol @@ -15,20 +15,22 @@ contract TestRewardsV2 is ZeusScript { function tx_prep() public parseState { + address rewardingServiceManager = address(_rewardingServiceManager()); + IRewardsCoordinator rewardsCoordinator = _rewardsCoordinator(); // Deploy token - (address[] memory operatorsRegisteredToAVS, uint256[] memory privateKeys) = _getAllOperatorsRegisteredToAVS(address(_rewardingServiceManager())); + (address[] memory operatorsRegisteredToAVS, uint256[] memory privateKeys) = _getAllOperatorsRegisteredToAVS(rewardingServiceManager); // for the first 3/5 of the operators, set the AVS split to random values for (uint256 i = 0; i < operatorsRegisteredToAVS.length*3/5; i++) { - vm.startBroadcast(privateKeys[i]); - _rewardsCoordinator().setOperatorAVSSplit(operatorsRegisteredToAVS[i], address(_rewardingServiceManager()), uint16(vm.randomUint(1, 10000))); + vm.startBroadcast(operatorsRegisteredToAVS[i]); + rewardsCoordinator.setOperatorAVSSplit(operatorsRegisteredToAVS[i], rewardingServiceManager, uint16(vm.randomUint(1, 10000))); vm.stopBroadcast(); } // for 1/5 through 4/5 of the operators, set the PI split to random values for (uint256 i = operatorsRegisteredToAVS.length*1/5; i < operatorsRegisteredToAVS.length*4/5; i++) { - vm.startBroadcast(privateKeys[i]); - _rewardsCoordinator().setOperatorPISplit(operatorsRegisteredToAVS[i], uint16(vm.randomUint(1, 10000))); + vm.startBroadcast(operatorsRegisteredToAVS[i]); + rewardsCoordinator.setOperatorPISplit(operatorsRegisteredToAVS[i], uint16(vm.randomUint(1, 10000))); vm.stopBroadcast(); } From 6a622621e9fe5c1b8324787ceda30fb1cc38c296 Mon Sep 17 00:00:00 2001 From: gpsanant Date: Tue, 10 Dec 2024 14:15:01 -0800 Subject: [PATCH 6/9] fix: timing --- script/utils/rewards_testing/TestRewardsV2.s.sol | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/script/utils/rewards_testing/TestRewardsV2.s.sol b/script/utils/rewards_testing/TestRewardsV2.s.sol index 8586167d7..2afebb27c 100644 --- a/script/utils/rewards_testing/TestRewardsV2.s.sol +++ b/script/utils/rewards_testing/TestRewardsV2.s.sol @@ -56,8 +56,8 @@ contract TestRewardsV2 is ZeusScript { // Format Range uint32 moddedCurrTimestamp = uint32(block.timestamp) - (uint32(block.timestamp) % _rewardsCoordinator().CALCULATION_INTERVAL_SECONDS()); - uint32 startTimestamp = moddedCurrTimestamp - _rewardsCoordinator().MAX_REWARDS_DURATION(); - uint32 duration = _rewardsCoordinator().MAX_REWARDS_DURATION(); + uint32 startTimestamp = moddedCurrTimestamp - 1 weeks; + uint32 duration = 1 weeks; (address[] memory operatorsRegisteredToAVS,) = _getAllOperatorsRegisteredToAVS(address(_rewardingServiceManager())); From fa9e5052b92e4c627cf820c06178e928c607ddfd Mon Sep 17 00:00:00 2001 From: gpsanant Date: Wed, 11 Dec 2024 07:36:34 -0800 Subject: [PATCH 7/9] feat: there we go --- .gitignore | 2 ++ lib/forge-std | 2 +- .../utils/rewards_testing/TestRewardsV2.s.sol | 19 ++++++++++++++- test.sh | 23 ------------------- 4 files changed, 21 insertions(+), 25 deletions(-) delete mode 100755 test.sh diff --git a/.gitignore b/.gitignore index cb82d385c..b8d8058ad 100644 --- a/.gitignore +++ b/.gitignore @@ -47,3 +47,5 @@ InheritanceGraph.png surya_report.md .idea + +test.sh \ No newline at end of file diff --git a/lib/forge-std b/lib/forge-std index 1714bee72..4f57c59f0 160000 --- a/lib/forge-std +++ b/lib/forge-std @@ -1 +1 @@ -Subproject commit 1714bee72e286e73f76e320d110e0eaf5c4e649d +Subproject commit 4f57c59f066a03d13de8c65bb34fca8247f5fcb2 diff --git a/script/utils/rewards_testing/TestRewardsV2.s.sol b/script/utils/rewards_testing/TestRewardsV2.s.sol index 2afebb27c..478fed418 100644 --- a/script/utils/rewards_testing/TestRewardsV2.s.sol +++ b/script/utils/rewards_testing/TestRewardsV2.s.sol @@ -37,6 +37,23 @@ contract TestRewardsV2 is ZeusScript { // this leaves 1/5 of the operators with no splits set } + function tx_prep2() public parseState { + (address[] memory operators,) = _getAllRegisteredOperators(); + IStrategy[] memory strategies = _getAVStrategies(); + address[] memory strategiesAddresses = new address[](strategies.length); + for(uint256 i = 0; i < strategies.length; i++){ + strategiesAddresses[i] = address(strategies[i]); + } + ServiceManagerMock serviceManager = _rewardingServiceManager(); + + for(uint256 i = 0; i < operators.length; i++){ + vm.startBroadcast(); + serviceManager.setOperatorRestakedStrategies(operators[i], strategiesAddresses); + vm.stopBroadcast(); + } + + } + function tx_1() public parseState { // Deploy token string memory name = "RewardsV2_OperatorDirectedRewards_Test_1"; @@ -94,7 +111,7 @@ contract TestRewardsV2 is ZeusScript { // Format Range uint32 moddedCurrTimestamp = uint32(block.timestamp) - (uint32(block.timestamp) % _rewardsCoordinator().CALCULATION_INTERVAL_SECONDS()); uint32 startTimestamp = moddedCurrTimestamp - 1 weeks; - uint32 duration = 1 weeks; + uint32 duration = 2 weeks; rewardsSubmission[0] = IRewardsCoordinator.RewardsSubmission({ strategiesAndMultipliers: strategyAndMultipliers, diff --git a/test.sh b/test.sh deleted file mode 100755 index d19ceaa7d..000000000 --- a/test.sh +++ /dev/null @@ -1,23 +0,0 @@ -#!/bin/bash - -source .env - -operator1address=$(cast w a --private-key $OPERATOR_1) -operator2address=$(cast w a --private-key $OPERATOR_2) -operator3address=$(cast w a --private-key $OPERATOR_3) -operator4address=$(cast w a --private-key $OPERATOR_4) - -# cast send --rpc-url $RPC_URL --private-key $OPERATOR_1 0x45b4c4DAE69393f62e1d14C5fe375792DF4E6332 "registerAsOperator((address,address,uint32), string)" "($operator1address,0x0000000000000000000000000000000000000000,10)" "https://operator.com/123" -# cast send --rpc-url $RPC_URL --private-key $OPERATOR_2 0x45b4c4DAE69393f62e1d14C5fe375792DF4E6332 "registerAsOperator((address,address,uint32), string)" "($operator2address,0x0000000000000000000000000000000000000000,0)" "https://123qwe.com/opop" -# cast send --rpc-url $RPC_URL --private-key $OPERATOR_3 0x45b4c4DAE69393f62e1d14C5fe375792DF4E6332 "registerAsOperator((address,address,uint32), string)" "($operator3address,0x0000000000000000000000000000000000000000,0)" "https://geezlouise.com/13" -# cast send --rpc-url $RPC_URL --private-key $OPERATOR_4 0x45b4c4DAE69393f62e1d14C5fe375792DF4E6332 "registerAsOperator((address,address,uint32), string)" "($operator4address,0x0000000000000000000000000000000000000000,0)" "https://urmama.com/rich_dank" - -# cast send --rpc-url $RPC_URL --private-key $OPERATOR_1 0x78697cd4EE4BdE0514fE8a7C61E8cB1A152B5d78 "registerOperatorWithCoordinator(bytes memory, bytes calldata)" "" "" -# cast send --rpc-url $RPC_URL --private-key $OPERATOR_2 0x78697cd4EE4BdE0514fE8a7C61E8cB1A152B5d78 "registerOperatorWithCoordinator(bytes memory, bytes calldata)" "" "" -# cast send --rpc-url $RPC_URL --private-key $OPERATOR_3 0x78697cd4EE4BdE0514fE8a7C61E8cB1A152B5d78 "registerOperatorWithCoordinator(bytes memory, bytes calldata)" "" "" -# cast send --rpc-url $RPC_URL --private-key $OPERATOR_4 0x78697cd4EE4BdE0514fE8a7C61E8cB1A152B5d78 "registerOperatorWithCoordinator(bytes memory, bytes calldata)" "" "" - -cast send --rpc-url $RPC_URL --private-key $OPERATOR_1 0x45b4c4DAE69393f62e1d14C5fe375792DF4E6332 "updateOperatorMetadataURI(string calldata)" "https://operator-metadata.s3.amazonaws.com/operator_1.json" -cast send --rpc-url $RPC_URL --private-key $OPERATOR_2 0x45b4c4DAE69393f62e1d14C5fe375792DF4E6332 "updateOperatorMetadataURI(string calldata)" "https://operator-metadata.s3.amazonaws.com/operator_2.json" -cast send --rpc-url $RPC_URL --private-key $OPERATOR_3 0x45b4c4DAE69393f62e1d14C5fe375792DF4E6332 "updateOperatorMetadataURI(string calldata)" "https://operator-metadata.s3.amazonaws.com/operator_3.json" -cast send --rpc-url $RPC_URL --private-key $OPERATOR_4 0x45b4c4DAE69393f62e1d14C5fe375792DF4E6332 "updateOperatorMetadataURI(string calldata)" "https://operator-metadata.s3.amazonaws.com/operator_4.json" \ No newline at end of file From 6f3a3a27669ebfd476db2708e2dcae6124fee8d6 Mon Sep 17 00:00:00 2001 From: gpsanant Date: Wed, 11 Dec 2024 10:03:55 -0800 Subject: [PATCH 8/9] feat: add commission spam --- .../utils/rewards_testing/TestRewardsV2.s.sol | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/script/utils/rewards_testing/TestRewardsV2.s.sol b/script/utils/rewards_testing/TestRewardsV2.s.sol index 478fed418..d9b162387 100644 --- a/script/utils/rewards_testing/TestRewardsV2.s.sol +++ b/script/utils/rewards_testing/TestRewardsV2.s.sol @@ -54,6 +54,31 @@ contract TestRewardsV2 is ZeusScript { } + function tx_prep3() public parseState { + address rewardingServiceManager = address(_rewardingServiceManager()); + IRewardsCoordinator rewardsCoordinator = _rewardsCoordinator(); + // Deploy token + (address[] memory operatorsRegisteredToAVS,) = _getAllOperatorsRegisteredToAVS(rewardingServiceManager); + + // for the second 1/5 of the operators, set the AVS split to random values + for (uint256 i = operatorsRegisteredToAVS.length*1/5; i < operatorsRegisteredToAVS.length*1/5 + 4; i++) { + vm.startBroadcast(operatorsRegisteredToAVS[i]); + rewardsCoordinator.setOperatorAVSSplit(operatorsRegisteredToAVS[i], rewardingServiceManager, uint16(vm.randomUint(1, 10000))); + rewardsCoordinator.setOperatorPISplit(operatorsRegisteredToAVS[i], uint16(vm.randomUint(1, 10000))); + vm.stopBroadcast(); + } + + // for the third 1/5 of the operators, set the PI split to random values + for (uint256 i = operatorsRegisteredToAVS.length*1/5; i < operatorsRegisteredToAVS.length*1/5+4; i++) { + vm.startBroadcast(operatorsRegisteredToAVS[i]); + rewardsCoordinator.setOperatorAVSSplit(operatorsRegisteredToAVS[i], rewardingServiceManager, uint16(vm.randomUint(1, 10000))); + rewardsCoordinator.setOperatorPISplit(operatorsRegisteredToAVS[i], uint16(vm.randomUint(1, 10000))); + vm.stopBroadcast(); + } + + // this leaves 1/5 of the operators with no splits set + } + function tx_1() public parseState { // Deploy token string memory name = "RewardsV2_OperatorDirectedRewards_Test_1"; From 110f24367d25968e0d9a3f1d0e23aecbb01cc96e Mon Sep 17 00:00:00 2001 From: gpsanant Date: Wed, 11 Dec 2024 13:52:38 -0800 Subject: [PATCH 9/9] feat: various --- .../utils/rewards_testing/TestRewardsV2.s.sol | 28 ++++++++++++++----- 1 file changed, 21 insertions(+), 7 deletions(-) diff --git a/script/utils/rewards_testing/TestRewardsV2.s.sol b/script/utils/rewards_testing/TestRewardsV2.s.sol index d9b162387..da92c6af6 100644 --- a/script/utils/rewards_testing/TestRewardsV2.s.sol +++ b/script/utils/rewards_testing/TestRewardsV2.s.sol @@ -75,8 +75,22 @@ contract TestRewardsV2 is ZeusScript { rewardsCoordinator.setOperatorPISplit(operatorsRegisteredToAVS[i], uint16(vm.randomUint(1, 10000))); vm.stopBroadcast(); } + } + + function tx_prep4() public parseState { + address rewardingServiceManager = address(_rewardingServiceManager()); + IRewardsCoordinator rewardsCoordinator = _rewardsCoordinator(); + // Deploy token + (address[] memory operatorsRegisteredToAVS,) = _getAllOperatorsRegisteredToAVS(rewardingServiceManager); + + // for the second 1/5 of the operators, set the AVS split to random values + for (uint256 i = operatorsRegisteredToAVS.length*3/5; i < operatorsRegisteredToAVS.length*4/5 + 4; i++) { + emit log_named_address("Operator", operatorsRegisteredToAVS[i]); + vm.startBroadcast(); + ServiceManagerMock(rewardingServiceManager).deregisterOperatorFromAVS(operatorsRegisteredToAVS[i]); + vm.stopBroadcast(); + } - // this leaves 1/5 of the operators with no splits set } function tx_1() public parseState { @@ -98,8 +112,8 @@ contract TestRewardsV2 is ZeusScript { // Format Range uint32 moddedCurrTimestamp = uint32(block.timestamp) - (uint32(block.timestamp) % _rewardsCoordinator().CALCULATION_INTERVAL_SECONDS()); - uint32 startTimestamp = moddedCurrTimestamp - 1 weeks; - uint32 duration = 1 weeks; + uint32 startTimestamp = moddedCurrTimestamp - 3 days; + uint32 duration = 3 days; (address[] memory operatorsRegisteredToAVS,) = _getAllOperatorsRegisteredToAVS(address(_rewardingServiceManager())); @@ -135,8 +149,8 @@ contract TestRewardsV2 is ZeusScript { // Format Range uint32 moddedCurrTimestamp = uint32(block.timestamp) - (uint32(block.timestamp) % _rewardsCoordinator().CALCULATION_INTERVAL_SECONDS()); - uint32 startTimestamp = moddedCurrTimestamp - 1 weeks; - uint32 duration = 2 weeks; + uint32 startTimestamp = moddedCurrTimestamp - 3 days; + uint32 duration = 3 days; rewardsSubmission[0] = IRewardsCoordinator.RewardsSubmission({ strategiesAndMultipliers: strategyAndMultipliers, @@ -171,8 +185,8 @@ contract TestRewardsV2 is ZeusScript { // Format Range uint32 calculationIntervalSeconds = _rewardsCoordinator().CALCULATION_INTERVAL_SECONDS(); uint32 moddedCurrTimestamp = uint32(block.timestamp) - (uint32(block.timestamp) % calculationIntervalSeconds); - uint32 startTimestamp = moddedCurrTimestamp; - uint32 duration = 2 weeks; + uint32 startTimestamp = moddedCurrTimestamp - 3 days; + uint32 duration = 3 days; rewardsSubmission[0] = IRewardsCoordinator.RewardsSubmission({ strategiesAndMultipliers: strategyAndMultipliers,