diff --git a/nucypher/blockchain/eth/sol/source/contracts/staking_contracts/PoolingStakingContract.sol b/nucypher/blockchain/eth/sol/source/contracts/staking_contracts/PoolingStakingContract.sol index 8a735fd96..ecfb435aa 100644 --- a/nucypher/blockchain/eth/sol/source/contracts/staking_contracts/PoolingStakingContract.sol +++ b/nucypher/blockchain/eth/sol/source/contracts/staking_contracts/PoolingStakingContract.sol @@ -15,6 +15,7 @@ contract PoolingStakingContract is AbstractStakingContract, Ownable { event TokensDeposited(address indexed sender, uint256 value, uint256 depositedTokens); event TokensWithdrawn(address indexed sender, uint256 value, uint256 depositedTokens); event ETHWithdrawn(address indexed sender, uint256 value); + event DepositSet(address indexed sender, bool value); struct Delegator { uint256 depositedTokens; @@ -22,7 +23,8 @@ contract PoolingStakingContract is AbstractStakingContract, Ownable { uint256 withdrawnETH; } - StakingEscrow public escrow; + StakingEscrow public immutable escrow; + uint256 public totalDepositedTokens; uint256 public totalWithdrawnReward; uint256 public totalWithdrawnETH; @@ -32,6 +34,7 @@ contract PoolingStakingContract is AbstractStakingContract, Ownable { uint256 public ownerWithdrawnETH; mapping (address => Delegator) public delegators; + bool depositIsEnabled = true; /** * @param _router Address of the StakingInterfaceRouter contract @@ -47,11 +50,28 @@ contract PoolingStakingContract is AbstractStakingContract, Ownable { ownerFraction = _ownerFraction; } + /** + * @notice Enabled deposit + */ + function enableDeposit() external onlyOwner { + depositIsEnabled = true; + emit DepositSet(msg.sender, depositIsEnabled); + } + + /** + * @notice Disable deposit + */ + function disableDeposit() external onlyOwner { + depositIsEnabled = false; + emit DepositSet(msg.sender, depositIsEnabled); + } + /** * @notice Transfer tokens as delegator * @param _value Amount of tokens to transfer */ function depositTokens(uint256 _value) external { + require(depositIsEnabled, "Deposit must be enabled"); require(_value > 0, "Value must be not empty"); totalDepositedTokens = totalDepositedTokens.add(_value); Delegator storage delegator = delegators[msg.sender]; diff --git a/tests/contracts/main/staking_contracts/test_pooling_contract.py b/tests/contracts/main/staking_contracts/test_pooling_contract.py index f408442db..2c0352c9c 100644 --- a/tests/contracts/main/staking_contracts/test_pooling_contract.py +++ b/tests/contracts/main/staking_contracts/test_pooling_contract.py @@ -102,6 +102,41 @@ def test_staking(testerchain, token_economics, token, escrow, pooling_contract, assert pooling_contract.functions.getAvailableOwnerReward().call() == 0 assert pooling_contract.functions.getAvailableReward().call() == 0 + # Disable deposit + log = pooling_contract.events.DepositSet.createFilter(fromBlock='latest') + with pytest.raises((TransactionFailed, ValueError)): + tx = pooling_contract.functions.disableDeposit().transact({'from': delegators[0]}) + testerchain.wait_for_receipt(tx) + tx = pooling_contract.functions.disableDeposit().transact({'from': owner}) + testerchain.wait_for_receipt(tx) + events = log.get_all_entries() + assert len(events) == 1 + event_args = events[-1]['args'] + assert event_args['sender'] == owner + assert not event_args['value'] + + delegator = delegators[0] + tokens = token.functions.balanceOf(delegator).call() + tx = token.functions.approve(pooling_contract.address, tokens).transact({'from': delegator}) + testerchain.wait_for_receipt(tx) + with pytest.raises((TransactionFailed, ValueError)): + tx = pooling_contract.functions.depositTokens(tokens).transact({'from': delegator}) + testerchain.wait_for_receipt(tx) + tx = token.functions.approve(pooling_contract.address, 0).transact({'from': delegator}) + testerchain.wait_for_receipt(tx) + + # Enable deposit + with pytest.raises((TransactionFailed, ValueError)): + tx = pooling_contract.functions.enableDeposit().transact({'from': delegators[0]}) + testerchain.wait_for_receipt(tx) + tx = pooling_contract.functions.enableDeposit().transact({'from': owner}) + testerchain.wait_for_receipt(tx) + events = log.get_all_entries() + assert len(events) == 2 + event_args = events[-1]['args'] + assert event_args['sender'] == owner + assert event_args['value'] + # Delegators deposit tokens to the pooling contract again for index, delegator in enumerate(delegators): tokens = token.functions.balanceOf(delegator).call() @@ -409,3 +444,5 @@ def test_reentrancy(testerchain, pooling_contract, token, deploy_contract): tx = testerchain.client.send_transaction({'to': contract_address}) testerchain.wait_for_receipt(tx) assert testerchain.w3.eth.getBalance(contract_address) == balance + + # TODO reentrancy test for owner