From 2dbc366044c8fded3eadd85097899b3b673f3c69 Mon Sep 17 00:00:00 2001 From: ivan Date: Mon, 24 Jun 2024 00:25:04 +0200 Subject: [PATCH] Introduce configurable lock period for worker contract --- packages/contracts/src/GatewayRegistry.sol | 4 +-- packages/contracts/src/NetworkController.sol | 25 ++++++++++++++++--- .../src/interfaces/INetworkController.sol | 6 +++++ .../StakersRewardDistributor.withdraw.t.sol | 6 ++--- .../WorkerRegistration.constructor.t.sol | 1 - .../WorkerRegistration/WorkerRegistration.sol | 1 + 6 files changed, 33 insertions(+), 10 deletions(-) diff --git a/packages/contracts/src/GatewayRegistry.sol b/packages/contracts/src/GatewayRegistry.sol index aaafd7b..713022b 100644 --- a/packages/contracts/src/GatewayRegistry.sol +++ b/packages/contracts/src/GatewayRegistry.sol @@ -159,7 +159,7 @@ contract GatewayRegistry is AccessControlledPausableUpgradeable, IGatewayRegistr */ function stake(uint256 amount, uint128 durationBlocks, bool withAutoExtension) public whenNotPaused { require(amount >= minStake, "Cannot stake below minStake"); - require(durationBlocks >= router.networkController().epochLength(), "Cannot stake for less than an epoch"); + require(durationBlocks >= router.networkController().workerEpochLength(), "Cannot stake for less than an epoch"); require(durationBlocks * averageBlockTime <= MAX_LOCK_DURATION, "Lock duration too long"); require(operators[msg.sender].stake.amount == 0, "Stake already exists, call addStake instead"); uint256 _computationUnits = computationUnitsAmount(amount, durationBlocks); @@ -245,7 +245,7 @@ contract GatewayRegistry is AccessControlledPausableUpgradeable, IGatewayRegistr } uint256 computationUnits = _stake.lockStart > blockNumber ? _stake.oldCUs : computationUnitsAmount(_stake.amount, _stake.duration); - uint256 epochLength = uint256(router.networkController().epochLength()); + uint256 epochLength = uint256(router.networkController().workerEpochLength()); if (_stake.duration <= epochLength) { return computationUnits; } diff --git a/packages/contracts/src/NetworkController.sol b/packages/contracts/src/NetworkController.sol index cc02a80..1e96083 100644 --- a/packages/contracts/src/NetworkController.sol +++ b/packages/contracts/src/NetworkController.sol @@ -13,7 +13,10 @@ import "./interfaces/INetworkController.sol"; contract NetworkController is AccessControl, INetworkController { uint256 internal constant ONE_BASIS_POINT = 10_000; + /// @notice deprecated uint128 public epochLength; + + uint128 public workerEpochLength; uint128 public firstEpochBlock; uint256 public bondAmount; uint256 public stakingDeadlock = 2; @@ -31,7 +34,7 @@ contract NetworkController is AccessControl, INetworkController { for (uint256 i = 0; i < _allowedVestedTargets.length; i++) { setAllowedVestedTarget(_allowedVestedTargets[i], true); } - epochLength = _epochLength; + workerEpochLength = _epochLength; firstEpochBlock = nextEpoch(); emit EpochLengthUpdated(_epochLength); @@ -46,11 +49,25 @@ contract NetworkController is AccessControl, INetworkController { uint128 nextEpochStart = nextEpoch(); epochCheckpoint = epochNumber(); firstEpochBlock = nextEpochStart; - epochLength = _epochLength; + workerEpochLength = _epochLength; emit EpochLengthUpdated(_epochLength); } + /// @dev Set how long the + function setLockPeriod(uint128 _lockPeriod) external onlyRole(DEFAULT_ADMIN_ROLE) { + require(_lockPeriod > 1, "Lock period too short"); + require(_lockPeriod < 100000, "Lock period too long"); + + epochLength = _lockPeriod; + + emit LockPeriodUpdated(_lockPeriod); + } + + function lockPeriod() external view returns (uint128) { + return epochLength; + } + /// @dev Set amount of tokens required to register a worker function setBondAmount(uint256 _bondAmount) public onlyRole(DEFAULT_ADMIN_ROLE) { require(_bondAmount > 0, "Bond cannot be 0"); @@ -103,13 +120,13 @@ contract NetworkController is AccessControl, INetworkController { function nextEpoch() public view returns (uint128) { uint128 blockNumber = uint128(block.number); if (blockNumber < firstEpochBlock) return firstEpochBlock; - return ((blockNumber - firstEpochBlock) / epochLength + 1) * epochLength + firstEpochBlock; + return ((blockNumber - firstEpochBlock) / workerEpochLength + 1) * workerEpochLength + firstEpochBlock; } /// @inheritdoc INetworkController function epochNumber() public view returns (uint128) { uint128 blockNumber = uint128(block.number); if (blockNumber < firstEpochBlock) return epochCheckpoint; - return (blockNumber - firstEpochBlock) / epochLength + epochCheckpoint + 1; + return (blockNumber - firstEpochBlock) / workerEpochLength + epochCheckpoint + 1; } } diff --git a/packages/contracts/src/interfaces/INetworkController.sol b/packages/contracts/src/interfaces/INetworkController.sol index 090cc58..22f0704 100644 --- a/packages/contracts/src/interfaces/INetworkController.sol +++ b/packages/contracts/src/interfaces/INetworkController.sol @@ -12,10 +12,16 @@ interface INetworkController { event AllowedVestedTargetUpdated(address target, bool isAllowed); event TargetCapacityUpdated(uint256 target); event RewardCoefficientUpdated(uint256 coefficient); + event LockPeriodUpdated(uint256 lockPeriod); + /// @notice Deprecated /// @dev Amount of blocks in one epoch + /// @notice It's now lock period for workers for compatibility reason function epochLength() external view returns (uint128); + /// @dev Amount of blocks in one epoch + function workerEpochLength() external view returns (uint128); + /// @dev Amount of tokens required to register a worker function bondAmount() external view returns (uint256); diff --git a/packages/contracts/test/Staking/StakersRewardDistributor.withdraw.t.sol b/packages/contracts/test/Staking/StakersRewardDistributor.withdraw.t.sol index 29113f5..79769fd 100644 --- a/packages/contracts/test/Staking/StakersRewardDistributor.withdraw.t.sol +++ b/packages/contracts/test/Staking/StakersRewardDistributor.withdraw.t.sol @@ -85,7 +85,7 @@ contract StakersRewardDistributionWithdrawTest is StakersRewardDistributionTest } function test_CannotWithdrawBeforeFullEpochEnds() public { - network.setEpochLength(50); + network.setLockPeriod(50); assertEq(network.nextEpoch(), 5); staking.deposit(workers[0], 100); (, uint256 whenCanWithdraw) = staking.getDeposit(address(this), workers[0]); @@ -96,9 +96,9 @@ contract StakersRewardDistributionWithdrawTest is StakersRewardDistributionTest jumpToMomentWhenCanWithdraw(address(this)); staking.withdraw(workers[0], 50); staking.deposit(workers[0], 100); - assertEq(network.nextEpoch(), 105); (, whenCanWithdraw) = staking.getDeposit(address(this), workers[0]); - assertEq(whenCanWithdraw, 155); + assertEq(network.nextEpoch(), 57); + assertEq(whenCanWithdraw, 107); } // 2.5M gas for 100 distinct deposits diff --git a/packages/contracts/test/WorkerRegistration/WorkerRegistration.constructor.t.sol b/packages/contracts/test/WorkerRegistration/WorkerRegistration.constructor.t.sol index 7c053bf..b3a9bb5 100644 --- a/packages/contracts/test/WorkerRegistration/WorkerRegistration.constructor.t.sol +++ b/packages/contracts/test/WorkerRegistration/WorkerRegistration.constructor.t.sol @@ -6,7 +6,6 @@ import "./WorkerRegistration.sol"; contract WorkerRegistrationConstructorTest is WorkerRegistrationTest { function testConstructor() public { assertEq(address(workerRegistration.SQD()), address(token)); - assertEq(workerRegistration.epochLength(), EPOCH_LENGTH); assertEq(workerRegistration.lockPeriod(), EPOCH_LENGTH); } diff --git a/packages/contracts/test/WorkerRegistration/WorkerRegistration.sol b/packages/contracts/test/WorkerRegistration/WorkerRegistration.sol index 49db1e6..25e8226 100644 --- a/packages/contracts/test/WorkerRegistration/WorkerRegistration.sol +++ b/packages/contracts/test/WorkerRegistration/WorkerRegistration.sol @@ -40,6 +40,7 @@ contract WorkerRegistrationTest is BaseTest { workerRegistration = WorkerRegistration(address(router.workerRegistration())); networkController = NetworkController(address(router.networkController())); networkController.setEpochLength(EPOCH_LENGTH); + networkController.setLockPeriod(EPOCH_LENGTH); vm.roll(workerRegistration.nextEpoch()); staking = Staking(address(router.staking())); token.approve(address(workerRegistration), workerRegistration.bondAmount());