본문 바로가기
Hack/Cryptocurrency

ERC-165 (Ethereum Request for Comments 165)

by Becoming a Hacker 2023. 6. 21.
반응형

ERC-165 (Ethereum Request for Comments 165)

ERC-165는 Smart Contract에서 Interface 지원을 위해 사용하는 Ethereum 표준 규격으로, Smart Contract가 특정 Interface를 구현하고 있는 지 확인하는 기능을 지원합니다.

 

ERC-165: Standard Interface Detection

 

eips.ethereum.org

 

ERC-165를 준수하는 Smart Contract는 다른 Contract나 Client가 해당 Contract가 특정 Interface를 지원하고 있는 지 확인할 수 있도록 supportsInterface 함수가 구현되어있습니다.

pragma solidity ^0.4.20;

interface ERC165 {
    /// @notice Query if a contract implements an interface
    /// @param interfaceID The interface identifier, as specified in ERC-165
    /// @dev Interface identification is specified in ERC-165. This function
    ///  uses less than 30,000 gas.
    /// @return `true` if the contract implements `interfaceID` and
    ///  `interfaceID` is not 0xffffffff, `false` otherwise
    function supportsInterface(bytes4 interfaceID) external view returns (bool);
}

 

모든 Solidity는 4Byte의 Hash 값인 Selector를 가지고 있으며, Selector는 해당 함수의 이름과 매개변수의 타입 등을 조합하여 생성된 고유한 식별 값입니다. 해당 함수의 Selector 값을 확인할 수 있는 방법은 아래와 같습니다.

예시 함수 : function test(address test_address) external view returns (bool)

  1. keccak256을 이용한 해싱
    • bytes4(keccak256("test(address)"))
      • keccak256 함수를 사용하여 문자열을 해싱
      • 앞에서부터 4Byte 선택
  2. Contract 내부에서 각 메서드의 Selector 호출
    • this.test.selector
  3. type 함수와 .interfaceId 사용
    • bytes4 interfaceId = type(InterfaceName).interfaceId;
      • type 함수를 사용하여 인터페이스 유형을 가져옴
      • .interfaceId를 사용하여 인터페이스의 인터페이스 식별자 참조

 

ERC-165가 구현된 Smart Contract에서 특정 Interface의 구현 여부를 판단하는 방법도 이러한 Selector 값을 기준으로 확인을 하게 됩니다.

 

아래의 코드는 openzeppelin에서 ERC-165를 구현한 코드 입니다.

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol)

pragma solidity ^0.8.19;

import "./IERC165.sol";

/**
 * @dev Implementation of the {IERC165} interface.
 *
 * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check
 * for the additional interface id that will be supported. For example:
 *
 * ```solidity
 * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
 *     return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);
 * }
 * ```
 */
abstract contract ERC165 is IERC165 {
    /**
     * @dev See {IERC165-supportsInterface}.
     */
    function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {
        return interfaceId == type(IERC165).interfaceId;
    }
}

댓글