sherlock-audit / 2023-01-uxd-judging

3 stars 1 forks source link

HonorLt - OFT abandons OFTCore supported interfaces #401

Closed github-actions[bot] closed 1 year ago

github-actions[bot] commented 1 year ago

HonorLt

medium

OFT abandons OFTCore supported interfaces

Summary

Contract OFT incorrectly overrides the supportsInterface function making some of the supported values return false.

Vulnerability Detail

OFT overrrides supportsInterface from OFTCore and IERC165:

    function supportsInterface(bytes4 interfaceId) public view virtual override(OFTCore, IERC165) returns (bool) {
        return interfaceId == type(IOFT).interfaceId || interfaceId == type(IERC20).interfaceId || super.supportsInterface(interfaceId);
    }

It adds its own types and finally calls the supper method for the inherited methods. However, it overrides 2 different interfaces, thus the supper is called only on the most right override (IERC165), making it lose the values returned from OFTCore:

    function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165, IERC165) returns (bool) {
        return interfaceId == type(IOFTCore).interfaceId || super.supportsInterface(interfaceId);
    }

For more context, here is a Twitter thread warning about similar issues: https://twitter.com/0xCygaar/status/1604226205724553216?s=20

Impact

Other contracts that rely on introspection values might treat the contract as incompatible even though it implements the necessary functions.

Code Snippet

Proof of concept:

// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

abstract contract A {
    function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {
        return interfaceId == type(A).interfaceId;
    }

    function a() public view virtual returns (string memory) {
        return "a";
    }
}

abstract contract B {
    function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {
        return interfaceId == type(B).interfaceId;
    }

    function b() public view virtual returns (string memory) {
        return "B";
    }
}

interface IOFT {
    function oft() external view returns (string memory);
}

contract OFT is IOFT, A, B {
    bytes4 public typeA = type(A).interfaceId;
    bytes4 public typeB = type(B).interfaceId;
    bytes4 public typeOFT = type(IOFT).interfaceId;

    function supportsInterface(bytes4 interfaceId) public view virtual override(A, B) returns (bool) {
        return interfaceId == type(IOFT).interfaceId || super.supportsInterface(interfaceId);
    }

    function oft() public pure override returns (string memory) {
        return "OFT";
    }
}
  1. Deploy OFT.
  2. Call supportsInterface with all three values (typeA, typeB, typeOFT) and see the results. typeA should return false, others true.

https://github.com/sherlock-audit/2023-01-uxd/blob/main/contracts/external/layer-zero/token/oft/OFT.sol#L14-L16

Tool used

Manual Review

Recommendation

Consider fixing the inheritance tree to correctly account for all the supported interfaces or manually include all of them.