diff --git a/contracts/test/SetupPaymentsLib.t.sol b/contracts/test/SetupPaymentsLib.t.sol index 53f22164..928950d5 100644 --- a/contracts/test/SetupPaymentsLib.t.sol +++ b/contracts/test/SetupPaymentsLib.t.sol @@ -7,6 +7,7 @@ import "../script/utils/CoreDeploymentLib.sol"; import "../script/utils/HelloWorldDeploymentLib.sol"; import "@eigenlayer/contracts/interfaces/IRewardsCoordinator.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"; @@ -25,6 +26,7 @@ contract TestConstants { address RECIPIENT = address(1); address EARNER = address(2); uint256 INDEX_TO_PROVE = 0; + uint256 NUM_EARNERS = 4; } contract SetupPaymentsLibTest is Test, TestConstants, HelloWorldTaskManagerSetup { @@ -34,10 +36,11 @@ contract SetupPaymentsLibTest is Test, TestConstants, HelloWorldTaskManagerSetup IRewardsCoordinator public rewardsCoordinator; IStrategy public strategy; + address proxyAdmin; function setUp() public override virtual { - address proxyAdmin = UpgradeableProxyLib.deployProxyAdmin(); + proxyAdmin = UpgradeableProxyLib.deployProxyAdmin(); coreConfigData = CoreDeploymentLib.readDeploymentConfigValues("test/mockData/config/core/", 1337); // TODO: Fix this to correct path coreDeployment = CoreDeploymentLib.deployContracts(proxyAdmin, coreConfigData); @@ -52,18 +55,28 @@ contract SetupPaymentsLibTest is Test, TestConstants, HelloWorldTaskManagerSetup labelContracts(coreDeployment, helloWorldDeployment); rewardsCoordinator = IRewardsCoordinator(coreDeployment.rewardsCoordinator); + mockToken.mint(address(this), 100000); + mockToken.mint(address(rewardsCoordinator), 100000); } - function testSubmitPaymentRoot() public { - address[] memory earners = new address[](8); + function testSubmitRoot() public { + address[] memory earners = new address[](NUM_EARNERS); for (uint256 i = 0; i < earners.length; i++) { earners[i] = address(1); } + uint32 endTimestamp = rewardsCoordinator.currRewardsCalculationEndTimestamp() + 1 weeks; + cheats.warp(endTimestamp + 1); + + + bytes32[] memory tokenLeaves = SetupPaymentsLib.createTokenLeaves(rewardsCoordinator, NUM_TOKEN_EARNINGS, TOKEN_EARNINGS, address(strategy)); + IRewardsCoordinator.EarnerTreeMerkleLeaf[] memory earnerLeaves =SetupPaymentsLib.createEarnerLeaves(earners, tokenLeaves); // SetupPaymentsLib.submitPaymentRoot(rewardsCoordinator, earners, address(strategy)); - SetupPaymentsLib.submitPaymentRoot(rewardsCoordinator, earners, address(strategy), 8, 1, 100); + cheats.startPrank(address(0), address(0)); + SetupPaymentsLib.submitRoot(rewardsCoordinator, tokenLeaves, earnerLeaves, address(strategy), endTimestamp, NUM_EARNERS, 1, 100); + cheats.stopPrank(); } function testWriteLeavesToJson() public { @@ -92,7 +105,7 @@ contract SetupPaymentsLibTest is Test, TestConstants, HelloWorldTaskManagerSetup } function testGenerateMerkleProof() public { - SetupPaymentsLib.PaymentLeaves memory paymentLeaves = SetupPaymentsLib.parseLeavesFromJson("test/mockData/scratch/payment_leaves.json"); + SetupPaymentsLib.PaymentLeaves memory paymentLeaves = SetupPaymentsLib.parseLeavesFromJson("test/mockData/scratch/payments.json"); bytes32[] memory leaves = paymentLeaves.leaves; uint256 indexToProve = 0; @@ -101,28 +114,58 @@ contract SetupPaymentsLibTest is Test, TestConstants, HelloWorldTaskManagerSetup proof[0] = leaves[1]; proof[1] = keccak256(abi.encodePacked(leaves[2], leaves[3])); - bytes memory proofBytes1 = abi.encodePacked(proof); - bytes memory proofBytes2 = SetupPaymentsLib.generateMerkleProof(leaves, indexToProve); + bytes memory proofBytesConstructed = abi.encodePacked(proof); + bytes memory proofBytesCalculated = SetupPaymentsLib.generateMerkleProof(leaves, indexToProve); + + require(keccak256(proofBytesConstructed) == keccak256(proofBytesCalculated), "Proofs do not match"); + + 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(keccak256(proofBytes1) == keccak256(proofBytes2), "Proofs do not match"); + require(Merkle.verifyInclusionKeccak( + proofBytesCalculated, + root, + leaves[indexToProve], + indexToProve + )); } function testProcessClaim() public { - string memory filePath = "test/mockData/scratch/payment_leaves.json"; - IRewardsCoordinator.EarnerTreeMerkleLeaf memory earnerLeaf; - earnerLeaf.earner = EARNER; + emit log_named_address("token address", address(mockToken)); + string memory filePath = "test/mockData/scratch/payments.json"; + + address[] memory earners = new address[](NUM_EARNERS); + for (uint256 i = 0; i < earners.length; i++) { + earners[i] = address(1); + } + uint32 endTimestamp = rewardsCoordinator.currRewardsCalculationEndTimestamp() + 1 weeks; + cheats.warp(endTimestamp + 1); + + 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)); + SetupPaymentsLib.submitRoot(rewardsCoordinator, tokenLeaves, earnerLeaves, address(strategy), endTimestamp, NUM_EARNERS, 1, 100); + cheats.stopPrank(); + + + cheats.warp(block.timestamp + 2 weeks); + + cheats.startPrank(earnerLeaves[INDEX_TO_PROVE].earner, earnerLeaves[INDEX_TO_PROVE].earner); SetupPaymentsLib.processClaim( rewardsCoordinator, filePath, INDEX_TO_PROVE, RECIPIENT, - earnerLeaf, + earnerLeaves[INDEX_TO_PROVE], NUM_TOKEN_EARNINGS, address(strategy) ); - + cheats.stopPrank(); } function testCreatePaymentSubmissions() public { @@ -132,8 +175,6 @@ contract SetupPaymentsLibTest is Test, TestConstants, HelloWorldTaskManagerSetup uint32 startTimestamp = 10 days; cheats.warp(startTimestamp + 1); - mockToken.mint(address(this), type(uint256).max); - SetupPaymentsLib.createPaymentSubmissions( rewardsCoordinator, address(strategy), @@ -144,143 +185,3 @@ contract SetupPaymentsLibTest is Test, TestConstants, HelloWorldTaskManagerSetup ); } } - - -contract MockRewardsCoordinator is IRewardsCoordinator, TestConstants { - function processClaim(RewardsMerkleClaim calldata claim, address recipient) external override { - // Basic input checks - require(claim.rootIndex < type(uint32).max, "Invalid root index"); - require(claim.earnerIndex < type(uint32).max, "Invalid earner index"); - require(claim.earnerTreeProof.length > 0, "Empty earner tree proof"); - require(claim.earnerLeaf.earner == EARNER, "Invalid earner address"); - require(recipient == RECIPIENT, "Invalid recipient address"); - require(claim.tokenIndices.length == claim.tokenTreeProofs.length, "Mismatched token proofs"); - require(claim.tokenIndices.length == claim.tokenLeaves.length, "Mismatched token leaves"); - require(recipient != address(0), "Invalid recipient address"); - } - - function createAVSRewardsSubmission(RewardsSubmission[] calldata submissions) external override { - require(submissions.length > 0, "Empty submissions array"); - - for (uint256 i = 0; i < submissions.length; i++) { - RewardsSubmission memory submission = submissions[i]; - - require(submission.strategiesAndMultipliers.length > 0, "Empty strategies array"); - require(submission.token != IERC20(address(0)), "Invalid token address"); - require(submission.amount > 0, "Invalid amount"); - require(submission.startTimestamp >= block.timestamp, "Invalid start timestamp"); - require(submission.duration > 0, "Invalid duration"); - - uint256 totalMultiplier = 0; - for (uint256 j = 0; j < submission.strategiesAndMultipliers.length; j++) { - require(address(submission.strategiesAndMultipliers[j].strategy) != address(0), "Invalid strategy address"); - require(submission.strategiesAndMultipliers[j].multiplier > 0, "Invalid multiplier"); - totalMultiplier += submission.strategiesAndMultipliers[j].multiplier; - } - require(totalMultiplier == 10000, "Total multiplier must be 10000"); - } - - // If all checks pass, emit an event to simulate successful submission - emit AVSRewardsSubmissionCreated(msg.sender, submissions.length); - } - - // Event to simulate successful submission - event AVSRewardsSubmissionCreated(address submitter, uint256 submissionCount); - - function rewardsUpdater() external view returns (address){} - - function CALCULATION_INTERVAL_SECONDS() external view returns (uint32){} - - function MAX_REWARDS_DURATION() external view returns (uint32){} - - function MAX_RETROACTIVE_LENGTH() external view returns (uint32){} - - function MAX_FUTURE_LENGTH() external view returns (uint32){} - - function GENESIS_REWARDS_TIMESTAMP() external view returns (uint32){} - - function activationDelay() external view returns (uint32){} - - function claimerFor(address earner) external view returns (address){} - - function cumulativeClaimed(address claimer, IERC20 token) external view returns (uint256){} - - function globalOperatorCommissionBips() external view returns (uint16){} - - function operatorCommissionBips(address operator, address avs) external view returns (uint16){} - - function calculateEarnerLeafHash(EarnerTreeMerkleLeaf calldata leaf) external pure returns (bytes32){} - - function calculateTokenLeafHash(TokenTreeMerkleLeaf calldata leaf) external pure returns (bytes32){ - return keccak256(abi.encodePacked(leaf.cumulativeEarnings)); - } - - function checkClaim(RewardsMerkleClaim calldata claim) external view returns (bool){} - - function currRewardsCalculationEndTimestamp() external view returns (uint32){} - - function getDistributionRootsLength() external view returns (uint256){} - - function getDistributionRootAtIndex(uint256 index) external view returns (DistributionRoot memory){} - - function getCurrentDistributionRoot() external view returns (DistributionRoot memory){} - - function getCurrentClaimableDistributionRoot() external view returns (DistributionRoot memory){} - - function getRootIndexFromHash(bytes32 rootHash) external view returns (uint32){} - - - function disableRoot(uint32 rootIndex) external{} - - - function setClaimerFor(address claimer) external{} - - function setActivationDelay(uint32 _activationDelay) external{} - - function setGlobalOperatorCommission(uint16 _globalCommissionBips) external{} - - function setRewardsUpdater(address _rewardsUpdater) external{} - - function setRewardsForAllSubmitter(address _submitter, bool _newValue) external{} - - function createRewardsForAllSubmission(RewardsSubmission[] calldata rewardsSubmission) external{} - - function submitRoot(bytes32 root, uint32 rewardsCalculationEndTimestamp) external{} -} - - -contract MockStrategy is IStrategy { - - IERC20 public token; - - constructor(IERC20 _token) { - token = _token; - } - - function deposit(IERC20 token, uint256 amount) external returns (uint256){} - - function withdraw(address recipient, IERC20 token, uint256 amountShares) external{} - - function sharesToUnderlying(uint256 amountShares) external returns (uint256){} - - function underlyingToShares(uint256 amountUnderlying) external returns (uint256){} - - function userUnderlying(address user) external returns (uint256){} - - function shares(address user) external view returns (uint256){} - - function sharesToUnderlyingView(uint256 amountShares) external view returns (uint256){} - - function underlyingToSharesView(uint256 amountUnderlying) external view returns (uint256){} - - function userUnderlyingView(address user) external view returns (uint256){} - - function underlyingToken() external view returns (IERC20){ - return token; - } - - function totalShares() external view returns (uint256){} - - function explanation() external view returns (string memory){} -} - diff --git a/contracts/test/mockData/scratch/payment_leaves.json b/contracts/test/mockData/scratch/payment_leaves.json deleted file mode 100644 index 5434bec5..00000000 --- a/contracts/test/mockData/scratch/payment_leaves.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "leaves": [ - "0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef", - "0x2345678901bcdef2345678901bcdef2345678901bcdef2345678901bcdef2345", - "0x3456789012cdef3456789012cdef3456789012cdef3456789012cdef3456789", - "0x4567890123def4567890123def4567890123def4567890123def4567890123d" - ], - "tokenLeaves": [ - "0xabcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890", - "0xbcdef2345678901bcdef2345678901bcdef2345678901bcdef2345678901bcde", - "0xcdef3456789012cdef3456789012cdef3456789012cdef3456789012cdef345", - "0xdef4567890123def4567890123def4567890123def4567890123def4567890" - ] - } \ No newline at end of file diff --git a/contracts/test/mockData/scratch/payments.json b/contracts/test/mockData/scratch/payments.json new file mode 100644 index 00000000..77873afa --- /dev/null +++ b/contracts/test/mockData/scratch/payments.json @@ -0,0 +1,11 @@ +{ + "leaves": [ + "0x29036a1d92861ffd464a1e285030fad3978a36f953ae33c160e606d2ac746c42", + "0x29036a1d92861ffd464a1e285030fad3978a36f953ae33c160e606d2ac746c42", + "0x29036a1d92861ffd464a1e285030fad3978a36f953ae33c160e606d2ac746c42", + "0x29036a1d92861ffd464a1e285030fad3978a36f953ae33c160e606d2ac746c42" + ], + "tokenLeaves": [ + "0xf5d87050cb923194fe63c7ed2c45cbc913fa6ecf322f3631149c36d9460b3ad6" + ] +} \ No newline at end of file