Mini Apps

Ethereum provider

Use the mini-app Ethereum provider and EIP-6963 discovery helpers.

Use the Ethereum helpers when your mini app needs the injected EIP-1193 window.ethereum provider for EVM accounts, chain switching, native transfers, or ERC-20 reads and writes.

Do not use these helpers when you only need the Nimiq provider. Use the provider runtime page for window.nimiq.

Choose the Ethereum helper

Use requestMiniAppEthereumAccount() when a button click needs one connected address. It first reads eth_accounts, then asks with eth_requestAccounts only when no account is connected.

Use getMiniAppEthereumAccounts() when you need a non-prompting account check.

Use discoverEip6963Providers() only when wallet discovery semantics matter. Direct window.ethereum access is enough for most mini apps.

Connect one account

app/ethereum-account.ts
import { requestMiniAppEthereumAccount } from '@onmax/nimiq-mini-app-kit'

export async function connectEthereumAccount() {
  return await requestMiniAppEthereumAccount()
}

Expected behavior:

  • If the account is already connected, the helper returns it without prompting.
  • If no account is connected, Nimiq Pay asks the user to approve eth_requestAccounts.
  • Concurrent callers share one pending account request.

Switch to Polygon before a USDT read

Use the active chain deliberately before token reads or writes. USDT on Polygon uses 6 decimals.

app/polygon-usdt.ts
import {
  initMiniAppEthereumProvider,
  requestMiniAppEthereumAccount,
} from '@onmax/nimiq-mini-app-kit'
import { decodeFunctionResult, encodeFunctionData, formatUnits, parseAbi } from 'viem'

const USDT_POLYGON = '0xc2132D05D31c914a87C6611C10748AEb04B58e8F'
const ERC20_ABI = parseAbi([
  'function balanceOf(address account) view returns (uint256)',
])

export async function readPolygonUsdtBalance() {
  const ethereum = await initMiniAppEthereumProvider({ timeout: 10_000 })
  const account = await requestMiniAppEthereumAccount({ provider: ethereum })

  await ethereum.request({
    method: 'wallet_switchEthereumChain',
    params: [{ chainId: '0x89' }],
  })

  const data = encodeFunctionData({
    abi: ERC20_ABI,
    functionName: 'balanceOf',
    args: [account as `0x${string}`],
  })

  const rawBalance = await ethereum.request<`0x${string}`>({
    method: 'eth_call',
    params: [{ to: USDT_POLYGON, data }, 'latest'],
  })

  const balance = decodeFunctionResult({
    abi: ERC20_ABI,
    functionName: 'balanceOf',
    data: rawBalance,
  })

  return formatUnits(balance, 6)
}

Expected result in the deterministic simulator when the account has 1000000 raw units:

output
1

Add a missing chain after switch failure

Use wallet_addEthereumChain when wallet_switchEthereumChain fails because the chain is unknown to the host.

app/ensure-base.ts
import { initMiniAppEthereumProvider } from '@onmax/nimiq-mini-app-kit'

const BASE = {
  chainId: '0x2105',
  chainName: 'Base',
  nativeCurrency: { name: 'Ether', symbol: 'ETH', decimals: 18 },
  rpcUrls: ['https://mainnet.base.org'],
  blockExplorerUrls: ['https://basescan.org'],
}

export async function ensureBaseChain() {
  const ethereum = await initMiniAppEthereumProvider()

  try {
    await ethereum.request({
      method: 'wallet_switchEthereumChain',
      params: [{ chainId: BASE.chainId }],
    })
  }
  catch (error) {
    if ((error as { code?: number }).code !== 4902)
      throw error

    await ethereum.request({
      method: 'wallet_addEthereumChain',
      params: [BASE],
    })
  }
}

Expected behavior:

  • Known chain: the host asks the user to approve the switch.
  • Unknown chain with 4902: the host asks the user to add the chain.
  • Any other error stays visible to your app.

Discover announced providers

Use EIP-6963 discovery when an embedded wallet chooser or simulator shell needs provider announcements.

app/discover-wallets.ts
import { discoverEip6963Providers } from '@onmax/nimiq-mini-app-kit'

export async function listAnnouncedWallets() {
  const providers = await discoverEip6963Providers({ waitMs: 50 })

  return providers.map(({ info }) => ({
    name: info.name,
    rdns: info.rdns,
  }))
}

Do not pass timeout here. The helper option is waitMs.

Announce a simulator provider

Use registerEip6963Provider() when a custom host shell owns the provider and wants app-side discovery to find it.

host/register-provider.ts
import {
  registerEip6963Provider,
  type MiniAppEthereumProvider,
} from '@onmax/nimiq-mini-app-kit'

export function registerSimulatorWallet(provider: MiniAppEthereumProvider) {
  return registerEip6963Provider({
    uuid: '9d95c7a2-20ef-4b6f-9df7-a77b151e8051',
    name: 'Nimiq Pay Simulator',
    icon: '',
    rdns: 'com.nimiq.pay.simulator',
  }, provider)
}

Expected behavior:

  • The provider announces immediately.
  • It announces again when the page dispatches eip6963:requestProvider.
  • The returned cleanup function removes the event listener.

Runtime rules

  • Use eth_signTypedData_v4 for structured approvals, permits, and typed login challenges.
  • Use personal_sign only for plain text.
  • Switch to the intended chain before token reads or writes.
  • Parse and format token amounts with the token's real decimals.
  • Do not request accounts or signatures on page load.
Copyright © 2026