블록체인 학습
0 XP

try / catch 고급 활용

외부 호출이 실패하는 이유는 한 가지가 아닙니다. 상대가 require/revert("문자열") 로 되돌렸을 수도, 커스텀 error 로 되돌렸을 수도, assert 실패 같은 Panic 이 났을 수도 있습니다. catch 는 이 실패의 종류 에 따라 여러 갈래로 나눠 잡습니다. 덕분에 왜 실패했는지에 맞춰 다르게 대응할 수 있습니다.

catch 의 갈래들

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
 
interface IFeed {
    function getPrice() external returns (uint256);
}
 
contract Consumer {
    event Ok(uint256 price);
    event StringError(string reason);
    event PanicError(uint256 code);
    event LowLevelError(bytes data);
 
    function read(IFeed feed) public {
        try feed.getPrice() returns (uint256 price) {
            emit Ok(price);
        } catch Error(string memory reason) {
            // require / revert("...") 처럼 문자열 사유가 있는 실패
            emit StringError(reason);
        } catch Panic(uint256 code) {
            // assert 실패, 0 나눗셈, 배열 범위 초과 등
            emit PanicError(code);
        } catch (bytes memory data) {
            // 그 외 (커스텀 에러 등) 모든 실패를 원시 바이트로
            emit LowLevelError(data);
        }
    }
}

각 갈래의 의미

  • catch Error(string memory reason): revert("...") 나 require(false, "...") 처럼 Error(string) 으로 인코딩된 실패를 잡고, 그 문자열 사유를 꺼냅니다.
  • catch Panic(uint256 code): assert 실패, 0 나눗셈, 배열 범위 초과 등 Panic(uint256) 으로 인코딩된 내부 오류를 잡고, 원인을 나타내는 코드를 받습니다.
  • catch (bytes memory data): 위에서 잡히지 않은 그 외 모든 실패(대표적으로 커스텀 error)를 원시 바이트로 잡습니다. 가장 포괄적인 안전망입니다.

catch 를 나열하는 순서

세분화된 catch(Error, Panic)를 먼저 두고, 포괄적인 catch (bytes ...) 를 맨 아래 두어야 합니다. 그래야 각 실패가 가장 구체적인 갈래에서 처리됩니다.

커스텀 error 로 되돌려진 실패는 Error/Panic 어디에도 걸리지 않고 catch (bytes memory data) 로만 잡힙니다. 그 안에서 선택자를 비교해 어떤 커스텀 에러인지 식별할 수 있습니다.

외부 호출의 실패를 조용히 흡수하면 호출 측은 무엇이 잘못됐는지 모를 수 있습니다. catch 안에서 이벤트를 남기거나 상태를 기록해 추적 가능하게 하세요.

Code Editor
에디터를 불러오는 중...
실행 결과

Run 버튼을 눌러 코드를 실행하세요.