Skip to content

Commit

Permalink
Merge pull request nucypher#261 from vzotova/extra-penalty
Browse files Browse the repository at this point in the history
Increment penalty in case of repeated violation during previous duration
  • Loading branch information
cygnusv authored May 10, 2024
2 parents 56f7aa2 + 0091f66 commit 449ec47
Show file tree
Hide file tree
Showing 3 changed files with 44 additions and 8 deletions.
20 changes: 15 additions & 5 deletions contracts/contracts/TACoApplication.sol
Original file line number Diff line number Diff line change
Expand Up @@ -198,14 +198,15 @@ contract TACoApplication is

uint256 public constant REWARD_PER_TOKEN_MULTIPLIER = 10 ** 3;
uint256 internal constant FLOATING_POINT_DIVISOR = REWARD_PER_TOKEN_MULTIPLIER * 10 ** 18;
uint256 public constant PENALTY_BASE = 10000;
uint192 public constant PENALTY_BASE = 10000;

uint96 public immutable minimumAuthorization;
uint256 public immutable minOperatorSeconds;
uint256 public immutable rewardDuration;
uint256 public immutable deauthorizationDuration;
uint192 public immutable penaltyDefault;
uint256 public immutable penaltyDuration;
uint192 public immutable penaltyIncrement;

uint64 public immutable commitmentDurationOption1;
uint64 public immutable commitmentDurationOption2;
Expand Down Expand Up @@ -244,6 +245,7 @@ contract TACoApplication is
* @param _commitmentDeadline Last date to make a commitment
* @param _penaltyDefault Default penalty percentage (as a value out of 10000)
* @param _penaltyDuration Duration of penalty
* @param _penaltyIncrement Increment of penalty if violation occurs during an existing penalty period
*/
constructor(
IERC20 _token,
Expand All @@ -255,7 +257,8 @@ contract TACoApplication is
uint64[] memory _commitmentDurationOptions,
uint64 _commitmentDeadline,
uint192 _penaltyDefault,
uint256 _penaltyDuration
uint256 _penaltyDuration,
uint192 _penaltyIncrement
) {
uint256 totalSupply = _token.totalSupply();
require(
Expand All @@ -265,8 +268,9 @@ contract TACoApplication is
_commitmentDurationOptions.length >= 1 &&
_commitmentDurationOptions.length <= 4 &&
_penaltyDefault > 0 &&
_penaltyDefault < PENALTY_BASE &&
_penaltyDuration > 0,
_penaltyDefault <= PENALTY_BASE &&
_penaltyDuration > 0 &&
_penaltyDefault + _penaltyIncrement <= PENALTY_BASE,
"Wrong input parameters"
);
// This require is only to check potential overflow for 10% reward
Expand Down Expand Up @@ -295,6 +299,7 @@ contract TACoApplication is
commitmentDeadline = _commitmentDeadline;
penaltyDefault = _penaltyDefault;
penaltyDuration = _penaltyDuration;
penaltyIncrement = _penaltyIncrement;
_disableInitializers();
}

Expand Down Expand Up @@ -1073,7 +1078,12 @@ contract TACoApplication is
StakingProviderInfo storage info = stakingProviderInfo[_stakingProvider];
uint96 before = effectiveAuthorized(info.authorized, info.penaltyPercent);
info.endPenalty = uint64(block.timestamp + penaltyDuration);
info.penaltyPercent = penaltyDefault;
info.penaltyPercent = info.penaltyPercent == 0
? penaltyDefault
: info.penaltyPercent + penaltyIncrement;
if (info.penaltyPercent > PENALTY_BASE) {
info.penaltyPercent = PENALTY_BASE;
}
if (info.operatorConfirmed) {
authorizedOverall -= before - effectiveAuthorized(info.authorized, info.penaltyPercent);
}
Expand Down
2 changes: 2 additions & 0 deletions tests/application/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
COMMITMENT_DEADLINE = 60 * 60 * 24 * 200 # 200 days after deploymwent

PENALTY_DEFAULT = 1000 # 10% penalty
PENALTY_INCREMENT = 2500 # 25% penalty increment
PENALTY_DURATION = 60 * 60 * 24 # 1 day in seconds


Expand Down Expand Up @@ -83,6 +84,7 @@ def taco_application(project, creator, token, threshold_staking, oz_dependency,
now + COMMITMENT_DEADLINE,
PENALTY_DEFAULT,
PENALTY_DURATION,
PENALTY_INCREMENT,
)

encoded_initializer_function = encode_function_data()
Expand Down
30 changes: 27 additions & 3 deletions tests/application/test_operator.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
MIN_OPERATOR_SECONDS = 24 * 60 * 60
PENALTY_DEFAULT = 1000 # 10% penalty
PENALTY_DURATION = 60 * 60 * 24 # 1 day in seconds
PENALTY_INCREMENT = 2500


def test_bond_operator(accounts, threshold_staking, taco_application, child_application, chain):
Expand Down Expand Up @@ -497,12 +498,35 @@ def test_penalize(accounts, threshold_staking, taco_application, child_applicati
tx = child_application.penalize(staking_provider, sender=staking_provider)
timestamp = tx.timestamp
end_of_penalty = timestamp + PENALTY_DURATION
assert taco_application.getPenalty(staking_provider) == [PENALTY_DEFAULT, end_of_penalty]
assert taco_application.authorizedOverall() == min_authorization * 9 / 10
assert taco_application.getPenalty(staking_provider) == [
PENALTY_DEFAULT + PENALTY_INCREMENT,
end_of_penalty,
]
assert taco_application.authorizedOverall() == min_authorization * 65 / 100 # 65%
assert tx.events == [
taco_application.Penalized(
stakingProvider=staking_provider,
penaltyPercent=PENALTY_DEFAULT,
penaltyPercent=PENALTY_DEFAULT + PENALTY_INCREMENT,
endPenalty=end_of_penalty,
)
]

# Penalize several times in a row
chain.pending_timestamp += PENALTY_DURATION
child_application.penalize(staking_provider, sender=staking_provider) # 90%
child_application.penalize(staking_provider, sender=staking_provider) # 65%
child_application.penalize(staking_provider, sender=staking_provider) # 40%
child_application.penalize(staking_provider, sender=staking_provider) # 15%
tx = child_application.penalize(staking_provider, sender=staking_provider) # 0%
timestamp = tx.timestamp
end_of_penalty = timestamp + PENALTY_DURATION
penalty_base = taco_application.PENALTY_BASE()
assert taco_application.getPenalty(staking_provider) == [penalty_base, end_of_penalty]
assert taco_application.authorizedOverall() == 0
assert tx.events == [
taco_application.Penalized(
stakingProvider=staking_provider,
penaltyPercent=penalty_base,
endPenalty=end_of_penalty,
)
]
Expand Down

0 comments on commit 449ec47

Please sign in to comment.