---
title: Frontends on EmpoorioChain
description: Building a web frontend against the public testnet with @polkadot/api, the Eoonia Extension as signer, and honest handling of submitted / included / finalized.
---

# Frontends on EmpoorioChain

## Connect

```ts
import { ApiPromise, WsProvider } from "@polkadot/api";
const api = await ApiPromise.create({
  provider: new WsProvider("wss://rpc.testnet.empooriochain.org"),
});
// Sanity: api.runtimeVersion.specVersion === 220, ss58Format 2026, DMS 18 decimals
```

Respect the public rate limit (10 req/s per IP, one-hour ban): subscribe (`api.rpc.chain.subscribeFinalizedHeads`, `api.query.system.account(addr, cb)`) instead of polling, and run your own node for production traffic.

## Sign

Use the Eoonia Extension through `@polkadot/extension-dapp` (`web3Enable`, `web3Accounts`, `web3FromAddress`) — it exposes `window.injectedWeb3.eoonia`. Quote the fee first with `tx.paymentInfo(address)` and show it; validate against the transferable balance (bonded DMS is locked).

## Report states honestly

Every operation has three states and the UI must show all three: **submitted** (sent to the RPC), **included** (in a block, ~3.5 s p50), **finalized** (GRANDPA, ~17 s p50, irreversible). Inspect `ExtrinsicFailed` in `system.events` and report it; never show success for an included-but-failed extrinsic.

## Read

Native assets (`api.query.assets.account(assetId, addr)` — DUSD is #1), NFTs (`api.query.uniques.*`), staking (`api.query.empStaking.ledger(addr)`) are storage reads, no ABI. Nonces: read `System.Account`, not `accountNextIndex`.

## Serve

Static export or Next.js; no backend is needed to read, but "backend-less" apps hammer the shared RPC — cache and subscribe.
