Projects
Universal Profiles - Browser Extension app icon

Universal Profiles - Browser Extension

Contributor - background controllers and the DDD business-logic layer (later extracted into shared npm packages reused across the extension and LUKSO's mobile apps) · Sept 2023 – July 2026

Production wallet browser extension (Manifest V2 + V3) for LUKSO Universal Profiles - smart-contract accounts with granular on-chain permissions, gasless meta-transactions, and human-readable transaction decoding.

Browser ExtensionTypeScriptVue 3Web3Manifest V2 + V3
Onboarding welcome, a profile with its controllers, and a dApp permission request showing relayer quota usageWallet popup - Connections tab listing the dApps a profile is linked toControllers tab - the extension and other keys that hold partial control of the profilePer-controller permission editor showing granular on-chain permissions in plain languageActivity feed of profile data changes and value transfersTransaction confirmation decoding a smart-contract execution into a human-readable value transferAdvanced transaction view - network, relayer, gas limit and base feeDecoded transaction revealing the underlying execute() calldataEdit profile screen - changing avatar and cover image with IPFS uploadEncrypted backup export - warning shown before downloading the password-protected JSON fileRestore backup - uploading an encrypted profile backup fileOnboarding - create a new Universal Profile or recover an existing one

Universal Profiles are LUKSO's smart-contract accounts (LSP0 ERC725Account) owned by an LSP6 KeyManager, which grants named permissions - like SETDATA, CALL, DEPLOY, EDITPERMISSIONS, ADDCONTROLLER - to individual controller keys. This extension is the consumer wallet for that model: it injects an EIP-1193 provider into dApps, manages profiles and their controllers, presents permission changes in plain language, and can pay gas via a relay service so users transact without holding LYX.

Because the account lives on-chain rather than in a private key, there is no seed-phrase UI at all. Recovery works through encrypted JSON backup files, a QR-based cross-device import flow, where an already-authorized controller grants permissions to the new device or a restore flow through optionally configured controller key managed by LUKSO via https://my.universalprofile.cloud.

The extension runs a four-context topology - injected inpage provider → content script → background service worker → popup - with JSON-RPC multiplexed over duplex port streams. Above that, the business-logic layer is organized as DDD bounded contexts with a real domain / use-cases / infrastructure split on top of a shared @lukso/controllerapps-sharedlogic-ddd-core package.

Architecture & engineering highlights

  • Wallet feature set - onboarding and password setup, dApp connection approval, decoded transaction confirmation, message signing including SIWE, per-profile controller and permission management, gasless relayer configuration and quota, multi-network switching across LUKSO mainnet + testnet, Ethereum and Base, and many others, activity history, profile editing with IPFS image upload, QR cross-device import, encrypted backup export and restore, and configurable auto-lock.
  • Transaction-intent decoder with on-chain disambiguation - maps calldata to a set of human-readable renderers. Selectors are computed lazily from human-readable signatures rather than hardcoded, so they cannot drift out of sync, and ambiguous ones are resolved at confirmation time by live eth_call probes.
  • Sandboxed rendering of untrusted dApp data - decoded transaction content (token names, remote images, arbitrary calldata) renders inside an isolated iframe document rather than in the wallet's own DOM, so hostile metadata can never reach privileged UI.
  • LSP25 gasless meta-transactions - builds the relay-call digest, signs it using EIP-191 with the KeyManager as intended validator, and POSTs it to a relay service, with nonce channels, per-profile quota gating, and typed error paths.
  • Multi-target build for the extension's platform constraints - three ordered webpack compilers and a custom plugin that emits both V2 and V3 manifests from a single build. The MV3 service-worker compiler caps output at one chunk (Chrome forbids importScripts() after install) and forces inline source maps (MV3's CSP bans unsafe-eval); the inpage provider bundle is read off disk at build time and inlined as a string constant for page-world injection.
  • Domain layer extracted into shared packages - the backup / profile / keyring domain I built in-tree was factored out into @lukso/controllerapps-sharedlogic-* and re-integrated as a dependency, so the same domain logic now backs both the extension and LUKSO's mobile wallets.
  • Three transaction safeguards for failure modes that can brick a smart-contract account: blocking a transaction that would strip the extension's own controller permissions (self-lockout), preventing a profile from being set as its own controller, and rejecting no-op permission changes.
  • Wallet discovery and delivery - EIP-6963 multi-wallet discovery claims window.lukso and sets window.ethereum only when no other wallet owns it; the release pipeline runs end to end (release-please → draft GitHub prerelease → Chrome Web Store upload and publish via OAuth token exchange), with a Playwright harness that launches an unpacked extension in headed Chrome and tests split across three Jest configs feeding parallel CI jobs.

Tech stack

Extension & UI

TypeScript 5.5Vue 3.3Piniavue-routervue-i18nTanStack Vue QueryBulma + SCSSTailwind 3.4webextension-polyfill

Web3 & crypto

web3.js 1.10viem 2.33ethers 5.7@erc725/erc725.js@lukso/lsp-smart-contracts 0.15 (LSP0/1/3/4/5/6/7/8/12/25/26)@scure/bip32 + bip39@noble/secp256k1crypto-browserify / buffer / process

Extension platform & transport

Chrome MV2 + MV3@metamask/post-message-stream@metamask/object-multiplexPortDuplexStream (custom Duplex over Runtime.Port)

Storage

Dexie / IndexedDB

Build & tooling

webpack 5 (multi-compiler)Yarn 4 (Berry)ESLintstylelintBiomeHuskySentryGitHub Actions + release-please

Testing

Jest 29Playwright

All rights belong to their respective owners.