Striped Amber Bird
Medium
InteractionControl.sol :: pauseAll() if any contract is already paused, will cause the transaction to revert, preventing it from functioning as intended.
pauseAll()
is intended to pause all contracts; however, if an individual contract is already paused, the transaction will revert, preventing it from working as intended.
pauseAll() is implemented as follows.
function pauseAll() external onlyOwner {
for (uint256 i = 0; i < controlledContractNames.length; ++i) {
address addr = IContractAddressManager(contractAddressManager).getContractAddressForName(
controlledContractNames[i]
);
_pauseContract(addr);
}
}
As shown, it iterates through all contracts to pause them. However, if any contract has already been individually paused with pauseContract()
, the transaction will revert. This happens because _pauseContract()
invokes pause()
on the target contract, as defined in Pausable.sol.
function _pause() internal virtual whenNotPaused {
_paused = true;
emit Paused(_msgSender());
}
As shown, this requires that the contract be unpaused; otherwise, it reverts.
This is problematic in an emergency when you need to pause all contracts quickly. There’s no time to identify and unpause individual contracts, as every second is critical. This limitation hinders effective emergency response.
One of the protocol’s contracts is currently paused.
None.
None.
If a contract is already paused, calling pauseAll()
will cause a revert, preventing it from working as intended. In an emergency, this can be critical, as every second counts.
The previous sections demonstrate this issue.
To resolve this, check if the contract is unpaused; if it is, proceed to pause the contract.
function pauseAll() external onlyOwner {
for (uint256 i = 0; i < controlledContractNames.length; ++i) {
address addr = IContractAddressManager(contractAddressManager).getContractAddressForName(
controlledContractNames[i]
);
+ if (!IPausable(addr).paused()) {
+ _pauseContract(addr);
+ }
}
}