diff --git a/contracts/staking/contracts/src/interfaces/IVaultCore.sol b/contracts/staking/contracts/src/interfaces/IVaultCore.sol new file mode 100644 index 0000000000..5992e76920 --- /dev/null +++ b/contracts/staking/contracts/src/interfaces/IVaultCore.sol @@ -0,0 +1,60 @@ +/* + + Copyright 2018 ZeroEx Intl. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +*/ + +pragma solidity ^0.5.5; + + +interface IVaultCore +{ + + /// @dev This mixin contains core logic for vaults. + /// This includes management of the staking contract + /// and setting the vault to "Catastrophic Failure Mode". + /// It's up to the vault how they handle this failure mode; however, + /// all vaults should disable all functionality aside from withdrawals. + /// Vaults should only be set to Catastrophic Failure Mode iff there is + /// non-recoverable corruption of the staking contracts. If there is a + /// recoverable flaw/bug/vulnerability, simply detach the staking contract + /// by setting its address to `address(0)`. Once in Catostrophic Failure Mode, + /// a vault cannot be reset to normal mode; this prevents corruption of related + /// state in the staking contract. + + /// @dev Emitted when the Staking contract is changed. + /// @param stakingContractAddress Address of the new Staking contract. + event StakingContractChanged( + address stakingContractAddress + ); + + /// @dev Emitted when the Staking contract is put into Catostrophic Failure Mode + /// @param sender Address of sender (`msg.sender`) + event InCatostrophicFailureMode( + address sender + ); + + /// @dev Sets the address of the Staking Contract. + /// Note that only the contract owner can call this function. + /// @param _stakingContractAddress Address of Staking contract. + function setStakingContract(address payable _stakingContractAddress) + external; + + /// @dev Vault enters into Catostrophic Failure Mode. + /// *** WARNING - ONCE IN CATOSTROPHIC FAILURE MODE, YOU CAN NEVER GO BACK! *** + /// Note that only the contract owner can call this function. + function enterCatostrophicFailure() + external; +} \ No newline at end of file diff --git a/contracts/staking/contracts/src/vaults/MixinVaultCore.sol b/contracts/staking/contracts/src/vaults/MixinVaultCore.sol index 95de8fe5c5..7b130244bc 100644 --- a/contracts/staking/contracts/src/vaults/MixinVaultCore.sol +++ b/contracts/staking/contracts/src/vaults/MixinVaultCore.sol @@ -19,21 +19,39 @@ pragma solidity ^0.5.5; import "@0x/contracts-utils/contracts/src/Authorizable.sol"; +import "../interfaces/IVaultCore.sol"; contract MixinVaultCore is - Authorizable + Authorizable, + IVaultCore { + /// @dev This mixin contains core logic for vaults. + /// This includes management of the staking contract + /// and setting the vault to "Catastrophic Failure Mode". + /// It's up to the vault how they handle this failure mode; however, + /// all vaults should disable all functionality aside from withdrawals. + /// Vaults should only be set to Catastrophic Failure Mode iff there is + /// non-recoverable corruption of the staking contracts. If there is a + /// recoverable flaw/bug/vulnerability, simply detach the staking contract + /// by setting its address to `address(0)`. Once in Catostrophic Failure Mode, + /// a vault cannot be reset to normal mode; this prevents corruption of related + /// state in the staking contract. + + // Address of staking contract address payable internal stakingContractAddress; + // True iff vault has been set to Catostrophic Failure Mode bool internal isInCatostrophicFailure; + /// @dev Constructor. constructor() public { stakingContractAddress = 0x0000000000000000000000000000000000000000; isInCatostrophicFailure = false; } + /// @dev Asserts that the sender (`msg.sender`) is the staking contract. modifier onlyStakingContract { require( msg.sender == stakingContractAddress, @@ -42,6 +60,7 @@ contract MixinVaultCore is _; } + /// @dev Asserts that this contract *is in* Catostrophic Failure Mode. modifier onlyInCatostrophicFailure { require( isInCatostrophicFailure, @@ -50,6 +69,7 @@ contract MixinVaultCore is _; } + /// @dev Asserts that this contract *is not in* Catostrophic Failure Mode. modifier onlyNotInCatostrophicFailure { require( !isInCatostrophicFailure, @@ -58,17 +78,25 @@ contract MixinVaultCore is _; } - function setStakingContractAddrsess(address payable _stakingContractAddress) + /// @dev Sets the address of the Staking Contract. + /// Note that only the contract owner can call this function. + /// @param _stakingContractAddress Address of Staking contract. + function setStakingContract(address payable _stakingContractAddress) external onlyOwner { stakingContractAddress = _stakingContractAddress; + emit StakingContractChanged(stakingContractAddress); } + /// @dev Vault enters into Catostrophic Failure Mode. + /// *** WARNING - ONCE IN CATOSTROPHIC FAILURE MODE, YOU CAN NEVER GO BACK! *** + /// Note that only the contract owner can call this function. function enterCatostrophicFailure() external onlyOwner { isInCatostrophicFailure = true; + emit InCatostrophicFailureMode(msg.sender); } } \ No newline at end of file diff --git a/contracts/staking/contracts/src/vaults/StakingPoolRewardVault.sol b/contracts/staking/contracts/src/vaults/StakingPoolRewardVault.sol index e228c7a195..b3d0390bd3 100644 --- a/contracts/staking/contracts/src/vaults/StakingPoolRewardVault.sol +++ b/contracts/staking/contracts/src/vaults/StakingPoolRewardVault.sol @@ -42,6 +42,9 @@ contract StakingPoolRewardVault is /// allows withdrawals to be made. Once this vault is in catostrophic /// failure mode, it cannot be returned to normal mode; this prevents /// corruption of related state in the staking contract. + /// + /// When in Catastrophic Failure Mode, the Staking contract can still + /// perform withdrawals on behalf of its users. // mapping from Pool to Reward Balance in ETH mapping (bytes32 => Balance) internal balanceByPoolId; diff --git a/contracts/staking/test/utils/staking_wrapper.ts b/contracts/staking/test/utils/staking_wrapper.ts index f22633e52b..f0444a74af 100644 --- a/contracts/staking/test/utils/staking_wrapper.ts +++ b/contracts/staking/test/utils/staking_wrapper.ts @@ -134,7 +134,7 @@ export class StakingWrapper { ); // set staking proxy contract in zrx vault await (this - ._zrxVaultContractIfExists).setStakingContractAddrsess.awaitTransactionSuccessAsync( + ._zrxVaultContractIfExists).setStakingContract.awaitTransactionSuccessAsync( (this._stakingProxyContractIfExists).address, ); // set zrx vault in staking contract @@ -152,7 +152,7 @@ export class StakingWrapper { ); // set staking proxy contract in reward vault await (this - ._rewardVaultContractIfExists).setStakingContractAddrsess.awaitTransactionSuccessAsync( + ._rewardVaultContractIfExists).setStakingContract.awaitTransactionSuccessAsync( (this._stakingProxyContractIfExists).address, ); // set reward vault in staking contract