testnet
GitHub

How to Handle OKRW Precompile Errors

integration intermediate

Learn how to effectively handle custom errors from the OKRW precompile in both Solidity smart contracts and client-side applications using Ethers.js.

Prerequisites

  • Basic knowledge of Solidity `try/catch`.
  • Familiarity with JavaScript `try/catch` and Ethers.js.

On-Chain: Handling Errors in Solidity

Solidity's try/catch statement is the primary mechanism for handling errors from external calls within a smart contract. You can create a low-level catch (bytes memory reason) clause to inspect the raw revert data. From there, you can check the 4-byte selector to identify the specific custom error and decode its arguments.
// 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) {
            // Logic on success
        } 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");
            }
        }
    }
}
Note: Using low-level `catch` gives you maximum control to react differently to various error types without halting execution of the parent function.

Off-Chain: Handling Errors with Ethers.js

When interacting with the precompile from a frontend or backend, libraries like Ethers.js will throw an exception on revert. The custom error data is available in the error.data field of the caught object. You can use the contract's ABI interface to parse this data into a human-readable object containing the error name and arguments.
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)"
];

// Assume 'unauthorizedSigner' is an ethers.Signer for an account
// that is NOT the authorized minter.
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();
Source: maroo
ESC
Type to search