Audit Anomalies Archive — Issue#4

Zuhaib Mohammed
2 min readSep 8, 2023

--

Is it true that smart contracts are immutable? Well, not exactly. Smart contracts can be upgraded once they are deployed. To simplify how this works, think of two contracts: a proxy and an implementation contract. The proxy contract stores all the state variables but relies on the implementation contract for its logic using delegatecall. If you encounter a bug or need to add new features, you can upgrade the logic contract.

When writing smart contracts, it’s advisable for developers to leverage existing, battle-tested code rather than crafting custom solutions for the same task. Failure to conduct thorough unit testing can introduce bugs or vulnerabilities in the contract.

I recently audited a codebase that lacked any unit test cases. Many assumptions made during code development can be invalidated during testing by the developer if proper unit test cases are written. Going back to the issue at hand, the developer attempted to implement a custom version of the OpenZeppelin’s OwnerUpgradable contract but didn’t test it throughly.

Upgradable contracts typically do not use constructors; instead, they employ initialize functions with an initializer modifier to ensure they can be called only once. Consider a contract ProductManager with an initialize function and inherits the OwnerUpgradable contract with its own initialize function, e.g., function __owner_governable_init.

contract ProductManager is UUPSUpgradeable, OwnerGovernable {

function initialize() public initializer {
discountEnabled = true;
__owner_governable_init();
}
}

contract OwnerGovernable is Initializable {

function __owner_governable_init() internal initializer {
//custom function
governor = msg.sender;
owner = msg.sender;
}
}

Both contracts have an initializer modifier.

The should ring a bell in your head. when the proxy was deployed and the initialize function of ProductManager was called, the proxy reverted with the error message “Initializable: contract is already initialized”. This occurred because the initializer modifier was used twice.

For a practical demonstration of this issue via Foundry, you can find more details in this link.

Thank For Reading.

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

--

--