diff --git a/packages/horizon/contracts/interfaces/internal/IHorizonStakingMain.sol b/packages/horizon/contracts/interfaces/internal/IHorizonStakingMain.sol index 264005e8a..a934ac667 100644 --- a/packages/horizon/contracts/interfaces/internal/IHorizonStakingMain.sol +++ b/packages/horizon/contracts/interfaces/internal/IHorizonStakingMain.sol @@ -362,6 +362,13 @@ interface IHorizonStakingMain { */ error HorizonStakingNotAuthorized(address serviceProvider, address verifier, address caller); + /** + * @notice Thrown when attempting to create a provision with a verifier other than the + * subgraph data service. This restriction only applies during the transition period. + * @param verifier The verifier address + */ + error HorizonStakingInvalidVerifier(address verifier); + /** * @notice Thrown when attempting to create a provision with an invalid maximum verifier cut. * @param maxVerifierCut The maximum verifier cut @@ -562,6 +569,8 @@ interface IHorizonStakingMain { * service, where the data service is the verifier. * This function can be called by the service provider or by an operator authorized by the provider * for this specific verifier. + * @dev During the transition period, only the subgraph data service can be used as a verifier. This + * prevents an escape hatch for legacy allocation stake. * @dev Requirements: * - `tokens` cannot be zero. * - The `serviceProvider` must have enough idle stake to cover the tokens to provision. diff --git a/packages/horizon/contracts/staking/HorizonStaking.sol b/packages/horizon/contracts/staking/HorizonStaking.sol index 9c523d97e..9002bce8c 100644 --- a/packages/horizon/contracts/staking/HorizonStaking.sol +++ b/packages/horizon/contracts/staking/HorizonStaking.sol @@ -720,6 +720,11 @@ contract HorizonStaking is HorizonStakingBase, IHorizonStakingMain { uint64 _thawingPeriod ) private { require(_tokens > 0, HorizonStakingInvalidZeroTokens()); + // TODO: Remove this after the transition period - it prevents an early escape hatch for legacy allocations + require( + _verifier == SUBGRAPH_DATA_SERVICE_ADDRESS || __DEPRECATED_thawingPeriod == 0, + HorizonStakingInvalidVerifier(_verifier) + ); require(PPMMath.isValidPPM(_maxVerifierCut), HorizonStakingInvalidMaxVerifierCut(_maxVerifierCut)); require( _thawingPeriod <= _maxThawingPeriod, diff --git a/packages/horizon/hardhat.config.ts b/packages/horizon/hardhat.config.ts index 9b726a2ec..494de23d5 100644 --- a/packages/horizon/hardhat.config.ts +++ b/packages/horizon/hardhat.config.ts @@ -22,7 +22,7 @@ const config: HardhatUserConfig = { settings: { optimizer: { enabled: true, - runs: 70, + runs: 20, }, }, }, diff --git a/packages/horizon/test/staking/provision/parameters.t.sol b/packages/horizon/test/staking/provision/parameters.t.sol index 589dd4fc3..6e0b4fabf 100644 --- a/packages/horizon/test/staking/provision/parameters.t.sol +++ b/packages/horizon/test/staking/provision/parameters.t.sol @@ -82,7 +82,6 @@ contract HorizonStakingProvisionParametersTest is HorizonStakingTest { vm.stopPrank(); } - function test_ProvisionParametersAccept_SameParameters( uint256 amount, uint32 maxVerifierCut, diff --git a/packages/horizon/test/staking/provision/provision.t.sol b/packages/horizon/test/staking/provision/provision.t.sol index 81ed628fd..ba580be25 100644 --- a/packages/horizon/test/staking/provision/provision.t.sol +++ b/packages/horizon/test/staking/provision/provision.t.sol @@ -108,4 +108,20 @@ contract HorizonStakingProvisionTest is HorizonStakingTest { vm.expectRevert(expectedError); staking.provision(users.indexer, subgraphDataServiceAddress, amount, maxVerifierCut, thawingPeriod); } + + function testProvision_RevertWhen_VerifierIsNotSubgraphDataServiceDuringTransitionPeriod( + uint256 amount + ) public useIndexer useStake(amount) { + // simulate the transition period + _setStorage_DeprecatedThawingPeriod(THAWING_PERIOD_IN_BLOCKS); + + // oddly we use subgraphDataServiceLegacyAddress as the subgraph service address + // so subgraphDataServiceAddress is not the subgraph service ¯\_(ツ)_/¯ + bytes memory expectedError = abi.encodeWithSignature( + "HorizonStakingInvalidVerifier(address)", + subgraphDataServiceAddress + ); + vm.expectRevert(expectedError); + staking.provision(users.indexer, subgraphDataServiceAddress, amount, 0, 0); + } } diff --git a/packages/horizon/test/staking/stake/unstake.t.sol b/packages/horizon/test/staking/stake/unstake.t.sol index 13ea92e00..83c6a0a81 100644 --- a/packages/horizon/test/staking/stake/unstake.t.sol +++ b/packages/horizon/test/staking/stake/unstake.t.sol @@ -62,10 +62,10 @@ contract HorizonStakingUnstakeTest is HorizonStakingTest { _setStorage_ServiceProvider(users.indexer, tokensLocked, 0, tokensLocked, block.number, 0); // create provision, thaw and deprovision - _createProvision(users.indexer, subgraphDataServiceAddress, tokens, 0, MAX_THAWING_PERIOD); - _thaw(users.indexer, subgraphDataServiceAddress, tokens); + _createProvision(users.indexer, subgraphDataServiceLegacyAddress, tokens, 0, MAX_THAWING_PERIOD); + _thaw(users.indexer, subgraphDataServiceLegacyAddress, tokens); skip(MAX_THAWING_PERIOD + 1); - _deprovision(users.indexer, subgraphDataServiceAddress, 0); + _deprovision(users.indexer, subgraphDataServiceLegacyAddress, 0); // unstake _unstake(tokensToUnstake); @@ -90,10 +90,10 @@ contract HorizonStakingUnstakeTest is HorizonStakingTest { _setStorage_ServiceProvider(users.indexer, tokensThawing, 0, tokensThawing, tokensThawingUntilBlock, 0); // create provision, thaw and deprovision - _createProvision(users.indexer, subgraphDataServiceAddress, tokens, 0, MAX_THAWING_PERIOD); - _thaw(users.indexer, subgraphDataServiceAddress, tokens); + _createProvision(users.indexer, subgraphDataServiceLegacyAddress, tokens, 0, MAX_THAWING_PERIOD); + _thaw(users.indexer, subgraphDataServiceLegacyAddress, tokens); skip(MAX_THAWING_PERIOD + 1); - _deprovision(users.indexer, subgraphDataServiceAddress, 0); + _deprovision(users.indexer, subgraphDataServiceLegacyAddress, 0); // unstake _unstake(tokensToUnstake);