DevelopersSeptember 14, 2026by
Eoonia Wallet
Eoonia Wallet

The Eoonia Browser Extension: Injecting a Wallet That Speaks EmpoorioChain

A browser wallet for a Substrate chain has one job that looks trivial and is not: making polkadot-js produce a signature the chain accepts. On EmpoorioChain that requires knowing about two signed extensions no stock library has heard of. This post is for dApp developers who want to support Eoonia in the browser.

What the extension injects

const eoonia = window.injectedWeb3?.eoonia;
const injected = await eoonia.enable("My dApp");
const accounts = await injected.accounts.get();     // SS58 prefix 2026
const signer = injected.signer;                      // pass to ApiPromise

It follows the standard injectedWeb3 interface, so @polkadot/extension-dapp's web3Enable / web3Accounts discover it alongside other extensions.

The signed extensions problem

When polkadot-js builds an extrinsic it needs to know every signed extension the chain's runtime expects, in order, with their encoding. It reads most of them from metadata — but a custom extension's type must be registered by the client, or polkadot-js silently omits it and every byte after it shifts. The chain responds with a generic codec error.

EmpoorioChain has two. The extension registers them:

signedExtensions: {
  CheckPqcPolicy:      { extrinsic: { pqcSignature: "Option<Bytes>", batchReceipt: "Option<Bytes>" }, payload: {} },
  CheckDormantAccount: { extrinsic: {}, payload: {} },
}

A dApp that constructs its own ApiPromise must pass the same signedExtensions to ApiPromise.create, or use the API instance the extension exposes. Without this, nothing signs — and this is precisely the omission that kept the testnet transaction-free for its first 102,912 blocks.

Derivation

sr25519 from the recovery phrase with no derivation path yields the same vx… address as the Android app — a user's extension and phone agree.

EVM side

The extension also behaves as an Ethereum provider for chain id 2026: eth_requestAccounts, personal_sign, EIP-712 eth_signTypedData_v4, wallet_switchEthereumChain with chainChanged events from the popup. Since runtime 211 the chain accepts the resulting transactions.

Reliability

  • RPC failover: rpc.testnetrpc2.testnet automatically.
  • Network tiers: the extension distinguishes the public testnet from local development chains and refuses to sign for a chain whose genesis it does not recognise.
  • Metadata refresh after every runtime upgrade — eight happened in ten days in September 2026.

Tests

403 unit tests, run in Node rather than jsdom (under jsdom, Uint8Array instances from another realm break checksum comparisons — a real bug that cost a day). Three tests run against the live testnet, gated by a CI seed with a funded account; governance tests are gated separately because they lock 2,000 DMS.

Status

Built, tested, published to the ecosystem's repository. Not yet listed in a browser extension store. A dApp can load it unpacked today.

Based on the Eoonia extension work of 2026-09-07 (block 3) and FORMATO_DE_EXTRINSECOS.md.

Share this article