Skip to content

Latest commit

 

History

342 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Dusk Wallet

A non-custodial wallet for Dusk. Chrome and Firefox extension builds from one codebase.

Your keys. Your DUSK. No middleman.

CI   Release   Coverage   GitHub Repo stars   Join Discord   X (formerly Twitter) Follow   Read the docs

Dusk Wallet extension design

Features

🔐 Self-custody — Your mnemonic never leaves your device. Encrypted at rest.

⚡ Public & Shielded — Send from your public account or shield funds for privacy.

🌐 dApp Ready — Connect to any Dusk dApp through event-based provider discovery.

🔄 Multi-network — Switch between mainnet, testnet, devnet, or custom nodes.

🧩 Shared runtime — Extension targets share the same wallet engine and UI shell.

Install

Chrome Extension

From a fresh checkout:

npm ci
npm run build:chrome

Then load dist/ as an unpacked extension in chrome://extensions (Developer mode).

Firefox Extension

From a fresh checkout:

npm ci
npm run build:firefox

Then load dist-firefox/ as a temporary add-on in about:debugging.

For dApp Developers

The extension announces an EIP-1193-style provider through Dusk discovery events. Dusk isn't EVM, but the provider patterns are familiar.

Use Connect's conflict-aware discovery support; metadata is self-attested, not wallet authentication. Run this as a JavaScript module:

import { createDuskWallet } from "@dusk/connect";

const wallet = createDuskWallet();
await wallet.ready();

// When selection is required, show wallet.providers in a picker (or Connect UI).
// Make conflicts visible and disable those entries; pass a chosen UUID to wallet.selectProvider().
if (!wallet.provider) throw new Error("Select an unconflicted Dusk wallet before connecting");
const [profile] = await wallet.connect(); // dusk_requestProfiles; prompts for a profile grant.
console.log(profile.account);

// Keep requests/events on the wrapper so later selection changes are respected.
wallet.on("profilesChanged", console.log);
wallet.on("chainChanged", console.log);
// Call wallet.destroy() when the integration is torn down.

Typed-data signing

dusk_signTypedData signs structured, wallet-rendered data rather than an opaque digest — the Dusk analogue of eth_signTypedData_v4, not of eth_sign. The approval screen shows the domain, primary type, message previews and digest. Previews may be truncated; Full signing request (escaped JSON) exposes the complete request without normalizing its values. Sign is disabled if the full disclosure cannot match the pending digest within display limits. See the disclosure behavior and resource limits and #113.

const result = await wallet.request("dusk_signTypedData", {
  domain: { name: "Example", version: "1", chainId: "dusk:1" },
  types: {
    DuskTypedDataDomain: [
      { name: "name", type: "string" },
      { name: "version", type: "string" },
      { name: "chainId", type: "string" },
      { name: "verifyingContract", type: "bytes32" },
    ],
    SignIn: [{ name: "address", type: "string" }],
  },
  primaryType: "SignIn",
  message: { address: profile.account },
});
// → { account, publicKeyHex, origin, chainId, primaryType, digestHex, signature }

Two things to know before integrating:

  • Do not send origin. The wallet injects its own view of the requesting origin into the digest, and returns the exact string it used. A caller able to set it could obtain a signature attributable to a site it does not control.
  • domain.chainId must match the wallet's active chain, or the request is rejected before the user sees anything.

Verify signatures with @dusk/typed-data/bls, passing trusted chain/origin expectations and checking result.ok. Reconstruct the hash input with the wallet-returned origin. Also check the expected signer, authorization and replay protection. The signature covers a tagged wrapper around digestHex, not the bare digest — verifying the bare digest would accept signatures produced by any raw 32-byte signing path.

Canonical v0.1 docs:

Architecture

src/
├── background/      # Extension service worker
├── ui/              # Popup, full view, notifications
├── shared/          # Wallet logic (works everywhere)
├── platform/        # Platform abstraction (extension vs tauri)
└── wallet/          # Engine interface

The wallet engine runs in an offscreen document for extension builds. The shared runtime is structured so other hosts can reuse the same cryptographic core.

Additional documentation:

Development

npm run build:extension   # Build extension → dist/
npm run build:firefox     # Build Firefox extension → dist-firefox/

# Local Rusk node (Docker)
npm run rusk:up
npm run rusk:wait

# UI component workbench
npm run storybook

# E2E (Playwright + Docker Rusk)
npm run e2e:rusk

Security

  • Mnemonic encrypted with user password (PBKDF2 + AES-GCM)
  • No analytics, no tracking, no remote calls except to your chosen node

License

MIT

About

Multi-platform wallet for Dusk: Browser extension, desktop and mobile

Resources

Code of conduct

Contributing

Security policy

Stars

8 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages