OKRW Precompile

component core

OKRW exposes two stable EVM surfaces — the IOkrw precompile at 0x1000…0001 for Maroo-specific operations (mint, getParams), and the native ERC20 representation at 0xEeeE…EEeE for standard ERC20 calls (transfer, approve, balanceOf).

OKRW is Maroo's KRW-pegged stablecoin and the chain's native gas token. From a Solidity caller's perspective it shows up at two fixed addresses on every network: the IOkrw precompile (0x1000000000000000000000000000000000000001) exposes Maroo-specific operations like mint and getParams, while the native ERC20 representation (0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE) is the canonical ERC20 surface registered at genesis as the default token pair for the aokrw base denom. Use the ERC20 address for any standard wallet / DEX / vault integration; use the IOkrw precompile only for Maroo-extension operations.

Architecture

graph TD
    A[dApp / Designated Minter] -- "mint(to, amount)" --> B[IOkrw Precompile @ 0x10...01];
    B -- Mint event --> C[Indexers / Wallets];
    A2[Any dApp] -- "getParams()" --> B;

    classDef evm fill:#0096AA,stroke:#0096AA,color:#fff;
    classDef precompile fill:#FF8C50,stroke:#FF8C50,color:#fff;
    class A,C,A2 evm;
    class B precompile;

The designated minter calls mint on the IOkrw precompile, which emits a Mint event; getParams exposes the configured minter and mint denom. OKRW then moves as native value like any EVM balance.

Two addresses, one token

OKRW is one token with two complementary EVM surfaces. Both addresses are stable across testnet and mainnet — hard-code them or read them from @maroo-chain/contracts.

SurfaceAddressUse for
IOkrw precompile0x1000000000000000000000000000000000000001mint, getParams, Maroo-specific extensions
Native ERC20 representation0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeEStandard transfer, approve, transferFrom, balanceOf, totalSupply, Approval / Transfer events

The ERC20 representation is registered at genesis as a token pair mapping aokrw (the 18-decimal base denom) to its ERC20 contract address, with OWNER_MODULE as the contract owner. Standard ERC20 ABIs work against it unchanged.
// Standard ERC20 path — wallets, DEXs, vaults
IERC20 okrw = IERC20(0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE);
okrw.transfer(recipient, 10_000_000 ether);   // 10,000,000 OKRW
okrw.approve(spender, 10_000_000 ether);

// Maroo-extension path — minter operations
import "@maroo-chain/contracts/precompiles/okrw/IOkrw.sol";
IOkrw extn = IOkrw(0x1000000000000000000000000000000000000001);
extn.mint(recipient, 10_000_000 ether);       // authorized minter only

Denominations and unit conversion

OKRW uses Ethereum-style 18-decimal accounting. The base denom is aokrw (1 OKRW = 10^18 aokrw); the display denom is okrw. Note that aokrw is the gas / fee denom, while staking uses a separate denom (amaroo). Solidity literals that read as 1_000_000 ether mean 1,000,000 OKRW.
// 10,000,000 OKRW — a realistic transfer-cap example amount
uint256 amount = 10_000_000 ether;     // 10_000_000 * 10**18 aokrw
okrw.transfer(recipient, amount);

Why both surfaces exist

The native ERC20 representation is what every off-the-shelf EVM tool expects to see — wallets enumerate balances against it, DEX routers add it as a liquidity leg, accounting tools index its Transfer events. The IOkrw precompile carries Maroo-specific operations that don't fit the ERC20 interface (controlled minting by the authorized minter, parameter discovery via getParams). Both ultimately move the same underlying aokrw balances; choosing the right address is just a matter of which API surface the call needs.

Controlled minting authority

Unlike open-mint ERC20s, only the configured authorized minter address can successfully call IOkrw.mint. Any other caller reverts with UnauthorizedMinter(caller, authorizedMinter). Rotating the minter is a consortium-governance action and not something an external dApp performs. Read the current minter via IOkrw.getParams() and treat the answer as authoritative for routing mint requests through the right operator.
import "@maroo-chain/contracts/precompiles/okrw/IOkrw.sol";

IOkrw okrw = IOkrw(0x1000000000000000000000000000000000000001);
address minter = okrw.getParams().minter;
require(msg.sender == minter, "not authorized to mint");

Reading balances from off-chain code

Use the ERC20 address with any standard reader (viem, ethers, cast). The same address is also visible to the block explorer at https://explorer-testnet.maroo.io as an ERC20-style account.
import { createPublicClient, http, parseAbi } from "viem";

const OKRW_ERC20 = "0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE";
const erc20Abi = parseAbi([
  "function balanceOf(address) view returns (uint256)",
  "function totalSupply() view returns (uint256)",
]);

const client = createPublicClient({ transport: http("https://rpc-testnet.maroo.io") });
const balance = await client.readContract({
  address: OKRW_ERC20,
  abi: erc20Abi,
  functionName: "balanceOf",
  args: ["0xUserAddress..."],   // replace before production
});
Source: maroo
ESC
Type to search