testnet
GitHub EN

OKRW 프리컴파일 오류 처리 방법

integration intermediate

Solidity 스마트 컨트랙트와 Ethers.js를 사용하는 클라이언트 측 애플리케이션 모두에서 OKRW 프리컴파일의 사용자 정의 오류를 효과적으로 처리하는 방법을 배웁니다.

사전 요구사항

  • Solidity `try/catch`에 대한 기본 지식.
  • JavaScript `try/catch` 및 Ethers.js에 대한 익숙함.

온체인: Solidity에서 오류 처리

Solidity의 try/catch 문은 스마트 컨트랙트 내에서 외부 호출의 오류를 처리하는 주요 메커니즘입니다. 로우 레벨 catch (bytes memory reason) 절을 만들어 원시 revert 데이터를 검사할 수 있습니다. 거기서 4바이트 선택자를 확인하여 특정 사용자 정의 오류를 식별하고 해당 인수를 디코딩할 수 있습니다.
// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.18;

import "./IOkrw.sol";

contract ErrorHandler {
    IOkrw constant okrw = IOkrw(0x1000000000000000000000000000000000000001);

    event MintAttemptFailed(string reason);
    event Unauthorized(address caller, address expected);

    function attemptMint(address recipient, uint256 amount) external {
        try okrw.mint(recipient, amount) {
            // 성공 시 로직
        } catch (bytes memory reason) {
            bytes4 selector = bytes4(reason);

            if (selector == IOkrw.UnauthorizedMinter.selector) {
                (address caller, address authorizedMinter) = abi.decode(reason[4:], (address, address));
                emit Unauthorized(caller, authorizedMinter);
            } else if (selector == IOkrw.InvalidAddress.selector) {
                (address invalidAddr) = abi.decode(reason[4:], (address));
                emit MintAttemptFailed("Invalid address provided");
            } else {
                revert("Unknown precompile error");
            }
        }
    }
}
참고: 로우 레벨 `catch`를 사용하면 부모 함수의 실행을 중단하지 않고 다양한 오류 유형에 다르게 반응할 수 있는 최대의 제어권을 가질 수 있습니다.

오프체인: Ethers.js로 오류 처리

프론트엔드나 백엔드에서 프리컴파일과 상호작용할 때, Ethers.js와 같은 라이브러리는 revert 시 예외를 발생시킵니다. 사용자 정의 오류 데이터는 잡힌 객체의 error.data 필드에서 사용할 수 있습니다. 컨트랙트의 ABI 인터페이스를 사용하여 이 데이터를 오류 이름과 인수를 포함하는 사람이 읽을 수 있는 객체로 파싱할 수 있습니다.
const { ethers } = require("ethers");

const okrwPrecompileAddress = "0x1000000000000000000000000000000000000001";
const okrwAbi = [
    "function mint(address recipient, uint256 amount) external returns (bool)",
    "error UnauthorizedMinter(address caller, address authorizedMinter)",
    "error InvalidAddress(address addr)"
];

// 'unauthorizedSigner'가 공인된 발행자가 아닌 계정의 ethers.Signer라고 가정합니다.
const okrwContract = new ethers.Contract(okrwPrecompileAddress, okrwAbi, unauthorizedSigner);

async function main() {
    try {
        await okrwContract.mint("0xRecipientAddress...", ethers.parseEther("1"));
    } catch (e) {
        if (e.data) {
            const decodedError = okrwContract.interface.parseError(e.data);
            console.log(`Transaction failed with custom error: ${decodedError.name}`);
            
            if (decodedError.name === 'UnauthorizedMinter') {
                const [caller, authorizedMinter] = decodedError.args;
                console.log(`Caller ${caller} is not the authorized minter ${authorizedMinter}.`);
            }
        } else {
            console.error("An unexpected error occurred:", e.message);
        }
    }
}

main();
소스: maroo
ESC
검색어를 입력하세요