From 07f6a55860c345fe902a77dbe0e6818f361779b6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1s=20Migone?= Date: Mon, 26 Aug 2024 17:59:39 -0300 Subject: [PATCH 01/24] test: wip refactor unit tests for staking fns MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Tomás Migone --- packages/horizon/test/GraphBase.t.sol | 4 - .../test/data-service/DataService.t.sol | 21 ++- .../HorizonStakingShared.t.sol | 165 ++++++++++++++++-- .../horizon/test/staking/HorizonStaking.t.sol | 18 -- .../test/staking/allocation/close.t.sol | 8 +- .../test/staking/allocation/collect.t.sol | 4 +- .../test/staking/delegation/delegate.t.sol | 2 +- .../test/staking/delegation/undelegate.t.sol | 2 +- .../test/staking/delegation/withdraw.t.sol | 11 +- .../test/staking/provision/reprovision.t.sol | 8 +- .../horizon/test/staking/stake/stake.t.sol | 10 +- .../horizon/test/staking/stake/unstake.t.sol | 54 +----- .../horizon/test/staking/stake/withdraw.t.sol | 6 +- .../test/staking/transfer-tools/ttools.t.sol | 8 +- 14 files changed, 193 insertions(+), 128 deletions(-) diff --git a/packages/horizon/test/GraphBase.t.sol b/packages/horizon/test/GraphBase.t.sol index 6236d00dd..d9323f56b 100644 --- a/packages/horizon/test/GraphBase.t.sol +++ b/packages/horizon/test/GraphBase.t.sol @@ -54,10 +54,6 @@ abstract contract GraphBaseTest is Utils, Constants { Users internal users; - /* Constants */ - - Constants public constants; - /* * SET UP */ diff --git a/packages/horizon/test/data-service/DataService.t.sol b/packages/horizon/test/data-service/DataService.t.sol index 98f7aadb3..a178bef12 100644 --- a/packages/horizon/test/data-service/DataService.t.sol +++ b/packages/horizon/test/data-service/DataService.t.sol @@ -69,7 +69,7 @@ contract DataServiceTest is HorizonStakingSharedTest { dataService.setProvisionTokensRange(dataService.PROVISION_TOKENS_MIN(), dataService.PROVISION_TOKENS_MAX()); tokens = bound(tokens, dataService.PROVISION_TOKENS_MIN(), dataService.PROVISION_TOKENS_MAX()); - _createProvision(address(dataService), tokens, 0, 0); + _createProvision(users.indexer, address(dataService), tokens, 0, 0); dataService.checkProvisionTokens(users.indexer); } @@ -81,7 +81,7 @@ contract DataServiceTest is HorizonStakingSharedTest { ); // this checker accepts provisions with any amount of tokens - _createProvision(address(dataServiceOverride), tokens, 0, 0); + _createProvision(users.indexer, address(dataServiceOverride), tokens, 0, 0); dataServiceOverride.checkProvisionTokens(users.indexer); } @@ -89,7 +89,7 @@ contract DataServiceTest is HorizonStakingSharedTest { dataService.setProvisionTokensRange(dataService.PROVISION_TOKENS_MIN(), dataService.PROVISION_TOKENS_MAX()); tokens = bound(tokens, 1, dataService.PROVISION_TOKENS_MIN() - 1); - _createProvision(address(dataService), tokens, 0, 0); + _createProvision(users.indexer, address(dataService), tokens, 0, 0); vm.expectRevert( abi.encodeWithSelector( ProvisionManager.ProvisionManagerInvalidValue.selector, @@ -142,7 +142,7 @@ contract DataServiceTest is HorizonStakingSharedTest { dataService.setVerifierCutRange(dataService.VERIFIER_CUT_MIN(), dataService.VERIFIER_CUT_MAX()); verifierCut = uint32(bound(verifierCut, dataService.VERIFIER_CUT_MIN(), dataService.VERIFIER_CUT_MAX())); - _createProvision(address(dataService), dataService.PROVISION_TOKENS_MIN(), verifierCut, 0); + _createProvision(users.indexer, address(dataService), dataService.PROVISION_TOKENS_MIN(), verifierCut, 0); dataService.checkProvisionParameters(users.indexer, false); } @@ -151,7 +151,7 @@ contract DataServiceTest is HorizonStakingSharedTest { dataServiceOverride.setVerifierCutRange(dataService.VERIFIER_CUT_MIN(), dataService.VERIFIER_CUT_MAX()); // this checker accepts provisions with any verifier cut range - _createProvision(address(dataService), dataService.PROVISION_TOKENS_MIN(), verifierCut, 0); + _createProvision(users.indexer, address(dataService), dataService.PROVISION_TOKENS_MIN(), verifierCut, 0); dataServiceOverride.checkProvisionParameters(users.indexer, false); } @@ -159,7 +159,7 @@ contract DataServiceTest is HorizonStakingSharedTest { dataService.setVerifierCutRange(dataService.VERIFIER_CUT_MIN(), dataService.VERIFIER_CUT_MAX()); verifierCut = uint32(bound(verifierCut, 0, dataService.VERIFIER_CUT_MIN() - 1)); - _createProvision(address(dataService), dataService.PROVISION_TOKENS_MIN(), verifierCut, 0); + _createProvision(users.indexer, address(dataService), dataService.PROVISION_TOKENS_MIN(), verifierCut, 0); vm.expectRevert( abi.encodeWithSelector( ProvisionManager.ProvisionManagerInvalidValue.selector, @@ -205,7 +205,7 @@ contract DataServiceTest is HorizonStakingSharedTest { bound(thawingPeriod, dataService.THAWING_PERIOD_MIN(), dataService.THAWING_PERIOD_MAX()) ); - _createProvision(address(dataService), dataService.PROVISION_TOKENS_MIN(), 0, thawingPeriod); + _createProvision(users.indexer, address(dataService), dataService.PROVISION_TOKENS_MIN(), 0, thawingPeriod); dataService.checkProvisionParameters(users.indexer, false); } @@ -214,7 +214,7 @@ contract DataServiceTest is HorizonStakingSharedTest { dataServiceOverride.setThawingPeriodRange(dataService.THAWING_PERIOD_MIN(), dataService.THAWING_PERIOD_MAX()); // this checker accepts provisions with any verifier cut range - _createProvision(address(dataService), dataService.PROVISION_TOKENS_MIN(), 0, thawingPeriod); + _createProvision(users.indexer, address(dataService), dataService.PROVISION_TOKENS_MIN(), 0, thawingPeriod); dataServiceOverride.checkProvisionParameters(users.indexer, false); } @@ -222,7 +222,7 @@ contract DataServiceTest is HorizonStakingSharedTest { dataService.setThawingPeriodRange(dataService.THAWING_PERIOD_MIN(), dataService.THAWING_PERIOD_MAX()); thawingPeriod = uint32(bound(thawingPeriod, 0, dataService.THAWING_PERIOD_MIN() - 1)); - _createProvision(address(dataService), dataService.PROVISION_TOKENS_MIN(), 0, thawingPeriod); + _createProvision(users.indexer, address(dataService), dataService.PROVISION_TOKENS_MIN(), 0, thawingPeriod); vm.expectRevert( abi.encodeWithSelector( ProvisionManager.ProvisionManagerInvalidValue.selector, @@ -255,6 +255,7 @@ contract DataServiceTest is HorizonStakingSharedTest { // stage provision parameter changes _createProvision( + users.indexer, address(dataService), dataService.PROVISION_TOKENS_MIN(), dataService.VERIFIER_CUT_MIN(), @@ -287,6 +288,7 @@ contract DataServiceTest is HorizonStakingSharedTest { // stage provision parameter changes _createProvision( + users.indexer, address(dataService), dataService.PROVISION_TOKENS_MIN(), dataService.VERIFIER_CUT_MIN(), @@ -324,6 +326,7 @@ contract DataServiceTest is HorizonStakingSharedTest { // stage provision parameter changes _createProvision( + users.indexer, address(dataService), dataService.PROVISION_TOKENS_MIN(), dataService.VERIFIER_CUT_MIN(), diff --git a/packages/horizon/test/shared/horizon-staking/HorizonStakingShared.t.sol b/packages/horizon/test/shared/horizon-staking/HorizonStakingShared.t.sol index faf7b8039..325ed7d46 100644 --- a/packages/horizon/test/shared/horizon-staking/HorizonStakingShared.t.sol +++ b/packages/horizon/test/shared/horizon-staking/HorizonStakingShared.t.sol @@ -5,6 +5,11 @@ import "forge-std/Test.sol"; import { GraphBaseTest } from "../../GraphBase.t.sol"; import { IGraphPayments } from "../../../contracts/interfaces/IGraphPayments.sol"; +import { IHorizonStaking } from "../../../contracts/interfaces/IHorizonStaking.sol"; +import { IHorizonStakingBase } from "../../../contracts/interfaces/internal/IHorizonStakingBase.sol"; +import { IHorizonStakingMain } from "../../../contracts/interfaces/internal/IHorizonStakingMain.sol"; + +import { MathUtils } from "../../../contracts/libraries/MathUtils.sol"; abstract contract HorizonStakingSharedTest is GraphBaseTest { /* @@ -17,9 +22,9 @@ abstract contract HorizonStakingSharedTest is GraphBaseTest { vm.stopPrank(); } - modifier assumeProvisionTokens(uint256 tokens) { - vm.assume(tokens > 0); - vm.assume(tokens <= MAX_STAKING_TOKENS); + modifier useStake(uint256 amount) { + vm.assume(amount > 0); + _stake(amount); _; } @@ -47,32 +52,27 @@ abstract contract HorizonStakingSharedTest is GraphBaseTest { _; } - /* - * HELPERS - */ - - function _useProvision( - address dataService, - uint256 tokens, - uint32 maxVerifierCut, - uint64 thawingPeriod - ) internal { + function _useProvision(address dataService, uint256 tokens, uint32 maxVerifierCut, uint64 thawingPeriod) internal { vm.assume(tokens <= MAX_STAKING_TOKENS); vm.assume(tokens > 0); vm.assume(maxVerifierCut <= MAX_MAX_VERIFIER_CUT); vm.assume(thawingPeriod <= MAX_THAWING_PERIOD); - _createProvision(dataService, tokens, maxVerifierCut, thawingPeriod); + + _createProvision(users.indexer, dataService, tokens, maxVerifierCut, thawingPeriod); } + /* + * HELPERS: these are shortcuts to perform common actions that often involve multiple contract calls + */ function _createProvision( - address dataServiceAddress, + address serviceProvider, + address verifier, uint256 tokens, uint32 maxVerifierCut, uint64 thawingPeriod ) internal { - token.approve(address(staking), tokens); - staking.stakeTo(users.indexer, tokens); - staking.provision(users.indexer, dataServiceAddress, tokens, maxVerifierCut, thawingPeriod); + _stakeTo(serviceProvider, tokens); + _provision(serviceProvider, verifier, tokens, maxVerifierCut, thawingPeriod); } function _setDelegationFeeCut(IGraphPayments.PaymentTypes paymentType, uint256 cut) internal { @@ -80,4 +80,133 @@ abstract contract HorizonStakingSharedTest is GraphBaseTest { uint256 delegationFeeCut = staking.getDelegationFeeCut(users.indexer, subgraphDataServiceAddress, paymentType); assertEq(delegationFeeCut, cut); } + + /* + * ACTIONS: these are individual contract calls wrapped in assertion blocks to ensure they work as expected + */ + function _stake(uint256 tokens) internal { + (, address msgSender, ) = vm.readCallers(); + _stakeTo(msgSender, tokens); + } + + function _stakeTo(address serviceProvider, uint256 tokens) internal { + (, address msgSender, ) = vm.readCallers(); + + // before + uint256 beforeStakingBalance = token.balanceOf(address(staking)); + uint256 beforeSenderBalance = token.balanceOf(msgSender); + IHorizonStaking.ServiceProvider memory beforeServiceProvider = staking.getServiceProvider(serviceProvider); + + // stakeTo + token.approve(address(staking), tokens); + vm.expectEmit(); + emit IHorizonStakingBase.StakeDeposited(serviceProvider, tokens); + staking.stakeTo(serviceProvider, tokens); + + // after + uint256 afterStakingBalance = token.balanceOf(address(staking)); + uint256 afterSenderBalance = token.balanceOf(msgSender); + IHorizonStaking.ServiceProvider memory afterServiceProvider = staking.getServiceProvider(serviceProvider); + + // assert + assertEq(afterStakingBalance, beforeStakingBalance + tokens); + assertEq(afterSenderBalance, beforeSenderBalance - tokens); + assertEq(afterServiceProvider.tokensStaked, beforeServiceProvider.tokensStaked + tokens); + } + + function _unstake(uint256 _tokens) internal { + (, address msgSender, ) = vm.readCallers(); + + uint256 deprecatedThawingPeriod = uint256(vm.load(address(staking), bytes32(uint256(13)))); + + // before + uint256 beforeSenderBalance = token.balanceOf(msgSender); + uint256 beforeStakingBalance = token.balanceOf(address(staking)); + IHorizonStaking.ServiceProvider memory beforeServiceProvider = staking.getServiceProvider(msgSender); + + // unstake + if (deprecatedThawingPeriod == 0) { + vm.expectEmit(address(staking)); + emit IHorizonStakingMain.StakeWithdrawn(msgSender, _tokens); + staking.unstake(_tokens); + } else { + // TODO + } + + // after + uint256 afterSenderBalance = token.balanceOf(msgSender); + uint256 afterStakingBalance = token.balanceOf(address(staking)); + IHorizonStaking.ServiceProvider memory afterServiceProvider = staking.getServiceProvider(msgSender); + + // assert + if (deprecatedThawingPeriod == 0) { + assertEq(afterSenderBalance - beforeSenderBalance, _tokens); + assertEq(afterStakingBalance, beforeStakingBalance - _tokens); + assertEq(afterServiceProvider.tokensStaked, beforeServiceProvider.tokensStaked - _tokens); + } else { + // TODO + } + } + + function _unstakeDuringLockingPeriod( + uint256 _tokens, + uint256 _tokensStillThawing, + uint256 _tokensToWithdraw, + uint32 _oldLockingPeriod + ) internal { + uint256 previousIndexerTokens = token.balanceOf(users.indexer); + uint256 previousIndexerIdleStake = staking.getIdleStake(users.indexer); + + vm.expectEmit(address(staking)); + uint256 lockingPeriod = block.number + THAWING_PERIOD_IN_BLOCKS; + if (_tokensStillThawing > 0) { + lockingPeriod = + block.number + + MathUtils.weightedAverageRoundingUp( + MathUtils.diffOrZero(_oldLockingPeriod, block.number), + _tokensStillThawing, + THAWING_PERIOD_IN_BLOCKS, + _tokens + ); + } + emit IHorizonStakingMain.StakeLocked(users.indexer, _tokens + _tokensStillThawing, lockingPeriod); + staking.unstake(_tokens); + + uint256 idleStake = staking.getIdleStake(users.indexer); + assertEq(idleStake, previousIndexerIdleStake - _tokens); + + uint256 newIndexerBalance = token.balanceOf(users.indexer); + assertEq(newIndexerBalance - previousIndexerTokens, _tokensToWithdraw); + } + + function _provision( + address serviceProvider, + address verifier, + uint256 tokens, + uint32 maxVerifierCut, + uint64 thawingPeriod + ) internal { + // before + IHorizonStaking.ServiceProvider memory beforeServiceProvider = staking.getServiceProvider(serviceProvider); + + // provision + vm.expectEmit(); + emit IHorizonStakingMain.ProvisionCreated(serviceProvider, verifier, tokens, maxVerifierCut, thawingPeriod); + staking.provision(serviceProvider, verifier, tokens, maxVerifierCut, thawingPeriod); + + // after + IHorizonStaking.Provision memory afterProvision = staking.getProvision(serviceProvider, verifier); + IHorizonStaking.ServiceProvider memory afterServiceProvider = staking.getServiceProvider(serviceProvider); + + // assert + assertEq(afterProvision.tokens, tokens); + assertEq(afterProvision.tokensThawing, 0); + assertEq(afterProvision.sharesThawing, 0); + assertEq(afterProvision.maxVerifierCut, maxVerifierCut); + assertEq(afterProvision.thawingPeriod, thawingPeriod); + assertEq(afterProvision.createdAt, uint64(block.timestamp)); + assertEq(afterProvision.maxVerifierCutPending, maxVerifierCut); + assertEq(afterProvision.thawingPeriodPending, thawingPeriod); + assertEq(afterServiceProvider.tokensProvisioned, tokens + beforeServiceProvider.tokensProvisioned); + } } diff --git a/packages/horizon/test/staking/HorizonStaking.t.sol b/packages/horizon/test/staking/HorizonStaking.t.sol index 1973f8581..70a123cfc 100644 --- a/packages/horizon/test/staking/HorizonStaking.t.sol +++ b/packages/horizon/test/staking/HorizonStaking.t.sol @@ -33,19 +33,6 @@ contract HorizonStakingTest is HorizonStakingSharedTest, IHorizonStakingTypes { vm.stopPrank(); } - modifier useStake(uint256 amount) { - vm.assume(amount > 0); - approve(address(staking), amount); - staking.stake(amount); - _; - } - - modifier useStakeTo(address to, uint256 amount) { - vm.assume(amount > 0); - _stakeTo(to, amount); - _; - } - modifier useThawRequest(uint256 thawAmount) { vm.assume(thawAmount > 0); _createThawRequest(thawAmount); @@ -93,11 +80,6 @@ contract HorizonStakingTest is HorizonStakingSharedTest, IHorizonStakingTypes { * HELPERS */ - function _stakeTo(address to, uint256 amount) internal { - approve(address(staking), amount); - staking.stakeTo(to, amount); - } - function _createThawRequest(uint256 thawAmount) internal returns (bytes32) { return staking.thaw(users.indexer, subgraphDataServiceAddress, thawAmount); } diff --git a/packages/horizon/test/staking/allocation/close.t.sol b/packages/horizon/test/staking/allocation/close.t.sol index c7c2aff68..0a6c3fa7c 100644 --- a/packages/horizon/test/staking/allocation/close.t.sol +++ b/packages/horizon/test/staking/allocation/close.t.sol @@ -18,7 +18,7 @@ contract HorizonStakingCloseAllocationTest is HorizonStakingExtensionTest { tokens = bound(tokens, 1, MAX_STAKING_TOKENS); _storeAllocation(tokens); _storeMaxAllocationEpochs(); - _createProvision(subgraphDataServiceLegacyAddress, tokens, 0, 0); + _createProvision(users.indexer, subgraphDataServiceLegacyAddress, tokens, 0, 0); // Skip 15 epochs vm.roll(15); @@ -35,7 +35,7 @@ contract HorizonStakingCloseAllocationTest is HorizonStakingExtensionTest { tokens = bound(tokens, 1, MAX_STAKING_TOKENS); _storeAllocation(tokens); _storeMaxAllocationEpochs(); - _createProvision(subgraphDataServiceLegacyAddress, tokens, 0, 0); + _createProvision(users.indexer, subgraphDataServiceLegacyAddress, tokens, 0, 0); address beneficiary = makeAddr("beneficiary"); _storeRewardsDestination(beneficiary); @@ -66,7 +66,7 @@ contract HorizonStakingCloseAllocationTest is HorizonStakingExtensionTest { tokens = bound(tokens, 1, MAX_STAKING_TOKENS); _storeAllocation(tokens); _storeMaxAllocationEpochs(); - _createProvision(subgraphDataServiceLegacyAddress, tokens, 0, 0); + _createProvision(users.indexer, subgraphDataServiceLegacyAddress, tokens, 0, 0); // Skip to over the max allocation epochs vm.roll(MAX_ALLOCATION_EPOCHS + 2); @@ -102,7 +102,7 @@ contract HorizonStakingCloseAllocationTest is HorizonStakingExtensionTest { _storeAllocation(legacyAllocationTokens); _storeMaxAllocationEpochs(); - _createProvision(subgraphDataServiceLegacyAddress, provisionTokens, 0, 0); + _createProvision(users.indexer, subgraphDataServiceLegacyAddress, provisionTokens, 0, 0); _storeDelegationPool(delegationTokens, indexingRewardCut, 0); // Skip 15 epochs diff --git a/packages/horizon/test/staking/allocation/collect.t.sol b/packages/horizon/test/staking/allocation/collect.t.sol index 3ea230a8b..39b7609d6 100644 --- a/packages/horizon/test/staking/allocation/collect.t.sol +++ b/packages/horizon/test/staking/allocation/collect.t.sol @@ -106,7 +106,7 @@ contract HorizonStakingCollectAllocationTest is HorizonStakingExtensionTest { _storeAllocation(allocationTokens); _storeProtocolTaxAndCuration(curationPercentage, protocolTaxPercentage); _storeDelegationPool(delegationTokens, 0, queryFeeCut); - _createProvision(subgraphDataServiceLegacyAddress, provisionTokens, 0, 0); + _createProvision(users.indexer, subgraphDataServiceLegacyAddress, provisionTokens, 0, 0); curation.signal(_subgraphDeploymentID, curationTokens); resetPrank(users.gateway); @@ -153,7 +153,7 @@ contract HorizonStakingCollectAllocationTest is HorizonStakingExtensionTest { allocationTokens = bound(allocationTokens, 0, MAX_STAKING_TOKENS); collectTokens = bound(collectTokens, 0, MAX_STAKING_TOKENS); - _createProvision(subgraphDataServiceLegacyAddress, provisionTokens, 0, 0); + _createProvision(users.indexer, subgraphDataServiceLegacyAddress, provisionTokens, 0, 0); _storeAllocation(allocationTokens); address beneficiary = makeAddr("beneficiary"); diff --git a/packages/horizon/test/staking/delegation/delegate.t.sol b/packages/horizon/test/staking/delegation/delegate.t.sol index 87416daf5..b64afa25a 100644 --- a/packages/horizon/test/staking/delegation/delegate.t.sol +++ b/packages/horizon/test/staking/delegation/delegate.t.sol @@ -78,7 +78,7 @@ contract HorizonStakingDelegateTest is HorizonStakingTest { function testDelegate_LegacySubgraphService(uint256 amount, uint256 delegationAmount) public useIndexer { amount = bound(amount, 1 ether, MAX_STAKING_TOKENS); delegationAmount = bound(delegationAmount, MIN_DELEGATION, MAX_STAKING_TOKENS); - _createProvision(subgraphDataServiceLegacyAddress, amount, 0, 0); + _createProvision(users.indexer, subgraphDataServiceLegacyAddress, amount, 0, 0); resetPrank(users.delegator); _delegateLegacy(users.indexer, delegationAmount); diff --git a/packages/horizon/test/staking/delegation/undelegate.t.sol b/packages/horizon/test/staking/delegation/undelegate.t.sol index d256d8502..1f62338b9 100644 --- a/packages/horizon/test/staking/delegation/undelegate.t.sol +++ b/packages/horizon/test/staking/delegation/undelegate.t.sol @@ -104,7 +104,7 @@ contract HorizonStakingUndelegateTest is HorizonStakingTest { function testUndelegate_LegacySubgraphService(uint256 amount, uint256 delegationAmount) public useIndexer { amount = bound(amount, 1, MAX_STAKING_TOKENS); delegationAmount = bound(delegationAmount, MIN_DELEGATION, MAX_STAKING_TOKENS); - _createProvision(subgraphDataServiceLegacyAddress, amount, 0, 0); + _createProvision(users.indexer, subgraphDataServiceLegacyAddress, amount, 0, 0); resetPrank(users.delegator); _delegateLegacy(users.indexer, delegationAmount); diff --git a/packages/horizon/test/staking/delegation/withdraw.t.sol b/packages/horizon/test/staking/delegation/withdraw.t.sol index 7eb6db57e..41b49fbb0 100644 --- a/packages/horizon/test/staking/delegation/withdraw.t.sol +++ b/packages/horizon/test/staking/delegation/withdraw.t.sol @@ -59,13 +59,12 @@ contract HorizonStakingWithdrawDelegationTest is HorizonStakingTest { } function _setupNewIndexer(uint256 tokens) private returns(address) { - address msgSender; - (, msgSender,) = vm.readCallers(); + (, address msgSender,) = vm.readCallers(); + address newIndexer = createUser("newIndexer"); vm.startPrank(newIndexer); - token.approve(address(staking), tokens); - staking.stakeTo(newIndexer, tokens); - staking.provision(newIndexer,subgraphDataServiceAddress, tokens, 0, MAX_THAWING_PERIOD); + _createProvision(newIndexer, subgraphDataServiceAddress, tokens, 0, MAX_THAWING_PERIOD); + vm.startPrank(msgSender); return newIndexer; } @@ -162,7 +161,7 @@ contract HorizonStakingWithdrawDelegationTest is HorizonStakingTest { function testWithdrawDelegation_LegacySubgraphService(uint256 delegationAmount) public useIndexer { delegationAmount = bound(delegationAmount, MIN_DELEGATION, MAX_STAKING_TOKENS); - _createProvision(subgraphDataServiceLegacyAddress, 10_000_000 ether, 0, MAX_THAWING_PERIOD); + _createProvision(users.indexer, subgraphDataServiceLegacyAddress, 10_000_000 ether, 0, MAX_THAWING_PERIOD); resetPrank(users.delegator); _delegateLegacy(users.indexer, delegationAmount); diff --git a/packages/horizon/test/staking/provision/reprovision.t.sol b/packages/horizon/test/staking/provision/reprovision.t.sol index 5d7ed8068..51cd154c9 100644 --- a/packages/horizon/test/staking/provision/reprovision.t.sol +++ b/packages/horizon/test/staking/provision/reprovision.t.sol @@ -36,7 +36,7 @@ contract HorizonStakingReprovisionTest is HorizonStakingTest { { skip(thawingPeriod + 1); - _createProvision(newDataService, 1 ether, 0, thawingPeriod); + _createProvision(users.indexer, newDataService, 1 ether, 0, thawingPeriod); // nThawRequests == 0 reprovisions all thaw requests _reprovision(provisionAmount, 0); @@ -64,7 +64,7 @@ contract HorizonStakingReprovisionTest is HorizonStakingTest { // Switch back to operator vm.startPrank(users.operator); - _createProvision(newDataService, 1 ether, 0, thawingPeriod); + _createProvision(users.indexer, newDataService, 1 ether, 0, thawingPeriod); _reprovision(provisionAmount, 0); uint256 idleStake = staking.getIdleStake(users.indexer); assertEq(idleStake, 0 ether); @@ -83,7 +83,7 @@ contract HorizonStakingReprovisionTest is HorizonStakingTest { { // Switch to indexer to create new provision vm.startPrank(users.indexer); - _createProvision(newDataService, 1 ether, 0, 0); + _createProvision(users.indexer, newDataService, 1 ether, 0, 0); // Switch back to operator vm.startPrank(users.operator); @@ -116,7 +116,7 @@ contract HorizonStakingReprovisionTest is HorizonStakingTest { { vm.assume(thawingPeriod > 0); - _createProvision(newDataService, 1 ether, 0, thawingPeriod); + _createProvision(users.indexer, newDataService, 1 ether, 0, thawingPeriod); bytes memory expectedError = abi.encodeWithSignature( "HorizonStakingInsufficientIdleStake(uint256,uint256)", diff --git a/packages/horizon/test/staking/stake/stake.t.sol b/packages/horizon/test/staking/stake/stake.t.sol index 9c1c69ad9..030d516a3 100644 --- a/packages/horizon/test/staking/stake/stake.t.sol +++ b/packages/horizon/test/staking/stake/stake.t.sol @@ -11,8 +11,9 @@ contract HorizonStakingStakeTest is HorizonStakingTest { * TESTS */ - function testStake_Tokens(uint256 amount) public useIndexer useStake(amount) { - assertTrue(staking.getStake(address(users.indexer)) == amount); + function testStake_Tokens(uint256 amount) public useIndexer { + amount = bound(amount, 1, MAX_STAKING_TOKENS); + _stake(amount); } function testStake_RevertWhen_ZeroTokens() public useIndexer { @@ -21,8 +22,9 @@ contract HorizonStakingStakeTest is HorizonStakingTest { staking.stake(0); } - function testStakeTo_Tokens(uint256 amount) public useOperator useStakeTo(users.indexer, amount) { - assertTrue(staking.getStake(address(users.indexer)) == amount); + function testStakeTo_Tokens(uint256 amount) public useOperator { + amount = bound(amount, 1, MAX_STAKING_TOKENS); + _stakeTo(users.indexer, amount); } function testStakeTo_RevertWhen_ZeroTokens() public useOperator { diff --git a/packages/horizon/test/staking/stake/unstake.t.sol b/packages/horizon/test/staking/stake/unstake.t.sol index c5d44a3fb..724037c87 100644 --- a/packages/horizon/test/staking/stake/unstake.t.sol +++ b/packages/horizon/test/staking/stake/unstake.t.sol @@ -3,57 +3,10 @@ pragma solidity 0.8.26; import "forge-std/Test.sol"; -import { IHorizonStakingMain } from "../../../contracts/interfaces/internal/IHorizonStakingMain.sol"; -import { MathUtils } from "../../../contracts/libraries/MathUtils.sol"; - import { HorizonStakingTest } from "../HorizonStaking.t.sol"; contract HorizonStakingUnstakeTest is HorizonStakingTest { - function _unstakeTokens(uint256 _tokens) private { - uint256 previousIndexerTokens = token.balanceOf(users.indexer); - uint256 previousIndexerIdleStake = staking.getIdleStake(users.indexer); - - vm.expectEmit(address(staking)); - emit IHorizonStakingMain.StakeWithdrawn(users.indexer, _tokens); - staking.unstake(_tokens); - - uint256 idleStake = staking.getIdleStake(users.indexer); - assertEq(idleStake, previousIndexerIdleStake - _tokens); - - uint256 newIndexerBalance = token.balanceOf(users.indexer); - assertEq(newIndexerBalance - previousIndexerTokens, _tokens); - } - - function _unstakeDuringLockingPeriod( - uint256 _tokens, - uint256 _tokensStillThawing, - uint256 _tokensToWithdraw, - uint32 _oldLockingPeriod - ) private { - uint256 previousIndexerTokens = token.balanceOf(users.indexer); - uint256 previousIndexerIdleStake = staking.getIdleStake(users.indexer); - - vm.expectEmit(address(staking)); - uint256 lockingPeriod = block.number + THAWING_PERIOD_IN_BLOCKS; - if (_tokensStillThawing > 0) { - lockingPeriod = block.number + MathUtils.weightedAverageRoundingUp( - MathUtils.diffOrZero(_oldLockingPeriod, block.number), - _tokensStillThawing, - THAWING_PERIOD_IN_BLOCKS, - _tokens - ); - } - emit IHorizonStakingMain.StakeLocked(users.indexer, _tokens + _tokensStillThawing, lockingPeriod); - staking.unstake(_tokens); - - uint256 idleStake = staking.getIdleStake(users.indexer); - assertEq(idleStake, previousIndexerIdleStake - _tokens); - - uint256 newIndexerBalance = token.balanceOf(users.indexer); - assertEq(newIndexerBalance - previousIndexerTokens, _tokensToWithdraw); - } - function _storeDeprecatedThawingPeriod(uint32 _thawingPeriod) private { uint256 slot = 13; bytes32 value = bytes32(uint256(_thawingPeriod)); @@ -75,10 +28,11 @@ contract HorizonStakingUnstakeTest is HorizonStakingTest { useProvision(tokens, maxVerifierCut, thawingPeriod) { tokensToUnstake = bound(tokensToUnstake, 1, tokens); + _createThawRequest(tokens); skip(thawingPeriod + 1); _deprovision(0); - _unstakeTokens(tokensToUnstake); + _unstake(tokensToUnstake); } function testUnstake_LockingPeriodGreaterThanZero_TokensDoneThawing( @@ -100,7 +54,7 @@ contract HorizonStakingUnstakeTest is HorizonStakingTest { _storeServiceProvider(users.indexer, tokensLocked, 0, tokensLocked, block.number, 0); // create provision, thaw request and deprovision - _createProvision(subgraphDataServiceAddress, tokens, 0, MAX_THAWING_PERIOD); + _createProvision(users.indexer, subgraphDataServiceAddress, tokens, 0, MAX_THAWING_PERIOD); _createThawRequest(tokens); skip(MAX_THAWING_PERIOD + 1); _deprovision(0); @@ -131,7 +85,7 @@ contract HorizonStakingUnstakeTest is HorizonStakingTest { _storeServiceProvider(users.indexer, tokensThawing, 0, tokensThawing, tokensThawingUntilBlock, 0); // create provision, thaw request and deprovision - _createProvision(subgraphDataServiceAddress, tokens, 0, MAX_THAWING_PERIOD); + _createProvision(users.indexer, subgraphDataServiceAddress, tokens, 0, MAX_THAWING_PERIOD); _createThawRequest(tokens); skip(MAX_THAWING_PERIOD + 1); _deprovision(0); diff --git a/packages/horizon/test/staking/stake/withdraw.t.sol b/packages/horizon/test/staking/stake/withdraw.t.sol index 73a96b542..2bb5b16be 100644 --- a/packages/horizon/test/staking/stake/withdraw.t.sol +++ b/packages/horizon/test/staking/stake/withdraw.t.sol @@ -29,14 +29,14 @@ contract HorizonStakingWithdrawTest is HorizonStakingTest { function testWithdraw_Tokens(uint256 tokens, uint256 tokensLocked) public useIndexer { vm.assume(tokens > 0); tokensLocked = bound(tokensLocked, 1, tokens); - _createProvision(subgraphDataServiceLegacyAddress, tokens, 0, MAX_THAWING_PERIOD); + _createProvision(users.indexer, subgraphDataServiceLegacyAddress, tokens, 0, MAX_THAWING_PERIOD); _storeServiceProvider(users.indexer, tokens, 0, tokensLocked, block.timestamp, 0); _withdrawLockedTokens(tokensLocked); } function testWithdraw_RevertWhen_ZeroTokens(uint256 tokens) public useIndexer { vm.assume(tokens > 0); - _createProvision(subgraphDataServiceLegacyAddress, tokens, 0, MAX_THAWING_PERIOD); + _createProvision(users.indexer, subgraphDataServiceLegacyAddress, tokens, 0, MAX_THAWING_PERIOD); _storeServiceProvider(users.indexer, tokens, 0, 0, block.timestamp, 0); vm.expectRevert(abi.encodeWithSelector( IHorizonStakingMain.HorizonStakingInvalidZeroTokens.selector @@ -47,7 +47,7 @@ contract HorizonStakingWithdrawTest is HorizonStakingTest { function testWithdraw_RevertWhen_StillThawing(uint256 tokens, uint256 tokensLocked) public useIndexer { vm.assume(tokens > 0); tokensLocked = bound(tokensLocked, 1, tokens); - _createProvision(subgraphDataServiceLegacyAddress, tokens, 0, MAX_THAWING_PERIOD); + _createProvision(users.indexer, subgraphDataServiceLegacyAddress, tokens, 0, MAX_THAWING_PERIOD); uint256 thawUntil = block.timestamp + 1; _storeServiceProvider(users.indexer, tokens, 0, tokensLocked, thawUntil, 0); vm.expectRevert(abi.encodeWithSelector( diff --git a/packages/horizon/test/staking/transfer-tools/ttools.t.sol b/packages/horizon/test/staking/transfer-tools/ttools.t.sol index c41731e10..114e7f8ba 100644 --- a/packages/horizon/test/staking/transfer-tools/ttools.t.sol +++ b/packages/horizon/test/staking/transfer-tools/ttools.t.sol @@ -69,7 +69,7 @@ contract HorizonStakingTransferToolsTest is HorizonStakingTest { // create provision and legacy delegation pool - this is done by the bridge when indexers move to L2 resetPrank(users.indexer); - _createProvision(subgraphDataServiceLegacyAddress, 100 ether, 0, 0); + _createProvision(users.indexer, subgraphDataServiceLegacyAddress, 100 ether, 0, 0); resetPrank(users.delegator); _delegateLegacy(users.indexer, 1 ether); @@ -92,7 +92,7 @@ contract HorizonStakingTransferToolsTest is HorizonStakingTest { // create provision and legacy delegation pool - this is done by the bridge when indexers move to L2 resetPrank(users.indexer); - _createProvision(subgraphDataServiceLegacyAddress, 100 ether, 0, 1 days); + _createProvision(users.indexer, subgraphDataServiceLegacyAddress, 100 ether, 0, 1 days); resetPrank(users.delegator); _delegateLegacy(users.indexer, originalDelegationAmount); @@ -120,7 +120,7 @@ contract HorizonStakingTransferToolsTest is HorizonStakingTest { // create provision and legacy delegation pool - this is done by the bridge when indexers move to L2 resetPrank(users.indexer); - _createProvision(subgraphDataServiceLegacyAddress, provisionSize, 0, 1 days); + _createProvision(users.indexer, subgraphDataServiceLegacyAddress, provisionSize, 0, 1 days); // initialize the delegation pool resetPrank(users.delegator); @@ -147,7 +147,7 @@ contract HorizonStakingTransferToolsTest is HorizonStakingTest { // create provision and legacy delegation pool - this is done by the bridge when indexers move to L2 resetPrank(users.indexer); - _createProvision(subgraphDataServiceLegacyAddress, 100 ether, 0, 1 days); + _createProvision(users.indexer, subgraphDataServiceLegacyAddress, 100 ether, 0, 1 days); resetPrank(users.delegator); _delegateLegacy(users.indexer, amountDelegated); From 6577ebdc91f4897098f4d57ab725c4251ece2bf6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1s=20Migone?= Date: Tue, 27 Aug 2024 16:16:13 -0300 Subject: [PATCH 02/24] test: refactor unstake tests passing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Tomás Migone --- .../HorizonStakingShared.t.sol | 167 +++++++++++++----- .../horizon/test/staking/HorizonStaking.t.sol | 12 +- .../test/staking/provision/deprovision.t.sol | 4 +- .../serviceProvider/serviceProvider.t.sol | 4 +- .../horizon/test/staking/stake/unstake.t.sol | 78 ++++---- packages/horizon/test/staking/thaw/thaw.t.sol | 18 +- 6 files changed, 178 insertions(+), 105 deletions(-) diff --git a/packages/horizon/test/shared/horizon-staking/HorizonStakingShared.t.sol b/packages/horizon/test/shared/horizon-staking/HorizonStakingShared.t.sol index 325ed7d46..e6397fadf 100644 --- a/packages/horizon/test/shared/horizon-staking/HorizonStakingShared.t.sol +++ b/packages/horizon/test/shared/horizon-staking/HorizonStakingShared.t.sol @@ -8,6 +8,7 @@ import { IGraphPayments } from "../../../contracts/interfaces/IGraphPayments.sol import { IHorizonStaking } from "../../../contracts/interfaces/IHorizonStaking.sol"; import { IHorizonStakingBase } from "../../../contracts/interfaces/internal/IHorizonStakingBase.sol"; import { IHorizonStakingMain } from "../../../contracts/interfaces/internal/IHorizonStakingMain.sol"; +import { IHorizonStakingTypes } from "../../../contracts/interfaces/internal/IHorizonStakingTypes.sol"; import { MathUtils } from "../../../contracts/libraries/MathUtils.sol"; @@ -95,7 +96,9 @@ abstract contract HorizonStakingSharedTest is GraphBaseTest { // before uint256 beforeStakingBalance = token.balanceOf(address(staking)); uint256 beforeSenderBalance = token.balanceOf(msgSender); - IHorizonStaking.ServiceProvider memory beforeServiceProvider = staking.getServiceProvider(serviceProvider); + IHorizonStaking.ServiceProviderInternal memory beforeServiceProvider = _getStorage_ServiceProviderInternal( + serviceProvider + ); // stakeTo token.approve(address(staking), tokens); @@ -106,12 +109,21 @@ abstract contract HorizonStakingSharedTest is GraphBaseTest { // after uint256 afterStakingBalance = token.balanceOf(address(staking)); uint256 afterSenderBalance = token.balanceOf(msgSender); - IHorizonStaking.ServiceProvider memory afterServiceProvider = staking.getServiceProvider(serviceProvider); + IHorizonStaking.ServiceProviderInternal memory afterServiceProvider = _getStorage_ServiceProviderInternal( + serviceProvider + ); // assert assertEq(afterStakingBalance, beforeStakingBalance + tokens); assertEq(afterSenderBalance, beforeSenderBalance - tokens); assertEq(afterServiceProvider.tokensStaked, beforeServiceProvider.tokensStaked + tokens); + assertEq(afterServiceProvider.tokensProvisioned, beforeServiceProvider.tokensProvisioned); + assertEq(afterServiceProvider.__DEPRECATED_tokensAllocated, beforeServiceProvider.__DEPRECATED_tokensAllocated); + assertEq(afterServiceProvider.__DEPRECATED_tokensLocked, beforeServiceProvider.__DEPRECATED_tokensLocked); + assertEq( + afterServiceProvider.__DEPRECATED_tokensLockedUntil, + beforeServiceProvider.__DEPRECATED_tokensLockedUntil + ); } function _unstake(uint256 _tokens) internal { @@ -122,63 +134,89 @@ abstract contract HorizonStakingSharedTest is GraphBaseTest { // before uint256 beforeSenderBalance = token.balanceOf(msgSender); uint256 beforeStakingBalance = token.balanceOf(address(staking)); - IHorizonStaking.ServiceProvider memory beforeServiceProvider = staking.getServiceProvider(msgSender); + IHorizonStaking.ServiceProviderInternal memory beforeServiceProvider = _getStorage_ServiceProviderInternal( + msgSender + ); + + bool withdrawCalled = beforeServiceProvider.__DEPRECATED_tokensLocked != 0 && + block.number >= beforeServiceProvider.__DEPRECATED_tokensLockedUntil; + + if (deprecatedThawingPeriod != 0 && beforeServiceProvider.__DEPRECATED_tokensLocked > 0) { + deprecatedThawingPeriod = MathUtils.weightedAverageRoundingUp( + MathUtils.diffOrZero( + withdrawCalled ? 0 : beforeServiceProvider.__DEPRECATED_tokensLockedUntil, + block.number + ), + withdrawCalled ? 0 : beforeServiceProvider.__DEPRECATED_tokensLocked, + deprecatedThawingPeriod, + _tokens + ); + } // unstake if (deprecatedThawingPeriod == 0) { vm.expectEmit(address(staking)); emit IHorizonStakingMain.StakeWithdrawn(msgSender, _tokens); - staking.unstake(_tokens); } else { - // TODO + if (withdrawCalled) { + vm.expectEmit(address(staking)); + emit IHorizonStakingMain.StakeWithdrawn(msgSender, beforeServiceProvider.__DEPRECATED_tokensLocked); + } + + vm.expectEmit(address(staking)); + emit IHorizonStakingMain.StakeLocked( + msgSender, + withdrawCalled ? _tokens : beforeServiceProvider.__DEPRECATED_tokensLocked + _tokens, + block.number + deprecatedThawingPeriod + ); } + staking.unstake(_tokens); // after uint256 afterSenderBalance = token.balanceOf(msgSender); uint256 afterStakingBalance = token.balanceOf(address(staking)); - IHorizonStaking.ServiceProvider memory afterServiceProvider = staking.getServiceProvider(msgSender); + IHorizonStaking.ServiceProviderInternal memory afterServiceProvider = _getStorage_ServiceProviderInternal( + msgSender + ); // assert if (deprecatedThawingPeriod == 0) { - assertEq(afterSenderBalance - beforeSenderBalance, _tokens); + assertEq(afterSenderBalance, _tokens + beforeSenderBalance); assertEq(afterStakingBalance, beforeStakingBalance - _tokens); assertEq(afterServiceProvider.tokensStaked, beforeServiceProvider.tokensStaked - _tokens); + assertEq(afterServiceProvider.tokensProvisioned, beforeServiceProvider.tokensProvisioned); + assertEq( + afterServiceProvider.__DEPRECATED_tokensAllocated, + beforeServiceProvider.__DEPRECATED_tokensAllocated + ); + assertEq(afterServiceProvider.__DEPRECATED_tokensLocked, beforeServiceProvider.__DEPRECATED_tokensLocked); + assertEq( + afterServiceProvider.__DEPRECATED_tokensLockedUntil, + beforeServiceProvider.__DEPRECATED_tokensLockedUntil + ); } else { - // TODO + assertEq( + afterServiceProvider.tokensStaked, + withdrawCalled + ? beforeServiceProvider.tokensStaked - beforeServiceProvider.__DEPRECATED_tokensLocked + : beforeServiceProvider.tokensStaked + ); + assertEq( + afterServiceProvider.__DEPRECATED_tokensLocked, + _tokens + (withdrawCalled ? 0 : beforeServiceProvider.__DEPRECATED_tokensLocked) + ); + assertEq(afterServiceProvider.__DEPRECATED_tokensLockedUntil, block.number + deprecatedThawingPeriod); + assertEq(afterServiceProvider.tokensProvisioned, beforeServiceProvider.tokensProvisioned); + assertEq( + afterServiceProvider.__DEPRECATED_tokensAllocated, + beforeServiceProvider.__DEPRECATED_tokensAllocated + ); + uint256 tokensTransferred = (withdrawCalled ? beforeServiceProvider.__DEPRECATED_tokensLocked : 0); + assertEq(afterSenderBalance, beforeSenderBalance + tokensTransferred); + assertEq(afterStakingBalance, beforeStakingBalance - tokensTransferred); } } - function _unstakeDuringLockingPeriod( - uint256 _tokens, - uint256 _tokensStillThawing, - uint256 _tokensToWithdraw, - uint32 _oldLockingPeriod - ) internal { - uint256 previousIndexerTokens = token.balanceOf(users.indexer); - uint256 previousIndexerIdleStake = staking.getIdleStake(users.indexer); - - vm.expectEmit(address(staking)); - uint256 lockingPeriod = block.number + THAWING_PERIOD_IN_BLOCKS; - if (_tokensStillThawing > 0) { - lockingPeriod = - block.number + - MathUtils.weightedAverageRoundingUp( - MathUtils.diffOrZero(_oldLockingPeriod, block.number), - _tokensStillThawing, - THAWING_PERIOD_IN_BLOCKS, - _tokens - ); - } - emit IHorizonStakingMain.StakeLocked(users.indexer, _tokens + _tokensStillThawing, lockingPeriod); - staking.unstake(_tokens); - - uint256 idleStake = staking.getIdleStake(users.indexer); - assertEq(idleStake, previousIndexerIdleStake - _tokens); - - uint256 newIndexerBalance = token.balanceOf(users.indexer); - assertEq(newIndexerBalance - previousIndexerTokens, _tokensToWithdraw); - } - function _provision( address serviceProvider, address verifier, @@ -187,7 +225,9 @@ abstract contract HorizonStakingSharedTest is GraphBaseTest { uint64 thawingPeriod ) internal { // before - IHorizonStaking.ServiceProvider memory beforeServiceProvider = staking.getServiceProvider(serviceProvider); + IHorizonStaking.ServiceProviderInternal memory beforeServiceProvider = _getStorage_ServiceProviderInternal( + serviceProvider + ); // provision vm.expectEmit(); @@ -196,7 +236,9 @@ abstract contract HorizonStakingSharedTest is GraphBaseTest { // after IHorizonStaking.Provision memory afterProvision = staking.getProvision(serviceProvider, verifier); - IHorizonStaking.ServiceProvider memory afterServiceProvider = staking.getServiceProvider(serviceProvider); + IHorizonStaking.ServiceProviderInternal memory afterServiceProvider = _getStorage_ServiceProviderInternal( + serviceProvider + ); // assert assertEq(afterProvision.tokens, tokens); @@ -207,6 +249,49 @@ abstract contract HorizonStakingSharedTest is GraphBaseTest { assertEq(afterProvision.createdAt, uint64(block.timestamp)); assertEq(afterProvision.maxVerifierCutPending, maxVerifierCut); assertEq(afterProvision.thawingPeriodPending, thawingPeriod); + assertEq(afterServiceProvider.tokensStaked, beforeServiceProvider.tokensStaked); assertEq(afterServiceProvider.tokensProvisioned, tokens + beforeServiceProvider.tokensProvisioned); + assertEq(afterServiceProvider.__DEPRECATED_tokensAllocated, beforeServiceProvider.__DEPRECATED_tokensAllocated); + assertEq(afterServiceProvider.__DEPRECATED_tokensLocked, beforeServiceProvider.__DEPRECATED_tokensLocked); + assertEq( + afterServiceProvider.__DEPRECATED_tokensLockedUntil, + beforeServiceProvider.__DEPRECATED_tokensLockedUntil + ); + } + + function _thaw(address serviceProvider, address verifier, uint256 tokens) internal returns (bytes32) { + // thaw + return staking.thaw(serviceProvider, verifier, tokens); + } + + function _deprovision(uint256 nThawRequests) internal { + staking.deprovision(users.indexer, subgraphDataServiceAddress, nThawRequests); + } + + /* + * STORAGE HELPERS + */ + function _getStorage_ServiceProviderInternal( + address serviceProvider + ) internal view returns (IHorizonStaking.ServiceProviderInternal memory) { + uint256 slotNumber = 14; + uint256 baseSlotUint = uint256(keccak256(abi.encode(serviceProvider, slotNumber))); + + IHorizonStakingTypes.ServiceProviderInternal memory serviceProviderInternal = IHorizonStakingTypes + .ServiceProviderInternal({ + tokensStaked: uint256(vm.load(address(staking), bytes32(baseSlotUint))), + __DEPRECATED_tokensAllocated: uint256(vm.load(address(staking), bytes32(baseSlotUint + 1))), + __DEPRECATED_tokensLocked: uint256(vm.load(address(staking), bytes32(baseSlotUint + 2))), + __DEPRECATED_tokensLockedUntil: uint256(vm.load(address(staking), bytes32(baseSlotUint + 3))), + tokensProvisioned: uint256(vm.load(address(staking), bytes32(baseSlotUint + 4))) + }); + + return serviceProviderInternal; + } + + function _setStorage_DeprecatedThawingPeriod(uint32 _thawingPeriod) internal { + uint256 slot = 13; + bytes32 value = bytes32(uint256(_thawingPeriod)); + vm.store(address(staking), bytes32(slot), value); } } diff --git a/packages/horizon/test/staking/HorizonStaking.t.sol b/packages/horizon/test/staking/HorizonStaking.t.sol index 70a123cfc..5d68adbad 100644 --- a/packages/horizon/test/staking/HorizonStaking.t.sol +++ b/packages/horizon/test/staking/HorizonStaking.t.sol @@ -35,13 +35,13 @@ contract HorizonStakingTest is HorizonStakingSharedTest, IHorizonStakingTypes { modifier useThawRequest(uint256 thawAmount) { vm.assume(thawAmount > 0); - _createThawRequest(thawAmount); + _thaw(users.indexer, subgraphDataServiceAddress, thawAmount); _; } modifier useThawAndDeprovision(uint256 amount, uint64 thawingPeriod) { vm.assume(amount > 0); - _createThawRequest(amount); + _thaw(users.indexer, subgraphDataServiceAddress, amount); skip(thawingPeriod + 1); _deprovision(0); _; @@ -80,14 +80,6 @@ contract HorizonStakingTest is HorizonStakingSharedTest, IHorizonStakingTypes { * HELPERS */ - function _createThawRequest(uint256 thawAmount) internal returns (bytes32) { - return staking.thaw(users.indexer, subgraphDataServiceAddress, thawAmount); - } - - function _deprovision(uint256 nThawRequests) internal { - staking.deprovision(users.indexer, subgraphDataServiceAddress, nThawRequests); - } - function _delegate(address serviceProvider, address verifier, uint256 tokens, uint256 minSharesOut) internal { __delegate(serviceProvider, verifier, tokens, minSharesOut, false); } diff --git a/packages/horizon/test/staking/provision/deprovision.t.sol b/packages/horizon/test/staking/provision/deprovision.t.sol index fbb9d0fc4..28780c82f 100644 --- a/packages/horizon/test/staking/provision/deprovision.t.sol +++ b/packages/horizon/test/staking/provision/deprovision.t.sol @@ -33,8 +33,8 @@ contract HorizonStakingDeprovisionTest is HorizonStakingTest { vm.assume(amount > 1); thawAmount = bound(thawAmount, 2, amount); uint256 thawAmount1 = thawAmount / 2; - _createThawRequest(thawAmount1); - _createThawRequest(thawAmount - thawAmount1); + _thaw(users.indexer, subgraphDataServiceAddress, thawAmount1); + _thaw(users.indexer, subgraphDataServiceAddress, thawAmount - thawAmount1); skip(thawingPeriod + 1); diff --git a/packages/horizon/test/staking/serviceProvider/serviceProvider.t.sol b/packages/horizon/test/staking/serviceProvider/serviceProvider.t.sol index 2d32fa9e2..8412331c6 100644 --- a/packages/horizon/test/staking/serviceProvider/serviceProvider.t.sol +++ b/packages/horizon/test/staking/serviceProvider/serviceProvider.t.sol @@ -106,7 +106,7 @@ contract HorizonStakingServiceProviderTest is HorizonStakingTest { ) public useIndexer useProvision(amount, MAX_MAX_VERIFIER_CUT, MAX_THAWING_PERIOD) { assertTrue(staking.hasStake(users.indexer)); - _createThawRequest(amount); + _thaw(users.indexer, subgraphDataServiceAddress, amount); skip(MAX_THAWING_PERIOD + 1); _deprovision(0); staking.unstake(amount); @@ -119,7 +119,7 @@ contract HorizonStakingServiceProviderTest is HorizonStakingTest { ) public useIndexer useProvision(amount, MAX_MAX_VERIFIER_CUT, MAX_THAWING_PERIOD) { assertEq(staking.getIndexerStakedTokens(users.indexer), amount); - _createThawRequest(amount); + _thaw(users.indexer, subgraphDataServiceAddress, amount); // Does not discount thawing tokens assertEq(staking.getIndexerStakedTokens(users.indexer), amount); diff --git a/packages/horizon/test/staking/stake/unstake.t.sol b/packages/horizon/test/staking/stake/unstake.t.sol index 724037c87..e370d0f7b 100644 --- a/packages/horizon/test/staking/stake/unstake.t.sol +++ b/packages/horizon/test/staking/stake/unstake.t.sol @@ -6,13 +6,6 @@ import "forge-std/Test.sol"; import { HorizonStakingTest } from "../HorizonStaking.t.sol"; contract HorizonStakingUnstakeTest is HorizonStakingTest { - - function _storeDeprecatedThawingPeriod(uint32 _thawingPeriod) private { - uint256 slot = 13; - bytes32 value = bytes32(uint256(_thawingPeriod)); - vm.store(address(staking), bytes32(slot), value); - } - /* * TESTS */ @@ -22,16 +15,34 @@ contract HorizonStakingUnstakeTest is HorizonStakingTest { uint256 tokensToUnstake, uint32 maxVerifierCut, uint64 thawingPeriod - ) - public - useIndexer - useProvision(tokens, maxVerifierCut, thawingPeriod) - { + ) public useIndexer useProvision(tokens, maxVerifierCut, thawingPeriod) { tokensToUnstake = bound(tokensToUnstake, 1, tokens); - _createThawRequest(tokens); + // thaw, wait and deprovision + _thaw(users.indexer, subgraphDataServiceAddress, tokens); skip(thawingPeriod + 1); _deprovision(0); + + _unstake(tokensToUnstake); + } + + function testUnstake_LockingPeriodGreaterThanZero_NoThawing( + uint256 tokens, + uint256 tokensToUnstake, + uint32 maxVerifierCut, + uint64 thawingPeriod + ) public useIndexer useProvision(tokens, maxVerifierCut, thawingPeriod) { + tokensToUnstake = bound(tokensToUnstake, 1, tokens); + + // vm.store to simulate locking period + _setStorage_DeprecatedThawingPeriod(THAWING_PERIOD_IN_BLOCKS); + + // thaw, wait and deprovision + _thaw(users.indexer, subgraphDataServiceAddress, tokens); + skip(thawingPeriod + 1); + _deprovision(0); + + // unstake _unstake(tokensToUnstake); } @@ -39,28 +50,25 @@ contract HorizonStakingUnstakeTest is HorizonStakingTest { uint256 tokens, uint256 tokensToUnstake, uint256 tokensLocked - ) - public - useIndexer - { + ) public useIndexer { // bounds tokens = bound(tokens, 1, MAX_STAKING_TOKENS); tokensToUnstake = bound(tokensToUnstake, 1, tokens); tokensLocked = bound(tokensLocked, 1, MAX_STAKING_TOKENS); // vm.store to simulate locked tokens with past locking period - _storeDeprecatedThawingPeriod(THAWING_PERIOD_IN_BLOCKS); + _setStorage_DeprecatedThawingPeriod(THAWING_PERIOD_IN_BLOCKS); token.transfer(address(staking), tokensLocked); _storeServiceProvider(users.indexer, tokensLocked, 0, tokensLocked, block.number, 0); - // create provision, thaw request and deprovision + // create provision, thaw and deprovision _createProvision(users.indexer, subgraphDataServiceAddress, tokens, 0, MAX_THAWING_PERIOD); - _createThawRequest(tokens); + _thaw(users.indexer, subgraphDataServiceAddress, tokens); skip(MAX_THAWING_PERIOD + 1); _deprovision(0); // unstake - _unstakeDuringLockingPeriod(tokensToUnstake, 0, tokensLocked, 0); + _unstake(tokensToUnstake); } function testUnstake_LockingPeriodGreaterThanZero_TokensStillThawing( @@ -68,10 +76,7 @@ contract HorizonStakingUnstakeTest is HorizonStakingTest { uint256 tokensToUnstake, uint256 tokensThawing, uint32 tokensThawingUntilBlock - ) - public - useIndexer - { + ) public useIndexer { // bounds tokens = bound(tokens, 1, MAX_STAKING_TOKENS); tokensToUnstake = bound(tokensToUnstake, 1, tokens); @@ -80,18 +85,18 @@ contract HorizonStakingUnstakeTest is HorizonStakingTest { vm.assume(tokensThawingUntilBlock < block.number + THAWING_PERIOD_IN_BLOCKS); // vm.store to simulate locked tokens still thawing - _storeDeprecatedThawingPeriod(THAWING_PERIOD_IN_BLOCKS); + _setStorage_DeprecatedThawingPeriod(THAWING_PERIOD_IN_BLOCKS); token.transfer(address(staking), tokensThawing); _storeServiceProvider(users.indexer, tokensThawing, 0, tokensThawing, tokensThawingUntilBlock, 0); - // create provision, thaw request and deprovision + // create provision, thaw and deprovision _createProvision(users.indexer, subgraphDataServiceAddress, tokens, 0, MAX_THAWING_PERIOD); - _createThawRequest(tokens); + _thaw(users.indexer, subgraphDataServiceAddress, tokens); skip(MAX_THAWING_PERIOD + 1); _deprovision(0); // unstake - _unstakeDuringLockingPeriod(tokensToUnstake, tokensThawing, 0, tokensThawingUntilBlock); + _unstake(tokensToUnstake); } function testUnstake_RevertWhen_ZeroTokens( @@ -113,11 +118,7 @@ contract HorizonStakingUnstakeTest is HorizonStakingTest { uint256 amount, uint32 maxVerifierCut, uint64 thawingPeriod - ) - public - useIndexer - useProvision(amount, maxVerifierCut, thawingPeriod) - { + ) public useIndexer useProvision(amount, maxVerifierCut, thawingPeriod) { bytes memory expectedError = abi.encodeWithSignature( "HorizonStakingInsufficientIdleStake(uint256,uint256)", amount, @@ -131,12 +132,7 @@ contract HorizonStakingUnstakeTest is HorizonStakingTest { uint256 amount, uint32 maxVerifierCut, uint64 thawingPeriod - ) - public - useIndexer - useProvision(amount, maxVerifierCut, thawingPeriod) - useThawRequest(amount) - { + ) public useIndexer useProvision(amount, maxVerifierCut, thawingPeriod) useThawRequest(amount) { skip(thawingPeriod + 1); bytes memory expectedError = abi.encodeWithSignature( @@ -147,4 +143,4 @@ contract HorizonStakingUnstakeTest is HorizonStakingTest { vm.expectRevert(expectedError); staking.unstake(amount); } -} \ No newline at end of file +} diff --git a/packages/horizon/test/staking/thaw/thaw.t.sol b/packages/horizon/test/staking/thaw/thaw.t.sol index 2ed99682f..957dc9649 100644 --- a/packages/horizon/test/staking/thaw/thaw.t.sol +++ b/packages/horizon/test/staking/thaw/thaw.t.sol @@ -21,7 +21,7 @@ contract HorizonStakingThawTest is HorizonStakingTest { bytes32 expectedThawRequestId = keccak256( abi.encodePacked(users.indexer, subgraphDataServiceAddress, users.indexer, uint256(0)) ); - bytes32 thawRequestId = _createThawRequest(thawAmount); + bytes32 thawRequestId = _thaw(users.indexer, subgraphDataServiceAddress, thawAmount); assertEq(thawRequestId, expectedThawRequestId); ThawRequest memory thawRequest = staking.getThawRequest(expectedThawRequestId); @@ -38,8 +38,8 @@ contract HorizonStakingThawTest is HorizonStakingTest { vm.assume(amount > 1); thawAmount = bound(thawAmount, 1, amount - 1); thawAmount2 = bound(thawAmount2, 1, amount - thawAmount); - bytes32 thawRequestId = _createThawRequest(thawAmount); - bytes32 thawRequestId2 = _createThawRequest(thawAmount2); + bytes32 thawRequestId = _thaw(users.indexer, subgraphDataServiceAddress, thawAmount); + bytes32 thawRequestId2 = _thaw(users.indexer, subgraphDataServiceAddress, thawAmount2); ThawRequest memory thawRequest = staking.getThawRequest(thawRequestId); assertEq(thawRequest.shares, thawAmount); @@ -55,7 +55,7 @@ contract HorizonStakingThawTest is HorizonStakingTest { uint256 amount, uint64 thawingPeriod ) public useOperator useProvision(amount, 0, thawingPeriod) { - bytes32 thawRequestId = _createThawRequest(amount); + bytes32 thawRequestId = _thaw(users.indexer, subgraphDataServiceAddress, amount); ThawRequest memory thawRequest = staking.getThawRequest(thawRequestId); assertEq(thawRequest.shares, amount); @@ -74,7 +74,7 @@ contract HorizonStakingThawTest is HorizonStakingTest { subgraphDataServiceAddress ); vm.expectRevert(expectedError); - _createThawRequest(amount); + _thaw(users.indexer, subgraphDataServiceAddress, amount); } function testThaw_RevertWhen_InsufficientTokensAvailable( @@ -89,7 +89,7 @@ contract HorizonStakingThawTest is HorizonStakingTest { thawAmount ); vm.expectRevert(expectedError); - _createThawRequest(thawAmount); + _thaw(users.indexer, subgraphDataServiceAddress, thawAmount); } function testThaw_RevertWhen_OverMaxThawRequests( @@ -101,12 +101,12 @@ contract HorizonStakingThawTest is HorizonStakingTest { thawAmount = bound(thawAmount, 1, amount / (MAX_THAW_REQUESTS + 1)); for (uint256 i = 0; i < 100; i++) { - _createThawRequest(thawAmount); + _thaw(users.indexer, subgraphDataServiceAddress, thawAmount); } bytes memory expectedError = abi.encodeWithSignature("HorizonStakingTooManyThawRequests()"); vm.expectRevert(expectedError); - _createThawRequest(thawAmount); + _thaw(users.indexer, subgraphDataServiceAddress, thawAmount); } function testThaw_RevertWhen_ThawingZeroTokens( @@ -116,6 +116,6 @@ contract HorizonStakingThawTest is HorizonStakingTest { uint256 thawAmount = 0 ether; bytes memory expectedError = abi.encodeWithSignature("HorizonStakingInvalidZeroTokens()"); vm.expectRevert(expectedError); - _createThawRequest(thawAmount); + _thaw(users.indexer, subgraphDataServiceAddress, thawAmount); } } From d54442c544bdc01463e069670b36574d50e0a09f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1s=20Migone?= Date: Tue, 27 Aug 2024 16:45:01 -0300 Subject: [PATCH 03/24] test: refactor withdraw tests MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Tomás Migone --- .../HorizonStakingShared.t.sol | 56 ++++++++++++++++-- .../horizon/test/staking/HorizonStaking.t.sol | 17 ------ .../horizon/test/staking/stake/unstake.t.sol | 10 ++-- .../horizon/test/staking/stake/withdraw.t.sol | 58 +++++++++---------- 4 files changed, 84 insertions(+), 57 deletions(-) diff --git a/packages/horizon/test/shared/horizon-staking/HorizonStakingShared.t.sol b/packages/horizon/test/shared/horizon-staking/HorizonStakingShared.t.sol index e6397fadf..e5045dc34 100644 --- a/packages/horizon/test/shared/horizon-staking/HorizonStakingShared.t.sol +++ b/packages/horizon/test/shared/horizon-staking/HorizonStakingShared.t.sol @@ -54,10 +54,9 @@ abstract contract HorizonStakingSharedTest is GraphBaseTest { } function _useProvision(address dataService, uint256 tokens, uint32 maxVerifierCut, uint64 thawingPeriod) internal { - vm.assume(tokens <= MAX_STAKING_TOKENS); - vm.assume(tokens > 0); - vm.assume(maxVerifierCut <= MAX_MAX_VERIFIER_CUT); - vm.assume(thawingPeriod <= MAX_THAWING_PERIOD); + tokens = bound(tokens, 1, MAX_STAKING_TOKENS); + maxVerifierCut = uint32(bound(maxVerifierCut, 0, MAX_MAX_VERIFIER_CUT)); + thawingPeriod = uint32(bound(thawingPeriod, 0, MAX_THAWING_PERIOD)); _createProvision(users.indexer, dataService, tokens, maxVerifierCut, thawingPeriod); } @@ -217,6 +216,38 @@ abstract contract HorizonStakingSharedTest is GraphBaseTest { } } + function _withdraw() internal { + (, address msgSender, ) = vm.readCallers(); + + // before + IHorizonStaking.ServiceProviderInternal memory beforeServiceProvider = _getStorage_ServiceProviderInternal( + msgSender + ); + uint256 beforeSenderBalance = token.balanceOf(msgSender); + uint256 beforeStakingBalance = token.balanceOf(address(staking)); + + // withdraw + vm.expectEmit(address(staking)); + emit IHorizonStakingMain.StakeWithdrawn(msgSender, beforeServiceProvider.__DEPRECATED_tokensLocked); + staking.withdraw(); + + // after + IHorizonStaking.ServiceProviderInternal memory afterServiceProvider = _getStorage_ServiceProviderInternal( + msgSender + ); + uint256 afterSenderBalance = token.balanceOf(msgSender); + uint256 afterStakingBalance = token.balanceOf(address(staking)); + + // assert + assertEq(afterSenderBalance - beforeSenderBalance, beforeServiceProvider.__DEPRECATED_tokensLocked); + assertEq(beforeStakingBalance - afterStakingBalance, beforeServiceProvider.__DEPRECATED_tokensLocked); + assertEq(afterServiceProvider.tokensStaked, beforeServiceProvider.tokensStaked - beforeServiceProvider.__DEPRECATED_tokensLocked); + assertEq(afterServiceProvider.tokensProvisioned, beforeServiceProvider.tokensProvisioned); + assertEq(afterServiceProvider.__DEPRECATED_tokensAllocated, beforeServiceProvider.__DEPRECATED_tokensAllocated); + assertEq(afterServiceProvider.__DEPRECATED_tokensLocked, 0); + assertEq(afterServiceProvider.__DEPRECATED_tokensLockedUntil, 0); + } + function _provision( address serviceProvider, address verifier, @@ -294,4 +325,21 @@ abstract contract HorizonStakingSharedTest is GraphBaseTest { bytes32 value = bytes32(uint256(_thawingPeriod)); vm.store(address(staking), bytes32(slot), value); } + + function _setStorage_ServiceProvider( + address _indexer, + uint256 _tokensStaked, + uint256 _tokensAllocated, + uint256 _tokensLocked, + uint256 _tokensLockedUntil, + uint256 _tokensProvisioned + ) internal { + uint256 serviceProviderSlot = 14; + bytes32 serviceProviderBaseSlot = keccak256(abi.encode(_indexer, serviceProviderSlot)); + vm.store(address(staking), bytes32(uint256(serviceProviderBaseSlot)), bytes32(_tokensStaked)); + vm.store(address(staking), bytes32(uint256(serviceProviderBaseSlot) + 1), bytes32(_tokensAllocated)); + vm.store(address(staking), bytes32(uint256(serviceProviderBaseSlot) + 2), bytes32(_tokensLocked)); + vm.store(address(staking), bytes32(uint256(serviceProviderBaseSlot) + 3), bytes32(_tokensLockedUntil)); + vm.store(address(staking), bytes32(uint256(serviceProviderBaseSlot) + 4), bytes32(_tokensProvisioned)); + } } diff --git a/packages/horizon/test/staking/HorizonStaking.t.sol b/packages/horizon/test/staking/HorizonStaking.t.sol index 5d68adbad..77d66c3f9 100644 --- a/packages/horizon/test/staking/HorizonStaking.t.sol +++ b/packages/horizon/test/staking/HorizonStaking.t.sol @@ -247,23 +247,6 @@ contract HorizonStakingTest is HorizonStakingSharedTest, IHorizonStakingTypes { return staking.getDelegationPool(users.indexer, verifier); } - function _storeServiceProvider( - address _indexer, - uint256 _tokensStaked, - uint256 _tokensAllocated, - uint256 _tokensLocked, - uint256 _tokensLockedUntil, - uint256 _tokensProvisioned - ) internal { - uint256 serviceProviderSlot = 14; - bytes32 serviceProviderBaseSlot = keccak256(abi.encode(_indexer, serviceProviderSlot)); - vm.store(address(staking), bytes32(uint256(serviceProviderBaseSlot)), bytes32(_tokensStaked)); - vm.store(address(staking), bytes32(uint256(serviceProviderBaseSlot) + 1), bytes32(_tokensAllocated)); - vm.store(address(staking), bytes32(uint256(serviceProviderBaseSlot) + 2), bytes32(_tokensLocked)); - vm.store(address(staking), bytes32(uint256(serviceProviderBaseSlot) + 3), bytes32(_tokensLockedUntil)); - vm.store(address(staking), bytes32(uint256(serviceProviderBaseSlot) + 4), bytes32(_tokensProvisioned)); - } - function _slash(address serviceProvider, address verifier, uint256 tokens, uint256 verifierCutAmount) internal { uint256 beforeProviderTokens = staking.getProviderTokensAvailable(serviceProvider, verifier); uint256 beforeDelegationTokens = staking.getDelegatedTokensAvailable(serviceProvider, verifier); diff --git a/packages/horizon/test/staking/stake/unstake.t.sol b/packages/horizon/test/staking/stake/unstake.t.sol index e370d0f7b..5c14f6437 100644 --- a/packages/horizon/test/staking/stake/unstake.t.sol +++ b/packages/horizon/test/staking/stake/unstake.t.sol @@ -34,7 +34,7 @@ contract HorizonStakingUnstakeTest is HorizonStakingTest { ) public useIndexer useProvision(tokens, maxVerifierCut, thawingPeriod) { tokensToUnstake = bound(tokensToUnstake, 1, tokens); - // vm.store to simulate locking period + // simulate transition period _setStorage_DeprecatedThawingPeriod(THAWING_PERIOD_IN_BLOCKS); // thaw, wait and deprovision @@ -56,10 +56,10 @@ contract HorizonStakingUnstakeTest is HorizonStakingTest { tokensToUnstake = bound(tokensToUnstake, 1, tokens); tokensLocked = bound(tokensLocked, 1, MAX_STAKING_TOKENS); - // vm.store to simulate locked tokens with past locking period + // simulate locked tokens with past locking period _setStorage_DeprecatedThawingPeriod(THAWING_PERIOD_IN_BLOCKS); token.transfer(address(staking), tokensLocked); - _storeServiceProvider(users.indexer, tokensLocked, 0, tokensLocked, block.number, 0); + _setStorage_ServiceProvider(users.indexer, tokensLocked, 0, tokensLocked, block.number, 0); // create provision, thaw and deprovision _createProvision(users.indexer, subgraphDataServiceAddress, tokens, 0, MAX_THAWING_PERIOD); @@ -84,10 +84,10 @@ contract HorizonStakingUnstakeTest is HorizonStakingTest { vm.assume(tokensThawingUntilBlock > block.number); vm.assume(tokensThawingUntilBlock < block.number + THAWING_PERIOD_IN_BLOCKS); - // vm.store to simulate locked tokens still thawing + // simulate locked tokens still thawing _setStorage_DeprecatedThawingPeriod(THAWING_PERIOD_IN_BLOCKS); token.transfer(address(staking), tokensThawing); - _storeServiceProvider(users.indexer, tokensThawing, 0, tokensThawing, tokensThawingUntilBlock, 0); + _setStorage_ServiceProvider(users.indexer, tokensThawing, 0, tokensThawing, tokensThawingUntilBlock, 0); // create provision, thaw and deprovision _createProvision(users.indexer, subgraphDataServiceAddress, tokens, 0, MAX_THAWING_PERIOD); diff --git a/packages/horizon/test/staking/stake/withdraw.t.sol b/packages/horizon/test/staking/stake/withdraw.t.sol index 2bb5b16be..0ef922bfa 100644 --- a/packages/horizon/test/staking/stake/withdraw.t.sol +++ b/packages/horizon/test/staking/stake/withdraw.t.sol @@ -8,52 +8,48 @@ import { IHorizonStakingMain } from "../../../contracts/interfaces/internal/IHor import { HorizonStakingTest } from "../HorizonStaking.t.sol"; contract HorizonStakingWithdrawTest is HorizonStakingTest { - - /* - * HELPERS - */ - - function _withdrawLockedTokens(uint256 tokens) private { - uint256 previousIndexerTokens = token.balanceOf(users.indexer); - vm.expectEmit(address(staking)); - emit IHorizonStakingMain.StakeWithdrawn(users.indexer, tokens); - staking.withdraw(); - uint256 newIndexerBalance = token.balanceOf(users.indexer); - assertEq(newIndexerBalance - previousIndexerTokens, tokens); - } - /* * TESTS */ function testWithdraw_Tokens(uint256 tokens, uint256 tokensLocked) public useIndexer { - vm.assume(tokens > 0); + tokens = bound(tokens, 1, MAX_STAKING_TOKENS); tokensLocked = bound(tokensLocked, 1, tokens); - _createProvision(users.indexer, subgraphDataServiceLegacyAddress, tokens, 0, MAX_THAWING_PERIOD); - _storeServiceProvider(users.indexer, tokens, 0, tokensLocked, block.timestamp, 0); - _withdrawLockedTokens(tokensLocked); + + // simulate locked tokens ready to withdraw + token.transfer(address(staking), tokens); + _setStorage_ServiceProvider(users.indexer, tokens, 0, tokensLocked, block.number, 0); + + _createProvision(users.indexer, subgraphDataServiceAddress, tokens, 0, MAX_THAWING_PERIOD); + + _withdraw(); } function testWithdraw_RevertWhen_ZeroTokens(uint256 tokens) public useIndexer { - vm.assume(tokens > 0); + tokens = bound(tokens, 1, MAX_STAKING_TOKENS); + + // simulate zero locked tokens + token.transfer(address(staking), tokens); + _setStorage_ServiceProvider(users.indexer, tokens, 0, 0, 0, 0); + _createProvision(users.indexer, subgraphDataServiceLegacyAddress, tokens, 0, MAX_THAWING_PERIOD); - _storeServiceProvider(users.indexer, tokens, 0, 0, block.timestamp, 0); - vm.expectRevert(abi.encodeWithSelector( - IHorizonStakingMain.HorizonStakingInvalidZeroTokens.selector - )); + + vm.expectRevert(abi.encodeWithSelector(IHorizonStakingMain.HorizonStakingInvalidZeroTokens.selector)); staking.withdraw(); } function testWithdraw_RevertWhen_StillThawing(uint256 tokens, uint256 tokensLocked) public useIndexer { - vm.assume(tokens > 0); + tokens = bound(tokens, 1, MAX_STAKING_TOKENS); tokensLocked = bound(tokensLocked, 1, tokens); - _createProvision(users.indexer, subgraphDataServiceLegacyAddress, tokens, 0, MAX_THAWING_PERIOD); + + // simulate locked tokens still thawing uint256 thawUntil = block.timestamp + 1; - _storeServiceProvider(users.indexer, tokens, 0, tokensLocked, thawUntil, 0); - vm.expectRevert(abi.encodeWithSelector( - IHorizonStakingMain.HorizonStakingStillThawing.selector, - thawUntil - )); + token.transfer(address(staking), tokens); + _setStorage_ServiceProvider(users.indexer, tokens, 0, tokensLocked, thawUntil, 0); + + _createProvision(users.indexer, subgraphDataServiceLegacyAddress, tokens, 0, MAX_THAWING_PERIOD); + + vm.expectRevert(abi.encodeWithSelector(IHorizonStakingMain.HorizonStakingStillThawing.selector, thawUntil)); staking.withdraw(); } -} \ No newline at end of file +} From a632d26243843208986b26aa055ef83d097dfb3e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1s=20Migone?= Date: Tue, 27 Aug 2024 17:06:37 -0300 Subject: [PATCH 04/24] test: refactor add to provision MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Tomás Migone --- .../HorizonStakingShared.t.sol | 50 ++++++++++++++++++- .../horizon/test/staking/HorizonStaking.t.sol | 8 --- .../test/staking/provision/provision.t.sol | 25 ++++------ 3 files changed, 58 insertions(+), 25 deletions(-) diff --git a/packages/horizon/test/shared/horizon-staking/HorizonStakingShared.t.sol b/packages/horizon/test/shared/horizon-staking/HorizonStakingShared.t.sol index e5045dc34..84da774d4 100644 --- a/packages/horizon/test/shared/horizon-staking/HorizonStakingShared.t.sol +++ b/packages/horizon/test/shared/horizon-staking/HorizonStakingShared.t.sol @@ -23,6 +23,14 @@ abstract contract HorizonStakingSharedTest is GraphBaseTest { vm.stopPrank(); } + modifier useOperator() { + vm.startPrank(users.indexer); + staking.setOperator(users.operator, subgraphDataServiceAddress, true); + vm.startPrank(users.operator); + _; + vm.stopPrank(); + } + modifier useStake(uint256 amount) { vm.assume(amount > 0); _stake(amount); @@ -241,7 +249,10 @@ abstract contract HorizonStakingSharedTest is GraphBaseTest { // assert assertEq(afterSenderBalance - beforeSenderBalance, beforeServiceProvider.__DEPRECATED_tokensLocked); assertEq(beforeStakingBalance - afterStakingBalance, beforeServiceProvider.__DEPRECATED_tokensLocked); - assertEq(afterServiceProvider.tokensStaked, beforeServiceProvider.tokensStaked - beforeServiceProvider.__DEPRECATED_tokensLocked); + assertEq( + afterServiceProvider.tokensStaked, + beforeServiceProvider.tokensStaked - beforeServiceProvider.__DEPRECATED_tokensLocked + ); assertEq(afterServiceProvider.tokensProvisioned, beforeServiceProvider.tokensProvisioned); assertEq(afterServiceProvider.__DEPRECATED_tokensAllocated, beforeServiceProvider.__DEPRECATED_tokensAllocated); assertEq(afterServiceProvider.__DEPRECATED_tokensLocked, 0); @@ -290,6 +301,43 @@ abstract contract HorizonStakingSharedTest is GraphBaseTest { ); } + function _addToProvision(address serviceProvider, address verifier, uint256 tokens) internal { + // before + IHorizonStaking.Provision memory beforeProvision = staking.getProvision(serviceProvider, verifier); + IHorizonStaking.ServiceProviderInternal memory beforeServiceProvider = _getStorage_ServiceProviderInternal( + serviceProvider + ); + + // addToProvision + vm.expectEmit(); + emit IHorizonStakingMain.ProvisionIncreased(serviceProvider, verifier, tokens); + staking.addToProvision(serviceProvider, verifier, tokens); + + // after + IHorizonStaking.Provision memory afterProvision = staking.getProvision(serviceProvider, verifier); + IHorizonStaking.ServiceProviderInternal memory afterServiceProvider = _getStorage_ServiceProviderInternal( + serviceProvider + ); + + // assert + assertEq(afterProvision.tokens, beforeProvision.tokens + tokens); + assertEq(afterProvision.tokensThawing, beforeProvision.tokensThawing); + assertEq(afterProvision.sharesThawing, beforeProvision.sharesThawing); + assertEq(afterProvision.maxVerifierCut, beforeProvision.maxVerifierCut); + assertEq(afterProvision.thawingPeriod, beforeProvision.thawingPeriod); + assertEq(afterProvision.createdAt, beforeProvision.createdAt); + assertEq(afterProvision.maxVerifierCutPending, beforeProvision.maxVerifierCutPending); + assertEq(afterProvision.thawingPeriodPending, beforeProvision.thawingPeriodPending); + assertEq(afterServiceProvider.tokensStaked, beforeServiceProvider.tokensStaked); + assertEq(afterServiceProvider.tokensProvisioned, beforeServiceProvider.tokensProvisioned + tokens); + assertEq(afterServiceProvider.__DEPRECATED_tokensAllocated, beforeServiceProvider.__DEPRECATED_tokensAllocated); + assertEq(afterServiceProvider.__DEPRECATED_tokensLocked, beforeServiceProvider.__DEPRECATED_tokensLocked); + assertEq( + afterServiceProvider.__DEPRECATED_tokensLockedUntil, + beforeServiceProvider.__DEPRECATED_tokensLockedUntil + ); + } + function _thaw(address serviceProvider, address verifier, uint256 tokens) internal returns (bytes32) { // thaw return staking.thaw(serviceProvider, verifier, tokens); diff --git a/packages/horizon/test/staking/HorizonStaking.t.sol b/packages/horizon/test/staking/HorizonStaking.t.sol index 77d66c3f9..8effc5762 100644 --- a/packages/horizon/test/staking/HorizonStaking.t.sol +++ b/packages/horizon/test/staking/HorizonStaking.t.sol @@ -25,14 +25,6 @@ contract HorizonStakingTest is HorizonStakingSharedTest, IHorizonStakingTypes { _; } - modifier useOperator() { - vm.startPrank(users.indexer); - staking.setOperator(users.operator, subgraphDataServiceAddress, true); - vm.startPrank(users.operator); - _; - vm.stopPrank(); - } - modifier useThawRequest(uint256 thawAmount) { vm.assume(thawAmount > 0); _thaw(users.indexer, subgraphDataServiceAddress, thawAmount); diff --git a/packages/horizon/test/staking/provision/provision.t.sol b/packages/horizon/test/staking/provision/provision.t.sol index 3394460fb..b6ccd2619 100644 --- a/packages/horizon/test/staking/provision/provision.t.sol +++ b/packages/horizon/test/staking/provision/provision.t.sol @@ -10,13 +10,12 @@ contract HorizonStakingProvisionTest is HorizonStakingTest { * TESTS */ - function testProvision_Create( - uint256 amount, - uint32 maxVerifierCut, - uint64 thawingPeriod - ) public useIndexer useProvision(amount, maxVerifierCut, thawingPeriod) { - uint256 provisionTokens = staking.getProviderTokensAvailable(users.indexer, subgraphDataServiceAddress); - assertEq(provisionTokens, amount); + function testProvision_Create(uint256 tokens, uint32 maxVerifierCut, uint64 thawingPeriod) public useIndexer { + tokens = bound(tokens, 1, MAX_STAKING_TOKENS); + maxVerifierCut = uint32(bound(maxVerifierCut, 0, MAX_MAX_VERIFIER_CUT)); + thawingPeriod = uint32(bound(thawingPeriod, 0, MAX_THAWING_PERIOD)); + + _createProvision(users.indexer, subgraphDataServiceAddress, tokens, maxVerifierCut, thawingPeriod); } function testProvision_RevertWhen_ZeroTokens() public useIndexer useStake(1000 ether) { @@ -87,18 +86,12 @@ contract HorizonStakingProvisionTest is HorizonStakingTest { uint32 maxVerifierCut, uint64 thawingPeriod, uint256 tokensToAdd - ) public useIndexer useProvision(amount, maxVerifierCut, thawingPeriod) { - tokensToAdd = bound(tokensToAdd, 1, type(uint256).max - amount); - // Set operator - staking.setOperator(users.operator, subgraphDataServiceAddress, true); + ) public useIndexer useProvision(amount, maxVerifierCut, thawingPeriod) useOperator { + tokensToAdd = bound(tokensToAdd, 1, MAX_STAKING_TOKENS); // Add more tokens to the provision - vm.startPrank(users.operator); _stakeTo(users.indexer, tokensToAdd); - staking.addToProvision(users.indexer, subgraphDataServiceAddress, tokensToAdd); - - uint256 provisionTokens = staking.getProviderTokensAvailable(users.indexer, subgraphDataServiceAddress); - assertEq(provisionTokens, amount + tokensToAdd); + _addToProvision(users.indexer, subgraphDataServiceAddress, tokensToAdd); } function testProvision_RevertWhen_OperatorNotAuthorized( From 201ae3134731b2e029af2d6761e6194b63043d74 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1s=20Migone?= Date: Tue, 27 Aug 2024 17:44:51 -0300 Subject: [PATCH 05/24] test: wip thaw refactor MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Tomás Migone --- .../HorizonStakingShared.t.sol | 72 +++++++++++++++++-- .../staking/{thaw => provision}/thaw.t.sol | 12 +--- 2 files changed, 70 insertions(+), 14 deletions(-) rename packages/horizon/test/staking/{thaw => provision}/thaw.t.sol (88%) diff --git a/packages/horizon/test/shared/horizon-staking/HorizonStakingShared.t.sol b/packages/horizon/test/shared/horizon-staking/HorizonStakingShared.t.sol index 84da774d4..c010c8984 100644 --- a/packages/horizon/test/shared/horizon-staking/HorizonStakingShared.t.sol +++ b/packages/horizon/test/shared/horizon-staking/HorizonStakingShared.t.sol @@ -10,6 +10,7 @@ import { IHorizonStakingBase } from "../../../contracts/interfaces/internal/IHor import { IHorizonStakingMain } from "../../../contracts/interfaces/internal/IHorizonStakingMain.sol"; import { IHorizonStakingTypes } from "../../../contracts/interfaces/internal/IHorizonStakingTypes.sol"; +import { LinkedList } from "../../../contracts/libraries/LinkedList.sol"; import { MathUtils } from "../../../contracts/libraries/MathUtils.sol"; abstract contract HorizonStakingSharedTest is GraphBaseTest { @@ -62,9 +63,11 @@ abstract contract HorizonStakingSharedTest is GraphBaseTest { } function _useProvision(address dataService, uint256 tokens, uint32 maxVerifierCut, uint64 thawingPeriod) internal { - tokens = bound(tokens, 1, MAX_STAKING_TOKENS); - maxVerifierCut = uint32(bound(maxVerifierCut, 0, MAX_MAX_VERIFIER_CUT)); - thawingPeriod = uint32(bound(thawingPeriod, 0, MAX_THAWING_PERIOD)); + // use assume instead of bound to avoid the bounding falling out of scope + vm.assume(tokens > 0); + vm.assume(tokens <= MAX_STAKING_TOKENS); + vm.assume(maxVerifierCut <= MAX_MAX_VERIFIER_CUT); + vm.assume(thawingPeriod <= MAX_THAWING_PERIOD); _createProvision(users.indexer, dataService, tokens, maxVerifierCut, thawingPeriod); } @@ -339,8 +342,69 @@ abstract contract HorizonStakingSharedTest is GraphBaseTest { } function _thaw(address serviceProvider, address verifier, uint256 tokens) internal returns (bytes32) { + // before + IHorizonStaking.Provision memory beforeProvision = staking.getProvision(serviceProvider, verifier); + LinkedList.List memory beforeThawRequestList = staking.getThawRequestList( + serviceProvider, + verifier, + serviceProvider + ); + IHorizonStaking.ThawRequest memory beforeTailThawRequest = staking.getThawRequest(beforeThawRequestList.tail); + + bytes32 expectedThawRequestId = keccak256( + abi.encodePacked(users.indexer, subgraphDataServiceAddress, users.indexer, uint256(0)) + ); + uint256 thawingShares = beforeProvision.sharesThawing == 0 + ? tokens + : (beforeProvision.sharesThawing * tokens) / beforeProvision.tokensThawing; + // thaw - return staking.thaw(serviceProvider, verifier, tokens); + vm.expectEmit(address(staking)); + emit IHorizonStakingMain.ThawRequestCreated( + serviceProvider, + verifier, + serviceProvider, + thawingShares, + uint64(block.timestamp + beforeProvision.thawingPeriod), + expectedThawRequestId + ); + vm.expectEmit(address(staking)); + emit IHorizonStakingMain.ProvisionThawed(serviceProvider, verifier, tokens); + bytes32 thawRequestId = staking.thaw(serviceProvider, verifier, tokens); + + // after + IHorizonStaking.Provision memory afterProvision = staking.getProvision(serviceProvider, verifier); + IHorizonStaking.ThawRequest memory afterThawRequest = staking.getThawRequest(thawRequestId); + LinkedList.List memory afterThawRequestList = staking.getThawRequestList( + serviceProvider, + verifier, + serviceProvider + ); + + // assert + assertEq(afterProvision.tokens, beforeProvision.tokens); + assertEq(afterProvision.tokensThawing, beforeProvision.tokensThawing + tokens); + assertEq(afterProvision.sharesThawing, beforeProvision.sharesThawing + thawingShares); + assertEq(afterProvision.maxVerifierCut, beforeProvision.maxVerifierCut); + assertEq(afterProvision.thawingPeriod, beforeProvision.thawingPeriod); + assertEq(afterProvision.createdAt, beforeProvision.createdAt); + assertEq(afterProvision.maxVerifierCutPending, beforeProvision.maxVerifierCutPending); + assertEq(afterProvision.thawingPeriodPending, beforeProvision.thawingPeriodPending); + assertEq(thawRequestId, expectedThawRequestId); + assertEq(afterThawRequest.shares, thawingShares); + assertEq(afterThawRequest.thawingUntil, block.timestamp + beforeProvision.thawingPeriod); + assertEq(afterThawRequest.next, bytes32(0)); + assertEq( + afterThawRequestList.head, + beforeThawRequestList.count == 0 ? thawRequestId : beforeThawRequestList.head + ); + assertEq(afterThawRequestList.tail, thawRequestId); + assertEq(afterThawRequestList.count, beforeThawRequestList.count + 1); + if (beforeThawRequestList.count != 0) { + assertEq(beforeTailThawRequest.next, thawRequestId); + } + + return thawRequestId; } function _deprovision(uint256 nThawRequests) internal { diff --git a/packages/horizon/test/staking/thaw/thaw.t.sol b/packages/horizon/test/staking/provision/thaw.t.sol similarity index 88% rename from packages/horizon/test/staking/thaw/thaw.t.sol rename to packages/horizon/test/staking/provision/thaw.t.sol index 957dc9649..e69665ca5 100644 --- a/packages/horizon/test/staking/thaw/thaw.t.sol +++ b/packages/horizon/test/staking/provision/thaw.t.sol @@ -7,26 +7,18 @@ import { IHorizonStakingTypes } from "../../../contracts/interfaces/internal/IHo import { HorizonStakingTest } from "../HorizonStaking.t.sol"; contract HorizonStakingThawTest is HorizonStakingTest { - /* * TESTS */ - function testThaw_Tokens( + function testThaw_Tokenss( uint256 amount, uint64 thawingPeriod, uint256 thawAmount ) public useIndexer useProvision(amount, 0, thawingPeriod) { thawAmount = bound(thawAmount, 1, amount); - bytes32 expectedThawRequestId = keccak256( - abi.encodePacked(users.indexer, subgraphDataServiceAddress, users.indexer, uint256(0)) - ); - bytes32 thawRequestId = _thaw(users.indexer, subgraphDataServiceAddress, thawAmount); - assertEq(thawRequestId, expectedThawRequestId); - ThawRequest memory thawRequest = staking.getThawRequest(expectedThawRequestId); - assertEq(thawRequest.shares, thawAmount); - assertEq(thawRequest.thawingUntil, block.timestamp + thawingPeriod); + _thaw(users.indexer, subgraphDataServiceAddress, thawAmount); } function testThaw_MultipleRequests( From 33cda770f8914e4249628f612cda467c769e8170 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1s=20Migone?= Date: Wed, 28 Aug 2024 12:07:50 -0300 Subject: [PATCH 06/24] test: refactor thaw tests MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Tomás Migone --- .../HorizonStakingShared.t.sol | 7 ++-- .../horizon/test/staking/provision/thaw.t.sol | 40 +++++++------------ 2 files changed, 19 insertions(+), 28 deletions(-) diff --git a/packages/horizon/test/shared/horizon-staking/HorizonStakingShared.t.sol b/packages/horizon/test/shared/horizon-staking/HorizonStakingShared.t.sol index c010c8984..4ac6f7351 100644 --- a/packages/horizon/test/shared/horizon-staking/HorizonStakingShared.t.sol +++ b/packages/horizon/test/shared/horizon-staking/HorizonStakingShared.t.sol @@ -349,10 +349,9 @@ abstract contract HorizonStakingSharedTest is GraphBaseTest { verifier, serviceProvider ); - IHorizonStaking.ThawRequest memory beforeTailThawRequest = staking.getThawRequest(beforeThawRequestList.tail); bytes32 expectedThawRequestId = keccak256( - abi.encodePacked(users.indexer, subgraphDataServiceAddress, users.indexer, uint256(0)) + abi.encodePacked(users.indexer, subgraphDataServiceAddress, users.indexer, beforeThawRequestList.nonce) ); uint256 thawingShares = beforeProvision.sharesThawing == 0 ? tokens @@ -380,6 +379,7 @@ abstract contract HorizonStakingSharedTest is GraphBaseTest { verifier, serviceProvider ); + IHorizonStaking.ThawRequest memory afterPreviousTailThawRequest = staking.getThawRequest(beforeThawRequestList.tail); // assert assertEq(afterProvision.tokens, beforeProvision.tokens); @@ -400,8 +400,9 @@ abstract contract HorizonStakingSharedTest is GraphBaseTest { ); assertEq(afterThawRequestList.tail, thawRequestId); assertEq(afterThawRequestList.count, beforeThawRequestList.count + 1); + assertEq(afterThawRequestList.nonce, beforeThawRequestList.nonce + 1); if (beforeThawRequestList.count != 0) { - assertEq(beforeTailThawRequest.next, thawRequestId); + assertEq(afterPreviousTailThawRequest.next, thawRequestId); } return thawRequestId; diff --git a/packages/horizon/test/staking/provision/thaw.t.sol b/packages/horizon/test/staking/provision/thaw.t.sol index e69665ca5..9207f07cf 100644 --- a/packages/horizon/test/staking/provision/thaw.t.sol +++ b/packages/horizon/test/staking/provision/thaw.t.sol @@ -11,7 +11,7 @@ contract HorizonStakingThawTest is HorizonStakingTest { * TESTS */ - function testThaw_Tokenss( + function testThaw_TokensstestThaw_Tokenss( uint256 amount, uint64 thawingPeriod, uint256 thawAmount @@ -25,33 +25,23 @@ contract HorizonStakingThawTest is HorizonStakingTest { uint256 amount, uint64 thawingPeriod, uint256 thawAmount, - uint256 thawAmount2 + uint256 thawSteps ) public useIndexer useProvision(amount, 0, thawingPeriod) { - vm.assume(amount > 1); - thawAmount = bound(thawAmount, 1, amount - 1); - thawAmount2 = bound(thawAmount2, 1, amount - thawAmount); - bytes32 thawRequestId = _thaw(users.indexer, subgraphDataServiceAddress, thawAmount); - bytes32 thawRequestId2 = _thaw(users.indexer, subgraphDataServiceAddress, thawAmount2); - - ThawRequest memory thawRequest = staking.getThawRequest(thawRequestId); - assertEq(thawRequest.shares, thawAmount); - assertEq(thawRequest.thawingUntil, block.timestamp + thawingPeriod); - assertEq(thawRequest.next, thawRequestId2); + thawSteps = bound(thawSteps, 1, MAX_THAW_REQUESTS); + vm.assume(amount >= thawSteps); // ensure the provision has at least 1 token for each thaw step + thawAmount = bound(thawAmount, 1, amount); + uint256 individualThawAmount = amount / thawSteps; - ThawRequest memory thawRequest2 = staking.getThawRequest(thawRequestId2); - assertEq(thawRequest2.shares, thawAmount2); - assertEq(thawRequest2.thawingUntil, block.timestamp + thawingPeriod); + for (uint i = 0; i < thawSteps; i++) { + _thaw(users.indexer, subgraphDataServiceAddress, individualThawAmount); + } } function testThaw_OperatorCanStartThawing( uint256 amount, uint64 thawingPeriod - ) public useOperator useProvision(amount, 0, thawingPeriod) { - bytes32 thawRequestId = _thaw(users.indexer, subgraphDataServiceAddress, amount); - - ThawRequest memory thawRequest = staking.getThawRequest(thawRequestId); - assertEq(thawRequest.shares, amount); - assertEq(thawRequest.thawingUntil, block.timestamp + thawingPeriod); + ) public useIndexer useProvision(amount, 0, thawingPeriod) useOperator { + _thaw(users.indexer, subgraphDataServiceAddress, amount); } function testThaw_RevertWhen_OperatorNotAuthorized( @@ -66,7 +56,7 @@ contract HorizonStakingThawTest is HorizonStakingTest { subgraphDataServiceAddress ); vm.expectRevert(expectedError); - _thaw(users.indexer, subgraphDataServiceAddress, amount); + staking.thaw(users.indexer, subgraphDataServiceAddress, amount); } function testThaw_RevertWhen_InsufficientTokensAvailable( @@ -81,7 +71,7 @@ contract HorizonStakingThawTest is HorizonStakingTest { thawAmount ); vm.expectRevert(expectedError); - _thaw(users.indexer, subgraphDataServiceAddress, thawAmount); + staking.thaw(users.indexer, subgraphDataServiceAddress, thawAmount); } function testThaw_RevertWhen_OverMaxThawRequests( @@ -98,7 +88,7 @@ contract HorizonStakingThawTest is HorizonStakingTest { bytes memory expectedError = abi.encodeWithSignature("HorizonStakingTooManyThawRequests()"); vm.expectRevert(expectedError); - _thaw(users.indexer, subgraphDataServiceAddress, thawAmount); + staking.thaw(users.indexer, subgraphDataServiceAddress, thawAmount); } function testThaw_RevertWhen_ThawingZeroTokens( @@ -108,6 +98,6 @@ contract HorizonStakingThawTest is HorizonStakingTest { uint256 thawAmount = 0 ether; bytes memory expectedError = abi.encodeWithSignature("HorizonStakingInvalidZeroTokens()"); vm.expectRevert(expectedError); - _thaw(users.indexer, subgraphDataServiceAddress, thawAmount); + staking.thaw(users.indexer, subgraphDataServiceAddress, thawAmount); } } From 78c281bbbaa9b44e7807b6992c68868d12800bb4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1s=20Migone?= Date: Wed, 28 Aug 2024 15:28:23 -0300 Subject: [PATCH 07/24] test: refactor deprovision test MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Tomás Migone --- packages/horizon/test/GraphBase.t.sol | 3 +- .../HorizonStakingShared.t.sol | 239 ++++++++++++++---- .../horizon/test/staking/HorizonStaking.t.sol | 12 +- .../test/staking/provision/deprovision.t.sol | 70 +++-- .../test/staking/provision/reprovision.t.sol | 42 +-- .../horizon/test/staking/provision/thaw.t.sol | 16 +- .../serviceProvider/serviceProvider.t.sol | 4 +- .../horizon/test/staking/stake/unstake.t.sol | 11 +- 8 files changed, 264 insertions(+), 133 deletions(-) diff --git a/packages/horizon/test/GraphBase.t.sol b/packages/horizon/test/GraphBase.t.sol index d9323f56b..d86a58cf7 100644 --- a/packages/horizon/test/GraphBase.t.sol +++ b/packages/horizon/test/GraphBase.t.sol @@ -14,6 +14,7 @@ import { GraphPayments } from "contracts/payments/GraphPayments.sol"; import { IHorizonStaking } from "contracts/interfaces/IHorizonStaking.sol"; import { HorizonStaking } from "contracts/staking/HorizonStaking.sol"; import { HorizonStakingExtension } from "contracts/staking/HorizonStakingExtension.sol"; +import { IHorizonStakingTypes } from "contracts/interfaces/internal/IHorizonStakingTypes.sol"; import { MockGRTToken } from "../contracts/mocks/MockGRTToken.sol"; import { EpochManagerMock } from "../contracts/mocks/EpochManagerMock.sol"; import { RewardsManagerMock } from "../contracts/mocks/RewardsManagerMock.sol"; @@ -22,7 +23,7 @@ import { Constants } from "./utils/Constants.sol"; import { Users } from "./utils/Users.sol"; import { Utils } from "./utils/Utils.sol"; -abstract contract GraphBaseTest is Utils, Constants { +abstract contract GraphBaseTest is IHorizonStakingTypes, Utils, Constants { /* * VARIABLES diff --git a/packages/horizon/test/shared/horizon-staking/HorizonStakingShared.t.sol b/packages/horizon/test/shared/horizon-staking/HorizonStakingShared.t.sol index 4ac6f7351..1b9303f97 100644 --- a/packages/horizon/test/shared/horizon-staking/HorizonStakingShared.t.sol +++ b/packages/horizon/test/shared/horizon-staking/HorizonStakingShared.t.sol @@ -5,15 +5,14 @@ import "forge-std/Test.sol"; import { GraphBaseTest } from "../../GraphBase.t.sol"; import { IGraphPayments } from "../../../contracts/interfaces/IGraphPayments.sol"; -import { IHorizonStaking } from "../../../contracts/interfaces/IHorizonStaking.sol"; import { IHorizonStakingBase } from "../../../contracts/interfaces/internal/IHorizonStakingBase.sol"; import { IHorizonStakingMain } from "../../../contracts/interfaces/internal/IHorizonStakingMain.sol"; -import { IHorizonStakingTypes } from "../../../contracts/interfaces/internal/IHorizonStakingTypes.sol"; import { LinkedList } from "../../../contracts/libraries/LinkedList.sol"; import { MathUtils } from "../../../contracts/libraries/MathUtils.sol"; abstract contract HorizonStakingSharedTest is GraphBaseTest { + using LinkedList for LinkedList.List; /* * MODIFIERS */ @@ -106,9 +105,7 @@ abstract contract HorizonStakingSharedTest is GraphBaseTest { // before uint256 beforeStakingBalance = token.balanceOf(address(staking)); uint256 beforeSenderBalance = token.balanceOf(msgSender); - IHorizonStaking.ServiceProviderInternal memory beforeServiceProvider = _getStorage_ServiceProviderInternal( - serviceProvider - ); + ServiceProviderInternal memory beforeServiceProvider = _getStorage_ServiceProviderInternal(serviceProvider); // stakeTo token.approve(address(staking), tokens); @@ -119,9 +116,7 @@ abstract contract HorizonStakingSharedTest is GraphBaseTest { // after uint256 afterStakingBalance = token.balanceOf(address(staking)); uint256 afterSenderBalance = token.balanceOf(msgSender); - IHorizonStaking.ServiceProviderInternal memory afterServiceProvider = _getStorage_ServiceProviderInternal( - serviceProvider - ); + ServiceProviderInternal memory afterServiceProvider = _getStorage_ServiceProviderInternal(serviceProvider); // assert assertEq(afterStakingBalance, beforeStakingBalance + tokens); @@ -144,9 +139,7 @@ abstract contract HorizonStakingSharedTest is GraphBaseTest { // before uint256 beforeSenderBalance = token.balanceOf(msgSender); uint256 beforeStakingBalance = token.balanceOf(address(staking)); - IHorizonStaking.ServiceProviderInternal memory beforeServiceProvider = _getStorage_ServiceProviderInternal( - msgSender - ); + ServiceProviderInternal memory beforeServiceProvider = _getStorage_ServiceProviderInternal(msgSender); bool withdrawCalled = beforeServiceProvider.__DEPRECATED_tokensLocked != 0 && block.number >= beforeServiceProvider.__DEPRECATED_tokensLockedUntil; @@ -185,9 +178,7 @@ abstract contract HorizonStakingSharedTest is GraphBaseTest { // after uint256 afterSenderBalance = token.balanceOf(msgSender); uint256 afterStakingBalance = token.balanceOf(address(staking)); - IHorizonStaking.ServiceProviderInternal memory afterServiceProvider = _getStorage_ServiceProviderInternal( - msgSender - ); + ServiceProviderInternal memory afterServiceProvider = _getStorage_ServiceProviderInternal(msgSender); // assert if (deprecatedThawingPeriod == 0) { @@ -231,9 +222,7 @@ abstract contract HorizonStakingSharedTest is GraphBaseTest { (, address msgSender, ) = vm.readCallers(); // before - IHorizonStaking.ServiceProviderInternal memory beforeServiceProvider = _getStorage_ServiceProviderInternal( - msgSender - ); + ServiceProviderInternal memory beforeServiceProvider = _getStorage_ServiceProviderInternal(msgSender); uint256 beforeSenderBalance = token.balanceOf(msgSender); uint256 beforeStakingBalance = token.balanceOf(address(staking)); @@ -243,9 +232,7 @@ abstract contract HorizonStakingSharedTest is GraphBaseTest { staking.withdraw(); // after - IHorizonStaking.ServiceProviderInternal memory afterServiceProvider = _getStorage_ServiceProviderInternal( - msgSender - ); + ServiceProviderInternal memory afterServiceProvider = _getStorage_ServiceProviderInternal(msgSender); uint256 afterSenderBalance = token.balanceOf(msgSender); uint256 afterStakingBalance = token.balanceOf(address(staking)); @@ -270,9 +257,7 @@ abstract contract HorizonStakingSharedTest is GraphBaseTest { uint64 thawingPeriod ) internal { // before - IHorizonStaking.ServiceProviderInternal memory beforeServiceProvider = _getStorage_ServiceProviderInternal( - serviceProvider - ); + ServiceProviderInternal memory beforeServiceProvider = _getStorage_ServiceProviderInternal(serviceProvider); // provision vm.expectEmit(); @@ -280,10 +265,8 @@ abstract contract HorizonStakingSharedTest is GraphBaseTest { staking.provision(serviceProvider, verifier, tokens, maxVerifierCut, thawingPeriod); // after - IHorizonStaking.Provision memory afterProvision = staking.getProvision(serviceProvider, verifier); - IHorizonStaking.ServiceProviderInternal memory afterServiceProvider = _getStorage_ServiceProviderInternal( - serviceProvider - ); + Provision memory afterProvision = staking.getProvision(serviceProvider, verifier); + ServiceProviderInternal memory afterServiceProvider = _getStorage_ServiceProviderInternal(serviceProvider); // assert assertEq(afterProvision.tokens, tokens); @@ -306,10 +289,8 @@ abstract contract HorizonStakingSharedTest is GraphBaseTest { function _addToProvision(address serviceProvider, address verifier, uint256 tokens) internal { // before - IHorizonStaking.Provision memory beforeProvision = staking.getProvision(serviceProvider, verifier); - IHorizonStaking.ServiceProviderInternal memory beforeServiceProvider = _getStorage_ServiceProviderInternal( - serviceProvider - ); + Provision memory beforeProvision = staking.getProvision(serviceProvider, verifier); + ServiceProviderInternal memory beforeServiceProvider = _getStorage_ServiceProviderInternal(serviceProvider); // addToProvision vm.expectEmit(); @@ -317,10 +298,8 @@ abstract contract HorizonStakingSharedTest is GraphBaseTest { staking.addToProvision(serviceProvider, verifier, tokens); // after - IHorizonStaking.Provision memory afterProvision = staking.getProvision(serviceProvider, verifier); - IHorizonStaking.ServiceProviderInternal memory afterServiceProvider = _getStorage_ServiceProviderInternal( - serviceProvider - ); + Provision memory afterProvision = staking.getProvision(serviceProvider, verifier); + ServiceProviderInternal memory afterServiceProvider = _getStorage_ServiceProviderInternal(serviceProvider); // assert assertEq(afterProvision.tokens, beforeProvision.tokens + tokens); @@ -343,7 +322,7 @@ abstract contract HorizonStakingSharedTest is GraphBaseTest { function _thaw(address serviceProvider, address verifier, uint256 tokens) internal returns (bytes32) { // before - IHorizonStaking.Provision memory beforeProvision = staking.getProvision(serviceProvider, verifier); + Provision memory beforeProvision = staking.getProvision(serviceProvider, verifier); LinkedList.List memory beforeThawRequestList = staking.getThawRequestList( serviceProvider, verifier, @@ -372,14 +351,14 @@ abstract contract HorizonStakingSharedTest is GraphBaseTest { bytes32 thawRequestId = staking.thaw(serviceProvider, verifier, tokens); // after - IHorizonStaking.Provision memory afterProvision = staking.getProvision(serviceProvider, verifier); - IHorizonStaking.ThawRequest memory afterThawRequest = staking.getThawRequest(thawRequestId); + Provision memory afterProvision = staking.getProvision(serviceProvider, verifier); + ThawRequest memory afterThawRequest = staking.getThawRequest(thawRequestId); LinkedList.List memory afterThawRequestList = staking.getThawRequestList( serviceProvider, verifier, serviceProvider ); - IHorizonStaking.ThawRequest memory afterPreviousTailThawRequest = staking.getThawRequest(beforeThawRequestList.tail); + ThawRequest memory afterPreviousTailThawRequest = staking.getThawRequest(beforeThawRequestList.tail); // assert assertEq(afterProvision.tokens, beforeProvision.tokens); @@ -408,8 +387,98 @@ abstract contract HorizonStakingSharedTest is GraphBaseTest { return thawRequestId; } - function _deprovision(uint256 nThawRequests) internal { - staking.deprovision(users.indexer, subgraphDataServiceAddress, nThawRequests); + function _deprovision(address serviceProvider, address verifier, uint256 nThawRequests) internal { + // before + Provision memory beforeProvision = staking.getProvision(serviceProvider, verifier); + ServiceProviderInternal memory beforeServiceProvider = _getStorage_ServiceProviderInternal(serviceProvider); + LinkedList.List memory beforeThawRequestList = staking.getThawRequestList( + serviceProvider, + verifier, + serviceProvider + ); + + ( + uint256 calcTokensThawed, + uint256 calcTokensThawing, + uint256 calcSharesThawing, + ThawRequest[] memory calcThawRequestsFulfilledList, + bytes32[] memory calcThawRequestsFulfilledListIds, + uint256[] memory calcThawRequestsFulfilledListTokens + ) = calcThawRequestData(serviceProvider, verifier, serviceProvider, nThawRequests); + + // deprovision + for (uint i = 0; i < calcThawRequestsFulfilledList.length; i++) { + ThawRequest memory thawRequest = calcThawRequestsFulfilledList[i]; + vm.expectEmit(address(staking)); + emit IHorizonStakingMain.ThawRequestFulfilled( + calcThawRequestsFulfilledListIds[i], + calcThawRequestsFulfilledListTokens[i], + thawRequest.shares, + thawRequest.thawingUntil + ); + } + vm.expectEmit(address(staking)); + emit IHorizonStakingMain.ThawRequestsFulfilled( + serviceProvider, + verifier, + serviceProvider, + calcThawRequestsFulfilledList.length, + calcTokensThawed + ); + vm.expectEmit(address(staking)); + emit IHorizonStakingMain.TokensDeprovisioned(serviceProvider, verifier, calcTokensThawed); + staking.deprovision(serviceProvider, verifier, nThawRequests); + + // after + Provision memory afterProvision = staking.getProvision(serviceProvider, verifier); + ServiceProviderInternal memory afterServiceProvider = _getStorage_ServiceProviderInternal(serviceProvider); + LinkedList.List memory afterThawRequestList = staking.getThawRequestList( + serviceProvider, + verifier, + serviceProvider + ); + + // assert + assertEq(afterProvision.tokens, beforeProvision.tokens - calcTokensThawed); + assertEq(afterProvision.tokensThawing, calcTokensThawing); + assertEq(afterProvision.sharesThawing, calcSharesThawing); + assertEq(afterProvision.maxVerifierCut, beforeProvision.maxVerifierCut); + assertEq(afterProvision.thawingPeriod, beforeProvision.thawingPeriod); + assertEq(afterProvision.createdAt, beforeProvision.createdAt); + assertEq(afterProvision.maxVerifierCutPending, beforeProvision.maxVerifierCutPending); + assertEq(afterProvision.thawingPeriodPending, beforeProvision.thawingPeriodPending); + assertEq(afterServiceProvider.tokensStaked, beforeServiceProvider.tokensStaked); + assertEq(afterServiceProvider.tokensProvisioned, beforeServiceProvider.tokensProvisioned - calcTokensThawed); + assertEq(afterServiceProvider.__DEPRECATED_tokensAllocated, beforeServiceProvider.__DEPRECATED_tokensAllocated); + assertEq(afterServiceProvider.__DEPRECATED_tokensLocked, beforeServiceProvider.__DEPRECATED_tokensLocked); + assertEq( + afterServiceProvider.__DEPRECATED_tokensLockedUntil, + beforeServiceProvider.__DEPRECATED_tokensLockedUntil + ); + for (uint i = 0; i < calcThawRequestsFulfilledListIds.length; i++) { + ThawRequest memory thawRequest = staking.getThawRequest(calcThawRequestsFulfilledListIds[i]); + assertEq(thawRequest.shares, 0); + assertEq(thawRequest.thawingUntil, 0); + assertEq(thawRequest.next, bytes32(0)); + } + if (calcThawRequestsFulfilledList.length == 0) { + assertEq(afterThawRequestList.head, beforeThawRequestList.head); + } else { + assertEq( + afterThawRequestList.head, + calcThawRequestsFulfilledList.length == beforeThawRequestList.count + ? bytes32(0) + : calcThawRequestsFulfilledList[calcThawRequestsFulfilledList.length - 1].next + ); + } + assertEq( + afterThawRequestList.tail, + calcThawRequestsFulfilledList.length == beforeThawRequestList.count + ? bytes32(0) + : beforeThawRequestList.tail + ); + assertEq(afterThawRequestList.count, beforeThawRequestList.count - calcThawRequestsFulfilledList.length); + assertEq(afterThawRequestList.nonce, beforeThawRequestList.nonce); } /* @@ -417,18 +486,17 @@ abstract contract HorizonStakingSharedTest is GraphBaseTest { */ function _getStorage_ServiceProviderInternal( address serviceProvider - ) internal view returns (IHorizonStaking.ServiceProviderInternal memory) { + ) internal view returns (ServiceProviderInternal memory) { uint256 slotNumber = 14; uint256 baseSlotUint = uint256(keccak256(abi.encode(serviceProvider, slotNumber))); - IHorizonStakingTypes.ServiceProviderInternal memory serviceProviderInternal = IHorizonStakingTypes - .ServiceProviderInternal({ - tokensStaked: uint256(vm.load(address(staking), bytes32(baseSlotUint))), - __DEPRECATED_tokensAllocated: uint256(vm.load(address(staking), bytes32(baseSlotUint + 1))), - __DEPRECATED_tokensLocked: uint256(vm.load(address(staking), bytes32(baseSlotUint + 2))), - __DEPRECATED_tokensLockedUntil: uint256(vm.load(address(staking), bytes32(baseSlotUint + 3))), - tokensProvisioned: uint256(vm.load(address(staking), bytes32(baseSlotUint + 4))) - }); + ServiceProviderInternal memory serviceProviderInternal = ServiceProviderInternal({ + tokensStaked: uint256(vm.load(address(staking), bytes32(baseSlotUint))), + __DEPRECATED_tokensAllocated: uint256(vm.load(address(staking), bytes32(baseSlotUint + 1))), + __DEPRECATED_tokensLocked: uint256(vm.load(address(staking), bytes32(baseSlotUint + 2))), + __DEPRECATED_tokensLockedUntil: uint256(vm.load(address(staking), bytes32(baseSlotUint + 3))), + tokensProvisioned: uint256(vm.load(address(staking), bytes32(baseSlotUint + 4))) + }); return serviceProviderInternal; } @@ -455,4 +523,75 @@ abstract contract HorizonStakingSharedTest is GraphBaseTest { vm.store(address(staking), bytes32(uint256(serviceProviderBaseSlot) + 3), bytes32(_tokensLockedUntil)); vm.store(address(staking), bytes32(uint256(serviceProviderBaseSlot) + 4), bytes32(_tokensProvisioned)); } + + /* + * MISC: private functions to help with testing + */ + function calcThawRequestData( + address serviceProvider, + address verifier, + address owner, + uint256 iterations + ) private view returns (uint256, uint256, uint256, ThawRequest[] memory, bytes32[] memory, uint256[] memory) { + LinkedList.List memory thawRequestList = staking.getThawRequestList(serviceProvider, verifier, owner); + if (thawRequestList.count == 0) { + return (0, 0, 0, new ThawRequest[](0), new bytes32[](0), new uint256[](0)); + } + + Provision memory prov = staking.getProvision(serviceProvider, verifier); + + uint256 tokensThawed = 0; + uint256 tokensThawing = prov.tokensThawing; + uint256 sharesThawing = prov.sharesThawing; + uint256 thawRequestsFulfilled = 0; + + bytes32 thawRequestId = thawRequestList.head; + while (thawRequestId != bytes32(0) && (iterations == 0 || thawRequestsFulfilled < iterations)) { + ThawRequest memory thawRequest = staking.getThawRequest(thawRequestId); + if (thawRequest.thawingUntil <= block.timestamp) { + thawRequestsFulfilled++; + uint256 tokens = (thawRequest.shares * prov.tokensThawing) / prov.sharesThawing; + tokensThawed += tokens; + tokensThawing -= tokens; + sharesThawing -= thawRequest.shares; + } else { + break; + } + thawRequestId = thawRequest.next; + } + + // we need to do a second pass because solidity doesnt allow dynamic arrays on memory + ThawRequest[] memory thawRequestsFulfilledList = new ThawRequest[](thawRequestsFulfilled); + bytes32[] memory thawRequestsFulfilledListIds = new bytes32[](thawRequestsFulfilled); + uint256[] memory thawRequestsFulfilledListTokens = new uint256[](thawRequestsFulfilled); + uint256 i = 0; + thawRequestId = thawRequestList.head; + while (thawRequestId != bytes32(0) && (iterations == 0 || i < iterations)) { + ThawRequest memory thawRequest = staking.getThawRequest(thawRequestId); + if (thawRequest.thawingUntil <= block.timestamp) { + uint256 tokens = (thawRequest.shares * prov.tokensThawing) / prov.sharesThawing; + thawRequestsFulfilledListTokens[i] = tokens; + thawRequestsFulfilledListIds[i] = thawRequestId; + thawRequestsFulfilledList[i] = staking.getThawRequest(thawRequestId); + thawRequestId = thawRequestsFulfilledList[i].next; + i++; + } else { + break; + } + thawRequestId = thawRequest.next; + } + + assertEq(thawRequestsFulfilled, thawRequestsFulfilledList.length); + assertEq(thawRequestsFulfilled, thawRequestsFulfilledListIds.length); + assertEq(thawRequestsFulfilled, thawRequestsFulfilledListTokens.length); + + return ( + tokensThawed, + tokensThawing, + sharesThawing, + thawRequestsFulfilledList, + thawRequestsFulfilledListIds, + thawRequestsFulfilledListTokens + ); + } } diff --git a/packages/horizon/test/staking/HorizonStaking.t.sol b/packages/horizon/test/staking/HorizonStaking.t.sol index 8effc5762..c8a0a2e5e 100644 --- a/packages/horizon/test/staking/HorizonStaking.t.sol +++ b/packages/horizon/test/staking/HorizonStaking.t.sol @@ -5,13 +5,12 @@ import "forge-std/Test.sol"; import { stdStorage, StdStorage } from "forge-std/Test.sol"; import { IHorizonStakingMain } from "../../contracts/interfaces/internal/IHorizonStakingMain.sol"; -import { IHorizonStakingTypes } from "../../contracts/interfaces/internal/IHorizonStakingTypes.sol"; import { LinkedList } from "../../contracts/libraries/LinkedList.sol"; import { MathUtils } from "../../contracts/libraries/MathUtils.sol"; import { HorizonStakingSharedTest } from "../shared/horizon-staking/HorizonStakingShared.t.sol"; -contract HorizonStakingTest is HorizonStakingSharedTest, IHorizonStakingTypes { +contract HorizonStakingTest is HorizonStakingSharedTest { using stdStorage for StdStorage; /* @@ -25,17 +24,11 @@ contract HorizonStakingTest is HorizonStakingSharedTest, IHorizonStakingTypes { _; } - modifier useThawRequest(uint256 thawAmount) { - vm.assume(thawAmount > 0); - _thaw(users.indexer, subgraphDataServiceAddress, thawAmount); - _; - } - modifier useThawAndDeprovision(uint256 amount, uint64 thawingPeriod) { vm.assume(amount > 0); _thaw(users.indexer, subgraphDataServiceAddress, amount); skip(thawingPeriod + 1); - _deprovision(0); + _deprovision(users.indexer, subgraphDataServiceAddress, 0); _; } @@ -81,6 +74,7 @@ contract HorizonStakingTest is HorizonStakingSharedTest, IHorizonStakingTypes { } + // struct required to avoid stack too deep errors >.< struct DelegateData { DelegationPool pool; Delegation delegation; diff --git a/packages/horizon/test/staking/provision/deprovision.t.sol b/packages/horizon/test/staking/provision/deprovision.t.sol index 28780c82f..a790970c6 100644 --- a/packages/horizon/test/staking/provision/deprovision.t.sol +++ b/packages/horizon/test/staking/provision/deprovision.t.sol @@ -6,7 +6,6 @@ import "forge-std/Test.sol"; import { HorizonStakingTest } from "../HorizonStaking.t.sol"; contract HorizonStakingDeprovisionTest is HorizonStakingTest { - /* * TESTS */ @@ -14,52 +13,65 @@ contract HorizonStakingDeprovisionTest is HorizonStakingTest { function testDeprovision_AllRequests( uint256 amount, uint32 maxVerifierCut, - uint64 thawingPeriod - ) public useIndexer useProvision(amount, maxVerifierCut, thawingPeriod) useThawRequest(amount) { + uint64 thawingPeriod, + uint256 thawCount, + uint256 deprovisionCount + ) public useIndexer useProvision(amount, maxVerifierCut, thawingPeriod) { + thawCount = bound(thawCount, 1, MAX_THAW_REQUESTS); + deprovisionCount = bound(deprovisionCount, 0, thawCount); + vm.assume(amount >= thawCount); // ensure the provision has at least 1 token for each thaw step + uint256 individualThawAmount = amount / thawCount; + + for (uint i = 0; i < thawCount; i++) { + _thaw(users.indexer, subgraphDataServiceAddress, individualThawAmount); + } + skip(thawingPeriod + 1); - // nThawRequests == 0 removes all thaw requests - _deprovision(0); - uint256 idleStake = staking.getIdleStake(users.indexer); - assertEq(idleStake, amount); + _deprovision(users.indexer, subgraphDataServiceAddress, deprovisionCount); } - function testDeprovision_FirstRequestOnly( + function testDeprovision_ThawedRequests( uint256 amount, uint32 maxVerifierCut, uint64 thawingPeriod, - uint256 thawAmount + uint256 thawCount ) public useIndexer useProvision(amount, maxVerifierCut, thawingPeriod) { - vm.assume(amount > 1); - thawAmount = bound(thawAmount, 2, amount); - uint256 thawAmount1 = thawAmount / 2; - _thaw(users.indexer, subgraphDataServiceAddress, thawAmount1); - _thaw(users.indexer, subgraphDataServiceAddress, thawAmount - thawAmount1); + thawCount = bound(thawCount, 2, MAX_THAW_REQUESTS); + vm.assume(amount >= thawCount); // ensure the provision has at least 1 token for each thaw step + uint256 individualThawAmount = amount / thawCount; + + for (uint i = 0; i < thawCount / 2; i++) { + _thaw(users.indexer, subgraphDataServiceAddress, individualThawAmount); + } skip(thawingPeriod + 1); - _deprovision(1); - uint256 idleStake = staking.getIdleStake(users.indexer); - assertEq(idleStake, thawAmount1); + for (uint i = 0; i < thawCount / 2; i++) { + _thaw(users.indexer, subgraphDataServiceAddress, individualThawAmount); + } + + _deprovision(users.indexer, subgraphDataServiceAddress, 0); } function testDeprovision_OperatorMovingTokens( uint256 amount, uint32 maxVerifierCut, uint64 thawingPeriod - ) public useOperator useProvision(amount, maxVerifierCut, thawingPeriod) useThawRequest(amount) { + ) public useIndexer useProvision(amount, maxVerifierCut, thawingPeriod) useOperator { + _thaw(users.indexer, subgraphDataServiceAddress, amount); skip(thawingPeriod + 1); - _deprovision(0); - uint256 idleStake = staking.getIdleStake(users.indexer); - assertEq(idleStake, amount); + _deprovision(users.indexer, subgraphDataServiceAddress, 0); } function testDeprovision_RevertWhen_OperatorNotAuthorized( uint256 amount, uint32 maxVerifierCut, uint64 thawingPeriod - ) public useIndexer useProvision(amount, maxVerifierCut, thawingPeriod) useThawRequest(amount) { + ) public useIndexer useProvision(amount, maxVerifierCut, thawingPeriod) { + _thaw(users.indexer, subgraphDataServiceAddress, amount); + vm.startPrank(users.operator); bytes memory expectedError = abi.encodeWithSignature( "HorizonStakingNotAuthorized(address,address,address)", @@ -68,8 +80,9 @@ contract HorizonStakingDeprovisionTest is HorizonStakingTest { subgraphDataServiceAddress ); vm.expectRevert(expectedError); - _deprovision(0); + staking.deprovision(users.indexer, subgraphDataServiceAddress, 0); } + function testDeprovision_RevertWhen_NoThawingTokens( uint256 amount, uint32 maxVerifierCut, @@ -77,17 +90,20 @@ contract HorizonStakingDeprovisionTest is HorizonStakingTest { ) public useIndexer useProvision(amount, maxVerifierCut, thawingPeriod) { bytes memory expectedError = abi.encodeWithSignature("HorizonStakingNothingThawing()"); vm.expectRevert(expectedError); - _deprovision(0); + staking.deprovision(users.indexer, subgraphDataServiceAddress, 0); } function testDeprovision_StillThawing( uint256 amount, uint32 maxVerifierCut, uint64 thawingPeriod - ) public useIndexer useProvision(amount, maxVerifierCut, thawingPeriod) useThawRequest(amount) { + ) public useIndexer useProvision(amount, maxVerifierCut, thawingPeriod) { vm.assume(thawingPeriod > 0); - _deprovision(0); + + _thaw(users.indexer, subgraphDataServiceAddress, amount); + + _deprovision(users.indexer, subgraphDataServiceAddress, 0); uint256 idleStake = staking.getIdleStake(users.indexer); assertEq(idleStake, 0); } -} \ No newline at end of file +} diff --git a/packages/horizon/test/staking/provision/reprovision.t.sol b/packages/horizon/test/staking/provision/reprovision.t.sol index 51cd154c9..d5724a12d 100644 --- a/packages/horizon/test/staking/provision/reprovision.t.sol +++ b/packages/horizon/test/staking/provision/reprovision.t.sol @@ -6,7 +6,6 @@ import "forge-std/Test.sol"; import { HorizonStakingTest } from "../HorizonStaking.t.sol"; contract HorizonStakingReprovisionTest is HorizonStakingTest { - /* * VARIABLES */ @@ -28,12 +27,8 @@ contract HorizonStakingReprovisionTest is HorizonStakingTest { function testReprovision_MovingTokens( uint64 thawingPeriod, uint256 provisionAmount - ) - public - useIndexer - useProvision(provisionAmount, 0, thawingPeriod) - useThawRequest(provisionAmount) - { + ) public useIndexer useProvision(provisionAmount, 0, thawingPeriod) { + _thaw(users.indexer, subgraphDataServiceAddress, provisionAmount); skip(thawingPeriod + 1); _createProvision(users.indexer, newDataService, 1 ether, 0, thawingPeriod); @@ -50,18 +45,14 @@ contract HorizonStakingReprovisionTest is HorizonStakingTest { function testReprovision_OperatorMovingTokens( uint64 thawingPeriod, uint256 provisionAmount - ) - public - useOperator - useProvision(provisionAmount, 0, thawingPeriod) - useThawRequest(provisionAmount) - { + ) public useOperator useProvision(provisionAmount, 0, thawingPeriod) { + _thaw(users.indexer, subgraphDataServiceAddress, provisionAmount); skip(thawingPeriod + 1); // Switch to indexer to set operator for new data service vm.startPrank(users.indexer); staking.setOperator(users.operator, newDataService, true); - + // Switch back to operator vm.startPrank(users.operator); _createProvision(users.indexer, newDataService, 1 ether, 0, thawingPeriod); @@ -75,12 +66,9 @@ contract HorizonStakingReprovisionTest is HorizonStakingTest { function testReprovision_RevertWhen_OperatorNotAuthorizedForNewDataService( uint256 provisionAmount - ) - public - useOperator - useProvision(provisionAmount, 0, 0) - useThawRequest(provisionAmount) - { + ) public useOperator useProvision(provisionAmount, 0, 0) { + _thaw(users.indexer, subgraphDataServiceAddress, provisionAmount); + // Switch to indexer to create new provision vm.startPrank(users.indexer); _createProvision(users.indexer, newDataService, 1 ether, 0, 0); @@ -97,9 +85,7 @@ contract HorizonStakingReprovisionTest is HorizonStakingTest { _reprovision(provisionAmount, 0); } - function testReprovision_RevertWhen_NoThawingTokens( - uint256 amount - ) public useIndexer useProvision(amount, 0, 0) { + function testReprovision_RevertWhen_NoThawingTokens(uint256 amount) public useIndexer useProvision(amount, 0, 0) { bytes memory expectedError = abi.encodeWithSignature("HorizonStakingNothingThawing()"); vm.expectRevert(expectedError); _reprovision(amount, 0); @@ -108,13 +94,9 @@ contract HorizonStakingReprovisionTest is HorizonStakingTest { function testReprovision_RevertWhen_StillThawing( uint64 thawingPeriod, uint256 provisionAmount - ) - public - useIndexer - useProvision(provisionAmount, 0, thawingPeriod) - useThawRequest(provisionAmount) - { + ) public useIndexer useProvision(provisionAmount, 0, thawingPeriod) { vm.assume(thawingPeriod > 0); + _thaw(users.indexer, subgraphDataServiceAddress, provisionAmount); _createProvision(users.indexer, newDataService, 1 ether, 0, thawingPeriod); @@ -126,4 +108,4 @@ contract HorizonStakingReprovisionTest is HorizonStakingTest { vm.expectRevert(expectedError); _reprovision(provisionAmount, 0); } -} \ No newline at end of file +} diff --git a/packages/horizon/test/staking/provision/thaw.t.sol b/packages/horizon/test/staking/provision/thaw.t.sol index 9207f07cf..d3faf350a 100644 --- a/packages/horizon/test/staking/provision/thaw.t.sol +++ b/packages/horizon/test/staking/provision/thaw.t.sol @@ -11,7 +11,7 @@ contract HorizonStakingThawTest is HorizonStakingTest { * TESTS */ - function testThaw_TokensstestThaw_Tokenss( + function testThaw_Tokens( uint256 amount, uint64 thawingPeriod, uint256 thawAmount @@ -24,15 +24,13 @@ contract HorizonStakingThawTest is HorizonStakingTest { function testThaw_MultipleRequests( uint256 amount, uint64 thawingPeriod, - uint256 thawAmount, - uint256 thawSteps + uint256 thawCount ) public useIndexer useProvision(amount, 0, thawingPeriod) { - thawSteps = bound(thawSteps, 1, MAX_THAW_REQUESTS); - vm.assume(amount >= thawSteps); // ensure the provision has at least 1 token for each thaw step - thawAmount = bound(thawAmount, 1, amount); - uint256 individualThawAmount = amount / thawSteps; + thawCount = bound(thawCount, 1, MAX_THAW_REQUESTS); + vm.assume(amount >= thawCount); // ensure the provision has at least 1 token for each thaw step + uint256 individualThawAmount = amount / thawCount; - for (uint i = 0; i < thawSteps; i++) { + for (uint i = 0; i < thawCount; i++) { _thaw(users.indexer, subgraphDataServiceAddress, individualThawAmount); } } @@ -82,7 +80,7 @@ contract HorizonStakingThawTest is HorizonStakingTest { vm.assume(amount >= MAX_THAW_REQUESTS + 1); thawAmount = bound(thawAmount, 1, amount / (MAX_THAW_REQUESTS + 1)); - for (uint256 i = 0; i < 100; i++) { + for (uint256 i = 0; i < MAX_THAW_REQUESTS; i++) { _thaw(users.indexer, subgraphDataServiceAddress, thawAmount); } diff --git a/packages/horizon/test/staking/serviceProvider/serviceProvider.t.sol b/packages/horizon/test/staking/serviceProvider/serviceProvider.t.sol index 8412331c6..3a90c7718 100644 --- a/packages/horizon/test/staking/serviceProvider/serviceProvider.t.sol +++ b/packages/horizon/test/staking/serviceProvider/serviceProvider.t.sol @@ -108,7 +108,7 @@ contract HorizonStakingServiceProviderTest is HorizonStakingTest { _thaw(users.indexer, subgraphDataServiceAddress, amount); skip(MAX_THAWING_PERIOD + 1); - _deprovision(0); + _deprovision(users.indexer, subgraphDataServiceAddress, 0); staking.unstake(amount); assertFalse(staking.hasStake(users.indexer)); @@ -124,7 +124,7 @@ contract HorizonStakingServiceProviderTest is HorizonStakingTest { assertEq(staking.getIndexerStakedTokens(users.indexer), amount); skip(MAX_THAWING_PERIOD + 1); - _deprovision(0); + _deprovision(users.indexer, subgraphDataServiceAddress, 0); // Does not discount thawing tokens assertEq(staking.getIndexerStakedTokens(users.indexer), amount); diff --git a/packages/horizon/test/staking/stake/unstake.t.sol b/packages/horizon/test/staking/stake/unstake.t.sol index 5c14f6437..9a3970cb7 100644 --- a/packages/horizon/test/staking/stake/unstake.t.sol +++ b/packages/horizon/test/staking/stake/unstake.t.sol @@ -21,7 +21,7 @@ contract HorizonStakingUnstakeTest is HorizonStakingTest { // thaw, wait and deprovision _thaw(users.indexer, subgraphDataServiceAddress, tokens); skip(thawingPeriod + 1); - _deprovision(0); + _deprovision(users.indexer, subgraphDataServiceAddress, 0); _unstake(tokensToUnstake); } @@ -40,7 +40,7 @@ contract HorizonStakingUnstakeTest is HorizonStakingTest { // thaw, wait and deprovision _thaw(users.indexer, subgraphDataServiceAddress, tokens); skip(thawingPeriod + 1); - _deprovision(0); + _deprovision(users.indexer, subgraphDataServiceAddress, 0); // unstake _unstake(tokensToUnstake); @@ -65,7 +65,7 @@ contract HorizonStakingUnstakeTest is HorizonStakingTest { _createProvision(users.indexer, subgraphDataServiceAddress, tokens, 0, MAX_THAWING_PERIOD); _thaw(users.indexer, subgraphDataServiceAddress, tokens); skip(MAX_THAWING_PERIOD + 1); - _deprovision(0); + _deprovision(users.indexer, subgraphDataServiceAddress, 0); // unstake _unstake(tokensToUnstake); @@ -93,7 +93,7 @@ contract HorizonStakingUnstakeTest is HorizonStakingTest { _createProvision(users.indexer, subgraphDataServiceAddress, tokens, 0, MAX_THAWING_PERIOD); _thaw(users.indexer, subgraphDataServiceAddress, tokens); skip(MAX_THAWING_PERIOD + 1); - _deprovision(0); + _deprovision(users.indexer, subgraphDataServiceAddress, 0); // unstake _unstake(tokensToUnstake); @@ -132,7 +132,8 @@ contract HorizonStakingUnstakeTest is HorizonStakingTest { uint256 amount, uint32 maxVerifierCut, uint64 thawingPeriod - ) public useIndexer useProvision(amount, maxVerifierCut, thawingPeriod) useThawRequest(amount) { + ) public useIndexer useProvision(amount, maxVerifierCut, thawingPeriod) { + _thaw(users.indexer, subgraphDataServiceAddress, amount); skip(thawingPeriod + 1); bytes memory expectedError = abi.encodeWithSignature( From b16b1699d9ea3cd94d3ea45c9c84e83ab360694f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1s=20Migone?= Date: Wed, 28 Aug 2024 16:26:45 -0300 Subject: [PATCH 08/24] test: refactor reprovision tests MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Tomás Migone --- .../HorizonStakingShared.t.sol | 118 ++++++++++++++++++ .../test/staking/provision/deprovision.t.sol | 2 - .../test/staking/provision/reprovision.t.sol | 49 ++++---- 3 files changed, 144 insertions(+), 25 deletions(-) diff --git a/packages/horizon/test/shared/horizon-staking/HorizonStakingShared.t.sol b/packages/horizon/test/shared/horizon-staking/HorizonStakingShared.t.sol index 1b9303f97..0f3dc95cc 100644 --- a/packages/horizon/test/shared/horizon-staking/HorizonStakingShared.t.sol +++ b/packages/horizon/test/shared/horizon-staking/HorizonStakingShared.t.sol @@ -481,6 +481,124 @@ abstract contract HorizonStakingSharedTest is GraphBaseTest { assertEq(afterThawRequestList.nonce, beforeThawRequestList.nonce); } + function _reprovision( + address serviceProvider, + address verifier, + address newVerifier, + uint256 tokens, + uint256 nThawRequests + ) internal { + // before + Provision memory beforeProvision = staking.getProvision(serviceProvider, verifier); + Provision memory beforeProvisionNewVerifier = staking.getProvision(serviceProvider, newVerifier); + ServiceProviderInternal memory beforeServiceProvider = _getStorage_ServiceProviderInternal(serviceProvider); + LinkedList.List memory beforeThawRequestList = staking.getThawRequestList( + serviceProvider, + verifier, + serviceProvider + ); + + ( + uint256 calcTokensThawed, + uint256 calcTokensThawing, + uint256 calcSharesThawing, + ThawRequest[] memory calcThawRequestsFulfilledList, + bytes32[] memory calcThawRequestsFulfilledListIds, + uint256[] memory calcThawRequestsFulfilledListTokens + ) = calcThawRequestData(serviceProvider, verifier, serviceProvider, nThawRequests); + + // reprovision + for (uint i = 0; i < calcThawRequestsFulfilledList.length; i++) { + ThawRequest memory thawRequest = calcThawRequestsFulfilledList[i]; + vm.expectEmit(address(staking)); + emit IHorizonStakingMain.ThawRequestFulfilled( + calcThawRequestsFulfilledListIds[i], + calcThawRequestsFulfilledListTokens[i], + thawRequest.shares, + thawRequest.thawingUntil + ); + } + vm.expectEmit(address(staking)); + emit IHorizonStakingMain.ThawRequestsFulfilled( + serviceProvider, + verifier, + serviceProvider, + calcThawRequestsFulfilledList.length, + calcTokensThawed + ); + vm.expectEmit(address(staking)); + emit IHorizonStakingMain.TokensDeprovisioned(serviceProvider, verifier, calcTokensThawed); + vm.expectEmit(); + emit IHorizonStakingMain.ProvisionIncreased(serviceProvider, newVerifier, tokens); + staking.reprovision(serviceProvider, verifier, newVerifier, tokens, nThawRequests); + + // after + Provision memory afterProvision = staking.getProvision(serviceProvider, verifier); + Provision memory afterProvisionNewVerifier = staking.getProvision(serviceProvider, newVerifier); + ServiceProviderInternal memory afterServiceProvider = _getStorage_ServiceProviderInternal(serviceProvider); + LinkedList.List memory afterThawRequestList = staking.getThawRequestList( + serviceProvider, + verifier, + serviceProvider + ); + + // assert: provision old verifier + assertEq(afterProvision.tokens, beforeProvision.tokens - calcTokensThawed); + assertEq(afterProvision.tokensThawing, calcTokensThawing); + assertEq(afterProvision.sharesThawing, calcSharesThawing); + assertEq(afterProvision.maxVerifierCut, beforeProvision.maxVerifierCut); + assertEq(afterProvision.thawingPeriod, beforeProvision.thawingPeriod); + assertEq(afterProvision.createdAt, beforeProvision.createdAt); + assertEq(afterProvision.maxVerifierCutPending, beforeProvision.maxVerifierCutPending); + assertEq(afterProvision.thawingPeriodPending, beforeProvision.thawingPeriodPending); + + // assert: provision new verifier + assertEq(afterProvisionNewVerifier.tokens, beforeProvisionNewVerifier.tokens + tokens); + assertEq(afterProvisionNewVerifier.tokensThawing, beforeProvisionNewVerifier.tokensThawing); + assertEq(afterProvisionNewVerifier.sharesThawing, beforeProvisionNewVerifier.sharesThawing); + assertEq(afterProvisionNewVerifier.maxVerifierCut, beforeProvisionNewVerifier.maxVerifierCut); + assertEq(afterProvisionNewVerifier.thawingPeriod, beforeProvisionNewVerifier.thawingPeriod); + assertEq(afterProvisionNewVerifier.createdAt, beforeProvisionNewVerifier.createdAt); + assertEq(afterProvisionNewVerifier.maxVerifierCutPending, beforeProvisionNewVerifier.maxVerifierCutPending); + assertEq(afterProvisionNewVerifier.thawingPeriodPending, beforeProvisionNewVerifier.thawingPeriodPending); + + // assert: service provider + assertEq(afterServiceProvider.tokensStaked, beforeServiceProvider.tokensStaked); + assertEq(afterServiceProvider.tokensProvisioned, beforeServiceProvider.tokensProvisioned + tokens - calcTokensThawed); + assertEq(afterServiceProvider.__DEPRECATED_tokensAllocated, beforeServiceProvider.__DEPRECATED_tokensAllocated); + assertEq(afterServiceProvider.__DEPRECATED_tokensLocked, beforeServiceProvider.__DEPRECATED_tokensLocked); + assertEq( + afterServiceProvider.__DEPRECATED_tokensLockedUntil, + beforeServiceProvider.__DEPRECATED_tokensLockedUntil + ); + + // assert: thaw request list old verifier + for (uint i = 0; i < calcThawRequestsFulfilledListIds.length; i++) { + ThawRequest memory thawRequest = staking.getThawRequest(calcThawRequestsFulfilledListIds[i]); + assertEq(thawRequest.shares, 0); + assertEq(thawRequest.thawingUntil, 0); + assertEq(thawRequest.next, bytes32(0)); + } + if (calcThawRequestsFulfilledList.length == 0) { + assertEq(afterThawRequestList.head, beforeThawRequestList.head); + } else { + assertEq( + afterThawRequestList.head, + calcThawRequestsFulfilledList.length == beforeThawRequestList.count + ? bytes32(0) + : calcThawRequestsFulfilledList[calcThawRequestsFulfilledList.length - 1].next + ); + } + assertEq( + afterThawRequestList.tail, + calcThawRequestsFulfilledList.length == beforeThawRequestList.count + ? bytes32(0) + : beforeThawRequestList.tail + ); + assertEq(afterThawRequestList.count, beforeThawRequestList.count - calcThawRequestsFulfilledList.length); + assertEq(afterThawRequestList.nonce, beforeThawRequestList.nonce); + } + /* * STORAGE HELPERS */ diff --git a/packages/horizon/test/staking/provision/deprovision.t.sol b/packages/horizon/test/staking/provision/deprovision.t.sol index a790970c6..9087fea55 100644 --- a/packages/horizon/test/staking/provision/deprovision.t.sol +++ b/packages/horizon/test/staking/provision/deprovision.t.sol @@ -103,7 +103,5 @@ contract HorizonStakingDeprovisionTest is HorizonStakingTest { _thaw(users.indexer, subgraphDataServiceAddress, amount); _deprovision(users.indexer, subgraphDataServiceAddress, 0); - uint256 idleStake = staking.getIdleStake(users.indexer); - assertEq(idleStake, 0); } } diff --git a/packages/horizon/test/staking/provision/reprovision.t.sol b/packages/horizon/test/staking/provision/reprovision.t.sol index d5724a12d..40a6cee68 100644 --- a/packages/horizon/test/staking/provision/reprovision.t.sol +++ b/packages/horizon/test/staking/provision/reprovision.t.sol @@ -12,14 +12,6 @@ contract HorizonStakingReprovisionTest is HorizonStakingTest { address private newDataService = makeAddr("newDataService"); - /* - * HELPERS - */ - - function _reprovision(uint256 tokens, uint256 nThawRequests) private { - staking.reprovision(users.indexer, subgraphDataServiceAddress, newDataService, tokens, nThawRequests); - } - /* * TESTS */ @@ -33,13 +25,29 @@ contract HorizonStakingReprovisionTest is HorizonStakingTest { _createProvision(users.indexer, newDataService, 1 ether, 0, thawingPeriod); - // nThawRequests == 0 reprovisions all thaw requests - _reprovision(provisionAmount, 0); - uint256 idleStake = staking.getIdleStake(users.indexer); - assertEq(idleStake, 0 ether); + _reprovision(users.indexer, subgraphDataServiceAddress, newDataService, provisionAmount, 0); + } + + function testReprovision_TokensOverThawingTokens() public useIndexer { + uint64 thawingPeriod = 1 days; - uint256 provisionTokens = staking.getProviderTokensAvailable(users.indexer, newDataService); - assertEq(provisionTokens, provisionAmount + 1 ether); + // create provision A, thaw 10 ether, skip time so they are fully thawed + _createProvision(users.indexer, subgraphDataServiceAddress, 100 ether, 0, thawingPeriod); + _thaw(users.indexer, subgraphDataServiceAddress, 10 ether); + skip(thawingPeriod + 1); + + // create provision B + _createProvision(users.indexer, newDataService, 1 ether, 0, thawingPeriod); + + // reprovision 100 ether from A to B + // this should revert because there are only 10 ether that thawed and the service provider + // doesn't have additional idle stake to cover the difference + vm.expectRevert(); + staking.reprovision(users.indexer, subgraphDataServiceAddress, newDataService, 100 ether, 0); + + // now add some idle stake and try again, it should not revert + _stake(100 ether); + _reprovision(users.indexer, subgraphDataServiceAddress, newDataService, 100 ether, 0); } function testReprovision_OperatorMovingTokens( @@ -56,12 +64,7 @@ contract HorizonStakingReprovisionTest is HorizonStakingTest { // Switch back to operator vm.startPrank(users.operator); _createProvision(users.indexer, newDataService, 1 ether, 0, thawingPeriod); - _reprovision(provisionAmount, 0); - uint256 idleStake = staking.getIdleStake(users.indexer); - assertEq(idleStake, 0 ether); - - uint256 provisionTokens = staking.getProviderTokensAvailable(users.indexer, newDataService); - assertEq(provisionTokens, provisionAmount + 1 ether); + _reprovision(users.indexer, subgraphDataServiceAddress, newDataService, provisionAmount, 0); } function testReprovision_RevertWhen_OperatorNotAuthorizedForNewDataService( @@ -82,13 +85,13 @@ contract HorizonStakingReprovisionTest is HorizonStakingTest { newDataService ); vm.expectRevert(expectedError); - _reprovision(provisionAmount, 0); + staking.reprovision(users.indexer, subgraphDataServiceAddress, newDataService, provisionAmount, 0); } function testReprovision_RevertWhen_NoThawingTokens(uint256 amount) public useIndexer useProvision(amount, 0, 0) { bytes memory expectedError = abi.encodeWithSignature("HorizonStakingNothingThawing()"); vm.expectRevert(expectedError); - _reprovision(amount, 0); + staking.reprovision(users.indexer, subgraphDataServiceAddress, newDataService, amount, 0); } function testReprovision_RevertWhen_StillThawing( @@ -106,6 +109,6 @@ contract HorizonStakingReprovisionTest is HorizonStakingTest { 0 ); vm.expectRevert(expectedError); - _reprovision(provisionAmount, 0); + staking.reprovision(users.indexer, subgraphDataServiceAddress, newDataService, provisionAmount, 0); } } From 24c097942fee10ba3e1c0e1d51969dbd94d56309 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1s=20Migone?= Date: Wed, 28 Aug 2024 16:52:32 -0300 Subject: [PATCH 09/24] test: refactor provision parameters functions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Tomás Migone --- .../test/data-service/DataService.t.sol | 6 +- .../HorizonStakingShared.t.sol | 75 ++++++++++++++++++- .../test/staking/provision/parameters.t.sol | 36 +-------- 3 files changed, 80 insertions(+), 37 deletions(-) diff --git a/packages/horizon/test/data-service/DataService.t.sol b/packages/horizon/test/data-service/DataService.t.sol index a178bef12..2ba72cfd0 100644 --- a/packages/horizon/test/data-service/DataService.t.sol +++ b/packages/horizon/test/data-service/DataService.t.sol @@ -261,7 +261,7 @@ contract DataServiceTest is HorizonStakingSharedTest { dataService.VERIFIER_CUT_MIN(), dataService.THAWING_PERIOD_MIN() ); - staking.setProvisionParameters(users.indexer, address(dataService), maxVerifierCut, thawingPeriod); + _setProvisionParameters(users.indexer, address(dataService), maxVerifierCut, thawingPeriod); // accept provision parameters if (maxVerifierCut != dataService.VERIFIER_CUT_MIN() || thawingPeriod != dataService.THAWING_PERIOD_MIN()) { @@ -294,7 +294,7 @@ contract DataServiceTest is HorizonStakingSharedTest { dataService.VERIFIER_CUT_MIN(), dataService.THAWING_PERIOD_MIN() ); - staking.setProvisionParameters( + _setProvisionParameters( users.indexer, address(dataService), dataService.VERIFIER_CUT_MIN(), @@ -332,7 +332,7 @@ contract DataServiceTest is HorizonStakingSharedTest { dataService.VERIFIER_CUT_MIN(), dataService.THAWING_PERIOD_MIN() ); - staking.setProvisionParameters( + _setProvisionParameters( users.indexer, address(dataService), maxVerifierCut, diff --git a/packages/horizon/test/shared/horizon-staking/HorizonStakingShared.t.sol b/packages/horizon/test/shared/horizon-staking/HorizonStakingShared.t.sol index 0f3dc95cc..1851140bf 100644 --- a/packages/horizon/test/shared/horizon-staking/HorizonStakingShared.t.sol +++ b/packages/horizon/test/shared/horizon-staking/HorizonStakingShared.t.sol @@ -564,7 +564,10 @@ abstract contract HorizonStakingSharedTest is GraphBaseTest { // assert: service provider assertEq(afterServiceProvider.tokensStaked, beforeServiceProvider.tokensStaked); - assertEq(afterServiceProvider.tokensProvisioned, beforeServiceProvider.tokensProvisioned + tokens - calcTokensThawed); + assertEq( + afterServiceProvider.tokensProvisioned, + beforeServiceProvider.tokensProvisioned + tokens - calcTokensThawed + ); assertEq(afterServiceProvider.__DEPRECATED_tokensAllocated, beforeServiceProvider.__DEPRECATED_tokensAllocated); assertEq(afterServiceProvider.__DEPRECATED_tokensLocked, beforeServiceProvider.__DEPRECATED_tokensLocked); assertEq( @@ -599,6 +602,76 @@ abstract contract HorizonStakingSharedTest is GraphBaseTest { assertEq(afterThawRequestList.nonce, beforeThawRequestList.nonce); } + function _setProvisionParameters( + address serviceProvider, + address verifier, + uint32 maxVerifierCut, + uint64 thawingPeriod + ) internal { + // before + Provision memory beforeProvision = staking.getProvision(serviceProvider, verifier); + + // setProvisionParameters + if (beforeProvision.maxVerifierCut != maxVerifierCut || beforeProvision.thawingPeriod != thawingPeriod) { + vm.expectEmit(); + emit IHorizonStakingMain.ProvisionParametersStaged( + serviceProvider, + verifier, + maxVerifierCut, + thawingPeriod + ); + } + staking.setProvisionParameters(serviceProvider, verifier, maxVerifierCut, thawingPeriod); + + // after + Provision memory afterProvision = staking.getProvision(serviceProvider, verifier); + + // assert + assertEq(afterProvision.tokens, beforeProvision.tokens); + assertEq(afterProvision.tokensThawing, beforeProvision.tokensThawing); + assertEq(afterProvision.sharesThawing, beforeProvision.sharesThawing); + assertEq(afterProvision.maxVerifierCut, beforeProvision.maxVerifierCut); + assertEq(afterProvision.thawingPeriod, beforeProvision.thawingPeriod); + assertEq(afterProvision.createdAt, beforeProvision.createdAt); + assertEq(afterProvision.maxVerifierCutPending, maxVerifierCut); + assertEq(afterProvision.thawingPeriodPending, thawingPeriod); + } + + function _acceptProvisionParameters(address serviceProvider) internal { + (, address msgSender, ) = vm.readCallers(); + + // before + Provision memory beforeProvision = staking.getProvision(serviceProvider, msgSender); + + // acceptProvisionParameters + if ( + beforeProvision.maxVerifierCutPending != beforeProvision.maxVerifierCut || + beforeProvision.thawingPeriodPending != beforeProvision.thawingPeriod + ) { + vm.expectEmit(); + emit IHorizonStakingMain.ProvisionParametersSet( + serviceProvider, + msgSender, + beforeProvision.maxVerifierCutPending, + beforeProvision.thawingPeriodPending + ); + } + staking.acceptProvisionParameters(serviceProvider); + + // after + Provision memory afterProvision = staking.getProvision(serviceProvider, msgSender); + + // assert + assertEq(afterProvision.tokens, beforeProvision.tokens); + assertEq(afterProvision.tokensThawing, beforeProvision.tokensThawing); + assertEq(afterProvision.sharesThawing, beforeProvision.sharesThawing); + assertEq(afterProvision.maxVerifierCut, beforeProvision.maxVerifierCutPending); + assertEq(afterProvision.maxVerifierCut, afterProvision.maxVerifierCutPending); + assertEq(afterProvision.thawingPeriod, beforeProvision.thawingPeriodPending); + assertEq(afterProvision.thawingPeriod, afterProvision.thawingPeriodPending); + assertEq(afterProvision.createdAt, beforeProvision.createdAt); + } + /* * STORAGE HELPERS */ diff --git a/packages/horizon/test/staking/provision/parameters.t.sol b/packages/horizon/test/staking/provision/parameters.t.sol index 298059a7a..acf20a65b 100644 --- a/packages/horizon/test/staking/provision/parameters.t.sol +++ b/packages/horizon/test/staking/provision/parameters.t.sol @@ -16,20 +16,7 @@ contract HorizonStakingProvisionParametersTest is HorizonStakingTest { uint32 maxVerifierCut, uint64 thawingPeriod ) public useIndexer useProvision(amount, 0, 0) { - vm.assume(maxVerifierCut != 0); - vm.assume(thawingPeriod != 0); - vm.expectEmit(); - emit IHorizonStakingMain.ProvisionParametersStaged( - users.indexer, - subgraphDataServiceAddress, - maxVerifierCut, - thawingPeriod - ); - staking.setProvisionParameters(users.indexer, subgraphDataServiceAddress, maxVerifierCut, thawingPeriod); - - Provision memory prov = staking.getProvision(users.indexer, subgraphDataServiceAddress); - assertEq(prov.maxVerifierCutPending, maxVerifierCut); - assertEq(prov.thawingPeriodPending, thawingPeriod); + _setProvisionParameters(users.indexer, subgraphDataServiceAddress, maxVerifierCut, thawingPeriod); } function test_ProvisionParametersSet_RevertWhen_ProvisionNotExists( @@ -78,27 +65,10 @@ contract HorizonStakingProvisionParametersTest is HorizonStakingTest { uint32 maxVerifierCut, uint64 thawingPeriod ) public useIndexer useProvision(amount, maxVerifierCut, thawingPeriod) { - Provision memory prov = staking.getProvision(users.indexer, subgraphDataServiceAddress); - - staking.setProvisionParameters(users.indexer, subgraphDataServiceAddress, maxVerifierCut, thawingPeriod); + _setProvisionParameters(users.indexer, subgraphDataServiceAddress, maxVerifierCut, thawingPeriod); vm.startPrank(subgraphDataServiceAddress); - - if (maxVerifierCut != prov.maxVerifierCut || thawingPeriod != prov.thawingPeriod) { - vm.expectEmit(); - emit IHorizonStakingMain.ProvisionParametersSet( - users.indexer, - subgraphDataServiceAddress, - maxVerifierCut, - thawingPeriod - ); - } - staking.acceptProvisionParameters(users.indexer); + _acceptProvisionParameters(users.indexer); vm.stopPrank(); - - assertEq(prov.maxVerifierCut, maxVerifierCut); - assertEq(prov.maxVerifierCutPending, maxVerifierCut); - assertEq(prov.thawingPeriod, thawingPeriod); - assertEq(prov.thawingPeriodPending, thawingPeriod); } } From fdbe5ee83b1b73da2d016ab4fe7546af34eeb95a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1s=20Migone?= Date: Thu, 29 Aug 2024 16:24:49 -0300 Subject: [PATCH 10/24] test: refactor provision tests MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Tomás Migone --- .../horizon/test/payments/GraphPayments.t.sol | 2 +- .../HorizonStakingShared.t.sol | 105 +++++++++++++++++- .../horizon/test/staking/HorizonStaking.t.sol | 2 +- .../test/staking/operator/operator.t.sol | 11 +- .../test/staking/provision/locked.t.sol | 8 +- .../test/staking/provision/provision.t.sol | 2 +- .../test/staking/provision/reprovision.t.sol | 2 +- .../serviceProvider/serviceProvider.t.sol | 2 +- 8 files changed, 116 insertions(+), 18 deletions(-) diff --git a/packages/horizon/test/payments/GraphPayments.t.sol b/packages/horizon/test/payments/GraphPayments.t.sol index 9d2ef7495..8fa23015b 100644 --- a/packages/horizon/test/payments/GraphPayments.t.sol +++ b/packages/horizon/test/payments/GraphPayments.t.sol @@ -60,7 +60,7 @@ contract GraphPaymentsTest is HorizonStakingSharedTest { uint256 amount, uint256 tokensDataService ) public useIndexer useProvision(amount, 0, 0) useDelegationFeeCut(IGraphPayments.PaymentTypes.QueryFee, delegationFeeCut) { - tokensDataService = bound(tokensDataService, amount + 1, MAX_STAKING_TOKENS); + tokensDataService = bound(tokensDataService, amount + 1, MAX_STAKING_TOKENS + 1); address escrowAddress = address(escrow); mint(escrowAddress, amount); diff --git a/packages/horizon/test/shared/horizon-staking/HorizonStakingShared.t.sol b/packages/horizon/test/shared/horizon-staking/HorizonStakingShared.t.sol index 1851140bf..023645c37 100644 --- a/packages/horizon/test/shared/horizon-staking/HorizonStakingShared.t.sol +++ b/packages/horizon/test/shared/horizon-staking/HorizonStakingShared.t.sol @@ -25,7 +25,7 @@ abstract contract HorizonStakingSharedTest is GraphBaseTest { modifier useOperator() { vm.startPrank(users.indexer); - staking.setOperator(users.operator, subgraphDataServiceAddress, true); + _setOperator(users.operator, subgraphDataServiceAddress, true); vm.startPrank(users.operator); _; vm.stopPrank(); @@ -256,13 +256,38 @@ abstract contract HorizonStakingSharedTest is GraphBaseTest { uint32 maxVerifierCut, uint64 thawingPeriod ) internal { + __provision(serviceProvider, verifier, tokens, maxVerifierCut, thawingPeriod, false); + } + + function _provisionLocked( + address serviceProvider, + address verifier, + uint256 tokens, + uint32 maxVerifierCut, + uint64 thawingPeriod + ) internal { + __provision(serviceProvider, verifier, tokens, maxVerifierCut, thawingPeriod, true); + } + + function __provision( + address serviceProvider, + address verifier, + uint256 tokens, + uint32 maxVerifierCut, + uint64 thawingPeriod, + bool locked + ) private { // before ServiceProviderInternal memory beforeServiceProvider = _getStorage_ServiceProviderInternal(serviceProvider); // provision vm.expectEmit(); emit IHorizonStakingMain.ProvisionCreated(serviceProvider, verifier, tokens, maxVerifierCut, thawingPeriod); - staking.provision(serviceProvider, verifier, tokens, maxVerifierCut, thawingPeriod); + if (locked) { + staking.provisionLocked(serviceProvider, verifier, tokens, maxVerifierCut, thawingPeriod); + } else { + staking.provision(serviceProvider, verifier, tokens, maxVerifierCut, thawingPeriod); + } // after Provision memory afterProvision = staking.getProvision(serviceProvider, verifier); @@ -672,6 +697,57 @@ abstract contract HorizonStakingSharedTest is GraphBaseTest { assertEq(afterProvision.createdAt, beforeProvision.createdAt); } + function _setOperator(address operator, address verifier, bool allow) internal { + __setOperator(operator, verifier, allow, false); + } + + function _setOperatorLocked(address operator, address verifier, bool allow) internal { + __setOperator(operator, verifier, allow, true); + } + + function __setOperator(address operator, address verifier, bool allow, bool locked) internal { + (, address msgSender, ) = vm.readCallers(); + + // staking contract knows the address of the legacy subgraph service + // but we cannot read it as it's an immutable, we have to use the global var :/ + bool legacy = verifier == subgraphDataServiceLegacyAddress; + + // before + bool beforeOperatorAllowed = _getStorage_OperatorAuth(msgSender, operator, verifier, legacy); + bool beforeOperatorAllowedGetter = staking.isAuthorized(operator, msgSender, verifier); + assertEq(beforeOperatorAllowed, beforeOperatorAllowedGetter); + + // setOperator + vm.expectEmit(address(staking)); + emit IHorizonStakingMain.OperatorSet(msgSender, operator, verifier, allow); + if (locked) { + staking.setOperatorLocked(operator, verifier, allow); + } else { + staking.setOperator(operator, verifier, allow); + } + + // after + bool afterOperatorAllowed = _getStorage_OperatorAuth(msgSender, operator, verifier, legacy); + bool afterOperatorAllowedGetter = staking.isAuthorized(operator, msgSender, verifier); + assertEq(afterOperatorAllowed, afterOperatorAllowedGetter); + + // assert + assertEq(afterOperatorAllowed, allow); + } + + function _setAllowedLockedVerifier(address verifier, bool allowed) internal { + // setAllowedLockedVerifier + vm.expectEmit(); + emit IHorizonStakingMain.AllowedLockedVerifierSet(verifier, allowed); + staking.setAllowedLockedVerifier(verifier, allowed); + + // after + bool afterAllowed = staking.isAllowedLockedVerifier(verifier); + + // assert + assertEq(afterAllowed, allowed); + } + /* * STORAGE HELPERS */ @@ -692,6 +768,31 @@ abstract contract HorizonStakingSharedTest is GraphBaseTest { return serviceProviderInternal; } + function _getStorage_OperatorAuth( + address serviceProvider, + address operator, + address verifier, + bool legacy + ) internal view returns (bool) { + uint256 baseSlot = legacy ? 21 : 31; + uint256 slot; + + if (legacy) { + slot = uint256(keccak256(abi.encode(serviceProvider, keccak256(abi.encode(operator, baseSlot))))); + } else { + console.log("TEST"); + slot = uint256( + keccak256( + abi.encode( + operator, + keccak256(abi.encode(verifier, keccak256(abi.encode(serviceProvider, baseSlot)))) + ) + ) + ); + } + return vm.load(address(staking), bytes32(slot)) == bytes32(uint256(1)); + } + function _setStorage_DeprecatedThawingPeriod(uint32 _thawingPeriod) internal { uint256 slot = 13; bytes32 value = bytes32(uint256(_thawingPeriod)); diff --git a/packages/horizon/test/staking/HorizonStaking.t.sol b/packages/horizon/test/staking/HorizonStaking.t.sol index c8a0a2e5e..156594f13 100644 --- a/packages/horizon/test/staking/HorizonStaking.t.sol +++ b/packages/horizon/test/staking/HorizonStaking.t.sol @@ -47,7 +47,7 @@ contract HorizonStakingTest is HorizonStakingSharedTest { address msgSender; (, msgSender, ) = vm.readCallers(); resetPrank(users.governor); - staking.setAllowedLockedVerifier(verifier, true); + _setAllowedLockedVerifier(verifier, true); resetPrank(msgSender); _; } diff --git a/packages/horizon/test/staking/operator/operator.t.sol b/packages/horizon/test/staking/operator/operator.t.sol index af06e0ef5..81e61e6ad 100644 --- a/packages/horizon/test/staking/operator/operator.t.sol +++ b/packages/horizon/test/staking/operator/operator.t.sol @@ -11,8 +11,8 @@ contract HorizonStakingOperatorTest is HorizonStakingTest { * TESTS */ - function testOperator_SetOperator() public useOperator { - assertTrue(staking.isAuthorized(users.operator, users.indexer, subgraphDataServiceAddress)); + function testOperator_SetOperator() public useIndexer { + _setOperator(users.operator, subgraphDataServiceAddress, true); } function testOperator_RevertWhen_CallerIsServiceProvider() public useIndexer { @@ -22,10 +22,7 @@ contract HorizonStakingOperatorTest is HorizonStakingTest { } function testOperator_RemoveOperator() public useIndexer { - staking.setOperator(users.operator, subgraphDataServiceAddress, true); - assertTrue(staking.isAuthorized(users.operator, users.indexer, subgraphDataServiceAddress)); - - staking.setOperator(users.operator, subgraphDataServiceAddress, false); - assertFalse(staking.isAuthorized(users.operator, users.indexer, subgraphDataServiceAddress)); + _setOperator(users.operator, subgraphDataServiceAddress, true); + _setOperator(users.operator, subgraphDataServiceAddress, false); } } \ No newline at end of file diff --git a/packages/horizon/test/staking/provision/locked.t.sol b/packages/horizon/test/staking/provision/locked.t.sol index 642ba9a10..f16900eb2 100644 --- a/packages/horizon/test/staking/provision/locked.t.sol +++ b/packages/horizon/test/staking/provision/locked.t.sol @@ -17,10 +17,10 @@ contract HorizonStakingProvisionLockedTest is HorizonStakingTest { uint256 provisionTokens = staking.getProviderTokensAvailable(users.indexer, subgraphDataServiceAddress); assertEq(provisionTokens, 0); - staking.setOperatorLocked(users.operator, subgraphDataServiceAddress, true); + _setOperatorLocked(users.operator, subgraphDataServiceAddress, true); vm.startPrank(users.operator); - staking.provisionLocked( + _provisionLocked( users.indexer, subgraphDataServiceAddress, amount, @@ -39,11 +39,11 @@ contract HorizonStakingProvisionLockedTest is HorizonStakingTest { assertEq(provisionTokens, 0); // Set operator - staking.setOperatorLocked(users.operator, subgraphDataServiceAddress, true); + _setOperatorLocked(users.operator, subgraphDataServiceAddress, true); // Disable locked verifier vm.startPrank(users.governor); - staking.setAllowedLockedVerifier(subgraphDataServiceAddress, false); + _setAllowedLockedVerifier(subgraphDataServiceAddress, false); vm.startPrank(users.operator); bytes memory expectedError = abi.encodeWithSignature("HorizonStakingVerifierNotAllowed(address)", subgraphDataServiceAddress); diff --git a/packages/horizon/test/staking/provision/provision.t.sol b/packages/horizon/test/staking/provision/provision.t.sol index b6ccd2619..e8f94c5df 100644 --- a/packages/horizon/test/staking/provision/provision.t.sol +++ b/packages/horizon/test/staking/provision/provision.t.sol @@ -74,7 +74,7 @@ contract HorizonStakingProvisionTest is HorizonStakingTest { resetPrank(users.indexer); token.approve(address(staking), amount / 2); - staking.stake(amount / 2); + _stake(amount / 2); bytes memory expectedError = abi.encodeWithSignature("HorizonStakingProvisionAlreadyExists()"); vm.expectRevert(expectedError); diff --git a/packages/horizon/test/staking/provision/reprovision.t.sol b/packages/horizon/test/staking/provision/reprovision.t.sol index 40a6cee68..d403a5c2e 100644 --- a/packages/horizon/test/staking/provision/reprovision.t.sol +++ b/packages/horizon/test/staking/provision/reprovision.t.sol @@ -59,7 +59,7 @@ contract HorizonStakingReprovisionTest is HorizonStakingTest { // Switch to indexer to set operator for new data service vm.startPrank(users.indexer); - staking.setOperator(users.operator, newDataService, true); + _setOperator(users.operator, newDataService, true); // Switch back to operator vm.startPrank(users.operator); diff --git a/packages/horizon/test/staking/serviceProvider/serviceProvider.t.sol b/packages/horizon/test/staking/serviceProvider/serviceProvider.t.sol index 3a90c7718..10a68ff5e 100644 --- a/packages/horizon/test/staking/serviceProvider/serviceProvider.t.sol +++ b/packages/horizon/test/staking/serviceProvider/serviceProvider.t.sol @@ -25,7 +25,7 @@ contract HorizonStakingServiceProviderTest is HorizonStakingTest { assertEq(sp.tokensStaked, amount); assertEq(sp.tokensProvisioned, amount); - staking.setOperator(users.operator, subgraphDataServiceAddress, true); + _setOperator(users.operator, subgraphDataServiceAddress, true); resetPrank(users.operator); _stakeTo(users.indexer, operatorAmount); sp = staking.getServiceProvider(users.indexer); From a2370b59cd6a9f1e0f8f2566e4c408135bc04138 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1s=20Migone?= Date: Thu, 29 Aug 2024 17:08:12 -0300 Subject: [PATCH 11/24] test: refactor operator tests MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Tomás Migone --- .../horizon/contracts/staking/HorizonStakingStorage.sol | 2 +- .../test/shared/horizon-staking/HorizonStakingShared.t.sol | 3 +-- packages/horizon/test/staking/operator/locked.t.sol | 6 ++---- 3 files changed, 4 insertions(+), 7 deletions(-) diff --git a/packages/horizon/contracts/staking/HorizonStakingStorage.sol b/packages/horizon/contracts/staking/HorizonStakingStorage.sol index 2b58b02c7..2934dfcd1 100644 --- a/packages/horizon/contracts/staking/HorizonStakingStorage.sol +++ b/packages/horizon/contracts/staking/HorizonStakingStorage.sol @@ -105,7 +105,7 @@ abstract contract HorizonStakingV1Storage { /// @dev Operator allow list (legacy) /// Only used when the verifier is the subgraph data service. - mapping(address legacyOperator => mapping(address serviceProvider => bool authorized)) internal _legacyOperatorAuth; + mapping(address serviceProvider => mapping(address legacyOperator => bool authorized)) internal _legacyOperatorAuth; // -- Asset Holders -- diff --git a/packages/horizon/test/shared/horizon-staking/HorizonStakingShared.t.sol b/packages/horizon/test/shared/horizon-staking/HorizonStakingShared.t.sol index 023645c37..8f4c785fc 100644 --- a/packages/horizon/test/shared/horizon-staking/HorizonStakingShared.t.sol +++ b/packages/horizon/test/shared/horizon-staking/HorizonStakingShared.t.sol @@ -778,9 +778,8 @@ abstract contract HorizonStakingSharedTest is GraphBaseTest { uint256 slot; if (legacy) { - slot = uint256(keccak256(abi.encode(serviceProvider, keccak256(abi.encode(operator, baseSlot))))); + slot = uint256(keccak256(abi.encode(operator, keccak256(abi.encode(serviceProvider, baseSlot))))); } else { - console.log("TEST"); slot = uint256( keccak256( abi.encode( diff --git a/packages/horizon/test/staking/operator/locked.t.sol b/packages/horizon/test/staking/operator/locked.t.sol index e6eb8038d..08ebe9944 100644 --- a/packages/horizon/test/staking/operator/locked.t.sol +++ b/packages/horizon/test/staking/operator/locked.t.sol @@ -12,8 +12,7 @@ contract HorizonStakingOperatorLockedTest is HorizonStakingTest { */ function testOperatorLocked_Set() public useIndexer useLockedVerifier(subgraphDataServiceAddress) { - staking.setOperatorLocked(users.operator, subgraphDataServiceAddress, true); - assertTrue(staking.isAuthorized(users.operator, users.indexer, subgraphDataServiceAddress)); + _setOperatorLocked(users.operator, subgraphDataServiceAddress, true); } function testOperatorLocked_RevertWhen_VerifierNotAllowed() public useIndexer { @@ -29,7 +28,6 @@ contract HorizonStakingOperatorLockedTest is HorizonStakingTest { } function testOperatorLocked_SetLegacySubgraphService() public useIndexer useLockedVerifier(subgraphDataServiceLegacyAddress) { - staking.setOperatorLocked(users.operator, subgraphDataServiceLegacyAddress, true); - assertTrue(staking.isAuthorized(users.operator, users.indexer, subgraphDataServiceLegacyAddress)); + _setOperatorLocked(users.operator, subgraphDataServiceLegacyAddress, true); } } \ No newline at end of file From cfcfcb98a1de778cfab4e53c451082c9e577e5ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1s=20Migone?= Date: Fri, 30 Aug 2024 11:03:02 -0300 Subject: [PATCH 12/24] chore: update some configs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Tomás Migone --- .../contracts/interfaces/IPaymentsEscrow.sol | 7 +------ .../horizon/contracts/payments/PaymentsEscrow.sol | 8 +------- packages/horizon/foundry.toml | 13 +++++++------ packages/horizon/package.json | 4 ++-- packages/horizon/test/staking/HorizonStaking.t.sol | 2 +- 5 files changed, 12 insertions(+), 22 deletions(-) diff --git a/packages/horizon/contracts/interfaces/IPaymentsEscrow.sol b/packages/horizon/contracts/interfaces/IPaymentsEscrow.sol index 7ab5ff023..937ded194 100644 --- a/packages/horizon/contracts/interfaces/IPaymentsEscrow.sol +++ b/packages/horizon/contracts/interfaces/IPaymentsEscrow.sol @@ -84,12 +84,7 @@ interface IPaymentsEscrow { * @param tokens The amount of tokens being thawed * @param thawEndTimestamp The timestamp at which the thawing period ends */ - event Thaw( - address indexed payer, - address indexed receiver, - uint256 tokens, - uint256 thawEndTimestamp - ); + event Thaw(address indexed payer, address indexed receiver, uint256 tokens, uint256 thawEndTimestamp); /** * @notice Emitted when a payer withdraws funds from the escrow for a payer-receiver pair diff --git a/packages/horizon/contracts/payments/PaymentsEscrow.sol b/packages/horizon/contracts/payments/PaymentsEscrow.sol index 5045be86d..26f699fe1 100644 --- a/packages/horizon/contracts/payments/PaymentsEscrow.sol +++ b/packages/horizon/contracts/payments/PaymentsEscrow.sol @@ -18,12 +18,7 @@ import { GraphDirectory } from "../utilities/GraphDirectory.sol"; * for payments made through the payments protocol for services provided * via a Graph Horizon data service. */ -contract PaymentsEscrow is - Initializable, - MulticallUpgradeable, - GraphDirectory, - IPaymentsEscrow -{ +contract PaymentsEscrow is Initializable, MulticallUpgradeable, GraphDirectory, IPaymentsEscrow { using TokenUtils for IGraphToken; /// @notice Authorization details for payer-collector pairs @@ -73,7 +68,6 @@ contract PaymentsEscrow is WITHDRAW_ESCROW_THAWING_PERIOD = withdrawEscrowThawingPeriod; } - /** * @notice Initialize the contract */ diff --git a/packages/horizon/foundry.toml b/packages/horizon/foundry.toml index a1826d45c..54fa4c22e 100644 --- a/packages/horizon/foundry.toml +++ b/packages/horizon/foundry.toml @@ -5,13 +5,14 @@ libs = ['node_modules', 'lib'] test = 'test' cache_path = 'cache_forge' fs_permissions = [{ access = "read", path = "./"}] -optimizer = true -optimizer-runs = 200 via_ir = true +optimizer = true +optimizer_runs = 200 -[profile.lite] +# For testing we remove some optimizations to make it faster +[profile.test] optimizer = false -optimizer-runs = 1 +optimizer_runs = 1 -[profile.lite.optimizer_details.yulDetails] -optimizerSteps = ':' \ No newline at end of file +[profile.test.optimizer_details.yulDetails] +optimizer_steps = ':' \ No newline at end of file diff --git a/packages/horizon/package.json b/packages/horizon/package.json index a214e1d0a..064e7e1db 100644 --- a/packages/horizon/package.json +++ b/packages/horizon/package.json @@ -9,8 +9,8 @@ "lint:sol": "prettier --write contracts/**/*.sol && solhint --noPrompt --fix contracts/**/*.sol --config node_modules/solhint-graph-config/index.js", "lint": "yarn lint:ts && yarn lint:sol", "clean": "rm -rf build cache typechain-types", - "build": "forge build && hardhat compile", - "test": "FOUNDRY_PROFILE=lite forge test -vvv && hardhat test" + "build": "forge build contracts && hardhat compile", + "test": "FOUNDRY_PROFILE=test forge test -vvv && hardhat test" }, "devDependencies": { "@graphprotocol/contracts": "workspace:^7.0.0", diff --git a/packages/horizon/test/staking/HorizonStaking.t.sol b/packages/horizon/test/staking/HorizonStaking.t.sol index 156594f13..31338393a 100644 --- a/packages/horizon/test/staking/HorizonStaking.t.sol +++ b/packages/horizon/test/staking/HorizonStaking.t.sol @@ -286,7 +286,7 @@ contract HorizonStakingTest is HorizonStakingSharedTest { assertEq(verifierTokens, verifierCutAmount); } - function _getSlotPoolTokens(address serviceProvider, address verifier, bool legacy) private returns (bytes32) { + function _getSlotPoolTokens(address serviceProvider, address verifier, bool legacy) private pure returns (bytes32) { bytes32 slotPoolTokens; if (legacy) { slotPoolTokens = bytes32(uint256(keccak256(abi.encode(serviceProvider, 20))) + 2); From 6769b0858c4a81fed0b7c16e15563656348f31f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1s=20Migone?= Date: Fri, 30 Aug 2024 16:37:42 -0300 Subject: [PATCH 13/24] test: wip refactor of delegation tests MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Tomás Migone --- .../HorizonStakingShared.t.sol | 227 +++++++++++++++++- .../horizon/test/staking/HorizonStaking.t.sol | 170 +------------ .../test/staking/delegation/delegate.t.sol | 2 +- .../test/staking/delegation/undelegate.t.sol | 4 +- .../test/staking/delegation/withdraw.t.sol | 4 +- .../test/staking/transfer-tools/ttools.t.sol | 12 +- 6 files changed, 236 insertions(+), 183 deletions(-) diff --git a/packages/horizon/test/shared/horizon-staking/HorizonStakingShared.t.sol b/packages/horizon/test/shared/horizon-staking/HorizonStakingShared.t.sol index 8f4c785fc..3e7c2e3bf 100644 --- a/packages/horizon/test/shared/horizon-staking/HorizonStakingShared.t.sol +++ b/packages/horizon/test/shared/horizon-staking/HorizonStakingShared.t.sol @@ -748,6 +748,148 @@ abstract contract HorizonStakingSharedTest is GraphBaseTest { assertEq(afterAllowed, allowed); } + function _delegate(address serviceProvider, address verifier, uint256 tokens, uint256 minSharesOut) internal { + __delegate(serviceProvider, verifier, tokens, minSharesOut, false); + } + + function _delegate(address serviceProvider, uint256 tokens) internal { + __delegate(serviceProvider, subgraphDataServiceLegacyAddress, tokens, 0, true); + } + + function __delegate( + address serviceProvider, + address verifier, + uint256 tokens, + uint256 minSharesOut, + bool legacy + ) internal { + (, address delegator, ) = vm.readCallers(); + + // before + DelegationPoolInternalTest memory beforePool = _getStorage_DelegationPoolInternal( + serviceProvider, + verifier, + legacy + ); + DelegationInternal memory beforeDelegation = _getStorage_Delegation( + serviceProvider, + verifier, + delegator, + legacy + ); + uint256 beforeDelegatorBalance = token.balanceOf(delegator); + uint256 beforeStakingBalance = token.balanceOf(address(staking)); + + uint256 calcShares = (beforePool.tokens == 0 || beforePool.tokens == beforePool.tokensThawing) + ? tokens + : ((tokens * beforePool.shares) / (beforePool.tokens - beforePool.tokensThawing)); + + // delegate + token.approve(address(staking), tokens); + vm.expectEmit(); + emit IHorizonStakingMain.TokensDelegated(serviceProvider, verifier, delegator, tokens); + if (legacy) { + staking.delegate(serviceProvider, tokens); + } else { + staking.delegate(serviceProvider, verifier, tokens, minSharesOut); + } + + // after + DelegationPoolInternalTest memory afterPool = _getStorage_DelegationPoolInternal( + serviceProvider, + verifier, + legacy + ); + DelegationInternal memory afterDelegation = _getStorage_Delegation( + serviceProvider, + verifier, + delegator, + legacy + ); + uint256 afterDelegatorBalance = token.balanceOf(delegator); + uint256 afterStakingBalance = token.balanceOf(address(staking)); + + uint256 deltaShares = afterDelegation.shares - beforeDelegation.shares; + + // assertions + assertEq(beforePool.tokens + tokens, afterPool.tokens); + assertEq(beforePool.shares + calcShares, afterPool.shares); + assertEq(beforePool.tokensThawing, afterPool.tokensThawing); + assertEq(beforePool.sharesThawing, afterPool.sharesThawing); + assertGe(deltaShares, minSharesOut); + assertEq(calcShares, deltaShares); + assertEq(beforePool.tokens + tokens, afterPool.tokens); + assertEq(beforeDelegatorBalance - tokens, afterDelegatorBalance); + assertEq(beforeStakingBalance + tokens, afterStakingBalance); + } + + function _undelegate(address serviceProvider, address verifier, uint256 shares) internal { + __undelegate(serviceProvider, verifier, shares, false); + } + + function _undelegate(address serviceProvider, uint256 shares) internal { + __undelegate(serviceProvider, subgraphDataServiceLegacyAddress, shares, true); + } + + function __undelegate(address serviceProvider, address verifier, uint256 shares, bool legacy) internal { + (, address delegator, ) = vm.readCallers(); + + // before + DelegationPoolInternalTest memory beforePool = _getStorage_DelegationPoolInternal(serviceProvider, verifier, legacy); + DelegationInternal memory beforeDelegation = _getStorage_Delegation(serviceProvider, verifier, delegator, legacy); + LinkedList.List memory beforeThawRequestList = staking.getThawRequestList(serviceProvider, verifier, delegator); + uint256 beforeDelegatedTokens = staking.getDelegatedTokensAvailable(serviceProvider, verifier); + + uint256 calcTokens = ((beforePool.tokens - beforePool.tokensThawing) * shares) / beforePool.shares; + uint256 calcThawingShares = beforePool.tokensThawing == 0 + ? calcTokens + : (beforePool.sharesThawing * calcTokens) / beforePool.tokensThawing; + uint64 calcThawingUntil = staking.getProvision(serviceProvider, verifier).thawingPeriod + + uint64(block.timestamp); + bytes32 calcThawRequestId = keccak256( + abi.encodePacked(serviceProvider, verifier, delegator, beforeThawRequestList.nonce) + ); + + // undelegate + vm.expectEmit(); + emit IHorizonStakingMain.ThawRequestCreated( + serviceProvider, + verifier, + delegator, + calcThawingShares, + calcThawingUntil, + calcThawRequestId + ); + vm.expectEmit(); + emit IHorizonStakingMain.TokensUndelegated(serviceProvider, verifier, delegator, calcTokens); + if (legacy) { + staking.undelegate(serviceProvider, shares); + } else { + staking.undelegate(serviceProvider, verifier, shares); + } + + // after + DelegationPoolInternalTest memory afterPool = _getStorage_DelegationPoolInternal(users.indexer, verifier, legacy); + DelegationInternal memory afterDelegation = _getStorage_Delegation(serviceProvider, verifier, delegator, legacy); + LinkedList.List memory afterThawRequestList = staking.getThawRequestList(serviceProvider, verifier, delegator); + ThawRequest memory afterThawRequest = staking.getThawRequest(calcThawRequestId); + uint256 afterDelegatedTokens = staking.getDelegatedTokensAvailable(serviceProvider, verifier); + + // assertions + assertEq(beforePool.shares, afterPool.shares + shares); + assertEq(beforePool.tokens, afterPool.tokens); + assertEq(beforePool.tokensThawing + calcTokens, afterPool.tokensThawing); + assertEq(beforePool.sharesThawing + calcThawingShares, afterPool.sharesThawing); + assertEq(beforeDelegation.shares - shares, afterDelegation.shares); + assertEq(afterThawRequest.shares, calcThawingShares); + assertEq(afterThawRequest.thawingUntil, calcThawingUntil); + assertEq(afterThawRequest.next, bytes32(0)); + assertEq(calcThawRequestId, afterThawRequestList.tail); + assertEq(beforeThawRequestList.nonce + 1, afterThawRequestList.nonce); + assertEq(beforeThawRequestList.count + 1, afterThawRequestList.count); + assertEq(afterDelegatedTokens + calcTokens, beforeDelegatedTokens); + } + /* * STORAGE HELPERS */ @@ -774,17 +916,17 @@ abstract contract HorizonStakingSharedTest is GraphBaseTest { address verifier, bool legacy ) internal view returns (bool) { - uint256 baseSlot = legacy ? 21 : 31; + uint256 slotNumber = legacy ? 21 : 31; uint256 slot; if (legacy) { - slot = uint256(keccak256(abi.encode(operator, keccak256(abi.encode(serviceProvider, baseSlot))))); + slot = uint256(keccak256(abi.encode(operator, keccak256(abi.encode(serviceProvider, slotNumber))))); } else { slot = uint256( keccak256( abi.encode( operator, - keccak256(abi.encode(verifier, keccak256(abi.encode(serviceProvider, baseSlot)))) + keccak256(abi.encode(verifier, keccak256(abi.encode(serviceProvider, slotNumber)))) ) ) ); @@ -815,6 +957,85 @@ abstract contract HorizonStakingSharedTest is GraphBaseTest { vm.store(address(staking), bytes32(uint256(serviceProviderBaseSlot) + 4), bytes32(_tokensProvisioned)); } + // DelegationPoolInternal contains a mapping, solidity doesn't allow constructing structs with + // nested mappings on memory: "Struct containing a (nested) mapping cannot be constructed" + // So we use a custom struct here and remove the nested mapping which we don't need anyways + struct DelegationPoolInternalTest { + // (Deprecated) Time, in blocks, an indexer must wait before updating delegation parameters + // (Deprecated) Percentage of indexing rewards for the service provider, in PPM + // (Deprecated) Percentage of query fees for the service provider, in PPM + uint256 __DEPRECATED_packed_data; + // (Deprecated) Block when the delegation parameters were last updated + uint256 __DEPRECATED_updatedAtBlock; + // Total tokens as pool reserves + uint256 tokens; + // Total shares minted in the pool + uint256 shares; + // Delegation details by delegator + uint256 _gap_delegators_mapping; + // Tokens thawing in the pool + uint256 tokensThawing; + // Shares representing the thawing tokens + uint256 sharesThawing; + } + + function _getStorage_DelegationPoolInternal( + address serviceProvider, + address verifier, + bool legacy + ) internal view returns (DelegationPoolInternalTest memory) { + uint256 slotNumber = legacy ? 20 : 33; + uint256 baseSlot; + if (legacy) { + baseSlot = uint256(keccak256(abi.encode(serviceProvider, slotNumber))); + } else { + baseSlot = uint256(keccak256(abi.encode(verifier, keccak256(abi.encode(serviceProvider, slotNumber))))); + } + + DelegationPoolInternalTest memory delegationPoolInternal = DelegationPoolInternalTest({ + __DEPRECATED_packed_data: uint256(vm.load(address(staking), bytes32(baseSlot))), + __DEPRECATED_updatedAtBlock: uint256(vm.load(address(staking), bytes32(baseSlot + 1))), + tokens: uint256(vm.load(address(staking), bytes32(baseSlot + 2))), + shares: uint256(vm.load(address(staking), bytes32(baseSlot + 3))), + _gap_delegators_mapping: uint256(vm.load(address(staking), bytes32(baseSlot + 4))), + tokensThawing: uint256(vm.load(address(staking), bytes32(baseSlot + 5))), + sharesThawing: uint256(vm.load(address(staking), bytes32(baseSlot + 6))) + }); + + return delegationPoolInternal; + } + + function _getStorage_Delegation( + address serviceProvider, + address verifier, + address delegator, + bool legacy + ) internal view returns (DelegationInternal memory) { + uint256 slotNumber = legacy ? 20 : 33; + uint256 baseSlot; + + // DelegationPool + if (legacy) { + baseSlot = uint256(keccak256(abi.encode(serviceProvider, slotNumber))); + } else { + baseSlot = uint256(keccak256(abi.encode(verifier, keccak256(abi.encode(serviceProvider, slotNumber))))); + } + + // delegators slot in DelegationPool + baseSlot += 4; + + // Delegation + baseSlot = uint256(keccak256(abi.encode(delegator, baseSlot))); + + DelegationInternal memory delegation = DelegationInternal({ + shares: uint256(vm.load(address(staking), bytes32(baseSlot))), + __DEPRECATED_tokensLocked: uint256(vm.load(address(staking), bytes32(baseSlot + 1))), + __DEPRECATED_tokensLockedUntil: uint256(vm.load(address(staking), bytes32(baseSlot + 2))) + }); + + return delegation; + } + /* * MISC: private functions to help with testing */ diff --git a/packages/horizon/test/staking/HorizonStaking.t.sol b/packages/horizon/test/staking/HorizonStaking.t.sol index 31338393a..67dc1a04f 100644 --- a/packages/horizon/test/staking/HorizonStaking.t.sol +++ b/packages/horizon/test/staking/HorizonStaking.t.sol @@ -65,164 +65,7 @@ contract HorizonStakingTest is HorizonStakingSharedTest { * HELPERS */ - function _delegate(address serviceProvider, address verifier, uint256 tokens, uint256 minSharesOut) internal { - __delegate(serviceProvider, verifier, tokens, minSharesOut, false); - } - - function _delegateLegacy(address serviceProvider, uint256 tokens) internal { - __delegate(serviceProvider, subgraphDataServiceLegacyAddress, tokens, 0, true); - } - - - // struct required to avoid stack too deep errors >.< - struct DelegateData { - DelegationPool pool; - Delegation delegation; - uint256 storagePoolTokens; - uint256 delegatedTokens; - uint256 delegatorBalance; - uint256 stakingBalance; - } - - function __delegate( - address serviceProvider, - address verifier, - uint256 tokens, - uint256 minSharesOut, - bool legacy - ) internal { - (, address delegator, ) = vm.readCallers(); - - // before - DelegateData memory beforeData = DelegateData({ - pool: staking.getDelegationPool(serviceProvider, verifier), - delegation: staking.getDelegation(serviceProvider, verifier, delegator), - storagePoolTokens: uint256(vm.load(address(staking), _getSlotPoolTokens(serviceProvider, verifier, legacy))), - delegatedTokens: staking.getDelegatedTokensAvailable(serviceProvider, verifier), - delegatorBalance: token.balanceOf(delegator), - stakingBalance: token.balanceOf(address(staking)) - }); - - uint256 calcShares = (beforeData.pool.tokens == 0 || beforeData.pool.tokens == beforeData.pool.tokensThawing) - ? tokens - : ((tokens * beforeData.pool.shares) / (beforeData.pool.tokens - beforeData.pool.tokensThawing)); - - // delegate - token.approve(address(staking), tokens); - vm.expectEmit(); - emit IHorizonStakingMain.TokensDelegated(serviceProvider, verifier, delegator, tokens); - if (legacy) { - staking.delegate(serviceProvider, tokens); - } else { - staking.delegate(serviceProvider, verifier, tokens, minSharesOut); - } - - // after - DelegateData memory afterData = DelegateData({ - pool: staking.getDelegationPool(serviceProvider, verifier), - delegation: staking.getDelegation(serviceProvider, verifier, delegator), - storagePoolTokens: uint256(vm.load(address(staking), _getSlotPoolTokens(serviceProvider, verifier, legacy))), - delegatedTokens: staking.getDelegatedTokensAvailable(serviceProvider, verifier), - delegatorBalance: token.balanceOf(delegator), - stakingBalance: token.balanceOf(address(staking)) - }); - - uint256 deltaShares = afterData.delegation.shares - beforeData.delegation.shares; - - // assertions - assertEq(beforeData.pool.tokens + tokens, afterData.pool.tokens); - assertEq(beforeData.pool.shares + calcShares, afterData.pool.shares); - assertEq(beforeData.pool.tokensThawing, afterData.pool.tokensThawing); - assertEq(beforeData.pool.sharesThawing, afterData.pool.sharesThawing); - assertGe(deltaShares, minSharesOut); - assertEq(calcShares, deltaShares); - assertEq(beforeData.delegatedTokens + tokens, afterData.delegatedTokens); - // Ensure correct slot is being updated, pools are stored in different storage locations for legacy subgraph data service - assertEq(beforeData.storagePoolTokens + tokens, afterData.storagePoolTokens); - assertEq(beforeData.delegatorBalance - tokens, afterData.delegatorBalance); - assertEq(beforeData.stakingBalance + tokens, afterData.stakingBalance); - } - - function _undelegate(address serviceProvider, address verifier, uint256 shares) internal { - __undelegate(serviceProvider, verifier, shares, false); - } - - function _undelegateLegacy(address serviceProvider, uint256 shares) internal { - __undelegate(serviceProvider, subgraphDataServiceLegacyAddress, shares, true); - } - - function __undelegate(address serviceProvider, address verifier, uint256 shares, bool legacy) internal { - (, address delegator, ) = vm.readCallers(); - - // Delegation pool data is stored in a different storage slot for the legacy subgraph data service - bytes32 slotPoolShares; - if (legacy) { - slotPoolShares = bytes32(uint256(keccak256(abi.encode(serviceProvider, 20))) + 3); - } else { - slotPoolShares = bytes32( - uint256(keccak256(abi.encode(verifier, keccak256(abi.encode(serviceProvider, 33))))) + 3 - ); - } - - // before - DelegationPool memory beforePool = staking.getDelegationPool(serviceProvider, verifier); - Delegation memory beforeDelegation = staking.getDelegation(serviceProvider, verifier, delegator); - LinkedList.List memory beforeThawRequestList = staking.getThawRequestList(serviceProvider, verifier, delegator); - uint256 beforeStoragePoolShares = uint256(vm.load(address(staking), slotPoolShares)); - uint256 beforeDelegatedTokens = staking.getDelegatedTokensAvailable(serviceProvider, verifier); - - uint256 calcTokens = ((beforePool.tokens - beforePool.tokensThawing) * shares) / beforePool.shares; - uint256 calcThawingShares = beforePool.tokensThawing == 0 - ? calcTokens - : (beforePool.sharesThawing * calcTokens) / beforePool.tokensThawing; - uint64 calcThawingUntil = staking.getProvision(serviceProvider, verifier).thawingPeriod + - uint64(block.timestamp); - bytes32 calcThawRequestId = keccak256( - abi.encodePacked(serviceProvider, verifier, delegator, beforeThawRequestList.nonce) - ); - - // undelegate - vm.expectEmit(); - emit IHorizonStakingMain.ThawRequestCreated( - serviceProvider, - verifier, - delegator, - calcThawingShares, - calcThawingUntil, - calcThawRequestId - ); - vm.expectEmit(); - emit IHorizonStakingMain.TokensUndelegated(serviceProvider, verifier, delegator, calcTokens); - if (legacy) { - staking.undelegate(serviceProvider, shares); - } else { - staking.undelegate(serviceProvider, verifier, shares); - } - - // after - DelegationPool memory afterPool = staking.getDelegationPool(users.indexer, verifier); - Delegation memory afterDelegation = staking.getDelegation(serviceProvider, verifier, delegator); - LinkedList.List memory afterThawRequestList = staking.getThawRequestList(serviceProvider, verifier, delegator); - ThawRequest memory afterThawRequest = staking.getThawRequest(calcThawRequestId); - uint256 afterStoragePoolShares = uint256(vm.load(address(staking), slotPoolShares)); - uint256 afterDelegatedTokens = staking.getDelegatedTokensAvailable(serviceProvider, verifier); - - // assertions - assertEq(beforePool.shares, afterPool.shares + shares); - assertEq(beforePool.tokens, afterPool.tokens); - assertEq(beforePool.tokensThawing + calcTokens, afterPool.tokensThawing); - assertEq(beforePool.sharesThawing + calcThawingShares, afterPool.sharesThawing); - assertEq(beforeDelegation.shares - shares, afterDelegation.shares); - assertEq(afterThawRequest.shares, calcThawingShares); - assertEq(afterThawRequest.thawingUntil, calcThawingUntil); - assertEq(afterThawRequest.next, bytes32(0)); - assertEq(calcThawRequestId, afterThawRequestList.tail); - assertEq(beforeThawRequestList.nonce + 1, afterThawRequestList.nonce); - assertEq(beforeThawRequestList.count + 1, afterThawRequestList.count); - assertEq(afterDelegatedTokens + calcTokens, beforeDelegatedTokens); - // Ensure correct slot is being updated, pools are stored in different storage locations for legacy subgraph data service - assertEq(beforeStoragePoolShares, afterStoragePoolShares + shares); - } + // todo remove these function _getDelegation(address verifier) internal view returns (Delegation memory) { @@ -286,15 +129,4 @@ contract HorizonStakingTest is HorizonStakingSharedTest { assertEq(verifierTokens, verifierCutAmount); } - function _getSlotPoolTokens(address serviceProvider, address verifier, bool legacy) private pure returns (bytes32) { - bytes32 slotPoolTokens; - if (legacy) { - slotPoolTokens = bytes32(uint256(keccak256(abi.encode(serviceProvider, 20))) + 2); - } else { - slotPoolTokens = bytes32( - uint256(keccak256(abi.encode(verifier, keccak256(abi.encode(serviceProvider, 33))))) + 2 - ); - } - return slotPoolTokens; - } } diff --git a/packages/horizon/test/staking/delegation/delegate.t.sol b/packages/horizon/test/staking/delegation/delegate.t.sol index b64afa25a..383ec7f01 100644 --- a/packages/horizon/test/staking/delegation/delegate.t.sol +++ b/packages/horizon/test/staking/delegation/delegate.t.sol @@ -81,7 +81,7 @@ contract HorizonStakingDelegateTest is HorizonStakingTest { _createProvision(users.indexer, subgraphDataServiceLegacyAddress, amount, 0, 0); resetPrank(users.delegator); - _delegateLegacy(users.indexer, delegationAmount); + _delegate(users.indexer, delegationAmount); } function testDelegate_RevertWhen_InvalidPool( diff --git a/packages/horizon/test/staking/delegation/undelegate.t.sol b/packages/horizon/test/staking/delegation/undelegate.t.sol index 1f62338b9..ff5c61cb1 100644 --- a/packages/horizon/test/staking/delegation/undelegate.t.sol +++ b/packages/horizon/test/staking/delegation/undelegate.t.sol @@ -107,10 +107,10 @@ contract HorizonStakingUndelegateTest is HorizonStakingTest { _createProvision(users.indexer, subgraphDataServiceLegacyAddress, amount, 0, 0); resetPrank(users.delegator); - _delegateLegacy(users.indexer, delegationAmount); + _delegate(users.indexer, delegationAmount); Delegation memory delegation = _getDelegation(subgraphDataServiceLegacyAddress); - _undelegateLegacy(users.indexer, delegation.shares); + _undelegate(users.indexer, delegation.shares); } function testUndelegate_RevertWhen_InvalidPool( diff --git a/packages/horizon/test/staking/delegation/withdraw.t.sol b/packages/horizon/test/staking/delegation/withdraw.t.sol index 41b49fbb0..8886ff622 100644 --- a/packages/horizon/test/staking/delegation/withdraw.t.sol +++ b/packages/horizon/test/staking/delegation/withdraw.t.sol @@ -164,9 +164,9 @@ contract HorizonStakingWithdrawDelegationTest is HorizonStakingTest { _createProvision(users.indexer, subgraphDataServiceLegacyAddress, 10_000_000 ether, 0, MAX_THAWING_PERIOD); resetPrank(users.delegator); - _delegateLegacy(users.indexer, delegationAmount); + _delegate(users.indexer, delegationAmount); Delegation memory delegation = _getDelegation(subgraphDataServiceLegacyAddress); - _undelegateLegacy(users.indexer, delegation.shares); + _undelegate(users.indexer, delegation.shares); LinkedList.List memory thawingRequests = staking.getThawRequestList(users.indexer, subgraphDataServiceLegacyAddress, users.delegator); ThawRequest memory thawRequest = staking.getThawRequest(thawingRequests.tail); diff --git a/packages/horizon/test/staking/transfer-tools/ttools.t.sol b/packages/horizon/test/staking/transfer-tools/ttools.t.sol index 114e7f8ba..d49d9de87 100644 --- a/packages/horizon/test/staking/transfer-tools/ttools.t.sol +++ b/packages/horizon/test/staking/transfer-tools/ttools.t.sol @@ -72,7 +72,7 @@ contract HorizonStakingTransferToolsTest is HorizonStakingTest { _createProvision(users.indexer, subgraphDataServiceLegacyAddress, 100 ether, 0, 0); resetPrank(users.delegator); - _delegateLegacy(users.indexer, 1 ether); + _delegate(users.indexer, 1 ether); // send amount to staking contract - this should be done by the bridge resetPrank(users.delegator); @@ -95,7 +95,7 @@ contract HorizonStakingTransferToolsTest is HorizonStakingTest { _createProvision(users.indexer, subgraphDataServiceLegacyAddress, 100 ether, 0, 1 days); resetPrank(users.delegator); - _delegateLegacy(users.indexer, originalDelegationAmount); + _delegate(users.indexer, originalDelegationAmount); // send amount to staking contract - this should be done by the bridge resetPrank(users.delegator); @@ -103,7 +103,7 @@ contract HorizonStakingTransferToolsTest is HorizonStakingTest { // thaw some delegation before receiving new delegation from L1 resetPrank(users.delegator); - _undelegateLegacy(users.indexer, originalDelegationAmount / 10); + _undelegate(users.indexer, originalDelegationAmount / 10); resetPrank(graphTokenGatewayAddress); bytes memory data = abi.encode( @@ -124,7 +124,7 @@ contract HorizonStakingTransferToolsTest is HorizonStakingTest { // initialize the delegation pool resetPrank(users.delegator); - _delegateLegacy(users.indexer, originalDelegationAmount); + _delegate(users.indexer, originalDelegationAmount); // slash the entire provision resetPrank(subgraphDataServiceLegacyAddress); @@ -150,7 +150,7 @@ contract HorizonStakingTransferToolsTest is HorizonStakingTest { _createProvision(users.indexer, subgraphDataServiceLegacyAddress, 100 ether, 0, 1 days); resetPrank(users.delegator); - _delegateLegacy(users.indexer, amountDelegated); + _delegate(users.indexer, amountDelegated); // send amount to staking contract - this should be done by the bridge resetPrank(users.delegator); @@ -158,7 +158,7 @@ contract HorizonStakingTransferToolsTest is HorizonStakingTest { // thaw all delegation before receiving new delegation from L1 resetPrank(users.delegator); - _undelegateLegacy(users.indexer, amountDelegated); + _undelegate(users.indexer, amountDelegated); resetPrank(graphTokenGatewayAddress); bytes memory data = abi.encode( From 3ac7b826da5a61958a7e5b590401ffc057baf9bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1s=20Migone?= Date: Mon, 2 Sep 2024 10:31:28 -0300 Subject: [PATCH 14/24] test: refactor service provider tests MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Tomás Migone --- .../HorizonStakingShared.t.sol | 52 +++++++++++++++---- .../serviceProvider/serviceProvider.t.sol | 6 +-- 2 files changed, 44 insertions(+), 14 deletions(-) diff --git a/packages/horizon/test/shared/horizon-staking/HorizonStakingShared.t.sol b/packages/horizon/test/shared/horizon-staking/HorizonStakingShared.t.sol index 3e7c2e3bf..90ecbfbe1 100644 --- a/packages/horizon/test/shared/horizon-staking/HorizonStakingShared.t.sol +++ b/packages/horizon/test/shared/horizon-staking/HorizonStakingShared.t.sol @@ -57,7 +57,7 @@ abstract contract HorizonStakingSharedTest is GraphBaseTest { } modifier useDelegationFeeCut(IGraphPayments.PaymentTypes paymentType, uint256 cut) { - _setDelegationFeeCut(paymentType, cut); + _setDelegationFeeCut(users.indexer, subgraphDataServiceAddress, paymentType, cut); _; } @@ -85,12 +85,6 @@ abstract contract HorizonStakingSharedTest is GraphBaseTest { _provision(serviceProvider, verifier, tokens, maxVerifierCut, thawingPeriod); } - function _setDelegationFeeCut(IGraphPayments.PaymentTypes paymentType, uint256 cut) internal { - staking.setDelegationFeeCut(users.indexer, subgraphDataServiceAddress, paymentType, cut); - uint256 delegationFeeCut = staking.getDelegationFeeCut(users.indexer, subgraphDataServiceAddress, paymentType); - assertEq(delegationFeeCut, cut); - } - /* * ACTIONS: these are individual contract calls wrapped in assertion blocks to ensure they work as expected */ @@ -835,8 +829,17 @@ abstract contract HorizonStakingSharedTest is GraphBaseTest { (, address delegator, ) = vm.readCallers(); // before - DelegationPoolInternalTest memory beforePool = _getStorage_DelegationPoolInternal(serviceProvider, verifier, legacy); - DelegationInternal memory beforeDelegation = _getStorage_Delegation(serviceProvider, verifier, delegator, legacy); + DelegationPoolInternalTest memory beforePool = _getStorage_DelegationPoolInternal( + serviceProvider, + verifier, + legacy + ); + DelegationInternal memory beforeDelegation = _getStorage_Delegation( + serviceProvider, + verifier, + delegator, + legacy + ); LinkedList.List memory beforeThawRequestList = staking.getThawRequestList(serviceProvider, verifier, delegator); uint256 beforeDelegatedTokens = staking.getDelegatedTokensAvailable(serviceProvider, verifier); @@ -869,8 +872,17 @@ abstract contract HorizonStakingSharedTest is GraphBaseTest { } // after - DelegationPoolInternalTest memory afterPool = _getStorage_DelegationPoolInternal(users.indexer, verifier, legacy); - DelegationInternal memory afterDelegation = _getStorage_Delegation(serviceProvider, verifier, delegator, legacy); + DelegationPoolInternalTest memory afterPool = _getStorage_DelegationPoolInternal( + users.indexer, + verifier, + legacy + ); + DelegationInternal memory afterDelegation = _getStorage_Delegation( + serviceProvider, + verifier, + delegator, + legacy + ); LinkedList.List memory afterThawRequestList = staking.getThawRequestList(serviceProvider, verifier, delegator); ThawRequest memory afterThawRequest = staking.getThawRequest(calcThawRequestId); uint256 afterDelegatedTokens = staking.getDelegatedTokensAvailable(serviceProvider, verifier); @@ -890,6 +902,24 @@ abstract contract HorizonStakingSharedTest is GraphBaseTest { assertEq(afterDelegatedTokens + calcTokens, beforeDelegatedTokens); } + function _setDelegationFeeCut( + address serviceProvider, + address verifier, + IGraphPayments.PaymentTypes paymentType, + uint256 feeCut + ) internal { + // setDelegationFeeCut + vm.expectEmit(); + emit IHorizonStakingMain.DelegationFeeCutSet(serviceProvider, verifier, paymentType, feeCut); + staking.setDelegationFeeCut(serviceProvider, verifier, paymentType, feeCut); + + // after + uint256 afterDelegationFeeCut = staking.getDelegationFeeCut(serviceProvider, verifier, paymentType); + + // assert + assertEq(afterDelegationFeeCut, feeCut); + } + /* * STORAGE HELPERS */ diff --git a/packages/horizon/test/staking/serviceProvider/serviceProvider.t.sol b/packages/horizon/test/staking/serviceProvider/serviceProvider.t.sol index 10a68ff5e..5da6347f2 100644 --- a/packages/horizon/test/staking/serviceProvider/serviceProvider.t.sol +++ b/packages/horizon/test/staking/serviceProvider/serviceProvider.t.sol @@ -40,7 +40,7 @@ contract HorizonStakingServiceProviderTest is HorizonStakingTest { vm.assume(paymentTypeInput < 3); IGraphPayments.PaymentTypes paymentType = IGraphPayments.PaymentTypes(paymentTypeInput); feeCut = bound(feeCut, 0, MAX_PPM); - _setDelegationFeeCut(paymentType, feeCut); + _setDelegationFeeCut(users.indexer, subgraphDataServiceAddress, paymentType, feeCut); } function testServiceProvider_GetProvision( @@ -60,7 +60,7 @@ contract HorizonStakingServiceProviderTest is HorizonStakingTest { assertEq(p.maxVerifierCutPending, maxVerifierCut); assertEq(p.thawingPeriodPending, thawingPeriod); - staking.thaw(users.indexer, subgraphDataServiceAddress, thawAmount); + _thaw(users.indexer, subgraphDataServiceAddress, thawAmount); p = staking.getProvision(users.indexer, subgraphDataServiceAddress); assertEq(p.tokensThawing, thawAmount); } @@ -75,7 +75,7 @@ contract HorizonStakingServiceProviderTest is HorizonStakingTest { uint256 tokensAvailable = staking.getTokensAvailable(users.indexer, subgraphDataServiceAddress, 0); assertEq(tokensAvailable, amount); - staking.thaw(users.indexer, subgraphDataServiceAddress, thawAmount); + _thaw(users.indexer, subgraphDataServiceAddress, thawAmount); tokensAvailable = staking.getTokensAvailable(users.indexer, subgraphDataServiceAddress, 0); assertEq(tokensAvailable, amount - thawAmount); } From cb96d326538cb8678512874198162d76e89c3c6b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1s=20Migone?= Date: Mon, 2 Sep 2024 15:29:33 -0300 Subject: [PATCH 15/24] test: refactor delegation tests MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Tomás Migone --- .../HorizonStakingShared.t.sol | 256 +++++++++++++++++- .../horizon/test/staking/HorizonStaking.t.sol | 11 - .../test/staking/delegation/addToPool.t.sol | 6 +- .../test/staking/delegation/delegate.t.sol | 6 +- .../test/staking/delegation/undelegate.t.sol | 10 +- .../test/staking/delegation/withdraw.t.sol | 41 +-- .../test/staking/transfer-tools/ttools.t.sol | 2 - 7 files changed, 263 insertions(+), 69 deletions(-) diff --git a/packages/horizon/test/shared/horizon-staking/HorizonStakingShared.t.sol b/packages/horizon/test/shared/horizon-staking/HorizonStakingShared.t.sol index 90ecbfbe1..a078a13eb 100644 --- a/packages/horizon/test/shared/horizon-staking/HorizonStakingShared.t.sol +++ b/packages/horizon/test/shared/horizon-staking/HorizonStakingShared.t.sol @@ -13,6 +13,9 @@ import { MathUtils } from "../../../contracts/libraries/MathUtils.sol"; abstract contract HorizonStakingSharedTest is GraphBaseTest { using LinkedList for LinkedList.List; + + event Transfer(address indexed from, address indexed to, uint tokens); + /* * MODIFIERS */ @@ -349,7 +352,7 @@ abstract contract HorizonStakingSharedTest is GraphBaseTest { ); bytes32 expectedThawRequestId = keccak256( - abi.encodePacked(users.indexer, subgraphDataServiceAddress, users.indexer, beforeThawRequestList.nonce) + abi.encodePacked(users.indexer, verifier, users.indexer, beforeThawRequestList.nonce) ); uint256 thawingShares = beforeProvision.sharesThawing == 0 ? tokens @@ -423,7 +426,7 @@ abstract contract HorizonStakingSharedTest is GraphBaseTest { ThawRequest[] memory calcThawRequestsFulfilledList, bytes32[] memory calcThawRequestsFulfilledListIds, uint256[] memory calcThawRequestsFulfilledListTokens - ) = calcThawRequestData(serviceProvider, verifier, serviceProvider, nThawRequests); + ) = calcThawRequestData(serviceProvider, verifier, serviceProvider, nThawRequests, false); // deprovision for (uint i = 0; i < calcThawRequestsFulfilledList.length; i++) { @@ -524,7 +527,7 @@ abstract contract HorizonStakingSharedTest is GraphBaseTest { ThawRequest[] memory calcThawRequestsFulfilledList, bytes32[] memory calcThawRequestsFulfilledListIds, uint256[] memory calcThawRequestsFulfilledListTokens - ) = calcThawRequestData(serviceProvider, verifier, serviceProvider, nThawRequests); + ) = calcThawRequestData(serviceProvider, verifier, serviceProvider, nThawRequests, false); // reprovision for (uint i = 0; i < calcThawRequestsFulfilledList.length; i++) { @@ -699,7 +702,7 @@ abstract contract HorizonStakingSharedTest is GraphBaseTest { __setOperator(operator, verifier, allow, true); } - function __setOperator(address operator, address verifier, bool allow, bool locked) internal { + function __setOperator(address operator, address verifier, bool allow, bool locked) private { (, address msgSender, ) = vm.readCallers(); // staking contract knows the address of the legacy subgraph service @@ -756,7 +759,7 @@ abstract contract HorizonStakingSharedTest is GraphBaseTest { uint256 tokens, uint256 minSharesOut, bool legacy - ) internal { + ) private { (, address delegator, ) = vm.readCallers(); // before @@ -810,9 +813,11 @@ abstract contract HorizonStakingSharedTest is GraphBaseTest { assertEq(beforePool.shares + calcShares, afterPool.shares); assertEq(beforePool.tokensThawing, afterPool.tokensThawing); assertEq(beforePool.sharesThawing, afterPool.sharesThawing); + assertEq(beforeDelegation.shares + calcShares, afterDelegation.shares); + assertEq(beforeDelegation.__DEPRECATED_tokensLocked, afterDelegation.__DEPRECATED_tokensLocked); + assertEq(beforeDelegation.__DEPRECATED_tokensLockedUntil, afterDelegation.__DEPRECATED_tokensLockedUntil); assertGe(deltaShares, minSharesOut); assertEq(calcShares, deltaShares); - assertEq(beforePool.tokens + tokens, afterPool.tokens); assertEq(beforeDelegatorBalance - tokens, afterDelegatorBalance); assertEq(beforeStakingBalance + tokens, afterStakingBalance); } @@ -825,7 +830,7 @@ abstract contract HorizonStakingSharedTest is GraphBaseTest { __undelegate(serviceProvider, subgraphDataServiceLegacyAddress, shares, true); } - function __undelegate(address serviceProvider, address verifier, uint256 shares, bool legacy) internal { + function __undelegate(address serviceProvider, address verifier, uint256 shares, bool legacy) private { (, address delegator, ) = vm.readCallers(); // before @@ -902,6 +907,227 @@ abstract contract HorizonStakingSharedTest is GraphBaseTest { assertEq(afterDelegatedTokens + calcTokens, beforeDelegatedTokens); } + function _withdrawDelegated( + address serviceProvider, + address verifier, + address newServiceProvider, + uint256 minSharesForNewProvider, + uint256 nThawRequests + ) internal { + __withdrawDelegated( + serviceProvider, + verifier, + newServiceProvider, + minSharesForNewProvider, + nThawRequests, + false + ); + } + + function _withdrawDelegated(address serviceProvider, address newServiceProvider) internal { + __withdrawDelegated(serviceProvider, subgraphDataServiceLegacyAddress, newServiceProvider, 0, 0, true); + } + + function __withdrawDelegated( + address _serviceProvider, + address _verifier, + address _newServiceProvider, + uint256 _minSharesForNewProvider, + uint256 _nThawRequests, + bool legacy + ) private { + (, address msgSender, ) = vm.readCallers(); + + bool reDelegate = _newServiceProvider != address(0); + + // before + DelegationPoolInternalTest memory beforeDelegationPool = _getStorage_DelegationPoolInternal( + _serviceProvider, + _verifier, + legacy + ); + DelegationPoolInternalTest memory beforeNewDelegationPool = _getStorage_DelegationPoolInternal( + _newServiceProvider, + _verifier, + legacy + ); + DelegationInternal memory beforeNewDelegation = _getStorage_Delegation( + _newServiceProvider, + _verifier, + msgSender, + legacy + ); + LinkedList.List memory beforeThawRequestList = staking.getThawRequestList( + _serviceProvider, + _verifier, + msgSender + ); + uint256 beforeSenderBalance = token.balanceOf(msgSender); + uint256 beforeStakingBalance = token.balanceOf(address(staking)); + + ( + uint256 calcTokensThawed, + uint256 calcTokensThawing, + uint256 calcSharesThawing, + ThawRequest[] memory calcThawRequestsFulfilledList, + bytes32[] memory calcThawRequestsFulfilledListIds, + uint256[] memory calcThawRequestsFulfilledListTokens + ) = calcThawRequestData(_serviceProvider, _verifier, msgSender, _nThawRequests, true); + + // withdrawDelegated + for (uint i = 0; i < calcThawRequestsFulfilledList.length; i++) { + ThawRequest memory thawRequest = calcThawRequestsFulfilledList[i]; + vm.expectEmit(address(staking)); + emit IHorizonStakingMain.ThawRequestFulfilled( + calcThawRequestsFulfilledListIds[i], + calcThawRequestsFulfilledListTokens[i], + thawRequest.shares, + thawRequest.thawingUntil + ); + } + vm.expectEmit(address(staking)); + emit IHorizonStakingMain.ThawRequestsFulfilled( + _serviceProvider, + _verifier, + msgSender, + calcThawRequestsFulfilledList.length, + calcTokensThawed + ); + if (calcTokensThawed != 0) { + vm.expectEmit(); + if (reDelegate) { + emit IHorizonStakingMain.TokensDelegated(_newServiceProvider, _verifier, msgSender, calcTokensThawed); + } else { + emit Transfer(address(staking), msgSender, calcTokensThawed); + } + } + vm.expectEmit(); + emit IHorizonStakingMain.DelegatedTokensWithdrawn(_serviceProvider, _verifier, msgSender, calcTokensThawed); + staking.withdrawDelegated( + _serviceProvider, + _verifier, + _newServiceProvider, + _minSharesForNewProvider, + _nThawRequests + ); + + // after + DelegationPoolInternalTest memory afterDelegationPool = _getStorage_DelegationPoolInternal( + _serviceProvider, + _verifier, + legacy + ); + DelegationPoolInternalTest memory afterNewDelegationPool = _getStorage_DelegationPoolInternal( + _newServiceProvider, + _verifier, + legacy + ); + DelegationInternal memory afterNewDelegation = _getStorage_Delegation( + _newServiceProvider, + _verifier, + msgSender, + legacy + ); + LinkedList.List memory afterThawRequestList = staking.getThawRequestList( + _serviceProvider, + _verifier, + msgSender + ); + uint256 afterSenderBalance = token.balanceOf(msgSender); + uint256 afterStakingBalance = token.balanceOf(address(staking)); + + // assert + assertEq(afterDelegationPool.tokens, beforeDelegationPool.tokens - calcTokensThawed); + assertEq(afterDelegationPool.shares, beforeDelegationPool.shares); + assertEq(afterDelegationPool.tokensThawing, calcTokensThawing); + assertEq(afterDelegationPool.sharesThawing, calcSharesThawing); + + for (uint i = 0; i < calcThawRequestsFulfilledListIds.length; i++) { + ThawRequest memory thawRequest = staking.getThawRequest(calcThawRequestsFulfilledListIds[i]); + assertEq(thawRequest.shares, 0); + assertEq(thawRequest.thawingUntil, 0); + assertEq(thawRequest.next, bytes32(0)); + } + if (calcThawRequestsFulfilledList.length == 0) { + assertEq(afterThawRequestList.head, beforeThawRequestList.head); + } else { + assertEq( + afterThawRequestList.head, + calcThawRequestsFulfilledList.length == beforeThawRequestList.count + ? bytes32(0) + : calcThawRequestsFulfilledList[calcThawRequestsFulfilledList.length - 1].next + ); + } + assertEq( + afterThawRequestList.tail, + calcThawRequestsFulfilledList.length == beforeThawRequestList.count + ? bytes32(0) + : beforeThawRequestList.tail + ); + assertEq(afterThawRequestList.count, beforeThawRequestList.count - calcThawRequestsFulfilledList.length); + assertEq(afterThawRequestList.nonce, beforeThawRequestList.nonce); + + if (reDelegate) { + uint256 calcShares = (afterNewDelegationPool.tokens == 0 || + afterNewDelegationPool.tokens == afterNewDelegationPool.tokensThawing) + ? calcTokensThawed + : ((calcTokensThawed * afterNewDelegationPool.shares) / + (afterNewDelegationPool.tokens - afterNewDelegationPool.tokensThawing)); + uint256 deltaShares = afterNewDelegation.shares - beforeNewDelegation.shares; + + assertEq(afterNewDelegationPool.tokens, beforeNewDelegationPool.tokens + calcTokensThawed); + assertEq(afterNewDelegationPool.shares, beforeNewDelegationPool.shares + calcShares); + assertEq(afterNewDelegationPool.tokensThawing, beforeNewDelegationPool.tokensThawing); + assertEq(afterNewDelegationPool.sharesThawing, beforeNewDelegationPool.sharesThawing); + assertEq(afterNewDelegation.shares, beforeNewDelegation.shares + calcShares); + assertEq(afterNewDelegation.__DEPRECATED_tokensLocked, beforeNewDelegation.__DEPRECATED_tokensLocked); + assertEq( + afterNewDelegation.__DEPRECATED_tokensLockedUntil, + beforeNewDelegation.__DEPRECATED_tokensLockedUntil + ); + assertGe(deltaShares, _minSharesForNewProvider); + assertEq(calcShares, deltaShares); + assertEq(afterSenderBalance - beforeSenderBalance, 0); + assertEq(beforeStakingBalance - afterStakingBalance, 0); + } else { + assertEq(beforeStakingBalance - afterStakingBalance, calcTokensThawed); + assertEq(afterSenderBalance - beforeSenderBalance, calcTokensThawed); + } + } + + function _addToDelegationPool(address serviceProvider, address verifier, uint256 tokens) internal { + (, address msgSender, ) = vm.readCallers(); + + // staking contract knows the address of the legacy subgraph service + // but we cannot read it as it's an immutable, we have to use the global var :/ + bool legacy = verifier == subgraphDataServiceLegacyAddress; + + // before + DelegationPoolInternalTest memory beforePool = _getStorage_DelegationPoolInternal(serviceProvider, verifier, legacy); + uint256 beforeSenderBalance = token.balanceOf(msgSender); + uint256 beforeStakingBalance = token.balanceOf(address(staking)); + + // addToDelegationPool + vm.expectEmit(); + emit Transfer(msgSender, address(staking), tokens); + vm.expectEmit(address(staking)); + emit IHorizonStakingMain.TokensToDelegationPoolAdded(serviceProvider, verifier, tokens); + staking.addToDelegationPool(serviceProvider, verifier, tokens); + + // after + DelegationPoolInternalTest memory afterPool = _getStorage_DelegationPoolInternal(serviceProvider, verifier, legacy); + uint256 afterSenderBalance = token.balanceOf(msgSender); + uint256 afterStakingBalance = token.balanceOf(address(staking)); + + // assert + assertEq(beforeSenderBalance - tokens, afterSenderBalance); + assertEq(beforeStakingBalance + tokens, afterStakingBalance); + assertEq(beforePool.tokens + tokens, afterPool.tokens); + assertEq(beforePool.shares, afterPool.shares); + assertEq(beforePool.tokensThawing, afterPool.tokensThawing); + assertEq(beforePool.sharesThawing, afterPool.sharesThawing); + } + function _setDelegationFeeCut( address serviceProvider, address verifier, @@ -1073,7 +1299,8 @@ abstract contract HorizonStakingSharedTest is GraphBaseTest { address serviceProvider, address verifier, address owner, - uint256 iterations + uint256 iterations, + bool delegation ) private view returns (uint256, uint256, uint256, ThawRequest[] memory, bytes32[] memory, uint256[] memory) { LinkedList.List memory thawRequestList = staking.getThawRequestList(serviceProvider, verifier, owner); if (thawRequestList.count == 0) { @@ -1081,10 +1308,11 @@ abstract contract HorizonStakingSharedTest is GraphBaseTest { } Provision memory prov = staking.getProvision(serviceProvider, verifier); + DelegationPool memory pool = staking.getDelegationPool(serviceProvider, verifier); uint256 tokensThawed = 0; - uint256 tokensThawing = prov.tokensThawing; - uint256 sharesThawing = prov.sharesThawing; + uint256 tokensThawing = delegation ? pool.tokensThawing : prov.tokensThawing; + uint256 sharesThawing = delegation ? pool.sharesThawing : prov.sharesThawing; uint256 thawRequestsFulfilled = 0; bytes32 thawRequestId = thawRequestList.head; @@ -1092,7 +1320,9 @@ abstract contract HorizonStakingSharedTest is GraphBaseTest { ThawRequest memory thawRequest = staking.getThawRequest(thawRequestId); if (thawRequest.thawingUntil <= block.timestamp) { thawRequestsFulfilled++; - uint256 tokens = (thawRequest.shares * prov.tokensThawing) / prov.sharesThawing; + uint256 tokens = delegation + ? (thawRequest.shares * pool.tokensThawing) / pool.sharesThawing + : (thawRequest.shares * prov.tokensThawing) / prov.sharesThawing; tokensThawed += tokens; tokensThawing -= tokens; sharesThawing -= thawRequest.shares; @@ -1111,7 +1341,9 @@ abstract contract HorizonStakingSharedTest is GraphBaseTest { while (thawRequestId != bytes32(0) && (iterations == 0 || i < iterations)) { ThawRequest memory thawRequest = staking.getThawRequest(thawRequestId); if (thawRequest.thawingUntil <= block.timestamp) { - uint256 tokens = (thawRequest.shares * prov.tokensThawing) / prov.sharesThawing; + uint256 tokens = delegation + ? (thawRequest.shares * pool.tokensThawing) / pool.sharesThawing + : (thawRequest.shares * prov.tokensThawing) / prov.sharesThawing; thawRequestsFulfilledListTokens[i] = tokens; thawRequestsFulfilledListIds[i] = thawRequestId; thawRequestsFulfilledList[i] = staking.getThawRequest(thawRequestId); diff --git a/packages/horizon/test/staking/HorizonStaking.t.sol b/packages/horizon/test/staking/HorizonStaking.t.sol index 67dc1a04f..75d2b7569 100644 --- a/packages/horizon/test/staking/HorizonStaking.t.sol +++ b/packages/horizon/test/staking/HorizonStaking.t.sol @@ -65,17 +65,6 @@ contract HorizonStakingTest is HorizonStakingSharedTest { * HELPERS */ - - - // todo remove these - function _getDelegation(address verifier) internal view returns (Delegation memory) { - return staking.getDelegation(users.indexer, verifier, users.delegator); - } - - function _getDelegationPool(address verifier) internal view returns (DelegationPool memory) { - return staking.getDelegationPool(users.indexer, verifier); - } - function _slash(address serviceProvider, address verifier, uint256 tokens, uint256 verifierCutAmount) internal { uint256 beforeProviderTokens = staking.getProviderTokensAvailable(serviceProvider, verifier); uint256 beforeDelegationTokens = staking.getDelegatedTokensAvailable(serviceProvider, verifier); diff --git a/packages/horizon/test/staking/delegation/addToPool.t.sol b/packages/horizon/test/staking/delegation/addToPool.t.sol index 4ef0c480a..56104cd3d 100644 --- a/packages/horizon/test/staking/delegation/addToPool.t.sol +++ b/packages/horizon/test/staking/delegation/addToPool.t.sol @@ -27,9 +27,7 @@ contract HorizonStakingDelegationAddToPoolTest is HorizonStakingTest { resetPrank(subgraphDataServiceAddress); mint(subgraphDataServiceAddress, delegationAmount); token.approve(address(staking), delegationAmount); - vm.expectEmit(address(staking)); - emit IHorizonStakingMain.TokensToDelegationPoolAdded(users.indexer, subgraphDataServiceAddress, delegationAmount); - staking.addToDelegationPool(users.indexer, subgraphDataServiceAddress, delegationAmount); + _addToDelegationPool(users.indexer, subgraphDataServiceAddress, delegationAmount); uint256 delegatedTokens = staking.getDelegatedTokensAvailable(users.indexer, subgraphDataServiceAddress); assertEq(delegatedTokens, delegationAmount); @@ -46,7 +44,7 @@ contract HorizonStakingDelegationAddToPoolTest is HorizonStakingTest { resetPrank(address(payments)); mint(address(payments), delegationAmount); token.approve(address(staking), delegationAmount); - staking.addToDelegationPool(users.indexer, subgraphDataServiceAddress, delegationAmount); + _addToDelegationPool(users.indexer, subgraphDataServiceAddress, delegationAmount); uint256 delegatedTokens = staking.getDelegatedTokensAvailable(users.indexer, subgraphDataServiceAddress); assertEq(delegatedTokens, delegationAmount); diff --git a/packages/horizon/test/staking/delegation/delegate.t.sol b/packages/horizon/test/staking/delegation/delegate.t.sol index 383ec7f01..8bbd43a73 100644 --- a/packages/horizon/test/staking/delegation/delegate.t.sol +++ b/packages/horizon/test/staking/delegation/delegate.t.sol @@ -30,7 +30,7 @@ contract HorizonStakingDelegateTest is HorizonStakingTest { vm.startPrank(users.delegator); _delegate(users.indexer, subgraphDataServiceAddress, delegationAmount, 0); - Delegation memory delegation = _getDelegation(subgraphDataServiceAddress); + DelegationInternal memory delegation = _getStorage_Delegation(users.indexer, subgraphDataServiceAddress, users.delegator, false); undelegateAmount = bound(undelegateAmount, 1 wei, delegation.shares - 1 ether); _undelegate(users.indexer, subgraphDataServiceAddress, undelegateAmount); @@ -46,7 +46,7 @@ contract HorizonStakingDelegateTest is HorizonStakingTest { vm.startPrank(users.delegator); _delegate(users.indexer, subgraphDataServiceAddress, delegationAmount, 0); - Delegation memory delegation = _getDelegation(subgraphDataServiceAddress); + DelegationInternal memory delegation = _getStorage_Delegation(users.indexer, subgraphDataServiceAddress, users.delegator, false); _undelegate(users.indexer, subgraphDataServiceAddress, delegation.shares); _delegate(users.indexer, subgraphDataServiceAddress, delegationAmount, 0); @@ -112,7 +112,7 @@ contract HorizonStakingDelegateTest is HorizonStakingTest { delegationTokens = bound(delegationTokens, MIN_DELEGATION, MAX_STAKING_TOKENS); resetPrank(users.delegator); _delegate(users.indexer, subgraphDataServiceAddress, delegationTokens, 0); - Delegation memory delegation = _getDelegation(subgraphDataServiceAddress); + DelegationInternal memory delegation = _getStorage_Delegation(users.indexer, subgraphDataServiceAddress, users.delegator, false); _undelegate(users.indexer, subgraphDataServiceAddress, delegation.shares); resetPrank(subgraphDataServiceAddress); diff --git a/packages/horizon/test/staking/delegation/undelegate.t.sol b/packages/horizon/test/staking/delegation/undelegate.t.sol index ff5c61cb1..ddafc722c 100644 --- a/packages/horizon/test/staking/delegation/undelegate.t.sol +++ b/packages/horizon/test/staking/delegation/undelegate.t.sol @@ -17,7 +17,7 @@ contract HorizonStakingUndelegateTest is HorizonStakingTest { uint256 delegationAmount ) public useIndexer useProvision(amount, 0, 0) useDelegation(delegationAmount) { resetPrank(users.delegator); - Delegation memory delegation = _getDelegation(subgraphDataServiceAddress); + DelegationInternal memory delegation = _getStorage_Delegation(users.indexer, subgraphDataServiceAddress, users.delegator, false); _undelegate(users.indexer, subgraphDataServiceAddress, delegation.shares); } @@ -31,7 +31,7 @@ contract HorizonStakingUndelegateTest is HorizonStakingTest { resetPrank(users.delegator); _delegate(users.indexer, subgraphDataServiceAddress, delegationAmount, 0); - Delegation memory delegation = _getDelegation(subgraphDataServiceAddress); + DelegationInternal memory delegation = _getStorage_Delegation(users.indexer, subgraphDataServiceAddress, users.delegator, false); // there is a min delegation amount of 1 ether after undelegating uint256 undelegateAmount = (delegation.shares - 1 ether) / undelegateSteps; @@ -73,7 +73,7 @@ contract HorizonStakingUndelegateTest is HorizonStakingTest { uint256 overDelegationShares ) public useIndexer useProvision(amount, 0, 0) useDelegation(delegationAmount) { resetPrank(users.delegator); - Delegation memory delegation = _getDelegation(subgraphDataServiceAddress); + DelegationInternal memory delegation = _getStorage_Delegation(users.indexer, subgraphDataServiceAddress, users.delegator, false); overDelegationShares = bound(overDelegationShares, delegation.shares + 1, MAX_STAKING_TOKENS + 1); bytes memory expectedError = abi.encodeWithSignature( @@ -109,7 +109,7 @@ contract HorizonStakingUndelegateTest is HorizonStakingTest { resetPrank(users.delegator); _delegate(users.indexer, delegationAmount); - Delegation memory delegation = _getDelegation(subgraphDataServiceLegacyAddress); + DelegationInternal memory delegation = _getStorage_Delegation(users.indexer, subgraphDataServiceAddress, users.delegator, true); _undelegate(users.indexer, delegation.shares); } @@ -125,7 +125,7 @@ contract HorizonStakingUndelegateTest is HorizonStakingTest { _slash(users.indexer, subgraphDataServiceAddress, tokens + delegationTokens, 0); resetPrank(users.delegator); - Delegation memory delegation = _getDelegation(subgraphDataServiceAddress); + DelegationInternal memory delegation = _getStorage_Delegation(users.indexer, subgraphDataServiceAddress, users.delegator, false); vm.expectRevert(abi.encodeWithSelector( IHorizonStakingMain.HorizonStakingInvalidDelegationPoolState.selector, users.indexer, diff --git a/packages/horizon/test/staking/delegation/withdraw.t.sol b/packages/horizon/test/staking/delegation/withdraw.t.sol index 8886ff622..105ce2914 100644 --- a/packages/horizon/test/staking/delegation/withdraw.t.sol +++ b/packages/horizon/test/staking/delegation/withdraw.t.sol @@ -17,11 +17,11 @@ contract HorizonStakingWithdrawDelegationTest is HorizonStakingTest { modifier useUndelegate(uint256 shares) { vm.stopPrank(); vm.startPrank(users.delegator); - Delegation memory delegation = _getDelegation(subgraphDataServiceAddress); + DelegationInternal memory delegation = _getStorage_Delegation(users.indexer, subgraphDataServiceAddress, users.delegator, false); shares = bound(shares, 1, delegation.shares); if (shares != delegation.shares) { - DelegationPool memory pool = _getDelegationPool(subgraphDataServiceAddress); + DelegationPoolInternalTest memory pool = _getStorage_DelegationPoolInternal(users.indexer, subgraphDataServiceAddress, false); uint256 tokens = (shares * (pool.tokens - pool.tokensThawing)) / pool.shares; uint256 newTokensThawing = pool.tokensThawing + tokens; uint256 remainingTokens = (delegation.shares * (pool.tokens - newTokensThawing)) / pool.shares; @@ -35,29 +35,6 @@ contract HorizonStakingWithdrawDelegationTest is HorizonStakingTest { /* * HELPERS */ - - function _withdrawDelegated(address _verifier, address _newIndexer) private { - LinkedList.List memory thawingRequests = staking.getThawRequestList(users.indexer, _verifier, users.delegator); - ThawRequest memory thawRequest = staking.getThawRequest(thawingRequests.tail); - - uint256 previousBalance = token.balanceOf(users.delegator); - uint256 expectedTokens = _expectedTokensFromThawRequest(thawRequest, _verifier); - staking.withdrawDelegated(users.indexer, _verifier, _newIndexer, 0, 0); - - if (_newIndexer != address(0)) { - uint256 delegatedTokens = staking.getDelegatedTokensAvailable(_newIndexer, _verifier); - assertEq(delegatedTokens, expectedTokens); - } else { - uint256 newBalance = token.balanceOf(users.delegator); - assertEq(newBalance - previousBalance, expectedTokens); - } - } - - function _expectedTokensFromThawRequest(ThawRequest memory thawRequest, address verifier) private view returns (uint256) { - DelegationPool memory pool = _getDelegationPool(verifier); - return (thawRequest.shares * pool.tokensThawing) / pool.sharesThawing; - } - function _setupNewIndexer(uint256 tokens) private returns(address) { (, address msgSender,) = vm.readCallers(); @@ -88,7 +65,7 @@ contract HorizonStakingWithdrawDelegationTest is HorizonStakingTest { skip(thawRequest.thawingUntil + 1); - _withdrawDelegated(subgraphDataServiceAddress, address(0)); + _withdrawDelegated(users.indexer, subgraphDataServiceAddress, address(0), 0, 0); } function testWithdrawDelegation_RevertWhen_NotThawing( @@ -117,7 +94,7 @@ contract HorizonStakingWithdrawDelegationTest is HorizonStakingTest { // Setup new service provider address newIndexer = _setupNewIndexer(10_000_000 ether); - _withdrawDelegated(subgraphDataServiceAddress, newIndexer); + _withdrawDelegated(users.indexer, subgraphDataServiceAddress, newIndexer, 0, 0); } function testWithdrawDelegation_ZeroTokens( @@ -130,7 +107,7 @@ contract HorizonStakingWithdrawDelegationTest is HorizonStakingTest { useUndelegate(delegationAmount) { uint256 previousBalance = token.balanceOf(users.delegator); - staking.withdrawDelegated(users.indexer, subgraphDataServiceAddress, address(0), 0, 0); + _withdrawDelegated(users.indexer, subgraphDataServiceAddress, address(0), 0, 0); // Nothing changed since thawing period haven't finished uint256 newBalance = token.balanceOf(users.delegator); @@ -150,7 +127,7 @@ contract HorizonStakingWithdrawDelegationTest is HorizonStakingTest { address newIndexer = _setupNewIndexer(10_000_000 ether); uint256 previousBalance = token.balanceOf(users.delegator); - staking.withdrawDelegated(users.indexer, subgraphDataServiceAddress, newIndexer, 0, 0); + _withdrawDelegated(users.indexer, subgraphDataServiceAddress, newIndexer, 0, 0); uint256 newBalance = token.balanceOf(users.delegator); assertEq(newBalance, previousBalance); @@ -165,7 +142,7 @@ contract HorizonStakingWithdrawDelegationTest is HorizonStakingTest { resetPrank(users.delegator); _delegate(users.indexer, delegationAmount); - Delegation memory delegation = _getDelegation(subgraphDataServiceLegacyAddress); + DelegationInternal memory delegation = _getStorage_Delegation(users.indexer, subgraphDataServiceAddress, users.delegator, true); _undelegate(users.indexer, delegation.shares); LinkedList.List memory thawingRequests = staking.getThawRequestList(users.indexer, subgraphDataServiceLegacyAddress, users.delegator); @@ -173,7 +150,7 @@ contract HorizonStakingWithdrawDelegationTest is HorizonStakingTest { skip(thawRequest.thawingUntil + 1); - _withdrawDelegated(subgraphDataServiceLegacyAddress, address(0)); + _withdrawDelegated(users.indexer, address(0)); } function testWithdrawDelegation_RevertWhen_InvalidPool( @@ -183,7 +160,7 @@ contract HorizonStakingWithdrawDelegationTest is HorizonStakingTest { delegationTokens = bound(delegationTokens, MIN_DELEGATION, MAX_STAKING_TOKENS); resetPrank(users.delegator); _delegate(users.indexer, subgraphDataServiceAddress, delegationTokens, 0); - Delegation memory delegation = _getDelegation(subgraphDataServiceAddress); + DelegationInternal memory delegation = _getStorage_Delegation(users.indexer, subgraphDataServiceAddress, users.delegator, false); _undelegate(users.indexer, subgraphDataServiceAddress, delegation.shares); skip(MAX_THAWING_PERIOD + 1); diff --git a/packages/horizon/test/staking/transfer-tools/ttools.t.sol b/packages/horizon/test/staking/transfer-tools/ttools.t.sol index d49d9de87..524c4a4ec 100644 --- a/packages/horizon/test/staking/transfer-tools/ttools.t.sol +++ b/packages/horizon/test/staking/transfer-tools/ttools.t.sol @@ -9,8 +9,6 @@ import { IL2StakingBase } from "@graphprotocol/contracts/contracts/l2/staking/IL import { IHorizonStakingExtension } from "../../../contracts/interfaces/internal/IHorizonStakingExtension.sol"; contract HorizonStakingTransferToolsTest is HorizonStakingTest { - event Transfer(address indexed from, address indexed to, uint tokens); - /* * TESTS */ From dc419964a9ff71884ff6c9beb09243ddb75929fb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1s=20Migone?= Date: Mon, 2 Sep 2024 16:33:06 -0300 Subject: [PATCH 16/24] test: refactor governance tests MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Tomás Migone --- .../HorizonStakingShared.t.sol | 100 +++++++++++++++--- .../test/staking/governance/governance.t.sol | 23 ++-- 2 files changed, 93 insertions(+), 30 deletions(-) diff --git a/packages/horizon/test/shared/horizon-staking/HorizonStakingShared.t.sol b/packages/horizon/test/shared/horizon-staking/HorizonStakingShared.t.sol index a078a13eb..07e75fdee 100644 --- a/packages/horizon/test/shared/horizon-staking/HorizonStakingShared.t.sol +++ b/packages/horizon/test/shared/horizon-staking/HorizonStakingShared.t.sol @@ -7,6 +7,7 @@ import { GraphBaseTest } from "../../GraphBase.t.sol"; import { IGraphPayments } from "../../../contracts/interfaces/IGraphPayments.sol"; import { IHorizonStakingBase } from "../../../contracts/interfaces/internal/IHorizonStakingBase.sol"; import { IHorizonStakingMain } from "../../../contracts/interfaces/internal/IHorizonStakingMain.sol"; +import { IHorizonStakingExtension } from "../../../contracts/interfaces/internal/IHorizonStakingExtension.sol"; import { LinkedList } from "../../../contracts/libraries/LinkedList.sol"; import { MathUtils } from "../../../contracts/libraries/MathUtils.sol"; @@ -732,19 +733,6 @@ abstract contract HorizonStakingSharedTest is GraphBaseTest { assertEq(afterOperatorAllowed, allow); } - function _setAllowedLockedVerifier(address verifier, bool allowed) internal { - // setAllowedLockedVerifier - vm.expectEmit(); - emit IHorizonStakingMain.AllowedLockedVerifierSet(verifier, allowed); - staking.setAllowedLockedVerifier(verifier, allowed); - - // after - bool afterAllowed = staking.isAllowedLockedVerifier(verifier); - - // assert - assertEq(afterAllowed, allowed); - } - function _delegate(address serviceProvider, address verifier, uint256 tokens, uint256 minSharesOut) internal { __delegate(serviceProvider, verifier, tokens, minSharesOut, false); } @@ -1103,7 +1091,11 @@ abstract contract HorizonStakingSharedTest is GraphBaseTest { bool legacy = verifier == subgraphDataServiceLegacyAddress; // before - DelegationPoolInternalTest memory beforePool = _getStorage_DelegationPoolInternal(serviceProvider, verifier, legacy); + DelegationPoolInternalTest memory beforePool = _getStorage_DelegationPoolInternal( + serviceProvider, + verifier, + legacy + ); uint256 beforeSenderBalance = token.balanceOf(msgSender); uint256 beforeStakingBalance = token.balanceOf(address(staking)); @@ -1115,7 +1107,11 @@ abstract contract HorizonStakingSharedTest is GraphBaseTest { staking.addToDelegationPool(serviceProvider, verifier, tokens); // after - DelegationPoolInternalTest memory afterPool = _getStorage_DelegationPoolInternal(serviceProvider, verifier, legacy); + DelegationPoolInternalTest memory afterPool = _getStorage_DelegationPoolInternal( + serviceProvider, + verifier, + legacy + ); uint256 afterSenderBalance = token.balanceOf(msgSender); uint256 afterStakingBalance = token.balanceOf(address(staking)); @@ -1146,6 +1142,71 @@ abstract contract HorizonStakingSharedTest is GraphBaseTest { assertEq(afterDelegationFeeCut, feeCut); } + function _setAllowedLockedVerifier(address verifier, bool allowed) internal { + // setAllowedLockedVerifier + vm.expectEmit(); + emit IHorizonStakingMain.AllowedLockedVerifierSet(verifier, allowed); + staking.setAllowedLockedVerifier(verifier, allowed); + + // after + bool afterAllowed = staking.isAllowedLockedVerifier(verifier); + + // assert + assertEq(afterAllowed, allowed); + } + + function _setDelegationSlashingEnabled() internal { + // setDelegationSlashingEnabled + vm.expectEmit(); + emit IHorizonStakingMain.DelegationSlashingEnabled(true); + staking.setDelegationSlashingEnabled(); + + // after + bool afterEnabled = staking.isDelegationSlashingEnabled(); + + // assert + assertEq(afterEnabled, true); + } + + function _clearThawingPeriod() internal { + // clearThawingPeriod + vm.expectEmit(address(staking)); + emit IHorizonStakingMain.ThawingPeriodCleared(); + staking.clearThawingPeriod(); + + // after + uint64 afterThawingPeriod = staking.__DEPRECATED_getThawingPeriod(); + + // assert + assertEq(afterThawingPeriod, 0); + } + + function _setMaxThawingPeriod(uint64 maxThawingPeriod) internal { + // setMaxThawingPeriod + vm.expectEmit(address(staking)); + emit IHorizonStakingMain.MaxThawingPeriodSet(maxThawingPeriod); + staking.setMaxThawingPeriod(maxThawingPeriod); + + // after + uint64 afterMaxThawingPeriod = staking.getMaxThawingPeriod(); + + // assert + assertEq(afterMaxThawingPeriod, maxThawingPeriod); + } + + function _setCounterpartStakingAddress(address counterpartStakingAddress) internal { + // setCounterpartStakingAddress + vm.expectEmit(address(staking)); + emit IHorizonStakingExtension.CounterpartStakingAddressSet(counterpartStakingAddress); + staking.setCounterpartStakingAddress(counterpartStakingAddress); + + // after + address afterCounterpartStakingAddress = _getStorage_CounterpartStakingAddress(); + + // assert + assertEq(afterCounterpartStakingAddress, counterpartStakingAddress); + } + /* * STORAGE HELPERS */ @@ -1292,6 +1353,15 @@ abstract contract HorizonStakingSharedTest is GraphBaseTest { return delegation; } + function _setStorage_DEPRECATED_ThawingPeriod(uint64 thawingPeriod) internal { + vm.store(address(staking), bytes32(uint256(13)), bytes32(uint256(thawingPeriod))); + } + + function _getStorage_CounterpartStakingAddress() internal view returns (address) { + uint256 slot = 24; + return address(uint160(uint256(vm.load(address(staking), bytes32(slot))))); + } + /* * MISC: private functions to help with testing */ diff --git a/packages/horizon/test/staking/governance/governance.t.sol b/packages/horizon/test/staking/governance/governance.t.sol index 932e053c4..19d1c6de0 100644 --- a/packages/horizon/test/staking/governance/governance.t.sol +++ b/packages/horizon/test/staking/governance/governance.t.sol @@ -21,8 +21,7 @@ contract HorizonStakingGovernanceTest is HorizonStakingTest { */ function testGovernance_SetAllowedLockedVerifier() public useGovernor { - staking.setAllowedLockedVerifier(subgraphDataServiceAddress, true); - assertTrue(staking.isAllowedLockedVerifier(subgraphDataServiceAddress)); + _setAllowedLockedVerifier(subgraphDataServiceAddress, true); } function testGovernance_RevertWhen_SetAllowedLockedVerifier_NotGovernor() public useIndexer { @@ -32,8 +31,7 @@ contract HorizonStakingGovernanceTest is HorizonStakingTest { } function testGovernance_SetDelgationSlashingEnabled() public useGovernor { - staking.setDelegationSlashingEnabled(); - assertTrue(staking.isDelegationSlashingEnabled()); + _setDelegationSlashingEnabled(); } function testGovernance_SetDelgationSlashing_NotGovernor() public useIndexer { @@ -42,12 +40,11 @@ contract HorizonStakingGovernanceTest is HorizonStakingTest { staking.setDelegationSlashingEnabled(); } - function testGovernance_ClearThawingPeriod(uint32 thawingPeriod) public useGovernor { - vm.store(address(staking), bytes32(uint256(13)), bytes32(uint256(thawingPeriod))); - assertEq(staking.__DEPRECATED_getThawingPeriod(), thawingPeriod); + function testGovernance_ClearThawingPeriod(uint64 thawingPeriod) public useGovernor { + // simulate previous thawing period + _setStorage_DEPRECATED_ThawingPeriod(thawingPeriod); - staking.clearThawingPeriod(); - assertEq(staking.__DEPRECATED_getThawingPeriod(), 0); + _clearThawingPeriod(); } function testGovernance_ClearThawingPeriod_NotGovernor() public useIndexer { @@ -57,8 +54,7 @@ contract HorizonStakingGovernanceTest is HorizonStakingTest { } function testGovernance__SetMaxThawingPeriod(uint64 maxThawingPeriod) public useGovernor { - staking.setMaxThawingPeriod(maxThawingPeriod); - assertEq(staking.getMaxThawingPeriod(), maxThawingPeriod); + _setMaxThawingPeriod(maxThawingPeriod); } function testGovernance__SetMaxThawingPeriod_NotGovernor() public useIndexer { @@ -68,10 +64,7 @@ contract HorizonStakingGovernanceTest is HorizonStakingTest { } function testGovernance_SetCounterpartStakingAddress(address counterpartStakingAddress) public useGovernor { - staking.setCounterpartStakingAddress(counterpartStakingAddress); - bytes32 storedValue = vm.load(address(staking), bytes32(uint256(24))); - address storedCounterpartStakingAddress = address(uint160(uint256(storedValue))); - assertEq(storedCounterpartStakingAddress, counterpartStakingAddress); + _setCounterpartStakingAddress(counterpartStakingAddress); } function testGovernance_RevertWhen_SetCounterpartStakingAddress_NotGovernor( From 8157a68014e0082de350b0793742ba92742ad974 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1s=20Migone?= Date: Mon, 2 Sep 2024 16:36:31 -0300 Subject: [PATCH 17/24] test: refactor ttools tests MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Tomás Migone --- .../HorizonStakingShared.t.sol | 81 +++++++++++++++++ .../test/staking/transfer-tools/ttools.t.sol | 88 +------------------ 2 files changed, 82 insertions(+), 87 deletions(-) diff --git a/packages/horizon/test/shared/horizon-staking/HorizonStakingShared.t.sol b/packages/horizon/test/shared/horizon-staking/HorizonStakingShared.t.sol index 07e75fdee..1d83a981e 100644 --- a/packages/horizon/test/shared/horizon-staking/HorizonStakingShared.t.sol +++ b/packages/horizon/test/shared/horizon-staking/HorizonStakingShared.t.sol @@ -8,6 +8,7 @@ import { IGraphPayments } from "../../../contracts/interfaces/IGraphPayments.sol import { IHorizonStakingBase } from "../../../contracts/interfaces/internal/IHorizonStakingBase.sol"; import { IHorizonStakingMain } from "../../../contracts/interfaces/internal/IHorizonStakingMain.sol"; import { IHorizonStakingExtension } from "../../../contracts/interfaces/internal/IHorizonStakingExtension.sol"; +import { IL2StakingBase } from "@graphprotocol/contracts/contracts/l2/staking/IL2StakingBase.sol"; import { LinkedList } from "../../../contracts/libraries/LinkedList.sol"; import { MathUtils } from "../../../contracts/libraries/MathUtils.sol"; @@ -1207,6 +1208,86 @@ abstract contract HorizonStakingSharedTest is GraphBaseTest { assertEq(afterCounterpartStakingAddress, counterpartStakingAddress); } + function _onTokenTransfer_ReceiveDelegation(address from, uint256 tokens, bytes memory data) internal { + (, bytes memory fnData) = abi.decode(data, (uint8, bytes)); + (address serviceProvider, address delegator) = abi.decode(fnData, (address, address)); + bytes32 slotPoolTokens = bytes32(uint256(keccak256(abi.encode(serviceProvider, 20))) + 2); + + // before + DelegationPool memory beforePool = staking.getDelegationPool(serviceProvider, subgraphDataServiceLegacyAddress); + Delegation memory beforeDelegation = staking.getDelegation( + serviceProvider, + subgraphDataServiceLegacyAddress, + delegator + ); + uint256 beforeStoragePoolTokens = uint256(vm.load(address(staking), slotPoolTokens)); + uint256 beforeDelegatedTokens = staking.getDelegatedTokensAvailable( + serviceProvider, + subgraphDataServiceLegacyAddress + ); + uint256 beforeDelegatorBalance = token.balanceOf(delegator); + uint256 beforeStakingBalance = token.balanceOf(address(staking)); + uint256 calcShares = (beforePool.tokens == 0 || beforePool.tokens == beforePool.tokensThawing) + ? tokens + : ((tokens * beforePool.shares) / (beforePool.tokens - beforePool.tokensThawing)); + + bool earlyExit = (calcShares == 0 || tokens < 1 ether) || + (beforePool.tokens == 0 && (beforePool.shares != 0 || beforePool.sharesThawing != 0)); + + // onTokenTransfer + if (earlyExit) { + vm.expectEmit(); + emit Transfer(address(staking), delegator, tokens); + vm.expectEmit(); + emit IL2StakingBase.TransferredDelegationReturnedToDelegator(serviceProvider, delegator, tokens); + } else { + vm.expectEmit(); + emit IHorizonStakingExtension.StakeDelegated(serviceProvider, delegator, tokens, calcShares); + } + staking.onTokenTransfer(from, tokens, data); + + // after + DelegationPool memory afterPool = staking.getDelegationPool(serviceProvider, subgraphDataServiceLegacyAddress); + Delegation memory afterDelegation = staking.getDelegation( + serviceProvider, + subgraphDataServiceLegacyAddress, + delegator + ); + uint256 afterStoragePoolTokens = uint256(vm.load(address(staking), slotPoolTokens)); + uint256 afterDelegatedTokens = staking.getDelegatedTokensAvailable( + serviceProvider, + subgraphDataServiceLegacyAddress + ); + uint256 afterDelegatorBalance = token.balanceOf(delegator); + uint256 afterStakingBalance = token.balanceOf(address(staking)); + + uint256 deltaShares = afterDelegation.shares - beforeDelegation.shares; + + // assertions + if (earlyExit) { + assertEq(beforePool.tokens, afterPool.tokens); + assertEq(beforePool.shares, afterPool.shares); + assertEq(beforePool.tokensThawing, afterPool.tokensThawing); + assertEq(beforePool.sharesThawing, afterPool.sharesThawing); + assertEq(0, deltaShares); + assertEq(beforeDelegatedTokens, afterDelegatedTokens); + assertEq(beforeStoragePoolTokens, afterStoragePoolTokens); + assertEq(beforeDelegatorBalance + tokens, afterDelegatorBalance); + assertEq(beforeStakingBalance - tokens, afterStakingBalance); + } else { + assertEq(beforePool.tokens + tokens, afterPool.tokens); + assertEq(beforePool.shares + calcShares, afterPool.shares); + assertEq(beforePool.tokensThawing, afterPool.tokensThawing); + assertEq(beforePool.sharesThawing, afterPool.sharesThawing); + assertEq(calcShares, deltaShares); + assertEq(beforeDelegatedTokens + tokens, afterDelegatedTokens); + // Ensure correct slot is being updated, pools are stored in different storage locations for legacy subgraph data service + assertEq(beforeStoragePoolTokens + tokens, afterStoragePoolTokens); + assertEq(beforeDelegatorBalance, afterDelegatorBalance); + assertEq(beforeStakingBalance, afterStakingBalance); + } + } + /* * STORAGE HELPERS */ diff --git a/packages/horizon/test/staking/transfer-tools/ttools.t.sol b/packages/horizon/test/staking/transfer-tools/ttools.t.sol index 524c4a4ec..feadb852e 100644 --- a/packages/horizon/test/staking/transfer-tools/ttools.t.sol +++ b/packages/horizon/test/staking/transfer-tools/ttools.t.sol @@ -5,8 +5,6 @@ import "forge-std/Test.sol"; import { HorizonStakingTest } from "../HorizonStaking.t.sol"; import { IL2StakingTypes } from "@graphprotocol/contracts/contracts/l2/staking/IL2StakingTypes.sol"; -import { IL2StakingBase } from "@graphprotocol/contracts/contracts/l2/staking/IL2StakingBase.sol"; -import { IHorizonStakingExtension } from "../../../contracts/interfaces/internal/IHorizonStakingExtension.sol"; contract HorizonStakingTransferToolsTest is HorizonStakingTest { /* @@ -164,89 +162,5 @@ contract HorizonStakingTransferToolsTest is HorizonStakingTest { abi.encode(users.indexer, users.delegator) ); _onTokenTransfer_ReceiveDelegation(counterpartStaking, amountReceived, data); - } - - /** - * HELPERS - */ - - function _onTokenTransfer_ReceiveDelegation(address from, uint256 tokens, bytes memory data) internal { - (, bytes memory fnData) = abi.decode(data, (uint8, bytes)); - (address serviceProvider, address delegator) = abi.decode(fnData, (address, address)); - bytes32 slotPoolTokens = bytes32(uint256(keccak256(abi.encode(serviceProvider, 20))) + 2); - - // before - DelegationPool memory beforePool = staking.getDelegationPool(serviceProvider, subgraphDataServiceLegacyAddress); - Delegation memory beforeDelegation = staking.getDelegation( - serviceProvider, - subgraphDataServiceLegacyAddress, - delegator - ); - uint256 beforeStoragePoolTokens = uint256(vm.load(address(staking), slotPoolTokens)); - uint256 beforeDelegatedTokens = staking.getDelegatedTokensAvailable( - serviceProvider, - subgraphDataServiceLegacyAddress - ); - uint256 beforeDelegatorBalance = token.balanceOf(delegator); - uint256 beforeStakingBalance = token.balanceOf(address(staking)); - uint256 calcShares = (beforePool.tokens == 0 || beforePool.tokens == beforePool.tokensThawing) - ? tokens - : ((tokens * beforePool.shares) / (beforePool.tokens - beforePool.tokensThawing)); - - bool earlyExit = (calcShares == 0 || tokens < 1 ether) || - (beforePool.tokens == 0 && (beforePool.shares != 0 || beforePool.sharesThawing != 0)); - - // onTokenTransfer - if (earlyExit) { - vm.expectEmit(); - emit Transfer(address(staking), delegator, tokens); - vm.expectEmit(); - emit IL2StakingBase.TransferredDelegationReturnedToDelegator(serviceProvider, delegator, tokens); - } else { - vm.expectEmit(); - emit IHorizonStakingExtension.StakeDelegated(serviceProvider, delegator, tokens, calcShares); - } - staking.onTokenTransfer(from, tokens, data); - - // after - DelegationPool memory afterPool = staking.getDelegationPool(serviceProvider, subgraphDataServiceLegacyAddress); - Delegation memory afterDelegation = staking.getDelegation( - serviceProvider, - subgraphDataServiceLegacyAddress, - delegator - ); - uint256 afterStoragePoolTokens = uint256(vm.load(address(staking), slotPoolTokens)); - uint256 afterDelegatedTokens = staking.getDelegatedTokensAvailable( - serviceProvider, - subgraphDataServiceLegacyAddress - ); - uint256 afterDelegatorBalance = token.balanceOf(delegator); - uint256 afterStakingBalance = token.balanceOf(address(staking)); - - uint256 deltaShares = afterDelegation.shares - beforeDelegation.shares; - - // assertions - if (earlyExit) { - assertEq(beforePool.tokens, afterPool.tokens); - assertEq(beforePool.shares, afterPool.shares); - assertEq(beforePool.tokensThawing, afterPool.tokensThawing); - assertEq(beforePool.sharesThawing, afterPool.sharesThawing); - assertEq(0, deltaShares); - assertEq(beforeDelegatedTokens, afterDelegatedTokens); - assertEq(beforeStoragePoolTokens, afterStoragePoolTokens); - assertEq(beforeDelegatorBalance + tokens, afterDelegatorBalance); - assertEq(beforeStakingBalance - tokens, afterStakingBalance); - } else { - assertEq(beforePool.tokens + tokens, afterPool.tokens); - assertEq(beforePool.shares + calcShares, afterPool.shares); - assertEq(beforePool.tokensThawing, afterPool.tokensThawing); - assertEq(beforePool.sharesThawing, afterPool.sharesThawing); - assertEq(calcShares, deltaShares); - assertEq(beforeDelegatedTokens + tokens, afterDelegatedTokens); - // Ensure correct slot is being updated, pools are stored in different storage locations for legacy subgraph data service - assertEq(beforeStoragePoolTokens + tokens, afterStoragePoolTokens); - assertEq(beforeDelegatorBalance, afterDelegatorBalance); - assertEq(beforeStakingBalance, afterStakingBalance); - } - } + } } From 7b477d218f600fc320450809ca9580285deb6b5c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1s=20Migone?= Date: Tue, 3 Sep 2024 13:51:23 -0300 Subject: [PATCH 18/24] test: refactor slash test MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Tomás Migone --- .../HorizonStakingShared.t.sol | 93 +++++++++++++++++++ .../horizon/test/staking/HorizonStaking.t.sol | 58 ------------ .../horizon/test/staking/slash/slash.t.sol | 9 -- 3 files changed, 93 insertions(+), 67 deletions(-) diff --git a/packages/horizon/test/shared/horizon-staking/HorizonStakingShared.t.sol b/packages/horizon/test/shared/horizon-staking/HorizonStakingShared.t.sol index 1d83a981e..2f433e03c 100644 --- a/packages/horizon/test/shared/horizon-staking/HorizonStakingShared.t.sol +++ b/packages/horizon/test/shared/horizon-staking/HorizonStakingShared.t.sol @@ -12,9 +12,11 @@ import { IL2StakingBase } from "@graphprotocol/contracts/contracts/l2/staking/IL import { LinkedList } from "../../../contracts/libraries/LinkedList.sol"; import { MathUtils } from "../../../contracts/libraries/MathUtils.sol"; +import { PPMMath } from "../../../contracts/libraries/PPMMath.sol"; abstract contract HorizonStakingSharedTest is GraphBaseTest { using LinkedList for LinkedList.List; + using PPMMath for uint256; event Transfer(address indexed from, address indexed to, uint tokens); @@ -1288,6 +1290,97 @@ abstract contract HorizonStakingSharedTest is GraphBaseTest { } } + function _slash(address serviceProvider, address verifier, uint256 tokens, uint256 verifierCutAmount) internal { + bool isDelegationSlashingEnabled = staking.isDelegationSlashingEnabled(); + + // staking contract knows the address of the legacy subgraph service + // but we cannot read it as it's an immutable, we have to use the global var :/ + bool legacy = verifier == subgraphDataServiceLegacyAddress; + + // before + Provision memory beforeProvision = staking.getProvision(serviceProvider, verifier); + DelegationPoolInternalTest memory beforePool = _getStorage_DelegationPoolInternal( + serviceProvider, + verifier, + legacy + ); + ServiceProviderInternal memory beforeServiceProvider = _getStorage_ServiceProviderInternal(serviceProvider); + uint256 beforeStakingBalance = token.balanceOf(address(staking)); + uint256 beforeVerifierBalance = token.balanceOf(verifier); + + // Calculate expected tokens after slashing + uint256 tokensToSlash = MathUtils.min(tokens, beforeProvision.tokens + beforePool.tokens); + uint256 providerTokensSlashed = MathUtils.min(beforeProvision.tokens, tokensToSlash); + uint256 delegationTokensSlashed = tokensToSlash - providerTokensSlashed; + + if (tokensToSlash > 0) { + if (verifierCutAmount > 0) { + vm.expectEmit(address(token)); + emit Transfer(address(staking), verifier, verifierCutAmount); + vm.expectEmit(address(staking)); + emit IHorizonStakingMain.VerifierTokensSent(serviceProvider, verifier, verifier, verifierCutAmount); + } + if (providerTokensSlashed - verifierCutAmount > 0) { + vm.expectEmit(address(token)); + emit Transfer(address(staking), address(0), providerTokensSlashed - verifierCutAmount); + } + vm.expectEmit(address(staking)); + emit IHorizonStakingMain.ProvisionSlashed(serviceProvider, verifier, providerTokensSlashed); + } + + if (delegationTokensSlashed > 0) { + if (isDelegationSlashingEnabled) { + vm.expectEmit(address(token)); + emit Transfer(address(staking), address(0), delegationTokensSlashed); + vm.expectEmit(address(staking)); + emit IHorizonStakingMain.DelegationSlashed(serviceProvider, verifier, delegationTokensSlashed); + } else { + vm.expectEmit(address(staking)); + emit IHorizonStakingMain.DelegationSlashingSkipped(serviceProvider, verifier, delegationTokensSlashed); + } + } + staking.slash(serviceProvider, tokens, verifierCutAmount, verifier); + + // after + Provision memory afterProvision = staking.getProvision(serviceProvider, verifier); + DelegationPoolInternalTest memory afterPool = _getStorage_DelegationPoolInternal( + serviceProvider, + verifier, + legacy + ); + ServiceProviderInternal memory afterServiceProvider = _getStorage_ServiceProviderInternal(serviceProvider); + uint256 afterStakingBalance = token.balanceOf(address(staking)); + uint256 afterVerifierBalance = token.balanceOf(verifier); + + uint256 tokensSlashed = providerTokensSlashed + (isDelegationSlashingEnabled ? delegationTokensSlashed : 0); + uint256 provisionThawingTokens = (beforeProvision.tokensThawing * + (1e18 - ((providerTokensSlashed * 1e18) / beforeProvision.tokens))) / (1e18); + + // assert + assertEq(afterProvision.tokens + providerTokensSlashed, beforeProvision.tokens); + assertEq(afterProvision.tokensThawing, provisionThawingTokens); + assertEq(afterProvision.sharesThawing, beforeProvision.sharesThawing); + assertEq(afterProvision.maxVerifierCut, beforeProvision.maxVerifierCut); + assertEq(afterProvision.maxVerifierCutPending, beforeProvision.maxVerifierCutPending); + assertEq(afterProvision.thawingPeriod, beforeProvision.thawingPeriod); + assertEq(afterProvision.thawingPeriodPending, beforeProvision.thawingPeriodPending); + + if (isDelegationSlashingEnabled) { + uint256 poolThawingTokens = (beforePool.tokensThawing * + (1e18 - ((delegationTokensSlashed * 1e18) / beforePool.tokens))) / (1e18); + assertEq(afterPool.tokens + delegationTokensSlashed, beforePool.tokens); + assertEq(afterPool.shares, beforePool.shares); + assertEq(afterPool.tokensThawing, poolThawingTokens); + assertEq(afterPool.sharesThawing, beforePool.sharesThawing); + } + + assertEq(beforeStakingBalance - tokensSlashed, afterStakingBalance); + assertEq(beforeVerifierBalance + verifierCutAmount, afterVerifierBalance); + + assertEq(afterServiceProvider.tokensStaked + providerTokensSlashed, beforeServiceProvider.tokensStaked); + assertEq(afterServiceProvider.tokensProvisioned + providerTokensSlashed, beforeServiceProvider.tokensProvisioned); + } + /* * STORAGE HELPERS */ diff --git a/packages/horizon/test/staking/HorizonStaking.t.sol b/packages/horizon/test/staking/HorizonStaking.t.sol index 75d2b7569..b1562a86a 100644 --- a/packages/horizon/test/staking/HorizonStaking.t.sol +++ b/packages/horizon/test/staking/HorizonStaking.t.sol @@ -60,62 +60,4 @@ contract HorizonStakingTest is HorizonStakingSharedTest { resetPrank(msgSender); _; } - - /* - * HELPERS - */ - - function _slash(address serviceProvider, address verifier, uint256 tokens, uint256 verifierCutAmount) internal { - uint256 beforeProviderTokens = staking.getProviderTokensAvailable(serviceProvider, verifier); - uint256 beforeDelegationTokens = staking.getDelegatedTokensAvailable(serviceProvider, verifier); - bool isDelegationSlashingEnabled = staking.isDelegationSlashingEnabled(); - - // Calculate expected tokens after slashing - uint256 providerTokensSlashed = MathUtils.min(beforeProviderTokens, tokens); - uint256 expectedProviderTokensAfterSlashing = beforeProviderTokens - providerTokensSlashed; - - uint256 delegationTokensSlashed = MathUtils.min(beforeDelegationTokens, tokens - providerTokensSlashed); - uint256 expectedDelegationTokensAfterSlashing = beforeDelegationTokens - - (isDelegationSlashingEnabled ? delegationTokensSlashed : 0); - - vm.expectEmit(address(staking)); - if (verifierCutAmount > 0) { - emit IHorizonStakingMain.VerifierTokensSent( - serviceProvider, - verifier, - verifier, - verifierCutAmount - ); - } - emit IHorizonStakingMain.ProvisionSlashed(serviceProvider, verifier, providerTokensSlashed); - - if (isDelegationSlashingEnabled) { - emit IHorizonStakingMain.DelegationSlashed( - serviceProvider, - verifier, - delegationTokensSlashed - ); - } else { - emit IHorizonStakingMain.DelegationSlashingSkipped( - serviceProvider, - verifier, - delegationTokensSlashed - ); - } - staking.slash(serviceProvider, tokens, verifierCutAmount, verifier); - - if (!isDelegationSlashingEnabled) { - expectedDelegationTokensAfterSlashing = beforeDelegationTokens; - } - - uint256 provisionTokens = staking.getProviderTokensAvailable(serviceProvider, verifier); - assertEq(provisionTokens, expectedProviderTokensAfterSlashing); - - uint256 delegationTokens = staking.getDelegatedTokensAvailable(serviceProvider, verifier); - assertEq(delegationTokens, expectedDelegationTokensAfterSlashing); - - uint256 verifierTokens = token.balanceOf(verifier); - assertEq(verifierTokens, verifierCutAmount); - } - } diff --git a/packages/horizon/test/staking/slash/slash.t.sol b/packages/horizon/test/staking/slash/slash.t.sol index b68794604..087239f69 100644 --- a/packages/horizon/test/staking/slash/slash.t.sol +++ b/packages/horizon/test/staking/slash/slash.t.sol @@ -8,15 +8,6 @@ import { IHorizonStakingMain } from "../../../contracts/interfaces/internal/IHor import { HorizonStakingTest } from "../HorizonStaking.t.sol"; contract HorizonStakingSlashTest is HorizonStakingTest { - - /* - * MODIFIERS - */ - - /* - * HELPERS - */ - /* * TESTS */ From 86e0388e6bcd5bb1d869c10feee014426ef1714e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1s=20Migone?= Date: Tue, 3 Sep 2024 17:28:39 -0300 Subject: [PATCH 19/24] test: refactor legacy allocation tests wip MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Tomás Migone --- .../HorizonStakingShared.t.sol | 112 +++++++++++++++++- .../horizon/test/staking/HorizonStaking.t.sol | 4 - .../allocation/HorizonStakingExtension.t.sol | 98 --------------- .../test/staking/allocation/allocation.t.sol | 54 ++++----- .../test/staking/allocation/close.t.sol | 38 +++--- .../test/staking/allocation/collect.t.sol | 41 +++---- 6 files changed, 177 insertions(+), 170 deletions(-) delete mode 100644 packages/horizon/test/staking/allocation/HorizonStakingExtension.t.sol diff --git a/packages/horizon/test/shared/horizon-staking/HorizonStakingShared.t.sol b/packages/horizon/test/shared/horizon-staking/HorizonStakingShared.t.sol index 2f433e03c..b6804295c 100644 --- a/packages/horizon/test/shared/horizon-staking/HorizonStakingShared.t.sol +++ b/packages/horizon/test/shared/horizon-staking/HorizonStakingShared.t.sol @@ -20,6 +20,10 @@ abstract contract HorizonStakingSharedTest is GraphBaseTest { event Transfer(address indexed from, address indexed to, uint tokens); + address internal _allocationId = makeAddr("allocationId"); + bytes32 internal constant _subgraphDeploymentID = keccak256("subgraphDeploymentID"); + uint256 internal constant MAX_ALLOCATION_EPOCHS = 28; + /* * MODIFIERS */ @@ -78,6 +82,11 @@ abstract contract HorizonStakingSharedTest is GraphBaseTest { _createProvision(users.indexer, dataService, tokens, maxVerifierCut, thawingPeriod); } + modifier useAllocation(uint256 tokens) { + _createAllocation(users.indexer, _allocationId, _subgraphDeploymentID, tokens); + _; + } + /* * HELPERS: these are shortcuts to perform common actions that often involve multiple contract calls */ @@ -92,6 +101,28 @@ abstract contract HorizonStakingSharedTest is GraphBaseTest { _provision(serviceProvider, verifier, tokens, maxVerifierCut, thawingPeriod); } + function _createAllocation( + address serviceProvider, + address allocationId, + bytes32 subgraphDeploymentID, + uint256 tokens + ) internal { + IHorizonStakingExtension.Allocation memory _allocation = IHorizonStakingExtension.Allocation({ + indexer: serviceProvider, + subgraphDeploymentID: subgraphDeploymentID, + tokens: tokens, + createdAtEpoch: block.timestamp, + closedAtEpoch: 0, + collectedFees: 0, + __DEPRECATED_effectiveAllocation: 0, + accRewardsPerAllocatedToken: 0, + distributedRebates: 0 + }); + _setStorage_allocation(_allocation, allocationId, 0); + + token.transfer(address(staking), tokens); + } + /* * ACTIONS: these are individual contract calls wrapped in assertion blocks to ensure they work as expected */ @@ -1378,7 +1409,10 @@ abstract contract HorizonStakingSharedTest is GraphBaseTest { assertEq(beforeVerifierBalance + verifierCutAmount, afterVerifierBalance); assertEq(afterServiceProvider.tokensStaked + providerTokensSlashed, beforeServiceProvider.tokensStaked); - assertEq(afterServiceProvider.tokensProvisioned + providerTokensSlashed, beforeServiceProvider.tokensProvisioned); + assertEq( + afterServiceProvider.tokensProvisioned + providerTokensSlashed, + beforeServiceProvider.tokensProvisioned + ); } /* @@ -1536,6 +1570,82 @@ abstract contract HorizonStakingSharedTest is GraphBaseTest { return address(uint160(uint256(vm.load(address(staking), bytes32(slot))))); } + function _setStorage_allocation( + IHorizonStakingExtension.Allocation memory allocation, + address allocationId, + uint256 tokens + ) internal { + // __DEPRECATED_allocations + uint256 allocationsSlot = 15; + bytes32 allocationBaseSlot = keccak256(abi.encode(allocationId, allocationsSlot)); + vm.store(address(staking), allocationBaseSlot, bytes32(uint256(uint160(allocation.indexer)))); + vm.store(address(staking), bytes32(uint256(allocationBaseSlot) + 1), allocation.subgraphDeploymentID); + vm.store(address(staking), bytes32(uint256(allocationBaseSlot) + 2), bytes32(tokens)); + vm.store(address(staking), bytes32(uint256(allocationBaseSlot) + 3), bytes32(allocation.createdAtEpoch)); + vm.store(address(staking), bytes32(uint256(allocationBaseSlot) + 4), bytes32(allocation.closedAtEpoch)); + vm.store(address(staking), bytes32(uint256(allocationBaseSlot) + 5), bytes32(allocation.collectedFees)); + vm.store( + address(staking), + bytes32(uint256(allocationBaseSlot) + 6), + bytes32(allocation.__DEPRECATED_effectiveAllocation) + ); + vm.store( + address(staking), + bytes32(uint256(allocationBaseSlot) + 7), + bytes32(allocation.accRewardsPerAllocatedToken) + ); + vm.store(address(staking), bytes32(uint256(allocationBaseSlot) + 8), bytes32(allocation.distributedRebates)); + + // _serviceProviders + uint256 serviceProviderSlot = 14; + bytes32 serviceProviderBaseSlot = keccak256(abi.encode(allocation.indexer, serviceProviderSlot)); + uint256 currentTokensStaked = uint256(vm.load(address(staking), serviceProviderBaseSlot)); + uint256 currentTokensProvisioned = uint256( + vm.load(address(staking), bytes32(uint256(serviceProviderBaseSlot) + 1)) + ); + vm.store( + address(staking), + bytes32(uint256(serviceProviderBaseSlot) + 0), + bytes32(currentTokensStaked + tokens) + ); + vm.store( + address(staking), + bytes32(uint256(serviceProviderBaseSlot) + 1), + bytes32(currentTokensProvisioned + tokens) + ); + + // __DEPRECATED_subgraphAllocations + uint256 subgraphsAllocationsSlot = 16; + bytes32 subgraphAllocationsBaseSlot = keccak256( + abi.encode(allocation.subgraphDeploymentID, subgraphsAllocationsSlot) + ); + uint256 currentAllocatedTokens = uint256(vm.load(address(staking), subgraphAllocationsBaseSlot)); + vm.store(address(staking), subgraphAllocationsBaseSlot, bytes32(currentAllocatedTokens + tokens)); + } + + + function _setStorage_RewardsDestination(address serviceProvider, address destination) internal { + uint256 rewardsDestinationSlot = 23; + bytes32 rewardsDestinationSlotBaseSlot = keccak256(abi.encode(serviceProvider, rewardsDestinationSlot)); + vm.store(address(staking), rewardsDestinationSlotBaseSlot, bytes32(uint256(uint160(destination)))); + } + + function _setStorage_MaxAllocationEpochs() internal { + uint256 slot = 13; + vm.store(address(staking), bytes32(slot), bytes32(MAX_ALLOCATION_EPOCHS) << 128); + } + + function _setStorage_DelegationPool(address serviceProvider, uint256 tokens, uint32 indexingRewardCut, uint32 queryFeeCut) internal { + bytes32 baseSlot = keccak256(abi.encode(serviceProvider, uint256(20))); + bytes32 feeCutValues = bytes32( + (uint256(indexingRewardCut) << uint256(32)) | + (uint256(queryFeeCut) << uint256(64)) + ); + bytes32 tokensSlot = bytes32(uint256(baseSlot) + 2); + vm.store(address(staking), baseSlot, feeCutValues); + vm.store(address(staking), tokensSlot, bytes32(tokens)); + } + /* * MISC: private functions to help with testing */ diff --git a/packages/horizon/test/staking/HorizonStaking.t.sol b/packages/horizon/test/staking/HorizonStaking.t.sol index b1562a86a..617e46ce7 100644 --- a/packages/horizon/test/staking/HorizonStaking.t.sol +++ b/packages/horizon/test/staking/HorizonStaking.t.sol @@ -4,10 +4,6 @@ pragma solidity 0.8.26; import "forge-std/Test.sol"; import { stdStorage, StdStorage } from "forge-std/Test.sol"; -import { IHorizonStakingMain } from "../../contracts/interfaces/internal/IHorizonStakingMain.sol"; -import { LinkedList } from "../../contracts/libraries/LinkedList.sol"; -import { MathUtils } from "../../contracts/libraries/MathUtils.sol"; - import { HorizonStakingSharedTest } from "../shared/horizon-staking/HorizonStakingShared.t.sol"; contract HorizonStakingTest is HorizonStakingSharedTest { diff --git a/packages/horizon/test/staking/allocation/HorizonStakingExtension.t.sol b/packages/horizon/test/staking/allocation/HorizonStakingExtension.t.sol deleted file mode 100644 index bf9524c43..000000000 --- a/packages/horizon/test/staking/allocation/HorizonStakingExtension.t.sol +++ /dev/null @@ -1,98 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity 0.8.26; - -import "forge-std/Test.sol"; - -import { HorizonStakingTest } from "../HorizonStaking.t.sol"; -import { IHorizonStakingExtension } from "../../../contracts/interfaces/internal/IHorizonStakingExtension.sol"; - -contract HorizonStakingExtensionTest is HorizonStakingTest { - - /* - * VARIABLES - */ - - address internal _allocationId = makeAddr("allocationId"); - bytes32 internal constant _subgraphDeploymentID = keccak256("subgraphDeploymentID"); - bytes32 internal constant _poi = keccak256("poi"); - uint256 internal constant MAX_ALLOCATION_EPOCHS = 28; - IHorizonStakingExtension.Allocation internal _allocation; - - /* - * MODIFIERS - */ - - modifier useAllocation() { - _storeAllocation(0); - _; - } - - /* - * SET UP - */ - - function setUp() public virtual override { - super.setUp(); - - _allocation = IHorizonStakingExtension.Allocation({ - indexer: users.indexer, - subgraphDeploymentID: _subgraphDeploymentID, - tokens: 0, - createdAtEpoch: block.timestamp, - closedAtEpoch: 0, - collectedFees: 0, - __DEPRECATED_effectiveAllocation: 0, - accRewardsPerAllocatedToken: 0, - distributedRebates: 0 - }); - } - - function _storeDelegationPool(uint256 tokens, uint32 indexingRewardCut, uint32 queryFeeCut) internal { - bytes32 baseSlot = keccak256(abi.encode(users.indexer, uint256(20))); - bytes32 feeCutValues = bytes32( - (uint256(indexingRewardCut) << uint256(32)) | - (uint256(queryFeeCut) << uint256(64)) - ); - bytes32 tokensSlot = bytes32(uint256(baseSlot) + 2); - vm.store(address(staking), baseSlot, feeCutValues); - vm.store(address(staking), tokensSlot, bytes32(tokens)); - } - - /* - * HELPERS - */ - - function _storeAllocation(uint256 tokens) internal { - uint256 allocationsSlot = 15; - bytes32 allocationBaseSlot = keccak256(abi.encode(_allocationId, allocationsSlot)); - vm.store(address(staking), allocationBaseSlot, bytes32(uint256(uint160(_allocation.indexer)))); - vm.store(address(staking), bytes32(uint256(allocationBaseSlot) + 1), _allocation.subgraphDeploymentID); - vm.store(address(staking), bytes32(uint256(allocationBaseSlot) + 2), bytes32(tokens)); - vm.store(address(staking), bytes32(uint256(allocationBaseSlot) + 3), bytes32(_allocation.createdAtEpoch)); - vm.store(address(staking), bytes32(uint256(allocationBaseSlot) + 4), bytes32(_allocation.closedAtEpoch)); - vm.store(address(staking), bytes32(uint256(allocationBaseSlot) + 5), bytes32(_allocation.collectedFees)); - vm.store(address(staking), bytes32(uint256(allocationBaseSlot) + 6), bytes32(_allocation.__DEPRECATED_effectiveAllocation)); - vm.store(address(staking), bytes32(uint256(allocationBaseSlot) + 7), bytes32(_allocation.accRewardsPerAllocatedToken)); - vm.store(address(staking), bytes32(uint256(allocationBaseSlot) + 8), bytes32(_allocation.distributedRebates)); - - uint256 serviceProviderSlot = 14; - bytes32 serviceProviderBaseSlot = keccak256(abi.encode(_allocation.indexer, serviceProviderSlot)); - vm.store(address(staking), bytes32(uint256(serviceProviderBaseSlot) + 0), bytes32(tokens)); - vm.store(address(staking), bytes32(uint256(serviceProviderBaseSlot) + 1), bytes32(tokens)); - - uint256 subgraphsAllocationsSlot = 16; - bytes32 subgraphAllocationsBaseSlot = keccak256(abi.encode(_allocation.subgraphDeploymentID, subgraphsAllocationsSlot)); - vm.store(address(staking), subgraphAllocationsBaseSlot, bytes32(tokens)); - } - - function _storeMaxAllocationEpochs() internal { - uint256 slot = 13; - vm.store(address(staking), bytes32(slot), bytes32(MAX_ALLOCATION_EPOCHS) << 128); - } - - function _storeRewardsDestination(address destination) internal { - uint256 rewardsDestinationSlot = 23; - bytes32 rewardsDestinationSlotBaseSlot = keccak256(abi.encode(users.indexer, rewardsDestinationSlot)); - vm.store(address(staking), rewardsDestinationSlotBaseSlot, bytes32(uint256(uint160(destination)))); - } -} \ No newline at end of file diff --git a/packages/horizon/test/staking/allocation/allocation.t.sol b/packages/horizon/test/staking/allocation/allocation.t.sol index 83e23a81f..1c611ddaa 100644 --- a/packages/horizon/test/staking/allocation/allocation.t.sol +++ b/packages/horizon/test/staking/allocation/allocation.t.sol @@ -3,39 +3,39 @@ pragma solidity 0.8.26; import "forge-std/Test.sol"; -import { HorizonStakingExtensionTest } from "./HorizonStakingExtension.t.sol"; +import { HorizonStakingTest } from "../HorizonStaking.t.sol"; import { IHorizonStakingExtension } from "../../../contracts/interfaces/internal/IHorizonStakingExtension.sol"; -contract HorizonStakingAllocationTest is HorizonStakingExtensionTest { +contract HorizonStakingAllocationTest is HorizonStakingTest { /* * TESTS */ - function testAllocation_GetAllocation() public useAllocation { - IHorizonStakingExtension.Allocation memory allocation = staking.getAllocation(_allocationId); - assertEq(allocation.indexer, _allocation.indexer); - assertEq(allocation.subgraphDeploymentID, _allocation.subgraphDeploymentID); - assertEq(allocation.tokens, _allocation.tokens); - assertEq(allocation.createdAtEpoch, _allocation.createdAtEpoch); - assertEq(allocation.closedAtEpoch, _allocation.closedAtEpoch); - assertEq(allocation.collectedFees, _allocation.collectedFees); - assertEq(allocation.__DEPRECATED_effectiveAllocation, _allocation.__DEPRECATED_effectiveAllocation); - assertEq(allocation.accRewardsPerAllocatedToken, _allocation.accRewardsPerAllocatedToken); - assertEq(allocation.distributedRebates, _allocation.distributedRebates); - } - - function testAllocation_GetAllocationData() public useAllocation { - (address indexer, bytes32 subgraphDeploymentID, uint256 tokens, uint256 accRewardsPerAllocatedToken, uint256 accRewardsPending) = - staking.getAllocationData(_allocationId); - assertEq(indexer, _allocation.indexer); - assertEq(subgraphDeploymentID, _allocation.subgraphDeploymentID); - assertEq(tokens, _allocation.tokens); - assertEq(accRewardsPerAllocatedToken, _allocation.accRewardsPerAllocatedToken); - assertEq(accRewardsPending, 0); - } - - function testAllocation_GetAllocationState_Active() public useAllocation { + // function testAllocation_GetAllocation(uint256 tokens) public useIndexer useAllocation(tokens) { + // IHorizonStakingExtension.Allocation memory allocation = staking.getAllocation(_allocationId); + // assertEq(allocation.indexer, _allocation.indexer); + // assertEq(allocation.subgraphDeploymentID, _allocation.subgraphDeploymentID); + // assertEq(allocation.tokens, _allocation.tokens); + // assertEq(allocation.createdAtEpoch, _allocation.createdAtEpoch); + // assertEq(allocation.closedAtEpoch, _allocation.closedAtEpoch); + // assertEq(allocation.collectedFees, _allocation.collectedFees); + // assertEq(allocation.__DEPRECATED_effectiveAllocation, _allocation.__DEPRECATED_effectiveAllocation); + // assertEq(allocation.accRewardsPerAllocatedToken, _allocation.accRewardsPerAllocatedToken); + // assertEq(allocation.distributedRebates, _allocation.distributedRebates); + // } + + // function testAllocation_GetAllocationData(uint256 tokens) public useIndexer useAllocation(tokens) { + // (address indexer, bytes32 subgraphDeploymentID, uint256 tokens_, uint256 accRewardsPerAllocatedToken, uint256 accRewardsPending) = + // staking.getAllocationData(_allocationId); + // assertEq(indexer, _allocation.indexer); + // assertEq(subgraphDeploymentID, _allocation.subgraphDeploymentID); + // assertEq(tokens_, _allocation.tokens); + // assertEq(accRewardsPerAllocatedToken, _allocation.accRewardsPerAllocatedToken); + // assertEq(accRewardsPending, 0); + // } + + function testAllocation_GetAllocationState_Active(uint256 tokens) public useIndexer useAllocation(tokens) { IHorizonStakingExtension.AllocationState state = staking.getAllocationState(_allocationId); assertEq(uint16(state), uint16(IHorizonStakingExtension.AllocationState.Active)); } @@ -45,7 +45,7 @@ contract HorizonStakingAllocationTest is HorizonStakingExtensionTest { assertEq(uint16(state), uint16(IHorizonStakingExtension.AllocationState.Null)); } - function testAllocation_IsAllocation() public useAllocation { + function testAllocation_IsAllocation(uint256 tokens) public useIndexer useAllocation(tokens) { bool isAllocation = staking.isAllocation(_allocationId); assertTrue(isAllocation); } diff --git a/packages/horizon/test/staking/allocation/close.t.sol b/packages/horizon/test/staking/allocation/close.t.sol index 0a6c3fa7c..f084c2af0 100644 --- a/packages/horizon/test/staking/allocation/close.t.sol +++ b/packages/horizon/test/staking/allocation/close.t.sol @@ -3,21 +3,22 @@ pragma solidity 0.8.26; import "forge-std/Test.sol"; -import { HorizonStakingExtensionTest } from "./HorizonStakingExtension.t.sol"; +import { HorizonStakingTest } from "../HorizonStaking.t.sol"; import { IHorizonStakingExtension } from "../../../contracts/interfaces/internal/IHorizonStakingExtension.sol"; import { PPMMath } from "../../../contracts/libraries/PPMMath.sol"; -contract HorizonStakingCloseAllocationTest is HorizonStakingExtensionTest { +contract HorizonStakingCloseAllocationTest is HorizonStakingTest { using PPMMath for uint256; + bytes32 internal constant _poi = keccak256("poi"); + /* * TESTS */ - function testCloseAllocation(uint256 tokens) public useIndexer { + function testCloseAllocation(uint256 tokens) public useIndexer useAllocation(1 ether) { tokens = bound(tokens, 1, MAX_STAKING_TOKENS); - _storeAllocation(tokens); - _storeMaxAllocationEpochs(); + _setStorage_MaxAllocationEpochs(); _createProvision(users.indexer, subgraphDataServiceLegacyAddress, tokens, 0, 0); // Skip 15 epochs @@ -31,14 +32,14 @@ contract HorizonStakingCloseAllocationTest is HorizonStakingExtensionTest { assertEq(staking.getStake(address(users.indexer)), tokens * 2 + ALLOCATIONS_REWARD_CUT); } - function testCloseAllocation_WithBeneficiaryAddress(uint256 tokens) public useIndexer { + function testCloseAllocation_WithBeneficiaryAddress(uint256 tokens) public useIndexer useAllocation(1 ether) { tokens = bound(tokens, 1, MAX_STAKING_TOKENS); - _storeAllocation(tokens); - _storeMaxAllocationEpochs(); + + _setStorage_MaxAllocationEpochs(); _createProvision(users.indexer, subgraphDataServiceLegacyAddress, tokens, 0, 0); address beneficiary = makeAddr("beneficiary"); - _storeRewardsDestination(beneficiary); + _setStorage_RewardsDestination(users.indexer, beneficiary); // Skip 15 epochs vm.roll(15); @@ -56,16 +57,15 @@ contract HorizonStakingCloseAllocationTest is HorizonStakingExtensionTest { staking.closeAllocation(_allocationId, _poi); } - function testCloseAllocation_RevertWhen_NotIndexer() public useAllocation { + function testCloseAllocation_RevertWhen_NotIndexer() public useIndexer useAllocation(1 ether) { resetPrank(users.delegator); vm.expectRevert("!auth"); staking.closeAllocation(_allocationId, _poi); } - function testCloseAllocation_AfterMaxEpochs_AnyoneCanClose(uint256 tokens) public useIndexer { + function testCloseAllocation_AfterMaxEpochs_AnyoneCanClose(uint256 tokens) public useIndexer useAllocation(1 ether) { tokens = bound(tokens, 1, MAX_STAKING_TOKENS); - _storeAllocation(tokens); - _storeMaxAllocationEpochs(); + _setStorage_MaxAllocationEpochs(); _createProvision(users.indexer, subgraphDataServiceLegacyAddress, tokens, 0, 0); // Skip to over the max allocation epochs @@ -80,9 +80,8 @@ contract HorizonStakingCloseAllocationTest is HorizonStakingExtensionTest { assertEq(staking.getStake(address(users.indexer)), tokens * 2); } - function testCloseAllocation_RevertWhen_ZeroTokensNotAuthorized() public useIndexer { - _storeAllocation(0); - _storeMaxAllocationEpochs(); + function testCloseAllocation_RevertWhen_ZeroTokensNotAuthorized() public useIndexer useAllocation(1 ether){ + _setStorage_MaxAllocationEpochs(); // Skip to over the max allocation epochs vm.roll(MAX_ALLOCATION_EPOCHS + 2); @@ -92,7 +91,7 @@ contract HorizonStakingCloseAllocationTest is HorizonStakingExtensionTest { staking.closeAllocation(_allocationId, 0x0); } - function testCloseAllocation_WithDelegation(uint256 tokens, uint256 delegationTokens, uint32 indexingRewardCut) public useIndexer { + function testCloseAllocation_WithDelegation(uint256 tokens, uint256 delegationTokens, uint32 indexingRewardCut) public useIndexer useAllocation(1 ether) { tokens = bound(tokens, 2, MAX_STAKING_TOKENS); delegationTokens = bound(delegationTokens, MIN_DELEGATION, MAX_STAKING_TOKENS); vm.assume(indexingRewardCut <= MAX_PPM); @@ -100,10 +99,9 @@ contract HorizonStakingCloseAllocationTest is HorizonStakingExtensionTest { uint256 legacyAllocationTokens = tokens / 2; uint256 provisionTokens = tokens - legacyAllocationTokens; - _storeAllocation(legacyAllocationTokens); - _storeMaxAllocationEpochs(); + _setStorage_MaxAllocationEpochs(); _createProvision(users.indexer, subgraphDataServiceLegacyAddress, provisionTokens, 0, 0); - _storeDelegationPool(delegationTokens, indexingRewardCut, 0); + _setStorage_DelegationPool(users.indexer, delegationTokens, indexingRewardCut, 0); // Skip 15 epochs vm.roll(15); diff --git a/packages/horizon/test/staking/allocation/collect.t.sol b/packages/horizon/test/staking/allocation/collect.t.sol index 39b7609d6..ee7335274 100644 --- a/packages/horizon/test/staking/allocation/collect.t.sol +++ b/packages/horizon/test/staking/allocation/collect.t.sol @@ -3,12 +3,11 @@ pragma solidity 0.8.26; import "forge-std/Test.sol"; -import { HorizonStakingExtensionTest } from "./HorizonStakingExtension.t.sol"; -import { IHorizonStakingExtension } from "../../../contracts/interfaces/internal/IHorizonStakingExtension.sol"; +import { HorizonStakingTest } from "../HorizonStaking.t.sol"; import { ExponentialRebates } from "../../../contracts/staking/libraries/ExponentialRebates.sol"; import { PPMMath } from "../../../contracts/libraries/PPMMath.sol"; -contract HorizonStakingCollectAllocationTest is HorizonStakingExtensionTest { +contract HorizonStakingCollectAllocationTest is HorizonStakingTest { using PPMMath for uint256; uint32 private alphaNumerator = 100; @@ -36,7 +35,7 @@ contract HorizonStakingCollectAllocationTest is HorizonStakingExtensionTest { uint256 alphaDenominatorOffset = 24; bytes32 alphaValues = bytes32( (uint256(alphaNumerator) << (8 * alphaNumeratorOffset)) | - (uint256(alphaDenominator) << (8 * alphaDenominatorOffset)) + (uint256(alphaDenominator) << (8 * alphaDenominatorOffset)) ); vm.store(address(staking), bytes32(alphaSlot), alphaValues); @@ -46,7 +45,7 @@ contract HorizonStakingCollectAllocationTest is HorizonStakingExtensionTest { uint256 lambdaDenominatorOffset = 24; bytes32 lambdaValues = bytes32( (uint256(lambdaNumerator) << (8 * lambdaNumeratorOffset)) | - (uint256(lambdaDenominator) << (8 * lambdaDenominatorOffset)) + (uint256(lambdaDenominator) << (8 * lambdaDenominatorOffset)) ); vm.store(address(staking), bytes32(lambdaSlot), lambdaValues); } @@ -58,9 +57,10 @@ contract HorizonStakingCollectAllocationTest is HorizonStakingExtensionTest { bytes32 originalValue = vm.load(address(staking), slot); bytes32 newProtocolTaxValue = bytes32( - (uint256(originalValue) & ~((0xFFFFFFFF << (8 * curationOffset)) | (0xFFFFFFFF << (8 * protocolTaxOffset))) | - (uint256(curationPercentage) << (8 * curationOffset))) | - (uint256(taxPercentage) << (8 * protocolTaxOffset)) + ((uint256(originalValue) & + ~((0xFFFFFFFF << (8 * curationOffset)) | (0xFFFFFFFF << (8 * protocolTaxOffset)))) | + (uint256(curationPercentage) << (8 * curationOffset))) | + (uint256(taxPercentage) << (8 * protocolTaxOffset)) ); vm.store(address(staking), slot, newProtocolTaxValue); } @@ -69,7 +69,7 @@ contract HorizonStakingCollectAllocationTest is HorizonStakingExtensionTest { * TESTS */ - function testCollectAllocation_RevertWhen_InvalidAllocationId(uint256 tokens) public useAllocation { + function testCollectAllocation_RevertWhen_InvalidAllocationId(uint256 tokens) public useIndexer useAllocation(1 ether) { vm.expectRevert("!alloc"); staking.collect(tokens, address(0)); } @@ -79,7 +79,7 @@ contract HorizonStakingCollectAllocationTest is HorizonStakingExtensionTest { staking.collect(tokens, _allocationId); } - function testCollectAllocation_ZeroTokens() public useAllocation { + function testCollectAllocation_ZeroTokens() public useIndexer useAllocation(1 ether) { staking.collect(0, _allocationId); assertEq(staking.getStake(address(users.indexer)), 0); } @@ -93,7 +93,7 @@ contract HorizonStakingCollectAllocationTest is HorizonStakingExtensionTest { uint32 protocolTaxPercentage, uint256 delegationTokens, uint32 queryFeeCut - ) public useRebateParameters { + ) public useIndexer useRebateParameters useAllocation(1 ether) { provisionTokens = bound(provisionTokens, 1, MAX_STAKING_TOKENS); allocationTokens = bound(allocationTokens, 0, MAX_STAKING_TOKENS); collectTokens = bound(collectTokens, 0, MAX_STAKING_TOKENS); @@ -103,9 +103,8 @@ contract HorizonStakingCollectAllocationTest is HorizonStakingExtensionTest { vm.assume(protocolTaxPercentage <= MAX_PPM); vm.assume(queryFeeCut <= MAX_PPM); resetPrank(users.indexer); - _storeAllocation(allocationTokens); _storeProtocolTaxAndCuration(curationPercentage, protocolTaxPercentage); - _storeDelegationPool(delegationTokens, 0, queryFeeCut); + _setStorage_DelegationPool(users.indexer, delegationTokens, 0, queryFeeCut); _createProvision(users.indexer, subgraphDataServiceLegacyAddress, provisionTokens, 0, 0); curation.signal(_subgraphDeploymentID, curationTokens); @@ -115,13 +114,13 @@ contract HorizonStakingCollectAllocationTest is HorizonStakingExtensionTest { uint256 protocolTaxTokens = collectTokens.mulPPMRoundUp(protocolTaxPercentage); uint256 queryFees = collectTokens - protocolTaxTokens; - + uint256 curationCutTokens = 0; if (curationTokens > 0) { curationCutTokens = queryFees.mulPPMRoundUp(curationPercentage); queryFees -= curationCutTokens; } - + uint256 newRebates = ExponentialRebates.exponentialRebates( queryFees, allocationTokens, @@ -140,7 +139,10 @@ contract HorizonStakingCollectAllocationTest is HorizonStakingExtensionTest { assertEq(staking.getStake(address(users.indexer)), allocationTokens + provisionTokens + payment); assertEq(curation.curation(_subgraphDeploymentID), curationTokens + curationCutTokens); - assertEq(staking.getDelegationPool(users.indexer, subgraphDataServiceLegacyAddress).tokens, delegationTokens + delegationFeeCut); + assertEq( + staking.getDelegationPool(users.indexer, subgraphDataServiceLegacyAddress).tokens, + delegationTokens + delegationFeeCut + ); assertEq(token.balanceOf(address(payments)), 0); } @@ -148,16 +150,15 @@ contract HorizonStakingCollectAllocationTest is HorizonStakingExtensionTest { uint256 provisionTokens, uint256 allocationTokens, uint256 collectTokens - ) public useIndexer useRebateParameters { + ) public useIndexer useRebateParameters useAllocation(1 ether) { provisionTokens = bound(provisionTokens, 1, MAX_STAKING_TOKENS); allocationTokens = bound(allocationTokens, 0, MAX_STAKING_TOKENS); collectTokens = bound(collectTokens, 0, MAX_STAKING_TOKENS); _createProvision(users.indexer, subgraphDataServiceLegacyAddress, provisionTokens, 0, 0); - _storeAllocation(allocationTokens); address beneficiary = makeAddr("beneficiary"); - _storeRewardsDestination(beneficiary); + _setStorage_RewardsDestination(users.indexer, beneficiary); resetPrank(users.gateway); approve(address(staking), collectTokens); @@ -175,4 +176,4 @@ contract HorizonStakingCollectAllocationTest is HorizonStakingExtensionTest { assertEq(token.balanceOf(beneficiary), payment); } -} \ No newline at end of file +} From 859a905abe1ee94f5bef12114947ff736018b5ba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1s=20Migone?= Date: Wed, 4 Sep 2024 17:31:25 -0300 Subject: [PATCH 20/24] test: refacto allocation close tests MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Tomás Migone --- .../HorizonStakingShared.t.sol | 165 +++++++++++++++++- .../test/staking/allocation/close.t.sol | 42 +---- .../test/staking/allocation/collect.t.sol | 2 +- 3 files changed, 164 insertions(+), 45 deletions(-) diff --git a/packages/horizon/test/shared/horizon-staking/HorizonStakingShared.t.sol b/packages/horizon/test/shared/horizon-staking/HorizonStakingShared.t.sol index b6804295c..4dae950ca 100644 --- a/packages/horizon/test/shared/horizon-staking/HorizonStakingShared.t.sol +++ b/packages/horizon/test/shared/horizon-staking/HorizonStakingShared.t.sol @@ -101,12 +101,15 @@ abstract contract HorizonStakingSharedTest is GraphBaseTest { _provision(serviceProvider, verifier, tokens, maxVerifierCut, thawingPeriod); } + // This allows setting up contract state with legacy allocations function _createAllocation( address serviceProvider, address allocationId, bytes32 subgraphDeploymentID, uint256 tokens ) internal { + _setStorage_MaxAllocationEpochs(MAX_ALLOCATION_EPOCHS); + IHorizonStakingExtension.Allocation memory _allocation = IHorizonStakingExtension.Allocation({ indexer: serviceProvider, subgraphDeploymentID: subgraphDeploymentID, @@ -118,7 +121,10 @@ abstract contract HorizonStakingSharedTest is GraphBaseTest { accRewardsPerAllocatedToken: 0, distributedRebates: 0 }); - _setStorage_allocation(_allocation, allocationId, 0); + _setStorage_allocation(_allocation, allocationId, tokens); + + // delegation pool initialized + _setStorage_DelegationPool(serviceProvider, 0, uint32(PPMMath.MAX_PPM), uint32(PPMMath.MAX_PPM)); token.transfer(address(staking), tokens); } @@ -1415,6 +1421,120 @@ abstract contract HorizonStakingSharedTest is GraphBaseTest { ); } + // Current rewards manager is mocked and assumed to mint fixed rewards + function _closeAllocation(address allocationId, bytes32 poi) internal { + (, address msgSender, ) = vm.readCallers(); + + // before + IHorizonStakingExtension.Allocation memory beforeAllocation = staking.getAllocation(allocationId); + DelegationPoolInternalTest memory beforePool = _getStorage_DelegationPoolInternal( + beforeAllocation.indexer, + subgraphDataServiceLegacyAddress, + true + ); + ServiceProviderInternal memory beforeServiceProvider = _getStorage_ServiceProviderInternal( + beforeAllocation.indexer + ); + uint256 beforeSubgraphAllocations = _getStorage_SubgraphAllocations(beforeAllocation.subgraphDeploymentID); + + bool isAuth = staking.isAuthorized(msgSender, beforeAllocation.indexer, subgraphDataServiceLegacyAddress); + address rewardsDestination = _getStorage_RewardsDestination(beforeAllocation.indexer); + + uint256 beforeStakingBalance = token.balanceOf(address(staking)); + uint256 beforeIndexerBalance = token.balanceOf(beforeAllocation.indexer); + uint256 beforeBeneficiaryBalance = token.balanceOf(rewardsDestination); + + uint256 calcRewards = ALLOCATIONS_REWARD_CUT; + uint256 calcDelegatorRewards = ALLOCATIONS_REWARD_CUT - + uint256(beforePool.__DEPRECATED_indexingRewardCut).mulPPM(calcRewards); + uint256 calcIndexerRewards = ALLOCATIONS_REWARD_CUT - (beforePool.tokens > 0 ? calcDelegatorRewards : 0); + + // closeAllocation + vm.expectEmit(address(staking)); + emit IHorizonStakingExtension.AllocationClosed( + beforeAllocation.indexer, + beforeAllocation.subgraphDeploymentID, + epochManager.currentEpoch(), + beforeAllocation.tokens, + allocationId, + msgSender, + poi, + !isAuth + ); + staking.closeAllocation(allocationId, poi); + + // after + IHorizonStakingExtension.Allocation memory afterAllocation = staking.getAllocation(allocationId); + DelegationPoolInternalTest memory afterPool = _getStorage_DelegationPoolInternal( + beforeAllocation.indexer, + subgraphDataServiceLegacyAddress, + true + ); + ServiceProviderInternal memory afterServiceProvider = _getStorage_ServiceProviderInternal( + beforeAllocation.indexer + ); + uint256 afterSubgraphAllocations = _getStorage_SubgraphAllocations(beforeAllocation.subgraphDeploymentID); + uint256 afterStakingBalance = token.balanceOf(address(staking)); + uint256 afterIndexerBalance = token.balanceOf(beforeAllocation.indexer); + uint256 afterBeneficiaryBalance = token.balanceOf(rewardsDestination); + + if (beforeAllocation.tokens > 0) { + if (isAuth && poi != 0) { + if (rewardsDestination != address(0)) { + assertEq(beforeStakingBalance + calcRewards - calcIndexerRewards, afterStakingBalance); + assertEq(beforeIndexerBalance, afterIndexerBalance); + assertEq(beforeBeneficiaryBalance + calcIndexerRewards, afterBeneficiaryBalance); + } else { + assertEq(beforeStakingBalance + calcRewards, afterStakingBalance); + assertEq(beforeIndexerBalance, afterIndexerBalance); + assertEq(beforeBeneficiaryBalance, afterBeneficiaryBalance); + } + } else { + assertEq(beforeStakingBalance, afterStakingBalance); + assertEq(beforeIndexerBalance, afterIndexerBalance); + assertEq(beforeBeneficiaryBalance, afterBeneficiaryBalance); + } + } else { + assertEq(beforeStakingBalance, afterStakingBalance); + assertEq(beforeIndexerBalance, afterIndexerBalance); + assertEq(beforeBeneficiaryBalance, afterBeneficiaryBalance); + } + + assertEq(afterAllocation.indexer, beforeAllocation.indexer); + assertEq(afterAllocation.subgraphDeploymentID, beforeAllocation.subgraphDeploymentID); + assertEq(afterAllocation.tokens, beforeAllocation.tokens); + assertEq(afterAllocation.createdAtEpoch, beforeAllocation.createdAtEpoch); + assertEq(afterAllocation.closedAtEpoch, epochManager.currentEpoch()); + assertEq(afterAllocation.collectedFees, beforeAllocation.collectedFees); + assertEq(afterAllocation.__DEPRECATED_effectiveAllocation, beforeAllocation.__DEPRECATED_effectiveAllocation); + assertEq(afterAllocation.accRewardsPerAllocatedToken, beforeAllocation.accRewardsPerAllocatedToken); + assertEq(afterAllocation.distributedRebates, beforeAllocation.distributedRebates); + + if (beforeAllocation.tokens > 0 && isAuth && poi != 0 && rewardsDestination == address(0)) { + assertEq(afterServiceProvider.tokensStaked, beforeServiceProvider.tokensStaked + calcIndexerRewards); + } else { + assertEq(afterServiceProvider.tokensStaked, beforeServiceProvider.tokensStaked); + } + assertEq(afterServiceProvider.tokensProvisioned, beforeServiceProvider.tokensProvisioned); + assertEq( + afterServiceProvider.__DEPRECATED_tokensAllocated + beforeAllocation.tokens, + beforeServiceProvider.__DEPRECATED_tokensAllocated + ); + assertEq(afterServiceProvider.__DEPRECATED_tokensLocked, beforeServiceProvider.__DEPRECATED_tokensLocked); + assertEq( + afterServiceProvider.__DEPRECATED_tokensLockedUntil, + beforeServiceProvider.__DEPRECATED_tokensLockedUntil + ); + + assertEq(afterSubgraphAllocations + beforeAllocation.tokens, beforeSubgraphAllocations); + + if (beforeAllocation.tokens > 0 && isAuth && poi != 0 && beforePool.tokens > 0) { + assertEq(afterPool.tokens, beforePool.tokens + calcDelegatorRewards); + } else { + assertEq(afterPool.tokens, beforePool.tokens); + } + } + /* * STORAGE HELPERS */ @@ -1487,9 +1607,11 @@ abstract contract HorizonStakingSharedTest is GraphBaseTest { // So we use a custom struct here and remove the nested mapping which we don't need anyways struct DelegationPoolInternalTest { // (Deprecated) Time, in blocks, an indexer must wait before updating delegation parameters + uint32 __DEPRECATED_cooldownBlocks; // (Deprecated) Percentage of indexing rewards for the service provider, in PPM + uint32 __DEPRECATED_indexingRewardCut; // (Deprecated) Percentage of query fees for the service provider, in PPM - uint256 __DEPRECATED_packed_data; + uint32 __DEPRECATED_queryFeeCut; // (Deprecated) Block when the delegation parameters were last updated uint256 __DEPRECATED_updatedAtBlock; // Total tokens as pool reserves @@ -1517,8 +1639,12 @@ abstract contract HorizonStakingSharedTest is GraphBaseTest { baseSlot = uint256(keccak256(abi.encode(verifier, keccak256(abi.encode(serviceProvider, slotNumber))))); } + uint256 packedData = uint256(vm.load(address(staking), bytes32(baseSlot))); + DelegationPoolInternalTest memory delegationPoolInternal = DelegationPoolInternalTest({ - __DEPRECATED_packed_data: uint256(vm.load(address(staking), bytes32(baseSlot))), + __DEPRECATED_cooldownBlocks: uint32(packedData & 0xFFFFFFFF), + __DEPRECATED_indexingRewardCut: uint32((packedData >> 32) & 0xFFFFFFFF), + __DEPRECATED_queryFeeCut: uint32((packedData >> 64) & 0xFFFFFFFF), __DEPRECATED_updatedAtBlock: uint256(vm.load(address(staking), bytes32(baseSlot + 1))), tokens: uint256(vm.load(address(staking), bytes32(baseSlot + 2))), shares: uint256(vm.load(address(staking), bytes32(baseSlot + 3))), @@ -1623,6 +1749,11 @@ abstract contract HorizonStakingSharedTest is GraphBaseTest { vm.store(address(staking), subgraphAllocationsBaseSlot, bytes32(currentAllocatedTokens + tokens)); } + function _getStorage_SubgraphAllocations(bytes32 subgraphDeploymentID) internal view returns (uint256) { + uint256 subgraphsAllocationsSlot = 16; + bytes32 subgraphAllocationsBaseSlot = keccak256(abi.encode(subgraphDeploymentID, subgraphsAllocationsSlot)); + return uint256(vm.load(address(staking), subgraphAllocationsBaseSlot)); + } function _setStorage_RewardsDestination(address serviceProvider, address destination) internal { uint256 rewardsDestinationSlot = 23; @@ -1630,16 +1761,34 @@ abstract contract HorizonStakingSharedTest is GraphBaseTest { vm.store(address(staking), rewardsDestinationSlotBaseSlot, bytes32(uint256(uint160(destination)))); } - function _setStorage_MaxAllocationEpochs() internal { + function _getStorage_RewardsDestination(address serviceProvider) internal view returns (address) { + uint256 rewardsDestinationSlot = 23; + bytes32 rewardsDestinationSlotBaseSlot = keccak256(abi.encode(serviceProvider, rewardsDestinationSlot)); + return address(uint160(uint256(vm.load(address(staking), rewardsDestinationSlotBaseSlot)))); + } + + function _setStorage_MaxAllocationEpochs(uint256 maxAllocationEpochs) internal { uint256 slot = 13; - vm.store(address(staking), bytes32(slot), bytes32(MAX_ALLOCATION_EPOCHS) << 128); + vm.store(address(staking), bytes32(slot), bytes32(maxAllocationEpochs) << 128); + + uint256 readMaxAllocationEpochs = _getStorage_MaxAllocationEpochs(); + assertEq(readMaxAllocationEpochs, maxAllocationEpochs); + } + + function _getStorage_MaxAllocationEpochs() internal view returns (uint64) { + uint256 slot = 13; + return uint64(uint256(vm.load(address(staking), bytes32(slot)) >> 128)); } - function _setStorage_DelegationPool(address serviceProvider, uint256 tokens, uint32 indexingRewardCut, uint32 queryFeeCut) internal { + function _setStorage_DelegationPool( + address serviceProvider, + uint256 tokens, + uint32 indexingRewardCut, + uint32 queryFeeCut + ) internal { bytes32 baseSlot = keccak256(abi.encode(serviceProvider, uint256(20))); bytes32 feeCutValues = bytes32( - (uint256(indexingRewardCut) << uint256(32)) | - (uint256(queryFeeCut) << uint256(64)) + (uint256(indexingRewardCut) << uint256(32)) | (uint256(queryFeeCut) << uint256(64)) ); bytes32 tokensSlot = bytes32(uint256(baseSlot) + 2); vm.store(address(staking), baseSlot, feeCutValues); diff --git a/packages/horizon/test/staking/allocation/close.t.sol b/packages/horizon/test/staking/allocation/close.t.sol index f084c2af0..aaa4f22e3 100644 --- a/packages/horizon/test/staking/allocation/close.t.sol +++ b/packages/horizon/test/staking/allocation/close.t.sol @@ -18,24 +18,16 @@ contract HorizonStakingCloseAllocationTest is HorizonStakingTest { function testCloseAllocation(uint256 tokens) public useIndexer useAllocation(1 ether) { tokens = bound(tokens, 1, MAX_STAKING_TOKENS); - _setStorage_MaxAllocationEpochs(); _createProvision(users.indexer, subgraphDataServiceLegacyAddress, tokens, 0, 0); // Skip 15 epochs vm.roll(15); - staking.closeAllocation(_allocationId, _poi); - IHorizonStakingExtension.Allocation memory allocation = staking.getAllocation(_allocationId); - assertEq(allocation.closedAtEpoch, epochManager.currentEpoch()); - - // Stake should be updated with rewards - assertEq(staking.getStake(address(users.indexer)), tokens * 2 + ALLOCATIONS_REWARD_CUT); + _closeAllocation(_allocationId, _poi); } function testCloseAllocation_WithBeneficiaryAddress(uint256 tokens) public useIndexer useAllocation(1 ether) { tokens = bound(tokens, 1, MAX_STAKING_TOKENS); - - _setStorage_MaxAllocationEpochs(); _createProvision(users.indexer, subgraphDataServiceLegacyAddress, tokens, 0, 0); address beneficiary = makeAddr("beneficiary"); @@ -44,12 +36,7 @@ contract HorizonStakingCloseAllocationTest is HorizonStakingTest { // Skip 15 epochs vm.roll(15); - staking.closeAllocation(_allocationId, _poi); - IHorizonStakingExtension.Allocation memory allocation = staking.getAllocation(_allocationId); - assertEq(allocation.closedAtEpoch, epochManager.currentEpoch()); - - // Stake should be updated with rewards - assertEq(token.balanceOf(beneficiary), ALLOCATIONS_REWARD_CUT); + _closeAllocation(_allocationId, _poi); } function testCloseAllocation_RevertWhen_NotActive() public { @@ -65,26 +52,17 @@ contract HorizonStakingCloseAllocationTest is HorizonStakingTest { function testCloseAllocation_AfterMaxEpochs_AnyoneCanClose(uint256 tokens) public useIndexer useAllocation(1 ether) { tokens = bound(tokens, 1, MAX_STAKING_TOKENS); - _setStorage_MaxAllocationEpochs(); _createProvision(users.indexer, subgraphDataServiceLegacyAddress, tokens, 0, 0); // Skip to over the max allocation epochs - vm.roll(MAX_ALLOCATION_EPOCHS + 2); + vm.roll((MAX_ALLOCATION_EPOCHS + 1)* EPOCH_LENGTH + 1); resetPrank(users.delegator); - staking.closeAllocation(_allocationId, 0x0); - IHorizonStakingExtension.Allocation memory allocation = staking.getAllocation(_allocationId); - assertEq(allocation.closedAtEpoch, epochManager.currentEpoch()); - - // No rewards distributed - assertEq(staking.getStake(address(users.indexer)), tokens * 2); + _closeAllocation(_allocationId, 0x0); } function testCloseAllocation_RevertWhen_ZeroTokensNotAuthorized() public useIndexer useAllocation(1 ether){ - _setStorage_MaxAllocationEpochs(); - - // Skip to over the max allocation epochs - vm.roll(MAX_ALLOCATION_EPOCHS + 2); + _createProvision(users.indexer, subgraphDataServiceLegacyAddress, 100 ether, 0, 0); resetPrank(users.delegator); vm.expectRevert("!auth"); @@ -99,20 +77,12 @@ contract HorizonStakingCloseAllocationTest is HorizonStakingTest { uint256 legacyAllocationTokens = tokens / 2; uint256 provisionTokens = tokens - legacyAllocationTokens; - _setStorage_MaxAllocationEpochs(); _createProvision(users.indexer, subgraphDataServiceLegacyAddress, provisionTokens, 0, 0); _setStorage_DelegationPool(users.indexer, delegationTokens, indexingRewardCut, 0); // Skip 15 epochs vm.roll(15); - staking.closeAllocation(_allocationId, _poi); - IHorizonStakingExtension.Allocation memory allocation = staking.getAllocation(_allocationId); - assertEq(allocation.closedAtEpoch, epochManager.currentEpoch()); - - uint256 indexerRewardCut = ALLOCATIONS_REWARD_CUT.mulPPM(indexingRewardCut); - uint256 delegationFeeCut = ALLOCATIONS_REWARD_CUT - indexerRewardCut; - assertEq(staking.getStake(address(users.indexer)), tokens + indexerRewardCut); - assertEq(staking.getDelegationPool(users.indexer, subgraphDataServiceLegacyAddress).tokens, delegationTokens + delegationFeeCut); + _closeAllocation(_allocationId, _poi); } } \ No newline at end of file diff --git a/packages/horizon/test/staking/allocation/collect.t.sol b/packages/horizon/test/staking/allocation/collect.t.sol index ee7335274..6c91786a4 100644 --- a/packages/horizon/test/staking/allocation/collect.t.sol +++ b/packages/horizon/test/staking/allocation/collect.t.sol @@ -150,7 +150,7 @@ contract HorizonStakingCollectAllocationTest is HorizonStakingTest { uint256 provisionTokens, uint256 allocationTokens, uint256 collectTokens - ) public useIndexer useRebateParameters useAllocation(1 ether) { + ) public useIndexer useRebateParameters useAllocation(allocationTokens) { provisionTokens = bound(provisionTokens, 1, MAX_STAKING_TOKENS); allocationTokens = bound(allocationTokens, 0, MAX_STAKING_TOKENS); collectTokens = bound(collectTokens, 0, MAX_STAKING_TOKENS); From 3a38af76adf90be9db461c5157052de62f875031 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1s=20Migone?= Date: Fri, 6 Sep 2024 15:40:36 -0300 Subject: [PATCH 21/24] test: refactor collect allocation tests MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Tomás Migone --- .../HorizonStakingShared.t.sol | 353 +++++++++++++++++- .../test/staking/allocation/collect.t.sol | 112 +----- .../test/staking/governance/governance.t.sol | 4 +- 3 files changed, 350 insertions(+), 119 deletions(-) diff --git a/packages/horizon/test/shared/horizon-staking/HorizonStakingShared.t.sol b/packages/horizon/test/shared/horizon-staking/HorizonStakingShared.t.sol index 4dae950ca..83980c3a9 100644 --- a/packages/horizon/test/shared/horizon-staking/HorizonStakingShared.t.sol +++ b/packages/horizon/test/shared/horizon-staking/HorizonStakingShared.t.sol @@ -13,6 +13,7 @@ import { IL2StakingBase } from "@graphprotocol/contracts/contracts/l2/staking/IL import { LinkedList } from "../../../contracts/libraries/LinkedList.sol"; import { MathUtils } from "../../../contracts/libraries/MathUtils.sol"; import { PPMMath } from "../../../contracts/libraries/PPMMath.sol"; +import { ExponentialRebates } from "../../../contracts/staking/libraries/ExponentialRebates.sol"; abstract contract HorizonStakingSharedTest is GraphBaseTest { using LinkedList for LinkedList.List; @@ -24,6 +25,11 @@ abstract contract HorizonStakingSharedTest is GraphBaseTest { bytes32 internal constant _subgraphDeploymentID = keccak256("subgraphDeploymentID"); uint256 internal constant MAX_ALLOCATION_EPOCHS = 28; + uint32 internal alphaNumerator = 100; + uint32 internal alphaDenominator = 100; + uint32 internal lambdaNumerator = 60; + uint32 internal lambdaDenominator = 100; + /* * MODIFIERS */ @@ -83,10 +89,16 @@ abstract contract HorizonStakingSharedTest is GraphBaseTest { } modifier useAllocation(uint256 tokens) { + vm.assume(tokens <= MAX_STAKING_TOKENS); _createAllocation(users.indexer, _allocationId, _subgraphDeploymentID, tokens); _; } + modifier useRebateParameters() { + _setStorage_RebateParameters(alphaNumerator, alphaDenominator, lambdaNumerator, lambdaDenominator); + _; + } + /* * HELPERS: these are shortcuts to perform common actions that often involve multiple contract calls */ @@ -172,7 +184,7 @@ abstract contract HorizonStakingSharedTest is GraphBaseTest { function _unstake(uint256 _tokens) internal { (, address msgSender, ) = vm.readCallers(); - uint256 deprecatedThawingPeriod = uint256(vm.load(address(staking), bytes32(uint256(13)))); + uint256 deprecatedThawingPeriod = staking.__DEPRECATED_getThawingPeriod(); // before uint256 beforeSenderBalance = token.balanceOf(msgSender); @@ -1527,7 +1539,7 @@ abstract contract HorizonStakingSharedTest is GraphBaseTest { ); assertEq(afterSubgraphAllocations + beforeAllocation.tokens, beforeSubgraphAllocations); - + if (beforeAllocation.tokens > 0 && isAuth && poi != 0 && beforePool.tokens > 0) { assertEq(afterPool.tokens, beforePool.tokens + calcDelegatorRewards); } else { @@ -1535,6 +1547,126 @@ abstract contract HorizonStakingSharedTest is GraphBaseTest { } } + function _collect(uint256 tokens, address allocationId) internal { + (, address msgSender, ) = vm.readCallers(); + + // before + IHorizonStakingExtension.Allocation memory beforeAllocation = staking.getAllocation(allocationId); + DelegationPoolInternalTest memory beforePool = _getStorage_DelegationPoolInternal( + beforeAllocation.indexer, + subgraphDataServiceLegacyAddress, + true + ); + ServiceProviderInternal memory beforeServiceProvider = _getStorage_ServiceProviderInternal( + beforeAllocation.indexer + ); + + (uint32 curationPercentage, uint32 protocolPercentage) = _getStorage_ProtocolTaxAndCuration(); + address rewardsDestination = _getStorage_RewardsDestination(beforeAllocation.indexer); + + uint256 beforeStakingBalance = token.balanceOf(address(staking)); + uint256 beforeSenderBalance = token.balanceOf(msgSender); + uint256 beforeCurationBalance = token.balanceOf(address(curation)); + uint256 beforeBeneficiaryBalance = token.balanceOf(rewardsDestination); + + // calc some stuff + uint256 calcProtocolTaxTokens = tokens.mulPPMRoundUp(protocolPercentage); + uint256 calcQueryFees = tokens - calcProtocolTaxTokens; + + uint256 calcCurationCutTokens = 0; + if (curation.isCurated(beforeAllocation.subgraphDeploymentID)) { + calcCurationCutTokens = calcQueryFees.mulPPMRoundUp(curationPercentage); + calcQueryFees -= calcCurationCutTokens; + } + + uint256 calcNewRebates = ExponentialRebates.exponentialRebates( + calcQueryFees + beforeAllocation.collectedFees, + beforeAllocation.tokens, + alphaNumerator, + alphaDenominator, + lambdaNumerator, + lambdaDenominator + ); + uint256 calcPayment = calcNewRebates > calcQueryFees ? calcQueryFees : calcNewRebates; + + uint256 calcDelegationFeeCut = 0; + if (beforePool.tokens > 0) { + calcDelegationFeeCut = calcPayment - calcPayment.mulPPM(beforePool.__DEPRECATED_queryFeeCut); + calcPayment -= calcDelegationFeeCut; + } + + // staking.collect() + if (tokens > 0) { + vm.expectEmit(address(staking)); + emit IHorizonStakingExtension.RebateCollected( + msgSender, + beforeAllocation.indexer, + beforeAllocation.subgraphDeploymentID, + allocationId, + epochManager.currentEpoch(), + tokens, + calcProtocolTaxTokens, + calcCurationCutTokens, + calcQueryFees, + calcPayment, + calcDelegationFeeCut + ); + } + staking.collect(tokens, allocationId); + + // after + IHorizonStakingExtension.Allocation memory afterAllocation = staking.getAllocation(allocationId); + DelegationPoolInternalTest memory afterPool = _getStorage_DelegationPoolInternal( + beforeAllocation.indexer, + subgraphDataServiceLegacyAddress, + true + ); + ServiceProviderInternal memory afterServiceProvider = _getStorage_ServiceProviderInternal( + beforeAllocation.indexer + ); + + uint256 afterBeneficiaryBalance = token.balanceOf(rewardsDestination); + uint256 afterStakingBalance = token.balanceOf(address(staking)); + uint256 afterSenderBalance = token.balanceOf(msgSender); + uint256 afterCurationBalance = token.balanceOf(address(curation)); + + // assert + + assertEq(afterSenderBalance + tokens, beforeSenderBalance); + assertEq(afterCurationBalance, beforeCurationBalance + calcCurationCutTokens); + if (rewardsDestination != address(0)) { + assertEq(afterBeneficiaryBalance, beforeBeneficiaryBalance + calcPayment); + assertEq(afterStakingBalance, beforeStakingBalance + calcDelegationFeeCut); + } else { + assertEq(afterBeneficiaryBalance, beforeBeneficiaryBalance); + assertEq(afterStakingBalance, beforeStakingBalance + calcDelegationFeeCut + calcPayment); + } + + assertEq( + afterAllocation.collectedFees, + beforeAllocation.collectedFees + tokens - calcProtocolTaxTokens - calcCurationCutTokens + ); + assertEq(afterAllocation.indexer, beforeAllocation.indexer); + assertEq(afterAllocation.subgraphDeploymentID, beforeAllocation.subgraphDeploymentID); + assertEq(afterAllocation.tokens, beforeAllocation.tokens); + assertEq(afterAllocation.createdAtEpoch, beforeAllocation.createdAtEpoch); + assertEq(afterAllocation.closedAtEpoch, beforeAllocation.closedAtEpoch); + assertEq(afterAllocation.accRewardsPerAllocatedToken, beforeAllocation.accRewardsPerAllocatedToken); + assertEq(afterAllocation.distributedRebates, beforeAllocation.distributedRebates + calcNewRebates); + + assertEq(afterPool.tokens, beforePool.tokens + calcDelegationFeeCut); + assertEq(afterPool.shares, beforePool.shares); + assertEq(afterPool.tokensThawing, beforePool.tokensThawing); + assertEq(afterPool.sharesThawing, beforePool.sharesThawing); + + assertEq(afterServiceProvider.tokensProvisioned, beforeServiceProvider.tokensProvisioned); + if (rewardsDestination != address(0)) { + assertEq(afterServiceProvider.tokensStaked, beforeServiceProvider.tokensStaked); + } else { + assertEq(afterServiceProvider.tokensStaked, beforeServiceProvider.tokensStaked + calcPayment); + } + } + /* * STORAGE HELPERS */ @@ -1579,10 +1711,26 @@ abstract contract HorizonStakingSharedTest is GraphBaseTest { return vm.load(address(staking), bytes32(slot)) == bytes32(uint256(1)); } + // function _setStorage_DeprecatedThawingPeriod(uint32 _thawingPeriod) internal { + // uint256 slot = 13; + // bytes32 value = bytes32(uint256(_thawingPeriod)); + // vm.store(address(staking), bytes32(slot), value); + // } + function _setStorage_DeprecatedThawingPeriod(uint32 _thawingPeriod) internal { uint256 slot = 13; - bytes32 value = bytes32(uint256(_thawingPeriod)); - vm.store(address(staking), bytes32(slot), value); + + // Read the current value of the slot + uint256 currentSlotValue = uint256(vm.load(address(staking), bytes32(slot))); + + // Create a mask to clear the bits for __DEPRECATED_thawingPeriod (bits 0-31) + uint256 mask = ~(uint256(0xFFFFFFFF)); // Mask to clear the first 32 bits + + // Clear the bits for __DEPRECATED_thawingPeriod and set the new value + uint256 newSlotValue = (currentSlotValue & mask) | uint256(_thawingPeriod); + + // Store the updated value back into the slot + vm.store(address(staking), bytes32(slot), bytes32(newSlotValue)); } function _setStorage_ServiceProvider( @@ -1687,10 +1835,6 @@ abstract contract HorizonStakingSharedTest is GraphBaseTest { return delegation; } - function _setStorage_DEPRECATED_ThawingPeriod(uint64 thawingPeriod) internal { - vm.store(address(staking), bytes32(uint256(13)), bytes32(uint256(thawingPeriod))); - } - function _getStorage_CounterpartStakingAddress() internal view returns (address) { uint256 slot = 24; return address(uint160(uint256(vm.load(address(staking), bytes32(slot))))); @@ -1769,15 +1913,36 @@ abstract contract HorizonStakingSharedTest is GraphBaseTest { function _setStorage_MaxAllocationEpochs(uint256 maxAllocationEpochs) internal { uint256 slot = 13; - vm.store(address(staking), bytes32(slot), bytes32(maxAllocationEpochs) << 128); + + // Read the current value of the storage slot + uint256 currentSlotValue = uint256(vm.load(address(staking), bytes32(slot))); + + // Mask to clear the specific bits for __DEPRECATED_maxAllocationEpochs (bits 128-159) + uint256 mask = ~(uint256(0xFFFFFFFF) << 128); + + // Clear the bits and set the new maxAllocationEpochs value + uint256 newSlotValue = (currentSlotValue & mask) | (uint256(maxAllocationEpochs) << 128); + + // Store the updated value back into the slot + vm.store(address(staking), bytes32(slot), bytes32(newSlotValue)); uint256 readMaxAllocationEpochs = _getStorage_MaxAllocationEpochs(); assertEq(readMaxAllocationEpochs, maxAllocationEpochs); } - function _getStorage_MaxAllocationEpochs() internal view returns (uint64) { + function _getStorage_MaxAllocationEpochs() internal view returns (uint256) { uint256 slot = 13; - return uint64(uint256(vm.load(address(staking), bytes32(slot)) >> 128)); + + // Read the current value of the storage slot + uint256 currentSlotValue = uint256(vm.load(address(staking), bytes32(slot))); + + // Mask to isolate bits 128-159 + uint256 mask = uint256(0xFFFFFFFF) << 128; + + // Extract the maxAllocationEpochs by masking and shifting + uint256 maxAllocationEpochs = (currentSlotValue & mask) >> 128; + + return maxAllocationEpochs; } function _setStorage_DelegationPool( @@ -1795,6 +1960,172 @@ abstract contract HorizonStakingSharedTest is GraphBaseTest { vm.store(address(staking), tokensSlot, bytes32(tokens)); } + // function _setStorage_RebateParameters( + // uint32 alphaNumerator, + // uint32 alphaDenominator, + // uint32 lambdaNumerator, + // uint32 lambdaDenominator + // ) internal { + // // Store alpha numerator and denominator + // uint256 alphaSlot = 13; + // uint256 alphaNumeratorOffset = 20; + // uint256 alphaDenominatorOffset = 24; + // bytes32 alphaValues = bytes32( + // (uint256(alphaNumerator) << (8 * alphaNumeratorOffset)) | + // (uint256(alphaDenominator) << (8 * alphaDenominatorOffset)) + // ); + // vm.store(address(staking), bytes32(alphaSlot), alphaValues); + + // // Store lambda numerator and denominator + // uint256 lambdaSlot = 25; + // uint256 lambdaNumeratorOffset = 20; + // uint256 lambdaDenominatorOffset = 24; + // bytes32 lambdaValues = bytes32( + // (uint256(lambdaNumerator) << (8 * lambdaNumeratorOffset)) | + // (uint256(lambdaDenominator) << (8 * lambdaDenominatorOffset)) + // ); + // vm.store(address(staking), bytes32(lambdaSlot), lambdaValues); + + // ( + // uint32 readAlphaNumerator, + // uint32 readAlphaDenominator, + // uint32 readLambdaNumerator, + // uint32 readLambdaDenominator + // ) = _getStorage_RebateParameters(); + // assertEq(readAlphaNumerator, alphaNumerator); + // assertEq(readAlphaDenominator, alphaDenominator); + // assertEq(readLambdaNumerator, lambdaNumerator); + // assertEq(readLambdaDenominator, lambdaDenominator); + // } + + function _setStorage_RebateParameters( + uint32 alphaNumerator, + uint32 alphaDenominator, + uint32 lambdaNumerator, + uint32 lambdaDenominator + ) internal { + // Store alpha numerator and denominator in slot 13 + uint256 alphaSlot = 13; + uint256 alphaNumeratorOffset = 160; // Offset for __DEPRECATED_alphaNumerator (20th byte) + uint256 alphaDenominatorOffset = 192; // Offset for __DEPRECATED_alphaDenominator (24th byte) + + // Read current value of the slot + uint256 currentAlphaSlotValue = uint256(vm.load(address(staking), bytes32(alphaSlot))); + + // Create a mask to clear the bits for alphaNumerator and alphaDenominator + uint256 alphaMask = ~(uint256(0xFFFFFFFF) << alphaNumeratorOffset) & + ~(uint256(0xFFFFFFFF) << alphaDenominatorOffset); + + // Clear and set new values + uint256 newAlphaSlotValue = (currentAlphaSlotValue & alphaMask) | + (uint256(alphaNumerator) << alphaNumeratorOffset) | + (uint256(alphaDenominator) << alphaDenominatorOffset); + + // Store the updated value back into the slot + vm.store(address(staking), bytes32(alphaSlot), bytes32(newAlphaSlotValue)); + + // Store lambda numerator and denominator in slot 25 + uint256 lambdaSlot = 25; + uint256 lambdaNumeratorOffset = 160; // Offset for lambdaNumerator (20th byte) + uint256 lambdaDenominatorOffset = 192; // Offset for lambdaDenominator (24th byte) + + // Read current value of the slot + uint256 currentLambdaSlotValue = uint256(vm.load(address(staking), bytes32(lambdaSlot))); + + // Create a mask to clear the bits for lambdaNumerator and lambdaDenominator + uint256 lambdaMask = ~(uint256(0xFFFFFFFF) << lambdaNumeratorOffset) & + ~(uint256(0xFFFFFFFF) << lambdaDenominatorOffset); + + // Clear and set new values + uint256 newLambdaSlotValue = (currentLambdaSlotValue & lambdaMask) | + (uint256(lambdaNumerator) << lambdaNumeratorOffset) | + (uint256(lambdaDenominator) << lambdaDenominatorOffset); + + // Store the updated value back into the slot + vm.store(address(staking), bytes32(lambdaSlot), bytes32(newLambdaSlotValue)); + + // Verify the storage + ( + uint32 readAlphaNumerator, + uint32 readAlphaDenominator, + uint32 readLambdaNumerator, + uint32 readLambdaDenominator + ) = _getStorage_RebateParameters(); + assertEq(readAlphaNumerator, alphaNumerator); + assertEq(readAlphaDenominator, alphaDenominator); + assertEq(readLambdaNumerator, lambdaNumerator); + assertEq(readLambdaDenominator, lambdaDenominator); + } + + function _getStorage_RebateParameters() internal view returns (uint32, uint32, uint32, uint32) { + // Read alpha numerator and denominator + uint256 alphaSlot = 13; + uint256 alphaValues = uint256(vm.load(address(staking), bytes32(alphaSlot))); + uint32 alphaNumerator = uint32(alphaValues >> 160); + uint32 alphaDenominator = uint32(alphaValues >> 192); + + // Read lambda numerator and denominator + uint256 lambdaSlot = 25; + uint256 lambdaValues = uint256(vm.load(address(staking), bytes32(lambdaSlot))); + uint32 lambdaNumerator = uint32(lambdaValues >> 160); + uint32 lambdaDenominator = uint32(lambdaValues >> 192); + + return (alphaNumerator, alphaDenominator, lambdaNumerator, lambdaDenominator); + } + + // function _setStorage_ProtocolTaxAndCuration(uint32 curationPercentage, uint32 taxPercentage) private { + // bytes32 slot = bytes32(uint256(13)); + // uint256 curationOffset = 4; + // uint256 protocolTaxOffset = 8; + // bytes32 originalValue = vm.load(address(staking), slot); + + // bytes32 newProtocolTaxValue = bytes32( + // ((uint256(originalValue) & + // ~((0xFFFFFFFF << (8 * curationOffset)) | (0xFFFFFFFF << (8 * protocolTaxOffset)))) | + // (uint256(curationPercentage) << (8 * curationOffset))) | + // (uint256(taxPercentage) << (8 * protocolTaxOffset)) + // ); + // vm.store(address(staking), slot, newProtocolTaxValue); + + // (uint32 readCurationPercentage, uint32 readTaxPercentage) = _getStorage_ProtocolTaxAndCuration(); + // assertEq(readCurationPercentage, curationPercentage); + // } + + function _setStorage_ProtocolTaxAndCuration(uint32 curationPercentage, uint32 taxPercentage) internal { + bytes32 slot = bytes32(uint256(13)); + + // Offsets for the percentages + uint256 curationOffset = 32; // __DEPRECATED_curationPercentage (2nd uint32, bits 32-63) + uint256 protocolTaxOffset = 64; // __DEPRECATED_protocolPercentage (3rd uint32, bits 64-95) + + // Read the current slot value + uint256 originalValue = uint256(vm.load(address(staking), slot)); + + // Create masks to clear the specific bits for the two percentages + uint256 mask = ~(uint256(0xFFFFFFFF) << curationOffset) & ~(uint256(0xFFFFFFFF) << protocolTaxOffset); // Mask for curationPercentage // Mask for protocolTax + + // Clear the existing bits and set the new values + uint256 newSlotValue = (originalValue & mask) | + (uint256(curationPercentage) << curationOffset) | + (uint256(taxPercentage) << protocolTaxOffset); + + // Store the updated slot value + vm.store(address(staking), slot, bytes32(newSlotValue)); + + // Verify the values were set correctly + (uint32 readCurationPercentage, uint32 readTaxPercentage) = _getStorage_ProtocolTaxAndCuration(); + assertEq(readCurationPercentage, curationPercentage); + assertEq(readTaxPercentage, taxPercentage); + } + + function _getStorage_ProtocolTaxAndCuration() internal view returns (uint32, uint32) { + bytes32 slot = bytes32(uint256(13)); + bytes32 value = vm.load(address(staking), slot); + uint32 curationPercentage = uint32(uint256(value) >> 32); + uint32 taxPercentage = uint32(uint256(value) >> 64); + return (curationPercentage, taxPercentage); + } + /* * MISC: private functions to help with testing */ diff --git a/packages/horizon/test/staking/allocation/collect.t.sol b/packages/horizon/test/staking/allocation/collect.t.sol index 6c91786a4..9a8329d62 100644 --- a/packages/horizon/test/staking/allocation/collect.t.sol +++ b/packages/horizon/test/staking/allocation/collect.t.sol @@ -10,61 +10,6 @@ import { PPMMath } from "../../../contracts/libraries/PPMMath.sol"; contract HorizonStakingCollectAllocationTest is HorizonStakingTest { using PPMMath for uint256; - uint32 private alphaNumerator = 100; - uint32 private alphaDenominator = 100; - uint32 private lambdaNumerator = 60; - uint32 private lambdaDenominator = 100; - - /* - * MODIFIERS - */ - - modifier useRebateParameters() { - _storeRebateParameters(); - _; - } - - /* - * HELPERS - */ - - function _storeRebateParameters() private { - // Store alpha numerator and denominator - uint256 alphaSlot = 13; - uint256 alphaNumeratorOffset = 20; - uint256 alphaDenominatorOffset = 24; - bytes32 alphaValues = bytes32( - (uint256(alphaNumerator) << (8 * alphaNumeratorOffset)) | - (uint256(alphaDenominator) << (8 * alphaDenominatorOffset)) - ); - vm.store(address(staking), bytes32(alphaSlot), alphaValues); - - // Store lambda numerator and denominator - uint256 lambdaSlot = 25; - uint256 lambdaNumeratorOffset = 20; - uint256 lambdaDenominatorOffset = 24; - bytes32 lambdaValues = bytes32( - (uint256(lambdaNumerator) << (8 * lambdaNumeratorOffset)) | - (uint256(lambdaDenominator) << (8 * lambdaDenominatorOffset)) - ); - vm.store(address(staking), bytes32(lambdaSlot), lambdaValues); - } - - function _storeProtocolTaxAndCuration(uint32 curationPercentage, uint32 taxPercentage) private { - bytes32 slot = bytes32(uint256(13)); - uint256 curationOffset = 4; - uint256 protocolTaxOffset = 8; - bytes32 originalValue = vm.load(address(staking), slot); - - bytes32 newProtocolTaxValue = bytes32( - ((uint256(originalValue) & - ~((0xFFFFFFFF << (8 * curationOffset)) | (0xFFFFFFFF << (8 * protocolTaxOffset)))) | - (uint256(curationPercentage) << (8 * curationOffset))) | - (uint256(taxPercentage) << (8 * protocolTaxOffset)) - ); - vm.store(address(staking), slot, newProtocolTaxValue); - } - /* * TESTS */ @@ -79,13 +24,7 @@ contract HorizonStakingCollectAllocationTest is HorizonStakingTest { staking.collect(tokens, _allocationId); } - function testCollectAllocation_ZeroTokens() public useIndexer useAllocation(1 ether) { - staking.collect(0, _allocationId); - assertEq(staking.getStake(address(users.indexer)), 0); - } - function testCollect_Tokenss( - uint256 provisionTokens, uint256 allocationTokens, uint256 collectTokens, uint256 curationTokens, @@ -93,76 +32,37 @@ contract HorizonStakingCollectAllocationTest is HorizonStakingTest { uint32 protocolTaxPercentage, uint256 delegationTokens, uint32 queryFeeCut - ) public useIndexer useRebateParameters useAllocation(1 ether) { - provisionTokens = bound(provisionTokens, 1, MAX_STAKING_TOKENS); - allocationTokens = bound(allocationTokens, 0, MAX_STAKING_TOKENS); + ) public useIndexer useRebateParameters useAllocation(allocationTokens) { collectTokens = bound(collectTokens, 0, MAX_STAKING_TOKENS); curationTokens = bound(curationTokens, 0, MAX_STAKING_TOKENS); delegationTokens = bound(delegationTokens, 0, MAX_STAKING_TOKENS); vm.assume(curationPercentage <= MAX_PPM); vm.assume(protocolTaxPercentage <= MAX_PPM); vm.assume(queryFeeCut <= MAX_PPM); + resetPrank(users.indexer); - _storeProtocolTaxAndCuration(curationPercentage, protocolTaxPercentage); + _setStorage_ProtocolTaxAndCuration(curationPercentage, protocolTaxPercentage); + console.log("queryFeeCut", queryFeeCut); _setStorage_DelegationPool(users.indexer, delegationTokens, 0, queryFeeCut); - _createProvision(users.indexer, subgraphDataServiceLegacyAddress, provisionTokens, 0, 0); curation.signal(_subgraphDeploymentID, curationTokens); resetPrank(users.gateway); approve(address(staking), collectTokens); - staking.collect(collectTokens, _allocationId); - - uint256 protocolTaxTokens = collectTokens.mulPPMRoundUp(protocolTaxPercentage); - uint256 queryFees = collectTokens - protocolTaxTokens; - - uint256 curationCutTokens = 0; - if (curationTokens > 0) { - curationCutTokens = queryFees.mulPPMRoundUp(curationPercentage); - queryFees -= curationCutTokens; - } - - uint256 newRebates = ExponentialRebates.exponentialRebates( - queryFees, - allocationTokens, - alphaNumerator, - alphaDenominator, - lambdaNumerator, - lambdaDenominator - ); - uint256 payment = newRebates > queryFees ? queryFees : newRebates; - - uint256 delegationFeeCut = 0; - if (delegationTokens > 0) { - delegationFeeCut = payment - payment.mulPPM(queryFeeCut); - payment -= delegationFeeCut; - } - - assertEq(staking.getStake(address(users.indexer)), allocationTokens + provisionTokens + payment); - assertEq(curation.curation(_subgraphDeploymentID), curationTokens + curationCutTokens); - assertEq( - staking.getDelegationPool(users.indexer, subgraphDataServiceLegacyAddress).tokens, - delegationTokens + delegationFeeCut - ); - assertEq(token.balanceOf(address(payments)), 0); + _collect(collectTokens, _allocationId); } function testCollect_WithBeneficiaryAddress( - uint256 provisionTokens, uint256 allocationTokens, uint256 collectTokens ) public useIndexer useRebateParameters useAllocation(allocationTokens) { - provisionTokens = bound(provisionTokens, 1, MAX_STAKING_TOKENS); - allocationTokens = bound(allocationTokens, 0, MAX_STAKING_TOKENS); collectTokens = bound(collectTokens, 0, MAX_STAKING_TOKENS); - _createProvision(users.indexer, subgraphDataServiceLegacyAddress, provisionTokens, 0, 0); - address beneficiary = makeAddr("beneficiary"); _setStorage_RewardsDestination(users.indexer, beneficiary); resetPrank(users.gateway); approve(address(staking), collectTokens); - staking.collect(collectTokens, _allocationId); + _collect(collectTokens, _allocationId); uint256 newRebates = ExponentialRebates.exponentialRebates( collectTokens, diff --git a/packages/horizon/test/staking/governance/governance.t.sol b/packages/horizon/test/staking/governance/governance.t.sol index 19d1c6de0..cb354697c 100644 --- a/packages/horizon/test/staking/governance/governance.t.sol +++ b/packages/horizon/test/staking/governance/governance.t.sol @@ -40,9 +40,9 @@ contract HorizonStakingGovernanceTest is HorizonStakingTest { staking.setDelegationSlashingEnabled(); } - function testGovernance_ClearThawingPeriod(uint64 thawingPeriod) public useGovernor { + function testGovernance_ClearThawingPeriod(uint32 thawingPeriod) public useGovernor { // simulate previous thawing period - _setStorage_DEPRECATED_ThawingPeriod(thawingPeriod); + _setStorage_DeprecatedThawingPeriod(thawingPeriod); _clearThawingPeriod(); } From ada5ff8da7222b83c6ec2f7e3685e0b5e380de90 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1s=20Migone?= Date: Fri, 6 Sep 2024 17:33:15 -0300 Subject: [PATCH 22/24] fix: remove comments MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Tomás Migone --- .../HorizonStakingShared.t.sol | 54 ++----------------- .../test/staking/allocation/allocation.t.sol | 23 -------- 2 files changed, 5 insertions(+), 72 deletions(-) diff --git a/packages/horizon/test/shared/horizon-staking/HorizonStakingShared.t.sol b/packages/horizon/test/shared/horizon-staking/HorizonStakingShared.t.sol index 83980c3a9..2f81bb0d1 100644 --- a/packages/horizon/test/shared/horizon-staking/HorizonStakingShared.t.sol +++ b/packages/horizon/test/shared/horizon-staking/HorizonStakingShared.t.sol @@ -1711,12 +1711,6 @@ abstract contract HorizonStakingSharedTest is GraphBaseTest { return vm.load(address(staking), bytes32(slot)) == bytes32(uint256(1)); } - // function _setStorage_DeprecatedThawingPeriod(uint32 _thawingPeriod) internal { - // uint256 slot = 13; - // bytes32 value = bytes32(uint256(_thawingPeriod)); - // vm.store(address(staking), bytes32(slot), value); - // } - function _setStorage_DeprecatedThawingPeriod(uint32 _thawingPeriod) internal { uint256 slot = 13; @@ -1960,44 +1954,6 @@ abstract contract HorizonStakingSharedTest is GraphBaseTest { vm.store(address(staking), tokensSlot, bytes32(tokens)); } - // function _setStorage_RebateParameters( - // uint32 alphaNumerator, - // uint32 alphaDenominator, - // uint32 lambdaNumerator, - // uint32 lambdaDenominator - // ) internal { - // // Store alpha numerator and denominator - // uint256 alphaSlot = 13; - // uint256 alphaNumeratorOffset = 20; - // uint256 alphaDenominatorOffset = 24; - // bytes32 alphaValues = bytes32( - // (uint256(alphaNumerator) << (8 * alphaNumeratorOffset)) | - // (uint256(alphaDenominator) << (8 * alphaDenominatorOffset)) - // ); - // vm.store(address(staking), bytes32(alphaSlot), alphaValues); - - // // Store lambda numerator and denominator - // uint256 lambdaSlot = 25; - // uint256 lambdaNumeratorOffset = 20; - // uint256 lambdaDenominatorOffset = 24; - // bytes32 lambdaValues = bytes32( - // (uint256(lambdaNumerator) << (8 * lambdaNumeratorOffset)) | - // (uint256(lambdaDenominator) << (8 * lambdaDenominatorOffset)) - // ); - // vm.store(address(staking), bytes32(lambdaSlot), lambdaValues); - - // ( - // uint32 readAlphaNumerator, - // uint32 readAlphaDenominator, - // uint32 readLambdaNumerator, - // uint32 readLambdaDenominator - // ) = _getStorage_RebateParameters(); - // assertEq(readAlphaNumerator, alphaNumerator); - // assertEq(readAlphaDenominator, alphaDenominator); - // assertEq(readLambdaNumerator, lambdaNumerator); - // assertEq(readLambdaDenominator, lambdaDenominator); - // } - function _setStorage_RebateParameters( uint32 alphaNumerator, uint32 alphaDenominator, @@ -2061,16 +2017,16 @@ abstract contract HorizonStakingSharedTest is GraphBaseTest { // Read alpha numerator and denominator uint256 alphaSlot = 13; uint256 alphaValues = uint256(vm.load(address(staking), bytes32(alphaSlot))); - uint32 alphaNumerator = uint32(alphaValues >> 160); - uint32 alphaDenominator = uint32(alphaValues >> 192); + uint32 alphaNumerator_ = uint32(alphaValues >> 160); + uint32 alphaDenominator_ = uint32(alphaValues >> 192); // Read lambda numerator and denominator uint256 lambdaSlot = 25; uint256 lambdaValues = uint256(vm.load(address(staking), bytes32(lambdaSlot))); - uint32 lambdaNumerator = uint32(lambdaValues >> 160); - uint32 lambdaDenominator = uint32(lambdaValues >> 192); + uint32 lambdaNumerator_ = uint32(lambdaValues >> 160); + uint32 lambdaDenominator_ = uint32(lambdaValues >> 192); - return (alphaNumerator, alphaDenominator, lambdaNumerator, lambdaDenominator); + return (alphaNumerator_, alphaDenominator_, lambdaNumerator_, lambdaDenominator_); } // function _setStorage_ProtocolTaxAndCuration(uint32 curationPercentage, uint32 taxPercentage) private { diff --git a/packages/horizon/test/staking/allocation/allocation.t.sol b/packages/horizon/test/staking/allocation/allocation.t.sol index 1c611ddaa..c5cb92609 100644 --- a/packages/horizon/test/staking/allocation/allocation.t.sol +++ b/packages/horizon/test/staking/allocation/allocation.t.sol @@ -12,29 +12,6 @@ contract HorizonStakingAllocationTest is HorizonStakingTest { * TESTS */ - // function testAllocation_GetAllocation(uint256 tokens) public useIndexer useAllocation(tokens) { - // IHorizonStakingExtension.Allocation memory allocation = staking.getAllocation(_allocationId); - // assertEq(allocation.indexer, _allocation.indexer); - // assertEq(allocation.subgraphDeploymentID, _allocation.subgraphDeploymentID); - // assertEq(allocation.tokens, _allocation.tokens); - // assertEq(allocation.createdAtEpoch, _allocation.createdAtEpoch); - // assertEq(allocation.closedAtEpoch, _allocation.closedAtEpoch); - // assertEq(allocation.collectedFees, _allocation.collectedFees); - // assertEq(allocation.__DEPRECATED_effectiveAllocation, _allocation.__DEPRECATED_effectiveAllocation); - // assertEq(allocation.accRewardsPerAllocatedToken, _allocation.accRewardsPerAllocatedToken); - // assertEq(allocation.distributedRebates, _allocation.distributedRebates); - // } - - // function testAllocation_GetAllocationData(uint256 tokens) public useIndexer useAllocation(tokens) { - // (address indexer, bytes32 subgraphDeploymentID, uint256 tokens_, uint256 accRewardsPerAllocatedToken, uint256 accRewardsPending) = - // staking.getAllocationData(_allocationId); - // assertEq(indexer, _allocation.indexer); - // assertEq(subgraphDeploymentID, _allocation.subgraphDeploymentID); - // assertEq(tokens_, _allocation.tokens); - // assertEq(accRewardsPerAllocatedToken, _allocation.accRewardsPerAllocatedToken); - // assertEq(accRewardsPending, 0); - // } - function testAllocation_GetAllocationState_Active(uint256 tokens) public useIndexer useAllocation(tokens) { IHorizonStakingExtension.AllocationState state = staking.getAllocationState(_allocationId); assertEq(uint16(state), uint16(IHorizonStakingExtension.AllocationState.Active)); From a909d6b0e278b56f93f06375763d0eeb94f3a9c7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1s=20Migone?= Date: Mon, 9 Sep 2024 14:59:05 -0300 Subject: [PATCH 23/24] chore: use solidity 0.8.27, remove compilation via ir MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Tomás Migone --- .../contracts/arbitrum/ITokenGateway.sol | 2 +- .../contracts/curation/ICuration.sol | 2 +- .../contracts/epochs/IEpochManager.sol | 2 +- .../contracts/gateway/ICallhookReceiver.sol | 2 +- .../contracts/governance/Controller.sol | 2 +- .../contracts/governance/Governed.sol | 2 +- .../contracts/governance/IController.sol | 2 +- .../contracts/governance/IManaged.sol | 2 +- .../contracts/governance/Pausable.sol | 2 +- .../contracts/l2/staking/IL2StakingBase.sol | 2 +- .../contracts/l2/staking/IL2StakingTypes.sol | 2 +- .../contracts/rewards/IRewardsIssuer.sol | 2 +- .../contracts/rewards/IRewardsManager.sol | 2 +- .../rewards/RewardsManagerStorage.sol | 2 +- .../contracts/contracts/token/IGraphToken.sol | 2 +- .../contracts/upgrades/GraphProxy.sol | 2 +- .../contracts/upgrades/GraphProxyAdmin.sol | 2 +- .../contracts/upgrades/GraphProxyStorage.sol | 2 +- .../contracts/upgrades/GraphUpgradeable.sol | 2 +- .../contracts/upgrades/IGraphProxy.sol | 2 +- .../contracts/contracts/utils/TokenUtils.sol | 2 +- .../contracts/data-service/DataService.sol | 2 +- .../data-service/DataServiceStorage.sol | 2 +- .../extensions/DataServiceFees.sol | 2 +- .../extensions/DataServiceFeesStorage.sol | 2 +- .../extensions/DataServicePausable.sol | 2 +- .../DataServicePausableUpgradeable.sol | 2 +- .../extensions/DataServiceRescuable.sol | 2 +- .../data-service/interfaces/IDataService.sol | 2 +- .../interfaces/IDataServiceFees.sol | 2 +- .../interfaces/IDataServicePausable.sol | 2 +- .../interfaces/IDataServiceRescuable.sol | 2 +- .../libraries/ProvisionTracker.sol | 2 +- .../utilities/ProvisionManager.sol | 2 +- .../utilities/ProvisionManagerStorage.sol | 2 +- .../contracts/interfaces/IGraphPayments.sol | 2 +- .../contracts/interfaces/IGraphProxyAdmin.sol | 2 +- .../contracts/interfaces/IHorizonStaking.sol | 2 +- .../interfaces/IPaymentsCollector.sol | 2 +- .../contracts/interfaces/IPaymentsEscrow.sol | 2 +- .../contracts/interfaces/ITAPCollector.sol | 2 +- .../internal/IHorizonStakingBase.sol | 2 +- .../internal/IHorizonStakingExtension.sol | 2 +- .../internal/IHorizonStakingMain.sol | 2 +- .../internal/IHorizonStakingTypes.sol | 2 +- .../contracts/libraries/Denominations.sol | 2 +- .../contracts/libraries/LibFixedMath.sol | 2 +- .../contracts/libraries/LinkedList.sol | 2 +- .../horizon/contracts/libraries/MathUtils.sol | 2 +- .../horizon/contracts/libraries/PPMMath.sol | 2 +- .../horizon/contracts/libraries/UintRange.sol | 2 +- .../contracts/mocks/ControllerMock.sol | 2 +- .../horizon/contracts/mocks/CurationMock.sol | 2 +- .../contracts/mocks/EpochManagerMock.sol | 2 +- .../horizon/contracts/mocks/MockGRTToken.sol | 2 +- .../contracts/mocks/RewardsManagerMock.sol | 2 +- .../contracts/payments/GraphPayments.sol | 2 +- .../contracts/payments/PaymentsEscrow.sol | 2 +- .../payments/collectors/TAPCollector.sol | 2 +- .../contracts/staking/HorizonStaking.sol | 2 +- .../contracts/staking/HorizonStakingBase.sol | 2 +- .../staking/HorizonStakingExtension.sol | 2 +- .../staking/HorizonStakingStorage.sol | 2 +- .../staking/libraries/ExponentialRebates.sol | 2 +- .../contracts/staking/utilities/Managed.sol | 2 +- .../contracts/utilities/GraphDirectory.sol | 2 +- packages/horizon/foundry.toml | 11 +- packages/horizon/hardhat.config.ts | 3 +- packages/horizon/test/GraphBase.t.sol | 3 +- .../test/data-service/DataService.t.sol | 2 +- .../data-service/DataServiceUpgradeable.t.sol | 2 +- .../extensions/DataServiceFees.t.sol | 69 +- .../extensions/DataServicePausable.t.sol | 2 +- .../DataServicePausableUpgradeable.t.sol | 2 +- .../implementations/DataServiceBase.sol | 2 +- .../DataServiceBaseUpgradeable.sol | 4 +- .../implementations/DataServiceImpFees.sol | 3 +- .../DataServiceImpPausable.sol | 2 +- .../DataServiceImpPausableUpgradeable.sol | 4 +- .../implementations/DataServiceOverride.sol | 2 +- .../libraries/ProvisionTracker.t.sol | 2 +- .../ProvisionTrackerImplementation.sol | 2 +- .../horizon/test/escrow/GraphEscrow.t.sol | 2 +- packages/horizon/test/escrow/collect.t.sol | 2 +- packages/horizon/test/escrow/collector.t.sol | 2 +- packages/horizon/test/escrow/deposit.t.sol | 2 +- packages/horizon/test/escrow/paused.t.sol | 2 +- packages/horizon/test/escrow/thaw.t.sol | 2 +- packages/horizon/test/escrow/withdraw.t.sol | 2 +- .../horizon/test/libraries/LinkedList.t.sol | 2 +- .../test/libraries/ListImplementation.sol | 4 +- .../horizon/test/payments/GraphPayments.t.sol | 2 +- .../HorizonStakingShared.t.sol | 1045 +++++++++-------- .../horizon/test/staking/HorizonStaking.t.sol | 2 +- .../test/staking/allocation/allocation.t.sol | 2 +- .../test/staking/allocation/close.t.sol | 2 +- .../test/staking/allocation/collect.t.sol | 2 +- .../test/staking/delegation/addToPool.t.sol | 2 +- .../test/staking/delegation/delegate.t.sol | 2 +- .../test/staking/delegation/undelegate.t.sol | 2 +- .../test/staking/delegation/withdraw.t.sol | 2 +- .../test/staking/governance/governance.t.sol | 2 +- .../test/staking/operator/locked.t.sol | 2 +- .../test/staking/operator/operator.t.sol | 2 +- .../test/staking/provision/deprovision.t.sol | 2 +- .../test/staking/provision/locked.t.sol | 2 +- .../test/staking/provision/parameters.t.sol | 2 +- .../test/staking/provision/provision.t.sol | 2 +- .../test/staking/provision/reprovision.t.sol | 2 +- .../horizon/test/staking/provision/thaw.t.sol | 2 +- .../serviceProvider/serviceProvider.t.sol | 2 +- .../horizon/test/staking/slash/slash.t.sol | 2 +- .../horizon/test/staking/stake/stake.t.sol | 2 +- .../horizon/test/staking/stake/unstake.t.sol | 2 +- .../horizon/test/staking/stake/withdraw.t.sol | 2 +- .../test/staking/transfer-tools/ttools.t.sol | 2 +- .../test/utilities/GraphDirectory.t.sol | 2 +- .../GraphDirectoryImplementation.sol | 2 +- packages/horizon/test/utils/Constants.sol | 2 +- packages/horizon/test/utils/Users.sol | 2 +- packages/horizon/test/utils/Utils.sol | 2 +- .../contracts/DisputeManager.sol | 2 +- .../contracts/DisputeManagerStorage.sol | 2 +- .../contracts/SubgraphService.sol | 2 +- .../contracts/SubgraphServiceStorage.sol | 2 +- .../contracts/interfaces/IDisputeManager.sol | 2 +- .../contracts/interfaces/ISubgraphService.sol | 2 +- .../contracts/libraries/Allocation.sol | 2 +- .../contracts/libraries/Attestation.sol | 2 +- .../contracts/libraries/LegacyAllocation.sol | 2 +- .../contracts/utilities/AllocationManager.sol | 2 +- .../utilities/AllocationManagerStorage.sol | 2 +- .../utilities/AttestationManager.sol | 2 +- .../utilities/AttestationManagerStorage.sol | 2 +- .../contracts/utilities/Directory.sol | 2 +- packages/subgraph-service/hardhat.config.ts | 2 +- .../test/SubgraphBaseTest.t.sol | 2 +- .../test/disputeManager/DisputeManager.t.sol | 2 +- .../constructor/constructor.t.sol | 2 +- .../governance/fishermanRewardCut.t.sol | 2 +- .../test/mocks/MockCuration.sol | 2 +- .../test/mocks/MockGRTToken.sol | 2 +- .../test/mocks/MockRewardsManager.sol | 2 +- .../test/shared/SubgraphServiceShared.t.sol | 2 +- .../subgraphService/SubgraphService.t.sol | 2 +- .../subgraphService/allocation/stop.t.sol | 2 +- .../subgraphService/collect/collect.t.sol | 2 +- .../subgraphService/provider/register.t.sol | 2 +- .../subgraphService/provision/accept.t.sol | 2 +- .../subgraph-service/test/utils/Constants.sol | 2 +- .../subgraph-service/test/utils/Users.sol | 2 +- .../subgraph-service/test/utils/Utils.sol | 2 +- 152 files changed, 776 insertions(+), 656 deletions(-) diff --git a/packages/contracts/contracts/arbitrum/ITokenGateway.sol b/packages/contracts/contracts/arbitrum/ITokenGateway.sol index 96080858c..3b12e578e 100644 --- a/packages/contracts/contracts/arbitrum/ITokenGateway.sol +++ b/packages/contracts/contracts/arbitrum/ITokenGateway.sol @@ -23,7 +23,7 @@ * */ -pragma solidity ^0.7.6 || 0.8.26; +pragma solidity ^0.7.6 || 0.8.27; interface ITokenGateway { /// @notice event deprecated in favor of DepositInitiated and WithdrawalInitiated diff --git a/packages/contracts/contracts/curation/ICuration.sol b/packages/contracts/contracts/curation/ICuration.sol index 635b45a0c..fe2f0e929 100644 --- a/packages/contracts/contracts/curation/ICuration.sol +++ b/packages/contracts/contracts/curation/ICuration.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-or-later -pragma solidity ^0.7.6 || 0.8.26; +pragma solidity ^0.7.6 || 0.8.27; /** * @title Curation Interface diff --git a/packages/contracts/contracts/epochs/IEpochManager.sol b/packages/contracts/contracts/epochs/IEpochManager.sol index 23c55f15b..c65280d59 100644 --- a/packages/contracts/contracts/epochs/IEpochManager.sol +++ b/packages/contracts/contracts/epochs/IEpochManager.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-or-later -pragma solidity ^0.7.6 || 0.8.26; +pragma solidity ^0.7.6 || 0.8.27; interface IEpochManager { // -- Configuration -- diff --git a/packages/contracts/contracts/gateway/ICallhookReceiver.sol b/packages/contracts/contracts/gateway/ICallhookReceiver.sol index 0fc27cf23..8d003cb76 100644 --- a/packages/contracts/contracts/gateway/ICallhookReceiver.sol +++ b/packages/contracts/contracts/gateway/ICallhookReceiver.sol @@ -6,7 +6,7 @@ * be allowlisted by the governor, but also implement this interface that contains * the function that will actually be called by the L2GraphTokenGateway. */ -pragma solidity ^0.7.6 || 0.8.26; +pragma solidity ^0.7.6 || 0.8.27; interface ICallhookReceiver { /** diff --git a/packages/contracts/contracts/governance/Controller.sol b/packages/contracts/contracts/governance/Controller.sol index a24b96b4e..2b71fd885 100644 --- a/packages/contracts/contracts/governance/Controller.sol +++ b/packages/contracts/contracts/governance/Controller.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-or-later -pragma solidity ^0.7.6 || 0.8.26; +pragma solidity ^0.7.6 || 0.8.27; import { IController } from "./IController.sol"; import { IManaged } from "./IManaged.sol"; diff --git a/packages/contracts/contracts/governance/Governed.sol b/packages/contracts/contracts/governance/Governed.sol index c9cf940db..76a3247dd 100644 --- a/packages/contracts/contracts/governance/Governed.sol +++ b/packages/contracts/contracts/governance/Governed.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-or-later -pragma solidity ^0.7.6 || 0.8.26; +pragma solidity ^0.7.6 || 0.8.27; /** * @title Graph Governance contract diff --git a/packages/contracts/contracts/governance/IController.sol b/packages/contracts/contracts/governance/IController.sol index 093a0303a..6ab72010e 100644 --- a/packages/contracts/contracts/governance/IController.sol +++ b/packages/contracts/contracts/governance/IController.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-or-later -pragma solidity ^0.7.6 || 0.8.26; +pragma solidity ^0.7.6 || 0.8.27; interface IController { function getGovernor() external view returns (address); diff --git a/packages/contracts/contracts/governance/IManaged.sol b/packages/contracts/contracts/governance/IManaged.sol index 59f44dd9a..ff6625d81 100644 --- a/packages/contracts/contracts/governance/IManaged.sol +++ b/packages/contracts/contracts/governance/IManaged.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-or-later -pragma solidity ^0.7.6 || 0.8.26; +pragma solidity ^0.7.6 || 0.8.27; import { IController } from "./IController.sol"; diff --git a/packages/contracts/contracts/governance/Pausable.sol b/packages/contracts/contracts/governance/Pausable.sol index 260d658af..6c5d2fd2c 100644 --- a/packages/contracts/contracts/governance/Pausable.sol +++ b/packages/contracts/contracts/governance/Pausable.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-or-later -pragma solidity ^0.7.6 || 0.8.26; +pragma solidity ^0.7.6 || 0.8.27; abstract contract Pausable { /** diff --git a/packages/contracts/contracts/l2/staking/IL2StakingBase.sol b/packages/contracts/contracts/l2/staking/IL2StakingBase.sol index 8c0b145de..f5c33c2d0 100644 --- a/packages/contracts/contracts/l2/staking/IL2StakingBase.sol +++ b/packages/contracts/contracts/l2/staking/IL2StakingBase.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-or-later -pragma solidity ^0.7.6 || 0.8.26; +pragma solidity ^0.7.6 || 0.8.27; import { ICallhookReceiver } from "../../gateway/ICallhookReceiver.sol"; diff --git a/packages/contracts/contracts/l2/staking/IL2StakingTypes.sol b/packages/contracts/contracts/l2/staking/IL2StakingTypes.sol index 086f88e77..500694e89 100644 --- a/packages/contracts/contracts/l2/staking/IL2StakingTypes.sol +++ b/packages/contracts/contracts/l2/staking/IL2StakingTypes.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-or-later -pragma solidity ^0.7.6 || 0.8.26; +pragma solidity ^0.7.6 || 0.8.27; interface IL2StakingTypes { /// @dev Message codes for the L1 -> L2 bridge callhook diff --git a/packages/contracts/contracts/rewards/IRewardsIssuer.sol b/packages/contracts/contracts/rewards/IRewardsIssuer.sol index 4bcfa6ea0..705ce8db8 100644 --- a/packages/contracts/contracts/rewards/IRewardsIssuer.sol +++ b/packages/contracts/contracts/rewards/IRewardsIssuer.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-or-later -pragma solidity ^0.7.6 || 0.8.26; +pragma solidity ^0.7.6 || 0.8.27; interface IRewardsIssuer { /** diff --git a/packages/contracts/contracts/rewards/IRewardsManager.sol b/packages/contracts/contracts/rewards/IRewardsManager.sol index 4030ad2e5..3b6bf3ff6 100644 --- a/packages/contracts/contracts/rewards/IRewardsManager.sol +++ b/packages/contracts/contracts/rewards/IRewardsManager.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-or-later -pragma solidity ^0.7.6 || 0.8.26; +pragma solidity ^0.7.6 || 0.8.27; interface IRewardsManager { /** diff --git a/packages/contracts/contracts/rewards/RewardsManagerStorage.sol b/packages/contracts/contracts/rewards/RewardsManagerStorage.sol index c40ad38f4..ded325593 100644 --- a/packages/contracts/contracts/rewards/RewardsManagerStorage.sol +++ b/packages/contracts/contracts/rewards/RewardsManagerStorage.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-or-later -pragma solidity ^0.7.6 || 0.8.26; +pragma solidity ^0.7.6 || 0.8.27; import "./IRewardsManager.sol"; import "../governance/Managed.sol"; diff --git a/packages/contracts/contracts/token/IGraphToken.sol b/packages/contracts/contracts/token/IGraphToken.sol index f6f1c00f6..df3b7643f 100644 --- a/packages/contracts/contracts/token/IGraphToken.sol +++ b/packages/contracts/contracts/token/IGraphToken.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-or-later -pragma solidity ^0.7.6 || 0.8.26; +pragma solidity ^0.7.6 || 0.8.27; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; diff --git a/packages/contracts/contracts/upgrades/GraphProxy.sol b/packages/contracts/contracts/upgrades/GraphProxy.sol index cb52ab1dc..d6fbfac7f 100644 --- a/packages/contracts/contracts/upgrades/GraphProxy.sol +++ b/packages/contracts/contracts/upgrades/GraphProxy.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-or-later -pragma solidity ^0.7.6 || 0.8.26; +pragma solidity ^0.7.6 || 0.8.27; import { GraphProxyStorage } from "./GraphProxyStorage.sol"; diff --git a/packages/contracts/contracts/upgrades/GraphProxyAdmin.sol b/packages/contracts/contracts/upgrades/GraphProxyAdmin.sol index 55bbd2176..db8e9dcb3 100644 --- a/packages/contracts/contracts/upgrades/GraphProxyAdmin.sol +++ b/packages/contracts/contracts/upgrades/GraphProxyAdmin.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-or-later -pragma solidity ^0.7.6 || 0.8.26; +pragma solidity ^0.7.6 || 0.8.27; import { Governed } from "../governance/Governed.sol"; diff --git a/packages/contracts/contracts/upgrades/GraphProxyStorage.sol b/packages/contracts/contracts/upgrades/GraphProxyStorage.sol index cd076c118..7871e4996 100644 --- a/packages/contracts/contracts/upgrades/GraphProxyStorage.sol +++ b/packages/contracts/contracts/upgrades/GraphProxyStorage.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-or-later -pragma solidity ^0.7.6 || 0.8.26; +pragma solidity ^0.7.6 || 0.8.27; /** * @title Graph Proxy Storage diff --git a/packages/contracts/contracts/upgrades/GraphUpgradeable.sol b/packages/contracts/contracts/upgrades/GraphUpgradeable.sol index ffc47aa40..60dfbe888 100644 --- a/packages/contracts/contracts/upgrades/GraphUpgradeable.sol +++ b/packages/contracts/contracts/upgrades/GraphUpgradeable.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-or-later -pragma solidity ^0.7.6 || 0.8.26; +pragma solidity ^0.7.6 || 0.8.27; import { IGraphProxy } from "./IGraphProxy.sol"; diff --git a/packages/contracts/contracts/upgrades/IGraphProxy.sol b/packages/contracts/contracts/upgrades/IGraphProxy.sol index e81722e3f..4f501ed7c 100644 --- a/packages/contracts/contracts/upgrades/IGraphProxy.sol +++ b/packages/contracts/contracts/upgrades/IGraphProxy.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-or-later -pragma solidity ^0.7.6 || 0.8.26; +pragma solidity ^0.7.6 || 0.8.27; interface IGraphProxy { function admin() external returns (address); diff --git a/packages/contracts/contracts/utils/TokenUtils.sol b/packages/contracts/contracts/utils/TokenUtils.sol index a34059a1d..fb125613a 100644 --- a/packages/contracts/contracts/utils/TokenUtils.sol +++ b/packages/contracts/contracts/utils/TokenUtils.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-or-later -pragma solidity ^0.7.6 || 0.8.26; +pragma solidity ^0.7.6 || 0.8.27; import "../token/IGraphToken.sol"; diff --git a/packages/horizon/contracts/data-service/DataService.sol b/packages/horizon/contracts/data-service/DataService.sol index c87cf5e40..8a06ad4ea 100644 --- a/packages/horizon/contracts/data-service/DataService.sol +++ b/packages/horizon/contracts/data-service/DataService.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-3.0-or-later -pragma solidity 0.8.26; +pragma solidity 0.8.27; import { IDataService } from "./interfaces/IDataService.sol"; diff --git a/packages/horizon/contracts/data-service/DataServiceStorage.sol b/packages/horizon/contracts/data-service/DataServiceStorage.sol index 03b060515..a0271443c 100644 --- a/packages/horizon/contracts/data-service/DataServiceStorage.sol +++ b/packages/horizon/contracts/data-service/DataServiceStorage.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-3.0-or-later -pragma solidity 0.8.26; +pragma solidity 0.8.27; abstract contract DataServiceV1Storage { /// @dev Gap to allow adding variables in future upgrades diff --git a/packages/horizon/contracts/data-service/extensions/DataServiceFees.sol b/packages/horizon/contracts/data-service/extensions/DataServiceFees.sol index bcec6f828..e0ea587f4 100644 --- a/packages/horizon/contracts/data-service/extensions/DataServiceFees.sol +++ b/packages/horizon/contracts/data-service/extensions/DataServiceFees.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-3.0-or-later -pragma solidity 0.8.26; +pragma solidity 0.8.27; import { IDataServiceFees } from "../interfaces/IDataServiceFees.sol"; diff --git a/packages/horizon/contracts/data-service/extensions/DataServiceFeesStorage.sol b/packages/horizon/contracts/data-service/extensions/DataServiceFeesStorage.sol index 483b67b80..cb4f908dc 100644 --- a/packages/horizon/contracts/data-service/extensions/DataServiceFeesStorage.sol +++ b/packages/horizon/contracts/data-service/extensions/DataServiceFeesStorage.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-3.0-or-later -pragma solidity 0.8.26; +pragma solidity 0.8.27; import { IDataServiceFees } from "../interfaces/IDataServiceFees.sol"; diff --git a/packages/horizon/contracts/data-service/extensions/DataServicePausable.sol b/packages/horizon/contracts/data-service/extensions/DataServicePausable.sol index 404876dc6..4d88cb72e 100644 --- a/packages/horizon/contracts/data-service/extensions/DataServicePausable.sol +++ b/packages/horizon/contracts/data-service/extensions/DataServicePausable.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-3.0-or-later -pragma solidity 0.8.26; +pragma solidity 0.8.27; import { IDataServicePausable } from "../interfaces/IDataServicePausable.sol"; diff --git a/packages/horizon/contracts/data-service/extensions/DataServicePausableUpgradeable.sol b/packages/horizon/contracts/data-service/extensions/DataServicePausableUpgradeable.sol index 53003ebfc..52f27d9c4 100644 --- a/packages/horizon/contracts/data-service/extensions/DataServicePausableUpgradeable.sol +++ b/packages/horizon/contracts/data-service/extensions/DataServicePausableUpgradeable.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-3.0-or-later -pragma solidity 0.8.26; +pragma solidity 0.8.27; import { IDataServicePausable } from "../interfaces/IDataServicePausable.sol"; diff --git a/packages/horizon/contracts/data-service/extensions/DataServiceRescuable.sol b/packages/horizon/contracts/data-service/extensions/DataServiceRescuable.sol index 96fae4c26..081950b8d 100644 --- a/packages/horizon/contracts/data-service/extensions/DataServiceRescuable.sol +++ b/packages/horizon/contracts/data-service/extensions/DataServiceRescuable.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-3.0-or-later -pragma solidity 0.8.26; +pragma solidity 0.8.27; import { Address } from "@openzeppelin/contracts/utils/Address.sol"; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; diff --git a/packages/horizon/contracts/data-service/interfaces/IDataService.sol b/packages/horizon/contracts/data-service/interfaces/IDataService.sol index 258fc336c..b7e1028f0 100644 --- a/packages/horizon/contracts/data-service/interfaces/IDataService.sol +++ b/packages/horizon/contracts/data-service/interfaces/IDataService.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-3.0-or-later -pragma solidity 0.8.26; +pragma solidity 0.8.27; import { IGraphPayments } from "../../interfaces/IGraphPayments.sol"; diff --git a/packages/horizon/contracts/data-service/interfaces/IDataServiceFees.sol b/packages/horizon/contracts/data-service/interfaces/IDataServiceFees.sol index 5e84863e6..483f11274 100644 --- a/packages/horizon/contracts/data-service/interfaces/IDataServiceFees.sol +++ b/packages/horizon/contracts/data-service/interfaces/IDataServiceFees.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-3.0-or-later -pragma solidity 0.8.26; +pragma solidity 0.8.27; import { IDataService } from "./IDataService.sol"; diff --git a/packages/horizon/contracts/data-service/interfaces/IDataServicePausable.sol b/packages/horizon/contracts/data-service/interfaces/IDataServicePausable.sol index 04e931749..bd27ca848 100644 --- a/packages/horizon/contracts/data-service/interfaces/IDataServicePausable.sol +++ b/packages/horizon/contracts/data-service/interfaces/IDataServicePausable.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-3.0-or-later -pragma solidity 0.8.26; +pragma solidity 0.8.27; import { IDataService } from "./IDataService.sol"; diff --git a/packages/horizon/contracts/data-service/interfaces/IDataServiceRescuable.sol b/packages/horizon/contracts/data-service/interfaces/IDataServiceRescuable.sol index ba21f3019..811d3b92e 100644 --- a/packages/horizon/contracts/data-service/interfaces/IDataServiceRescuable.sol +++ b/packages/horizon/contracts/data-service/interfaces/IDataServiceRescuable.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-3.0-or-later -pragma solidity 0.8.26; +pragma solidity 0.8.27; import { IDataService } from "./IDataService.sol"; diff --git a/packages/horizon/contracts/data-service/libraries/ProvisionTracker.sol b/packages/horizon/contracts/data-service/libraries/ProvisionTracker.sol index 08ac970bb..fef392302 100644 --- a/packages/horizon/contracts/data-service/libraries/ProvisionTracker.sol +++ b/packages/horizon/contracts/data-service/libraries/ProvisionTracker.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-3.0-or-later -pragma solidity 0.8.26; +pragma solidity 0.8.27; import { IHorizonStaking } from "../../interfaces/IHorizonStaking.sol"; diff --git a/packages/horizon/contracts/data-service/utilities/ProvisionManager.sol b/packages/horizon/contracts/data-service/utilities/ProvisionManager.sol index ef7c9bcf1..d1cf94287 100644 --- a/packages/horizon/contracts/data-service/utilities/ProvisionManager.sol +++ b/packages/horizon/contracts/data-service/utilities/ProvisionManager.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-3.0-or-later -pragma solidity 0.8.26; +pragma solidity 0.8.27; import { IHorizonStaking } from "../../interfaces/IHorizonStaking.sol"; diff --git a/packages/horizon/contracts/data-service/utilities/ProvisionManagerStorage.sol b/packages/horizon/contracts/data-service/utilities/ProvisionManagerStorage.sol index 8649055db..0a6bed2be 100644 --- a/packages/horizon/contracts/data-service/utilities/ProvisionManagerStorage.sol +++ b/packages/horizon/contracts/data-service/utilities/ProvisionManagerStorage.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-3.0-or-later -pragma solidity 0.8.26; +pragma solidity 0.8.27; /** * @title Storage layout for the {ProvisionManager} helper contract. diff --git a/packages/horizon/contracts/interfaces/IGraphPayments.sol b/packages/horizon/contracts/interfaces/IGraphPayments.sol index ab89c94f8..f446d6f52 100644 --- a/packages/horizon/contracts/interfaces/IGraphPayments.sol +++ b/packages/horizon/contracts/interfaces/IGraphPayments.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-3.0-or-later -pragma solidity 0.8.26; +pragma solidity 0.8.27; /** * @title Interface for the {GraphPayments} contract diff --git a/packages/horizon/contracts/interfaces/IGraphProxyAdmin.sol b/packages/horizon/contracts/interfaces/IGraphProxyAdmin.sol index 6bc063057..de812fa87 100644 --- a/packages/horizon/contracts/interfaces/IGraphProxyAdmin.sol +++ b/packages/horizon/contracts/interfaces/IGraphProxyAdmin.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-or-later -pragma solidity 0.8.26; +pragma solidity 0.8.27; /** * @title IGraphProxyAdmin diff --git a/packages/horizon/contracts/interfaces/IHorizonStaking.sol b/packages/horizon/contracts/interfaces/IHorizonStaking.sol index 1cf1b6283..e38c3e451 100644 --- a/packages/horizon/contracts/interfaces/IHorizonStaking.sol +++ b/packages/horizon/contracts/interfaces/IHorizonStaking.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-or-later -pragma solidity 0.8.26; +pragma solidity 0.8.27; import { IHorizonStakingTypes } from "./internal/IHorizonStakingTypes.sol"; import { IHorizonStakingMain } from "./internal/IHorizonStakingMain.sol"; diff --git a/packages/horizon/contracts/interfaces/IPaymentsCollector.sol b/packages/horizon/contracts/interfaces/IPaymentsCollector.sol index 176f6284b..bcd67df0a 100644 --- a/packages/horizon/contracts/interfaces/IPaymentsCollector.sol +++ b/packages/horizon/contracts/interfaces/IPaymentsCollector.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-or-later -pragma solidity 0.8.26; +pragma solidity 0.8.27; import { IGraphPayments } from "./IGraphPayments.sol"; diff --git a/packages/horizon/contracts/interfaces/IPaymentsEscrow.sol b/packages/horizon/contracts/interfaces/IPaymentsEscrow.sol index 937ded194..4b98cf0a5 100644 --- a/packages/horizon/contracts/interfaces/IPaymentsEscrow.sol +++ b/packages/horizon/contracts/interfaces/IPaymentsEscrow.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-3.0-or-later -pragma solidity 0.8.26; +pragma solidity 0.8.27; import { IGraphPayments } from "./IGraphPayments.sol"; diff --git a/packages/horizon/contracts/interfaces/ITAPCollector.sol b/packages/horizon/contracts/interfaces/ITAPCollector.sol index 28561e2ce..e7b5bc4fd 100644 --- a/packages/horizon/contracts/interfaces/ITAPCollector.sol +++ b/packages/horizon/contracts/interfaces/ITAPCollector.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-3.0-or-later -pragma solidity 0.8.26; +pragma solidity 0.8.27; import { IPaymentsCollector } from "./IPaymentsCollector.sol"; diff --git a/packages/horizon/contracts/interfaces/internal/IHorizonStakingBase.sol b/packages/horizon/contracts/interfaces/internal/IHorizonStakingBase.sol index 522ddf44e..e221dc2cf 100644 --- a/packages/horizon/contracts/interfaces/internal/IHorizonStakingBase.sol +++ b/packages/horizon/contracts/interfaces/internal/IHorizonStakingBase.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-or-later -pragma solidity 0.8.26; +pragma solidity 0.8.27; import { IHorizonStakingTypes } from "./IHorizonStakingTypes.sol"; import { IGraphPayments } from "../IGraphPayments.sol"; diff --git a/packages/horizon/contracts/interfaces/internal/IHorizonStakingExtension.sol b/packages/horizon/contracts/interfaces/internal/IHorizonStakingExtension.sol index 2df5cd82a..6e29cb5c9 100644 --- a/packages/horizon/contracts/interfaces/internal/IHorizonStakingExtension.sol +++ b/packages/horizon/contracts/interfaces/internal/IHorizonStakingExtension.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-or-later -pragma solidity 0.8.26; +pragma solidity 0.8.27; import { IRewardsIssuer } from "@graphprotocol/contracts/contracts/rewards/IRewardsIssuer.sol"; import { IL2StakingBase } from "@graphprotocol/contracts/contracts/l2/staking/IL2StakingBase.sol"; diff --git a/packages/horizon/contracts/interfaces/internal/IHorizonStakingMain.sol b/packages/horizon/contracts/interfaces/internal/IHorizonStakingMain.sol index bbbfa07b6..418459d9f 100644 --- a/packages/horizon/contracts/interfaces/internal/IHorizonStakingMain.sol +++ b/packages/horizon/contracts/interfaces/internal/IHorizonStakingMain.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-or-later -pragma solidity 0.8.26; +pragma solidity 0.8.27; import { IGraphPayments } from "../../interfaces/IGraphPayments.sol"; diff --git a/packages/horizon/contracts/interfaces/internal/IHorizonStakingTypes.sol b/packages/horizon/contracts/interfaces/internal/IHorizonStakingTypes.sol index 5c2f3f5e7..eef8098e6 100644 --- a/packages/horizon/contracts/interfaces/internal/IHorizonStakingTypes.sol +++ b/packages/horizon/contracts/interfaces/internal/IHorizonStakingTypes.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-or-later -pragma solidity 0.8.26; +pragma solidity 0.8.27; /* solhint-disable var-name-mixedcase */ // TODO: create custom var-name-mixedcase diff --git a/packages/horizon/contracts/libraries/Denominations.sol b/packages/horizon/contracts/libraries/Denominations.sol index fe5cf2d05..675194b1e 100644 --- a/packages/horizon/contracts/libraries/Denominations.sol +++ b/packages/horizon/contracts/libraries/Denominations.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-3.0-or-later -pragma solidity 0.8.26; +pragma solidity 0.8.27; /** * @title Denominations library diff --git a/packages/horizon/contracts/libraries/LibFixedMath.sol b/packages/horizon/contracts/libraries/LibFixedMath.sol index 1a941ed11..f23329b5e 100644 --- a/packages/horizon/contracts/libraries/LibFixedMath.sol +++ b/packages/horizon/contracts/libraries/LibFixedMath.sol @@ -18,7 +18,7 @@ // SPDX-License-Identifier: Apache-2.0 -pragma solidity 0.8.26; +pragma solidity 0.8.27; // solhint-disable indent /// @dev Signed, fixed-point, 127-bit precision math library. diff --git a/packages/horizon/contracts/libraries/LinkedList.sol b/packages/horizon/contracts/libraries/LinkedList.sol index 13607e257..aa72b3fcf 100644 --- a/packages/horizon/contracts/libraries/LinkedList.sol +++ b/packages/horizon/contracts/libraries/LinkedList.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-or-later -pragma solidity 0.8.26; +pragma solidity 0.8.27; /** * @title LinkedList library diff --git a/packages/horizon/contracts/libraries/MathUtils.sol b/packages/horizon/contracts/libraries/MathUtils.sol index a5ad3f41a..1a5599fb6 100644 --- a/packages/horizon/contracts/libraries/MathUtils.sol +++ b/packages/horizon/contracts/libraries/MathUtils.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-or-later -pragma solidity 0.8.26; +pragma solidity 0.8.27; /** * @title MathUtils Library diff --git a/packages/horizon/contracts/libraries/PPMMath.sol b/packages/horizon/contracts/libraries/PPMMath.sol index b02230628..5bd636add 100644 --- a/packages/horizon/contracts/libraries/PPMMath.sol +++ b/packages/horizon/contracts/libraries/PPMMath.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-3.0-or-later -pragma solidity 0.8.26; +pragma solidity 0.8.27; /** * @title PPMMath library diff --git a/packages/horizon/contracts/libraries/UintRange.sol b/packages/horizon/contracts/libraries/UintRange.sol index 12fe10176..b2caf779c 100644 --- a/packages/horizon/contracts/libraries/UintRange.sol +++ b/packages/horizon/contracts/libraries/UintRange.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-3.0-or-later -pragma solidity 0.8.26; +pragma solidity 0.8.27; /** * @title UintRange library diff --git a/packages/horizon/contracts/mocks/ControllerMock.sol b/packages/horizon/contracts/mocks/ControllerMock.sol index 82673dca6..557b1eff6 100644 --- a/packages/horizon/contracts/mocks/ControllerMock.sol +++ b/packages/horizon/contracts/mocks/ControllerMock.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-or-later -pragma solidity 0.8.26; +pragma solidity 0.8.27; import { IController } from "@graphprotocol/contracts/contracts/governance/IController.sol"; import { IManaged } from "@graphprotocol/contracts/contracts/governance/IManaged.sol"; diff --git a/packages/horizon/contracts/mocks/CurationMock.sol b/packages/horizon/contracts/mocks/CurationMock.sol index 402a07e4c..996f971b1 100644 --- a/packages/horizon/contracts/mocks/CurationMock.sol +++ b/packages/horizon/contracts/mocks/CurationMock.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-or-later -pragma solidity 0.8.26; +pragma solidity 0.8.27; import { MockGRTToken } from "./MockGRTToken.sol"; diff --git a/packages/horizon/contracts/mocks/EpochManagerMock.sol b/packages/horizon/contracts/mocks/EpochManagerMock.sol index b76714e50..12f694a5e 100644 --- a/packages/horizon/contracts/mocks/EpochManagerMock.sol +++ b/packages/horizon/contracts/mocks/EpochManagerMock.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-or-later -pragma solidity 0.8.26; +pragma solidity 0.8.27; import { IEpochManager } from "@graphprotocol/contracts/contracts/epochs/IEpochManager.sol"; diff --git a/packages/horizon/contracts/mocks/MockGRTToken.sol b/packages/horizon/contracts/mocks/MockGRTToken.sol index 1d5649f29..235999ae5 100644 --- a/packages/horizon/contracts/mocks/MockGRTToken.sol +++ b/packages/horizon/contracts/mocks/MockGRTToken.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity 0.8.26; +pragma solidity 0.8.27; import { ERC20 } from "@openzeppelin/contracts/token/ERC20/ERC20.sol"; import { IGraphToken } from "@graphprotocol/contracts/contracts/token/IGraphToken.sol"; diff --git a/packages/horizon/contracts/mocks/RewardsManagerMock.sol b/packages/horizon/contracts/mocks/RewardsManagerMock.sol index 2388d99b6..272584ca4 100644 --- a/packages/horizon/contracts/mocks/RewardsManagerMock.sol +++ b/packages/horizon/contracts/mocks/RewardsManagerMock.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-or-later -pragma solidity 0.8.26; +pragma solidity 0.8.27; import { MockGRTToken } from "./MockGRTToken.sol"; diff --git a/packages/horizon/contracts/payments/GraphPayments.sol b/packages/horizon/contracts/payments/GraphPayments.sol index 4072c2616..b7cb34db7 100644 --- a/packages/horizon/contracts/payments/GraphPayments.sol +++ b/packages/horizon/contracts/payments/GraphPayments.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-3.0-or-later -pragma solidity 0.8.26; +pragma solidity 0.8.27; import { IGraphToken } from "@graphprotocol/contracts/contracts/token/IGraphToken.sol"; import { IGraphPayments } from "../interfaces/IGraphPayments.sol"; diff --git a/packages/horizon/contracts/payments/PaymentsEscrow.sol b/packages/horizon/contracts/payments/PaymentsEscrow.sol index 26f699fe1..5d0694346 100644 --- a/packages/horizon/contracts/payments/PaymentsEscrow.sol +++ b/packages/horizon/contracts/payments/PaymentsEscrow.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-3.0-or-later -pragma solidity 0.8.26; +pragma solidity 0.8.27; import { IGraphToken } from "@graphprotocol/contracts/contracts/token/IGraphToken.sol"; import { IGraphPayments } from "../interfaces/IGraphPayments.sol"; diff --git a/packages/horizon/contracts/payments/collectors/TAPCollector.sol b/packages/horizon/contracts/payments/collectors/TAPCollector.sol index e385667c7..f3d67e819 100644 --- a/packages/horizon/contracts/payments/collectors/TAPCollector.sol +++ b/packages/horizon/contracts/payments/collectors/TAPCollector.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-3.0-or-later -pragma solidity 0.8.26; +pragma solidity 0.8.27; import { IGraphPayments } from "../../interfaces/IGraphPayments.sol"; import { ITAPCollector } from "../../interfaces/ITAPCollector.sol"; diff --git a/packages/horizon/contracts/staking/HorizonStaking.sol b/packages/horizon/contracts/staking/HorizonStaking.sol index e6cc98315..74b2d8d09 100644 --- a/packages/horizon/contracts/staking/HorizonStaking.sol +++ b/packages/horizon/contracts/staking/HorizonStaking.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-or-later -pragma solidity 0.8.26; +pragma solidity 0.8.27; import { IGraphToken } from "@graphprotocol/contracts/contracts/token/IGraphToken.sol"; import { IHorizonStakingMain } from "../interfaces/internal/IHorizonStakingMain.sol"; diff --git a/packages/horizon/contracts/staking/HorizonStakingBase.sol b/packages/horizon/contracts/staking/HorizonStakingBase.sol index 722a2f061..b3e94c7ea 100644 --- a/packages/horizon/contracts/staking/HorizonStakingBase.sol +++ b/packages/horizon/contracts/staking/HorizonStakingBase.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-or-later -pragma solidity 0.8.26; +pragma solidity 0.8.27; import { IHorizonStakingTypes } from "../interfaces/internal/IHorizonStakingTypes.sol"; import { IHorizonStakingBase } from "../interfaces/internal/IHorizonStakingBase.sol"; diff --git a/packages/horizon/contracts/staking/HorizonStakingExtension.sol b/packages/horizon/contracts/staking/HorizonStakingExtension.sol index 1f6843d53..ba7eb3a5b 100644 --- a/packages/horizon/contracts/staking/HorizonStakingExtension.sol +++ b/packages/horizon/contracts/staking/HorizonStakingExtension.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-or-later -pragma solidity 0.8.26; +pragma solidity 0.8.27; import { ICuration } from "@graphprotocol/contracts/contracts/curation/ICuration.sol"; import { IGraphToken } from "@graphprotocol/contracts/contracts/token/IGraphToken.sol"; diff --git a/packages/horizon/contracts/staking/HorizonStakingStorage.sol b/packages/horizon/contracts/staking/HorizonStakingStorage.sol index 2934dfcd1..ff515962a 100644 --- a/packages/horizon/contracts/staking/HorizonStakingStorage.sol +++ b/packages/horizon/contracts/staking/HorizonStakingStorage.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-or-later -pragma solidity 0.8.26; +pragma solidity 0.8.27; import { IHorizonStakingExtension } from "../interfaces/internal/IHorizonStakingExtension.sol"; import { IHorizonStakingTypes } from "../interfaces/internal/IHorizonStakingTypes.sol"; diff --git a/packages/horizon/contracts/staking/libraries/ExponentialRebates.sol b/packages/horizon/contracts/staking/libraries/ExponentialRebates.sol index 1f7f0b3d2..cda9bf247 100644 --- a/packages/horizon/contracts/staking/libraries/ExponentialRebates.sol +++ b/packages/horizon/contracts/staking/libraries/ExponentialRebates.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-or-later -pragma solidity 0.8.26; +pragma solidity 0.8.27; import { LibFixedMath } from "../../libraries/LibFixedMath.sol"; diff --git a/packages/horizon/contracts/staking/utilities/Managed.sol b/packages/horizon/contracts/staking/utilities/Managed.sol index 4d8e77b4f..44d0ad81b 100644 --- a/packages/horizon/contracts/staking/utilities/Managed.sol +++ b/packages/horizon/contracts/staking/utilities/Managed.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-or-later -pragma solidity 0.8.26; +pragma solidity 0.8.27; import { GraphDirectory } from "../../utilities/GraphDirectory.sol"; diff --git a/packages/horizon/contracts/utilities/GraphDirectory.sol b/packages/horizon/contracts/utilities/GraphDirectory.sol index b63bcdeab..c24a7984d 100644 --- a/packages/horizon/contracts/utilities/GraphDirectory.sol +++ b/packages/horizon/contracts/utilities/GraphDirectory.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-or-later -pragma solidity 0.8.26; +pragma solidity 0.8.27; import { IGraphToken } from "@graphprotocol/contracts/contracts/token/IGraphToken.sol"; import { IHorizonStaking } from "../interfaces/IHorizonStaking.sol"; diff --git a/packages/horizon/foundry.toml b/packages/horizon/foundry.toml index 54fa4c22e..56cb8a0b6 100644 --- a/packages/horizon/foundry.toml +++ b/packages/horizon/foundry.toml @@ -5,14 +5,5 @@ libs = ['node_modules', 'lib'] test = 'test' cache_path = 'cache_forge' fs_permissions = [{ access = "read", path = "./"}] -via_ir = true optimizer = true -optimizer_runs = 200 - -# For testing we remove some optimizations to make it faster -[profile.test] -optimizer = false -optimizer_runs = 1 - -[profile.test.optimizer_details.yulDetails] -optimizer_steps = ':' \ No newline at end of file +optimizer_runs = 200 \ No newline at end of file diff --git a/packages/horizon/hardhat.config.ts b/packages/horizon/hardhat.config.ts index fa73c9643..de221c723 100644 --- a/packages/horizon/hardhat.config.ts +++ b/packages/horizon/hardhat.config.ts @@ -7,9 +7,8 @@ import { HardhatUserConfig } from 'hardhat/config' const config: HardhatUserConfig = { solidity: { - version: '0.8.26', + version: '0.8.27', settings: { - viaIR: true, optimizer: { enabled: true, runs: 200, diff --git a/packages/horizon/test/GraphBase.t.sol b/packages/horizon/test/GraphBase.t.sol index d86a58cf7..3c2375b8d 100644 --- a/packages/horizon/test/GraphBase.t.sol +++ b/packages/horizon/test/GraphBase.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity 0.8.26; +pragma solidity 0.8.27; import "forge-std/Test.sol"; @@ -24,7 +24,6 @@ import { Users } from "./utils/Users.sol"; import { Utils } from "./utils/Utils.sol"; abstract contract GraphBaseTest is IHorizonStakingTypes, Utils, Constants { - /* * VARIABLES */ diff --git a/packages/horizon/test/data-service/DataService.t.sol b/packages/horizon/test/data-service/DataService.t.sol index 2ba72cfd0..c535c6dea 100644 --- a/packages/horizon/test/data-service/DataService.t.sol +++ b/packages/horizon/test/data-service/DataService.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: UNLICENSED -pragma solidity 0.8.26; +pragma solidity 0.8.27; import { IHorizonStakingMain } from "../../contracts/interfaces/internal/IHorizonStakingMain.sol"; import { HorizonStakingSharedTest } from "../shared/horizon-staking/HorizonStakingShared.t.sol"; diff --git a/packages/horizon/test/data-service/DataServiceUpgradeable.t.sol b/packages/horizon/test/data-service/DataServiceUpgradeable.t.sol index c8721260f..be33173f8 100644 --- a/packages/horizon/test/data-service/DataServiceUpgradeable.t.sol +++ b/packages/horizon/test/data-service/DataServiceUpgradeable.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: UNLICENSED -pragma solidity 0.8.26; +pragma solidity 0.8.27; import { GraphBaseTest } from "../GraphBase.t.sol"; import { DataServiceBaseUpgradeable } from "./implementations/DataServiceBaseUpgradeable.sol"; diff --git a/packages/horizon/test/data-service/extensions/DataServiceFees.t.sol b/packages/horizon/test/data-service/extensions/DataServiceFees.t.sol index 4ab1406ae..f6f31d54c 100644 --- a/packages/horizon/test/data-service/extensions/DataServiceFees.t.sol +++ b/packages/horizon/test/data-service/extensions/DataServiceFees.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: UNLICENSED -pragma solidity 0.8.26; +pragma solidity 0.8.27; import { HorizonStakingSharedTest } from "../../shared/horizon-staking/HorizonStakingShared.t.sol"; import { DataServiceImpFees } from "../implementations/DataServiceImpFees.sol"; @@ -126,20 +126,27 @@ contract DataServiceFeesTest is HorizonStakingSharedTest { } // -- Assertion functions -- - + // use struct to avoid 'stack too deep' error + struct CalcValues_LockStake { + uint256 unlockTimestamp; + uint256 stakeToLock; + bytes32 predictedClaimId; + } function _assert_lockStake(address serviceProvider, uint256 tokens) private { // before state (bytes32 beforeHead, , uint256 beforeNonce, uint256 beforeCount) = dataService.claimsLists(serviceProvider); uint256 beforeLockedStake = dataService.feesProvisionTracker(serviceProvider); // calc - uint256 unlockTimestamp = block.timestamp + dataService.LOCK_DURATION(); - uint256 stakeToLock = tokens * dataService.STAKE_TO_FEES_RATIO(); - bytes32 predictedClaimId = keccak256(abi.encodePacked(address(dataService), serviceProvider, beforeNonce)); + CalcValues_LockStake memory calcValues = CalcValues_LockStake({ + unlockTimestamp: block.timestamp + dataService.LOCK_DURATION(), + stakeToLock: tokens * dataService.STAKE_TO_FEES_RATIO(), + predictedClaimId: keccak256(abi.encodePacked(address(dataService), serviceProvider, beforeNonce)) + }); // it should emit a an event vm.expectEmit(); - emit IDataServiceFees.StakeClaimLocked(serviceProvider, predictedClaimId, stakeToLock, unlockTimestamp); + emit IDataServiceFees.StakeClaimLocked(serviceProvider, calcValues.predictedClaimId, calcValues.stakeToLock, calcValues.unlockTimestamp); dataService.lockStake(serviceProvider, tokens); // after state @@ -149,24 +156,30 @@ contract DataServiceFeesTest is HorizonStakingSharedTest { ); // it should lock the tokens - assertEq(beforeLockedStake + stakeToLock, afterLockedStake); + assertEq(beforeLockedStake + calcValues.stakeToLock, afterLockedStake); // it should create a stake claim (uint256 claimTokens, uint256 createdAt, uint256 releaseAt, bytes32 nextClaim) = dataService.claims( - predictedClaimId + calcValues.predictedClaimId ); - assertEq(claimTokens, stakeToLock); + assertEq(claimTokens, calcValues.stakeToLock); assertEq(createdAt, block.timestamp); - assertEq(releaseAt, unlockTimestamp); + assertEq(releaseAt, calcValues.unlockTimestamp); assertEq(nextClaim, bytes32(0)); // it should update the list assertEq(afterCount, beforeCount + 1); assertEq(afterNonce, beforeNonce + 1); - assertEq(afterHead, beforeCount == 0 ? predictedClaimId : beforeHead); - assertEq(afterTail, predictedClaimId); + assertEq(afterHead, beforeCount == 0 ? calcValues.predictedClaimId : beforeHead); + assertEq(afterTail, calcValues.predictedClaimId); } + // use struct to avoid 'stack too deep' error + struct CalcValues_ReleaseStake { + uint256 claimsCount; + uint256 tokensReleased; + bytes32 head; + } function _assert_releaseStake(address serviceProvider, uint256 n) private { // before state (bytes32 beforeHead, bytes32 beforeTail, uint256 beforeNonce, uint256 beforeCount) = dataService.claimsLists( @@ -177,23 +190,25 @@ contract DataServiceFeesTest is HorizonStakingSharedTest { // calc and set events vm.expectEmit(); - uint256 claimsCount = 0; - uint256 tokensReleased = 0; - bytes32 head = beforeHead; - while (head != bytes32(0) && (claimsCount < n || n == 0)) { - (uint256 claimTokens, , uint256 releaseAt, bytes32 nextClaim) = dataService.claims(head); + CalcValues_ReleaseStake memory calcValues = CalcValues_ReleaseStake({ + claimsCount: 0, + tokensReleased: 0, + head: beforeHead + }); + while (calcValues.head != bytes32(0) && (calcValues.claimsCount < n || n == 0)) { + (uint256 claimTokens, , uint256 releaseAt, bytes32 nextClaim) = dataService.claims(calcValues.head); if (releaseAt > block.timestamp) { break; } - emit IDataServiceFees.StakeClaimReleased(serviceProvider, head, claimTokens, releaseAt); - head = nextClaim; - tokensReleased += claimTokens; - claimsCount++; + emit IDataServiceFees.StakeClaimReleased(serviceProvider, calcValues.head, claimTokens, releaseAt); + calcValues.head = nextClaim; + calcValues.tokensReleased += claimTokens; + calcValues.claimsCount++; } // it should emit a an event - emit IDataServiceFees.StakeClaimsReleased(serviceProvider, claimsCount, tokensReleased); + emit IDataServiceFees.StakeClaimsReleased(serviceProvider, calcValues.claimsCount, calcValues.tokensReleased); dataService.releaseStake(n); // after state @@ -203,17 +218,17 @@ contract DataServiceFeesTest is HorizonStakingSharedTest { uint256 afterLockedStake = dataService.feesProvisionTracker(serviceProvider); // it should release the tokens - assertEq(beforeLockedStake - tokensReleased, afterLockedStake); + assertEq(beforeLockedStake - calcValues.tokensReleased, afterLockedStake); // it should remove the processed claims from the list - assertEq(afterCount, beforeCount - claimsCount); + assertEq(afterCount, beforeCount - calcValues.claimsCount); assertEq(afterNonce, beforeNonce); - if (claimsCount != 0) { + if (calcValues.claimsCount != 0) { assertNotEq(afterHead, beforeHead); } else { assertEq(afterHead, beforeHead); } - assertEq(afterHead, head); - assertEq(afterTail, claimsCount == beforeCount ? bytes32(0) : beforeTail); + assertEq(afterHead, calcValues.head); + assertEq(afterTail, calcValues.claimsCount == beforeCount ? bytes32(0) : beforeTail); } } diff --git a/packages/horizon/test/data-service/extensions/DataServicePausable.t.sol b/packages/horizon/test/data-service/extensions/DataServicePausable.t.sol index c71cace11..111838fe4 100644 --- a/packages/horizon/test/data-service/extensions/DataServicePausable.t.sol +++ b/packages/horizon/test/data-service/extensions/DataServicePausable.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: UNLICENSED -pragma solidity 0.8.26; +pragma solidity 0.8.27; import { HorizonStakingSharedTest } from "../../shared/horizon-staking/HorizonStakingShared.t.sol"; import { DataServiceImpPausable } from "../implementations/DataServiceImpPausable.sol"; diff --git a/packages/horizon/test/data-service/extensions/DataServicePausableUpgradeable.t.sol b/packages/horizon/test/data-service/extensions/DataServicePausableUpgradeable.t.sol index 9f4a8822b..6e58810c1 100644 --- a/packages/horizon/test/data-service/extensions/DataServicePausableUpgradeable.t.sol +++ b/packages/horizon/test/data-service/extensions/DataServicePausableUpgradeable.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: UNLICENSED -pragma solidity 0.8.26; +pragma solidity 0.8.27; import { GraphBaseTest } from "../../GraphBase.t.sol"; import { DataServiceImpPausableUpgradeable } from "../implementations/DataServiceImpPausableUpgradeable.sol"; diff --git a/packages/horizon/test/data-service/implementations/DataServiceBase.sol b/packages/horizon/test/data-service/implementations/DataServiceBase.sol index b8171e649..d98dd2857 100644 --- a/packages/horizon/test/data-service/implementations/DataServiceBase.sol +++ b/packages/horizon/test/data-service/implementations/DataServiceBase.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-3.0-or-later -pragma solidity 0.8.26; +pragma solidity 0.8.27; import { DataService } from "../../../contracts/data-service/DataService.sol"; import { IGraphPayments } from "./../../../contracts/interfaces/IGraphPayments.sol"; diff --git a/packages/horizon/test/data-service/implementations/DataServiceBaseUpgradeable.sol b/packages/horizon/test/data-service/implementations/DataServiceBaseUpgradeable.sol index fbe2fe211..31309c524 100644 --- a/packages/horizon/test/data-service/implementations/DataServiceBaseUpgradeable.sol +++ b/packages/horizon/test/data-service/implementations/DataServiceBaseUpgradeable.sol @@ -1,11 +1,11 @@ // SPDX-License-Identifier: GPL-3.0-or-later -pragma solidity 0.8.26; +pragma solidity 0.8.27; import { DataService } from "../../../contracts/data-service/DataService.sol"; import { IGraphPayments } from "./../../../contracts/interfaces/IGraphPayments.sol"; contract DataServiceBaseUpgradeable is DataService { - constructor(address controller) DataService(controller) { + constructor(address controller_) DataService(controller_) { _disableInitializers(); } diff --git a/packages/horizon/test/data-service/implementations/DataServiceImpFees.sol b/packages/horizon/test/data-service/implementations/DataServiceImpFees.sol index ee071c47d..efabda6ff 100644 --- a/packages/horizon/test/data-service/implementations/DataServiceImpFees.sol +++ b/packages/horizon/test/data-service/implementations/DataServiceImpFees.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-3.0-or-later -pragma solidity 0.8.26; +pragma solidity 0.8.27; import { DataService } from "../../../contracts/data-service/DataService.sol"; import { DataServiceFees } from "../../../contracts/data-service/extensions/DataServiceFees.sol"; @@ -25,6 +25,7 @@ contract DataServiceImpFees is DataServiceFees { uint256 amount = abi.decode(data, (uint256)); _releaseStake(serviceProvider, 0); _lockStake(serviceProvider, amount * STAKE_TO_FEES_RATIO, block.timestamp + LOCK_DURATION); + return amount; } function lockStake(address serviceProvider, uint256 amount) external { diff --git a/packages/horizon/test/data-service/implementations/DataServiceImpPausable.sol b/packages/horizon/test/data-service/implementations/DataServiceImpPausable.sol index 5d49f8873..0ca990ab1 100644 --- a/packages/horizon/test/data-service/implementations/DataServiceImpPausable.sol +++ b/packages/horizon/test/data-service/implementations/DataServiceImpPausable.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-3.0-or-later -pragma solidity 0.8.26; +pragma solidity 0.8.27; import { DataService } from "../../../contracts/data-service/DataService.sol"; import { DataServicePausable } from "../../../contracts/data-service/extensions/DataServicePausable.sol"; diff --git a/packages/horizon/test/data-service/implementations/DataServiceImpPausableUpgradeable.sol b/packages/horizon/test/data-service/implementations/DataServiceImpPausableUpgradeable.sol index 5b55d0866..39b2bb26b 100644 --- a/packages/horizon/test/data-service/implementations/DataServiceImpPausableUpgradeable.sol +++ b/packages/horizon/test/data-service/implementations/DataServiceImpPausableUpgradeable.sol @@ -1,12 +1,12 @@ // SPDX-License-Identifier: GPL-3.0-or-later -pragma solidity 0.8.26; +pragma solidity 0.8.27; import { DataService } from "../../../contracts/data-service/DataService.sol"; import { DataServicePausableUpgradeable } from "../../../contracts/data-service/extensions/DataServicePausableUpgradeable.sol"; import { IGraphPayments } from "./../../../contracts/interfaces/IGraphPayments.sol"; contract DataServiceImpPausableUpgradeable is DataServicePausableUpgradeable { - constructor(address controller) DataService(controller) { + constructor(address controller_) DataService(controller_) { _disableInitializers(); } diff --git a/packages/horizon/test/data-service/implementations/DataServiceOverride.sol b/packages/horizon/test/data-service/implementations/DataServiceOverride.sol index 838be68a5..c5d50ca74 100644 --- a/packages/horizon/test/data-service/implementations/DataServiceOverride.sol +++ b/packages/horizon/test/data-service/implementations/DataServiceOverride.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-3.0-or-later -pragma solidity 0.8.26; +pragma solidity 0.8.27; import { DataServiceBase } from "./DataServiceBase.sol"; diff --git a/packages/horizon/test/data-service/libraries/ProvisionTracker.t.sol b/packages/horizon/test/data-service/libraries/ProvisionTracker.t.sol index a7ec2f614..af147fdd6 100644 --- a/packages/horizon/test/data-service/libraries/ProvisionTracker.t.sol +++ b/packages/horizon/test/data-service/libraries/ProvisionTracker.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: UNLICENSED -pragma solidity 0.8.26; +pragma solidity 0.8.27; import { HorizonStakingSharedTest } from "../../shared/horizon-staking/HorizonStakingShared.t.sol"; import { ProvisionTrackerImplementation } from "./ProvisionTrackerImplementation.sol"; diff --git a/packages/horizon/test/data-service/libraries/ProvisionTrackerImplementation.sol b/packages/horizon/test/data-service/libraries/ProvisionTrackerImplementation.sol index 0093fba72..5c9cf4a6a 100644 --- a/packages/horizon/test/data-service/libraries/ProvisionTrackerImplementation.sol +++ b/packages/horizon/test/data-service/libraries/ProvisionTrackerImplementation.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: UNLICENSED -pragma solidity 0.8.26; +pragma solidity 0.8.27; import { ProvisionTracker } from "../../../contracts/data-service/libraries/ProvisionTracker.sol"; diff --git a/packages/horizon/test/escrow/GraphEscrow.t.sol b/packages/horizon/test/escrow/GraphEscrow.t.sol index a510f57bf..2421ea80c 100644 --- a/packages/horizon/test/escrow/GraphEscrow.t.sol +++ b/packages/horizon/test/escrow/GraphEscrow.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity 0.8.26; +pragma solidity 0.8.27; import "forge-std/Test.sol"; diff --git a/packages/horizon/test/escrow/collect.t.sol b/packages/horizon/test/escrow/collect.t.sol index 1ba403a23..67efcc6e7 100644 --- a/packages/horizon/test/escrow/collect.t.sol +++ b/packages/horizon/test/escrow/collect.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity 0.8.26; +pragma solidity 0.8.27; import "forge-std/Test.sol"; diff --git a/packages/horizon/test/escrow/collector.t.sol b/packages/horizon/test/escrow/collector.t.sol index 5023c38ce..3e5b71bc0 100644 --- a/packages/horizon/test/escrow/collector.t.sol +++ b/packages/horizon/test/escrow/collector.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity 0.8.26; +pragma solidity 0.8.27; import "forge-std/Test.sol"; diff --git a/packages/horizon/test/escrow/deposit.t.sol b/packages/horizon/test/escrow/deposit.t.sol index 79b7c3616..3ce341a1a 100644 --- a/packages/horizon/test/escrow/deposit.t.sol +++ b/packages/horizon/test/escrow/deposit.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity 0.8.26; +pragma solidity 0.8.27; import "forge-std/Test.sol"; diff --git a/packages/horizon/test/escrow/paused.t.sol b/packages/horizon/test/escrow/paused.t.sol index 2be37a61b..f6b65aa2b 100644 --- a/packages/horizon/test/escrow/paused.t.sol +++ b/packages/horizon/test/escrow/paused.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity 0.8.26; +pragma solidity 0.8.27; import "forge-std/Test.sol"; diff --git a/packages/horizon/test/escrow/thaw.t.sol b/packages/horizon/test/escrow/thaw.t.sol index 35f501ff3..36808602c 100644 --- a/packages/horizon/test/escrow/thaw.t.sol +++ b/packages/horizon/test/escrow/thaw.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity 0.8.26; +pragma solidity 0.8.27; import "forge-std/Test.sol"; diff --git a/packages/horizon/test/escrow/withdraw.t.sol b/packages/horizon/test/escrow/withdraw.t.sol index f7ffdd1c6..0e5670c7a 100644 --- a/packages/horizon/test/escrow/withdraw.t.sol +++ b/packages/horizon/test/escrow/withdraw.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity 0.8.26; +pragma solidity 0.8.27; import "forge-std/Test.sol"; diff --git a/packages/horizon/test/libraries/LinkedList.t.sol b/packages/horizon/test/libraries/LinkedList.t.sol index 5150b6116..1850cdb47 100644 --- a/packages/horizon/test/libraries/LinkedList.t.sol +++ b/packages/horizon/test/libraries/LinkedList.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: UNLICENSED -pragma solidity 0.8.26; +pragma solidity 0.8.27; import "forge-std/console.sol"; import {Test} from "forge-std/Test.sol"; diff --git a/packages/horizon/test/libraries/ListImplementation.sol b/packages/horizon/test/libraries/ListImplementation.sol index 9c8bbfb60..fda762c6d 100644 --- a/packages/horizon/test/libraries/ListImplementation.sol +++ b/packages/horizon/test/libraries/ListImplementation.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: UNLICENSED -pragma solidity 0.8.26; +pragma solidity 0.8.27; import { LinkedList } from "../../contracts/libraries/LinkedList.sol"; @@ -34,7 +34,7 @@ contract ListImplementation { return items[_id].next; } - function _processItemAddition(bytes32 _id, bytes memory _acc) internal returns (bool, bytes memory) { + function _processItemAddition(bytes32 _id, bytes memory _acc) internal view returns (bool, bytes memory) { uint256 sum = abi.decode(_acc, (uint256)); sum += items[_id].data; return (false, abi.encode(sum)); // dont break, do delete diff --git a/packages/horizon/test/payments/GraphPayments.t.sol b/packages/horizon/test/payments/GraphPayments.t.sol index 8fa23015b..62e582c26 100644 --- a/packages/horizon/test/payments/GraphPayments.t.sol +++ b/packages/horizon/test/payments/GraphPayments.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity 0.8.26; +pragma solidity 0.8.27; import "forge-std/Test.sol"; diff --git a/packages/horizon/test/shared/horizon-staking/HorizonStakingShared.t.sol b/packages/horizon/test/shared/horizon-staking/HorizonStakingShared.t.sol index 2f81bb0d1..d9f300979 100644 --- a/packages/horizon/test/shared/horizon-staking/HorizonStakingShared.t.sol +++ b/packages/horizon/test/shared/horizon-staking/HorizonStakingShared.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity 0.8.26; +pragma solidity 0.8.27; import "forge-std/Test.sol"; @@ -472,22 +472,15 @@ abstract contract HorizonStakingSharedTest is GraphBaseTest { serviceProvider ); - ( - uint256 calcTokensThawed, - uint256 calcTokensThawing, - uint256 calcSharesThawing, - ThawRequest[] memory calcThawRequestsFulfilledList, - bytes32[] memory calcThawRequestsFulfilledListIds, - uint256[] memory calcThawRequestsFulfilledListTokens - ) = calcThawRequestData(serviceProvider, verifier, serviceProvider, nThawRequests, false); + CalcValues_ThawRequestData memory calcValues = calcThawRequestData(serviceProvider, verifier, serviceProvider, nThawRequests, false); // deprovision - for (uint i = 0; i < calcThawRequestsFulfilledList.length; i++) { - ThawRequest memory thawRequest = calcThawRequestsFulfilledList[i]; + for (uint i = 0; i < calcValues.thawRequestsFulfilledList.length; i++) { + ThawRequest memory thawRequest = calcValues.thawRequestsFulfilledList[i]; vm.expectEmit(address(staking)); emit IHorizonStakingMain.ThawRequestFulfilled( - calcThawRequestsFulfilledListIds[i], - calcThawRequestsFulfilledListTokens[i], + calcValues.thawRequestsFulfilledListIds[i], + calcValues.thawRequestsFulfilledListTokens[i], thawRequest.shares, thawRequest.thawingUntil ); @@ -497,11 +490,11 @@ abstract contract HorizonStakingSharedTest is GraphBaseTest { serviceProvider, verifier, serviceProvider, - calcThawRequestsFulfilledList.length, - calcTokensThawed + calcValues.thawRequestsFulfilledList.length, + calcValues.tokensThawed ); vm.expectEmit(address(staking)); - emit IHorizonStakingMain.TokensDeprovisioned(serviceProvider, verifier, calcTokensThawed); + emit IHorizonStakingMain.TokensDeprovisioned(serviceProvider, verifier, calcValues.tokensThawed); staking.deprovision(serviceProvider, verifier, nThawRequests); // after @@ -514,48 +507,54 @@ abstract contract HorizonStakingSharedTest is GraphBaseTest { ); // assert - assertEq(afterProvision.tokens, beforeProvision.tokens - calcTokensThawed); - assertEq(afterProvision.tokensThawing, calcTokensThawing); - assertEq(afterProvision.sharesThawing, calcSharesThawing); + assertEq(afterProvision.tokens, beforeProvision.tokens - calcValues.tokensThawed); + assertEq(afterProvision.tokensThawing, calcValues.tokensThawing); + assertEq(afterProvision.sharesThawing, calcValues.sharesThawing); assertEq(afterProvision.maxVerifierCut, beforeProvision.maxVerifierCut); assertEq(afterProvision.thawingPeriod, beforeProvision.thawingPeriod); assertEq(afterProvision.createdAt, beforeProvision.createdAt); assertEq(afterProvision.maxVerifierCutPending, beforeProvision.maxVerifierCutPending); assertEq(afterProvision.thawingPeriodPending, beforeProvision.thawingPeriodPending); assertEq(afterServiceProvider.tokensStaked, beforeServiceProvider.tokensStaked); - assertEq(afterServiceProvider.tokensProvisioned, beforeServiceProvider.tokensProvisioned - calcTokensThawed); + assertEq(afterServiceProvider.tokensProvisioned, beforeServiceProvider.tokensProvisioned - calcValues.tokensThawed); assertEq(afterServiceProvider.__DEPRECATED_tokensAllocated, beforeServiceProvider.__DEPRECATED_tokensAllocated); assertEq(afterServiceProvider.__DEPRECATED_tokensLocked, beforeServiceProvider.__DEPRECATED_tokensLocked); assertEq( afterServiceProvider.__DEPRECATED_tokensLockedUntil, beforeServiceProvider.__DEPRECATED_tokensLockedUntil ); - for (uint i = 0; i < calcThawRequestsFulfilledListIds.length; i++) { - ThawRequest memory thawRequest = staking.getThawRequest(calcThawRequestsFulfilledListIds[i]); + for (uint i = 0; i < calcValues.thawRequestsFulfilledListIds.length; i++) { + ThawRequest memory thawRequest = staking.getThawRequest(calcValues.thawRequestsFulfilledListIds[i]); assertEq(thawRequest.shares, 0); assertEq(thawRequest.thawingUntil, 0); assertEq(thawRequest.next, bytes32(0)); } - if (calcThawRequestsFulfilledList.length == 0) { + if (calcValues.thawRequestsFulfilledList.length == 0) { assertEq(afterThawRequestList.head, beforeThawRequestList.head); } else { assertEq( afterThawRequestList.head, - calcThawRequestsFulfilledList.length == beforeThawRequestList.count + calcValues.thawRequestsFulfilledList.length == beforeThawRequestList.count ? bytes32(0) - : calcThawRequestsFulfilledList[calcThawRequestsFulfilledList.length - 1].next + : calcValues.thawRequestsFulfilledList[calcValues.thawRequestsFulfilledList.length - 1].next ); } assertEq( afterThawRequestList.tail, - calcThawRequestsFulfilledList.length == beforeThawRequestList.count + calcValues.thawRequestsFulfilledList.length == beforeThawRequestList.count ? bytes32(0) : beforeThawRequestList.tail ); - assertEq(afterThawRequestList.count, beforeThawRequestList.count - calcThawRequestsFulfilledList.length); + assertEq(afterThawRequestList.count, beforeThawRequestList.count - calcValues.thawRequestsFulfilledList.length); assertEq(afterThawRequestList.nonce, beforeThawRequestList.nonce); } + struct BeforeValues_Reprovision { + Provision provision; + Provision provisionNewVerifier; + ServiceProviderInternal serviceProvider; + LinkedList.List thawRequestList; + } function _reprovision( address serviceProvider, address verifier, @@ -564,31 +563,23 @@ abstract contract HorizonStakingSharedTest is GraphBaseTest { uint256 nThawRequests ) internal { // before - Provision memory beforeProvision = staking.getProvision(serviceProvider, verifier); - Provision memory beforeProvisionNewVerifier = staking.getProvision(serviceProvider, newVerifier); - ServiceProviderInternal memory beforeServiceProvider = _getStorage_ServiceProviderInternal(serviceProvider); - LinkedList.List memory beforeThawRequestList = staking.getThawRequestList( - serviceProvider, - verifier, - serviceProvider - ); + BeforeValues_Reprovision memory beforeValues = BeforeValues_Reprovision({ + provision: staking.getProvision(serviceProvider, verifier), + provisionNewVerifier: staking.getProvision(serviceProvider, newVerifier), + serviceProvider: _getStorage_ServiceProviderInternal(serviceProvider), + thawRequestList: staking.getThawRequestList(serviceProvider, verifier, serviceProvider) + }); - ( - uint256 calcTokensThawed, - uint256 calcTokensThawing, - uint256 calcSharesThawing, - ThawRequest[] memory calcThawRequestsFulfilledList, - bytes32[] memory calcThawRequestsFulfilledListIds, - uint256[] memory calcThawRequestsFulfilledListTokens - ) = calcThawRequestData(serviceProvider, verifier, serviceProvider, nThawRequests, false); + // calc + CalcValues_ThawRequestData memory calcValues = calcThawRequestData(serviceProvider, verifier, serviceProvider, nThawRequests, false); // reprovision - for (uint i = 0; i < calcThawRequestsFulfilledList.length; i++) { - ThawRequest memory thawRequest = calcThawRequestsFulfilledList[i]; + for (uint i = 0; i < calcValues.thawRequestsFulfilledList.length; i++) { + ThawRequest memory thawRequest = calcValues.thawRequestsFulfilledList[i]; vm.expectEmit(address(staking)); emit IHorizonStakingMain.ThawRequestFulfilled( - calcThawRequestsFulfilledListIds[i], - calcThawRequestsFulfilledListTokens[i], + calcValues.thawRequestsFulfilledListIds[i], + calcValues.thawRequestsFulfilledListTokens[i], thawRequest.shares, thawRequest.thawingUntil ); @@ -598,11 +589,11 @@ abstract contract HorizonStakingSharedTest is GraphBaseTest { serviceProvider, verifier, serviceProvider, - calcThawRequestsFulfilledList.length, - calcTokensThawed + calcValues.thawRequestsFulfilledList.length, + calcValues.tokensThawed ); vm.expectEmit(address(staking)); - emit IHorizonStakingMain.TokensDeprovisioned(serviceProvider, verifier, calcTokensThawed); + emit IHorizonStakingMain.TokensDeprovisioned(serviceProvider, verifier, calcValues.tokensThawed); vm.expectEmit(); emit IHorizonStakingMain.ProvisionIncreased(serviceProvider, newVerifier, tokens); staking.reprovision(serviceProvider, verifier, newVerifier, tokens, nThawRequests); @@ -618,63 +609,63 @@ abstract contract HorizonStakingSharedTest is GraphBaseTest { ); // assert: provision old verifier - assertEq(afterProvision.tokens, beforeProvision.tokens - calcTokensThawed); - assertEq(afterProvision.tokensThawing, calcTokensThawing); - assertEq(afterProvision.sharesThawing, calcSharesThawing); - assertEq(afterProvision.maxVerifierCut, beforeProvision.maxVerifierCut); - assertEq(afterProvision.thawingPeriod, beforeProvision.thawingPeriod); - assertEq(afterProvision.createdAt, beforeProvision.createdAt); - assertEq(afterProvision.maxVerifierCutPending, beforeProvision.maxVerifierCutPending); - assertEq(afterProvision.thawingPeriodPending, beforeProvision.thawingPeriodPending); + assertEq(afterProvision.tokens, beforeValues.provision.tokens - calcValues.tokensThawed); + assertEq(afterProvision.tokensThawing, calcValues.tokensThawing); + assertEq(afterProvision.sharesThawing, calcValues.sharesThawing); + assertEq(afterProvision.maxVerifierCut, beforeValues.provision.maxVerifierCut); + assertEq(afterProvision.thawingPeriod, beforeValues.provision.thawingPeriod); + assertEq(afterProvision.createdAt, beforeValues.provision.createdAt); + assertEq(afterProvision.maxVerifierCutPending, beforeValues.provision.maxVerifierCutPending); + assertEq(afterProvision.thawingPeriodPending, beforeValues.provision.thawingPeriodPending); // assert: provision new verifier - assertEq(afterProvisionNewVerifier.tokens, beforeProvisionNewVerifier.tokens + tokens); - assertEq(afterProvisionNewVerifier.tokensThawing, beforeProvisionNewVerifier.tokensThawing); - assertEq(afterProvisionNewVerifier.sharesThawing, beforeProvisionNewVerifier.sharesThawing); - assertEq(afterProvisionNewVerifier.maxVerifierCut, beforeProvisionNewVerifier.maxVerifierCut); - assertEq(afterProvisionNewVerifier.thawingPeriod, beforeProvisionNewVerifier.thawingPeriod); - assertEq(afterProvisionNewVerifier.createdAt, beforeProvisionNewVerifier.createdAt); - assertEq(afterProvisionNewVerifier.maxVerifierCutPending, beforeProvisionNewVerifier.maxVerifierCutPending); - assertEq(afterProvisionNewVerifier.thawingPeriodPending, beforeProvisionNewVerifier.thawingPeriodPending); + assertEq(afterProvisionNewVerifier.tokens, beforeValues.provisionNewVerifier.tokens + tokens); + assertEq(afterProvisionNewVerifier.tokensThawing, beforeValues.provisionNewVerifier.tokensThawing); + assertEq(afterProvisionNewVerifier.sharesThawing, beforeValues.provisionNewVerifier.sharesThawing); + assertEq(afterProvisionNewVerifier.maxVerifierCut, beforeValues.provisionNewVerifier.maxVerifierCut); + assertEq(afterProvisionNewVerifier.thawingPeriod, beforeValues.provisionNewVerifier.thawingPeriod); + assertEq(afterProvisionNewVerifier.createdAt, beforeValues.provisionNewVerifier.createdAt); + assertEq(afterProvisionNewVerifier.maxVerifierCutPending, beforeValues.provisionNewVerifier.maxVerifierCutPending); + assertEq(afterProvisionNewVerifier.thawingPeriodPending, beforeValues.provisionNewVerifier.thawingPeriodPending); // assert: service provider - assertEq(afterServiceProvider.tokensStaked, beforeServiceProvider.tokensStaked); + assertEq(afterServiceProvider.tokensStaked, beforeValues.serviceProvider.tokensStaked); assertEq( afterServiceProvider.tokensProvisioned, - beforeServiceProvider.tokensProvisioned + tokens - calcTokensThawed + beforeValues.serviceProvider.tokensProvisioned + tokens - calcValues.tokensThawed ); - assertEq(afterServiceProvider.__DEPRECATED_tokensAllocated, beforeServiceProvider.__DEPRECATED_tokensAllocated); - assertEq(afterServiceProvider.__DEPRECATED_tokensLocked, beforeServiceProvider.__DEPRECATED_tokensLocked); + assertEq(afterServiceProvider.__DEPRECATED_tokensAllocated, beforeValues.serviceProvider.__DEPRECATED_tokensAllocated); + assertEq(afterServiceProvider.__DEPRECATED_tokensLocked, beforeValues.serviceProvider.__DEPRECATED_tokensLocked); assertEq( afterServiceProvider.__DEPRECATED_tokensLockedUntil, - beforeServiceProvider.__DEPRECATED_tokensLockedUntil + beforeValues.serviceProvider.__DEPRECATED_tokensLockedUntil ); // assert: thaw request list old verifier - for (uint i = 0; i < calcThawRequestsFulfilledListIds.length; i++) { - ThawRequest memory thawRequest = staking.getThawRequest(calcThawRequestsFulfilledListIds[i]); + for (uint i = 0; i < calcValues.thawRequestsFulfilledListIds.length; i++) { + ThawRequest memory thawRequest = staking.getThawRequest(calcValues.thawRequestsFulfilledListIds[i]); assertEq(thawRequest.shares, 0); assertEq(thawRequest.thawingUntil, 0); assertEq(thawRequest.next, bytes32(0)); } - if (calcThawRequestsFulfilledList.length == 0) { - assertEq(afterThawRequestList.head, beforeThawRequestList.head); + if (calcValues.thawRequestsFulfilledList.length == 0) { + assertEq(afterThawRequestList.head, beforeValues.thawRequestList.head); } else { assertEq( afterThawRequestList.head, - calcThawRequestsFulfilledList.length == beforeThawRequestList.count + calcValues.thawRequestsFulfilledList.length == beforeValues.thawRequestList.count ? bytes32(0) - : calcThawRequestsFulfilledList[calcThawRequestsFulfilledList.length - 1].next + : calcValues.thawRequestsFulfilledList[calcValues.thawRequestsFulfilledList.length - 1].next ); } assertEq( afterThawRequestList.tail, - calcThawRequestsFulfilledList.length == beforeThawRequestList.count + calcValues.thawRequestsFulfilledList.length == beforeValues.thawRequestList.count ? bytes32(0) - : beforeThawRequestList.tail + : beforeValues.thawRequestList.tail ); - assertEq(afterThawRequestList.count, beforeThawRequestList.count - calcThawRequestsFulfilledList.length); - assertEq(afterThawRequestList.nonce, beforeThawRequestList.nonce); + assertEq(afterThawRequestList.count, beforeValues.thawRequestList.count - calcValues.thawRequestsFulfilledList.length); + assertEq(afterThawRequestList.nonce, beforeValues.thawRequestList.nonce); } function _setProvisionParameters( @@ -870,32 +861,40 @@ abstract contract HorizonStakingSharedTest is GraphBaseTest { __undelegate(serviceProvider, subgraphDataServiceLegacyAddress, shares, true); } + struct BeforeValues_Undelegate { + DelegationPoolInternalTest pool; + DelegationInternal delegation; + LinkedList.List thawRequestList; + uint256 delegatedTokens; + } + struct CalcValues_Undelegate { + uint256 tokens; + uint256 thawingShares; + uint64 thawingUntil; + bytes32 thawRequestId; + } + function __undelegate(address serviceProvider, address verifier, uint256 shares, bool legacy) private { (, address delegator, ) = vm.readCallers(); // before - DelegationPoolInternalTest memory beforePool = _getStorage_DelegationPoolInternal( - serviceProvider, - verifier, - legacy - ); - DelegationInternal memory beforeDelegation = _getStorage_Delegation( - serviceProvider, - verifier, - delegator, - legacy - ); - LinkedList.List memory beforeThawRequestList = staking.getThawRequestList(serviceProvider, verifier, delegator); - uint256 beforeDelegatedTokens = staking.getDelegatedTokensAvailable(serviceProvider, verifier); - - uint256 calcTokens = ((beforePool.tokens - beforePool.tokensThawing) * shares) / beforePool.shares; - uint256 calcThawingShares = beforePool.tokensThawing == 0 - ? calcTokens - : (beforePool.sharesThawing * calcTokens) / beforePool.tokensThawing; - uint64 calcThawingUntil = staking.getProvision(serviceProvider, verifier).thawingPeriod + + BeforeValues_Undelegate memory beforeValues; + beforeValues.pool = _getStorage_DelegationPoolInternal(serviceProvider, verifier, legacy); + beforeValues.delegation = _getStorage_Delegation(serviceProvider, verifier, delegator, legacy); + beforeValues.thawRequestList = staking.getThawRequestList(serviceProvider, verifier, delegator); + beforeValues.delegatedTokens = staking.getDelegatedTokensAvailable(serviceProvider, verifier); + + // calc + CalcValues_Undelegate memory calcValues; + calcValues.tokens = ((beforeValues.pool.tokens - beforeValues.pool.tokensThawing) * shares) / beforeValues.pool.shares; + calcValues.thawingShares = beforeValues.pool.tokensThawing == 0 + ? calcValues.tokens + : (beforeValues.pool.sharesThawing * calcValues.tokens) / beforeValues.pool.tokensThawing; + calcValues.thawingUntil = + staking.getProvision(serviceProvider, verifier).thawingPeriod + uint64(block.timestamp); - bytes32 calcThawRequestId = keccak256( - abi.encodePacked(serviceProvider, verifier, delegator, beforeThawRequestList.nonce) + calcValues.thawRequestId = keccak256( + abi.encodePacked(serviceProvider, verifier, delegator, beforeValues.thawRequestList.nonce) ); // undelegate @@ -904,12 +903,12 @@ abstract contract HorizonStakingSharedTest is GraphBaseTest { serviceProvider, verifier, delegator, - calcThawingShares, - calcThawingUntil, - calcThawRequestId + calcValues.thawingShares, + calcValues.thawingUntil, + calcValues.thawRequestId ); vm.expectEmit(); - emit IHorizonStakingMain.TokensUndelegated(serviceProvider, verifier, delegator, calcTokens); + emit IHorizonStakingMain.TokensUndelegated(serviceProvider, verifier, delegator, calcValues.tokens); if (legacy) { staking.undelegate(serviceProvider, shares); } else { @@ -929,22 +928,22 @@ abstract contract HorizonStakingSharedTest is GraphBaseTest { legacy ); LinkedList.List memory afterThawRequestList = staking.getThawRequestList(serviceProvider, verifier, delegator); - ThawRequest memory afterThawRequest = staking.getThawRequest(calcThawRequestId); + ThawRequest memory afterThawRequest = staking.getThawRequest(calcValues.thawRequestId); uint256 afterDelegatedTokens = staking.getDelegatedTokensAvailable(serviceProvider, verifier); // assertions - assertEq(beforePool.shares, afterPool.shares + shares); - assertEq(beforePool.tokens, afterPool.tokens); - assertEq(beforePool.tokensThawing + calcTokens, afterPool.tokensThawing); - assertEq(beforePool.sharesThawing + calcThawingShares, afterPool.sharesThawing); - assertEq(beforeDelegation.shares - shares, afterDelegation.shares); - assertEq(afterThawRequest.shares, calcThawingShares); - assertEq(afterThawRequest.thawingUntil, calcThawingUntil); + assertEq(beforeValues.pool.shares, afterPool.shares + shares); + assertEq(beforeValues.pool.tokens, afterPool.tokens); + assertEq(beforeValues.pool.tokensThawing + calcValues.tokens, afterPool.tokensThawing); + assertEq(beforeValues.pool.sharesThawing + calcValues.thawingShares, afterPool.sharesThawing); + assertEq(beforeValues.delegation.shares - shares, afterDelegation.shares); + assertEq(afterThawRequest.shares, calcValues.thawingShares); + assertEq(afterThawRequest.thawingUntil, calcValues.thawingUntil); assertEq(afterThawRequest.next, bytes32(0)); - assertEq(calcThawRequestId, afterThawRequestList.tail); - assertEq(beforeThawRequestList.nonce + 1, afterThawRequestList.nonce); - assertEq(beforeThawRequestList.count + 1, afterThawRequestList.count); - assertEq(afterDelegatedTokens + calcTokens, beforeDelegatedTokens); + assertEq(calcValues.thawRequestId, afterThawRequestList.tail); + assertEq(beforeValues.thawRequestList.nonce + 1, afterThawRequestList.nonce); + assertEq(beforeValues.thawRequestList.count + 1, afterThawRequestList.count); + assertEq(afterDelegatedTokens + calcValues.tokens, beforeValues.delegatedTokens); } function _withdrawDelegated( @@ -968,6 +967,22 @@ abstract contract HorizonStakingSharedTest is GraphBaseTest { __withdrawDelegated(serviceProvider, subgraphDataServiceLegacyAddress, newServiceProvider, 0, 0, true); } + struct BeforeValues_WithdrawDelegated { + DelegationPoolInternalTest pool; + DelegationPoolInternalTest newPool; + DelegationInternal newDelegation; + LinkedList.List thawRequestList; + uint256 senderBalance; + uint256 stakingBalance; + } + struct AfterValues_WithdrawDelegated { + DelegationPoolInternalTest pool; + DelegationPoolInternalTest newPool; + DelegationInternal newDelegation; + LinkedList.List thawRequestList; + uint256 senderBalance; + uint256 stakingBalance; + } function __withdrawDelegated( address _serviceProvider, address _verifier, @@ -981,46 +996,29 @@ abstract contract HorizonStakingSharedTest is GraphBaseTest { bool reDelegate = _newServiceProvider != address(0); // before - DelegationPoolInternalTest memory beforeDelegationPool = _getStorage_DelegationPoolInternal( + BeforeValues_WithdrawDelegated memory beforeValues; + beforeValues.pool = _getStorage_DelegationPoolInternal(_serviceProvider, _verifier, legacy); + beforeValues.newPool = _getStorage_DelegationPoolInternal(_newServiceProvider, _verifier, legacy); + beforeValues.newDelegation = _getStorage_Delegation(_serviceProvider, _verifier, msgSender, legacy); + beforeValues.thawRequestList = staking.getThawRequestList(_serviceProvider, _verifier, msgSender); + beforeValues.senderBalance = token.balanceOf(msgSender); + beforeValues.stakingBalance = token.balanceOf(address(staking)); + + CalcValues_ThawRequestData memory calcValues = calcThawRequestData( _serviceProvider, _verifier, - legacy - ); - DelegationPoolInternalTest memory beforeNewDelegationPool = _getStorage_DelegationPoolInternal( - _newServiceProvider, - _verifier, - legacy - ); - DelegationInternal memory beforeNewDelegation = _getStorage_Delegation( - _newServiceProvider, - _verifier, msgSender, - legacy - ); - LinkedList.List memory beforeThawRequestList = staking.getThawRequestList( - _serviceProvider, - _verifier, - msgSender + _nThawRequests, + true ); - uint256 beforeSenderBalance = token.balanceOf(msgSender); - uint256 beforeStakingBalance = token.balanceOf(address(staking)); - - ( - uint256 calcTokensThawed, - uint256 calcTokensThawing, - uint256 calcSharesThawing, - ThawRequest[] memory calcThawRequestsFulfilledList, - bytes32[] memory calcThawRequestsFulfilledListIds, - uint256[] memory calcThawRequestsFulfilledListTokens - ) = calcThawRequestData(_serviceProvider, _verifier, msgSender, _nThawRequests, true); // withdrawDelegated - for (uint i = 0; i < calcThawRequestsFulfilledList.length; i++) { - ThawRequest memory thawRequest = calcThawRequestsFulfilledList[i]; + for (uint i = 0; i < calcValues.thawRequestsFulfilledList.length; i++) { + ThawRequest memory thawRequest = calcValues.thawRequestsFulfilledList[i]; vm.expectEmit(address(staking)); emit IHorizonStakingMain.ThawRequestFulfilled( - calcThawRequestsFulfilledListIds[i], - calcThawRequestsFulfilledListTokens[i], + calcValues.thawRequestsFulfilledListIds[i], + calcValues.thawRequestsFulfilledListTokens[i], thawRequest.shares, thawRequest.thawingUntil ); @@ -1030,19 +1028,19 @@ abstract contract HorizonStakingSharedTest is GraphBaseTest { _serviceProvider, _verifier, msgSender, - calcThawRequestsFulfilledList.length, - calcTokensThawed + calcValues.thawRequestsFulfilledList.length, + calcValues.tokensThawed ); - if (calcTokensThawed != 0) { + if (calcValues.tokensThawed != 0) { vm.expectEmit(); if (reDelegate) { - emit IHorizonStakingMain.TokensDelegated(_newServiceProvider, _verifier, msgSender, calcTokensThawed); + emit IHorizonStakingMain.TokensDelegated(_newServiceProvider, _verifier, msgSender, calcValues.tokensThawed); } else { - emit Transfer(address(staking), msgSender, calcTokensThawed); + emit Transfer(address(staking), msgSender, calcValues.tokensThawed); } } vm.expectEmit(); - emit IHorizonStakingMain.DelegatedTokensWithdrawn(_serviceProvider, _verifier, msgSender, calcTokensThawed); + emit IHorizonStakingMain.DelegatedTokensWithdrawn(_serviceProvider, _verifier, msgSender, calcValues.tokensThawed); staking.withdrawDelegated( _serviceProvider, _verifier, @@ -1052,86 +1050,70 @@ abstract contract HorizonStakingSharedTest is GraphBaseTest { ); // after - DelegationPoolInternalTest memory afterDelegationPool = _getStorage_DelegationPoolInternal( - _serviceProvider, - _verifier, - legacy - ); - DelegationPoolInternalTest memory afterNewDelegationPool = _getStorage_DelegationPoolInternal( - _newServiceProvider, - _verifier, - legacy - ); - DelegationInternal memory afterNewDelegation = _getStorage_Delegation( - _newServiceProvider, - _verifier, - msgSender, - legacy - ); - LinkedList.List memory afterThawRequestList = staking.getThawRequestList( - _serviceProvider, - _verifier, - msgSender - ); - uint256 afterSenderBalance = token.balanceOf(msgSender); - uint256 afterStakingBalance = token.balanceOf(address(staking)); + AfterValues_WithdrawDelegated memory afterValues; + afterValues.pool = _getStorage_DelegationPoolInternal(_serviceProvider, _verifier, legacy); + afterValues.newPool = _getStorage_DelegationPoolInternal(_newServiceProvider, _verifier, legacy); + afterValues.newDelegation = _getStorage_Delegation(_newServiceProvider, _verifier, msgSender, legacy); + afterValues.thawRequestList = staking.getThawRequestList(_serviceProvider, _verifier, msgSender); + afterValues.senderBalance = token.balanceOf(msgSender); + afterValues.stakingBalance = token.balanceOf(address(staking)); // assert - assertEq(afterDelegationPool.tokens, beforeDelegationPool.tokens - calcTokensThawed); - assertEq(afterDelegationPool.shares, beforeDelegationPool.shares); - assertEq(afterDelegationPool.tokensThawing, calcTokensThawing); - assertEq(afterDelegationPool.sharesThawing, calcSharesThawing); + assertEq(afterValues.pool.tokens, beforeValues.pool.tokens - calcValues.tokensThawed); + assertEq(afterValues.pool.shares, beforeValues.pool.shares); + assertEq(afterValues.pool.tokensThawing, calcValues.tokensThawing); + assertEq(afterValues.pool.sharesThawing, calcValues.sharesThawing); - for (uint i = 0; i < calcThawRequestsFulfilledListIds.length; i++) { - ThawRequest memory thawRequest = staking.getThawRequest(calcThawRequestsFulfilledListIds[i]); + for (uint i = 0; i < calcValues.thawRequestsFulfilledListIds.length; i++) { + ThawRequest memory thawRequest = staking.getThawRequest(calcValues.thawRequestsFulfilledListIds[i]); assertEq(thawRequest.shares, 0); assertEq(thawRequest.thawingUntil, 0); assertEq(thawRequest.next, bytes32(0)); } - if (calcThawRequestsFulfilledList.length == 0) { - assertEq(afterThawRequestList.head, beforeThawRequestList.head); + if (calcValues.thawRequestsFulfilledList.length == 0) { + assertEq(afterValues.thawRequestList.head, beforeValues.thawRequestList.head); } else { assertEq( - afterThawRequestList.head, - calcThawRequestsFulfilledList.length == beforeThawRequestList.count + afterValues.thawRequestList.head, + calcValues.thawRequestsFulfilledList.length == beforeValues.thawRequestList.count ? bytes32(0) - : calcThawRequestsFulfilledList[calcThawRequestsFulfilledList.length - 1].next + : calcValues.thawRequestsFulfilledList[calcValues.thawRequestsFulfilledList.length - 1].next ); } assertEq( - afterThawRequestList.tail, - calcThawRequestsFulfilledList.length == beforeThawRequestList.count + afterValues.thawRequestList.tail, + calcValues.thawRequestsFulfilledList.length == beforeValues.thawRequestList.count ? bytes32(0) - : beforeThawRequestList.tail + : beforeValues.thawRequestList.tail ); - assertEq(afterThawRequestList.count, beforeThawRequestList.count - calcThawRequestsFulfilledList.length); - assertEq(afterThawRequestList.nonce, beforeThawRequestList.nonce); + assertEq(afterValues.thawRequestList.count, beforeValues.thawRequestList.count - calcValues.thawRequestsFulfilledList.length); + assertEq(afterValues.thawRequestList.nonce, beforeValues.thawRequestList.nonce); if (reDelegate) { - uint256 calcShares = (afterNewDelegationPool.tokens == 0 || - afterNewDelegationPool.tokens == afterNewDelegationPool.tokensThawing) - ? calcTokensThawed - : ((calcTokensThawed * afterNewDelegationPool.shares) / - (afterNewDelegationPool.tokens - afterNewDelegationPool.tokensThawing)); - uint256 deltaShares = afterNewDelegation.shares - beforeNewDelegation.shares; - - assertEq(afterNewDelegationPool.tokens, beforeNewDelegationPool.tokens + calcTokensThawed); - assertEq(afterNewDelegationPool.shares, beforeNewDelegationPool.shares + calcShares); - assertEq(afterNewDelegationPool.tokensThawing, beforeNewDelegationPool.tokensThawing); - assertEq(afterNewDelegationPool.sharesThawing, beforeNewDelegationPool.sharesThawing); - assertEq(afterNewDelegation.shares, beforeNewDelegation.shares + calcShares); - assertEq(afterNewDelegation.__DEPRECATED_tokensLocked, beforeNewDelegation.__DEPRECATED_tokensLocked); + uint256 calcShares = (afterValues.newPool.tokens == 0 || + afterValues.newPool.tokens == afterValues.newPool.tokensThawing) + ? calcValues.tokensThawed + : ((calcValues.tokensThawed * afterValues.newPool.shares) / + (afterValues.newPool.tokens - afterValues.newPool.tokensThawing)); + uint256 deltaShares = afterValues.newDelegation.shares - beforeValues.newDelegation.shares; + + assertEq(afterValues.newPool.tokens, beforeValues.newPool.tokens + calcValues.tokensThawed); + assertEq(afterValues.newPool.shares, beforeValues.newPool.shares + calcShares); + assertEq(afterValues.newPool.tokensThawing, beforeValues.newPool.tokensThawing); + assertEq(afterValues.newPool.sharesThawing, beforeValues.newPool.sharesThawing); + assertEq(afterValues.newDelegation.shares, beforeValues.newDelegation.shares + calcShares); + assertEq(afterValues.newDelegation.__DEPRECATED_tokensLocked, beforeValues.newDelegation.__DEPRECATED_tokensLocked); assertEq( - afterNewDelegation.__DEPRECATED_tokensLockedUntil, - beforeNewDelegation.__DEPRECATED_tokensLockedUntil + afterValues.newDelegation.__DEPRECATED_tokensLockedUntil, + beforeValues.newDelegation.__DEPRECATED_tokensLockedUntil ); assertGe(deltaShares, _minSharesForNewProvider); assertEq(calcShares, deltaShares); - assertEq(afterSenderBalance - beforeSenderBalance, 0); - assertEq(beforeStakingBalance - afterStakingBalance, 0); + assertEq(afterValues.senderBalance - beforeValues.senderBalance, 0); + assertEq(beforeValues.stakingBalance - afterValues.stakingBalance, 0); } else { - assertEq(beforeStakingBalance - afterStakingBalance, calcTokensThawed); - assertEq(afterSenderBalance - beforeSenderBalance, calcTokensThawed); + assertEq(beforeValues.stakingBalance - afterValues.stakingBalance, calcValues.tokensThawed); + assertEq(afterValues.senderBalance - beforeValues.senderBalance, calcValues.tokensThawed); } } @@ -1259,31 +1241,44 @@ abstract contract HorizonStakingSharedTest is GraphBaseTest { assertEq(afterCounterpartStakingAddress, counterpartStakingAddress); } + struct BeforeValues_ReceiveDelegation { + DelegationPoolInternalTest pool; + DelegationInternal delegation; + uint256 delegatedTokens; + uint256 stakingBalance; + uint256 delegatorBalance; + } function _onTokenTransfer_ReceiveDelegation(address from, uint256 tokens, bytes memory data) internal { - (, bytes memory fnData) = abi.decode(data, (uint8, bytes)); - (address serviceProvider, address delegator) = abi.decode(fnData, (address, address)); - bytes32 slotPoolTokens = bytes32(uint256(keccak256(abi.encode(serviceProvider, 20))) + 2); + address serviceProvider; + address delegator; + { + (, bytes memory fnData) = abi.decode(data, (uint8, bytes)); + (serviceProvider, delegator) = abi.decode(fnData, (address, address)); + } // before - DelegationPool memory beforePool = staking.getDelegationPool(serviceProvider, subgraphDataServiceLegacyAddress); - Delegation memory beforeDelegation = staking.getDelegation( + BeforeValues_ReceiveDelegation memory beforeValues; + beforeValues.pool = _getStorage_DelegationPoolInternal(serviceProvider, subgraphDataServiceLegacyAddress, true); + beforeValues.delegation = _getStorage_Delegation( serviceProvider, subgraphDataServiceLegacyAddress, - delegator + delegator, + true ); - uint256 beforeStoragePoolTokens = uint256(vm.load(address(staking), slotPoolTokens)); - uint256 beforeDelegatedTokens = staking.getDelegatedTokensAvailable( + beforeValues.stakingBalance = token.balanceOf(address(staking)); + beforeValues.delegatorBalance = token.balanceOf(delegator); + beforeValues.delegatedTokens = staking.getDelegatedTokensAvailable( serviceProvider, subgraphDataServiceLegacyAddress ); - uint256 beforeDelegatorBalance = token.balanceOf(delegator); - uint256 beforeStakingBalance = token.balanceOf(address(staking)); - uint256 calcShares = (beforePool.tokens == 0 || beforePool.tokens == beforePool.tokensThawing) + + // calc + uint256 calcShares = (beforeValues.pool.tokens == 0 || beforeValues.pool.tokens == beforeValues.pool.tokensThawing) ? tokens - : ((tokens * beforePool.shares) / (beforePool.tokens - beforePool.tokensThawing)); + : ((tokens * beforeValues.pool.shares) / (beforeValues.pool.tokens - beforeValues.pool.tokensThawing)); bool earlyExit = (calcShares == 0 || tokens < 1 ether) || - (beforePool.tokens == 0 && (beforePool.shares != 0 || beforePool.sharesThawing != 0)); + (beforeValues.pool.tokens == 0 && (beforeValues.pool.shares != 0 || beforeValues.pool.sharesThawing != 0)); // onTokenTransfer if (earlyExit) { @@ -1298,13 +1293,13 @@ abstract contract HorizonStakingSharedTest is GraphBaseTest { staking.onTokenTransfer(from, tokens, data); // after - DelegationPool memory afterPool = staking.getDelegationPool(serviceProvider, subgraphDataServiceLegacyAddress); - Delegation memory afterDelegation = staking.getDelegation( + DelegationPoolInternalTest memory afterPool = _getStorage_DelegationPoolInternal(serviceProvider, subgraphDataServiceLegacyAddress, true); + DelegationInternal memory afterDelegation = _getStorage_Delegation( serviceProvider, subgraphDataServiceLegacyAddress, - delegator + delegator, + true ); - uint256 afterStoragePoolTokens = uint256(vm.load(address(staking), slotPoolTokens)); uint256 afterDelegatedTokens = staking.getDelegatedTokensAvailable( serviceProvider, subgraphDataServiceLegacyAddress @@ -1312,33 +1307,41 @@ abstract contract HorizonStakingSharedTest is GraphBaseTest { uint256 afterDelegatorBalance = token.balanceOf(delegator); uint256 afterStakingBalance = token.balanceOf(address(staking)); - uint256 deltaShares = afterDelegation.shares - beforeDelegation.shares; - // assertions if (earlyExit) { - assertEq(beforePool.tokens, afterPool.tokens); - assertEq(beforePool.shares, afterPool.shares); - assertEq(beforePool.tokensThawing, afterPool.tokensThawing); - assertEq(beforePool.sharesThawing, afterPool.sharesThawing); - assertEq(0, deltaShares); - assertEq(beforeDelegatedTokens, afterDelegatedTokens); - assertEq(beforeStoragePoolTokens, afterStoragePoolTokens); - assertEq(beforeDelegatorBalance + tokens, afterDelegatorBalance); - assertEq(beforeStakingBalance - tokens, afterStakingBalance); + assertEq(beforeValues.pool.tokens, afterPool.tokens); + assertEq(beforeValues.pool.shares, afterPool.shares); + assertEq(beforeValues.pool.tokensThawing, afterPool.tokensThawing); + assertEq(beforeValues.pool.sharesThawing, afterPool.sharesThawing); + assertEq(0, afterDelegation.shares - beforeValues.delegation.shares); + assertEq(beforeValues.delegatedTokens, afterDelegatedTokens); + assertEq(beforeValues.delegatorBalance + tokens, afterDelegatorBalance); + assertEq(beforeValues.stakingBalance - tokens, afterStakingBalance); } else { - assertEq(beforePool.tokens + tokens, afterPool.tokens); - assertEq(beforePool.shares + calcShares, afterPool.shares); - assertEq(beforePool.tokensThawing, afterPool.tokensThawing); - assertEq(beforePool.sharesThawing, afterPool.sharesThawing); - assertEq(calcShares, deltaShares); - assertEq(beforeDelegatedTokens + tokens, afterDelegatedTokens); - // Ensure correct slot is being updated, pools are stored in different storage locations for legacy subgraph data service - assertEq(beforeStoragePoolTokens + tokens, afterStoragePoolTokens); - assertEq(beforeDelegatorBalance, afterDelegatorBalance); - assertEq(beforeStakingBalance, afterStakingBalance); + assertEq(beforeValues.pool.tokens + tokens, afterPool.tokens); + assertEq(beforeValues.pool.shares + calcShares, afterPool.shares); + assertEq(beforeValues.pool.tokensThawing, afterPool.tokensThawing); + assertEq(beforeValues.pool.sharesThawing, afterPool.sharesThawing); + assertEq(calcShares, afterDelegation.shares - beforeValues.delegation.shares); + assertEq(beforeValues.delegatedTokens + tokens, afterDelegatedTokens); + assertEq(beforeValues.delegatorBalance, afterDelegatorBalance); + assertEq(beforeValues.stakingBalance, afterStakingBalance); } } + struct BeforeValues_Slash { + Provision provision; + DelegationPoolInternalTest pool; + ServiceProviderInternal serviceProvider; + uint256 stakingBalance; + uint256 verifierBalance; + } + struct CalcValues_Slash { + uint256 tokensToSlash; + uint256 providerTokensSlashed; + uint256 delegationTokensSlashed; + } + function _slash(address serviceProvider, address verifier, uint256 tokens, uint256 verifierCutAmount) internal { bool isDelegationSlashingEnabled = staking.isDelegationSlashingEnabled(); @@ -1347,45 +1350,51 @@ abstract contract HorizonStakingSharedTest is GraphBaseTest { bool legacy = verifier == subgraphDataServiceLegacyAddress; // before - Provision memory beforeProvision = staking.getProvision(serviceProvider, verifier); - DelegationPoolInternalTest memory beforePool = _getStorage_DelegationPoolInternal( - serviceProvider, - verifier, - legacy - ); - ServiceProviderInternal memory beforeServiceProvider = _getStorage_ServiceProviderInternal(serviceProvider); - uint256 beforeStakingBalance = token.balanceOf(address(staking)); - uint256 beforeVerifierBalance = token.balanceOf(verifier); + BeforeValues_Slash memory before; + before.provision = staking.getProvision(serviceProvider, verifier); + before.pool = _getStorage_DelegationPoolInternal(serviceProvider, verifier, legacy); + before.serviceProvider = _getStorage_ServiceProviderInternal(serviceProvider); + before.stakingBalance = token.balanceOf(address(staking)); + before.verifierBalance = token.balanceOf(verifier); // Calculate expected tokens after slashing - uint256 tokensToSlash = MathUtils.min(tokens, beforeProvision.tokens + beforePool.tokens); - uint256 providerTokensSlashed = MathUtils.min(beforeProvision.tokens, tokensToSlash); - uint256 delegationTokensSlashed = tokensToSlash - providerTokensSlashed; + CalcValues_Slash memory calcValues; + calcValues.tokensToSlash = MathUtils.min(tokens, before.provision.tokens + before.pool.tokens); + calcValues.providerTokensSlashed = MathUtils.min(before.provision.tokens, calcValues.tokensToSlash); + calcValues.delegationTokensSlashed = calcValues.tokensToSlash - calcValues.providerTokensSlashed; - if (tokensToSlash > 0) { + if (calcValues.tokensToSlash > 0) { if (verifierCutAmount > 0) { vm.expectEmit(address(token)); emit Transfer(address(staking), verifier, verifierCutAmount); vm.expectEmit(address(staking)); emit IHorizonStakingMain.VerifierTokensSent(serviceProvider, verifier, verifier, verifierCutAmount); } - if (providerTokensSlashed - verifierCutAmount > 0) { + if (calcValues.providerTokensSlashed - verifierCutAmount > 0) { vm.expectEmit(address(token)); - emit Transfer(address(staking), address(0), providerTokensSlashed - verifierCutAmount); + emit Transfer(address(staking), address(0), calcValues.providerTokensSlashed - verifierCutAmount); } vm.expectEmit(address(staking)); - emit IHorizonStakingMain.ProvisionSlashed(serviceProvider, verifier, providerTokensSlashed); + emit IHorizonStakingMain.ProvisionSlashed(serviceProvider, verifier, calcValues.providerTokensSlashed); } - if (delegationTokensSlashed > 0) { + if (calcValues.delegationTokensSlashed > 0) { if (isDelegationSlashingEnabled) { vm.expectEmit(address(token)); - emit Transfer(address(staking), address(0), delegationTokensSlashed); + emit Transfer(address(staking), address(0), calcValues.delegationTokensSlashed); vm.expectEmit(address(staking)); - emit IHorizonStakingMain.DelegationSlashed(serviceProvider, verifier, delegationTokensSlashed); + emit IHorizonStakingMain.DelegationSlashed( + serviceProvider, + verifier, + calcValues.delegationTokensSlashed + ); } else { vm.expectEmit(address(staking)); - emit IHorizonStakingMain.DelegationSlashingSkipped(serviceProvider, verifier, delegationTokensSlashed); + emit IHorizonStakingMain.DelegationSlashingSkipped( + serviceProvider, + verifier, + calcValues.delegationTokensSlashed + ); } } staking.slash(serviceProvider, tokens, verifierCutAmount, verifier); @@ -1401,36 +1410,58 @@ abstract contract HorizonStakingSharedTest is GraphBaseTest { uint256 afterStakingBalance = token.balanceOf(address(staking)); uint256 afterVerifierBalance = token.balanceOf(verifier); - uint256 tokensSlashed = providerTokensSlashed + (isDelegationSlashingEnabled ? delegationTokensSlashed : 0); - uint256 provisionThawingTokens = (beforeProvision.tokensThawing * - (1e18 - ((providerTokensSlashed * 1e18) / beforeProvision.tokens))) / (1e18); + { + uint256 tokensSlashed = calcValues.providerTokensSlashed + + (isDelegationSlashingEnabled ? calcValues.delegationTokensSlashed : 0); + uint256 provisionThawingTokens = (before.provision.tokensThawing * + (1e18 - ((calcValues.providerTokensSlashed * 1e18) / before.provision.tokens))) / (1e18); + + // assert + assertEq(afterProvision.tokens + calcValues.providerTokensSlashed, before.provision.tokens); + assertEq(afterProvision.tokensThawing, provisionThawingTokens); + assertEq(afterProvision.sharesThawing, before.provision.sharesThawing); + assertEq(afterProvision.maxVerifierCut, before.provision.maxVerifierCut); + assertEq(afterProvision.maxVerifierCutPending, before.provision.maxVerifierCutPending); + assertEq(afterProvision.thawingPeriod, before.provision.thawingPeriod); + assertEq(afterProvision.thawingPeriodPending, before.provision.thawingPeriodPending); - // assert - assertEq(afterProvision.tokens + providerTokensSlashed, beforeProvision.tokens); - assertEq(afterProvision.tokensThawing, provisionThawingTokens); - assertEq(afterProvision.sharesThawing, beforeProvision.sharesThawing); - assertEq(afterProvision.maxVerifierCut, beforeProvision.maxVerifierCut); - assertEq(afterProvision.maxVerifierCutPending, beforeProvision.maxVerifierCutPending); - assertEq(afterProvision.thawingPeriod, beforeProvision.thawingPeriod); - assertEq(afterProvision.thawingPeriodPending, beforeProvision.thawingPeriodPending); + if (isDelegationSlashingEnabled) { + uint256 poolThawingTokens = (before.pool.tokensThawing * + (1e18 - ((calcValues.delegationTokensSlashed * 1e18) / before.pool.tokens))) / (1e18); + assertEq(afterPool.tokens + calcValues.delegationTokensSlashed, before.pool.tokens); + assertEq(afterPool.shares, before.pool.shares); + assertEq(afterPool.tokensThawing, poolThawingTokens); + assertEq(afterPool.sharesThawing, before.pool.sharesThawing); + } - if (isDelegationSlashingEnabled) { - uint256 poolThawingTokens = (beforePool.tokensThawing * - (1e18 - ((delegationTokensSlashed * 1e18) / beforePool.tokens))) / (1e18); - assertEq(afterPool.tokens + delegationTokensSlashed, beforePool.tokens); - assertEq(afterPool.shares, beforePool.shares); - assertEq(afterPool.tokensThawing, poolThawingTokens); - assertEq(afterPool.sharesThawing, beforePool.sharesThawing); - } + assertEq(before.stakingBalance - tokensSlashed, afterStakingBalance); + assertEq(before.verifierBalance + verifierCutAmount, afterVerifierBalance); - assertEq(beforeStakingBalance - tokensSlashed, afterStakingBalance); - assertEq(beforeVerifierBalance + verifierCutAmount, afterVerifierBalance); + assertEq( + afterServiceProvider.tokensStaked + calcValues.providerTokensSlashed, + before.serviceProvider.tokensStaked + ); + assertEq( + afterServiceProvider.tokensProvisioned + calcValues.providerTokensSlashed, + before.serviceProvider.tokensProvisioned + ); + } + } - assertEq(afterServiceProvider.tokensStaked + providerTokensSlashed, beforeServiceProvider.tokensStaked); - assertEq( - afterServiceProvider.tokensProvisioned + providerTokensSlashed, - beforeServiceProvider.tokensProvisioned - ); + // use struct to avoid 'stack too deep' error + struct CalcValues_CloseAllocation { + uint256 rewards; + uint256 delegatorRewards; + uint256 indexerRewards; + } + struct BeforeValues_CloseAllocation { + IHorizonStakingExtension.Allocation allocation; + DelegationPoolInternalTest pool; + ServiceProviderInternal serviceProvider; + uint256 subgraphAllocations; + uint256 stakingBalance; + uint256 indexerBalance; + uint256 beneficiaryBalance; } // Current rewards manager is mocked and assumed to mint fixed rewards @@ -1438,36 +1469,47 @@ abstract contract HorizonStakingSharedTest is GraphBaseTest { (, address msgSender, ) = vm.readCallers(); // before - IHorizonStakingExtension.Allocation memory beforeAllocation = staking.getAllocation(allocationId); - DelegationPoolInternalTest memory beforePool = _getStorage_DelegationPoolInternal( - beforeAllocation.indexer, + BeforeValues_CloseAllocation memory beforeValues; + beforeValues.allocation = staking.getAllocation(allocationId); + beforeValues.pool = _getStorage_DelegationPoolInternal( + beforeValues.allocation.indexer, subgraphDataServiceLegacyAddress, true ); - ServiceProviderInternal memory beforeServiceProvider = _getStorage_ServiceProviderInternal( - beforeAllocation.indexer + beforeValues.serviceProvider = _getStorage_ServiceProviderInternal(beforeValues.allocation.indexer); + beforeValues.subgraphAllocations = _getStorage_SubgraphAllocations( + beforeValues.allocation.subgraphDeploymentID + ); + beforeValues.stakingBalance = token.balanceOf(address(staking)); + beforeValues.indexerBalance = token.balanceOf(beforeValues.allocation.indexer); + beforeValues.beneficiaryBalance = token.balanceOf( + _getStorage_RewardsDestination(beforeValues.allocation.indexer) ); - uint256 beforeSubgraphAllocations = _getStorage_SubgraphAllocations(beforeAllocation.subgraphDeploymentID); - - bool isAuth = staking.isAuthorized(msgSender, beforeAllocation.indexer, subgraphDataServiceLegacyAddress); - address rewardsDestination = _getStorage_RewardsDestination(beforeAllocation.indexer); - uint256 beforeStakingBalance = token.balanceOf(address(staking)); - uint256 beforeIndexerBalance = token.balanceOf(beforeAllocation.indexer); - uint256 beforeBeneficiaryBalance = token.balanceOf(rewardsDestination); + bool isAuth = staking.isAuthorized( + msgSender, + beforeValues.allocation.indexer, + subgraphDataServiceLegacyAddress + ); + address rewardsDestination = _getStorage_RewardsDestination(beforeValues.allocation.indexer); - uint256 calcRewards = ALLOCATIONS_REWARD_CUT; - uint256 calcDelegatorRewards = ALLOCATIONS_REWARD_CUT - - uint256(beforePool.__DEPRECATED_indexingRewardCut).mulPPM(calcRewards); - uint256 calcIndexerRewards = ALLOCATIONS_REWARD_CUT - (beforePool.tokens > 0 ? calcDelegatorRewards : 0); + CalcValues_CloseAllocation memory calcValues = CalcValues_CloseAllocation({ + rewards: ALLOCATIONS_REWARD_CUT, + delegatorRewards: ALLOCATIONS_REWARD_CUT - + uint256(beforeValues.pool.__DEPRECATED_indexingRewardCut).mulPPM(ALLOCATIONS_REWARD_CUT), + indexerRewards: 0 + }); + calcValues.indexerRewards = + ALLOCATIONS_REWARD_CUT - + (beforeValues.pool.tokens > 0 ? calcValues.delegatorRewards : 0); // closeAllocation vm.expectEmit(address(staking)); emit IHorizonStakingExtension.AllocationClosed( - beforeAllocation.indexer, - beforeAllocation.subgraphDeploymentID, + beforeValues.allocation.indexer, + beforeValues.allocation.subgraphDeploymentID, epochManager.currentEpoch(), - beforeAllocation.tokens, + beforeValues.allocation.tokens, allocationId, msgSender, poi, @@ -1478,121 +1520,164 @@ abstract contract HorizonStakingSharedTest is GraphBaseTest { // after IHorizonStakingExtension.Allocation memory afterAllocation = staking.getAllocation(allocationId); DelegationPoolInternalTest memory afterPool = _getStorage_DelegationPoolInternal( - beforeAllocation.indexer, + beforeValues.allocation.indexer, subgraphDataServiceLegacyAddress, true ); ServiceProviderInternal memory afterServiceProvider = _getStorage_ServiceProviderInternal( - beforeAllocation.indexer + beforeValues.allocation.indexer + ); + uint256 afterSubgraphAllocations = _getStorage_SubgraphAllocations( + beforeValues.allocation.subgraphDeploymentID ); - uint256 afterSubgraphAllocations = _getStorage_SubgraphAllocations(beforeAllocation.subgraphDeploymentID); uint256 afterStakingBalance = token.balanceOf(address(staking)); - uint256 afterIndexerBalance = token.balanceOf(beforeAllocation.indexer); + uint256 afterIndexerBalance = token.balanceOf(beforeValues.allocation.indexer); uint256 afterBeneficiaryBalance = token.balanceOf(rewardsDestination); - if (beforeAllocation.tokens > 0) { + if (beforeValues.allocation.tokens > 0) { if (isAuth && poi != 0) { if (rewardsDestination != address(0)) { - assertEq(beforeStakingBalance + calcRewards - calcIndexerRewards, afterStakingBalance); - assertEq(beforeIndexerBalance, afterIndexerBalance); - assertEq(beforeBeneficiaryBalance + calcIndexerRewards, afterBeneficiaryBalance); + assertEq( + beforeValues.stakingBalance + calcValues.rewards - calcValues.indexerRewards, + afterStakingBalance + ); + assertEq(beforeValues.indexerBalance, afterIndexerBalance); + assertEq(beforeValues.beneficiaryBalance + calcValues.indexerRewards, afterBeneficiaryBalance); } else { - assertEq(beforeStakingBalance + calcRewards, afterStakingBalance); - assertEq(beforeIndexerBalance, afterIndexerBalance); - assertEq(beforeBeneficiaryBalance, afterBeneficiaryBalance); + assertEq(beforeValues.stakingBalance + calcValues.rewards, afterStakingBalance); + assertEq(beforeValues.indexerBalance, afterIndexerBalance); + assertEq(beforeValues.beneficiaryBalance, afterBeneficiaryBalance); } } else { - assertEq(beforeStakingBalance, afterStakingBalance); - assertEq(beforeIndexerBalance, afterIndexerBalance); - assertEq(beforeBeneficiaryBalance, afterBeneficiaryBalance); + assertEq(beforeValues.stakingBalance, afterStakingBalance); + assertEq(beforeValues.indexerBalance, afterIndexerBalance); + assertEq(beforeValues.beneficiaryBalance, afterBeneficiaryBalance); } } else { - assertEq(beforeStakingBalance, afterStakingBalance); - assertEq(beforeIndexerBalance, afterIndexerBalance); - assertEq(beforeBeneficiaryBalance, afterBeneficiaryBalance); + assertEq(beforeValues.stakingBalance, afterStakingBalance); + assertEq(beforeValues.indexerBalance, afterIndexerBalance); + assertEq(beforeValues.beneficiaryBalance, afterBeneficiaryBalance); } - assertEq(afterAllocation.indexer, beforeAllocation.indexer); - assertEq(afterAllocation.subgraphDeploymentID, beforeAllocation.subgraphDeploymentID); - assertEq(afterAllocation.tokens, beforeAllocation.tokens); - assertEq(afterAllocation.createdAtEpoch, beforeAllocation.createdAtEpoch); + assertEq(afterAllocation.indexer, beforeValues.allocation.indexer); + assertEq(afterAllocation.subgraphDeploymentID, beforeValues.allocation.subgraphDeploymentID); + assertEq(afterAllocation.tokens, beforeValues.allocation.tokens); + assertEq(afterAllocation.createdAtEpoch, beforeValues.allocation.createdAtEpoch); assertEq(afterAllocation.closedAtEpoch, epochManager.currentEpoch()); - assertEq(afterAllocation.collectedFees, beforeAllocation.collectedFees); - assertEq(afterAllocation.__DEPRECATED_effectiveAllocation, beforeAllocation.__DEPRECATED_effectiveAllocation); - assertEq(afterAllocation.accRewardsPerAllocatedToken, beforeAllocation.accRewardsPerAllocatedToken); - assertEq(afterAllocation.distributedRebates, beforeAllocation.distributedRebates); + assertEq(afterAllocation.collectedFees, beforeValues.allocation.collectedFees); + assertEq( + afterAllocation.__DEPRECATED_effectiveAllocation, + beforeValues.allocation.__DEPRECATED_effectiveAllocation + ); + assertEq(afterAllocation.accRewardsPerAllocatedToken, beforeValues.allocation.accRewardsPerAllocatedToken); + assertEq(afterAllocation.distributedRebates, beforeValues.allocation.distributedRebates); - if (beforeAllocation.tokens > 0 && isAuth && poi != 0 && rewardsDestination == address(0)) { - assertEq(afterServiceProvider.tokensStaked, beforeServiceProvider.tokensStaked + calcIndexerRewards); + if (beforeValues.allocation.tokens > 0 && isAuth && poi != 0 && rewardsDestination == address(0)) { + assertEq( + afterServiceProvider.tokensStaked, + beforeValues.serviceProvider.tokensStaked + calcValues.indexerRewards + ); } else { - assertEq(afterServiceProvider.tokensStaked, beforeServiceProvider.tokensStaked); + assertEq(afterServiceProvider.tokensStaked, beforeValues.serviceProvider.tokensStaked); } - assertEq(afterServiceProvider.tokensProvisioned, beforeServiceProvider.tokensProvisioned); + assertEq(afterServiceProvider.tokensProvisioned, beforeValues.serviceProvider.tokensProvisioned); assertEq( - afterServiceProvider.__DEPRECATED_tokensAllocated + beforeAllocation.tokens, - beforeServiceProvider.__DEPRECATED_tokensAllocated + afterServiceProvider.__DEPRECATED_tokensAllocated + beforeValues.allocation.tokens, + beforeValues.serviceProvider.__DEPRECATED_tokensAllocated + ); + assertEq( + afterServiceProvider.__DEPRECATED_tokensLocked, + beforeValues.serviceProvider.__DEPRECATED_tokensLocked ); - assertEq(afterServiceProvider.__DEPRECATED_tokensLocked, beforeServiceProvider.__DEPRECATED_tokensLocked); assertEq( afterServiceProvider.__DEPRECATED_tokensLockedUntil, - beforeServiceProvider.__DEPRECATED_tokensLockedUntil + beforeValues.serviceProvider.__DEPRECATED_tokensLockedUntil ); - assertEq(afterSubgraphAllocations + beforeAllocation.tokens, beforeSubgraphAllocations); + assertEq(afterSubgraphAllocations + beforeValues.allocation.tokens, beforeValues.subgraphAllocations); - if (beforeAllocation.tokens > 0 && isAuth && poi != 0 && beforePool.tokens > 0) { - assertEq(afterPool.tokens, beforePool.tokens + calcDelegatorRewards); + if (beforeValues.allocation.tokens > 0 && isAuth && poi != 0 && beforeValues.pool.tokens > 0) { + assertEq(afterPool.tokens, beforeValues.pool.tokens + calcValues.delegatorRewards); } else { - assertEq(afterPool.tokens, beforePool.tokens); + assertEq(afterPool.tokens, beforeValues.pool.tokens); } } + // use struct to avoid 'stack too deep' error + struct BeforeValues_Collect { + IHorizonStakingExtension.Allocation allocation; + DelegationPoolInternalTest pool; + ServiceProviderInternal serviceProvider; + uint256 stakingBalance; + uint256 senderBalance; + uint256 curationBalance; + uint256 beneficiaryBalance; + } + struct CalcValues_Collect { + uint256 protocolTaxTokens; + uint256 queryFees; + uint256 curationCutTokens; + uint256 newRebates; + uint256 payment; + uint256 delegationFeeCut; + } + struct AfterValues_Collect { + IHorizonStakingExtension.Allocation allocation; + DelegationPoolInternalTest pool; + ServiceProviderInternal serviceProvider; + uint256 stakingBalance; + uint256 senderBalance; + uint256 curationBalance; + uint256 beneficiaryBalance; + } + function _collect(uint256 tokens, address allocationId) internal { (, address msgSender, ) = vm.readCallers(); // before - IHorizonStakingExtension.Allocation memory beforeAllocation = staking.getAllocation(allocationId); - DelegationPoolInternalTest memory beforePool = _getStorage_DelegationPoolInternal( - beforeAllocation.indexer, + BeforeValues_Collect memory beforeValues; + beforeValues.allocation = staking.getAllocation(allocationId); + beforeValues.pool = _getStorage_DelegationPoolInternal( + beforeValues.allocation.indexer, subgraphDataServiceLegacyAddress, true ); - ServiceProviderInternal memory beforeServiceProvider = _getStorage_ServiceProviderInternal( - beforeAllocation.indexer - ); + beforeValues.serviceProvider = _getStorage_ServiceProviderInternal(beforeValues.allocation.indexer); (uint32 curationPercentage, uint32 protocolPercentage) = _getStorage_ProtocolTaxAndCuration(); - address rewardsDestination = _getStorage_RewardsDestination(beforeAllocation.indexer); + address rewardsDestination = _getStorage_RewardsDestination(beforeValues.allocation.indexer); - uint256 beforeStakingBalance = token.balanceOf(address(staking)); - uint256 beforeSenderBalance = token.balanceOf(msgSender); - uint256 beforeCurationBalance = token.balanceOf(address(curation)); - uint256 beforeBeneficiaryBalance = token.balanceOf(rewardsDestination); + beforeValues.stakingBalance = token.balanceOf(address(staking)); + beforeValues.senderBalance = token.balanceOf(msgSender); + beforeValues.curationBalance = token.balanceOf(address(curation)); + beforeValues.beneficiaryBalance = token.balanceOf(rewardsDestination); // calc some stuff - uint256 calcProtocolTaxTokens = tokens.mulPPMRoundUp(protocolPercentage); - uint256 calcQueryFees = tokens - calcProtocolTaxTokens; - - uint256 calcCurationCutTokens = 0; - if (curation.isCurated(beforeAllocation.subgraphDeploymentID)) { - calcCurationCutTokens = calcQueryFees.mulPPMRoundUp(curationPercentage); - calcQueryFees -= calcCurationCutTokens; + CalcValues_Collect memory calcValues; + calcValues.protocolTaxTokens = tokens.mulPPMRoundUp(protocolPercentage); + calcValues.queryFees = tokens - calcValues.protocolTaxTokens; + calcValues.curationCutTokens = 0; + if (curation.isCurated(beforeValues.allocation.subgraphDeploymentID)) { + calcValues.curationCutTokens = calcValues.queryFees.mulPPMRoundUp(curationPercentage); + calcValues.queryFees -= calcValues.curationCutTokens; } - - uint256 calcNewRebates = ExponentialRebates.exponentialRebates( - calcQueryFees + beforeAllocation.collectedFees, - beforeAllocation.tokens, + calcValues.newRebates = ExponentialRebates.exponentialRebates( + calcValues.queryFees + beforeValues.allocation.collectedFees, + beforeValues.allocation.tokens, alphaNumerator, alphaDenominator, lambdaNumerator, lambdaDenominator ); - uint256 calcPayment = calcNewRebates > calcQueryFees ? calcQueryFees : calcNewRebates; - - uint256 calcDelegationFeeCut = 0; - if (beforePool.tokens > 0) { - calcDelegationFeeCut = calcPayment - calcPayment.mulPPM(beforePool.__DEPRECATED_queryFeeCut); - calcPayment -= calcDelegationFeeCut; + calcValues.payment = calcValues.newRebates > calcValues.queryFees + ? calcValues.queryFees + : calcValues.newRebates; + calcValues.delegationFeeCut = 0; + if (beforeValues.pool.tokens > 0) { + calcValues.delegationFeeCut = + calcValues.payment - + calcValues.payment.mulPPM(beforeValues.pool.__DEPRECATED_queryFeeCut); + calcValues.payment -= calcValues.delegationFeeCut; } // staking.collect() @@ -1600,70 +1685,79 @@ abstract contract HorizonStakingSharedTest is GraphBaseTest { vm.expectEmit(address(staking)); emit IHorizonStakingExtension.RebateCollected( msgSender, - beforeAllocation.indexer, - beforeAllocation.subgraphDeploymentID, + beforeValues.allocation.indexer, + beforeValues.allocation.subgraphDeploymentID, allocationId, epochManager.currentEpoch(), tokens, - calcProtocolTaxTokens, - calcCurationCutTokens, - calcQueryFees, - calcPayment, - calcDelegationFeeCut + calcValues.protocolTaxTokens, + calcValues.curationCutTokens, + calcValues.queryFees, + calcValues.payment, + calcValues.delegationFeeCut ); } staking.collect(tokens, allocationId); // after - IHorizonStakingExtension.Allocation memory afterAllocation = staking.getAllocation(allocationId); - DelegationPoolInternalTest memory afterPool = _getStorage_DelegationPoolInternal( - beforeAllocation.indexer, + AfterValues_Collect memory afterValues; + afterValues.allocation = staking.getAllocation(allocationId); + afterValues.pool = _getStorage_DelegationPoolInternal( + beforeValues.allocation.indexer, subgraphDataServiceLegacyAddress, true ); - ServiceProviderInternal memory afterServiceProvider = _getStorage_ServiceProviderInternal( - beforeAllocation.indexer - ); - - uint256 afterBeneficiaryBalance = token.balanceOf(rewardsDestination); - uint256 afterStakingBalance = token.balanceOf(address(staking)); - uint256 afterSenderBalance = token.balanceOf(msgSender); - uint256 afterCurationBalance = token.balanceOf(address(curation)); + afterValues.serviceProvider = _getStorage_ServiceProviderInternal(beforeValues.allocation.indexer); + afterValues.stakingBalance = token.balanceOf(address(staking)); + afterValues.senderBalance = token.balanceOf(msgSender); + afterValues.curationBalance = token.balanceOf(address(curation)); + afterValues.beneficiaryBalance = token.balanceOf(rewardsDestination); // assert - - assertEq(afterSenderBalance + tokens, beforeSenderBalance); - assertEq(afterCurationBalance, beforeCurationBalance + calcCurationCutTokens); + assertEq(afterValues.senderBalance + tokens, beforeValues.senderBalance); + assertEq(afterValues.curationBalance, beforeValues.curationBalance + calcValues.curationCutTokens); if (rewardsDestination != address(0)) { - assertEq(afterBeneficiaryBalance, beforeBeneficiaryBalance + calcPayment); - assertEq(afterStakingBalance, beforeStakingBalance + calcDelegationFeeCut); + assertEq(afterValues.beneficiaryBalance, beforeValues.beneficiaryBalance + calcValues.payment); + assertEq(afterValues.stakingBalance, beforeValues.stakingBalance + calcValues.delegationFeeCut); } else { - assertEq(afterBeneficiaryBalance, beforeBeneficiaryBalance); - assertEq(afterStakingBalance, beforeStakingBalance + calcDelegationFeeCut + calcPayment); + assertEq(afterValues.beneficiaryBalance, beforeValues.beneficiaryBalance); + assertEq( + afterValues.stakingBalance, + beforeValues.stakingBalance + calcValues.delegationFeeCut + calcValues.payment + ); } assertEq( - afterAllocation.collectedFees, - beforeAllocation.collectedFees + tokens - calcProtocolTaxTokens - calcCurationCutTokens - ); - assertEq(afterAllocation.indexer, beforeAllocation.indexer); - assertEq(afterAllocation.subgraphDeploymentID, beforeAllocation.subgraphDeploymentID); - assertEq(afterAllocation.tokens, beforeAllocation.tokens); - assertEq(afterAllocation.createdAtEpoch, beforeAllocation.createdAtEpoch); - assertEq(afterAllocation.closedAtEpoch, beforeAllocation.closedAtEpoch); - assertEq(afterAllocation.accRewardsPerAllocatedToken, beforeAllocation.accRewardsPerAllocatedToken); - assertEq(afterAllocation.distributedRebates, beforeAllocation.distributedRebates + calcNewRebates); - - assertEq(afterPool.tokens, beforePool.tokens + calcDelegationFeeCut); - assertEq(afterPool.shares, beforePool.shares); - assertEq(afterPool.tokensThawing, beforePool.tokensThawing); - assertEq(afterPool.sharesThawing, beforePool.sharesThawing); + afterValues.allocation.collectedFees, + beforeValues.allocation.collectedFees + tokens - calcValues.protocolTaxTokens - calcValues.curationCutTokens + ); + assertEq(afterValues.allocation.indexer, beforeValues.allocation.indexer); + assertEq(afterValues.allocation.subgraphDeploymentID, beforeValues.allocation.subgraphDeploymentID); + assertEq(afterValues.allocation.tokens, beforeValues.allocation.tokens); + assertEq(afterValues.allocation.createdAtEpoch, beforeValues.allocation.createdAtEpoch); + assertEq(afterValues.allocation.closedAtEpoch, beforeValues.allocation.closedAtEpoch); + assertEq( + afterValues.allocation.accRewardsPerAllocatedToken, + beforeValues.allocation.accRewardsPerAllocatedToken + ); + assertEq( + afterValues.allocation.distributedRebates, + beforeValues.allocation.distributedRebates + calcValues.newRebates + ); - assertEq(afterServiceProvider.tokensProvisioned, beforeServiceProvider.tokensProvisioned); + assertEq(afterValues.pool.tokens, beforeValues.pool.tokens + calcValues.delegationFeeCut); + assertEq(afterValues.pool.shares, beforeValues.pool.shares); + assertEq(afterValues.pool.tokensThawing, beforeValues.pool.tokensThawing); + assertEq(afterValues.pool.sharesThawing, beforeValues.pool.sharesThawing); + + assertEq(afterValues.serviceProvider.tokensProvisioned, beforeValues.serviceProvider.tokensProvisioned); if (rewardsDestination != address(0)) { - assertEq(afterServiceProvider.tokensStaked, beforeServiceProvider.tokensStaked); + assertEq(afterValues.serviceProvider.tokensStaked, beforeValues.serviceProvider.tokensStaked); } else { - assertEq(afterServiceProvider.tokensStaked, beforeServiceProvider.tokensStaked + calcPayment); + assertEq( + afterValues.serviceProvider.tokensStaked, + beforeValues.serviceProvider.tokensStaked + calcValues.payment + ); } } @@ -1955,47 +2049,57 @@ abstract contract HorizonStakingSharedTest is GraphBaseTest { } function _setStorage_RebateParameters( - uint32 alphaNumerator, - uint32 alphaDenominator, - uint32 lambdaNumerator, - uint32 lambdaDenominator + uint32 alphaNumerator_, + uint32 alphaDenominator_, + uint32 lambdaNumerator_, + uint32 lambdaDenominator_ ) internal { // Store alpha numerator and denominator in slot 13 uint256 alphaSlot = 13; - uint256 alphaNumeratorOffset = 160; // Offset for __DEPRECATED_alphaNumerator (20th byte) - uint256 alphaDenominatorOffset = 192; // Offset for __DEPRECATED_alphaDenominator (24th byte) - // Read current value of the slot - uint256 currentAlphaSlotValue = uint256(vm.load(address(staking), bytes32(alphaSlot))); + uint256 newAlphaSlotValue; + { + uint256 alphaNumeratorOffset = 160; // Offset for __DEPRECATED_alphaNumerator (20th byte) + uint256 alphaDenominatorOffset = 192; // Offset for __DEPRECATED_alphaDenominator (24th byte) + + // Read current value of the slot + uint256 currentAlphaSlotValue = uint256(vm.load(address(staking), bytes32(alphaSlot))); - // Create a mask to clear the bits for alphaNumerator and alphaDenominator - uint256 alphaMask = ~(uint256(0xFFFFFFFF) << alphaNumeratorOffset) & - ~(uint256(0xFFFFFFFF) << alphaDenominatorOffset); + // Create a mask to clear the bits for alphaNumerator and alphaDenominator + uint256 alphaMask = ~(uint256(0xFFFFFFFF) << alphaNumeratorOffset) & + ~(uint256(0xFFFFFFFF) << alphaDenominatorOffset); - // Clear and set new values - uint256 newAlphaSlotValue = (currentAlphaSlotValue & alphaMask) | - (uint256(alphaNumerator) << alphaNumeratorOffset) | - (uint256(alphaDenominator) << alphaDenominatorOffset); + // Clear and set new values + newAlphaSlotValue = + (currentAlphaSlotValue & alphaMask) | + (uint256(alphaNumerator_) << alphaNumeratorOffset) | + (uint256(alphaDenominator_) << alphaDenominatorOffset); + } // Store the updated value back into the slot vm.store(address(staking), bytes32(alphaSlot), bytes32(newAlphaSlotValue)); // Store lambda numerator and denominator in slot 25 uint256 lambdaSlot = 25; - uint256 lambdaNumeratorOffset = 160; // Offset for lambdaNumerator (20th byte) - uint256 lambdaDenominatorOffset = 192; // Offset for lambdaDenominator (24th byte) - // Read current value of the slot - uint256 currentLambdaSlotValue = uint256(vm.load(address(staking), bytes32(lambdaSlot))); + uint256 newLambdaSlotValue; + { + uint256 lambdaNumeratorOffset = 160; // Offset for lambdaNumerator (20th byte) + uint256 lambdaDenominatorOffset = 192; // Offset for lambdaDenominator (24th byte) - // Create a mask to clear the bits for lambdaNumerator and lambdaDenominator - uint256 lambdaMask = ~(uint256(0xFFFFFFFF) << lambdaNumeratorOffset) & - ~(uint256(0xFFFFFFFF) << lambdaDenominatorOffset); + // Read current value of the slot + uint256 currentLambdaSlotValue = uint256(vm.load(address(staking), bytes32(lambdaSlot))); - // Clear and set new values - uint256 newLambdaSlotValue = (currentLambdaSlotValue & lambdaMask) | - (uint256(lambdaNumerator) << lambdaNumeratorOffset) | - (uint256(lambdaDenominator) << lambdaDenominatorOffset); + // Create a mask to clear the bits for lambdaNumerator and lambdaDenominator + uint256 lambdaMask = ~(uint256(0xFFFFFFFF) << lambdaNumeratorOffset) & + ~(uint256(0xFFFFFFFF) << lambdaDenominatorOffset); + + // Clear and set new values + newLambdaSlotValue = + (currentLambdaSlotValue & lambdaMask) | + (uint256(lambdaNumerator_) << lambdaNumeratorOffset) | + (uint256(lambdaDenominator_) << lambdaDenominatorOffset); + } // Store the updated value back into the slot vm.store(address(staking), bytes32(lambdaSlot), bytes32(newLambdaSlotValue)); @@ -2007,10 +2111,10 @@ abstract contract HorizonStakingSharedTest is GraphBaseTest { uint32 readLambdaNumerator, uint32 readLambdaDenominator ) = _getStorage_RebateParameters(); - assertEq(readAlphaNumerator, alphaNumerator); - assertEq(readAlphaDenominator, alphaDenominator); - assertEq(readLambdaNumerator, lambdaNumerator); - assertEq(readLambdaDenominator, lambdaDenominator); + assertEq(readAlphaNumerator, alphaNumerator_); + assertEq(readAlphaDenominator, alphaDenominator_); + assertEq(readLambdaNumerator, lambdaNumerator_); + assertEq(readLambdaDenominator, lambdaDenominator_); } function _getStorage_RebateParameters() internal view returns (uint32, uint32, uint32, uint32) { @@ -2085,16 +2189,26 @@ abstract contract HorizonStakingSharedTest is GraphBaseTest { /* * MISC: private functions to help with testing */ + // use struct to avoid 'stack too deep' error + struct CalcValues_ThawRequestData { + uint256 tokensThawed; + uint256 tokensThawing; + uint256 sharesThawing; + ThawRequest[] thawRequestsFulfilledList; + bytes32[] thawRequestsFulfilledListIds; + uint256[] thawRequestsFulfilledListTokens; + } + function calcThawRequestData( address serviceProvider, address verifier, address owner, uint256 iterations, bool delegation - ) private view returns (uint256, uint256, uint256, ThawRequest[] memory, bytes32[] memory, uint256[] memory) { + ) private view returns (CalcValues_ThawRequestData memory) { LinkedList.List memory thawRequestList = staking.getThawRequestList(serviceProvider, verifier, owner); if (thawRequestList.count == 0) { - return (0, 0, 0, new ThawRequest[](0), new bytes32[](0), new uint256[](0)); + return CalcValues_ThawRequestData(0, 0, 0, new ThawRequest[](0), new bytes32[](0), new uint256[](0)); } Provision memory prov = staking.getProvision(serviceProvider, verifier); @@ -2149,13 +2263,14 @@ abstract contract HorizonStakingSharedTest is GraphBaseTest { assertEq(thawRequestsFulfilled, thawRequestsFulfilledListIds.length); assertEq(thawRequestsFulfilled, thawRequestsFulfilledListTokens.length); - return ( - tokensThawed, - tokensThawing, - sharesThawing, - thawRequestsFulfilledList, - thawRequestsFulfilledListIds, - thawRequestsFulfilledListTokens - ); + return + CalcValues_ThawRequestData( + tokensThawed, + tokensThawing, + sharesThawing, + thawRequestsFulfilledList, + thawRequestsFulfilledListIds, + thawRequestsFulfilledListTokens + ); } } diff --git a/packages/horizon/test/staking/HorizonStaking.t.sol b/packages/horizon/test/staking/HorizonStaking.t.sol index 617e46ce7..d846d1754 100644 --- a/packages/horizon/test/staking/HorizonStaking.t.sol +++ b/packages/horizon/test/staking/HorizonStaking.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity 0.8.26; +pragma solidity 0.8.27; import "forge-std/Test.sol"; import { stdStorage, StdStorage } from "forge-std/Test.sol"; diff --git a/packages/horizon/test/staking/allocation/allocation.t.sol b/packages/horizon/test/staking/allocation/allocation.t.sol index c5cb92609..9e80433b3 100644 --- a/packages/horizon/test/staking/allocation/allocation.t.sol +++ b/packages/horizon/test/staking/allocation/allocation.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity 0.8.26; +pragma solidity 0.8.27; import "forge-std/Test.sol"; diff --git a/packages/horizon/test/staking/allocation/close.t.sol b/packages/horizon/test/staking/allocation/close.t.sol index aaa4f22e3..121307056 100644 --- a/packages/horizon/test/staking/allocation/close.t.sol +++ b/packages/horizon/test/staking/allocation/close.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity 0.8.26; +pragma solidity 0.8.27; import "forge-std/Test.sol"; diff --git a/packages/horizon/test/staking/allocation/collect.t.sol b/packages/horizon/test/staking/allocation/collect.t.sol index 9a8329d62..9b8b1d9e5 100644 --- a/packages/horizon/test/staking/allocation/collect.t.sol +++ b/packages/horizon/test/staking/allocation/collect.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity 0.8.26; +pragma solidity 0.8.27; import "forge-std/Test.sol"; diff --git a/packages/horizon/test/staking/delegation/addToPool.t.sol b/packages/horizon/test/staking/delegation/addToPool.t.sol index 56104cd3d..e88becbbf 100644 --- a/packages/horizon/test/staking/delegation/addToPool.t.sol +++ b/packages/horizon/test/staking/delegation/addToPool.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity 0.8.26; +pragma solidity 0.8.27; import "forge-std/Test.sol"; diff --git a/packages/horizon/test/staking/delegation/delegate.t.sol b/packages/horizon/test/staking/delegation/delegate.t.sol index 8bbd43a73..d5e101bca 100644 --- a/packages/horizon/test/staking/delegation/delegate.t.sol +++ b/packages/horizon/test/staking/delegation/delegate.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity 0.8.26; +pragma solidity 0.8.27; import "forge-std/Test.sol"; diff --git a/packages/horizon/test/staking/delegation/undelegate.t.sol b/packages/horizon/test/staking/delegation/undelegate.t.sol index ddafc722c..cc2492ba8 100644 --- a/packages/horizon/test/staking/delegation/undelegate.t.sol +++ b/packages/horizon/test/staking/delegation/undelegate.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity 0.8.26; +pragma solidity 0.8.27; import "forge-std/Test.sol"; diff --git a/packages/horizon/test/staking/delegation/withdraw.t.sol b/packages/horizon/test/staking/delegation/withdraw.t.sol index 105ce2914..fc9072898 100644 --- a/packages/horizon/test/staking/delegation/withdraw.t.sol +++ b/packages/horizon/test/staking/delegation/withdraw.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity 0.8.26; +pragma solidity 0.8.27; import "forge-std/Test.sol"; diff --git a/packages/horizon/test/staking/governance/governance.t.sol b/packages/horizon/test/staking/governance/governance.t.sol index cb354697c..401828a3e 100644 --- a/packages/horizon/test/staking/governance/governance.t.sol +++ b/packages/horizon/test/staking/governance/governance.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity 0.8.26; +pragma solidity 0.8.27; import "forge-std/Test.sol"; diff --git a/packages/horizon/test/staking/operator/locked.t.sol b/packages/horizon/test/staking/operator/locked.t.sol index 08ebe9944..706b47a07 100644 --- a/packages/horizon/test/staking/operator/locked.t.sol +++ b/packages/horizon/test/staking/operator/locked.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity 0.8.26; +pragma solidity 0.8.27; import "forge-std/Test.sol"; diff --git a/packages/horizon/test/staking/operator/operator.t.sol b/packages/horizon/test/staking/operator/operator.t.sol index 81e61e6ad..5d509ba68 100644 --- a/packages/horizon/test/staking/operator/operator.t.sol +++ b/packages/horizon/test/staking/operator/operator.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity 0.8.26; +pragma solidity 0.8.27; import "forge-std/Test.sol"; diff --git a/packages/horizon/test/staking/provision/deprovision.t.sol b/packages/horizon/test/staking/provision/deprovision.t.sol index 9087fea55..6d03c3f6e 100644 --- a/packages/horizon/test/staking/provision/deprovision.t.sol +++ b/packages/horizon/test/staking/provision/deprovision.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity 0.8.26; +pragma solidity 0.8.27; import "forge-std/Test.sol"; diff --git a/packages/horizon/test/staking/provision/locked.t.sol b/packages/horizon/test/staking/provision/locked.t.sol index f16900eb2..a8adfc774 100644 --- a/packages/horizon/test/staking/provision/locked.t.sol +++ b/packages/horizon/test/staking/provision/locked.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity 0.8.26; +pragma solidity 0.8.27; import "forge-std/Test.sol"; diff --git a/packages/horizon/test/staking/provision/parameters.t.sol b/packages/horizon/test/staking/provision/parameters.t.sol index acf20a65b..8171f95b4 100644 --- a/packages/horizon/test/staking/provision/parameters.t.sol +++ b/packages/horizon/test/staking/provision/parameters.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity 0.8.26; +pragma solidity 0.8.27; import "forge-std/Test.sol"; diff --git a/packages/horizon/test/staking/provision/provision.t.sol b/packages/horizon/test/staking/provision/provision.t.sol index e8f94c5df..50dc12057 100644 --- a/packages/horizon/test/staking/provision/provision.t.sol +++ b/packages/horizon/test/staking/provision/provision.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity 0.8.26; +pragma solidity 0.8.27; import "forge-std/Test.sol"; diff --git a/packages/horizon/test/staking/provision/reprovision.t.sol b/packages/horizon/test/staking/provision/reprovision.t.sol index d403a5c2e..6fd170e4b 100644 --- a/packages/horizon/test/staking/provision/reprovision.t.sol +++ b/packages/horizon/test/staking/provision/reprovision.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity 0.8.26; +pragma solidity 0.8.27; import "forge-std/Test.sol"; diff --git a/packages/horizon/test/staking/provision/thaw.t.sol b/packages/horizon/test/staking/provision/thaw.t.sol index d3faf350a..bb0b3409d 100644 --- a/packages/horizon/test/staking/provision/thaw.t.sol +++ b/packages/horizon/test/staking/provision/thaw.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity 0.8.26; +pragma solidity 0.8.27; import "forge-std/Test.sol"; diff --git a/packages/horizon/test/staking/serviceProvider/serviceProvider.t.sol b/packages/horizon/test/staking/serviceProvider/serviceProvider.t.sol index 5da6347f2..63578791a 100644 --- a/packages/horizon/test/staking/serviceProvider/serviceProvider.t.sol +++ b/packages/horizon/test/staking/serviceProvider/serviceProvider.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity 0.8.26; +pragma solidity 0.8.27; import "forge-std/Test.sol"; diff --git a/packages/horizon/test/staking/slash/slash.t.sol b/packages/horizon/test/staking/slash/slash.t.sol index 087239f69..bf1f2fb1e 100644 --- a/packages/horizon/test/staking/slash/slash.t.sol +++ b/packages/horizon/test/staking/slash/slash.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity 0.8.26; +pragma solidity 0.8.27; import "forge-std/Test.sol"; diff --git a/packages/horizon/test/staking/stake/stake.t.sol b/packages/horizon/test/staking/stake/stake.t.sol index 030d516a3..55474245c 100644 --- a/packages/horizon/test/staking/stake/stake.t.sol +++ b/packages/horizon/test/staking/stake/stake.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity 0.8.26; +pragma solidity 0.8.27; import "forge-std/Test.sol"; diff --git a/packages/horizon/test/staking/stake/unstake.t.sol b/packages/horizon/test/staking/stake/unstake.t.sol index 9a3970cb7..13ea92e00 100644 --- a/packages/horizon/test/staking/stake/unstake.t.sol +++ b/packages/horizon/test/staking/stake/unstake.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity 0.8.26; +pragma solidity 0.8.27; import "forge-std/Test.sol"; diff --git a/packages/horizon/test/staking/stake/withdraw.t.sol b/packages/horizon/test/staking/stake/withdraw.t.sol index 0ef922bfa..b28dea022 100644 --- a/packages/horizon/test/staking/stake/withdraw.t.sol +++ b/packages/horizon/test/staking/stake/withdraw.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity 0.8.26; +pragma solidity 0.8.27; import "forge-std/Test.sol"; diff --git a/packages/horizon/test/staking/transfer-tools/ttools.t.sol b/packages/horizon/test/staking/transfer-tools/ttools.t.sol index feadb852e..11bb6e62d 100644 --- a/packages/horizon/test/staking/transfer-tools/ttools.t.sol +++ b/packages/horizon/test/staking/transfer-tools/ttools.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity 0.8.26; +pragma solidity 0.8.27; import "forge-std/Test.sol"; diff --git a/packages/horizon/test/utilities/GraphDirectory.t.sol b/packages/horizon/test/utilities/GraphDirectory.t.sol index 35ab2a291..ece4afe65 100644 --- a/packages/horizon/test/utilities/GraphDirectory.t.sol +++ b/packages/horizon/test/utilities/GraphDirectory.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: UNLICENSED -pragma solidity 0.8.26; +pragma solidity 0.8.27; import "forge-std/Test.sol"; import { stdStorage, StdStorage } from "forge-std/Test.sol"; diff --git a/packages/horizon/test/utilities/GraphDirectoryImplementation.sol b/packages/horizon/test/utilities/GraphDirectoryImplementation.sol index 57780f450..1095adc3a 100644 --- a/packages/horizon/test/utilities/GraphDirectoryImplementation.sol +++ b/packages/horizon/test/utilities/GraphDirectoryImplementation.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-or-later -pragma solidity 0.8.26; +pragma solidity 0.8.27; import { IGraphToken } from "@graphprotocol/contracts/contracts/token/IGraphToken.sol"; import { IHorizonStaking } from "../../contracts/interfaces/IHorizonStaking.sol"; diff --git a/packages/horizon/test/utils/Constants.sol b/packages/horizon/test/utils/Constants.sol index 29daaaa96..f08fa4ec1 100644 --- a/packages/horizon/test/utils/Constants.sol +++ b/packages/horizon/test/utils/Constants.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity 0.8.26; +pragma solidity 0.8.27; abstract contract Constants { uint256 internal constant MAX_PPM = 1000000; // 100% in parts per million diff --git a/packages/horizon/test/utils/Users.sol b/packages/horizon/test/utils/Users.sol index 3329d69da..b26329f91 100644 --- a/packages/horizon/test/utils/Users.sol +++ b/packages/horizon/test/utils/Users.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity 0.8.26; +pragma solidity 0.8.27; struct Users { address governor; diff --git a/packages/horizon/test/utils/Utils.sol b/packages/horizon/test/utils/Utils.sol index 47e4e68df..5aae4de3f 100644 --- a/packages/horizon/test/utils/Utils.sol +++ b/packages/horizon/test/utils/Utils.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity 0.8.26; +pragma solidity 0.8.27; import "forge-std/Test.sol"; diff --git a/packages/subgraph-service/contracts/DisputeManager.sol b/packages/subgraph-service/contracts/DisputeManager.sol index a9afcff28..f48c20463 100644 --- a/packages/subgraph-service/contracts/DisputeManager.sol +++ b/packages/subgraph-service/contracts/DisputeManager.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-2.0-or-later -pragma solidity 0.8.26; +pragma solidity 0.8.27; import { IGraphToken } from "@graphprotocol/contracts/contracts/token/IGraphToken.sol"; import { IHorizonStaking } from "@graphprotocol/horizon/contracts/interfaces/IHorizonStaking.sol"; diff --git a/packages/subgraph-service/contracts/DisputeManagerStorage.sol b/packages/subgraph-service/contracts/DisputeManagerStorage.sol index 8ff0685bf..a8790230d 100644 --- a/packages/subgraph-service/contracts/DisputeManagerStorage.sol +++ b/packages/subgraph-service/contracts/DisputeManagerStorage.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-or-later -pragma solidity 0.8.26; +pragma solidity 0.8.27; import { IDisputeManager } from "./interfaces/IDisputeManager.sol"; import { ISubgraphService } from "./interfaces/ISubgraphService.sol"; diff --git a/packages/subgraph-service/contracts/SubgraphService.sol b/packages/subgraph-service/contracts/SubgraphService.sol index 51cb889f7..5023e6160 100644 --- a/packages/subgraph-service/contracts/SubgraphService.sol +++ b/packages/subgraph-service/contracts/SubgraphService.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-3.0-or-later -pragma solidity 0.8.26; +pragma solidity 0.8.27; import { IGraphPayments } from "@graphprotocol/horizon/contracts/interfaces/IGraphPayments.sol"; import { IGraphToken } from "@graphprotocol/contracts/contracts/token/IGraphToken.sol"; diff --git a/packages/subgraph-service/contracts/SubgraphServiceStorage.sol b/packages/subgraph-service/contracts/SubgraphServiceStorage.sol index 54de429f1..e953dfba0 100644 --- a/packages/subgraph-service/contracts/SubgraphServiceStorage.sol +++ b/packages/subgraph-service/contracts/SubgraphServiceStorage.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-3.0-or-later -pragma solidity 0.8.26; +pragma solidity 0.8.27; import { ISubgraphService } from "./interfaces/ISubgraphService.sol"; diff --git a/packages/subgraph-service/contracts/interfaces/IDisputeManager.sol b/packages/subgraph-service/contracts/interfaces/IDisputeManager.sol index 73f7e56d6..95511ecc2 100644 --- a/packages/subgraph-service/contracts/interfaces/IDisputeManager.sol +++ b/packages/subgraph-service/contracts/interfaces/IDisputeManager.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-or-later -pragma solidity 0.8.26; +pragma solidity 0.8.27; import { Attestation } from "../libraries/Attestation.sol"; diff --git a/packages/subgraph-service/contracts/interfaces/ISubgraphService.sol b/packages/subgraph-service/contracts/interfaces/ISubgraphService.sol index e993c5159..e12554303 100644 --- a/packages/subgraph-service/contracts/interfaces/ISubgraphService.sol +++ b/packages/subgraph-service/contracts/interfaces/ISubgraphService.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-3.0-or-later -pragma solidity 0.8.26; +pragma solidity 0.8.27; import { IDataServiceFees } from "@graphprotocol/horizon/contracts/data-service/interfaces/IDataServiceFees.sol"; import { IGraphPayments } from "@graphprotocol/horizon/contracts/interfaces/IGraphPayments.sol"; diff --git a/packages/subgraph-service/contracts/libraries/Allocation.sol b/packages/subgraph-service/contracts/libraries/Allocation.sol index e039b75bd..a55034f17 100644 --- a/packages/subgraph-service/contracts/libraries/Allocation.sol +++ b/packages/subgraph-service/contracts/libraries/Allocation.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-3.0-or-later -pragma solidity 0.8.26; +pragma solidity 0.8.27; import { Math } from "@openzeppelin/contracts/utils/math/Math.sol"; diff --git a/packages/subgraph-service/contracts/libraries/Attestation.sol b/packages/subgraph-service/contracts/libraries/Attestation.sol index 0211db674..66a3cb5fb 100644 --- a/packages/subgraph-service/contracts/libraries/Attestation.sol +++ b/packages/subgraph-service/contracts/libraries/Attestation.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-3.0-or-later -pragma solidity 0.8.26; +pragma solidity 0.8.27; /** * @title Attestation library diff --git a/packages/subgraph-service/contracts/libraries/LegacyAllocation.sol b/packages/subgraph-service/contracts/libraries/LegacyAllocation.sol index 81e6bcdcb..83bef8037 100644 --- a/packages/subgraph-service/contracts/libraries/LegacyAllocation.sol +++ b/packages/subgraph-service/contracts/libraries/LegacyAllocation.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-3.0-or-later -pragma solidity 0.8.26; +pragma solidity 0.8.27; /** * @title LegacyAllocation library diff --git a/packages/subgraph-service/contracts/utilities/AllocationManager.sol b/packages/subgraph-service/contracts/utilities/AllocationManager.sol index 1a9c86928..2e40f28d3 100644 --- a/packages/subgraph-service/contracts/utilities/AllocationManager.sol +++ b/packages/subgraph-service/contracts/utilities/AllocationManager.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-3.0-or-later -pragma solidity 0.8.26; +pragma solidity 0.8.27; import { IGraphPayments } from "@graphprotocol/horizon/contracts/interfaces/IGraphPayments.sol"; import { IGraphToken } from "@graphprotocol/contracts/contracts/token/IGraphToken.sol"; diff --git a/packages/subgraph-service/contracts/utilities/AllocationManagerStorage.sol b/packages/subgraph-service/contracts/utilities/AllocationManagerStorage.sol index da812f5c1..f11e18d1b 100644 --- a/packages/subgraph-service/contracts/utilities/AllocationManagerStorage.sol +++ b/packages/subgraph-service/contracts/utilities/AllocationManagerStorage.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-3.0-or-later -pragma solidity 0.8.26; +pragma solidity 0.8.27; import { Allocation } from "../libraries/Allocation.sol"; import { LegacyAllocation } from "../libraries/LegacyAllocation.sol"; diff --git a/packages/subgraph-service/contracts/utilities/AttestationManager.sol b/packages/subgraph-service/contracts/utilities/AttestationManager.sol index 0d8405917..97c55ab8b 100644 --- a/packages/subgraph-service/contracts/utilities/AttestationManager.sol +++ b/packages/subgraph-service/contracts/utilities/AttestationManager.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-3.0-or-later -pragma solidity 0.8.26; +pragma solidity 0.8.27; import { AttestationManagerV1Storage } from "./AttestationManagerStorage.sol"; diff --git a/packages/subgraph-service/contracts/utilities/AttestationManagerStorage.sol b/packages/subgraph-service/contracts/utilities/AttestationManagerStorage.sol index 5bf57af65..5f86a19f3 100644 --- a/packages/subgraph-service/contracts/utilities/AttestationManagerStorage.sol +++ b/packages/subgraph-service/contracts/utilities/AttestationManagerStorage.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-3.0-or-later -pragma solidity 0.8.26; +pragma solidity 0.8.27; abstract contract AttestationManagerV1Storage { /// @dev EIP712 domain separator diff --git a/packages/subgraph-service/contracts/utilities/Directory.sol b/packages/subgraph-service/contracts/utilities/Directory.sol index 920a0ae5e..53de7c6e7 100644 --- a/packages/subgraph-service/contracts/utilities/Directory.sol +++ b/packages/subgraph-service/contracts/utilities/Directory.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-3.0-or-later -pragma solidity 0.8.26; +pragma solidity 0.8.27; import { IDisputeManager } from "../interfaces/IDisputeManager.sol"; import { ISubgraphService } from "../interfaces/ISubgraphService.sol"; diff --git a/packages/subgraph-service/hardhat.config.ts b/packages/subgraph-service/hardhat.config.ts index a8e05c779..17ebc2053 100644 --- a/packages/subgraph-service/hardhat.config.ts +++ b/packages/subgraph-service/hardhat.config.ts @@ -8,7 +8,7 @@ import { HardhatUserConfig } from 'hardhat/config' const config: HardhatUserConfig = { solidity: { - version: '0.8.26', + version: '0.8.27', settings: { viaIR: true, optimizer: { diff --git a/packages/subgraph-service/test/SubgraphBaseTest.t.sol b/packages/subgraph-service/test/SubgraphBaseTest.t.sol index 2fe5ccf64..d42b66e29 100644 --- a/packages/subgraph-service/test/SubgraphBaseTest.t.sol +++ b/packages/subgraph-service/test/SubgraphBaseTest.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity 0.8.26; +pragma solidity 0.8.27; import "forge-std/Test.sol"; diff --git a/packages/subgraph-service/test/disputeManager/DisputeManager.t.sol b/packages/subgraph-service/test/disputeManager/DisputeManager.t.sol index 1077c1435..685150e62 100644 --- a/packages/subgraph-service/test/disputeManager/DisputeManager.t.sol +++ b/packages/subgraph-service/test/disputeManager/DisputeManager.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity 0.8.26; +pragma solidity 0.8.27; import "forge-std/Test.sol"; diff --git a/packages/subgraph-service/test/disputeManager/constructor/constructor.t.sol b/packages/subgraph-service/test/disputeManager/constructor/constructor.t.sol index 76f90481a..c9166719f 100644 --- a/packages/subgraph-service/test/disputeManager/constructor/constructor.t.sol +++ b/packages/subgraph-service/test/disputeManager/constructor/constructor.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity 0.8.26; +pragma solidity 0.8.27; import "forge-std/Test.sol"; diff --git a/packages/subgraph-service/test/disputeManager/governance/fishermanRewardCut.t.sol b/packages/subgraph-service/test/disputeManager/governance/fishermanRewardCut.t.sol index 5a09bdd03..3eddddc37 100644 --- a/packages/subgraph-service/test/disputeManager/governance/fishermanRewardCut.t.sol +++ b/packages/subgraph-service/test/disputeManager/governance/fishermanRewardCut.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity 0.8.26; +pragma solidity 0.8.27; import "forge-std/Test.sol"; diff --git a/packages/subgraph-service/test/mocks/MockCuration.sol b/packages/subgraph-service/test/mocks/MockCuration.sol index 68b4a8ce9..e0158a99e 100644 --- a/packages/subgraph-service/test/mocks/MockCuration.sol +++ b/packages/subgraph-service/test/mocks/MockCuration.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-or-later -pragma solidity 0.8.26; +pragma solidity 0.8.27; contract MockCuration { function isCurated(bytes32) public pure returns (bool) { diff --git a/packages/subgraph-service/test/mocks/MockGRTToken.sol b/packages/subgraph-service/test/mocks/MockGRTToken.sol index d581f8299..7d21fd00a 100644 --- a/packages/subgraph-service/test/mocks/MockGRTToken.sol +++ b/packages/subgraph-service/test/mocks/MockGRTToken.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity 0.8.26; +pragma solidity 0.8.27; import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; import "@graphprotocol/contracts/contracts/token/IGraphToken.sol"; diff --git a/packages/subgraph-service/test/mocks/MockRewardsManager.sol b/packages/subgraph-service/test/mocks/MockRewardsManager.sol index 59ca5577e..363fbf902 100644 --- a/packages/subgraph-service/test/mocks/MockRewardsManager.sol +++ b/packages/subgraph-service/test/mocks/MockRewardsManager.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity 0.8.26; +pragma solidity 0.8.27; import "forge-std/Test.sol"; diff --git a/packages/subgraph-service/test/shared/SubgraphServiceShared.t.sol b/packages/subgraph-service/test/shared/SubgraphServiceShared.t.sol index 1067acf14..089fdd9a9 100644 --- a/packages/subgraph-service/test/shared/SubgraphServiceShared.t.sol +++ b/packages/subgraph-service/test/shared/SubgraphServiceShared.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity 0.8.26; +pragma solidity 0.8.27; import "forge-std/Test.sol"; diff --git a/packages/subgraph-service/test/subgraphService/SubgraphService.t.sol b/packages/subgraph-service/test/subgraphService/SubgraphService.t.sol index 12d20581f..e9c3d5529 100644 --- a/packages/subgraph-service/test/subgraphService/SubgraphService.t.sol +++ b/packages/subgraph-service/test/subgraphService/SubgraphService.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity 0.8.26; +pragma solidity 0.8.27; import "forge-std/Test.sol"; diff --git a/packages/subgraph-service/test/subgraphService/allocation/stop.t.sol b/packages/subgraph-service/test/subgraphService/allocation/stop.t.sol index 84b9da27e..ee5958115 100644 --- a/packages/subgraph-service/test/subgraphService/allocation/stop.t.sol +++ b/packages/subgraph-service/test/subgraphService/allocation/stop.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity 0.8.26; +pragma solidity 0.8.27; import "forge-std/Test.sol"; diff --git a/packages/subgraph-service/test/subgraphService/collect/collect.t.sol b/packages/subgraph-service/test/subgraphService/collect/collect.t.sol index 4891a4a75..9df747b4f 100644 --- a/packages/subgraph-service/test/subgraphService/collect/collect.t.sol +++ b/packages/subgraph-service/test/subgraphService/collect/collect.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity 0.8.26; +pragma solidity 0.8.27; import "forge-std/Test.sol"; diff --git a/packages/subgraph-service/test/subgraphService/provider/register.t.sol b/packages/subgraph-service/test/subgraphService/provider/register.t.sol index 8e3d0577e..1df1f5571 100644 --- a/packages/subgraph-service/test/subgraphService/provider/register.t.sol +++ b/packages/subgraph-service/test/subgraphService/provider/register.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity 0.8.26; +pragma solidity 0.8.27; import "forge-std/Test.sol"; diff --git a/packages/subgraph-service/test/subgraphService/provision/accept.t.sol b/packages/subgraph-service/test/subgraphService/provision/accept.t.sol index 9fdb0b76f..1c8191275 100644 --- a/packages/subgraph-service/test/subgraphService/provision/accept.t.sol +++ b/packages/subgraph-service/test/subgraphService/provision/accept.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity 0.8.26; +pragma solidity 0.8.27; import "forge-std/Test.sol"; diff --git a/packages/subgraph-service/test/utils/Constants.sol b/packages/subgraph-service/test/utils/Constants.sol index e20d1fc72..1dbfd082e 100644 --- a/packages/subgraph-service/test/utils/Constants.sol +++ b/packages/subgraph-service/test/utils/Constants.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity 0.8.26; +pragma solidity 0.8.27; abstract contract Constants { uint256 internal constant MAX_TOKENS = 10_000_000_000 ether; diff --git a/packages/subgraph-service/test/utils/Users.sol b/packages/subgraph-service/test/utils/Users.sol index b2976f98a..69c3e411e 100644 --- a/packages/subgraph-service/test/utils/Users.sol +++ b/packages/subgraph-service/test/utils/Users.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity 0.8.26; +pragma solidity 0.8.27; struct Users { address governor; diff --git a/packages/subgraph-service/test/utils/Utils.sol b/packages/subgraph-service/test/utils/Utils.sol index 47e4e68df..5aae4de3f 100644 --- a/packages/subgraph-service/test/utils/Utils.sol +++ b/packages/subgraph-service/test/utils/Utils.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity 0.8.26; +pragma solidity 0.8.27; import "forge-std/Test.sol"; From 177fcdfd40b67550d4a5fbd62069f12731ffcd8e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1s=20Migone?= Date: Mon, 9 Sep 2024 16:20:49 -0300 Subject: [PATCH 24/24] chore: use solidity 0.8.27 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Tomás Migone --- packages/subgraph-service/foundry.toml | 10 +- packages/subgraph-service/package.json | 2 +- .../test/disputeManager/DisputeManager.t.sol | 61 ++++++----- .../disputeManager/disputes/disputes.t.sol | 2 +- .../disputes/indexing/accept.t.sol | 2 +- .../disputes/indexing/cancel.t.sol | 2 +- .../disputes/indexing/create.t.sol | 2 +- .../disputes/indexing/draw.t.sol | 2 +- .../disputes/indexing/reject.t.sol | 2 +- .../disputes/query/accept.t.sol | 2 +- .../disputes/query/cancel.t.sol | 2 +- .../disputes/query/create.t.sol | 2 +- .../disputeManager/disputes/query/draw.t.sol | 2 +- .../disputes/query/reject.t.sol | 2 +- .../disputes/queryConflict/accept.t.sol | 2 +- .../disputes/queryConflict/cancel.t.sol | 2 +- .../disputes/queryConflict/create.t.sol | 2 +- .../disputes/queryConflict/draw.t.sol | 2 +- .../disputes/queryConflict/reject.t.sol | 2 +- .../governance/arbitrator.t.sol | 2 +- .../governance/disputeDeposit.t.sol | 2 +- .../governance/maxSlashingCut.t.sol | 2 +- .../test/shared/HorizonStakingShared.t.sol | 2 +- .../subgraphService/SubgraphService.t.sol | 101 ++++++++++++------ .../allocation/closeStale.t.sol | 2 +- .../subgraphService/allocation/resize.t.sol | 2 +- .../subgraphService/allocation/start.t.sol | 2 +- .../collect/indexing/indexing.t.sol | 2 +- .../subgraphService/collect/query/query.t.sol | 2 +- .../provider/rewardsDestination.t.sol | 2 +- 30 files changed, 136 insertions(+), 90 deletions(-) diff --git a/packages/subgraph-service/foundry.toml b/packages/subgraph-service/foundry.toml index 235a58eb9..9f5c3a92a 100644 --- a/packages/subgraph-service/foundry.toml +++ b/packages/subgraph-service/foundry.toml @@ -4,14 +4,6 @@ out = 'build' libs = ['node_modules', 'lib'] test = 'test' cache_path = 'cache_forge' +fs_permissions = [{ access = "read", path = "./"}] optimizer = true optimizer-runs = 200 -via_ir = true -fs_permissions = [{ access = "read", path = "./"}] - -[profile.lite] -optimizer = false -optimizer-runs = 1 - -[profile.lite.optimizer_details.yulDetails] -optimizerSteps = ':' \ No newline at end of file diff --git a/packages/subgraph-service/package.json b/packages/subgraph-service/package.json index da7b33a3d..bb5dd9ea9 100644 --- a/packages/subgraph-service/package.json +++ b/packages/subgraph-service/package.json @@ -10,7 +10,7 @@ "lint": "yarn lint:ts && yarn lint:sol", "clean": "rm -rf build cache typechain-types", "build": "forge build && hardhat compile", - "test": "FOUNDRY_PROFILE=lite forge test -vvvv && hardhat test" + "test": "forge test && hardhat test" }, "devDependencies": { "@graphprotocol/contracts": "workspace:^7.0.0", diff --git a/packages/subgraph-service/test/disputeManager/DisputeManager.t.sol b/packages/subgraph-service/test/disputeManager/DisputeManager.t.sol index 685150e62..0d99aec0b 100644 --- a/packages/subgraph-service/test/disputeManager/DisputeManager.t.sol +++ b/packages/subgraph-service/test/disputeManager/DisputeManager.t.sol @@ -166,54 +166,67 @@ contract DisputeManagerTest is SubgraphServiceSharedTest { return _disputeID; } + struct BeforeValues_CreateQueryDisputeConflict { + Attestation.State attestation1; + Attestation.State attestation2; + address indexer1; + address indexer2; + uint256 stakeSnapshot1; + uint256 stakeSnapshot2; + } function _createQueryDisputeConflict( bytes memory attestationData1, bytes memory attestationData2 ) internal returns (bytes32, bytes32) { (, address fisherman,) = vm.readCallers(); - Attestation.State memory attestation1 = Attestation.parse(attestationData1); - Attestation.State memory attestation2 = Attestation.parse(attestationData2); - address indexer1 = disputeManager.getAttestationIndexer(attestation1); - address indexer2 = disputeManager.getAttestationIndexer(attestation2); + + BeforeValues_CreateQueryDisputeConflict memory beforeValues; + beforeValues.attestation1 = Attestation.parse(attestationData1); + beforeValues.attestation2 = Attestation.parse(attestationData2); + beforeValues.indexer1 = disputeManager.getAttestationIndexer(beforeValues.attestation1); + beforeValues.indexer2 = disputeManager.getAttestationIndexer(beforeValues.attestation2); + beforeValues.stakeSnapshot1 = disputeManager.getStakeSnapshot(beforeValues.indexer1); + beforeValues.stakeSnapshot2 = disputeManager.getStakeSnapshot(beforeValues.indexer2); + bytes32 expectedDisputeId1 = keccak256( abi.encodePacked( - attestation1.requestCID, - attestation1.responseCID, - attestation1.subgraphDeploymentId, - indexer1, + beforeValues.attestation1.requestCID, + beforeValues.attestation1.responseCID, + beforeValues.attestation1.subgraphDeploymentId, + beforeValues.indexer1, fisherman ) ); bytes32 expectedDisputeId2 = keccak256( abi.encodePacked( - attestation2.requestCID, - attestation2.responseCID, - attestation2.subgraphDeploymentId, - indexer2, + beforeValues.attestation2.requestCID, + beforeValues.attestation2.responseCID, + beforeValues.attestation2.subgraphDeploymentId, + beforeValues.indexer2, fisherman ) ); - uint256 stakeSnapshot1 = disputeManager.getStakeSnapshot(indexer1); - uint256 stakeSnapshot2 = disputeManager.getStakeSnapshot(indexer2); + // createQueryDisputeConflict vm.expectEmit(address(disputeManager)); emit IDisputeManager.QueryDisputeCreated( expectedDisputeId1, - indexer1, + beforeValues.indexer1, fisherman, 0, - attestation1.subgraphDeploymentId, + beforeValues.attestation1.subgraphDeploymentId, attestationData1, - stakeSnapshot1 + beforeValues.stakeSnapshot1 ); + vm.expectEmit(address(disputeManager)); emit IDisputeManager.QueryDisputeCreated( expectedDisputeId2, - indexer2, + beforeValues.indexer2, fisherman, 0, - attestation2.subgraphDeploymentId, + beforeValues.attestation2.subgraphDeploymentId, attestationData2, - stakeSnapshot2 + beforeValues.stakeSnapshot2 ); (bytes32 _disputeId1, bytes32 _disputeId2) = disputeManager.createQueryDisputeConflict(attestationData1, attestationData2); @@ -226,24 +239,24 @@ contract DisputeManagerTest is SubgraphServiceSharedTest { // Check dispute values IDisputeManager.Dispute memory dispute1 = _getDispute(_disputeId1); - assertEq(dispute1.indexer, indexer1, "Indexer 1 should match"); + assertEq(dispute1.indexer, beforeValues.indexer1, "Indexer 1 should match"); assertEq(dispute1.fisherman, fisherman, "Fisherman 1 should match"); assertEq(dispute1.deposit, 0, "Deposit 1 should match"); assertEq(dispute1.relatedDisputeId, _disputeId2, "Related dispute ID 1 should be the id of the other dispute"); assertEq(uint8(dispute1.disputeType), uint8(IDisputeManager.DisputeType.QueryDispute), "Dispute type 1 should be query"); assertEq(uint8(dispute1.status), uint8(IDisputeManager.DisputeStatus.Pending), "Dispute status 1 should be pending"); assertEq(dispute1.createdAt, block.timestamp, "Created at 1 should match"); - assertEq(dispute1.stakeSnapshot, stakeSnapshot1, "Stake snapshot 1 should match"); + assertEq(dispute1.stakeSnapshot, beforeValues.stakeSnapshot1, "Stake snapshot 1 should match"); IDisputeManager.Dispute memory dispute2 = _getDispute(_disputeId2); - assertEq(dispute2.indexer, indexer2, "Indexer 2 should match"); + assertEq(dispute2.indexer, beforeValues.indexer2, "Indexer 2 should match"); assertEq(dispute2.fisherman, fisherman, "Fisherman 2 should match"); assertEq(dispute2.deposit, 0, "Deposit 2 should match"); assertEq(dispute2.relatedDisputeId, _disputeId1, "Related dispute ID 2 should be the id of the other dispute"); assertEq(uint8(dispute2.disputeType), uint8(IDisputeManager.DisputeType.QueryDispute), "Dispute type 2 should be query"); assertEq(uint8(dispute2.status), uint8(IDisputeManager.DisputeStatus.Pending), "Dispute status 2 should be pending"); assertEq(dispute2.createdAt, block.timestamp, "Created at 2 should match"); - assertEq(dispute2.stakeSnapshot, stakeSnapshot2, "Stake snapshot 2 should match"); + assertEq(dispute2.stakeSnapshot, beforeValues.stakeSnapshot2, "Stake snapshot 2 should match"); return (_disputeId1, _disputeId2); } diff --git a/packages/subgraph-service/test/disputeManager/disputes/disputes.t.sol b/packages/subgraph-service/test/disputeManager/disputes/disputes.t.sol index cd229dbc4..b6b4a6890 100644 --- a/packages/subgraph-service/test/disputeManager/disputes/disputes.t.sol +++ b/packages/subgraph-service/test/disputeManager/disputes/disputes.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity 0.8.26; +pragma solidity 0.8.27; import "forge-std/Test.sol"; diff --git a/packages/subgraph-service/test/disputeManager/disputes/indexing/accept.t.sol b/packages/subgraph-service/test/disputeManager/disputes/indexing/accept.t.sol index 5e0d36132..49bee9e26 100644 --- a/packages/subgraph-service/test/disputeManager/disputes/indexing/accept.t.sol +++ b/packages/subgraph-service/test/disputeManager/disputes/indexing/accept.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity 0.8.26; +pragma solidity 0.8.27; import "forge-std/Test.sol"; diff --git a/packages/subgraph-service/test/disputeManager/disputes/indexing/cancel.t.sol b/packages/subgraph-service/test/disputeManager/disputes/indexing/cancel.t.sol index 0a09ad7f4..1639f2cad 100644 --- a/packages/subgraph-service/test/disputeManager/disputes/indexing/cancel.t.sol +++ b/packages/subgraph-service/test/disputeManager/disputes/indexing/cancel.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity 0.8.26; +pragma solidity 0.8.27; import "forge-std/Test.sol"; diff --git a/packages/subgraph-service/test/disputeManager/disputes/indexing/create.t.sol b/packages/subgraph-service/test/disputeManager/disputes/indexing/create.t.sol index 0174315a2..8d1b75c21 100644 --- a/packages/subgraph-service/test/disputeManager/disputes/indexing/create.t.sol +++ b/packages/subgraph-service/test/disputeManager/disputes/indexing/create.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity 0.8.26; +pragma solidity 0.8.27; import "forge-std/Test.sol"; diff --git a/packages/subgraph-service/test/disputeManager/disputes/indexing/draw.t.sol b/packages/subgraph-service/test/disputeManager/disputes/indexing/draw.t.sol index 3df590f74..7ce70d962 100644 --- a/packages/subgraph-service/test/disputeManager/disputes/indexing/draw.t.sol +++ b/packages/subgraph-service/test/disputeManager/disputes/indexing/draw.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity 0.8.26; +pragma solidity 0.8.27; import "forge-std/Test.sol"; diff --git a/packages/subgraph-service/test/disputeManager/disputes/indexing/reject.t.sol b/packages/subgraph-service/test/disputeManager/disputes/indexing/reject.t.sol index 5401c0afe..41b5adabc 100644 --- a/packages/subgraph-service/test/disputeManager/disputes/indexing/reject.t.sol +++ b/packages/subgraph-service/test/disputeManager/disputes/indexing/reject.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity 0.8.26; +pragma solidity 0.8.27; import "forge-std/Test.sol"; diff --git a/packages/subgraph-service/test/disputeManager/disputes/query/accept.t.sol b/packages/subgraph-service/test/disputeManager/disputes/query/accept.t.sol index d0f00234d..7670d381e 100644 --- a/packages/subgraph-service/test/disputeManager/disputes/query/accept.t.sol +++ b/packages/subgraph-service/test/disputeManager/disputes/query/accept.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity 0.8.26; +pragma solidity 0.8.27; import "forge-std/Test.sol"; diff --git a/packages/subgraph-service/test/disputeManager/disputes/query/cancel.t.sol b/packages/subgraph-service/test/disputeManager/disputes/query/cancel.t.sol index a61db6ad9..5a70e2f70 100644 --- a/packages/subgraph-service/test/disputeManager/disputes/query/cancel.t.sol +++ b/packages/subgraph-service/test/disputeManager/disputes/query/cancel.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity 0.8.26; +pragma solidity 0.8.27; import "forge-std/Test.sol"; diff --git a/packages/subgraph-service/test/disputeManager/disputes/query/create.t.sol b/packages/subgraph-service/test/disputeManager/disputes/query/create.t.sol index 01f27cf66..4eba11744 100644 --- a/packages/subgraph-service/test/disputeManager/disputes/query/create.t.sol +++ b/packages/subgraph-service/test/disputeManager/disputes/query/create.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity 0.8.26; +pragma solidity 0.8.27; import "forge-std/Test.sol"; diff --git a/packages/subgraph-service/test/disputeManager/disputes/query/draw.t.sol b/packages/subgraph-service/test/disputeManager/disputes/query/draw.t.sol index 1b9c96ad2..2ff182378 100644 --- a/packages/subgraph-service/test/disputeManager/disputes/query/draw.t.sol +++ b/packages/subgraph-service/test/disputeManager/disputes/query/draw.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity 0.8.26; +pragma solidity 0.8.27; import "forge-std/Test.sol"; diff --git a/packages/subgraph-service/test/disputeManager/disputes/query/reject.t.sol b/packages/subgraph-service/test/disputeManager/disputes/query/reject.t.sol index 07c738a90..fff210ea6 100644 --- a/packages/subgraph-service/test/disputeManager/disputes/query/reject.t.sol +++ b/packages/subgraph-service/test/disputeManager/disputes/query/reject.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity 0.8.26; +pragma solidity 0.8.27; import "forge-std/Test.sol"; diff --git a/packages/subgraph-service/test/disputeManager/disputes/queryConflict/accept.t.sol b/packages/subgraph-service/test/disputeManager/disputes/queryConflict/accept.t.sol index 1cfde0a8c..46a6d4bdd 100644 --- a/packages/subgraph-service/test/disputeManager/disputes/queryConflict/accept.t.sol +++ b/packages/subgraph-service/test/disputeManager/disputes/queryConflict/accept.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity 0.8.26; +pragma solidity 0.8.27; import "forge-std/Test.sol"; diff --git a/packages/subgraph-service/test/disputeManager/disputes/queryConflict/cancel.t.sol b/packages/subgraph-service/test/disputeManager/disputes/queryConflict/cancel.t.sol index 4de2b3155..36d14fab2 100644 --- a/packages/subgraph-service/test/disputeManager/disputes/queryConflict/cancel.t.sol +++ b/packages/subgraph-service/test/disputeManager/disputes/queryConflict/cancel.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity 0.8.26; +pragma solidity 0.8.27; import "forge-std/Test.sol"; diff --git a/packages/subgraph-service/test/disputeManager/disputes/queryConflict/create.t.sol b/packages/subgraph-service/test/disputeManager/disputes/queryConflict/create.t.sol index 2f54983ae..edd2d545b 100644 --- a/packages/subgraph-service/test/disputeManager/disputes/queryConflict/create.t.sol +++ b/packages/subgraph-service/test/disputeManager/disputes/queryConflict/create.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity 0.8.26; +pragma solidity 0.8.27; import "forge-std/Test.sol"; diff --git a/packages/subgraph-service/test/disputeManager/disputes/queryConflict/draw.t.sol b/packages/subgraph-service/test/disputeManager/disputes/queryConflict/draw.t.sol index 5127b56a5..5444936cc 100644 --- a/packages/subgraph-service/test/disputeManager/disputes/queryConflict/draw.t.sol +++ b/packages/subgraph-service/test/disputeManager/disputes/queryConflict/draw.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity 0.8.26; +pragma solidity 0.8.27; import "forge-std/Test.sol"; diff --git a/packages/subgraph-service/test/disputeManager/disputes/queryConflict/reject.t.sol b/packages/subgraph-service/test/disputeManager/disputes/queryConflict/reject.t.sol index 078969267..ff347f7d2 100644 --- a/packages/subgraph-service/test/disputeManager/disputes/queryConflict/reject.t.sol +++ b/packages/subgraph-service/test/disputeManager/disputes/queryConflict/reject.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity 0.8.26; +pragma solidity 0.8.27; import "forge-std/Test.sol"; diff --git a/packages/subgraph-service/test/disputeManager/governance/arbitrator.t.sol b/packages/subgraph-service/test/disputeManager/governance/arbitrator.t.sol index 53e36a497..1277235fd 100644 --- a/packages/subgraph-service/test/disputeManager/governance/arbitrator.t.sol +++ b/packages/subgraph-service/test/disputeManager/governance/arbitrator.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity 0.8.26; +pragma solidity 0.8.27; import "forge-std/Test.sol"; diff --git a/packages/subgraph-service/test/disputeManager/governance/disputeDeposit.t.sol b/packages/subgraph-service/test/disputeManager/governance/disputeDeposit.t.sol index 163157886..1df13acb2 100644 --- a/packages/subgraph-service/test/disputeManager/governance/disputeDeposit.t.sol +++ b/packages/subgraph-service/test/disputeManager/governance/disputeDeposit.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity 0.8.26; +pragma solidity 0.8.27; import "forge-std/Test.sol"; diff --git a/packages/subgraph-service/test/disputeManager/governance/maxSlashingCut.t.sol b/packages/subgraph-service/test/disputeManager/governance/maxSlashingCut.t.sol index 343e514bc..a554f774c 100644 --- a/packages/subgraph-service/test/disputeManager/governance/maxSlashingCut.t.sol +++ b/packages/subgraph-service/test/disputeManager/governance/maxSlashingCut.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity 0.8.26; +pragma solidity 0.8.27; import "forge-std/Test.sol"; diff --git a/packages/subgraph-service/test/shared/HorizonStakingShared.t.sol b/packages/subgraph-service/test/shared/HorizonStakingShared.t.sol index 28a22e1a2..e07516903 100644 --- a/packages/subgraph-service/test/shared/HorizonStakingShared.t.sol +++ b/packages/subgraph-service/test/shared/HorizonStakingShared.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity 0.8.26; +pragma solidity 0.8.27; import "forge-std/Test.sol"; diff --git a/packages/subgraph-service/test/subgraphService/SubgraphService.t.sol b/packages/subgraph-service/test/subgraphService/SubgraphService.t.sol index e9c3d5529..05c038680 100644 --- a/packages/subgraph-service/test/subgraphService/SubgraphService.t.sol +++ b/packages/subgraph-service/test/subgraphService/SubgraphService.t.sol @@ -30,7 +30,7 @@ contract SubgraphServiceTest is SubgraphServiceSharedTest { * MODIFIERS */ - modifier useOperator { + modifier useOperator() { resetPrank(users.indexer); staking.setOperator(users.operator, address(subgraphService), true); resetPrank(users.operator); @@ -38,7 +38,7 @@ contract SubgraphServiceTest is SubgraphServiceSharedTest { vm.stopPrank(); } - modifier useRewardsDestination { + modifier useRewardsDestination() { _setRewardsDestination(users.rewardsDestination); _; } @@ -74,10 +74,10 @@ contract SubgraphServiceTest is SubgraphServiceSharedTest { uint64 thawingPeriod = provision.thawingPeriod; uint32 maxVerifierCutPending = provision.maxVerifierCutPending; uint64 thawingPeriodPending = provision.thawingPeriodPending; - + vm.expectEmit(address(subgraphService)); emit IDataService.ProvisionAccepted(_indexer); - + // Accept provision subgraphService.acceptProvision(_indexer, _data); @@ -110,7 +110,13 @@ contract SubgraphServiceTest is SubgraphServiceSharedTest { } vm.expectEmit(address(subgraphService)); - emit AllocationManager.AllocationResized(_indexer, _allocationId, subgraphDeploymentId, _tokens, beforeSubgraphAllocatedTokens); + emit AllocationManager.AllocationResized( + _indexer, + _allocationId, + subgraphDeploymentId, + _tokens, + beforeSubgraphAllocatedTokens + ); // resize allocation subgraphService.resizeAllocation(_indexer, _allocationId, _tokens); @@ -119,8 +125,12 @@ contract SubgraphServiceTest is SubgraphServiceSharedTest { uint256 afterSubgraphAllocatedTokens = subgraphService.getSubgraphAllocatedTokens(subgraphDeploymentId); uint256 afterAllocatedTokens = subgraphService.allocationProvisionTracker(_indexer); Allocation.State memory afterAllocation = subgraphService.getAllocation(_allocationId); - uint256 accRewardsPerAllocatedTokenDelta = afterAllocation.accRewardsPerAllocatedToken - beforeAllocation.accRewardsPerAllocatedToken; - uint256 afterAccRewardsPending = rewardsManager.calcRewards(beforeAllocation.tokens, accRewardsPerAllocatedTokenDelta); + uint256 accRewardsPerAllocatedTokenDelta = afterAllocation.accRewardsPerAllocatedToken - + beforeAllocation.accRewardsPerAllocatedToken; + uint256 afterAccRewardsPending = rewardsManager.calcRewards( + beforeAllocation.tokens, + accRewardsPerAllocatedTokenDelta + ); // check state if (_tokens > beforeAllocation.tokens) { @@ -138,10 +148,17 @@ contract SubgraphServiceTest is SubgraphServiceSharedTest { assertTrue(subgraphService.isActiveAllocation(_allocationId)); Allocation.State memory allocation = subgraphService.getAllocation(_allocationId); - uint256 previousSubgraphAllocatedTokens = subgraphService.getSubgraphAllocatedTokens(allocation.subgraphDeploymentId); - + uint256 previousSubgraphAllocatedTokens = subgraphService.getSubgraphAllocatedTokens( + allocation.subgraphDeploymentId + ); + vm.expectEmit(address(subgraphService)); - emit AllocationManager.AllocationClosed(allocation.indexer, _allocationId, allocation.subgraphDeploymentId, allocation.tokens); + emit AllocationManager.AllocationClosed( + allocation.indexer, + _allocationId, + allocation.subgraphDeploymentId, + allocation.tokens + ); // close stale allocation subgraphService.closeStaleAllocation(_allocationId); @@ -182,15 +199,20 @@ contract SubgraphServiceTest is SubgraphServiceSharedTest { uint256 paymentCollected = 0; Allocation.State memory allocation; CollectPaymentData memory collectPaymentDataBefore; - + // PaymentType.IndexingRewards variables IndexingRewardsData memory indexingRewardsData; - uint32 delegationRatio = subgraphService.delegationRatio(); address rewardsDestination = subgraphService.rewardsDestination(_indexer); collectPaymentDataBefore.rewardsDestinationBalance = token.balanceOf(rewardsDestination); - collectPaymentDataBefore.indexerProvisionBalance = staking.getProviderTokensAvailable(_indexer, address(subgraphService)); - collectPaymentDataBefore.delegationPoolBalance = staking.getDelegatedTokensAvailable(_indexer, address(subgraphService)); - + collectPaymentDataBefore.indexerProvisionBalance = staking.getProviderTokensAvailable( + _indexer, + address(subgraphService) + ); + collectPaymentDataBefore.delegationPoolBalance = staking.getDelegatedTokensAvailable( + _indexer, + address(subgraphService) + ); + // PaymentType.QueryFee variables QueryFeeData memory queryFeeData; queryFeeData.protocolPaymentCut = graphPayments.PROTOCOL_PAYMENT_CUT(); @@ -257,25 +279,38 @@ contract SubgraphServiceTest is SubgraphServiceSharedTest { // Collect payment data after CollectPaymentData memory collectPaymentDataAfter; collectPaymentDataAfter.rewardsDestinationBalance = token.balanceOf(rewardsDestination); - collectPaymentDataAfter.indexerProvisionBalance = staking.getProviderTokensAvailable(_indexer, address(subgraphService)); - collectPaymentDataAfter.delegationPoolBalance = staking.getDelegatedTokensAvailable(_indexer, address(subgraphService)); + collectPaymentDataAfter.indexerProvisionBalance = staking.getProviderTokensAvailable( + _indexer, + address(subgraphService) + ); + collectPaymentDataAfter.delegationPoolBalance = staking.getDelegatedTokensAvailable( + _indexer, + address(subgraphService) + ); collectPaymentDataAfter.indexerBalance = token.balanceOf(_indexer); collectPaymentDataAfter.curationBalance = token.balanceOf(address(curation)); collectPaymentDataAfter.lockedTokens = subgraphService.feesProvisionTracker(_indexer); if (_paymentType == IGraphPayments.PaymentTypes.QueryFee) { // Check indexer got paid the correct amount - uint256 tokensProtocol = paymentCollected.mulPPM(protocolPaymentCut); - uint256 curationTokens = paymentCollected.mulPPM(queryFeeData.curationCut); - uint256 expectedIndexerTokensPayment = paymentCollected - tokensProtocol - curationTokens; - assertEq(collectPaymentDataAfter.indexerBalance, collectPaymentDataBefore.indexerBalance + expectedIndexerTokensPayment); + { + uint256 tokensProtocol = paymentCollected.mulPPM(protocolPaymentCut); + uint256 curationTokens = paymentCollected.mulPPM(queryFeeData.curationCut); + uint256 expectedIndexerTokensPayment = paymentCollected - tokensProtocol - curationTokens; + assertEq( + collectPaymentDataAfter.indexerBalance, + collectPaymentDataBefore.indexerBalance + expectedIndexerTokensPayment + ); - // Check curation got paid the correct amount - assertEq(collectPaymentDataAfter.curationBalance, collectPaymentDataBefore.curationBalance + curationTokens); + // Check curation got paid the correct amount + assertEq( + collectPaymentDataAfter.curationBalance, + collectPaymentDataBefore.curationBalance + curationTokens + ); + } // Check locked tokens - uint256 stakeToFeesRatio = subgraphService.stakeToFeesRatio(); - uint256 tokensToLock = paymentCollected * stakeToFeesRatio; + uint256 tokensToLock = paymentCollected * subgraphService.stakeToFeesRatio(); assertEq(collectPaymentDataAfter.lockedTokens, collectPaymentDataBefore.lockedTokens + tokensToLock); // Check the stake claim @@ -290,10 +325,12 @@ contract SubgraphServiceTest is SubgraphServiceSharedTest { } else { // Update allocation after collecting rewards allocation = subgraphService.getAllocation(allocationId); - + // Check allocation state assertEq(allocation.accRewardsPending, 0); - uint256 accRewardsPerAllocatedToken = rewardsManager.onSubgraphAllocationUpdate(allocation.subgraphDeploymentId); + uint256 accRewardsPerAllocatedToken = rewardsManager.onSubgraphAllocationUpdate( + allocation.subgraphDeploymentId + ); assertEq(allocation.accRewardsPerAllocatedToken, accRewardsPerAllocatedToken); assertEq(allocation.lastPOIPresentedAt, block.timestamp); @@ -301,7 +338,7 @@ contract SubgraphServiceTest is SubgraphServiceSharedTest { if (rewardsDestination == address(0)) { // If rewards destination is address zero indexer should get paid to their provision balance assertEq( - collectPaymentDataAfter.indexerProvisionBalance, + collectPaymentDataAfter.indexerProvisionBalance, collectPaymentDataBefore.indexerProvisionBalance + indexingRewardsData.tokensIndexerRewards ); } else { @@ -314,12 +351,16 @@ contract SubgraphServiceTest is SubgraphServiceSharedTest { // Check delegation pool got paid the correct amount assertEq( - collectPaymentDataAfter.delegationPoolBalance, + collectPaymentDataAfter.delegationPoolBalance, collectPaymentDataBefore.delegationPoolBalance + indexingRewardsData.tokensDelegationRewards ); // If after collecting indexing rewards the indexer is over allocated the allcation should close - uint256 tokensAvailable = staking.getTokensAvailable(_indexer, address(subgraphService), delegationRatio); + uint256 tokensAvailable = staking.getTokensAvailable( + _indexer, + address(subgraphService), + subgraphService.delegationRatio() + ); if (allocation.tokens <= tokensAvailable) { // Indexer isn't over allocated so allocation should still be open assertTrue(allocation.isOpen()); diff --git a/packages/subgraph-service/test/subgraphService/allocation/closeStale.t.sol b/packages/subgraph-service/test/subgraphService/allocation/closeStale.t.sol index 3e6672dd7..68d736261 100644 --- a/packages/subgraph-service/test/subgraphService/allocation/closeStale.t.sol +++ b/packages/subgraph-service/test/subgraphService/allocation/closeStale.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity 0.8.26; +pragma solidity 0.8.27; import "forge-std/Test.sol"; diff --git a/packages/subgraph-service/test/subgraphService/allocation/resize.t.sol b/packages/subgraph-service/test/subgraphService/allocation/resize.t.sol index 3da7c5a0c..0df994929 100644 --- a/packages/subgraph-service/test/subgraphService/allocation/resize.t.sol +++ b/packages/subgraph-service/test/subgraphService/allocation/resize.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity 0.8.26; +pragma solidity 0.8.27; import "forge-std/Test.sol"; diff --git a/packages/subgraph-service/test/subgraphService/allocation/start.t.sol b/packages/subgraph-service/test/subgraphService/allocation/start.t.sol index 6db5e73db..9157444fb 100644 --- a/packages/subgraph-service/test/subgraphService/allocation/start.t.sol +++ b/packages/subgraph-service/test/subgraphService/allocation/start.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity 0.8.26; +pragma solidity 0.8.27; import "forge-std/Test.sol"; diff --git a/packages/subgraph-service/test/subgraphService/collect/indexing/indexing.t.sol b/packages/subgraph-service/test/subgraphService/collect/indexing/indexing.t.sol index d51f9ea4b..8b29ec830 100644 --- a/packages/subgraph-service/test/subgraphService/collect/indexing/indexing.t.sol +++ b/packages/subgraph-service/test/subgraphService/collect/indexing/indexing.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity 0.8.26; +pragma solidity 0.8.27; import "forge-std/Test.sol"; diff --git a/packages/subgraph-service/test/subgraphService/collect/query/query.t.sol b/packages/subgraph-service/test/subgraphService/collect/query/query.t.sol index 9e20ad352..6ad7b5347 100644 --- a/packages/subgraph-service/test/subgraphService/collect/query/query.t.sol +++ b/packages/subgraph-service/test/subgraphService/collect/query/query.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity 0.8.26; +pragma solidity 0.8.27; import "forge-std/Test.sol"; diff --git a/packages/subgraph-service/test/subgraphService/provider/rewardsDestination.t.sol b/packages/subgraph-service/test/subgraphService/provider/rewardsDestination.t.sol index 3926bc362..0b4c805b2 100644 --- a/packages/subgraph-service/test/subgraphService/provider/rewardsDestination.t.sol +++ b/packages/subgraph-service/test/subgraphService/provider/rewardsDestination.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity 0.8.26; +pragma solidity 0.8.27; import "forge-std/Test.sol";