From 4973ecd7b8d573ab9aae411c6b7d50f7b808184e Mon Sep 17 00:00:00 2001 From: Pablo Carranza Velez Date: Tue, 14 May 2024 15:13:06 -0300 Subject: [PATCH] fix: various fixes and a bit of cleanup --- packages/horizon/contracts/HorizonStaking.sol | 197 +++++++++++++----- .../contracts/HorizonStakingExtension.sol | 43 +++- .../contracts/HorizonStakingStorage.sol | 6 +- .../horizon/contracts/IHorizonStakingBase.sol | 3 + .../contracts/IHorizonStakingExtension.sol | 16 +- .../contracts/IHorizonStakingTypes.sol | 10 +- .../StakingBackwardsCompatibility.sol | 4 +- packages/horizon/hardhat.config.ts | 10 +- 8 files changed, 232 insertions(+), 57 deletions(-) diff --git a/packages/horizon/contracts/HorizonStaking.sol b/packages/horizon/contracts/HorizonStaking.sol index 75be4377f..560d509bf 100644 --- a/packages/horizon/contracts/HorizonStaking.sol +++ b/packages/horizon/contracts/HorizonStaking.sol @@ -11,10 +11,21 @@ import { Managed } from "./Managed.sol"; import { IGraphToken } from "./IGraphToken.sol"; import { HorizonStakingV1Storage } from "./HorizonStakingStorage.sol"; +/** + * @title HorizonStaking contract + * @dev This contract is the main Staking contract in The Graph protocol after Horizon. + * It is designed to be deployed as an upgrade to the L2Staking contract from the legacy contracts + * package. + * It uses an HorizonStakingExtension contract to implement the full IHorizonStaking interface through delegatecalls. + * This is due to the contract size limit on Arbitrum (24kB like mainnet). + */ contract HorizonStaking is HorizonStakingV1Storage, IHorizonStakingBase, GraphUpgradeable { + /// @dev 100% in parts per million + uint32 internal constant MAX_PPM = 1000000; + /// Maximum value that can be set as the maxVerifierCut in a provision. /// It is equivalent to 100% in parts-per-million - uint32 private constant MAX_MAX_VERIFIER_CUT = 1000000; // 50% + uint32 private constant MAX_MAX_VERIFIER_CUT = 1000000; // 100% /// Minimum size of a provision uint256 private constant MIN_PROVISION_SIZE = 1e18; @@ -37,6 +48,17 @@ contract HorizonStaking is HorizonStakingV1Storage, IHorizonStakingBase, GraphUp error HorizonStakingInvalidProvision(address serviceProvider, address verifier); error HorizonStakingNotAuthorized(address caller, address serviceProvider, address verifier); error HorizonStakingInsufficientCapacity(); + error HorizonStakingInsufficientShares(); + error HorizonStakingInsufficientCapacityForLegacyAllocations(); + error HorizonStakingTooManyThawRequests(); + error HorizonStakingInsufficientTokens(uint256 expected, uint256 available); + + modifier onlyAuthorized(address _serviceProvider, address _verifier) { + if (!isAuthorized(msg.sender, _serviceProvider, _verifier)) { + revert HorizonStakingNotAuthorized(msg.sender, _serviceProvider, _verifier); + } + _; + } constructor( address _controller, @@ -107,31 +129,41 @@ contract HorizonStaking is HorizonStakingV1Storage, IHorizonStakingBase, GraphUp _stake(_serviceProvider, _tokens); } - // can be called by anyone if the indexer has provisioned stake to this verifier + /** + * @notice Deposit tokens on the service provider stake, on behalf of the service provider, provisioned + * to a specific verifier. The provider must have previously provisioned stake to that verifier. + * @param _serviceProvider Address of the indexer + * @param _verifier Address of the verifier + * @param _tokens Amount of tokens to stake + */ function stakeToProvision( address _serviceProvider, address _verifier, uint256 _tokens ) external override notPartialPaused { - Provision storage prov = provisions[_serviceProvider][_verifier]; - if (prov.tokens == 0) { - revert HorizonStakingInvalidProvision(_serviceProvider, _verifier); - } stakeTo(_serviceProvider, _tokens); _addToProvision(_serviceProvider, _verifier, _tokens); } - // create a provision + /** + * @notice Provision stake to a verifier. The tokens will be locked with a thawing period + * and will be slashable by the verifier. This is the main mechanism to provision stake to a data + * 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. + * @param _serviceProvider The service provider address + * @param _verifier The verifier address for which the tokens are provisioned (who will be able to slash the tokens) + * @param _tokens The amount of tokens that will be locked and slashable + * @param _maxVerifierCut The maximum cut, expressed in PPM, that a verifier can transfer instead of burning when slashing + * @param _thawingPeriod The period in seconds that the tokens will be thawing before they can be removed from the provision + */ function provision( address _serviceProvider, address _verifier, uint256 _tokens, uint32 _maxVerifierCut, uint64 _thawingPeriod - ) external override notPartialPaused { - if (!isAuthorized(msg.sender, _serviceProvider, _verifier)) { - revert HorizonStakingNotAuthorized(msg.sender, _serviceProvider, _verifier); - } + ) external override notPartialPaused onlyAuthorized(_serviceProvider, _verifier) { if (getIdleStake(_serviceProvider) < _tokens) { revert HorizonStakingInsufficientCapacity(); } @@ -139,24 +171,38 @@ contract HorizonStaking is HorizonStakingV1Storage, IHorizonStakingBase, GraphUp _createProvision(_serviceProvider, _tokens, _verifier, _maxVerifierCut, _thawingPeriod); } - // add more tokens from idle stake to an existing provision + /** + * @notice Add more tokens to an existing provision. + * This function can be called by the service provider or by an operator authorized by the provider + * for this specific verifier. + * @param _serviceProvider The service provider address + * @param _verifier The verifier address for which the tokens are provisioned + * @param _tokens The amount of tokens to add to the provision + */ function addToProvision( address _serviceProvider, address _verifier, uint256 _tokens - ) external override notPartialPaused { - require(isAuthorized(msg.sender, _serviceProvider, _verifier), "!auth"); + ) external override notPartialPaused onlyAuthorized(_serviceProvider, _verifier) { _addToProvision(_serviceProvider, _verifier, _tokens); } - // initiate a thawing to remove tokens from a provision + /** + * @notice Start thawing tokens to remove them from a provision. + * This function can be called by the service provider or by an operator authorized by the provider + * for this specific verifier. + * @param _serviceProvider The service provider address + * @param _verifier The verifier address for which the tokens are provisioned + * @param _tokens The amount of tokens to thaw + */ function thaw( address _serviceProvider, address _verifier, uint256 _tokens - ) external override notPartialPaused returns (bytes32) { - require(isAuthorized(msg.sender, _serviceProvider, _verifier), "!auth"); - require(_tokens > 0, "!tokens"); + ) external override notPartialPaused onlyAuthorized(_serviceProvider, _verifier) returns (bytes32) { + if (_tokens == 0) { + revert HorizonStakingInvalidZeroTokens(); + } Provision storage prov = provisions[_serviceProvider][_verifier]; ServiceProviderInternal storage serviceProvider = serviceProviders[_serviceProvider]; bytes32 thawRequestId = keccak256( @@ -168,11 +214,18 @@ contract HorizonStaking is HorizonStakingV1Storage, IHorizonStakingBase, GraphUp require(getProviderTokensAvailable(_serviceProvider, _verifier) >= _tokens, "insufficient tokens available"); prov.tokensThawing = prov.tokensThawing + _tokens; - thawRequest.shares = (prov.sharesThawing * _tokens) / prov.tokensThawing; + if (prov.sharesThawing == 0) { + thawRequest.shares = _tokens; + } else { + thawRequest.shares = (prov.sharesThawing * _tokens) / prov.tokensThawing; + } + thawRequest.thawingUntil = uint64(block.timestamp + uint256(prov.thawingPeriod)); prov.sharesThawing = prov.sharesThawing + thawRequest.shares; - require(prov.nThawRequests < MAX_THAW_REQUESTS, "max thaw requests"); + if (prov.nThawRequests >= MAX_THAW_REQUESTS) { + revert HorizonStakingTooManyThawRequests(); + } if (prov.nThawRequests == 0) { prov.firstThawRequestId = thawRequestId; } else { @@ -217,39 +270,62 @@ contract HorizonStaking is HorizonStakingV1Storage, IHorizonStakingBase, GraphUp uint256 _tokens ) external override notPartialPaused { require(isAuthorized(msg.sender, _serviceProvider, _verifier), "!auth"); - require(_tokens > 0, "!tokens"); - ServiceProviderInternal storage serviceProvider = serviceProviders[_serviceProvider]; + if (_tokens == 0) { + revert HorizonStakingInvalidZeroTokens(); + } _fulfillThawRequests(_serviceProvider, _verifier, _tokens); - serviceProvider.tokensProvisioned = serviceProvider.tokensProvisioned - _tokens; } - // moves thawed stake from one provision into another provision + /** + * @notice Move already thawed stake from one provision into another provision + * This function can be called by the service provider or by an operator authorized by the provider + * for the two corresponding verifiers. + * The provider must have previously provisioned tokens to the new verifier. + * @param _serviceProvider The service provider address + * @param _oldVerifier The verifier address for which the tokens are currently provisioned + * @param _newVerifier The verifier address for which the tokens will be provisioned + * @param _tokens The amount of tokens to move + */ function reprovision( address _serviceProvider, address _oldVerifier, address _newVerifier, uint256 _tokens - ) external override notPartialPaused { - require(isAuthorized(msg.sender, _serviceProvider, _oldVerifier), "!auth"); - require(isAuthorized(msg.sender, _serviceProvider, _newVerifier), "!auth"); - require(_tokens > 0, "!tokens"); - + ) + external + override + notPartialPaused + onlyAuthorized(_serviceProvider, _oldVerifier) + onlyAuthorized(_serviceProvider, _newVerifier) + { _fulfillThawRequests(_serviceProvider, _oldVerifier, _tokens); _addToProvision(_serviceProvider, _newVerifier, _tokens); } - // moves idle stake back to the owner's account - stake is removed from the protocol + /** + * @notice Move idle stake back to the owner's account. + * If tokens were thawing they must be deprovisioned first. + * Stake is removed from the protocol. + * @param _tokens Amount of tokens to unstake + */ function unstake(uint256 _tokens) external override notPaused { address serviceProvider = msg.sender; - require(_tokens > 0, "!tokens"); - require(getIdleStake(serviceProvider) >= _tokens, "insufficient idle stake"); + if (_tokens == 0) { + revert HorizonStakingInvalidZeroTokens(); + } + if (getIdleStake(serviceProvider) < _tokens) { + revert HorizonStakingInsufficientCapacity(); + } ServiceProviderInternal storage sp = serviceProviders[serviceProvider]; uint256 stakedTokens = sp.tokensStaked; - // Check that the indexer's stake minus + // Check that the indexer's stake minus the tokens to unstake is sufficient + // to cover existing allocations // TODO this is only needed until legacy allocations are closed, // so we should remove it after the transition period - require((stakedTokens - _tokens) >= sp.__DEPRECATED_tokensAllocated, "!stake-avail"); + if ((stakedTokens - _tokens) < sp.__DEPRECATED_tokensAllocated) { + revert HorizonStakingInsufficientCapacityForLegacyAllocations(); + } // This is also only during the transition period: we need // to ensure tokens stay locked after closing legacy allocations. @@ -283,10 +359,16 @@ contract HorizonStaking is HorizonStakingV1Storage, IHorizonStakingBase, GraphUp } } - // slash a service provider - // (called by a verifier) - // if delegation slashing is disabled and it would've happened, - // this is skipped rather than reverting + /** + * @notice Slash a service provider. This can only be called by a verifier to which + * the provider has provisioned stake, and up to the amount of tokens they have provisioned. + * @dev If delegation slashing is disabled, and the amount of tokens is more than the + * provider's provisioned self-stake, the delegation slashing is skipped without reverting. + * @param _serviceProvider The service provider to slash + * @param _tokens The amount of tokens to slash + * @param _verifierCutAmount The amount of tokens to transfer instead of burning + * @param _verifierCutDestination The address to transfer the verifier cut to + */ function slash( address _serviceProvider, uint256 _tokens, @@ -295,12 +377,14 @@ contract HorizonStaking is HorizonStakingV1Storage, IHorizonStakingBase, GraphUp ) external override notPartialPaused { address verifier = msg.sender; Provision storage prov = provisions[_serviceProvider][verifier]; - require(prov.tokens >= _tokens, "insufficient tokens in provision"); + if (prov.tokens < _tokens) { + revert HorizonStakingInsufficientTokens(_tokens, prov.tokens); + } uint256 tokensToSlash = _tokens; uint256 providerTokensSlashed = MathUtils.min(prov.tokens, tokensToSlash); - require((prov.tokens * prov.maxVerifierCut) / 1e6 >= _verifierCutAmount, "verifier cut too high"); + require((prov.tokens * prov.maxVerifierCut) / MAX_PPM >= _verifierCutAmount, "verifier cut too high"); if (_verifierCutAmount > 0) { TokenUtils.pushTokens(_graphToken(), _verifierCutDestination, _verifierCutAmount); emit VerifierCutSent(_serviceProvider, verifier, _verifierCutDestination, _verifierCutAmount); @@ -324,7 +408,7 @@ contract HorizonStaking is HorizonStakingV1Storage, IHorizonStakingBase, GraphUp tokensToSlash = tokensToSlash - providerTokensSlashed; if (tokensToSlash > 0) { - DelegationPool storage pool; + DelegationPoolInternal storage pool; if (verifier == SUBGRAPH_DATA_SERVICE_ADDRESS) { pool = legacyDelegationPools[_serviceProvider]; } else { @@ -377,7 +461,10 @@ contract HorizonStaking is HorizonStakingV1Storage, IHorizonStakingBase, GraphUp // provisioned tokens from the service provider that are not being thawed // `Provision.tokens - Provision.tokensThawing` - function getProviderTokensAvailable(address _serviceProvider, address _verifier) public view returns (uint256) { + function getProviderTokensAvailable( + address _serviceProvider, + address _verifier + ) public view override returns (uint256) { return provisions[_serviceProvider][_verifier].tokens - provisions[_serviceProvider][_verifier].tokensThawing; } @@ -417,7 +504,7 @@ contract HorizonStaking is HorizonStakingV1Storage, IHorizonStakingBase, GraphUp // Only allow delegations over a minimum, to prevent rounding attacks require(_tokens >= MINIMUM_DELEGATION, "!minimum-delegation"); - DelegationPool storage pool; + DelegationPoolInternal storage pool; if (_verifier == SUBGRAPH_DATA_SERVICE_ADDRESS) { pool = legacyDelegationPools[_serviceProvider]; } else { @@ -437,11 +524,11 @@ contract HorizonStaking is HorizonStakingV1Storage, IHorizonStakingBase, GraphUp emit TokensDelegated(_serviceProvider, _verifier, msg.sender, _tokens); } - // undelegete tokens from a service provider + // undelegate tokens from a service provider // the shares are burned and replaced with shares in the thawing pool function undelegate(address _serviceProvider, address _verifier, uint256 _shares) public override notPartialPaused { require(_shares > 0, "!shares"); - DelegationPool storage pool; + DelegationPoolInternal storage pool; if (_verifier == SUBGRAPH_DATA_SERVICE_ADDRESS) { pool = legacyDelegationPools[_serviceProvider]; } else { @@ -488,7 +575,7 @@ contract HorizonStaking is HorizonStakingV1Storage, IHorizonStakingBase, GraphUp address _verifier, address _newServiceProvider ) public override notPartialPaused { - DelegationPool storage pool; + DelegationPoolInternal storage pool; if (_verifier == SUBGRAPH_DATA_SERVICE_ADDRESS) { pool = legacyDelegationPools[_serviceProvider]; } else { @@ -543,6 +630,11 @@ contract HorizonStaking is HorizonStakingV1Storage, IHorizonStakingBase, GraphUp emit ParameterUpdated("thawingPeriod"); } + function setMaxThawingPeriod(uint64 _maxThawingPeriod) external override onlyGovernor { + maxThawingPeriod = _maxThawingPeriod; + emit ParameterUpdated("maxThawingPeriod"); + } + /** * @dev Withdraw indexer tokens once the thawing period has passed. * @param _indexer Address of indexer to withdraw funds from @@ -585,6 +677,7 @@ contract HorizonStaking is HorizonStakingV1Storage, IHorizonStakingBase, GraphUp sharesThawing: 0, maxVerifierCut: _maxVerifierCut, thawingPeriod: _thawingPeriod, + createdAt: uint64(block.timestamp), firstThawRequestId: bytes32(0), lastThawRequestId: bytes32(0), nThawRequests: 0 @@ -634,12 +727,20 @@ contract HorizonStaking is HorizonStakingV1Storage, IHorizonStakingBase, GraphUp prov.sharesThawing = sharesThawing; prov.tokensThawing = tokensThawing; prov.tokens = prov.tokens - _tokens; + serviceProviders[_serviceProvider].tokensProvisioned -= _tokens; } function _addToProvision(address _serviceProvider, address _verifier, uint256 _tokens) internal { Provision storage prov = provisions[_serviceProvider][_verifier]; - require(_tokens > 0, "!tokens"); - require(getIdleStake(_serviceProvider) >= _tokens, "insufficient capacity"); + if (_tokens == 0) { + revert HorizonStakingInvalidZeroTokens(); + } + if (prov.createdAt == 0) { + revert HorizonStakingInvalidProvision(_serviceProvider, _verifier); + } + if (getIdleStake(_serviceProvider) < _tokens) { + revert HorizonStakingInsufficientCapacity(); + } prov.tokens = prov.tokens + _tokens; serviceProviders[_serviceProvider].tokensProvisioned = diff --git a/packages/horizon/contracts/HorizonStakingExtension.sol b/packages/horizon/contracts/HorizonStakingExtension.sol index d9b61939e..a30271f9c 100644 --- a/packages/horizon/contracts/HorizonStakingExtension.sol +++ b/packages/horizon/contracts/HorizonStakingExtension.sol @@ -132,6 +132,47 @@ contract HorizonStakingExtension is StakingBackwardsCompatibility, IHorizonStaki } } + function getDelegationPool( + address _serviceProvider, + address _verifier + ) external view override returns (DelegationPool memory) { + DelegationPool memory pool; + DelegationPoolInternal storage poolInternal; + if (_verifier == SUBGRAPH_DATA_SERVICE_ADDRESS) { + poolInternal = legacyDelegationPools[_serviceProvider]; + } else { + poolInternal = delegationPools[_serviceProvider][_verifier]; + } + pool.tokens = poolInternal.tokens; + pool.shares = poolInternal.shares; + pool.tokensThawing = poolInternal.tokensThawing; + pool.sharesThawing = poolInternal.sharesThawing; + return pool; + } + + function getDelegation( + address _delegator, + address _serviceProvider, + address _verifier + ) external view override returns (Delegation memory) { + if (_verifier == SUBGRAPH_DATA_SERVICE_ADDRESS) { + return legacyDelegationPools[_serviceProvider].delegators[_delegator]; + } else { + return delegationPools[_serviceProvider][_verifier].delegators[_delegator]; + } + } + + function getThawRequest(bytes32 _thawRequestId) external view returns (ThawRequest memory) { + return thawRequests[_thawRequestId]; + } + + function getProvision( + address _serviceProvider, + address _verifier + ) external view override returns (Provision memory) { + return provisions[_serviceProvider][_verifier]; + } + /** * @dev Receive an Indexer's stake from L1. * The specified amount is added to the indexer's stake; the indexer's @@ -161,7 +202,7 @@ contract HorizonStakingExtension is StakingBackwardsCompatibility, IHorizonStaki IL2StakingTypes.ReceiveDelegationData memory _delegationData ) internal { // Get the delegation pool of the indexer - DelegationPool storage pool = legacyDelegationPools[_delegationData.indexer]; + DelegationPoolInternal storage pool = legacyDelegationPools[_delegationData.indexer]; Delegation storage delegation = pool.delegators[_delegationData.delegator]; // Calculate shares to issue (without applying any delegation tax) diff --git a/packages/horizon/contracts/HorizonStakingStorage.sol b/packages/horizon/contracts/HorizonStakingStorage.sol index 161566e9c..a0c13995d 100644 --- a/packages/horizon/contracts/HorizonStakingStorage.sol +++ b/packages/horizon/contracts/HorizonStakingStorage.sol @@ -87,9 +87,9 @@ abstract contract HorizonStakingV1Storage is Managed, IHorizonStakingTypes { /// Deprecated, no tax is applied now. uint32 internal __DEPRECATED_delegationTaxPercentage; - /// @dev Delegation pools : serviceProvider => DelegationPool + /// @dev Delegation pools : serviceProvider => DelegationPoolInternal /// These are for the subgraph data service. - mapping(address => DelegationPool) internal legacyDelegationPools; + mapping(address => DelegationPoolInternal) internal legacyDelegationPools; // -- Operators -- @@ -143,5 +143,5 @@ abstract contract HorizonStakingV1Storage is Managed, IHorizonStakingTypes { bool public delegationSlashingEnabled; // delegation pools for each service provider and verifier - mapping(address => mapping(address => DelegationPool)) internal delegationPools; + mapping(address => mapping(address => DelegationPoolInternal)) internal delegationPools; } diff --git a/packages/horizon/contracts/IHorizonStakingBase.sol b/packages/horizon/contracts/IHorizonStakingBase.sol index afbd8a6ea..52317b581 100644 --- a/packages/horizon/contracts/IHorizonStakingBase.sol +++ b/packages/horizon/contracts/IHorizonStakingBase.sol @@ -167,4 +167,7 @@ interface IHorizonStakingBase is IHorizonStakingTypes { * @param _verifier The verifier / data service on which they're claiming to act */ function isAuthorized(address _operator, address _serviceProvider, address _verifier) external view returns (bool); + + function getProviderTokensAvailable(address _serviceProvider, address _verifier) external view returns (uint256); + function setMaxThawingPeriod(uint64 _maxThawingPeriod) external; } diff --git a/packages/horizon/contracts/IHorizonStakingExtension.sol b/packages/horizon/contracts/IHorizonStakingExtension.sol index 6e8bfe161..2f3da8e59 100644 --- a/packages/horizon/contracts/IHorizonStakingExtension.sol +++ b/packages/horizon/contracts/IHorizonStakingExtension.sol @@ -14,7 +14,6 @@ interface IHorizonStakingExtension { function getStake(address serviceProvider) external view returns (uint256); function getDelegatedTokensAvailable(address _serviceProvider, address _verifier) external view returns (uint256); - function getTokensAvailable(address _serviceProvider, address _verifier) external view returns (uint256); function getServiceProvider( @@ -30,4 +29,19 @@ interface IHorizonStakingExtension { function setOperator(address _operator, address _verifier, bool _allowed) external; function getMaxThawingPeriod() external view returns (uint64); + + function getDelegationPool( + address _serviceProvider, + address _verifier + ) external view returns (IHorizonStakingTypes.DelegationPool memory); + function getDelegation( + address _delegator, + address _serviceProvider, + address _verifier + ) external view returns (IHorizonStakingTypes.Delegation memory); + function getThawRequest(bytes32 _thawRequestId) external view returns (IHorizonStakingTypes.ThawRequest memory); + function getProvision( + address _serviceProvider, + address _verifier + ) external view returns (IHorizonStakingTypes.Provision memory); } diff --git a/packages/horizon/contracts/IHorizonStakingTypes.sol b/packages/horizon/contracts/IHorizonStakingTypes.sol index b5c118698..8067e13f9 100644 --- a/packages/horizon/contracts/IHorizonStakingTypes.sol +++ b/packages/horizon/contracts/IHorizonStakingTypes.sol @@ -15,6 +15,7 @@ interface IHorizonStakingTypes { uint32 maxVerifierCut; // time, in seconds, tokens must thaw before being withdrawn uint64 thawingPeriod; + uint64 createdAt; bytes32 firstThawRequestId; bytes32 lastThawRequestId; uint256 nThawRequests; @@ -29,7 +30,7 @@ interface IHorizonStakingTypes { uint256 nextThawRequestNonce; } - struct DelegationPool { + struct DelegationPoolInternal { uint32 __DEPRECATED_cooldownBlocks; // solhint-disable-line var-name-mixedcase uint32 __DEPRECATED_indexingRewardCut; // in PPM uint32 __DEPRECATED_queryFeeCut; // in PPM @@ -41,6 +42,13 @@ interface IHorizonStakingTypes { uint256 sharesThawing; // Shares representing the thawing tokens } + struct DelegationPool { + uint256 tokens; // Total tokens as pool reserves + uint256 shares; // Total shares minted in the pool + uint256 tokensThawing; // Tokens thawing in the pool + uint256 sharesThawing; // Shares representing the thawing tokens + } + struct Delegation { uint256 shares; // Shares owned by a delegator in the pool uint256 __DEPRECATED_tokensLocked; // Tokens locked for undelegation diff --git a/packages/horizon/contracts/StakingBackwardsCompatibility.sol b/packages/horizon/contracts/StakingBackwardsCompatibility.sol index 63784155f..47a198545 100644 --- a/packages/horizon/contracts/StakingBackwardsCompatibility.sol +++ b/packages/horizon/contracts/StakingBackwardsCompatibility.sol @@ -320,7 +320,7 @@ abstract contract StakingBackwardsCompatibility is */ function _collectDelegationQueryRewards(address _indexer, uint256 _tokens) private returns (uint256) { uint256 delegationRewards = 0; - DelegationPool storage pool = legacyDelegationPools[_indexer]; + DelegationPoolInternal storage pool = legacyDelegationPools[_indexer]; if (pool.tokens > 0 && pool.__DEPRECATED_queryFeeCut < MAX_PPM) { uint256 indexerCut = (uint256(pool.__DEPRECATED_queryFeeCut) * _tokens) / MAX_PPM; delegationRewards = _tokens - indexerCut; @@ -338,7 +338,7 @@ abstract contract StakingBackwardsCompatibility is */ function _collectDelegationIndexingRewards(address _indexer, uint256 _tokens) private returns (uint256) { uint256 delegationRewards = 0; - DelegationPool storage pool = legacyDelegationPools[_indexer]; + DelegationPoolInternal storage pool = legacyDelegationPools[_indexer]; if (pool.tokens > 0 && pool.__DEPRECATED_indexingRewardCut < MAX_PPM) { uint256 indexerCut = (uint256(pool.__DEPRECATED_indexingRewardCut) * _tokens) / MAX_PPM; delegationRewards = _tokens - indexerCut; diff --git a/packages/horizon/hardhat.config.ts b/packages/horizon/hardhat.config.ts index f5c9172a8..123791c44 100644 --- a/packages/horizon/hardhat.config.ts +++ b/packages/horizon/hardhat.config.ts @@ -3,7 +3,15 @@ import '@nomicfoundation/hardhat-toolbox' import { HardhatUserConfig } from 'hardhat/config' const config: HardhatUserConfig = { - solidity: '0.8.24', + solidity: { + version: '0.8.24', + settings: { + optimizer: { + enabled: true, + runs: 200, + }, + }, + }, paths: { artifacts: './build/contracts', sources: './contracts',