커스텀 에러 (Custom Error)
require(condition, "긴 문자열") 의 문자열 메시지는 그대로 바이트코드에 저장되어 배포 비용을 늘리고, 되돌림이 일어날 때 그 문자열을 인코딩하느라 실행 gas 도 더 씁니다. 검증이 많은 컨트랙트라면 이 비용이 계속 쌓입니다.
Solidity 0.8.4 에 들어온 커스텀 에러(custom error) 가 이 문제를 해결합니다.
선언과 사용
커스텀 에러는 error 키워드로 선언하고, revert 와 함께 발생시킵니다. 컨트랙트 안이나 파일 최상단(전역) 어디에든 선언할 수 있습니다.
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
error Unauthorized();
contract Vault {
address public owner = msg.sender;
function close() public view {
if (msg.sender != owner) {
revert Unauthorized();
}
// ... 정상 처리
}
}커스텀 에러가 더 저렴한 이유
커스텀 에러는 긴 문자열 대신, 에러 시그니처를 해시한 4바이트 선택자(selector) 로 인코딩됩니다. Unauthorized() 라는 의미가 단 4바이트로 압축되어 되돌려지는 것입니다.
문자열이 바이트코드에 들어가지 않으니 배포 크기가 줄고, 되돌림 시 인코딩할 데이터가 작으니 실행 가스도 줄어듭니다. 같은 정보를 더 싸게 전달하는 셈입니다.
커스텀 에러를 발생시키는 revert
커스텀 에러는 revert ErrorName() 형태로 발생시킵니다. Error(string) 으로 되돌리는 require/revert("...") 와는 인코딩 방식 자체가 다릅니다.
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
error DeadlinePassed();
contract Auction {
uint256 public deadline;
function bid() public view {
if (block.timestamp > deadline) revert DeadlinePassed();
}
}커스텀 에러 이름은 PascalCase 로 짓고, 무엇이 잘못됐는지 드러나도록 의미 있게 만드세요. 예:
InsufficientBalance, Unauthorized, DeadlinePassed.
커스텀 error 는 보통 revert ErrorName() 형태로만 발생시킵니다. require 의 두 번째 인자로
커스텀 에러를 직접 넘기는 문법은 비교적 최신 컴파일러에서만 지원되므로, 이 과정에서는 if (...) revert ... 패턴을 표준으로 씁니다.