From e8abe650f7302f3a0964d01b8fa3b442b37d2f15 Mon Sep 17 00:00:00 2001 From: Victoria Zotova Date: Wed, 6 Sep 2023 14:43:13 -0400 Subject: [PATCH] TACoApplication: available commitment duration tied to two options --- contracts/contracts/TACoApplication.sol | 27 +++++--- .../coordination/TACoChildApplication.sol | 1 + tests/application/conftest.py | 4 ++ tests/application/test_authorization.py | 66 +++++++++++-------- 4 files changed, 64 insertions(+), 34 deletions(-) diff --git a/contracts/contracts/TACoApplication.sol b/contracts/contracts/TACoApplication.sol index 3a38ef08..20e92b9d 100644 --- a/contracts/contracts/TACoApplication.sol +++ b/contracts/contracts/TACoApplication.sol @@ -147,12 +147,12 @@ contract TACoApplication is IApplication, ITACoChildToRoot, OwnableUpgradeable { uint64 endCommitment; } - uint64 public constant MINIMUM_COMMITMENT = 365 days; - uint96 public immutable minimumAuthorization; uint256 public immutable minOperatorSeconds; uint256 public immutable rewardDuration; uint256 public immutable deauthorizationDuration; + uint64 public immutable commitmentDurationOption1; + uint64 public immutable commitmentDurationOption2; IStaking public immutable tStaking; IERC20 public immutable token; @@ -179,6 +179,8 @@ contract TACoApplication is IApplication, ITACoChildToRoot, OwnableUpgradeable { * @param _minOperatorSeconds Min amount of seconds while an operator can't be changed * @param _rewardDuration Duration of one reward cycle in seconds * @param _deauthorizationDuration Duration of decreasing authorization in seconds + * @param _commitmentDurationOption1 Option 1 for commitment duration + * @param _commitmentDurationOption2 Option 2 for commitment duration */ constructor( IERC20 _token, @@ -186,12 +188,17 @@ contract TACoApplication is IApplication, ITACoChildToRoot, OwnableUpgradeable { uint96 _minimumAuthorization, uint256 _minOperatorSeconds, uint256 _rewardDuration, - uint256 _deauthorizationDuration + uint256 _deauthorizationDuration, + uint64 _commitmentDurationOption1, + uint64 _commitmentDurationOption2 ) { require( _rewardDuration != 0 && _tStaking.authorizedStake(address(this), address(this)) == 0 && - _token.totalSupply() > 0, + _token.totalSupply() > 0 && + _commitmentDurationOption1 > 0 && + _commitmentDurationOption2 > 0 && + _commitmentDurationOption1 != _commitmentDurationOption2, "Wrong input parameters" ); rewardDuration = _rewardDuration; @@ -200,6 +207,8 @@ contract TACoApplication is IApplication, ITACoChildToRoot, OwnableUpgradeable { token = _token; tStaking = _tStaking; minOperatorSeconds = _minOperatorSeconds; + commitmentDurationOption1 = _commitmentDurationOption1; + commitmentDurationOption2 = _commitmentDurationOption2; _disableInitializers(); } @@ -535,17 +544,19 @@ contract TACoApplication is IApplication, ITACoChildToRoot, OwnableUpgradeable { /** * @notice Make a commitment to not request authorization decrease for specified duration * @param _stakingProvider Staking provider address - * @param _duration Duration of commitment + * @param _commitmentDurationOption2 If set to true then will be used second option of commitment duration. Otherwise first */ function makeCommitment( address _stakingProvider, - uint64 _duration + bool _commitmentDurationOption2 ) external onlyOwnerOrStakingProvider(_stakingProvider) { - require(_duration >= MINIMUM_COMMITMENT, "Duration must be greater than minimum"); + uint64 duration = !_commitmentDurationOption2 + ? commitmentDurationOption1 + : commitmentDurationOption2; StakingProviderInfo storage info = stakingProviderInfo[_stakingProvider]; require(info.endDeauthorization == 0, "Commitment can't be made during deauthorization"); require(info.endCommitment == 0, "Commitment already made"); - info.endCommitment = uint64(block.timestamp) + _duration; + info.endCommitment = uint64(block.timestamp) + duration; emit CommitmentMade(_stakingProvider, info.endCommitment); } diff --git a/contracts/contracts/coordination/TACoChildApplication.sol b/contracts/contracts/coordination/TACoChildApplication.sol index e898a5ef..e4a5722e 100644 --- a/contracts/contracts/coordination/TACoChildApplication.sol +++ b/contracts/contracts/coordination/TACoChildApplication.sol @@ -40,6 +40,7 @@ contract TACoChildApplication is ITACoRootToChild, ITACoChildApplication, Initia "Address for root application must be specified" ); rootApplication = _rootApplication; + _disableInitializers(); } /** diff --git a/tests/application/conftest.py b/tests/application/conftest.py index e2fee3c1..ebf441ab 100644 --- a/tests/application/conftest.py +++ b/tests/application/conftest.py @@ -28,6 +28,8 @@ REWARD_DURATION = 60 * 60 * 24 * 7 # one week in seconds DEAUTHORIZATION_DURATION = 60 * 60 * 24 * 60 # 60 days in seconds TOTAL_SUPPLY = Web3.to_wei(1_000_000_000, "ether") # TODO NU(1_000_000_000, 'NU').to_units() +COMMITMENT_DURATION_1 = 182 * 60 * 24 * 60 # 182 days in seconds +COMMITMENT_DURATION_2 = 365 * 60 * 24 * 60 # 365 days in seconds DEPENDENCY = project.dependencies["openzeppelin"]["4.9.1"] @@ -75,6 +77,8 @@ def taco_application(project, creator, token, threshold_staking): MIN_OPERATOR_SECONDS, REWARD_DURATION, DEAUTHORIZATION_DURATION, + COMMITMENT_DURATION_1, + COMMITMENT_DURATION_2, ) proxy_admin = DEPENDENCY.ProxyAdmin.deploy(sender=creator) diff --git a/tests/application/test_authorization.py b/tests/application/test_authorization.py index 30408314..faadae9d 100644 --- a/tests/application/test_authorization.py +++ b/tests/application/test_authorization.py @@ -412,17 +412,15 @@ def test_authorization_decrease_request( chain.pending_timestamp += deauthorization_duration taco_application.finishAuthorizationDecrease(staking_provider, sender=creator) threshold_staking.authorizationIncreased(staking_provider, 0, value, sender=creator) - minimum_commitment_duration = taco_application.MINIMUM_COMMITMENT() - taco_application.makeCommitment( - staking_provider, minimum_commitment_duration, sender=staking_provider - ) + commitment_duration = taco_application.commitmentDurationOption1() + taco_application.makeCommitment(staking_provider, False, sender=staking_provider) # Commitment is still active with ape.reverts("Can't request deauthorization before end of commitment"): threshold_staking.authorizationDecreaseRequested( staking_provider, value, value // 2, sender=creator ) - chain.pending_timestamp += minimum_commitment_duration + chain.pending_timestamp += commitment_duration # Now decrease can be requested threshold_staking.authorizationDecreaseRequested( @@ -692,27 +690,22 @@ def test_commitment(accounts, threshold_staking, taco_application, chain): Tests for authorization method: makeCommitment """ - creator, staking_provider = accounts[0:2] + creator, staking_provider, another_staking_provider = accounts[0:3] deauthorization_duration = DEAUTHORIZATION_DURATION minimum_authorization = MIN_AUTHORIZATION value = 2 * minimum_authorization - minimum_commitment_duration = taco_application.MINIMUM_COMMITMENT() + commitment_duration_1 = taco_application.commitmentDurationOption1() + commitment_duration_2 = taco_application.commitmentDurationOption2() # Commitment can be made only for authorized staking provider with ape.reverts("Not owner or provider"): - taco_application.makeCommitment( - staking_provider, minimum_commitment_duration, sender=staking_provider - ) + taco_application.makeCommitment(staking_provider, False, sender=staking_provider) + with ape.reverts("Not owner or provider"): + taco_application.makeCommitment(staking_provider, True, sender=staking_provider) # Prepare staking provider threshold_staking.authorizationIncreased(staking_provider, 0, value, sender=creator) - # Commitment can't be made for duration less than minimum - with ape.reverts("Duration must be greater than minimum"): - taco_application.makeCommitment( - staking_provider, minimum_commitment_duration - 1, sender=staking_provider - ) - # Begin deauthorization threshold_staking.authorizationDecreaseRequested( staking_provider, value, minimum_authorization, sender=creator @@ -720,20 +713,24 @@ def test_commitment(accounts, threshold_staking, taco_application, chain): # Commitment can't be made during deauthorization with ape.reverts("Commitment can't be made during deauthorization"): - taco_application.makeCommitment( - staking_provider, minimum_commitment_duration, sender=staking_provider - ) + taco_application.makeCommitment(staking_provider, False, sender=staking_provider) + with ape.reverts("Commitment can't be made during deauthorization"): + taco_application.makeCommitment(staking_provider, True, sender=staking_provider) # Finish deauthorization chain.pending_timestamp += deauthorization_duration taco_application.finishAuthorizationDecrease(staking_provider, sender=creator) - # And make a commitment - tx = taco_application.makeCommitment( - staking_provider, minimum_commitment_duration, sender=staking_provider - ) + # Commitment can be made only by staking provider + with ape.reverts("Not owner or provider"): + taco_application.makeCommitment(staking_provider, False, sender=another_staking_provider) + with ape.reverts("Not owner or provider"): + taco_application.makeCommitment(staking_provider, True, sender=another_staking_provider) + + # And make a commitment for shorter duration + tx = taco_application.makeCommitment(staking_provider, False, sender=staking_provider) timestamp = chain.pending_timestamp - 1 - end_commitment = timestamp + minimum_commitment_duration + end_commitment = timestamp + commitment_duration_1 assert ( taco_application.stakingProviderInfo(staking_provider)[END_COMMITMENT_SLOT] == end_commitment @@ -746,6 +743,23 @@ def test_commitment(accounts, threshold_staking, taco_application, chain): # Commitment can't be made twice with ape.reverts("Commitment already made"): - taco_application.makeCommitment( - staking_provider, minimum_commitment_duration, sender=staking_provider + taco_application.makeCommitment(staking_provider, False, sender=staking_provider) + with ape.reverts("Commitment already made"): + taco_application.makeCommitment(staking_provider, True, sender=staking_provider) + + # Another staking provider makes a commitment for longer period of time + threshold_staking.authorizationIncreased(another_staking_provider, 0, value, sender=creator) + tx = taco_application.makeCommitment( + another_staking_provider, True, sender=another_staking_provider + ) + timestamp = chain.pending_timestamp - 1 + end_commitment = timestamp + commitment_duration_2 + assert ( + taco_application.stakingProviderInfo(another_staking_provider)[END_COMMITMENT_SLOT] + == end_commitment + ) + assert tx.events == [ + taco_application.CommitmentMade( + stakingProvider=another_staking_provider, endCommitment=end_commitment ) + ]