How to Add a New Built-in dApp to Nautilus Wallet: 6-Step Implementation Guide
To add a new built-in dApp to Nautilus Wallet, create a Vue component in src/dapps/, register the dApp in src/dapps/dappsManifest.ts, and add a route in src/extension/popup/router.ts after providing translations and an icon.
Nautilus Wallet is an open-source browser extension wallet for the Ergo blockchain that ships with built-in dApps like SigmaUSD and Wallet Optimizer. If you are contributing to the nautls/nautilus-wallet repository, adding a new built-in dApp to Nautilus Wallet follows a predictable pipeline that integrates your component into the existing Vue 3 architecture.
Prerequisites and Overview
Before adding a built-in dApp, ensure you have the repository cloned and dependencies installed (pnpm install). The wallet uses Vue 3 with TypeScript, Vue Router, and Lucide icons. Built-in dApps are not external websites; they are first-party Vue components rendered inside the wallet's popup interface.
The process involves six distinct steps: creating the UI component, adding translation keys, providing an icon, registering in the manifest, configuring the router, and optionally adding tests.
Step-by-Step Process for Adding a Built-in dApp
1. Create the dApp UI Component
Create a new directory under src/dapps/ containing your Vue single-file component. Use the existing built-in dApps as templates.
<!-- src/dapps/my-dapp/MyDappView.vue -->
<script setup lang="ts">
import { ref } from "vue";
const message = ref("Hello from My dApp!");
</script>
<template>
<div class="p-4">
<h2 class="text-xl font-bold">{{ message }}</h2>
<!-- dApp-specific UI goes here -->
</div>
</template>
<style scoped>
/* optional component-scoped CSS */
</style>
The component is lazy-loaded by the router, so you can import services, composables, or heavy libraries without impacting initial load time. Reference src/dapps/sigma-usd/SigmaUSDView.vue or src/dapps/wallet-optimization/WalletOptimizationDApp.vue for production patterns.
2. Add Translation Entries
Add a title key for your dApp in every locale file under src/i18n/locales/. At minimum, update en-US.json.
// src/i18n/locales/en-US.json
{
"dapps": {
"myDapp": {
"title": "My Awesome dApp"
}
}
}
Repeat this entry in all supported locale files (e.g., es.json, ru.json). The tileKeypath in the manifest will reference this key as myDapp.title.
3. Provide an Icon
You have two options for the dApp tile icon:
Option A: SVG Asset
Place an SVG file in your dApp directory and import it as a Vue component:
// In src/dapps/dappsManifest.ts
import MyDappLogo from "./my-dapp/my-dapp-logo.svg";
Option B: Lucide Icon
Import any icon from the lucide-vue-next library:
import { Coffee } from "lucide-vue-next";
The icon must be a Vue component that can be rendered dynamically with <component :is="...">.
4. Register the dApp in the Manifest
Open src/dapps/dappsManifest.ts and add your dApp to the dappsManifest array. Use the component() helper defined in the same file to wrap your icon.
// src/dapps/dappsManifest.ts
import { component } from "./dappsManifest"; // helper function
import MyDappLogo from "./my-dapp/my-dapp-logo.svg";
export const dappsManifest: DAppManifestItem[] = [
// ...existing entries (SigmaUSD, Wallet Optimizer)
{
tileKeypath: "myDapp.title", // matches translation key
icon: component(MyDappLogo), // or component(Coffee, { size: 24 })
path: "/dapps/my-dapp" // URL route
}
];
The manifest drives the tile grid displayed in src/views/dapps/DappsList.vue. Each entry automatically generates a clickable card that navigates to the specified path.
5. Add the Router Entry
Expose your component under /dapps/<path> by adding a child route in src/extension/popup/router.ts. Insert the object into the children array of the /dapps route (around lines 60-68).
// src/extension/popup/router.ts
{
path: "my-dapp",
name: "my-dapp",
component: () => import("@/dapps/my-dapp/MyDappView.vue")
}
The router automatically constructs the full path /dapps/my-dapp, which must match the path declared in the manifest. The lazy-load function ensures the component code is only fetched when the user navigates to the dApp.
6. (Optional) Add Tests and Documentation
Maintain code quality by adding unit tests under tests/unit/ that mount your component and verify basic rendering. If your dApp exposes a public API for other connectors, document it in docs/dapp-connector/.
Complete Working Example
Here is the minimal set of changes required to add a dApp named "Portfolio Tracker":
Translation (src/i18n/locales/en-US.json):
{
"dapps": {
"portfolioTracker": {
"title": "Portfolio Tracker"
}
}
}
Manifest (src/dapps/dappsManifest.ts):
import { component } from "./dappsManifest";
import PortfolioIcon from "./portfolio-tracker/portfolio-icon.svg";
export const dappsManifest: DAppManifestItem[] = [
{
tileKeypath: "portfolioTracker.title",
icon: component(PortfolioIcon),
path: "/dapps/portfolio-tracker"
}
];
Router (src/extension/popup/router.ts):
{
path: "portfolio-tracker",
name: "portfolio-tracker",
component: () => import("@/dapps/portfolio-tracker/PortfolioTrackerView.vue")
}
After running pnpm dev, the "Portfolio Tracker" tile appears in the dApps gallery and navigates to your component.
Key Files Reference
| Purpose | File Path | Source Link |
|---|---|---|
| dApp manifest registry | src/dapps/dappsManifest.ts |
View on GitHub |
| Popup router configuration | src/extension/popup/router.ts |
View on GitHub |
| dApp list UI (tile grid) | src/views/dapps/DappsList.vue |
View on GitHub |
| Translation files | src/i18n/locales/*.json |
View en-US |
| Example: SigmaUSD dApp | src/dapps/sigma-usd/SigmaUSDView.vue |
View on GitHub |
| Example: Wallet Optimizer | src/dapps/wallet-optimization/WalletOptimizationDApp.vue |
View on GitHub |
Summary
- Create a Vue 3 component under
src/dapps/<your-dapp>/to house the user interface. - Translate by adding a title key under
dapps.<name>.titlein every locale file. - Icon your dApp using either an SVG import or a
lucide-vue-nextcomponent. - Register the dApp in
src/dapps/dappsManifest.tswithtileKeypath,icon, andpath. - Route the component in
src/extension/popup/router.tsas a child of/dappswith matching path. - Test your implementation by running
pnpm devand verifying the tile appears in the dApps gallery.
Frequently Asked Questions
Do I need to manually update the dApps list view to show my new tile?
No. The DappsList.vue component automatically renders tiles based on the dappsManifest array defined in src/dapps/dappsManifest.ts. As long as you register your dApp in the manifest with a valid tileKeypath and icon, the UI will display it without additional changes to the list view component.
Can I use external npm libraries in my built-in dApp?
Yes. Since built-in dApps are standard Vue 3 components, you can import external libraries from npm. The component is lazy-loaded via the router's dynamic import, so heavy dependencies will only be fetched when the user navigates to your dApp. Follow the existing patterns in SigmaUSDView.vue for service integration.
How do I handle state management within a built-in dApp?
Built-in dApps can use Vue's Composition API with ref and reactive for local state, or integrate with the wallet's existing composables located in the src/composables/ directory. For global state shared across the extension, import the relevant stores from src/stores/. The Wallet Optimizer dApp demonstrates complex state synchronization with the wallet's UTXO set.
What is the difference between a built-in dApp and a connected dApp?
Built-in dApps are first-party Vue components bundled directly into the extension source code and rendered inside the wallet's popup UI. Connected dApps are external websites that communicate with the wallet via the dApp Connector API (ERG-47). Built-in dApps have full access to internal services and don't require connection permissions, while connected dApps operate in a sandboxed browser context.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →