Audit Anomalies Archive — Issue#9

Zuhaib Mohammed
2 min readDec 19, 2023

Smart Contracts utilize the pausable pattern to halt their operation on the blockchain. The primary motivation behind implementing this design is to disable functionality during contract migration, upgrades, or, in the worst case, to prevent a potential hack.

The Pausable Library

Developers can incorporate the OpenZeppelin contract to integrate this feature into their contracts. Functions that should only be called when contracts are not paused should use the whenNotPaused modifier. Conversely, if a function is expected to be called in a paused state, the whenPaused modifier should be employed.

function abcd(uint value) public whenPaused {
//can be called when contract is paused
}

function xyz(uint value) public whenNotPaused {
//can be called when contract is not paused
}

It is essential for developers to guarantee that the pause and unpause functions are externally accessible to admins/owners for seamless toggling between them. There have been instances where developers inadvertently overlooked exposing these functions.”

function pause() external onlyOwner {
_pause();
}

function unpause() external onlyOwner {
_unpause();
}

Generally, projects may have different sets of contracts, such as Staking, Voting, DAO, etc. Each of these contracts may have its own Pausable pattern implemented.

Consider a scenario where the Staking contract needs to be paused, and simultaneously, a DAO vote is ongoing. Users who have staked their tokens in the Staking contract might be unable to vote in the DAO proposal. If the owner/admin is to pause all contracts, it should ideally happen in a single transaction to mitigate the risk of users listening to and front-running transactions. Moreover, Considering current gas prices, individually pausing multiple contracts could result in a costly transaction.

A straightforward solution would be to use a single contract for pausing and unpausing. This contract’s status can then be used across all smart contracts to track the current status.

The Bug

Now, let’s discuss a potential bug based on the described scenario. There are two contracts, Staking and Voting. The Staking contract inherits the pausable pattern for emergency cases, while the Voting contract does not. Imagine a situation where the Staking contract needs to be paused, but a Voting proposal is live. In this scenario, users who have staked their tokens cannot withdraw them, while token holders who haven’t staked can easily vote on the proposal. This leads to a Denial of Service(DoS) scenario for token stakers.

In conclusion, pausable contracts are valuable for emergency situations to prevent user funds from being compromised. However, developers must carefully analyze and design the architecture to avoid inconsistencies across smart contracts.

For a practical demonstration of this issue via Foundry, details can be found in this link.

Thanks for Reading !

Connect with me: https://linktr.ee/zuhaib44

--

--