Understanding Maroo Address Formats

integration intermediate

Maroo accounts have two equivalent string representations — EVM hex (0x…) and Bech32 (maroo1…). When each one matters, and how to convert between them in JS/TS.

Maroo accounts have two equivalent string forms — 0x… (EVM) and maroo1… (Bech32). For dApp work the EVM form is the default surface; Bech32 only shows up when you query non-EVM endpoints (validator / governance modules) or interface with IBC.

Prerequisites

  • Basic understanding of EVM hex addresses (e.g., from Ethereum).

EVM hex (the default surface)

The standard 42-character 0x… address. This is what MetaMask shows, what Solidity uses, what JSON-RPC returns, what the Maroo block explorer displays, and what every viem / ethers / Hardhat / Foundry tool expects.

Example: 0x71C7656EC7ab88b098defB751B7401B5f6d8976F

Bech32

Same 20-byte account ID, encoded with a network-identifying HRP (maroo for Maroo) and a checksum. You'll see this when:

  • querying validator / staking / governance modules (they take Bech32),
  • inspecting non-EVM query results,
  • interfacing with IBC (counterparty addresses).


Example: maroo1g9aher02v4dmf49m26de25d2n0a2th8g3z4x9a

It's the same key material — just a different string representation.

Converting between them in JS/TS

Both directions are O(1) — there's no network call. Use @cosmjs/encoding for Bech32 (it's lightweight and ships in many wallet stacks already), and ethers/viem hex helpers for 0x form.
import { fromBech32, toBech32 } from "@cosmjs/encoding";
import { getAddress, hexToBytes, bytesToHex } from "viem"; // or ethers equivalents

const HRP = "maroo";

// hex -> bech32
export function hexToBech32(hex: `0x${string}`): string {
  const bytes = hexToBytes(hex);
  return toBech32(HRP, bytes);
}

// bech32 -> hex (checksummed)
export function bech32ToHex(addr: string): `0x${string}` {
  const { data } = fromBech32(addr);
  return getAddress(`0x${bytesToHex(data).slice(2)}`);
}

// example round-trip
const hex     = "0x71C7656EC7ab88b098defB751B7401B5f6d8976F";
const bech32  = hexToBech32(hex);
// 'maroo1g9aher02v4dmf49m26de25d2n0a2th8g3z4x9a'
const andBack = bech32ToHex(bech32);
// '0x71C7656EC7ab88b098defB751B7401B5f6d8976F'
Note: Bech32 has a built-in checksum, so fromBech32 throws on typos. The 0x form has no checksum on its own — use viem's getAddress (or ethers' getAddress) to apply EIP-55 mixed-case checksumming.

Specialized prefixes

Bech32 has prefix variants for non-account roles. You'll only meet them when interfacing with validator / governance modules:

  • maroovaloper1… — validator operators (staking module messages).
  • maroovalcons1… — validator consensus addresses.
  • maroopub1… / maroovaloperpub1… — public-key encoded forms (rare in app code).


Account-level dApp work essentially never needs these.

Conclusion

Default to the 0x… form everywhere. Convert to Bech32 only at the boundary with validator / governance endpoints. The Maroo block explorer is EVM-style — it shows accounts at their 0x… URLs, so wallets and dashboards rendering EVM addresses are already aligned with what users see on the explorer.
ESC
Type to search