[![Version](https://img.shields.io/github/package-json/v/asgardex/asgardex-desktop?color=xyz&filename=package.json&style=flat-square)](https://github.com/asgardex/asgardex-desktop/releases) ![Test](https://github.com/asgardex/asgardex-desktop/workflows/Test/badge.svg) ![Electron build Windows](https://github.com/asgardex/asgardex-desktop/workflows/Electron%20build%20-%20Windows/badge.svg) ![Electron build Linux](https://github.com/asgardex/asgardex-desktop/workflows/Electron%20build%20-%20Linux/badge.svg) ![Electron build Mac](https://github.com/asgardex/asgardex-desktop/workflows/Electron%20build%20-%20macOS/badge.svg) [![Discord](https://img.shields.io/badge/chat-on%20discord-7289da.svg)](https://discord.gg/hkeJxHS7d7) [![Follow on Twitter](https://img.shields.io/twitter/follow/asgardex?style=social)](https://twitter.com/asgardex) [![Check our Website](https://img.shields.io/badge/Visit-Our%20Website-blue)](https://asgardex.com) ## Website This is the developer source repository, general information, and download page can be found at [Asgardex](https://asgardex.com) ## Feature list ### Symbols :heavy_check_mark: implemented :white_check_mark: planned `-` not needed #### Wallet | | RUNE | BTC | BCH | DOGE | ETH / ERC20 | LTC | COSMOS | BSC | AVAX | MAYA | DASH | SOL | XRP | ARB | BASE | TRON | | --------- | ------------------ | ------------------ | ------------------ | ------------------ | ------------------ | ------------------ | ------------------ | ------------------ | ------------------ | ------------------ | ------------------ | ------------------ | ------------------ | ------------------ | ------------------ | ------------------ | ------------------ | | Keystore | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | | Ledger \* | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | | Vultisig \*\*\* | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | | Send \*\* | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | | Receive | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | | Deposit | :heavy_check_mark: | - | - | - | - | - | - | - | - | :heavy_check_mark: | - | - | - | - | - | - | - | | Shares | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | | History | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | | Synths | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | - | - | - | - | - | - | - | - | (\*) Ledger `RUNE` is not supported at `stagenet`. Ledger `LTC`/`BCH`/`DOGE` are not supported at `testnet`. (\*\*) With or without memo (\*\*\*) Vultisig MPC wallet (BETA). Also supports ZEC, ADA, XRP, XRD, SOL, and TRON beyond the chains listed in the table. See [Vultisig section](#vultisig-beta) for details. #### THORChain Exchange | | RUNE | BSC /BEP20 | BTC | BCH | DOGE | ETH / ERC20 | LTC | COSMOS | AVAX | ARB | BASE | | -------------- | ------------------ | ------------------ | ------------------ | ------------------ | ------------------ | ------------------ | ------------------ | ------------------ | ------------------ | ------------------ | ------------------ | | Pools overview | - | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | | Pool detail | - | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | | Swap | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | | Deposit \* | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | | Withdraw \* | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | | Recovery tool | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | (\*) Symmetrical deposit/withdraw only #### MAYA Exchange | | MAYA | RUNE | BTC | ETH / ERC20 | DASH | ARB | | -------------- | ------------------------ | ------------------------ | ------------------------ | ------------------------ | ------------------------ | ------------------------ | ------------------------ | | Pools overview | - | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | | Pool detail | - | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | | Swap | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | | Deposit \* | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | | Withdraw \* | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | | Recovery tool | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | | Synths | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | | Savers | :heavy_multiplication_x: | :heavy_multiplication_x: | :heavy_multiplication_x: | :heavy_multiplication_x: | :heavy_multiplication_x: | :heavy_multiplication_x: | :heavy_multiplication_x: | (\*) Symmetrical deposit/withdraw only #### THORNode | Overview | Status | BOND | UNBOND | LEAVE | THORName | | ------------------ | ------------------ | ------------------ | ------------------ | ------------------ | ------------------ | | :heavy_check_mark: | :white_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | #### MAYANode | Overview | Status | BOND | UNBOND | LEAVE | MAYAName | | ------------------ | ------------------ | ------------------ | ------------------ | ------------------------ | ------------------ | | :heavy_check_mark: | :white_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_multiplication_x: | :heavy_check_mark: | ### Languages | ENGLISH :us: | GERMAN :de: | FRENCH :fr: | RUSSIAN :ru: | HINDI :hi: | SPANISH :es: | KOREAN :ko: | | ------------------ | ------------------ | ------------------ | ------------------ | ------------------ | ------------------ | ------------------ | | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | ### Misc - 100% open-source (built by the community) - Security first - 30 bps affiliate fees only on swaps over $1001 - No affiliate fee on: RunePool, LP actions ## ASGARDEX utilizes the following libraries, frameworks, and more: _(in alphabetical order)_ - [ESLint](https://github.com/eslint/eslint) - [Electron](https://github.com/electron/electron/) - [fp-ts](https://gcanti.github.io/fp-ts/) - [HeadlessUI](https://headlessui.com/) - [Observable Hooks](https://observable-hooks.js.org/) - [Prettier](https://github.com/prettier/prettier) - [ReactJS](https://github.com/facebook/react/) - [Styled Components](https://styled-components.com/) - [RxJS](https://rxjs.dev/) - [TailwindCSS](https://tailwindcss.com/) - [Typescript](https://github.com/microsoft/TypeScript) - [Vite](https://github.com/vitejs/vite) - [Vitest](https://github.com/vitest-dev/vitest) - [xchainjs-lib](https://github.com/xchainjs/xchainjs-lib/) - and others ... ## Installation It's recommended to use a Node version as same as Electron is running with (currently: [`Electron 35` / Node `22.14`](https://www.electronjs.org/docs/latest/tutorial/electron-timelines)). It's recommended to install [nvm](https://github.com/nvm-sh/nvm) to run as the same Node version locally as used for building ASGARDEX on CI. ```bash git clone https://github.com/asgardex/asgardex-desktop.git asgardex cd asgardex yarn ``` ## Environment variables While environment variables are not required (defaults are set), you can configure them. Create an `.env` file by copying all content of `.env.sample` and change these for your needs. ## Development - Build everything needed (main, preload and renderer) and run application in `watch` mode ```bash yarn dev ``` In case Node might run into memory issues locally set `--max-old-space-size` as follow: ```json export NODE_OPTIONS="--max-old-space-size=4096" ``` ## Tips & tricks for windows You may need to install the following dependencies in your local machine in order to build the native libraries used by Asgardex 1. Install python3 2. Install 'Microsoft C++ build tools' ## Tips & tricks for Linux You may need to install the following dependencies in your local machine in order to build the native libraries used by Asgardex 1. Install python3 2. Install dependency build-essential ```bash sudo apt-get install build-essential ``` 3. Install dependency libudev-dev ```bash sudo apt-get install libudev-dev ``` ### Generate ERC20/BEP20 & Avax & ARB asset white list Whenever [THORChain ERC20 asset whitelist](https://gitlab.com/thorchain/thornode/-/blob/develop/bifrost/pkg/chainclients/ethereum/token_list.json) has been updated (usually with a [new release of THORNode](https://gitlab.com/thorchain/thornode/-/tags)), run following script to auto-generate this list for ASGARDEX For synths to have an icon the asset in the whitelist needs to be duplicated and the synth boolean flipped `true` ```bash yarn generate:erc20whitelist yarn generate:avaxerc20whitelist yarn generate:bscerc20whitelist yarn generate:arberc20whitelist ``` ### How to auto-unlock a locked wallet while hot-reloading the app (for development only, disabled in production build) Use `VITE_WALLET_PASSWORD` to run the app by replacing `password` with your own password ```bash VITE_WALLET_PASSWORD=password yarn dev ``` Or add to `VITE_WALLET_PASSWORD=password` to `.env` file and run `yarn dev` ## Tests ### `unit` ```bash yarn test ``` ### `lint` ```bash yarn lint ``` ### bundle analyze visualize the bundle map using `source-map-explorer` ```bash yarn analyze ``` ### Auto updates To check locally if auto-update works correctly create `dev-app-update.yml` file at the root directory with a content based on [dev-app-update.sample.yml](./dev-app-update.sample.yml) with providing your GutHub personal access token. After that just play locally with version provided by `package.json` ## Folder structure ### `src` ```bash src ├── main # sources of Electron's main process ├── renderer # sources of Electron's renderer process (aka webapp) └── shared # shared sources for Electron's main and renderer processes ``` ### `src/main` (Electron's "main" app) ```bash src/main ├── electron.ts # entry point ├── i18n # internationalization (needed for menus) └── menu # "native" menus ``` ### `src/renderer` (Electron's "renderer" app aka ReactJS webapp) ```bash src/renderer ├── assets # static files (svg, fonts etc.) ├── components # basic components ├── contexts # React contexts to provide "global" accessible states (RxJS based) ├── helpers # helper functions ├── hooks # custom hooks ├── i18n # internationalization (translations etc.) ├── index.tsx # entry point ├── routes # routing ├── services # RxJS based IO handler and states (consumed by contexts) ├── types # TypeScript types (e.g. generated types for Midgard API) └── views # "Container" components ``` ## Security ASGARDEX follows [security recommendation made by Electron team](https://www.electronjs.org/docs/tutorial/security), such as: - [Disable the Node.js integration in renderers that display remote content](https://www.electronjs.org/docs/tutorial/security#2-do-not-enable-nodejs-integration-for-remote-content) - [Enable context isolation in renderers that display remote content](https://www.electronjs.org/docs/tutorial/security#3-enable-context-isolation-for-remote-content) - [Expose IPC-based APIs to provide one method per IPC message](https://www.electronjs.org/docs/tutorial/context-isolation#security-considerations) - [Disable the remote module](https://www.electronjs.org/docs/tutorial/security#15-disable-the-remote-module) - [Do not use openExternal with untrusted content](https://www.electronjs.org/docs/tutorial/security#14-do-not-use-openexternal-with-untrusted-content). Provided hostnames are defined in [`EXTERNALS_WHITELIST`](./src/main/api/url.ts), all others are blocked. This list has to be extended if needed. - [Use a current version of Electron](https://www.electronjs.org/docs/tutorial/security#17-use-a-current-version-of-electron) ## Packaging **Important note** for `macOS` users: Please follow guide of ["How to package `ASGARDEX` on macOS"](./PACKAGE_MACOS.md) before running following command. ```bash yarn package:electron ``` ### Flatpak (Linux) On Linux, `yarn package:electron` builds a Flatpak bundle alongside the `deb` and `AppImage` targets. The Flatpak target needs `flatpak` and `flatpak-builder` installed, plus the runtimes it bundles against (the config pins freedesktop `24.08`): ```bash # Build tooling (use your distro's package manager) sudo apt install flatpak flatpak-builder # Runtimes / base app flatpak remote-add --if-not-exists --user flathub https://flathub.org/repo/flathub.flatpakrepo flatpak install --user flathub org.freedesktop.Platform//24.08 org.freedesktop.Sdk//24.08 org.electronjs.Electron2.BaseApp//24.08 ``` The bundle is written to `release/ASGARDEX--linux.flatpak`. Install and run it with: ```bash flatpak install --user --bundle release/ASGARDEX--linux.flatpak flatpak run org.thorchain.asgardex ``` > Switching from a `*.deb`/AppImage install? Existing keystores are imported into the sandbox automatically on first launch — see [Keystores → Linux](#linux). ## Keystores By creating or importing a keystore wallet, ASGARDEX is adding its encrypted keystore into `wallets.json` in [Electron's `appData` folder](https://www.electronjs.org/docs/api/app#appgetpathname) at following location: ### Windows ```bash # ASGARDEX installed from *.exe %APPDATA%/ASGARDEX/storage/wallets.json # ASGARDEX built and run locally %APPDATA%/Electron/storage/wallets.json ``` ### macOS ```bash # ASGARDEX installed from *.dmg ~/Library/Application Support/ASGARDEX/storage/wallets.json # ASGARDEX built and run locally ~/Library/Application Support/Electron/storage/wallets.json ``` ### Linux ```bash # ASGARDEX installed from *.deb ~/.config/ASGARDEX/storage/wallets.json # ASGARDEX installed from *.flatpak (sandboxed path) ~/.var/app/org.thorchain.asgardex/config/ASGARDEX/storage/wallets.json # ASGARDEX built and run locally ~/.config/Electron/storage/wallets.json ``` The Flatpak runs in a sandbox, so `~/.config` is redirected to `~/.var/app/org.thorchain.asgardex/config`. When switching from the `*.deb`/AppImage install, ASGARDEX imports the existing `~/.config/ASGARDEX/storage` into the sandbox automatically on first launch (the native files are left untouched). By removing a wallet in `Wallet` -> `Settings` its data will be removed from `wallets.json`. ASGARDEX will prompt a message to users to inform about saving its phrase on a save place before removing the wallet. After removing all wallets `wallets.json` will be empty and won't include any wallet related data. ## Ledger accounts By adding a Ledger account to a wallet, ASGARDEX saves its `address` and some extra information (`chain`, `network`, `walletIndex`, `hdMode`) into `ledgers.json` located in [Electron's `appData` folder](https://www.electronjs.org/docs/api/app#appgetpathname): ### Windows ```bash # ASGARDEX installed from *.exe %APPDATA%/ASGARDEX/storage/ledgers.json # ASGARDEX built and run locally %APPDATA%/Electron/storage/ledgers.json ``` ### macOS ```bash # ASGARDEX installed from *.dmg ~/Library/Application Support/ASGARDEX/storage/ledgers.json # ASGARDEX built and run locally ~/Library/Application Support/Electron/storage/ledgers.json ``` ### Linux ```bash # ASGARDEX installed from *.deb ~/.config/ASGARDEX/storage/ledgers.json # ASGARDEX built and run locally ~/.config/Electron/storage/ledgers.json ``` Whenever a Ledger has been removed in `Wallet` -> `Settings`, its data will be removed from `ledgers.json`. By removing all Ledger accounts from each wallet `ledgers.json` will be empty and won't include any Ledger related data. The same by removing all wallets. ### Linux: Ledger device access (udev rules) On Linux the Ledger USB device is only accessible after the Ledger `udev` rules are installed — without them the app (any of `*.deb`, AppImage, or Flatpak) fails to connect with errors like "Getting address from Ledger failed". Install the rules once, then unplug and replug the device: ```bash curl -fsSL https://raw.githubusercontent.com/LedgerHQ/udev-rules/master/add_udev_rules.sh | sudo bash ``` This is a host-level requirement and is independent of the Flatpak sandbox (the Flatpak grants USB device access via `--device=all`). ## Vultisig (BETA) ASGARDEX supports [Vultisig](https://vultisig.com/) MPC (multi-party computation) wallets as a third wallet mode alongside Keystore and Ledger. The integration is currently in **beta** -- a "BETA" indicator is shown in the UI when Vultisig mode is active. ### What's implemented - **Vault creation** -- Two modes: *Fast vault* (email + password, server-assisted) and *Secure vault* (2-of-2 MPC with phone pairing via QR code) - **20-chain support** -- BTC, ETH, THOR, MAYA, BSC, AVAX, GAIA, DOGE, LTC, BCH, ARB, BASE, DASH, XRP, SOL, ZEC, ADA, TRON, XRD - **Send transactions** across all supported chains - **Token swaps** via THORChain and MAYAChain (verified: BTC, ETH, CACAO, ERC20 tokens) - **ERC20 token approvals** - **Vault import/export** using `.vult` files - **Vault lock/unlock** with password encryption - **Unified wallet dropdown** -- switch between Keystore, Ledger, and Vultisig vaults from the header ### Not yet implemented The following features are guarded with "not implemented" warnings when using a Vultisig wallet: - Trade deposits - Liquidity provision (add/withdraw) - Bonds management ### Architecture Vultisig uses the Vultisig MPC SDK, which runs exclusively in Electron's main process. The renderer communicates with the SDK via IPC through `window.apiMpc` (exposed in the preload script). Key files: - SDK IPC handlers: `src/main/api/mpc/` - Vault lifecycle: `src/renderer/services/wallet/vaultManager.ts` - MPC type definitions: `src/shared/api/mpcTypes.ts` ## Git branching workflow See [BRANCHING_WORKFLOW.md](./BRANCHING_WORKFLOW.md) ## Releasing See [RELEASE.md](./RELEASE.md) ## Docs See the [docs and guides here](https://docs.thorchain.org) ## Contributing Everyone is welcome to contribute. Check [open issues](https://github.com/asgardex/asgardex-desktop/issues) or create a new one to start your work with and open a PR afterwards. Newcomers might want to check issues labeled as [good first issues](https://github.com/asgardex/asgardex-desktop/labels/good%20first%20issue). ## Bug Reports Please use [bug report template](https://github.com/asgardex/asgardex-desktop/issues/new?assignees=&labels=bug&template=2-Bug_report.md) to file any bugs. ## License [MIT License](./LICENSE)