From 335494de4b946ad7d64136dcf3e3f5f0979f721f Mon Sep 17 00:00:00 2001 From: Victoria Zotova Date: Mon, 10 Jul 2023 17:06:26 -0400 Subject: [PATCH] Extracts Adjudicator from application to decrease contract size, fixes bug with releasing operator --- .github/workflows/main.yaml | 2 +- contracts/contracts/Adjudicator.sol | 40 +++++-------- contracts/contracts/PRECBDApplication.sol | 57 +++++++++++-------- contracts/test/AdjudicatorTestSet.sol | 18 ++---- contracts/test/PRECBDApplicationTestSet.sol | 42 -------------- ...ation.py => deploy_pre_cbd_application.py} | 4 -- tests/application/conftest.py | 24 ++------ tests/application/test_authorization.py | 22 +++++-- tests/application/test_operator.py | 9 ++- 9 files changed, 80 insertions(+), 138 deletions(-) rename scripts/{deploy_pre_application.py => deploy_pre_cbd_application.py} (80%) diff --git a/.github/workflows/main.yaml b/.github/workflows/main.yaml index 6b73df58..4a63fe7e 100644 --- a/.github/workflows/main.yaml +++ b/.github/workflows/main.yaml @@ -48,7 +48,7 @@ jobs: run: ape run scripts/deploy_nucypher_token.py --network ethereum:local - name: Deploy PRE Application - run: ape run scripts/deploy_pre_application.py --network ethereum:local + run: ape run scripts/deploy_pre_cbd_application.py --network ethereum:local - name: Deploy Staking Escrow run: ape run scripts/deploy_staking_escrow.py --network ethereum:local diff --git a/contracts/contracts/Adjudicator.sol b/contracts/contracts/Adjudicator.sol index fc38d43e..35e683b3 100644 --- a/contracts/contracts/Adjudicator.sol +++ b/contracts/contracts/Adjudicator.sol @@ -6,6 +6,7 @@ import "./lib/ReEncryptionValidator.sol"; import "./lib/SignatureVerifier.sol"; import "@openzeppelin/contracts/utils/math/Math.sol"; import "@openzeppelin/contracts/utils/math/SafeCast.sol"; +import "./PRECBDApplication.sol"; /** @@ -13,7 +14,7 @@ import "@openzeppelin/contracts/utils/math/SafeCast.sol"; * @notice Supervises operators' behavior and punishes when something's wrong. * @dev |v3.1.1| */ -abstract contract Adjudicator { +contract Adjudicator { using UmbralDeserializer for bytes; using SafeCast for uint256; @@ -37,6 +38,7 @@ abstract contract Adjudicator { uint256 public immutable basePenalty; uint256 public immutable penaltyHistoryCoefficient; uint256 public immutable percentagePenaltyCoefficient; + PRECBDApplication public immutable application; mapping (address => uint256) public penaltyHistory; mapping (bytes32 => bool) public evaluatedCFrags; @@ -50,16 +52,22 @@ abstract contract Adjudicator { * @param _percentagePenaltyCoefficient Coefficient for calculating the percentage penalty */ constructor( + PRECBDApplication _application, SignatureVerifier.HashAlgorithm _hashAlgorithm, uint256 _basePenalty, uint256 _penaltyHistoryCoefficient, uint256 _percentagePenaltyCoefficient ) { - require(_percentagePenaltyCoefficient != 0, "Wrong input parameters"); + require( + _percentagePenaltyCoefficient != 0 && + address(_application.token()) != address(0), + "Wrong input parameters" + ); hashAlgorithm = _hashAlgorithm; basePenalty = _basePenalty; percentagePenaltyCoefficient = _percentagePenaltyCoefficient; penaltyHistoryCoefficient = _penaltyHistoryCoefficient; + application = _application; } /** @@ -146,17 +154,17 @@ abstract contract Adjudicator { address operator = SignatureVerifier.recover( SignatureVerifier.hashEIP191(stamp, bytes1(0x45)), // Currently, we use version E (0x45) of EIP191 signatures _operatorIdentityEvidence); - address stakingProvider = stakingProviderFromOperator(operator); + address stakingProvider = application.stakingProviderFromOperator(operator); require(stakingProvider != address(0), "Operator must be related to a provider"); // 5. Check that staking provider can be slashed - uint96 stakingProviderValue = authorizedStake(stakingProvider); + uint96 stakingProviderValue = application.authorizedStake(stakingProvider); require(stakingProviderValue > 0, "Provider has no tokens"); // 6. If CFrag was incorrect, slash staking provider if (!cFragIsCorrect) { uint96 penalty = calculatePenalty(stakingProvider, stakingProviderValue); - slash(stakingProvider, penalty, msg.sender); + application.slash(stakingProvider, penalty, msg.sender); emit IncorrectCFragVerdict(evaluationHash, operator, stakingProvider); } } @@ -176,26 +184,4 @@ abstract contract Adjudicator { return penalty.toUint96(); } - /** - * @notice Get all tokens delegated to the staking provider - */ - function authorizedStake(address _stakingProvider) public view virtual returns (uint96); - - /** - * @notice Get staking provider address bonded with specified operator address - */ - function stakingProviderFromOperator(address _operator) public view virtual returns (address); - - /** - * @notice Slash the provider's stake and reward the investigator - * @param _stakingProvider Staking provider address - * @param _penalty Penalty - * @param _investigator Investigator - */ - function slash( - address _stakingProvider, - uint96 _penalty, - address _investigator - ) internal virtual; - } diff --git a/contracts/contracts/PRECBDApplication.sol b/contracts/contracts/PRECBDApplication.sol index 0f6dfbfa..fa0ea291 100644 --- a/contracts/contracts/PRECBDApplication.sol +++ b/contracts/contracts/PRECBDApplication.sol @@ -10,7 +10,6 @@ import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import "@openzeppelin-upgradeable/contracts/access/OwnableUpgradeable.sol"; import "../threshold/IApplication.sol"; import "../threshold/IStaking.sol"; -import "./Adjudicator.sol"; import "./coordination/IUpdatableStakeInfo.sol"; @@ -18,7 +17,7 @@ import "./coordination/IUpdatableStakeInfo.sol"; * @title PRE+CBD Application * @notice Contract distributes rewards for participating in app and slashes for violating rules */ -contract PRECBDApplication is IApplication, Adjudicator, OwnableUpgradeable { +contract PRECBDApplication is IApplication, OwnableUpgradeable { using SafeERC20 for IERC20; using SafeCast for uint256; @@ -133,7 +132,9 @@ contract PRECBDApplication is IApplication, Adjudicator, OwnableUpgradeable { IStaking public immutable tStaking; IERC20 public immutable token; + IUpdatableStakeInfo public updatableStakeInfo; + address public adjudicator; mapping (address => StakingProviderInfo) public stakingProviderInfo; address[] public stakingProviders; @@ -150,10 +151,6 @@ contract PRECBDApplication is IApplication, Adjudicator, OwnableUpgradeable { * @notice Constructor sets address of token contract and parameters for staking * @param _token T token contract * @param _tStaking T token staking contract - * @param _hashAlgorithm Hashing algorithm - * @param _basePenalty Base for the penalty calculation - * @param _penaltyHistoryCoefficient Coefficient for calculating the penalty depending on the history - * @param _percentagePenaltyCoefficient Coefficient for calculating the percentage penalty * @param _minAuthorization Amount of minimum allowable authorization * @param _minOperatorSeconds Min amount of seconds while an operator can't be changed * @param _rewardDuration Duration of one reward cycle @@ -162,22 +159,11 @@ contract PRECBDApplication is IApplication, Adjudicator, OwnableUpgradeable { constructor( IERC20 _token, IStaking _tStaking, - SignatureVerifier.HashAlgorithm _hashAlgorithm, - uint256 _basePenalty, - uint256 _penaltyHistoryCoefficient, - uint256 _percentagePenaltyCoefficient, uint256 _minAuthorization, uint256 _minOperatorSeconds, uint256 _rewardDuration, uint256 _deauthorizationDuration - ) - Adjudicator( - _hashAlgorithm, - _basePenalty, - _penaltyHistoryCoefficient, - _percentagePenaltyCoefficient - ) - { + ) { require( _rewardDuration != 0 && _tStaking.authorizedStake(address(this), address(this)) == 0 && @@ -242,6 +228,14 @@ contract PRECBDApplication is IApplication, Adjudicator, OwnableUpgradeable { updatableStakeInfo = _updatableStakeInfo; } + /** + * @notice Set Set adjudicator contract. If zero then slashing is disabled + */ + function setAdjudicator(address _adjudicator) external onlyOwner { + require(address(_adjudicator) != address(adjudicator), "New address must not be equal to the current one"); + adjudicator = _adjudicator; + } + //------------------------Reward------------------------------ /** @@ -412,7 +406,8 @@ contract PRECBDApplication is IApplication, Adjudicator, OwnableUpgradeable { if (info.authorized == 0) { _stakingProviderFromOperator[info.operator] = address(0); info.operator = address(0); - info.operatorConfirmed == false; + info.operatorConfirmed = false; + _releaseOperator(_stakingProvider); } } @@ -468,7 +463,8 @@ contract PRECBDApplication is IApplication, Adjudicator, OwnableUpgradeable { if (info.authorized == 0) { _stakingProviderFromOperator[info.operator] = address(0); info.operator = address(0); - info.operatorConfirmed == false; + info.operatorConfirmed = false; + _releaseOperator(_stakingProvider); } } @@ -494,7 +490,8 @@ contract PRECBDApplication is IApplication, Adjudicator, OwnableUpgradeable { if (info.authorized == 0) { _stakingProviderFromOperator[info.operator] = address(0); info.operator = address(0); - info.operatorConfirmed == false; + info.operatorConfirmed = false; + _releaseOperator(_stakingProvider); } } @@ -502,7 +499,7 @@ contract PRECBDApplication is IApplication, Adjudicator, OwnableUpgradeable { /** * @notice Returns staking provider for specified operator */ - function stakingProviderFromOperator(address _operator) public view override returns (address) { + function stakingProviderFromOperator(address _operator) public view returns (address) { return _stakingProviderFromOperator[_operator]; } @@ -516,7 +513,7 @@ contract PRECBDApplication is IApplication, Adjudicator, OwnableUpgradeable { /** * @notice Get all tokens delegated to the staking provider */ - function authorizedStake(address _stakingProvider) public view override returns (uint96) { + function authorizedStake(address _stakingProvider) public view returns (uint96) { return stakingProviderInfo[_stakingProvider].authorized; } @@ -634,6 +631,7 @@ contract PRECBDApplication is IApplication, Adjudicator, OwnableUpgradeable { info.operatorStartTimestamp = uint64(block.timestamp); info.operatorConfirmed = false; emit OperatorBonded(_stakingProvider, _operator, previousOperator, block.timestamp); + _releaseOperator(_stakingProvider); } /** @@ -650,6 +648,16 @@ contract PRECBDApplication is IApplication, Adjudicator, OwnableUpgradeable { info.operatorConfirmed = true; authorizedOverall += info.authorized; emit OperatorConfirmed(stakingProvider, msg.sender); + + if (address(updatableStakeInfo) != address(0)) { + updatableStakeInfo.updateOperator(stakingProvider, msg.sender); + } + } + + function _releaseOperator(address _stakingProvider) internal { + if (address(updatableStakeInfo) != address(0)) { + updatableStakeInfo.updateOperator(_stakingProvider, address(0)); + } } //-------------------------Slashing------------------------- @@ -664,8 +672,9 @@ contract PRECBDApplication is IApplication, Adjudicator, OwnableUpgradeable { uint96 _penalty, address _investigator ) - internal override + external { + require(msg.sender == adjudicator, "Only adjudicator allowed to slash"); address[] memory stakingProviderWrapper = new address[](1); stakingProviderWrapper[0] = _stakingProvider; tStaking.seize(_penalty, 100, _investigator, stakingProviderWrapper); diff --git a/contracts/test/AdjudicatorTestSet.sol b/contracts/test/AdjudicatorTestSet.sol index c92f5480..f1eb9d90 100644 --- a/contracts/test/AdjudicatorTestSet.sol +++ b/contracts/test/AdjudicatorTestSet.sol @@ -11,24 +11,14 @@ import "../contracts/lib/SignatureVerifier.sol"; /** * @notice Contract for testing the Adjudicator contract */ -contract ExtendedAdjudicator is Adjudicator { +contract PRECBDApplicationForAdjudicatorMock { uint32 public immutable secondsPerPeriod = 1; mapping (address => uint96) public stakingProviderInfo; mapping (address => uint256) public rewardInfo; mapping (address => address) _stakingProviderFromOperator; - constructor( - SignatureVerifier.HashAlgorithm _hashAlgorithm, - uint256 _basePenalty, - uint256 _penaltyHistoryCoefficient, - uint256 _percentagePenaltyCoefficient - ) - Adjudicator(_hashAlgorithm, _basePenalty, _penaltyHistoryCoefficient, _percentagePenaltyCoefficient) - { - } - - function stakingProviderFromOperator(address _operator) public view override returns (address) { + function stakingProviderFromOperator(address _operator) public view returns (address) { return _stakingProviderFromOperator[_operator]; } @@ -40,7 +30,7 @@ contract ExtendedAdjudicator is Adjudicator { _stakingProviderFromOperator[_operator] = _stakingProvider; } - function authorizedStake(address _stakingProvider) public view override returns (uint96) { + function authorizedStake(address _stakingProvider) public view returns (uint96) { return stakingProviderInfo[_stakingProvider]; } @@ -49,7 +39,7 @@ contract ExtendedAdjudicator is Adjudicator { uint96 _penalty, address _investigator ) - internal override + external { stakingProviderInfo[_stakingProvider] -= _penalty; rewardInfo[_investigator] += 1; diff --git a/contracts/test/PRECBDApplicationTestSet.sol b/contracts/test/PRECBDApplicationTestSet.sol index caf7e1a8..77ad6b85 100644 --- a/contracts/test/PRECBDApplicationTestSet.sol +++ b/contracts/test/PRECBDApplicationTestSet.sol @@ -168,45 +168,3 @@ contract Intermediary { } } - - -/** -* @notice Extended contract -*/ -contract ExtendedPRECBDApplication is PRECBDApplication { - - constructor( - IERC20 _token, - IStaking _tStaking, - SignatureVerifier.HashAlgorithm _hashAlgorithm, - uint256 _basePenalty, - uint256 _penaltyHistoryCoefficient, - uint256 _percentagePenaltyCoefficient, - uint256 _minAuthorization, - uint256 _minWorkerSeconds, - uint256 _rewardDuration, - uint256 _deauthorizationDuration - ) - PRECBDApplication( - _token, - _tStaking, - _hashAlgorithm, - _basePenalty, - _penaltyHistoryCoefficient, - _percentagePenaltyCoefficient, - _minAuthorization, - _minWorkerSeconds, - _rewardDuration, - _deauthorizationDuration - ) - {} - - function testSlash( - address _stakingProvider, - uint96 _penalty, - address _investigator - ) external { - slash(_stakingProvider, _penalty, _investigator); - } - -} diff --git a/scripts/deploy_pre_application.py b/scripts/deploy_pre_cbd_application.py similarity index 80% rename from scripts/deploy_pre_application.py rename to scripts/deploy_pre_cbd_application.py index 6b952142..736ad3a3 100644 --- a/scripts/deploy_pre_application.py +++ b/scripts/deploy_pre_cbd_application.py @@ -23,10 +23,6 @@ def main(account_id=None): pre_app = project.PRECBDApplication.deploy( t_token, t_staking, - deployments_config.get("pre_hash_algorithm"), - deployments_config.get("pre_base_penalty"), - deployments_config.get("pre_penalty_history_coefficient"), - deployments_config.get("pre_percentage_penalty_coefficient"), deployments_config.get("pre_min_authorization"), deployments_config.get("pre_min_operator_seconds"), deployments_config.get("reward_duration"), diff --git a/tests/application/conftest.py b/tests/application/conftest.py index 8d6437bb..32c4a507 100644 --- a/tests/application/conftest.py +++ b/tests/application/conftest.py @@ -25,13 +25,6 @@ MIN_OPERATOR_SECONDS = 24 * 60 * 60 TOTAL_SUPPLY = Web3.to_wei(10_000_000_000, "ether") -HASH_ALGORITHM_KECCAK256 = 0 -HASH_ALGORITHM_SHA256 = 1 -HASH_ALGORITHM_RIPEMD160 = 2 -HASH_ALGORITHM = HASH_ALGORITHM_SHA256 -BASE_PENALTY = 2 -PENALTY_HISTORY_COEFFICIENT = 0 -PERCENTAGE_PENALTY_COEFFICIENT = 100000 REWARD_DURATION = 60 * 60 * 24 * 7 # one week in seconds DEAUTHORIZATION_DURATION = 60 * 60 * 24 * 60 # 60 days in seconds @@ -72,16 +65,11 @@ def encode_function_data(initializer=None, *args): @pytest.fixture() -def pre_cbd_application(project, accounts, token, threshold_staking): - creator = accounts[0] +def pre_cbd_application(project, creator, token, threshold_staking): contract = creator.deploy( - project.ExtendedPRECBDApplication, + project.PRECBDApplication, token.address, threshold_staking.address, - HASH_ALGORITHM, - BASE_PENALTY, - PENALTY_HISTORY_COEFFICIENT, - PERCENTAGE_PENALTY_COEFFICIENT, MIN_AUTHORIZATION, MIN_OPERATOR_SECONDS, REWARD_DURATION, @@ -96,7 +84,7 @@ def pre_cbd_application(project, accounts, token, threshold_staking): encoded_initializer_function, sender=creator, ) - proxy_contract = project.ExtendedPRECBDApplication.at(proxy.address) + proxy_contract = project.PRECBDApplication.at(proxy.address) threshold_staking.setApplication(proxy_contract.address, sender=creator) proxy_contract.initialize(sender=creator) @@ -105,7 +93,7 @@ def pre_cbd_application(project, accounts, token, threshold_staking): @pytest.fixture() -def stake_info(project, deployer, pre_cbd_application): - contract = project.StakeInfo.deploy([pre_cbd_application.address], sender=deployer) - pre_cbd_application.setUpdatableStakeInfo(contract.address, sender=deployer) +def stake_info(project, creator, pre_cbd_application): + contract = project.StakeInfo.deploy([pre_cbd_application.address], sender=creator) + pre_cbd_application.setUpdatableStakeInfo(contract.address, sender=creator) return contract diff --git a/tests/application/test_authorization.py b/tests/application/test_authorization.py index c1ebae83..4e24084e 100644 --- a/tests/application/test_authorization.py +++ b/tests/application/test_authorization.py @@ -19,6 +19,7 @@ from ape.utils import ZERO_ADDRESS from web3 import Web3 +OPERATOR_CONFIRMED_SLOT = 1 AUTHORIZATION_SLOT = 3 DEAUTHORIZING_SLOT = 4 END_DEAUTHORIZATION_SLOT = 5 @@ -26,7 +27,7 @@ DEAUTHORIZATION_DURATION = 60 * 60 * 24 * 60 # 60 days in seconds -def test_authorization_increase(accounts, threshold_staking, pre_cbd_application): +def test_authorization_increase(accounts, threshold_staking, pre_cbd_application, stake_info): """ Tests for authorization method: authorizationIncreased """ @@ -131,7 +132,9 @@ def test_authorization_increase(accounts, threshold_staking, pre_cbd_application assert event["toAmount"] == value -def test_involuntary_authorization_decrease(accounts, threshold_staking, pre_cbd_application): +def test_involuntary_authorization_decrease( + accounts, threshold_staking, pre_cbd_application, stake_info +): """ Tests for authorization method: involuntaryAuthorizationDecrease """ @@ -161,6 +164,7 @@ def test_involuntary_authorization_decrease(accounts, threshold_staking, pre_cbd assert pre_cbd_application.authorizedStake(staking_provider) == authorization assert pre_cbd_application.isAuthorized(staking_provider) assert not pre_cbd_application.isOperatorConfirmed(staking_provider) + assert not pre_cbd_application.stakingProviderInfo(staking_provider)[OPERATOR_CONFIRMED_SLOT] events = pre_cbd_application.AuthorizationInvoluntaryDecreased.from_receipt(tx) assert len(events) == 1 @@ -189,6 +193,7 @@ def test_involuntary_authorization_decrease(accounts, threshold_staking, pre_cbd assert pre_cbd_application.authorizedStake(staking_provider) == authorization assert pre_cbd_application.isAuthorized(staking_provider) assert not pre_cbd_application.isOperatorConfirmed(staking_provider) + assert not pre_cbd_application.stakingProviderInfo(staking_provider)[OPERATOR_CONFIRMED_SLOT] events = pre_cbd_application.AuthorizationInvoluntaryDecreased.from_receipt(tx) assert len(events) == 1 @@ -237,6 +242,7 @@ def test_involuntary_authorization_decrease(accounts, threshold_staking, pre_cbd assert pre_cbd_application.authorizedStake(staking_provider) == 0 assert not pre_cbd_application.isAuthorized(staking_provider) assert not pre_cbd_application.isOperatorConfirmed(staking_provider) + assert not pre_cbd_application.stakingProviderInfo(staking_provider)[OPERATOR_CONFIRMED_SLOT] assert pre_cbd_application.getOperatorFromStakingProvider(staking_provider) == ZERO_ADDRESS assert pre_cbd_application.stakingProviderFromOperator(staking_provider) == ZERO_ADDRESS @@ -271,7 +277,9 @@ def test_involuntary_authorization_decrease(accounts, threshold_staking, pre_cbd assert event["toAmount"] == authorization -def test_authorization_decrease_request(accounts, threshold_staking, pre_cbd_application, chain): +def test_authorization_decrease_request( + accounts, threshold_staking, pre_cbd_application, stake_info, chain +): """ Tests for authorization method: authorizationDecreaseRequested """ @@ -373,7 +381,9 @@ def test_authorization_decrease_request(accounts, threshold_staking, pre_cbd_app assert event["toAmount"] == 0 -def test_finish_authorization_decrease(accounts, threshold_staking, pre_cbd_application, chain): +def test_finish_authorization_decrease( + accounts, threshold_staking, pre_cbd_application, stake_info, chain +): """ Tests for authorization method: finishAuthorizationDecrease """ @@ -473,6 +483,7 @@ def test_finish_authorization_decrease(accounts, threshold_staking, pre_cbd_appl assert pre_cbd_application.authorizedStake(staking_provider) == 0 assert not pre_cbd_application.isAuthorized(staking_provider) assert not pre_cbd_application.isOperatorConfirmed(staking_provider) + assert not pre_cbd_application.stakingProviderInfo(staking_provider)[OPERATOR_CONFIRMED_SLOT] assert threshold_staking.authorizedStake(staking_provider, pre_cbd_application.address) == 0 events = pre_cbd_application.AuthorizationDecreaseApproved.from_receipt(tx) @@ -483,7 +494,7 @@ def test_finish_authorization_decrease(accounts, threshold_staking, pre_cbd_appl assert event["toAmount"] == 0 -def test_resync(accounts, threshold_staking, pre_cbd_application): +def test_resync(accounts, threshold_staking, pre_cbd_application, stake_info): """ Tests for authorization method: resynchronizeAuthorization """ @@ -589,6 +600,7 @@ def test_resync(accounts, threshold_staking, pre_cbd_application): assert pre_cbd_application.authorizedStake(staking_provider) == 0 assert not pre_cbd_application.isAuthorized(staking_provider) assert not pre_cbd_application.isOperatorConfirmed(staking_provider) + assert not pre_cbd_application.stakingProviderInfo(staking_provider)[OPERATOR_CONFIRMED_SLOT] events = pre_cbd_application.AuthorizationReSynchronized.from_receipt(tx) assert len(events) == 1 diff --git a/tests/application/test_operator.py b/tests/application/test_operator.py index 9928dc0b..599bd92e 100644 --- a/tests/application/test_operator.py +++ b/tests/application/test_operator.py @@ -24,7 +24,7 @@ MIN_OPERATOR_SECONDS = 24 * 60 * 60 -def test_bond_operator(accounts, threshold_staking, pre_cbd_application, chain): +def test_bond_operator(accounts, threshold_staking, pre_cbd_application, stake_info, chain): ( creator, staking_provider_1, @@ -321,7 +321,9 @@ def test_bond_operator(accounts, threshold_staking, pre_cbd_application, chain): assert pre_cbd_application.stakingProviderFromOperator(operator2) == ZERO_ADDRESS -def test_confirm_address(accounts, threshold_staking, pre_cbd_application, chain, project): +def test_confirm_address( + accounts, threshold_staking, pre_cbd_application, stake_info, chain, project +): creator, staking_provider, operator, *everyone_else = accounts[0:] min_authorization = MIN_AUTHORIZATION min_operator_seconds = MIN_OPERATOR_SECONDS @@ -369,7 +371,8 @@ def test_slash(accounts, threshold_staking, pre_cbd_application): min_authorization = MIN_AUTHORIZATION penalty = min_authorization - pre_cbd_application.testSlash(staking_provider, penalty, investigator, sender=creator) + pre_cbd_application.setAdjudicator(creator, sender=creator) + pre_cbd_application.slash(staking_provider, penalty, investigator, sender=creator) assert threshold_staking.amountToSeize() == penalty assert threshold_staking.rewardMultiplier() == 100 assert threshold_staking.notifier() == investigator