HardhatDeFi
15,000 USDC
View results
Submission Details
Severity: medium
Invalid

Inconsistent Owner Initialization Between `AaveDIVAWrapperCore.sol` and `WToken.sol`

Summary

The contracts AaveDIVAWrapperCore.sol and WToken.sol handle owner initialization inconsistently. While AaveDIVAWrapperCore uses OpenZeppelin's Ownable2Step contract to initialize the owner, WToken manually sets an _owner variable in its constructor. This inconsistency creates confusion, increases the likelihood of errors, and leads to ambiguity regarding the ownership structure. Additionally, WToken.sol does not align with the OpenZeppelin ownership standard, which could hinder maintainability and interoperability.


Vulnerability Details

Type: Mismanagement of Ownership Initialization and Standard Deviation

Issue 1: Inconsistent Owner Initialization

  • Location:

    • AaveDIVAWrapperCore.sol initializes ownership using OpenZeppelin's Ownable2Step:

      @> constructor(address diva_, address aaveV3Pool_, address owner_) Ownable(owner_) {
    • WToken.sol manually sets _owner in its constructor:

      _owner = owner_;
  • Problem:

    • The owner of WToken is the AaveDIVAWrapperCore contract itself:

      WToken _wTokenContract = new WToken(..., address(this)); // wToken owner is the wrapper contract
    • However, the AaveDIVAWrapperCore relies on OpenZeppelin's ownership mechanisms, while WToken uses a custom _owner variable. This divergence creates inconsistency:

      • Ownership logic across the system is unclear and difficult to track.

      • Developers and auditors cannot rely on a uniform pattern.

      • Future maintainers might misinterpret the ownership logic.


Issue 2: Non-Standard Ownership in WToken

  • Location: WToken.sol:

    address private _owner; // Custom ownership logic
  • Problem:

    • The _owner variable does not use OpenZeppelin's Ownable or Ownable2Step contracts, which are industry standards.

    • This custom ownership logic lacks key OpenZeppelin features, such as ownership transfer mechanisms (transferOwnership or transferOwnershipWithTwoSteps).

    • The lack of an ownership transfer function makes ownership immutable, which is a design decision that should be explicitly documented.


Impact

Severity: Medium

  1. Functionality Impact:

    • No direct security risk is posed, but the inconsistency can lead to developer confusion and implementation errors when extending the system.

  2. Maintainability Impact:

    • Custom ownership in WToken deviates from OpenZeppelin standards, reducing clarity and interoperability.

  3. Risk of Mismanagement:

    • If ownership behavior diverges between the contracts, it could lead to unexpected governance or operational issues in the future.


Tools Used

The following tools and techniques were used to identify and analyze the issue:

  • Static Code Review: Manual inspection of ownership-related logic.

  • Solidity Compiler (v0.8.26): Verified owner initialization and inheritance mechanisms.

  • OpenZeppelin Documentation: Compared ownership patterns against established best practices.


Recommendations

Recommendation 1: Use OpenZeppelin’s Ownership Standard for WToken

  • Replace the custom _owner variable in WToken with OpenZeppelin's Ownable contract:

    contract WToken is IWToken, ERC20, Ownable {
    uint8 private _decimals;
    constructor(string memory symbol_, uint8 decimals_, address owner_) ERC20(symbol_, symbol_) {
    _transferOwnership(owner_); // Use OpenZeppelin's ownership mechanism
    _decimals = decimals_;
    }
    }
  • This ensures consistency in ownership management across all contracts.


Recommendation 2: Clearly Document Ownership Relationships

  • Clarify that:

    • The AaveDIVAWrapperCore contract acts as the owner of all WToken instances.

    • Ownership of WToken is immutable after deployment.

  • Include this information in the documentation or inline comments for future reference.


Recommendation 3: Consider Making Ownership Immutable in WToken

  • If ownership of WToken is meant to be immutable, declare the owner as immutable:

    address private immutable _owner;
    constructor(string memory symbol_, uint8 decimals_, address owner_) ERC20(symbol_, symbol_) {
    _owner = owner_; // Immutable initialization
    _decimals = decimals_;
    }
    modifier onlyOwner() {
    require(msg.sender == _owner, "WToken: caller is not the owner");
    _;
    }
  • Document the decision to use immutable ownership for transparency.


Recommendation 4: Test for Ownership Inconsistencies

  • Add unit tests to verify ownership relationships:

    • Ensure AaveDIVAWrapperCore is the owner of all WToken instances.

    • Confirm that only the owner can mint/burn tokens in WToken.


Example Implementation

Updated WToken Contract Using OpenZeppelin’s Ownable

contract WToken is IWToken, ERC20, Ownable {
uint8 private _decimals;
constructor(string memory symbol_, uint8 decimals_, address owner_) ERC20(symbol_, symbol_) {
_transferOwnership(owner_); // Initialize ownership
_decimals = decimals_;
}
function mint(address _recipient, uint256 _amount) external onlyOwner {
_mint(_recipient, _amount);
}
function burn(address _redeemer, uint256 _amount) external onlyOwner {
_burn(_redeemer, _amount);
}
function decimals() public view override returns (uint8) {
return _decimals;
}
}

Benefits of Recommendations

  1. Clarity: Unified ownership logic improves code readability and reduces developer confusion.

  2. Interoperability: Adopting OpenZeppelin standards ensures compatibility with other DeFi systems.

  3. Maintainability: Standardized ownership reduces technical debt and simplifies future upgrades.

Updates

Lead Judging Commences

bube Lead Judge 9 months ago
Submission Judgement Published
Invalidated
Reason: Design choice

Support

FAQs

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