diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 00000000..1103cfed Binary files /dev/null and b/.DS_Store differ diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 793b9df9..8c4833ab 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -31,7 +31,7 @@ jobs: - name: Run Forge build run: | forge --version - forge build --sizes + forge build --optimize --optimizer-runs 200 --via-ir --sizes id: build - name: Run Forge tests diff --git a/README.md b/README.md index dacd1251..10ea463e 100644 --- a/README.md +++ b/README.md @@ -82,6 +82,44 @@ npm run start:operator ``` +### Create and Claim Payments + +In a terminal, start a new instance of anvil and deploy the core and avs contracts +```sh +# Start anvil +npm run start:anvil-quick +# Deploy the EigenLayer contracts +npm run deploy:core + +# Deploy the Hello World AVS contracts +npm run deploy:hello-world + +``` + +In another terminal, run: + +```sh +# Create payment roots +npm run create-payments-root + +# Claim created payment +npm run claim-payments +``` + +To run operator directed payments, run: +```sh +#Create payment roots +npm run create-operator-directed-payments-root + +# Claim created payment +npm run claim-payments +``` + +In order to create and claim multiple payments (run the above two commands more than once), you must wait up to 5 minutes. + + + + ### Create Hello-World-AVS Tasks Open a separate terminal window #3, execute the following commands diff --git a/contracts/config/core/31337.json b/contracts/config/core/31337.json new file mode 100644 index 00000000..9088023b --- /dev/null +++ b/contracts/config/core/31337.json @@ -0,0 +1,29 @@ +{ + "strategyManager": { + "init_paused_status": 0, + "init_withdrawal_delay_blocks": 50400 + }, + "delegation": { + "init_paused_status": 0, + "init_withdrawal_delay_blocks": 50400 + }, + "slasher": { + "init_paused_status": 0 + }, + "eigenPodManager": { + "init_paused_status": 0 + }, + "rewardsCoordinator": { + "init_paused_status": 0, + "MAX_REWARDS_DURATION": 864000, + "MAX_RETROACTIVE_LENGTH": 86400, + "MAX_FUTURE_LENGTH": 86400, + "GENESIS_REWARDS_TIMESTAMP": 1672531200, + "rewards_updater_address": "0x14dC79964da2C08b23698B3D3cc7Ca32193d9955", + "rewards_updater_key": "0x4bbbf85ce3377467afe5d46f804f221813b2bb87f24d81f60f1fcdbf7cbf4356", + "activation_delay": 0, + "calculation_interval_seconds": 86400, + "global_operator_commission_bips": 1000 + } + } + \ No newline at end of file diff --git a/contracts/config/hello-world/31337.json b/contracts/config/hello-world/31337.json new file mode 100644 index 00000000..91fa44e5 --- /dev/null +++ b/contracts/config/hello-world/31337.json @@ -0,0 +1,10 @@ +{ + "addresses": { + "rewardsOwner": "0x23618e81E3f5cdF7f54C3d65f7FBc0aBf5B21E8f", + "rewardsInitiator": "0xa0Ee7A142d267C1f36714E4a8F75612F20a79720" + }, + "keys": { + "rewardsOwner": "0xdbda1821b80551c9d65939329250298aa3472ba22feea921c0cf5d620ea67b97", + "rewardsInitiator": "0x2a871d0798f97d79848a013d4936a73bf4cc922c825d33c1cf7073dff6d409c6" + } +} \ No newline at end of file diff --git a/contracts/lib/eigenlayer-middleware b/contracts/lib/eigenlayer-middleware index 74438b79..027226b6 160000 --- a/contracts/lib/eigenlayer-middleware +++ b/contracts/lib/eigenlayer-middleware @@ -1 +1 @@ -Subproject commit 74438b7915c35ca5a0d312654716160c2499169d +Subproject commit 027226b618b13d3a41f586b8d597fc92f4daafd2 diff --git a/contracts/lib/forge-std b/contracts/lib/forge-std index 58d30519..726a6ee5 160000 --- a/contracts/lib/forge-std +++ b/contracts/lib/forge-std @@ -1 +1 @@ -Subproject commit 58d30519826c313ce47345abedfdc07679e944d1 +Subproject commit 726a6ee5fc8427a0013d6f624e486c9130c0e336 diff --git a/contracts/script/DeployEigenLayerCore.s.sol b/contracts/script/DeployEigenLayerCore.s.sol index 3c60480d..18dbd9aa 100644 --- a/contracts/script/DeployEigenLayerCore.s.sol +++ b/contracts/script/DeployEigenLayerCore.s.sol @@ -6,7 +6,11 @@ import {Script} from "forge-std/Script.sol"; import {CoreDeploymentLib} from "./utils/CoreDeploymentLib.sol"; import {UpgradeableProxyLib} from "./utils/UpgradeableProxyLib.sol"; -contract DeployEigenLayerCore is Script { +import {IRewardsCoordinator} from "@eigenlayer/contracts/interfaces/IRewardsCoordinator.sol"; + +import "forge-std/Test.sol"; + +contract DeployEigenlayerCore is Script, Test { using CoreDeploymentLib for *; using UpgradeableProxyLib for address; @@ -22,6 +26,9 @@ contract DeployEigenLayerCore is Script { function run() external { vm.startBroadcast(deployer); + //set the rewards updater to the deployer address for payment flow + configData = CoreDeploymentLib.readDeploymentConfigValues("config/core/", block.chainid); + configData.rewardsCoordinator.updater = deployer; proxyAdmin = UpgradeableProxyLib.deployProxyAdmin(); deploymentData = CoreDeploymentLib.deployContracts(proxyAdmin, configData); vm.stopBroadcast(); diff --git a/contracts/script/HelloWorldDeployer.s.sol b/contracts/script/HelloWorldDeployer.s.sol index 3e4c7bea..92445b78 100644 --- a/contracts/script/HelloWorldDeployer.s.sol +++ b/contracts/script/HelloWorldDeployer.s.sol @@ -12,6 +12,8 @@ import {TransparentUpgradeableProxy} from "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol"; import {StrategyFactory} from "@eigenlayer/contracts/strategies/StrategyFactory.sol"; import {StrategyManager} from "@eigenlayer/contracts/core/StrategyManager.sol"; +import {IRewardsCoordinator} from "@eigenlayer/contracts/interfaces/IRewardsCoordinator.sol"; + import { @@ -20,41 +22,56 @@ import { IStrategy } from "@eigenlayer-middleware/src/interfaces/IECDSAStakeRegistryEventsAndErrors.sol"; -contract HelloWorldDeployer is Script { +import "forge-std/Test.sol"; + +contract HelloWorldDeployer is Script, Test { using CoreDeploymentLib for *; using UpgradeableProxyLib for address; address private deployer; address proxyAdmin; + address rewardsOwner; + address rewardsInitiator; IStrategy helloWorldStrategy; CoreDeploymentLib.DeploymentData coreDeployment; HelloWorldDeploymentLib.DeploymentData helloWorldDeployment; + HelloWorldDeploymentLib.DeploymentConfigData helloWorldConfig; Quorum internal quorum; ERC20Mock token; function setUp() public virtual { deployer = vm.rememberKey(vm.envUint("PRIVATE_KEY")); vm.label(deployer, "Deployer"); + + helloWorldConfig = HelloWorldDeploymentLib.readDeploymentConfigValues("config/hello-world/", block.chainid); + + coreDeployment = CoreDeploymentLib.readDeploymentJson("deployments/core/", block.chainid); } function run() external { vm.startBroadcast(deployer); - proxyAdmin = UpgradeableProxyLib.deployProxyAdmin(); + rewardsOwner = helloWorldConfig.rewardsOwner; + rewardsInitiator = helloWorldConfig.rewardsInitiator; token = new ERC20Mock(); helloWorldStrategy = IStrategy(StrategyFactory(coreDeployment.strategyFactory).deployNewStrategy(token)); + quorum.strategies.push( StrategyParams({strategy: helloWorldStrategy, multiplier: 10_000}) ); + + proxyAdmin = UpgradeableProxyLib.deployProxyAdmin(); + + helloWorldDeployment = - HelloWorldDeploymentLib.deployContracts(proxyAdmin, coreDeployment, quorum); + HelloWorldDeploymentLib.deployContracts(proxyAdmin, coreDeployment, quorum, rewardsInitiator, rewardsOwner); helloWorldDeployment.strategy = address(helloWorldStrategy); helloWorldDeployment.token = address(token); - vm.stopBroadcast(); + vm.stopBroadcast(); verifyDeployment(); HelloWorldDeploymentLib.writeDeploymentJson(helloWorldDeployment); } @@ -75,4 +92,4 @@ contract HelloWorldDeployer is Script { ); require(coreDeployment.avsDirectory != address(0), "AVSDirectory address cannot be zero"); } -} +} \ No newline at end of file diff --git a/contracts/script/SetupPayments.s.sol b/contracts/script/SetupPayments.s.sol index 657f0850..e570e4a3 100644 --- a/contracts/script/SetupPayments.s.sol +++ b/contracts/script/SetupPayments.s.sol @@ -6,14 +6,17 @@ import {HelloWorldDeploymentLib} from "./utils/HelloWorldDeploymentLib.sol"; import {CoreDeploymentLib} from "./utils/CoreDeploymentLib.sol"; import {SetupPaymentsLib} from "./utils/SetupPaymentsLib.sol"; import {IRewardsCoordinator} from "@eigenlayer/contracts/interfaces/IRewardsCoordinator.sol"; +import {RewardsCoordinator} from "@eigenlayer/contracts/core/RewardsCoordinator.sol"; +import {IStrategy} from "@eigenlayer/contracts/interfaces/IStrategy.sol"; +import {ERC20Mock} from "../test/ERC20Mock.sol"; -contract SetupPayments is Script { - struct PaymentInfo { - address[] earners; - bytes32[] earnerTokenRoots; +import "forge-std/Test.sol"; + +contract SetupPayments is Script, Test { + struct PaymentInfo { address recipient; - uint256 numPayments; - uint256 amountPerPayment; + uint32 numPayments; + uint32 amountPerPayment; uint32 duration; uint32 startTimestamp; uint32 endTimestamp; @@ -22,44 +25,147 @@ contract SetupPayments is Script { address private deployer; CoreDeploymentLib.DeploymentData coreDeployment; + CoreDeploymentLib.DeploymentConfigData coreConfig; + HelloWorldDeploymentLib.DeploymentData helloWorldDeployment; + HelloWorldDeploymentLib.DeploymentConfigData helloWorldConfig; + + RewardsCoordinator rewardsCoordinator; + string internal constant paymentInfofilePath = "test/mockData/scratch/payment_info.json"; string internal constant filePath = "test/mockData/scratch/payments.json"; + + + uint32 constant CALCULATION_INTERVAL_SECONDS = 1 days; uint256 constant NUM_TOKEN_EARNINGS = 1; - uint256 constant DURATION = 1 weeks; + uint32 constant DURATION = 1; + uint256 constant NUM_EARNERS = 8; + + uint32 numPayments = 8; + uint32 indexToProve = 0; + uint32 amountPerPayment = 100; + + address recipient = address(1); + IRewardsCoordinator.EarnerTreeMerkleLeaf[] public earnerLeaves; + address[] public earners; + uint32 startTimestamp; + uint32 endTimestamp; + uint256 cumumlativePaymentMultiplier; + address nonceSender = 0x998abeb3E57409262aE5b751f60747921B33613E; + + address operator1 = address(1); + address operator2 = address(2); + function setUp() public { deployer = vm.rememberKey(vm.envUint("PRIVATE_KEY")); vm.label(deployer, "Deployer"); coreDeployment = CoreDeploymentLib.readDeploymentJson("deployments/core/", block.chainid); + coreConfig = CoreDeploymentLib.readDeploymentConfigValues("config/core/", block.chainid); helloWorldDeployment = HelloWorldDeploymentLib.readDeploymentJson("deployments/hello-world/", block.chainid); + helloWorldConfig = HelloWorldDeploymentLib.readDeploymentConfigValues("config/hello-world/", block.chainid); + + rewardsCoordinator = RewardsCoordinator(coreDeployment.rewardsCoordinator); // TODO: Get the filePath from config } function run() external { + vm.startBroadcast(helloWorldConfig.rewardsInitiatorKey); + + if(rewardsCoordinator.currRewardsCalculationEndTimestamp() == 0) { + startTimestamp = uint32(block.timestamp) - (uint32(block.timestamp) % CALCULATION_INTERVAL_SECONDS); + } else { + startTimestamp = rewardsCoordinator.currRewardsCalculationEndTimestamp() - DURATION + CALCULATION_INTERVAL_SECONDS; + } + + endTimestamp = startTimestamp + 1; + + + if (endTimestamp > block.timestamp) { + revert("End timestamp must be in the future. Please wait to generate new payments."); + } + + // sets a multiplier based on block number such that cumulativeEarnings increase accordingly for multiple runs of this script in the same session + uint256 nonce = rewardsCoordinator.getDistributionRootsLength(); + amountPerPayment = uint32(amountPerPayment * (nonce + 1)); + + createAVSRewardsSubmissions(numPayments, amountPerPayment, startTimestamp); + vm.stopBroadcast(); vm.startBroadcast(deployer); - IRewardsCoordinator(coreDeployment.rewardsCoordinator).setRewardsUpdater(deployer); - PaymentInfo memory info = abi.decode(vm.parseJson(vm.readFile(filePath)), (PaymentInfo)); + earners = _getEarners(deployer); + submitPaymentRoot(earners, endTimestamp, numPayments, amountPerPayment); + vm.stopBroadcast(); + } - createAVSRewardsSubmissions(info.numPayments, info.amountPerPayment, info.duration, info.startTimestamp); - submitPaymentRoot(info.earners, info.endTimestamp, uint32(info.numPayments), uint32(info.amountPerPayment)); + function runOperatorDirected() external { + vm.startBroadcast(helloWorldConfig.rewardsInitiatorKey); + if(rewardsCoordinator.currRewardsCalculationEndTimestamp() == 0) { + startTimestamp = uint32(block.timestamp) - (uint32(block.timestamp) % CALCULATION_INTERVAL_SECONDS); + } else { + startTimestamp = rewardsCoordinator.currRewardsCalculationEndTimestamp() - DURATION + CALCULATION_INTERVAL_SECONDS; + } - IRewardsCoordinator.EarnerTreeMerkleLeaf memory earnerLeaf = IRewardsCoordinator.EarnerTreeMerkleLeaf({ - earner: info.earners[info.indexToProve], - earnerTokenRoot: info.earnerTokenRoots[info.indexToProve] - }); + endTimestamp = startTimestamp + 1; - processClaim(filePath, info.indexToProve, info.recipient, earnerLeaf); + if (endTimestamp > block.timestamp) { + revert("End timestamp must be in the future. Please wait to generate new payments."); + } + + // sets a multiplier based on block number such that cumulativeEarnings increase accordingly for multiple runs of this script in the same session + uint256 nonce = rewardsCoordinator.getDistributionRootsLength(); + amountPerPayment = uint32(amountPerPayment * (nonce + 1)); + + createOperatorDirectedAVSRewardsSubmissions(numPayments, amountPerPayment, startTimestamp); + vm.stopBroadcast(); + vm.startBroadcast(deployer); + earners = _getEarners(deployer); + submitPaymentRoot(earners, endTimestamp, numPayments, amountPerPayment); vm.stopBroadcast(); } + + function executeProcessClaim() public { + uint256 nonce = rewardsCoordinator.getDistributionRootsLength(); + amountPerPayment = uint32(amountPerPayment * nonce); - function createAVSRewardsSubmissions(uint256 numPayments, uint256 amountPerPayment, uint32 duration, uint32 startTimestamp) public { + vm.startBroadcast(deployer); + earnerLeaves = _getEarnerLeaves(_getEarners(deployer), amountPerPayment, helloWorldDeployment.strategy); + processClaim(filePath, indexToProve, recipient, earnerLeaves[indexToProve], amountPerPayment); + vm.stopBroadcast(); + } + + function createAVSRewardsSubmissions(uint256 numPayments, uint256 amountPerPayment, uint32 startTimestamp) public { + ERC20Mock(helloWorldDeployment.token).mint(helloWorldConfig.rewardsInitiator, amountPerPayment * numPayments); + ERC20Mock(helloWorldDeployment.token).increaseAllowance(helloWorldDeployment.helloWorldServiceManager, amountPerPayment * numPayments); + uint32 duration = rewardsCoordinator.MAX_REWARDS_DURATION(); SetupPaymentsLib.createAVSRewardsSubmissions( - IRewardsCoordinator(coreDeployment.rewardsCoordinator), + helloWorldDeployment.helloWorldServiceManager, + helloWorldDeployment.strategy, + numPayments, + amountPerPayment, + duration, + startTimestamp + ); + } + + + function createOperatorDirectedAVSRewardsSubmissions(uint256 numPayments, uint256 amountPerPayment, uint32 startTimestamp) public { + ERC20Mock(helloWorldDeployment.token).mint(helloWorldConfig.rewardsInitiator, amountPerPayment * numPayments); + ERC20Mock(helloWorldDeployment.token).increaseAllowance(helloWorldDeployment.helloWorldServiceManager, amountPerPayment * numPayments); + uint32 duration = 0; + address[] memory operators = new address[](2); + operators[0] = operator1; + operators[1] = operator2; + + uint256 numOperators = operators.length; + + SetupPaymentsLib.createOperatorDirectedAVSRewardsSubmissions( + helloWorldDeployment.helloWorldServiceManager, + operators, + numOperators, helloWorldDeployment.strategy, numPayments, amountPerPayment, @@ -68,7 +174,7 @@ contract SetupPayments is Script { ); } - function processClaim(string memory filePath, uint256 indexToProve, address recipient, IRewardsCoordinator.EarnerTreeMerkleLeaf memory earnerLeaf) public { + function processClaim(string memory filePath, uint256 indexToProve, address recipient, IRewardsCoordinator.EarnerTreeMerkleLeaf memory earnerLeaf, uint32 amountPerPayment) public { SetupPaymentsLib.processClaim( IRewardsCoordinator(coreDeployment.rewardsCoordinator), filePath, @@ -76,11 +182,13 @@ contract SetupPayments is Script { recipient, earnerLeaf, NUM_TOKEN_EARNINGS, - helloWorldDeployment.strategy + helloWorldDeployment.strategy, + amountPerPayment ); } function submitPaymentRoot(address[] memory earners, uint32 endTimestamp, uint32 numPayments, uint32 amountPerPayment) public { + emit log_named_uint("cumumlativePaymentMultiplier", cumumlativePaymentMultiplier); bytes32[] memory tokenLeaves = SetupPaymentsLib.createTokenLeaves( IRewardsCoordinator(coreDeployment.rewardsCoordinator), NUM_TOKEN_EARNINGS, @@ -88,6 +196,8 @@ contract SetupPayments is Script { helloWorldDeployment.strategy ); IRewardsCoordinator.EarnerTreeMerkleLeaf[] memory earnerLeaves = SetupPaymentsLib.createEarnerLeaves(earners, tokenLeaves); + emit log_named_uint("Earner Leaves Length", earnerLeaves.length); + emit log_named_uint("numPayments", numPayments); SetupPaymentsLib.submitRoot( IRewardsCoordinator(coreDeployment.rewardsCoordinator), @@ -100,4 +210,25 @@ contract SetupPayments is Script { filePath ); } + + function _getEarnerLeaves(address[] memory earners, uint32 amountPerPayment, address strategy) internal view returns (IRewardsCoordinator.EarnerTreeMerkleLeaf[] memory) { + bytes32[] memory tokenLeaves = SetupPaymentsLib.createTokenLeaves( + IRewardsCoordinator(coreDeployment.rewardsCoordinator), + NUM_TOKEN_EARNINGS, + amountPerPayment, + strategy + ); + + IRewardsCoordinator.EarnerTreeMerkleLeaf[] memory earnerLeaves = SetupPaymentsLib.createEarnerLeaves(earners, tokenLeaves); + + return earnerLeaves; + } + + function _getEarners(address deployer) internal pure returns (address[] memory) { + address[] memory earners = new address[](NUM_EARNERS); + for (uint256 i = 0; i < earners.length; i++) { + earners[i] = deployer; + } + return earners; + } } \ No newline at end of file diff --git a/contracts/script/utils/CoreDeploymentLib.sol b/contracts/script/utils/CoreDeploymentLib.sol index bb24138f..0fdb6311 100644 --- a/contracts/script/utils/CoreDeploymentLib.sol +++ b/contracts/script/utils/CoreDeploymentLib.sol @@ -66,6 +66,7 @@ library CoreDeploymentLib { uint256 maxFutureLength; uint256 genesisRewardsTimestamp; address updater; + uint256 updaterKey; uint256 activationDelay; uint256 calculationIntervalSeconds; uint256 globalOperatorCommissionBips; @@ -85,6 +86,7 @@ library CoreDeploymentLib { address pauserRegistry; address strategyFactory; address strategyBeacon; + address initialOwner; } function deployContracts( @@ -146,9 +148,9 @@ library CoreDeploymentLib { /// TODO: Get actual values uint32 CALCULATION_INTERVAL_SECONDS = 1 days; uint32 MAX_REWARDS_DURATION = 1 days; - uint32 MAX_RETROACTIVE_LENGTH = 1; - uint32 MAX_FUTURE_LENGTH = 1; - uint32 GENESIS_REWARDS_TIMESTAMP = 10 days; + uint32 MAX_RETROACTIVE_LENGTH = 1 days; + uint32 MAX_FUTURE_LENGTH = 2 days; + uint32 GENESIS_REWARDS_TIMESTAMP = 0; address rewardsCoordinatorImpl = address( new RewardsCoordinator( IDelegationManager(result.delegationManager), @@ -255,8 +257,7 @@ library CoreDeploymentLib { proxyAdmin, // initialOwner IPauserRegistry(result.pauserRegistry), // _pauserRegistry configData.rewardsCoordinator.initPausedStatus, // initialPausedStatus - /// TODO: is there a setter and is this expected? - address(0), // rewards updater + configData.rewardsCoordinator.updater, uint32(configData.rewardsCoordinator.activationDelay), // _activationDelay uint16(configData.rewardsCoordinator.globalOperatorCommissionBips) // _globalCommissionBips ) @@ -289,10 +290,10 @@ library CoreDeploymentLib { function readDeploymentConfigValues( string memory directoryPath, string memory fileName - ) internal returns (DeploymentConfigData memory) { + ) internal view returns (DeploymentConfigData memory) { string memory pathToFile = string.concat(directoryPath, fileName); - require(vm.exists(pathToFile), "Deployment file does not exist"); + require(vm.exists(pathToFile), "CoreDeployment: Deployment config file does not exist"); string memory json = vm.readFile(pathToFile); @@ -332,6 +333,8 @@ library CoreDeploymentLib { json.readUint(".rewardsCoordinator.GENESIS_REWARDS_TIMESTAMP"); data.rewardsCoordinator.updater = json.readAddress(".rewardsCoordinator.rewards_updater_address"); + data.rewardsCoordinator.updaterKey = + json.readUint(".rewardsCoordinator.rewards_updater_key"); data.rewardsCoordinator.activationDelay = json.readUint(".rewardsCoordinator.activation_delay"); data.rewardsCoordinator.calculationIntervalSeconds = @@ -346,7 +349,7 @@ library CoreDeploymentLib { function readDeploymentConfigValues( string memory directoryPath, uint256 chainId - ) internal returns (DeploymentConfigData memory) { + ) internal view returns (DeploymentConfigData memory) { return readDeploymentConfigValues(directoryPath, string.concat(vm.toString(chainId), ".json")); } @@ -354,17 +357,17 @@ library CoreDeploymentLib { function readDeploymentJson( string memory directoryPath, uint256 chainId - ) internal returns (DeploymentData memory) { + ) internal view returns (DeploymentData memory) { return readDeploymentJson(directoryPath, string.concat(vm.toString(chainId), ".json")); } function readDeploymentJson( string memory path, string memory fileName - ) internal returns (DeploymentData memory) { + ) internal view returns (DeploymentData memory) { string memory pathToFile = string.concat(path, fileName); - require(vm.exists(pathToFile), "Deployment file does not exist"); + require(vm.exists(pathToFile), "CoreDeployment: Deployment file does not exist"); string memory json = vm.readFile(pathToFile); @@ -374,6 +377,8 @@ library CoreDeploymentLib { data.eigenPodManager = json.readAddress(".addresses.eigenPodManager"); data.delegationManager = json.readAddress(".addresses.delegation"); data.avsDirectory = json.readAddress(".addresses.avsDirectory"); + data.rewardsCoordinator = json.readAddress(".addresses.rewardsCoordinator"); + data.initialOwner = json.readAddress(".addresses.proxyAdmin"); return data; } @@ -448,6 +453,8 @@ library CoreDeploymentLib { data.strategyFactory.getImplementation().toHexString(), '","strategyBeacon":"', data.strategyBeacon.toHexString(), + '","rewardsCoordinator":"', + data.rewardsCoordinator.toHexString(), '"}' ); } diff --git a/contracts/script/utils/HelloWorldDeploymentLib.sol b/contracts/script/utils/HelloWorldDeploymentLib.sol index fa8c0ba9..70f499bc 100644 --- a/contracts/script/utils/HelloWorldDeploymentLib.sol +++ b/contracts/script/utils/HelloWorldDeploymentLib.sol @@ -30,10 +30,19 @@ library HelloWorldDeploymentLib { address token; } + struct DeploymentConfigData { + address rewardsOwner; + address rewardsInitiator; + uint256 rewardsOwnerKey; + uint256 rewardsInitiatorKey; + } + function deployContracts( address proxyAdmin, CoreDeploymentLib.DeploymentData memory core, - Quorum memory quorum + Quorum memory quorum, + address rewardsInitiator, + address owner ) internal returns (DeploymentData memory) { DeploymentData memory result; @@ -53,36 +62,38 @@ library HelloWorldDeploymentLib { ECDSAStakeRegistry.initialize, (result.helloWorldServiceManager, 0, quorum) ); UpgradeableProxyLib.upgradeAndCall(result.stakeRegistry, stakeRegistryImpl, upgradeCall); - UpgradeableProxyLib.upgrade(result.helloWorldServiceManager, helloWorldServiceManagerImpl); + upgradeCall = abi.encodeCall(HelloWorldServiceManager.initialize, (owner, rewardsInitiator)); + UpgradeableProxyLib.upgradeAndCall(result.helloWorldServiceManager, helloWorldServiceManagerImpl, upgradeCall); return result; } function readDeploymentJson( uint256 chainId - ) internal returns (DeploymentData memory) { + ) internal view returns (DeploymentData memory) { return readDeploymentJson("deployments/", chainId); } function readDeploymentJson( string memory directoryPath, uint256 chainId - ) internal returns (DeploymentData memory) { + ) internal view returns (DeploymentData memory) { string memory fileName = string.concat(directoryPath, vm.toString(chainId), ".json"); - require(vm.exists(fileName), "Deployment file does not exist"); + require(vm.exists(fileName), "HelloWorldDeployment: Deployment file does not exist"); string memory json = vm.readFile(fileName); DeploymentData memory data; /// TODO: 2 Step for reading deployment json. Read to the core and the AVS data - data.helloWorldServiceManager = json.readAddress(".contracts.helloWorldServiceManager"); - data.stakeRegistry = json.readAddress(".contracts.stakeRegistry"); - data.strategy = json.readAddress(".contracts.strategy"); - data.token = json.readAddress(".contracts.token"); + data.helloWorldServiceManager = json.readAddress(".addresses.helloWorldServiceManager"); + data.stakeRegistry = json.readAddress(".addresses.stakeRegistry"); + data.strategy = json.readAddress(".addresses.strategy"); + data.token = json.readAddress(".addresses.token"); return data; } + /// write to default output path function writeDeploymentJson( @@ -109,6 +120,33 @@ library HelloWorldDeploymentLib { vm.writeFile(fileName, deploymentData); console2.log("Deployment artifacts written to:", fileName); } + + + function readDeploymentConfigValues( + string memory directoryPath, + string memory fileName + ) internal view returns (DeploymentConfigData memory) { + string memory pathToFile = string.concat(directoryPath, fileName); + + require(vm.exists(pathToFile), "HelloWorldDeployment: Deployment Config file does not exist"); + + string memory json = vm.readFile(pathToFile); + + DeploymentConfigData memory data; + data.rewardsOwner = json.readAddress(".addresses.rewardsOwner"); + data.rewardsInitiator = json.readAddress(".addresses.rewardsInitiator"); + data.rewardsOwnerKey = json.readUint(".keys.rewardsOwner"); + data.rewardsInitiatorKey = json.readUint(".keys.rewardsInitiator"); + return data; + } + + function readDeploymentConfigValues( + string memory directoryPath, + uint256 chainId + ) internal view returns (DeploymentConfigData memory) { + return + readDeploymentConfigValues(directoryPath, string.concat(vm.toString(chainId), ".json")); + } function _generateDeploymentJson( DeploymentData memory data, @@ -147,4 +185,4 @@ library HelloWorldDeploymentLib { '"}' ); } -} +} \ No newline at end of file diff --git a/contracts/script/utils/SetupPaymentsLib.sol b/contracts/script/utils/SetupPaymentsLib.sol index cde8379e..80e923f0 100644 --- a/contracts/script/utils/SetupPaymentsLib.sol +++ b/contracts/script/utils/SetupPaymentsLib.sol @@ -3,6 +3,7 @@ pragma solidity ^0.8.0; import {IRewardsCoordinator} from "@eigenlayer/contracts/interfaces/IRewardsCoordinator.sol"; import {IStrategy} from "eigenlayer-contracts/src/contracts/interfaces/IStrategyManager.sol"; +import {ECDSAServiceManagerBase} from "@eigenlayer-middleware/src/unaudited/ECDSAServiceManagerBase.sol"; import {Vm} from "forge-std/Vm.sol"; @@ -16,7 +17,7 @@ library SetupPaymentsLib { } function createAVSRewardsSubmissions( - IRewardsCoordinator rewardsCoordinator, + address helloWorldServiceManager, address strategy, uint256 numPayments, uint256 amountPerPayment, @@ -35,14 +36,56 @@ library SetupPaymentsLib { strategiesAndMultipliers: strategiesAndMultipliers, token: IStrategy(strategy).underlyingToken(), amount: amountPerPayment, - startTimestamp: startTimestamp , + startTimestamp: startTimestamp, duration: duration }); rewardsSubmissions[i] = rewardsSubmission; } + ECDSAServiceManagerBase(helloWorldServiceManager).createAVSRewardsSubmission(rewardsSubmissions); + } + + function createOperatorDirectedAVSRewardsSubmissions( + address helloWorldServiceManager, + address[] memory operators, + uint256 numOperators, + address strategy, + uint256 numPayments, + uint256 amountPerPayment, + uint32 duration, + uint32 startTimestamp + ) internal { + + uint256 operatorRewardAmount = amountPerPayment / numOperators; + + IRewardsCoordinator.OperatorReward[] memory operatorRewards = new IRewardsCoordinator.OperatorReward[](2); + for (uint256 i = 0; i < 2; i++) { + operatorRewards[i] = IRewardsCoordinator.OperatorReward({ + operator: operators[i], + amount: operatorRewardAmount + }); + } - rewardsCoordinator.createAVSRewardsSubmission(rewardsSubmissions); + IRewardsCoordinator.OperatorDirectedRewardsSubmission[] memory rewardsSubmissions = new IRewardsCoordinator.OperatorDirectedRewardsSubmission[](numPayments); + for (uint256 i = 0; i < numPayments; i++) { + IRewardsCoordinator.StrategyAndMultiplier[] memory strategiesAndMultipliers = new IRewardsCoordinator.StrategyAndMultiplier[](1); + strategiesAndMultipliers[0] = IRewardsCoordinator.StrategyAndMultiplier({ + strategy: IStrategy(strategy), + multiplier: 10000 + }); + + IRewardsCoordinator.OperatorDirectedRewardsSubmission memory rewardsSubmission = IRewardsCoordinator.OperatorDirectedRewardsSubmission({ + strategiesAndMultipliers: strategiesAndMultipliers, + token: IStrategy(strategy).underlyingToken(), + operatorRewards: operatorRewards, + startTimestamp: startTimestamp, + duration: duration, + description: "test" + }); + + rewardsSubmissions[i] = rewardsSubmission; + } + ECDSAServiceManagerBase(helloWorldServiceManager).createOperatorDirectedAVSRewardsSubmission(rewardsSubmissions); } function processClaim( @@ -52,11 +95,13 @@ library SetupPaymentsLib { address recipient, IRewardsCoordinator.EarnerTreeMerkleLeaf memory earnerLeaf, uint256 NUM_TOKEN_EARNINGS, - address strategy + address strategy, + uint32 amountPerPayment ) internal { PaymentLeaves memory paymentLeaves = parseLeavesFromJson(filePath); bytes memory proof = generateMerkleProof(paymentLeaves.leaves, indexToProve); + //we only have one token leaf bytes memory tokenProof = generateMerkleProof(paymentLeaves.tokenLeaves, 0); uint32[] memory tokenIndices = new uint32[](NUM_TOKEN_EARNINGS); @@ -64,10 +109,14 @@ library SetupPaymentsLib { tokenProofs[0] = tokenProof; IRewardsCoordinator.TokenTreeMerkleLeaf[] memory tokenLeaves = new IRewardsCoordinator.TokenTreeMerkleLeaf[](NUM_TOKEN_EARNINGS); - tokenLeaves[0] = defaultTokenLeaf(100, strategy); + tokenLeaves[0] = defaultTokenLeaf(amountPerPayment, strategy); + + + // this workflow assumes a new root submitted for every payment claimed. So we get the latest rood index to process a claim for + uint256 rootIndex = rewardsCoordinator.getDistributionRootsLength() - 1; IRewardsCoordinator.RewardsMerkleClaim memory claim = IRewardsCoordinator.RewardsMerkleClaim({ - rootIndex: 0, + rootIndex: uint32(rootIndex), earnerIndex: uint32(indexToProve), earnerTreeProof: proof, earnerLeaf: earnerLeaf, @@ -89,7 +138,7 @@ library SetupPaymentsLib { uint256 NUM_TOKEN_EARNINGS, string memory filePath ) internal { - bytes32 paymentRoot = createPaymentRoot(rewardsCoordinator, tokenLeaves, earnerLeaves, NUM_PAYMENTS, NUM_TOKEN_EARNINGS, strategy, filePath); + bytes32 paymentRoot = createPaymentRoot(rewardsCoordinator, tokenLeaves, earnerLeaves, NUM_PAYMENTS, NUM_TOKEN_EARNINGS, filePath); rewardsCoordinator.submitRoot(paymentRoot, rewardsCalculationEndTimestamp); } @@ -99,7 +148,6 @@ library SetupPaymentsLib { IRewardsCoordinator.EarnerTreeMerkleLeaf[] memory earnerLeaves, uint256 NUM_PAYMENTS, uint256 NUM_TOKEN_EARNINGS, - address strategy, string memory filePath ) internal returns (bytes32) { require(earnerLeaves.length == NUM_PAYMENTS, "Number of earners must match number of payments"); @@ -117,7 +165,7 @@ library SetupPaymentsLib { function createEarnerLeaves( address[] calldata earners, bytes32[] memory tokenLeaves - ) public returns (IRewardsCoordinator.EarnerTreeMerkleLeaf[] memory) { + ) public pure returns (IRewardsCoordinator.EarnerTreeMerkleLeaf[] memory) { IRewardsCoordinator.EarnerTreeMerkleLeaf[] memory leaves = new IRewardsCoordinator.EarnerTreeMerkleLeaf[](earners.length); for (uint256 i = 0; i < earners.length; i++) { leaves[i] = IRewardsCoordinator.EarnerTreeMerkleLeaf({ @@ -137,7 +185,7 @@ library SetupPaymentsLib { uint256 NUM_TOKEN_EARNINGS, uint256 TOKEN_EARNINGS, address strategy - ) internal returns (bytes32[] memory) { + ) internal view returns (bytes32[] memory) { bytes32[] memory leaves = new bytes32[](NUM_TOKEN_EARNINGS); for (uint256 i = 0; i < NUM_TOKEN_EARNINGS; i++) { IRewardsCoordinator.TokenTreeMerkleLeaf memory leaf = defaultTokenLeaf(TOKEN_EARNINGS, strategy); @@ -168,7 +216,7 @@ library SetupPaymentsLib { vm.writeJson(finalJson, filePath); } - function parseLeavesFromJson(string memory filePath) internal returns (PaymentLeaves memory) { + function parseLeavesFromJson(string memory filePath) internal view returns (PaymentLeaves memory) { string memory json = vm.readFile(filePath); bytes memory data = vm.parseJson(json); return abi.decode(data, (PaymentLeaves)); diff --git a/contracts/src/HelloWorldServiceManager.sol b/contracts/src/HelloWorldServiceManager.sol index fdebbbdc..34f76aeb 100644 --- a/contracts/src/HelloWorldServiceManager.sol +++ b/contracts/src/HelloWorldServiceManager.sol @@ -54,6 +54,13 @@ contract HelloWorldServiceManager is ECDSAServiceManagerBase, IHelloWorldService ) {} + function initialize( + address initialOwner, + address _rewardsInitiator + ) external initializer { + __ServiceManagerBase_init(initialOwner, _rewardsInitiator); + } + /* FUNCTIONS */ // NOTE: this function creates new task, assigns it a taskId function createNewTask( @@ -101,4 +108,5 @@ contract HelloWorldServiceManager is ECDSAServiceManagerBase, IHelloWorldService // emitting event emit TaskResponded(referenceTaskIndex, task, msg.sender); } -} + +} \ No newline at end of file diff --git a/contracts/test/CoreDeploymentLib.t.sol b/contracts/test/CoreDeploymentLib.t.sol index d5874bb9..30d32681 100644 --- a/contracts/test/CoreDeploymentLib.t.sol +++ b/contracts/test/CoreDeploymentLib.t.sol @@ -19,7 +19,7 @@ contract CoreDeploymentLibTest is Test { } /// won't test specific functionality/values. Testing behavior of the library - function test_ReadConfig() public { + function test_ReadConfig() view public { CoreDeploymentLib.readDeploymentConfigValues("test/mockData/config/core/", 1337); } @@ -29,7 +29,7 @@ contract CoreDeploymentLibTest is Test { CoreDeploymentLib.readDeploymentConfigValues("test/mockData/deployments/core/", 1337); } - function test_ReadDeployment() public { + function test_ReadDeployment() public view { CoreDeploymentLib.readDeploymentJson("test/mockData/deployments/core/", 1337); } diff --git a/contracts/test/HelloWorldServiceManager.t.sol b/contracts/test/HelloWorldServiceManager.t.sol index f7ad8b55..3eb37608 100644 --- a/contracts/test/HelloWorldServiceManager.t.sol +++ b/contracts/test/HelloWorldServiceManager.t.sol @@ -39,8 +39,13 @@ contract HelloWorldTaskManagerSetup is Test { Vm.Wallet key; } + struct AVSOwner { + Vm.Wallet key; + } + Operator[] internal operators; TrafficGenerator internal generator; + AVSOwner internal owner; HelloWorldDeploymentLib.DeploymentData internal helloWorldDeployment; CoreDeploymentLib.DeploymentData internal coreDeployment; @@ -52,6 +57,7 @@ contract HelloWorldTaskManagerSetup is Test { function setUp() public virtual { generator = TrafficGenerator({key: vm.createWallet("generator_wallet")}); + owner = AVSOwner({key: vm.createWallet("owner_wallet")}); address proxyAdmin = UpgradeableProxyLib.deployProxyAdmin(); @@ -65,7 +71,7 @@ contract HelloWorldTaskManagerSetup is Test { quorum.strategies.push(StrategyParams({strategy: strategy, multiplier: 10_000})); helloWorldDeployment = - HelloWorldDeploymentLib.deployContracts(proxyAdmin, coreDeployment, quorum); + HelloWorldDeploymentLib.deployContracts(proxyAdmin, coreDeployment, quorum, owner.key.addr, owner.key.addr); labelContracts(coreDeployment, helloWorldDeployment); } @@ -374,6 +380,9 @@ contract CreateTask is HelloWorldTaskManagerSetup { vm.prank(generator.key.addr); IHelloWorldServiceManager.Task memory newTask = sm.createNewTask(taskName); + + require(sha256(abi.encodePacked(newTask.name)) == sha256(abi.encodePacked(taskName)), "Task name not set correctly"); + require(newTask.taskCreatedBlock == uint32(block.number), "Task created block not set correctly"); } } @@ -433,4 +442,4 @@ contract RespondToTask is HelloWorldTaskManagerSetup { vm.roll(block.number+1); sm.respondToTask(newTask, taskIndex, signedTask); } -} +} \ No newline at end of file diff --git a/contracts/test/SetupPaymentsLib.t.sol b/contracts/test/SetupPaymentsLib.t.sol index 0aeebd62..cb5658d5 100644 --- a/contracts/test/SetupPaymentsLib.t.sol +++ b/contracts/test/SetupPaymentsLib.t.sol @@ -6,17 +6,21 @@ import "../script/utils/SetupPaymentsLib.sol"; import "../script/utils/CoreDeploymentLib.sol"; import "../script/utils/HelloWorldDeploymentLib.sol"; import "@eigenlayer/contracts/interfaces/IRewardsCoordinator.sol"; +import "../src/IHelloWorldServiceManager.sol"; import "@eigenlayer/contracts/interfaces/IStrategy.sol"; import "@eigenlayer/contracts/libraries/Merkle.sol"; import "../script/DeployEigenLayerCore.s.sol"; import "../script/HelloWorldDeployer.s.sol"; import {StrategyFactory} from "@eigenlayer/contracts/strategies/StrategyFactory.sol"; import {HelloWorldTaskManagerSetup} from "test/HelloWorldServiceManager.t.sol"; +import {ECDSAServiceManagerBase} from "@eigenlayer-middleware/src/unaudited/ECDSAServiceManagerBase.sol"; import { Quorum, StrategyParams, IStrategy } from "@eigenlayer-middleware/src/interfaces/IECDSAStakeRegistryEventsAndErrors.sol"; +import "@openzeppelin-upgrades/contracts/access/OwnableUpgradeable.sol"; + contract TestConstants { uint256 constant NUM_PAYMENTS = 8; @@ -35,10 +39,13 @@ contract SetupPaymentsLibTest is Test, TestConstants, HelloWorldTaskManagerSetup IRewardsCoordinator public rewardsCoordinator; + IHelloWorldServiceManager public helloWorldServiceManager; IStrategy public strategy; address proxyAdmin; string internal constant filePath = "test/mockData/scratch/payments.json"; + address rewardsInitiator = address(1); + address rewardsOwner = address(2); function setUp() public override virtual { @@ -53,12 +60,18 @@ contract SetupPaymentsLibTest is Test, TestConstants, HelloWorldTaskManagerSetup quorum.strategies.push(StrategyParams({strategy: strategy, multiplier: 10_000})); helloWorldDeployment = - HelloWorldDeploymentLib.deployContracts(proxyAdmin, coreDeployment, quorum); + HelloWorldDeploymentLib.deployContracts(proxyAdmin, coreDeployment, quorum, rewardsInitiator, rewardsOwner); labelContracts(coreDeployment, helloWorldDeployment); + + cheats.prank(rewardsOwner); + ECDSAServiceManagerBase(helloWorldDeployment.helloWorldServiceManager).setRewardsInitiator(rewardsInitiator); + rewardsCoordinator = IRewardsCoordinator(coreDeployment.rewardsCoordinator); + mockToken.mint(address(this), 100000); mockToken.mint(address(rewardsCoordinator), 100000); + mockToken.mint(rewardsInitiator, 100000); } @@ -74,7 +87,7 @@ contract SetupPaymentsLibTest is Test, TestConstants, HelloWorldTaskManagerSetup bytes32[] memory tokenLeaves = SetupPaymentsLib.createTokenLeaves(rewardsCoordinator, NUM_TOKEN_EARNINGS, TOKEN_EARNINGS, address(strategy)); IRewardsCoordinator.EarnerTreeMerkleLeaf[] memory earnerLeaves =SetupPaymentsLib.createEarnerLeaves(earners, tokenLeaves); - cheats.startPrank(address(0), address(0)); + cheats.startPrank(rewardsCoordinator.rewardsUpdater()); SetupPaymentsLib.submitRoot(rewardsCoordinator, tokenLeaves, earnerLeaves, address(strategy), endTimestamp, NUM_EARNERS, 1, filePath); cheats.stopPrank(); } @@ -106,8 +119,8 @@ contract SetupPaymentsLibTest is Test, TestConstants, HelloWorldTaskManagerSetup assertEq(paymentLeaves.tokenLeaves.length, 1, "Incorrect number of token leaves"); } - function testGenerateMerkleProof() public { - SetupPaymentsLib.PaymentLeaves memory paymentLeaves = SetupPaymentsLib.parseLeavesFromJson("test/mockData/scratch/payments.json"); + function testGenerateMerkleProof() public view { + SetupPaymentsLib.PaymentLeaves memory paymentLeaves = SetupPaymentsLib.parseLeavesFromJson("test/mockData/scratch/payments_test.json"); bytes32[] memory leaves = paymentLeaves.leaves; uint256 indexToProve = 0; @@ -123,10 +136,6 @@ contract SetupPaymentsLibTest is Test, TestConstants, HelloWorldTaskManagerSetup bytes32 root = SetupPaymentsLib.merkleizeKeccak(leaves); - emit log_named_bytes("proof", proofBytesCalculated); - emit log_named_bytes32("root", root); - emit log_named_bytes32("leaf", leaves[indexToProve]); - require(Merkle.verifyInclusionKeccak( proofBytesCalculated, root, @@ -149,7 +158,8 @@ contract SetupPaymentsLibTest is Test, TestConstants, HelloWorldTaskManagerSetup bytes32[] memory tokenLeaves = SetupPaymentsLib.createTokenLeaves(rewardsCoordinator, NUM_TOKEN_EARNINGS, TOKEN_EARNINGS, address(strategy)); IRewardsCoordinator.EarnerTreeMerkleLeaf[] memory earnerLeaves =SetupPaymentsLib.createEarnerLeaves(earners, tokenLeaves); - cheats.startPrank(address(0)); + + cheats.startPrank(rewardsCoordinator.rewardsUpdater()); SetupPaymentsLib.submitRoot(rewardsCoordinator, tokenLeaves, earnerLeaves, address(strategy), endTimestamp, NUM_EARNERS, 1, filePath); cheats.stopPrank(); @@ -164,7 +174,8 @@ contract SetupPaymentsLibTest is Test, TestConstants, HelloWorldTaskManagerSetup RECIPIENT, earnerLeaves[INDEX_TO_PROVE], NUM_TOKEN_EARNINGS, - address(strategy) + address(strategy), + uint32(TOKEN_EARNINGS) ); cheats.stopPrank(); @@ -176,10 +187,13 @@ contract SetupPaymentsLibTest is Test, TestConstants, HelloWorldTaskManagerSetup uint32 duration = rewardsCoordinator.MAX_REWARDS_DURATION(); uint32 startTimestamp = 10 days; cheats.warp(startTimestamp + 1); - mockToken.approve(address(rewardsCoordinator), amountPerPayment * numPayments); + + cheats.prank(rewardsInitiator); + mockToken.increaseAllowance(helloWorldDeployment.helloWorldServiceManager, amountPerPayment * numPayments); + cheats.startPrank(rewardsInitiator); SetupPaymentsLib.createAVSRewardsSubmissions( - rewardsCoordinator, + address(helloWorldDeployment.helloWorldServiceManager), address(strategy), numPayments, amountPerPayment, @@ -187,4 +201,4 @@ contract SetupPaymentsLibTest is Test, TestConstants, HelloWorldTaskManagerSetup startTimestamp ); } -} +} \ No newline at end of file diff --git a/contracts/test/mockData/config/core/1337.json b/contracts/test/mockData/config/core/1337.json index ac7e9710..9b55969d 100644 --- a/contracts/test/mockData/config/core/1337.json +++ b/contracts/test/mockData/config/core/1337.json @@ -20,6 +20,7 @@ "MAX_FUTURE_LENGTH": 86400, "GENESIS_REWARDS_TIMESTAMP": 1672531200, "rewards_updater_address": "0x1234567890123456789012345678901234567890", + "rewards_updater_key": "0x4bbbf85ce3377467afe5d46f804f221813b2bb87f24d81f60f1fcdbf7cbf4356", "activation_delay": 604800, "calculation_interval_seconds": 86400, "global_operator_commission_bips": 1000 diff --git a/contracts/test/mockData/config/hello-world/1337.json b/contracts/test/mockData/config/hello-world/1337.json index e69de29b..b0554185 100644 --- a/contracts/test/mockData/config/hello-world/1337.json +++ b/contracts/test/mockData/config/hello-world/1337.json @@ -0,0 +1,4 @@ +{ + "rewardsOwner": "0x", + "rewardsInitiator": "0x" +} \ No newline at end of file diff --git a/contracts/test/mockData/deployments/core/1337.json b/contracts/test/mockData/deployments/core/1337.json index 2ee0a262..fc442a1c 100644 --- a/contracts/test/mockData/deployments/core/1337.json +++ b/contracts/test/mockData/deployments/core/1337.json @@ -13,6 +13,7 @@ "strategyFactory": "0x7777777777777777777777777777777777777777", "strategyManagerImpl": "0x8888888888888888888888888888888888888888", "eigenPodManager": "0x9999999999999999999999999999999999999999", - "eigenPodManagerImpl": "0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "eigenPodManagerImpl": "0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + "rewardsCoordinator": "0xbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb" } } diff --git a/contracts/test/mockData/deployments/hello-world/1337.json b/contracts/test/mockData/deployments/hello-world/1337.json index e69de29b..6e2fac83 100644 --- a/contracts/test/mockData/deployments/hello-world/1337.json +++ b/contracts/test/mockData/deployments/hello-world/1337.json @@ -0,0 +1,4 @@ +{ + "rewardsOwner": "0x3C4293F66941ECa00f4950C10d4255d5c271bAe1", + "rewardsInitiator": "0x3C4293F66941ECa00f4950C10d4255d5c271bAe1" +} \ No newline at end of file diff --git a/contracts/test/mockData/scratch/31337.json b/contracts/test/mockData/scratch/31337.json index e2f55a3e..9a6ad6ab 100644 --- a/contracts/test/mockData/scratch/31337.json +++ b/contracts/test/mockData/scratch/31337.json @@ -1 +1 @@ -{"lastUpdate":{"timestamp":"1","block_number":"1"},"addresses":{"proxyAdmin":"0x5615deb798bb3e4dfa0139dfa1b3d433cc23b72f","delegation":"0xf62849f9a0b5bf2913b396098f7c7019b51a820a","delegationManagerImpl":"0xdb25a7b768311de128bbda7b8426c3f9c74f3240","avsDirectory":"0xc7183455a4c133ae270771860664b6b7ec320bb1","avsDirectoryImpl":"0x3381cd18e2fb4db236bf0525938ab6e43db0440f","strategyManager":"0x1d1499e622d69689cdf9004d05ec547d650ff211","strategyManagerImpl":"0x756e0562323adcda4430d6cb456d9151f605290b","eigenPodManager":"0x03a6a84cd762d9707a21605b548aaab891562aab","eigenPodManagerImpl":"0xe8dc788818033232ef9772cb2e6622f1ec8bc840","strategyFactory":"0x13aa49bac059d709dd0a18d6bb63290076a702d7","strategyFactoryImpl":"0x1af7f588a501ea2b5bb3feefa744892aa2cf00e6","strategyBeacon":"0x886d6d1eb8d415b00052828cd6d5b321f072073d"}} \ No newline at end of file +{"lastUpdate":{"timestamp":"1","block_number":"1"},"addresses":{"proxyAdmin":"0x5615deb798bb3e4dfa0139dfa1b3d433cc23b72f","delegation":"0xf62849f9a0b5bf2913b396098f7c7019b51a820a","delegationManagerImpl":"0xdb25a7b768311de128bbda7b8426c3f9c74f3240","avsDirectory":"0xc7183455a4c133ae270771860664b6b7ec320bb1","avsDirectoryImpl":"0x3381cd18e2fb4db236bf0525938ab6e43db0440f","strategyManager":"0x1d1499e622d69689cdf9004d05ec547d650ff211","strategyManagerImpl":"0x756e0562323adcda4430d6cb456d9151f605290b","eigenPodManager":"0x03a6a84cd762d9707a21605b548aaab891562aab","eigenPodManagerImpl":"0xe8dc788818033232ef9772cb2e6622f1ec8bc840","strategyFactory":"0x13aa49bac059d709dd0a18d6bb63290076a702d7","strategyFactoryImpl":"0x1af7f588a501ea2b5bb3feefa744892aa2cf00e6","strategyBeacon":"0x886d6d1eb8d415b00052828cd6d5b321f072073d","rewardsCoordinator":"0x15cf58144ef33af1e14b5208015d11f9143e27b9"}} \ No newline at end of file diff --git a/contracts/test/mockData/scratch/payment_info.json b/contracts/test/mockData/scratch/payment_info.json new file mode 100644 index 00000000..84a41de4 --- /dev/null +++ b/contracts/test/mockData/scratch/payment_info.json @@ -0,0 +1,11 @@ +{ + "paymentInfo": { + "recipient": "0x5555666677778888999900001111222233334444", + "numPayments": 8, + "amountPerPayment": "100000000000", + "duration": 2592000, + "startTimestamp": 864000, + "endTimestamp": 1701907200, + "indexToProve": 0 + } +} \ No newline at end of file diff --git a/contracts/test/mockData/scratch/payments.json b/contracts/test/mockData/scratch/payments.json index 77873afa..a08c08f7 100644 --- a/contracts/test/mockData/scratch/payments.json +++ b/contracts/test/mockData/scratch/payments.json @@ -1,11 +1,15 @@ { "leaves": [ - "0x29036a1d92861ffd464a1e285030fad3978a36f953ae33c160e606d2ac746c42", - "0x29036a1d92861ffd464a1e285030fad3978a36f953ae33c160e606d2ac746c42", - "0x29036a1d92861ffd464a1e285030fad3978a36f953ae33c160e606d2ac746c42", - "0x29036a1d92861ffd464a1e285030fad3978a36f953ae33c160e606d2ac746c42" + "0xb0f5692687465968e1da01441ba9006259724929e8c468dee28c6ff60c86ddf4", + "0xb0f5692687465968e1da01441ba9006259724929e8c468dee28c6ff60c86ddf4", + "0xb0f5692687465968e1da01441ba9006259724929e8c468dee28c6ff60c86ddf4", + "0xb0f5692687465968e1da01441ba9006259724929e8c468dee28c6ff60c86ddf4", + "0xb0f5692687465968e1da01441ba9006259724929e8c468dee28c6ff60c86ddf4", + "0xb0f5692687465968e1da01441ba9006259724929e8c468dee28c6ff60c86ddf4", + "0xb0f5692687465968e1da01441ba9006259724929e8c468dee28c6ff60c86ddf4", + "0xb0f5692687465968e1da01441ba9006259724929e8c468dee28c6ff60c86ddf4" ], "tokenLeaves": [ - "0xf5d87050cb923194fe63c7ed2c45cbc913fa6ecf322f3631149c36d9460b3ad6" + "0xe0c89917f508e4c4cb8aff33403a849560a853d87c90011da2a9bb86811fa248" ] } \ No newline at end of file diff --git a/contracts/test/mockData/scratch/payments_test.json b/contracts/test/mockData/scratch/payments_test.json new file mode 100644 index 00000000..c6ba47d6 --- /dev/null +++ b/contracts/test/mockData/scratch/payments_test.json @@ -0,0 +1,11 @@ +{ + "leaves": [ + "0x29036a1d92861ffd464a1e285030fad3978a36f953ae33c160e606d2ac746c42", + "0x29036a1d92861ffd464a1e285030fad3978a36f953ae33c160e606d2ac746c42", + "0x29036a1d92861ffd464a1e285030fad3978a36f953ae33c160e606d2ac746c42", + "0x29036a1d92861ffd464a1e285030fad3978a36f953ae33c160e606d2ac746c42" + ], + "tokenLeaves": [ + "0xf5d87050cb923194fe63c7ed2c45cbc913fa6ecf322f3631149c36d9460b3ad6" + ] + } \ No newline at end of file diff --git a/package.json b/package.json index 3870830a..d55d771f 100644 --- a/package.json +++ b/package.json @@ -6,10 +6,14 @@ "start:operator": "ts-node operator/index.ts", "start:traffic": "ts-node operator/createNewTasks.ts", "start:anvil": "anvil", - "deploy:core": "cd contracts && forge script script/DeployEigenLayerCore.s.sol --rpc-url http://localhost:8545 --broadcast", - "deploy:hello-world": "cd contracts && forge script script/HelloWorldDeployer.s.sol --rpc-url http://localhost:8545 --broadcast", - "deploy:core-debug": "cd contracts && forge script script/DeployEigenLayerCore.s.sol --rpc-url http://localhost:8545 --broadcast --revert-strings debug", + "start:anvil-quick": "anvil --block-time 0.01", + "deploy:core": "cd contracts && forge script script/DeployEigenLayerCore.s.sol --rpc-url http://localhost:8545 --broadcast --optimize --optimizer-runs 200 --via-ir", + "deploy:hello-world": "cd contracts && forge script script/HelloWorldDeployer.s.sol --rpc-url http://localhost:8545 --broadcast --optimize --optimizer-runs 200 --via-ir", + "deploy:core-debug": "cd contracts && forge script script/DeployEigenLayerCore.s.sol --rpc-url http://localhost:8545 --broadcast --revert-strings debug --optimize --optimizer-runs 200 --via-ir", "deploy:hello-world-debug": "cd contracts && forge script script/HelloWorldDeployer.s.sol --rpc-url http://localhost:8545 --broadcast --revert-strings debug", + "create-payments-root": "cd contracts && forge script script/SetupPayments.s.sol --rpc-url http://localhost:8545 --broadcast -v --sender 0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266", + "claim-payments": "cd contracts && forge script script/SetupPayments.s.sol --rpc-url http://localhost:8545 --broadcast --sig \"executeProcessClaim()\" -v --sender 0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266", + "create-operator-directed-payments-root": "cd contracts && forge script script/SetupPayments.s.sol --rpc-url http://localhost:8545 --broadcast --sig \"runOperatorDirected()\" -v --sender 0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266", "build": "cd contracts && forge build", "extract:abis": "node utils/abis.js", "test": "NODE_OPTIONS=\"$NODE_OPTIONS --experimental-vm-modules\" npx jest"