Core Contracts

Regnum Aurum Acquisition Corp
HardhatReal World AssetsNFT
77,280 USDC
View results
Submission Details
Severity: medium
Invalid

Incorrect Use of Constructor in Upgradeable Contract Leads to Ownership Initialization Failure

Summary

The StabilityPool contract is designed to be upgradeable but incorrectly uses a constructor to initialize _initialOwner. Upgradeable contracts should use an initializer function instead, as constructors are not executed in proxy deployments. This issue can lead to _initialOwner never being set properly, potentially causing unintended access control vulnerabilities.

Vulnerability Details

Vulnerability location: StabilityPool.sol#L59-L61

contract StabilityPool is IStabilityPool, Initializable, ReentrancyGuard, OwnableUpgradeable, PausableUpgradeable {
// [...]
// Constructor
@> constructor(address initialOwner) {
_initialOwner = initialOwner;
}
// [...]
}

Impact

  • Owner Not Set: If _initialOwner is meant to define the contract owner, it will remain unset when deployed via a proxy. This could lead to loss of ownership control

  • Access Control Issues: Functions relying on onlyOwner may become permanently inaccessible or behave unexpectedly.

  • Deployment Failures: The constructor’s purpose is defeated in an upgradeable setup, leading to confusion and potential deployment issues.

Tools Used

  • Manual code review

Recommendations

  • Remove the constructor and move _initialOwner initialization inside the initialize function:

contract StabilityPool is IStabilityPool, Initializable, ReentrancyGuard, OwnableUpgradeable, PausableUpgradeable {
// [...]
- // Constructor
- constructor(address initialOwner) {
- _initialOwner = initialOwner;
- }
/**
* @notice Initializes the StabilityPool contract.
* @param _rToken Address of the RToken contract.
* @param _deToken Address of the DEToken contract.
* @param _raacToken Address of the RAAC token contract.
* @param _raacMinter Address of the RAACMinter contract.
+ * @param initialOwner Address of the initial owner.
*/
function initialize(
address _rToken,
address _deToken,
address _raacToken,
address _raacMinter,
address _crvUSDToken,
address _lendingPool,
+ address initialOwner
) public initializer {
if (
_rToken == address(0) || _deToken == address(0) || _raacToken == address(0) || _raacMinter == address(0)
|| _crvUSDToken == address(0) || _lendingPool == address(0)
) revert InvalidAddress();
- __Ownable_init(_initialOwner);
+ __Ownable_init(initialOwner);
__Pausable_init();
rToken = IRToken(_rToken);
deToken = IDEToken(_deToken);
raacToken = IRAACToken(_raacToken);
raacMinter = IRAACMinter(_raacMinter);
crvUSDToken = IERC20(_crvUSDToken);
lendingPool = ILendingPool(_lendingPool);
// Get and store the decimals
rTokenDecimals = IRToken(_rToken).decimals();
deTokenDecimals = IDEToken(_deToken).decimals();
}
Updates

Lead Judging Commences

inallhonesty Lead Judge 7 months ago
Submission Judgement Published
Invalidated
Reason: Non-acceptable severity

Support

FAQs

Can't find an answer? Chat with us on Discord, Twitter or Linkedin.

Give us feedback!