├── swap ├── .gitignore ├── src │ ├── asb │ │ ├── rpc │ │ │ └── mod.rs │ │ └── recovery.rs │ ├── bitcoin.rs │ ├── protocol.rs │ ├── monero.rs │ ├── cli.rs │ ├── network.rs │ ├── lib.rs │ ├── asb.rs │ ├── cli │ │ └── list_sellers.rs │ ├── protocol │ │ └── alice.rs │ └── network │ │ └── transport.rs ├── migrations │ ├── 20240701231624_create_buffered_transfer_proofs_table.sql │ ├── 20250625160448_scale_monero_pool_to_0_to_1_if_above_1.sql │ ├── 20250122155820_add_unique_constraint_peer_addresses.sql │ ├── 20210903050345_create_swaps_table.sql │ ├── 20250704115958_receive_xmr_to_internal_wallet.sql │ └── 20250530215011_multiple_monero_receive_addresses.sql ├── build.rs └── tests │ ├── ensure_same_swap_id.rs │ ├── happy_path.rs │ ├── happy_path_alice_developer_tip.rs │ └── happy_path_alice_developer_tip_subaddress.rs ├── .helix └── ignore ├── .taurignore ├── swap-p2p └── src │ ├── patches.rs │ ├── out_event.rs │ ├── protocols.rs │ └── lib.rs ├── docs ├── .gitignore ├── pages │ ├── becoming_a_maker │ │ └── _meta.json │ ├── advanced │ │ └── _meta.json │ ├── getting_started │ │ ├── _meta.json │ │ └── verify_tauri_signature.mdx │ ├── usage │ │ └── _meta.json │ ├── _meta.json │ └── donate.mdx ├── public │ ├── favicon.ico │ ├── first_swap_1.png │ ├── first_swap_2.png │ ├── first_swap_3.png │ ├── first_swap_4.png │ ├── first_swap_5.png │ ├── first_swap_6.png │ ├── first_swap_7.png │ ├── rendezvous_1.png │ ├── rendezvous_2.png │ ├── apple-touch-icon.png │ ├── public_registry.png │ ├── start_swap_button.png │ ├── rendezvous_button_1.png │ ├── android-chrome-192x192.png │ ├── android-chrome-512x512.png │ ├── feedback_button_modal.png │ ├── public_registry_button_1.png │ └── manifest.webmanifest ├── next-env.d.ts ├── next.config.js ├── components │ └── Logo.tsx ├── tsconfig.json ├── package.json └── theme.config.jsx ├── swap-db ├── src │ └── lib.rs └── Cargo.toml ├── monero-tests ├── src │ └── lib.rs └── Cargo.toml ├── swap-core ├── src │ ├── lib.rs │ ├── monero.rs │ └── monero │ │ └── ext.rs └── Cargo.toml ├── src-gui ├── src │ ├── vite-env.d.ts │ ├── assets │ │ ├── groupWithChatbubbles.png │ │ └── walletWithBitcoinAndMonero.png │ ├── renderer │ │ ├── components │ │ │ ├── modal │ │ │ │ ├── introduction │ │ │ │ │ └── slides │ │ │ │ │ │ ├── SlideTypes.ts │ │ │ │ │ │ ├── Slide03_PrepareSwap.tsx │ │ │ │ │ │ ├── Slide02_ChooseAMaker.tsx │ │ │ │ │ │ ├── Slide01_GettingStarted.tsx │ │ │ │ │ │ ├── Slide04_ExecuteSwap.tsx │ │ │ │ │ │ ├── Slide05_KeepAnEyeOnYourSwaps.tsx │ │ │ │ │ │ └── Slide07_ReachOut.tsx │ │ │ │ ├── DialogHeader.tsx │ │ │ │ ├── wallet │ │ │ │ │ ├── pages │ │ │ │ │ │ ├── BitcoinWithdrawTxInMempoolPage.tsx │ │ │ │ │ │ └── AddressInputPage.tsx │ │ │ │ │ ├── WithdrawDialogContent.tsx │ │ │ │ │ └── WithdrawStepper.tsx │ │ │ │ └── swap │ │ │ │ │ └── pages │ │ │ │ │ ├── DebugPageSwitchBadge.tsx │ │ │ │ │ └── DebugPage.tsx │ │ │ ├── pages │ │ │ │ ├── swap │ │ │ │ │ ├── swap │ │ │ │ │ │ ├── in_progress │ │ │ │ │ │ │ ├── CancelTimelockExpiredPage.tsx │ │ │ │ │ │ │ ├── RedeemingMoneroPage.tsx │ │ │ │ │ │ │ ├── XmrLockedPage.tsx │ │ │ │ │ │ │ ├── BitcoinCancelledPage.tsx │ │ │ │ │ │ │ ├── EncryptedSignatureSentPage.tsx │ │ │ │ │ │ │ ├── ReceivedQuotePage.tsx │ │ │ │ │ │ │ ├── WaitingForXmrConfirmationsBeforeRedeemPage.tsx │ │ │ │ │ │ │ └── XmrLockInMempoolPage.tsx │ │ │ │ │ │ ├── components │ │ │ │ │ │ │ ├── MoneroTransactionInfoBox.tsx │ │ │ │ │ │ │ ├── BitcoinTransactionInfoBox.tsx │ │ │ │ │ │ │ ├── InfoBox.tsx │ │ │ │ │ │ │ └── DepositAddressInfoBox.tsx │ │ │ │ │ │ └── done │ │ │ │ │ │ │ └── BitcoinPunishedPage.tsx │ │ │ │ │ ├── SwapPage.tsx │ │ │ │ │ └── ApiAlertsBox.tsx │ │ │ │ ├── history │ │ │ │ │ ├── HistoryPage.tsx │ │ │ │ │ └── table │ │ │ │ │ │ └── ExportLogsButton.tsx │ │ │ │ ├── monero │ │ │ │ │ └── components │ │ │ │ │ │ └── index.ts │ │ │ │ ├── feedback │ │ │ │ │ └── FeedbackPage.tsx │ │ │ │ ├── wallet │ │ │ │ │ ├── WalletRefreshButton.tsx │ │ │ │ │ ├── WalletPage.tsx │ │ │ │ │ └── components │ │ │ │ │ │ └── WalletActionButtons.tsx │ │ │ │ └── help │ │ │ │ │ ├── DonateInfoBox.tsx │ │ │ │ │ ├── SettingsPage.tsx │ │ │ │ │ └── FeedbackInfoBox.tsx │ │ │ ├── alert │ │ │ │ ├── LoadingSpinnerAlert.tsx │ │ │ │ ├── SwapTxLockAlertsBox.tsx │ │ │ │ └── UnfinishedSwapsAlert.tsx │ │ │ ├── other │ │ │ │ ├── ExternalLink.tsx │ │ │ │ ├── HumanizedBitcoinBlockDuration.tsx │ │ │ │ ├── TruncatedText.tsx │ │ │ │ ├── Jdenticon.tsx │ │ │ │ ├── ClickToCopy.tsx │ │ │ │ ├── MonospaceTextBox.tsx │ │ │ │ └── ExpandableSearchBox.tsx │ │ │ ├── icons │ │ │ │ ├── LinkIconButton.tsx │ │ │ │ ├── MoneroIcon.tsx │ │ │ │ ├── BitcoinIcon.tsx │ │ │ │ └── MatrixIcon.tsx │ │ │ ├── navigation │ │ │ │ ├── NavigationFooter.tsx │ │ │ │ ├── UnfinishedSwapsCountBadge.tsx │ │ │ │ ├── Navigation.tsx │ │ │ │ └── RouteListItemIconButton.tsx │ │ │ ├── inputs │ │ │ │ └── CardSelection │ │ │ │ │ ├── CardSelectionGroup.tsx │ │ │ │ │ └── CardSelectionContext.tsx │ │ │ └── snackbar │ │ │ │ └── GlobalSnackbarProvider.tsx │ │ └── index.tsx │ ├── store │ │ ├── types.ts │ │ ├── config.ts │ │ ├── features │ │ │ ├── poolSlice.ts │ │ │ ├── bitcoinWalletSlice.ts │ │ │ ├── nodesSlice.ts │ │ │ └── ratesSlice.ts │ │ └── combinedReducer.ts │ ├── utils │ │ ├── logger.ts │ │ ├── typescriptUtils.tsx │ │ ├── hash.ts │ │ └── multiAddrUtils.ts │ └── models │ │ ├── rpcModel.ts │ │ └── storeModel.ts ├── .yarnrc.yml ├── .env.development ├── knip.json ├── tsconfig.node.json ├── .gitignore ├── tsconfig.json └── index.html ├── src-tauri ├── gen │ ├── apple │ │ ├── .gitignore │ │ ├── Assets.xcassets │ │ │ ├── Contents.json │ │ │ └── AppIcon.appiconset │ │ │ │ ├── AppIcon-512@2x.png │ │ │ │ ├── AppIcon-20x20@1x.png │ │ │ │ ├── AppIcon-20x20@2x.png │ │ │ │ ├── AppIcon-20x20@3x.png │ │ │ │ ├── AppIcon-29x29@1x.png │ │ │ │ ├── AppIcon-29x29@2x.png │ │ │ │ ├── AppIcon-29x29@3x.png │ │ │ │ ├── AppIcon-40x40@1x.png │ │ │ │ ├── AppIcon-40x40@2x.png │ │ │ │ ├── AppIcon-40x40@3x.png │ │ │ │ ├── AppIcon-60x60@2x.png │ │ │ │ ├── AppIcon-60x60@3x.png │ │ │ │ ├── AppIcon-76x76@1x.png │ │ │ │ ├── AppIcon-76x76@2x.png │ │ │ │ ├── AppIcon-20x20@2x-1.png │ │ │ │ ├── AppIcon-29x29@2x-1.png │ │ │ │ ├── AppIcon-40x40@2x-1.png │ │ │ │ └── AppIcon-83.5x83.5@2x.png │ │ ├── Sources │ │ │ └── unstoppableswap-gui-rs │ │ │ │ ├── main.mm │ │ │ │ └── bindings │ │ │ │ └── bindings.h │ │ ├── unstoppableswap-gui-rs.xcodeproj │ │ │ └── project.xcworkspace │ │ │ │ ├── contents.xcworkspacedata │ │ │ │ └── xcshareddata │ │ │ │ └── WorkspaceSettings.xcsettings │ │ ├── unstoppableswap-gui-rs_iOS │ │ │ └── unstoppableswap-gui-rs_iOS.entitlements │ │ ├── ExportOptions.plist │ │ └── Podfile │ └── android │ │ ├── settings.gradle │ │ ├── gradle │ │ └── wrapper │ │ │ ├── gradle-wrapper.jar │ │ │ └── gradle-wrapper.properties │ │ ├── app │ │ ├── src │ │ │ └── main │ │ │ │ ├── res │ │ │ │ ├── mipmap-hdpi │ │ │ │ │ ├── ic_launcher.png │ │ │ │ │ ├── ic_launcher_round.png │ │ │ │ │ └── ic_launcher_foreground.png │ │ │ │ ├── mipmap-mdpi │ │ │ │ │ ├── ic_launcher.png │ │ │ │ │ ├── ic_launcher_round.png │ │ │ │ │ └── ic_launcher_foreground.png │ │ │ │ ├── mipmap-xhdpi │ │ │ │ │ ├── ic_launcher.png │ │ │ │ │ ├── ic_launcher_round.png │ │ │ │ │ └── ic_launcher_foreground.png │ │ │ │ ├── mipmap-xxhdpi │ │ │ │ │ ├── ic_launcher.png │ │ │ │ │ ├── ic_launcher_round.png │ │ │ │ │ └── ic_launcher_foreground.png │ │ │ │ ├── mipmap-xxxhdpi │ │ │ │ │ ├── ic_launcher.png │ │ │ │ │ ├── ic_launcher_round.png │ │ │ │ │ └── ic_launcher_foreground.png │ │ │ │ ├── values │ │ │ │ │ ├── strings.xml │ │ │ │ │ ├── themes.xml │ │ │ │ │ └── colors.xml │ │ │ │ ├── xml │ │ │ │ │ └── file_paths.xml │ │ │ │ ├── values-night │ │ │ │ │ └── themes.xml │ │ │ │ └── layout │ │ │ │ │ └── activity_main.xml │ │ │ │ └── java │ │ │ │ └── net │ │ │ │ └── unstoppableswap │ │ │ │ └── gui │ │ │ │ └── MainActivity.kt │ │ ├── .gitignore │ │ └── proguard-rules.pro │ │ ├── .editorconfig │ │ ├── .gitignore │ │ ├── buildSrc │ │ └── build.gradle.kts │ │ └── build.gradle.kts ├── icons │ ├── 32x32.png │ ├── icon.icns │ ├── icon.ico │ ├── icon.png │ ├── 128x128.png │ ├── 128x128@2x.png │ ├── StoreLogo.png │ ├── Square30x30Logo.png │ ├── Square44x44Logo.png │ ├── Square71x71Logo.png │ ├── Square89x89Logo.png │ ├── Square107x107Logo.png │ ├── Square142x142Logo.png │ ├── Square150x150Logo.png │ ├── Square284x284Logo.png │ ├── Square310x310Logo.png │ ├── ios │ │ ├── AppIcon-512@2x.png │ │ ├── AppIcon-20x20@1x.png │ │ ├── AppIcon-20x20@2x.png │ │ ├── AppIcon-20x20@3x.png │ │ ├── AppIcon-29x29@1x.png │ │ ├── AppIcon-29x29@2x.png │ │ ├── AppIcon-29x29@3x.png │ │ ├── AppIcon-40x40@1x.png │ │ ├── AppIcon-40x40@2x.png │ │ ├── AppIcon-40x40@3x.png │ │ ├── AppIcon-60x60@2x.png │ │ ├── AppIcon-60x60@3x.png │ │ ├── AppIcon-76x76@1x.png │ │ ├── AppIcon-76x76@2x.png │ │ ├── AppIcon-20x20@2x-1.png │ │ ├── AppIcon-29x29@2x-1.png │ │ ├── AppIcon-40x40@2x-1.png │ │ └── AppIcon-83.5x83.5@2x.png │ └── android │ │ ├── mipmap-hdpi │ │ ├── ic_launcher.png │ │ ├── ic_launcher_round.png │ │ └── ic_launcher_foreground.png │ │ ├── mipmap-mdpi │ │ ├── ic_launcher.png │ │ ├── ic_launcher_round.png │ │ └── ic_launcher_foreground.png │ │ ├── mipmap-xhdpi │ │ ├── ic_launcher.png │ │ ├── ic_launcher_round.png │ │ └── ic_launcher_foreground.png │ │ ├── mipmap-xxhdpi │ │ ├── ic_launcher.png │ │ ├── ic_launcher_round.png │ │ └── ic_launcher_foreground.png │ │ └── mipmap-xxxhdpi │ │ ├── ic_launcher.png │ │ ├── ic_launcher_round.png │ │ └── ic_launcher_foreground.png ├── tauri.windows.conf.json ├── .gitignore ├── capabilities │ ├── desktop.json │ └── default.json ├── src │ └── main.rs ├── build.rs └── Cargo.toml ├── swap-orchestrator ├── src │ └── lib.rs ├── build.rs └── Cargo.toml ├── swap-env ├── src │ └── lib.rs └── Cargo.toml ├── dev-docs ├── asb │ ├── gap-limit.png │ ├── import-keystore.png │ ├── transactions-tab.png │ ├── enter-master-private-key.png │ └── diagrams │ │ └── cli-asb-overview.puml └── README.md ├── swap-serde ├── src │ └── lib.rs └── Cargo.toml ├── monero-rpc-pool └── migrations │ ├── 20250813185138_ravfx_uses_https.sql │ ├── 20250813225842_cryptostorm_mainnet_node.sql │ ├── 20250624073558_default_nodes_remove_ssl_where_not_supported.sql │ └── 20250618212026_initial_schema.sql ├── monero-sys ├── .gitignore ├── migrations │ └── 20250710170522_create_recent_wallets.sql ├── README.md ├── patches │ ├── 0004-fix-___isPlatformVersionAtLeast.patch │ ├── eigenwallet_0002_wallet2_increase_rpc_retries.patch │ └── 0003-include-locale-only-when-targeting-WIN32.patch ├── Cargo.toml └── tests │ └── special_paths.rs ├── dev-scripts ├── code2prompt_to_clipboard.sh ├── code2prompt_as_file_mac_os.sh ├── brew_dependencies_install.sh ├── homebrew │ └── eigenwallet.rb.template └── bump-version.sh ├── rust-toolchain.toml ├── swap-asb └── build.rs ├── .cursor └── rules │ ├── never-upgrade-deps-without-explicit-confirmation.mdc │ └── dont-run-cargo.mdc ├── throttle └── Cargo.toml ├── swap-fs └── Cargo.toml ├── swap-proptest ├── Cargo.toml └── src │ └── lib.rs ├── .gitmodules ├── CLAUDE.md ├── tracing-ext └── Cargo.toml ├── flatpak ├── org.eigenwallet.app.flatpakref ├── unstoppableswap-gui-rs.flatpak.sh ├── eigenwallet.flatpakrepo └── org.eigenwallet.app.appdata.xml ├── swap-controller-api └── Cargo.toml ├── .sqlx ├── query-2a356078a41b321234adf2aa385b501749f907f7c422945a8bdda2b6274f5225.json ├── query-50ef34b4efabe650d40096a390d9240b9a7cd62878dfaa6805563cfc21284cd5.json ├── query-e36c287aa98ae80ad4b6bb6f7e4b59cced041406a9db71da827b09f0d3bacfd6.json ├── query-b703032b4ddc627a1124817477e7a8e5014bdc694c36a14053ef3bb2fc0c69b0.json ├── query-1f332be08a5426f3fbcadea4e755d82ff1cdc2690eb464ccc607d3a613fa76a1.json ├── query-7c37de52b3bb2ccd0868ccb861127416848d85eaebe8245c58d5beac7d537087.json ├── query-a679f789c90ede34cd840d23d90087520dcf1777fdf4cc3ed7aab0c9d70d060c.json ├── query-081c729a0f1ad6e4ff3e13d6702c946bc4d37d50f40670b4f51d2efcce595aa6.json ├── query-e05620f420f8c1022971eeb66a803323a8cf258cbebb2834e3f7cf8f812fa646.json ├── query-d78acba5eb8563826dd190e0886aa665aae3c6f1e312ee444e65df1c95afe8b2.json ├── query-9047f0683f1cf956e9b367b4e85d61fe0ca4b4f7a6ae5986025601b2000565d9.json ├── query-e9d422daf774d099fcbde6c4cda35821da948bd86cc57798b4d8375baf0b51ae.json ├── query-60462ce4f45f174eb4603a2d94e67cf98eb7d6176515e6a28c4e8ce9fda6ef15.json ├── query-0d465a17ebbb5761421def759c73cad023c30705d5b41a1399ef79d8d2571d7c.json ├── query-88f761a4f7a0429cad1df0b1bebb1c0a27b2a45656549b23076d7542cfa21ecf.json ├── query-6130b6cdd184181f890964eb460741f5cf23b5237fb676faed009106627a4ca6.json ├── query-7e58428584d28a238ab37a83662b88afcef6fc5246f11c85a35869f79da61c34.json ├── query-5cc61dd0315571bc198401a354cd9431ee68360941f341386cbacf44ea598de8.json ├── query-dff8b986c3dde27b8121775e48a58564fa346b038866699210a63f8a33b03f0b.json └── query-d32d91ca2debc4212841282533482b2ff081234c7f9f848a7223ae04234995d9.json ├── electrum-pool └── Cargo.toml ├── monero-rpc ├── src │ └── lib.rs └── Cargo.toml ├── .github ├── ISSUE_TEMPLATE │ ├── submit_rendezvous_point.md │ └── bug_report.md └── dependabot.yml ├── .gitignore ├── swap-controller ├── Cargo.toml ├── src │ ├── repl │ │ └── parse.rs │ └── cli.rs └── Dockerfile ├── monero-harness └── Cargo.toml ├── .dockerignore ├── swap-feed ├── src │ ├── traits.rs │ ├── bin │ │ ├── kraken_ticker.rs │ │ ├── bitfinex_ticker.rs │ │ └── kucoin_ticker.rs │ └── lib.rs └── Cargo.toml ├── utils └── gpg_keys │ ├── einliterflasche.asc │ ├── binarybaron.asc │ └── readme.md ├── libp2p-rendezvous-node ├── src │ ├── tracing_util.rs │ └── behaviour.rs ├── Dockerfile └── Cargo.toml ├── monero-wallet └── Cargo.toml ├── swap-machine └── Cargo.toml ├── dprint.json ├── libp2p-tor ├── LICENSE └── CHANGELOG.md └── bitcoin-wallet └── Cargo.toml /swap/.gitignore: -------------------------------------------------------------------------------- 1 | tempdb 2 | -------------------------------------------------------------------------------- /.helix/ignore: -------------------------------------------------------------------------------- 1 | src-tauri/gen/ 2 | 3 | -------------------------------------------------------------------------------- /.taurignore: -------------------------------------------------------------------------------- 1 | **/monero-sys/monero/** 2 | -------------------------------------------------------------------------------- /swap-p2p/src/patches.rs: -------------------------------------------------------------------------------- 1 | pub mod identify; 2 | -------------------------------------------------------------------------------- /docs/.gitignore: -------------------------------------------------------------------------------- 1 | .next 2 | node_modules 3 | .DS_Store 4 | -------------------------------------------------------------------------------- /swap-db/src/lib.rs: -------------------------------------------------------------------------------- 1 | pub mod alice; 2 | pub mod bob; 3 | -------------------------------------------------------------------------------- /monero-tests/src/lib.rs: -------------------------------------------------------------------------------- 1 | // Empty but necessary for cargo 2 | -------------------------------------------------------------------------------- /swap-core/src/lib.rs: -------------------------------------------------------------------------------- 1 | pub mod bitcoin; 2 | pub mod monero; 3 | -------------------------------------------------------------------------------- /swap-p2p/src/out_event.rs: -------------------------------------------------------------------------------- 1 | pub mod alice; 2 | pub mod bob; 3 | -------------------------------------------------------------------------------- /src-gui/src/vite-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | -------------------------------------------------------------------------------- /src-tauri/gen/apple/.gitignore: -------------------------------------------------------------------------------- 1 | xcuserdata/ 2 | build/ 3 | Externals/ 4 | -------------------------------------------------------------------------------- /docs/pages/becoming_a_maker/_meta.json: -------------------------------------------------------------------------------- 1 | { 2 | "overview": "Overview" 3 | } 4 | -------------------------------------------------------------------------------- /src-gui/.yarnrc.yml: -------------------------------------------------------------------------------- 1 | nodeLinker: node-modules 2 | 3 | npmMinimalAgeGate: 7d 4 | -------------------------------------------------------------------------------- /swap/src/asb/rpc/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod server; 2 | 3 | pub use server::RpcServer; 4 | -------------------------------------------------------------------------------- /docs/pages/advanced/_meta.json: -------------------------------------------------------------------------------- 1 | { 2 | "swap_on_testnet": "How to swap on Testnet" 3 | } 4 | -------------------------------------------------------------------------------- /swap-orchestrator/src/lib.rs: -------------------------------------------------------------------------------- 1 | pub mod compose; 2 | pub mod containers; 3 | pub mod images; 4 | -------------------------------------------------------------------------------- /docs/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eigenwallet/core/HEAD/docs/public/favicon.ico -------------------------------------------------------------------------------- /swap-env/src/lib.rs: -------------------------------------------------------------------------------- 1 | pub mod config; 2 | pub mod defaults; 3 | pub mod env; 4 | pub mod prompt; 5 | -------------------------------------------------------------------------------- /swap/src/bitcoin.rs: -------------------------------------------------------------------------------- 1 | pub mod wallet; 2 | pub use swap_core::bitcoin::*; 3 | pub use wallet::*; 4 | -------------------------------------------------------------------------------- /swap/src/protocol.rs: -------------------------------------------------------------------------------- 1 | pub mod alice; 2 | pub mod bob; 3 | 4 | pub use swap_machine::common::*; 5 | -------------------------------------------------------------------------------- /src-tauri/gen/android/settings.gradle: -------------------------------------------------------------------------------- 1 | include ':app' 2 | 3 | apply from: 'tauri.settings.gradle' 4 | -------------------------------------------------------------------------------- /src-tauri/icons/32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eigenwallet/core/HEAD/src-tauri/icons/32x32.png -------------------------------------------------------------------------------- /src-tauri/icons/icon.icns: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eigenwallet/core/HEAD/src-tauri/icons/icon.icns -------------------------------------------------------------------------------- /src-tauri/icons/icon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eigenwallet/core/HEAD/src-tauri/icons/icon.ico -------------------------------------------------------------------------------- /src-tauri/icons/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eigenwallet/core/HEAD/src-tauri/icons/icon.png -------------------------------------------------------------------------------- /dev-docs/asb/gap-limit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eigenwallet/core/HEAD/dev-docs/asb/gap-limit.png -------------------------------------------------------------------------------- /docs/public/first_swap_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eigenwallet/core/HEAD/docs/public/first_swap_1.png -------------------------------------------------------------------------------- /docs/public/first_swap_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eigenwallet/core/HEAD/docs/public/first_swap_2.png -------------------------------------------------------------------------------- /docs/public/first_swap_3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eigenwallet/core/HEAD/docs/public/first_swap_3.png -------------------------------------------------------------------------------- /docs/public/first_swap_4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eigenwallet/core/HEAD/docs/public/first_swap_4.png -------------------------------------------------------------------------------- /docs/public/first_swap_5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eigenwallet/core/HEAD/docs/public/first_swap_5.png -------------------------------------------------------------------------------- /docs/public/first_swap_6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eigenwallet/core/HEAD/docs/public/first_swap_6.png -------------------------------------------------------------------------------- /docs/public/first_swap_7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eigenwallet/core/HEAD/docs/public/first_swap_7.png -------------------------------------------------------------------------------- /docs/public/rendezvous_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eigenwallet/core/HEAD/docs/public/rendezvous_1.png -------------------------------------------------------------------------------- /docs/public/rendezvous_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eigenwallet/core/HEAD/docs/public/rendezvous_2.png -------------------------------------------------------------------------------- /src-tauri/icons/128x128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eigenwallet/core/HEAD/src-tauri/icons/128x128.png -------------------------------------------------------------------------------- /swap-serde/src/lib.rs: -------------------------------------------------------------------------------- 1 | pub mod bitcoin; 2 | pub mod electrum; 3 | pub mod libp2p; 4 | pub mod monero; 5 | -------------------------------------------------------------------------------- /src-tauri/icons/128x128@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eigenwallet/core/HEAD/src-tauri/icons/128x128@2x.png -------------------------------------------------------------------------------- /src-tauri/icons/StoreLogo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eigenwallet/core/HEAD/src-tauri/icons/StoreLogo.png -------------------------------------------------------------------------------- /dev-docs/asb/import-keystore.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eigenwallet/core/HEAD/dev-docs/asb/import-keystore.png -------------------------------------------------------------------------------- /dev-docs/asb/transactions-tab.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eigenwallet/core/HEAD/dev-docs/asb/transactions-tab.png -------------------------------------------------------------------------------- /docs/public/apple-touch-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eigenwallet/core/HEAD/docs/public/apple-touch-icon.png -------------------------------------------------------------------------------- /docs/public/public_registry.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eigenwallet/core/HEAD/docs/public/public_registry.png -------------------------------------------------------------------------------- /docs/public/start_swap_button.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eigenwallet/core/HEAD/docs/public/start_swap_button.png -------------------------------------------------------------------------------- /swap-core/src/monero.rs: -------------------------------------------------------------------------------- 1 | pub mod ext; 2 | pub mod primitives; 3 | 4 | pub use ext::*; 5 | pub use primitives::*; 6 | -------------------------------------------------------------------------------- /docs/public/rendezvous_button_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eigenwallet/core/HEAD/docs/public/rendezvous_button_1.png -------------------------------------------------------------------------------- /src-tauri/icons/Square30x30Logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eigenwallet/core/HEAD/src-tauri/icons/Square30x30Logo.png -------------------------------------------------------------------------------- /src-tauri/icons/Square44x44Logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eigenwallet/core/HEAD/src-tauri/icons/Square44x44Logo.png -------------------------------------------------------------------------------- /src-tauri/icons/Square71x71Logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eigenwallet/core/HEAD/src-tauri/icons/Square71x71Logo.png -------------------------------------------------------------------------------- /src-tauri/icons/Square89x89Logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eigenwallet/core/HEAD/src-tauri/icons/Square89x89Logo.png -------------------------------------------------------------------------------- /docs/public/android-chrome-192x192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eigenwallet/core/HEAD/docs/public/android-chrome-192x192.png -------------------------------------------------------------------------------- /docs/public/android-chrome-512x512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eigenwallet/core/HEAD/docs/public/android-chrome-512x512.png -------------------------------------------------------------------------------- /docs/public/feedback_button_modal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eigenwallet/core/HEAD/docs/public/feedback_button_modal.png -------------------------------------------------------------------------------- /src-tauri/icons/Square107x107Logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eigenwallet/core/HEAD/src-tauri/icons/Square107x107Logo.png -------------------------------------------------------------------------------- /src-tauri/icons/Square142x142Logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eigenwallet/core/HEAD/src-tauri/icons/Square142x142Logo.png -------------------------------------------------------------------------------- /src-tauri/icons/Square150x150Logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eigenwallet/core/HEAD/src-tauri/icons/Square150x150Logo.png -------------------------------------------------------------------------------- /src-tauri/icons/Square284x284Logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eigenwallet/core/HEAD/src-tauri/icons/Square284x284Logo.png -------------------------------------------------------------------------------- /src-tauri/icons/Square310x310Logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eigenwallet/core/HEAD/src-tauri/icons/Square310x310Logo.png -------------------------------------------------------------------------------- /src-tauri/icons/ios/AppIcon-512@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eigenwallet/core/HEAD/src-tauri/icons/ios/AppIcon-512@2x.png -------------------------------------------------------------------------------- /docs/public/public_registry_button_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eigenwallet/core/HEAD/docs/public/public_registry_button_1.png -------------------------------------------------------------------------------- /monero-rpc-pool/migrations/20250813185138_ravfx_uses_https.sql: -------------------------------------------------------------------------------- 1 | UPDATE monero_nodes SET scheme = 'https' WHERE host LIKE '%ravfx%'; -------------------------------------------------------------------------------- /src-tauri/gen/apple/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info": { 3 | "version": 1, 4 | "author": "xcode" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /src-tauri/icons/ios/AppIcon-20x20@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eigenwallet/core/HEAD/src-tauri/icons/ios/AppIcon-20x20@1x.png -------------------------------------------------------------------------------- /src-tauri/icons/ios/AppIcon-20x20@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eigenwallet/core/HEAD/src-tauri/icons/ios/AppIcon-20x20@2x.png -------------------------------------------------------------------------------- /src-tauri/icons/ios/AppIcon-20x20@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eigenwallet/core/HEAD/src-tauri/icons/ios/AppIcon-20x20@3x.png -------------------------------------------------------------------------------- /src-tauri/icons/ios/AppIcon-29x29@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eigenwallet/core/HEAD/src-tauri/icons/ios/AppIcon-29x29@1x.png -------------------------------------------------------------------------------- /src-tauri/icons/ios/AppIcon-29x29@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eigenwallet/core/HEAD/src-tauri/icons/ios/AppIcon-29x29@2x.png -------------------------------------------------------------------------------- /src-tauri/icons/ios/AppIcon-29x29@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eigenwallet/core/HEAD/src-tauri/icons/ios/AppIcon-29x29@3x.png -------------------------------------------------------------------------------- /src-tauri/icons/ios/AppIcon-40x40@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eigenwallet/core/HEAD/src-tauri/icons/ios/AppIcon-40x40@1x.png -------------------------------------------------------------------------------- /src-tauri/icons/ios/AppIcon-40x40@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eigenwallet/core/HEAD/src-tauri/icons/ios/AppIcon-40x40@2x.png -------------------------------------------------------------------------------- /src-tauri/icons/ios/AppIcon-40x40@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eigenwallet/core/HEAD/src-tauri/icons/ios/AppIcon-40x40@3x.png -------------------------------------------------------------------------------- /src-tauri/icons/ios/AppIcon-60x60@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eigenwallet/core/HEAD/src-tauri/icons/ios/AppIcon-60x60@2x.png -------------------------------------------------------------------------------- /src-tauri/icons/ios/AppIcon-60x60@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eigenwallet/core/HEAD/src-tauri/icons/ios/AppIcon-60x60@3x.png -------------------------------------------------------------------------------- /src-tauri/icons/ios/AppIcon-76x76@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eigenwallet/core/HEAD/src-tauri/icons/ios/AppIcon-76x76@1x.png -------------------------------------------------------------------------------- /src-tauri/icons/ios/AppIcon-76x76@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eigenwallet/core/HEAD/src-tauri/icons/ios/AppIcon-76x76@2x.png -------------------------------------------------------------------------------- /swap/src/asb/recovery.rs: -------------------------------------------------------------------------------- 1 | pub mod cancel; 2 | pub mod punish; 3 | pub mod redeem; 4 | pub mod refund; 5 | pub mod safely_abort; 6 | -------------------------------------------------------------------------------- /dev-docs/asb/enter-master-private-key.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eigenwallet/core/HEAD/dev-docs/asb/enter-master-private-key.png -------------------------------------------------------------------------------- /src-gui/src/assets/groupWithChatbubbles.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eigenwallet/core/HEAD/src-gui/src/assets/groupWithChatbubbles.png -------------------------------------------------------------------------------- /src-tauri/icons/ios/AppIcon-20x20@2x-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eigenwallet/core/HEAD/src-tauri/icons/ios/AppIcon-20x20@2x-1.png -------------------------------------------------------------------------------- /src-tauri/icons/ios/AppIcon-29x29@2x-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eigenwallet/core/HEAD/src-tauri/icons/ios/AppIcon-29x29@2x-1.png -------------------------------------------------------------------------------- /src-tauri/icons/ios/AppIcon-40x40@2x-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eigenwallet/core/HEAD/src-tauri/icons/ios/AppIcon-40x40@2x-1.png -------------------------------------------------------------------------------- /src-tauri/icons/ios/AppIcon-83.5x83.5@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eigenwallet/core/HEAD/src-tauri/icons/ios/AppIcon-83.5x83.5@2x.png -------------------------------------------------------------------------------- /docs/pages/getting_started/_meta.json: -------------------------------------------------------------------------------- 1 | { 2 | "install_instructions": "Installation", 3 | "verify_tauri_signature": "Verify Signatures" 4 | } 5 | -------------------------------------------------------------------------------- /src-gui/.env.development: -------------------------------------------------------------------------------- 1 | VITE_TESTNET_STUB_PROVIDER_ADDRESS=/ip4/127.0.0.1/tcp/9939/p2p/12D3KooWS1DtT4JmZoAS6m4wZcxXnUB3eVFNvW8hSPrAyCtVSSYm 2 | -------------------------------------------------------------------------------- /src-gui/src/assets/walletWithBitcoinAndMonero.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eigenwallet/core/HEAD/src-gui/src/assets/walletWithBitcoinAndMonero.png -------------------------------------------------------------------------------- /src-tauri/icons/android/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eigenwallet/core/HEAD/src-tauri/icons/android/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /src-tauri/icons/android/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eigenwallet/core/HEAD/src-tauri/icons/android/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /src-tauri/icons/android/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eigenwallet/core/HEAD/src-tauri/icons/android/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /src-tauri/icons/android/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eigenwallet/core/HEAD/src-tauri/icons/android/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /monero-sys/.gitignore: -------------------------------------------------------------------------------- 1 | # IDE specific files 2 | .vscode/ 3 | .idea/ 4 | 5 | # Cargo specific 6 | .cargo/ 7 | /target/ 8 | **/*.rs.bk 9 | Cargo.lock 10 | -------------------------------------------------------------------------------- /src-tauri/gen/android/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eigenwallet/core/HEAD/src-tauri/gen/android/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /src-tauri/icons/android/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eigenwallet/core/HEAD/src-tauri/icons/android/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /src-tauri/icons/android/mipmap-hdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eigenwallet/core/HEAD/src-tauri/icons/android/mipmap-hdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /src-tauri/icons/android/mipmap-mdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eigenwallet/core/HEAD/src-tauri/icons/android/mipmap-mdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /src-tauri/icons/android/mipmap-xhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eigenwallet/core/HEAD/src-tauri/icons/android/mipmap-xhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /src-tauri/icons/android/mipmap-xxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eigenwallet/core/HEAD/src-tauri/icons/android/mipmap-xxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /src-tauri/icons/android/mipmap-xxxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eigenwallet/core/HEAD/src-tauri/icons/android/mipmap-xxxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /src-tauri/icons/android/mipmap-hdpi/ic_launcher_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eigenwallet/core/HEAD/src-tauri/icons/android/mipmap-hdpi/ic_launcher_foreground.png -------------------------------------------------------------------------------- /src-tauri/icons/android/mipmap-mdpi/ic_launcher_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eigenwallet/core/HEAD/src-tauri/icons/android/mipmap-mdpi/ic_launcher_foreground.png -------------------------------------------------------------------------------- /src-tauri/icons/android/mipmap-xhdpi/ic_launcher_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eigenwallet/core/HEAD/src-tauri/icons/android/mipmap-xhdpi/ic_launcher_foreground.png -------------------------------------------------------------------------------- /dev-docs/README.md: -------------------------------------------------------------------------------- 1 | # Documentation 2 | 3 | This directory hosts various pieces of documentation. 4 | 5 | - [`swap` CLI](./cli/README.md) 6 | - [`asb` service](./asb/README.md) 7 | -------------------------------------------------------------------------------- /src-tauri/gen/apple/Sources/unstoppableswap-gui-rs/main.mm: -------------------------------------------------------------------------------- 1 | #include "bindings/bindings.h" 2 | 3 | int main(int argc, char * argv[]) { 4 | ffi::start_app(); 5 | return 0; 6 | } 7 | -------------------------------------------------------------------------------- /src-tauri/icons/android/mipmap-xxhdpi/ic_launcher_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eigenwallet/core/HEAD/src-tauri/icons/android/mipmap-xxhdpi/ic_launcher_foreground.png -------------------------------------------------------------------------------- /src-tauri/icons/android/mipmap-xxxhdpi/ic_launcher_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eigenwallet/core/HEAD/src-tauri/icons/android/mipmap-xxxhdpi/ic_launcher_foreground.png -------------------------------------------------------------------------------- /src-tauri/gen/android/app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eigenwallet/core/HEAD/src-tauri/gen/android/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /src-tauri/gen/android/app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eigenwallet/core/HEAD/src-tauri/gen/android/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /src-tauri/gen/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eigenwallet/core/HEAD/src-tauri/gen/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /src-tauri/gen/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eigenwallet/core/HEAD/src-tauri/gen/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /src-tauri/gen/apple/Sources/unstoppableswap-gui-rs/bindings/bindings.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace ffi { 4 | extern "C" { 5 | void start_app(); 6 | } 7 | } 8 | 9 | -------------------------------------------------------------------------------- /src-tauri/gen/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eigenwallet/core/HEAD/src-tauri/gen/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /src-tauri/gen/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eigenwallet/core/HEAD/src-tauri/gen/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /src-tauri/gen/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eigenwallet/core/HEAD/src-tauri/gen/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /src-tauri/gen/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eigenwallet/core/HEAD/src-tauri/gen/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /src-tauri/gen/apple/Assets.xcassets/AppIcon.appiconset/AppIcon-512@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eigenwallet/core/HEAD/src-tauri/gen/apple/Assets.xcassets/AppIcon.appiconset/AppIcon-512@2x.png -------------------------------------------------------------------------------- /dev-scripts/code2prompt_to_clipboard.sh: -------------------------------------------------------------------------------- 1 | # Install using: 2 | # 1. cargo install code2prompt 3 | # 2. brew install code2prompt 4 | code2prompt . --exclude "*.lock" --exclude ".sqlx/*" --exclude "target" -------------------------------------------------------------------------------- /docs/pages/usage/_meta.json: -------------------------------------------------------------------------------- 1 | { 2 | "first_swap": "Complete your first swap", 3 | "market_maker_discovery": "Maker discovery", 4 | "refund_punish": "Cancel, Refund and Punish explained" 5 | } 6 | -------------------------------------------------------------------------------- /rust-toolchain.toml: -------------------------------------------------------------------------------- 1 | [toolchain] 2 | # also update this in the readme, changelog, and github actions 3 | channel = "1.88.0" 4 | components = ["clippy"] 5 | targets = ["armv7-unknown-linux-gnueabihf"] 6 | -------------------------------------------------------------------------------- /src-tauri/gen/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eigenwallet/core/HEAD/src-tauri/gen/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /src-tauri/gen/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eigenwallet/core/HEAD/src-tauri/gen/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /src-tauri/gen/android/app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | eigenwallet 3 | eigenwallet 4 | -------------------------------------------------------------------------------- /src-tauri/gen/apple/Assets.xcassets/AppIcon.appiconset/AppIcon-20x20@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eigenwallet/core/HEAD/src-tauri/gen/apple/Assets.xcassets/AppIcon.appiconset/AppIcon-20x20@1x.png -------------------------------------------------------------------------------- /src-tauri/gen/apple/Assets.xcassets/AppIcon.appiconset/AppIcon-20x20@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eigenwallet/core/HEAD/src-tauri/gen/apple/Assets.xcassets/AppIcon.appiconset/AppIcon-20x20@2x.png -------------------------------------------------------------------------------- /src-tauri/gen/apple/Assets.xcassets/AppIcon.appiconset/AppIcon-20x20@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eigenwallet/core/HEAD/src-tauri/gen/apple/Assets.xcassets/AppIcon.appiconset/AppIcon-20x20@3x.png -------------------------------------------------------------------------------- /src-tauri/gen/apple/Assets.xcassets/AppIcon.appiconset/AppIcon-29x29@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eigenwallet/core/HEAD/src-tauri/gen/apple/Assets.xcassets/AppIcon.appiconset/AppIcon-29x29@1x.png -------------------------------------------------------------------------------- /src-tauri/gen/apple/Assets.xcassets/AppIcon.appiconset/AppIcon-29x29@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eigenwallet/core/HEAD/src-tauri/gen/apple/Assets.xcassets/AppIcon.appiconset/AppIcon-29x29@2x.png -------------------------------------------------------------------------------- /src-tauri/gen/apple/Assets.xcassets/AppIcon.appiconset/AppIcon-29x29@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eigenwallet/core/HEAD/src-tauri/gen/apple/Assets.xcassets/AppIcon.appiconset/AppIcon-29x29@3x.png -------------------------------------------------------------------------------- /src-tauri/gen/apple/Assets.xcassets/AppIcon.appiconset/AppIcon-40x40@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eigenwallet/core/HEAD/src-tauri/gen/apple/Assets.xcassets/AppIcon.appiconset/AppIcon-40x40@1x.png -------------------------------------------------------------------------------- /src-tauri/gen/apple/Assets.xcassets/AppIcon.appiconset/AppIcon-40x40@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eigenwallet/core/HEAD/src-tauri/gen/apple/Assets.xcassets/AppIcon.appiconset/AppIcon-40x40@2x.png -------------------------------------------------------------------------------- /src-tauri/gen/apple/Assets.xcassets/AppIcon.appiconset/AppIcon-40x40@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eigenwallet/core/HEAD/src-tauri/gen/apple/Assets.xcassets/AppIcon.appiconset/AppIcon-40x40@3x.png -------------------------------------------------------------------------------- /src-tauri/gen/apple/Assets.xcassets/AppIcon.appiconset/AppIcon-60x60@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eigenwallet/core/HEAD/src-tauri/gen/apple/Assets.xcassets/AppIcon.appiconset/AppIcon-60x60@2x.png -------------------------------------------------------------------------------- /src-tauri/gen/apple/Assets.xcassets/AppIcon.appiconset/AppIcon-60x60@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eigenwallet/core/HEAD/src-tauri/gen/apple/Assets.xcassets/AppIcon.appiconset/AppIcon-60x60@3x.png -------------------------------------------------------------------------------- /src-tauri/gen/apple/Assets.xcassets/AppIcon.appiconset/AppIcon-76x76@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eigenwallet/core/HEAD/src-tauri/gen/apple/Assets.xcassets/AppIcon.appiconset/AppIcon-76x76@1x.png -------------------------------------------------------------------------------- /src-tauri/gen/apple/Assets.xcassets/AppIcon.appiconset/AppIcon-76x76@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eigenwallet/core/HEAD/src-tauri/gen/apple/Assets.xcassets/AppIcon.appiconset/AppIcon-76x76@2x.png -------------------------------------------------------------------------------- /src-tauri/gen/android/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eigenwallet/core/HEAD/src-tauri/gen/android/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png -------------------------------------------------------------------------------- /src-tauri/gen/android/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eigenwallet/core/HEAD/src-tauri/gen/android/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png -------------------------------------------------------------------------------- /src-tauri/gen/android/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eigenwallet/core/HEAD/src-tauri/gen/android/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png -------------------------------------------------------------------------------- /src-tauri/gen/apple/Assets.xcassets/AppIcon.appiconset/AppIcon-20x20@2x-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eigenwallet/core/HEAD/src-tauri/gen/apple/Assets.xcassets/AppIcon.appiconset/AppIcon-20x20@2x-1.png -------------------------------------------------------------------------------- /src-tauri/gen/apple/Assets.xcassets/AppIcon.appiconset/AppIcon-29x29@2x-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eigenwallet/core/HEAD/src-tauri/gen/apple/Assets.xcassets/AppIcon.appiconset/AppIcon-29x29@2x-1.png -------------------------------------------------------------------------------- /src-tauri/gen/apple/Assets.xcassets/AppIcon.appiconset/AppIcon-40x40@2x-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eigenwallet/core/HEAD/src-tauri/gen/apple/Assets.xcassets/AppIcon.appiconset/AppIcon-40x40@2x-1.png -------------------------------------------------------------------------------- /src-tauri/tauri.windows.conf.json: -------------------------------------------------------------------------------- 1 | { 2 | "bundle": { 3 | "resources": [ 4 | "libstdc++-6.dll", 5 | "libgcc_s_seh-1.dll", 6 | "libwinpthread-1.dll" 7 | ] 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src-tauri/gen/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eigenwallet/core/HEAD/src-tauri/gen/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png -------------------------------------------------------------------------------- /src-tauri/gen/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eigenwallet/core/HEAD/src-tauri/gen/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png -------------------------------------------------------------------------------- /src-tauri/gen/apple/Assets.xcassets/AppIcon.appiconset/AppIcon-83.5x83.5@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eigenwallet/core/HEAD/src-tauri/gen/apple/Assets.xcassets/AppIcon.appiconset/AppIcon-83.5x83.5@2x.png -------------------------------------------------------------------------------- /src-gui/src/renderer/components/modal/introduction/slides/SlideTypes.ts: -------------------------------------------------------------------------------- 1 | export type IntroSlideProps = { 2 | handleContinue: () => void; 3 | handlePrevious: () => void; 4 | hidePreviousButton?: boolean; 5 | }; 6 | -------------------------------------------------------------------------------- /src-gui/src/store/types.ts: -------------------------------------------------------------------------------- 1 | export enum Network { 2 | Testnet = "testnet", 3 | Mainnet = "mainnet", 4 | } 5 | 6 | export enum Blockchain { 7 | Bitcoin = "bitcoin", 8 | Monero = "monero", 9 | } 10 | -------------------------------------------------------------------------------- /src-tauri/gen/android/app/.gitignore: -------------------------------------------------------------------------------- 1 | /src/main/java/net/unstoppableswap/gui/generated 2 | /src/main/jniLibs/**/*.so 3 | /src/main/assets/tauri.conf.json 4 | /tauri.build.gradle.kts 5 | /proguard-tauri.pro 6 | /tauri.properties -------------------------------------------------------------------------------- /swap-asb/build.rs: -------------------------------------------------------------------------------- 1 | use anyhow::Result; 2 | use vergen::EmitBuilder; 3 | 4 | fn main() -> Result<()> { 5 | EmitBuilder::builder() 6 | .git_describe(true, true, None) 7 | .emit()?; 8 | Ok(()) 9 | } 10 | -------------------------------------------------------------------------------- /swap/migrations/20240701231624_create_buffered_transfer_proofs_table.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE if NOT EXISTS buffered_transfer_proofs 2 | ( 3 | swap_id TEXT PRIMARY KEY NOT NULL, 4 | proof TEXT NOT NULL 5 | ); -------------------------------------------------------------------------------- /.cursor/rules/never-upgrade-deps-without-explicit-confirmation.mdc: -------------------------------------------------------------------------------- 1 | --- 2 | description: 3 | globs: 4 | alwaysApply: false 5 | --- 6 | NEVER NEVER NEVER upgrade or changr the versions used in dependencies without explicitly asking for confirmation!! -------------------------------------------------------------------------------- /throttle/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "throttle" 3 | version = "0.1.0" 4 | edition = "2024" 5 | 6 | [dependencies] 7 | tracing = { workspace = true } 8 | 9 | [lib] 10 | path = "src/throttle.rs" 11 | 12 | [lints] 13 | workspace = true 14 | -------------------------------------------------------------------------------- /src-gui/src/utils/logger.ts: -------------------------------------------------------------------------------- 1 | const logger = { 2 | trace: console.log, 3 | debug: console.log, 4 | info: console.log, 5 | warn: console.warn, 6 | error: console.error, 7 | fatal: console.error, 8 | }; 9 | 10 | export default logger; 11 | -------------------------------------------------------------------------------- /src-gui/src/utils/typescriptUtils.tsx: -------------------------------------------------------------------------------- 1 | export function exhaustiveGuard(_value: never): never { 2 | throw new Error( 3 | `ERROR! Reached forbidden guard function with unexpected value: ${JSON.stringify( 4 | _value, 5 | )}`, 6 | ); 7 | } 8 | -------------------------------------------------------------------------------- /swap/build.rs: -------------------------------------------------------------------------------- 1 | use anyhow::Result; 2 | use vergen_git2::{Emitter, Git2Builder}; 3 | 4 | fn main() -> Result<()> { 5 | let git2 = Git2Builder::all_git()?; 6 | 7 | Emitter::default().add_instructions(&git2)?.emit()?; 8 | Ok(()) 9 | } 10 | -------------------------------------------------------------------------------- /src-gui/knip.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://unpkg.com/knip@5/schema.json", 3 | "entry": ["src/renderer/index.tsx", "index.html"], 4 | "project": ["src/**/*.{ts,tsx,js,jsx}"], 5 | "ignoreExportsUsedInFile": true, 6 | "tags": ["-lintignore"] 7 | } 8 | -------------------------------------------------------------------------------- /src-gui/src/models/rpcModel.ts: -------------------------------------------------------------------------------- 1 | // TODO: Auto generate this using typeshare from swap/src/cli/api/request.rs 2 | export type MoneroRecoveryResponse = { 3 | address: string; 4 | spend_key: string; 5 | view_key: string; 6 | restore_height: number; 7 | }; 8 | -------------------------------------------------------------------------------- /src-tauri/gen/apple/unstoppableswap-gui-rs.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /docs/next-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | /// 3 | 4 | // NOTE: This file should not be edited 5 | // see https://nextjs.org/docs/pages/building-your-application/configuring/typescript for more information. 6 | -------------------------------------------------------------------------------- /swap-fs/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "swap-fs" 3 | version = "0.1.0" 4 | edition = "2024" 5 | 6 | [dependencies] 7 | anyhow = { workspace = true } 8 | directories-next = "2" 9 | tracing = { workspace = true } 10 | 11 | [lints] 12 | workspace = true 13 | -------------------------------------------------------------------------------- /swap-proptest/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "swap-proptest" 3 | version = "0.1.0" 4 | edition = "2024" 5 | 6 | [dependencies] 7 | bitcoin = { workspace = true } 8 | ecdsa_fun = { workspace = true } 9 | proptest = "1" 10 | 11 | [lints] 12 | workspace = true 13 | -------------------------------------------------------------------------------- /docs/pages/_meta.json: -------------------------------------------------------------------------------- 1 | { 2 | "index": "Introduction", 3 | "getting_started": "Getting Started", 4 | "usage": "Usage", 5 | "advanced": "Advanced", 6 | "becoming_a_maker": "Becoming a Maker", 7 | "send_feedback": "Send Feedback", 8 | "donate": "Donate" 9 | } 10 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "monero-sys/monero"] 2 | path = monero-sys/monero 3 | url = https://github.com/mrcyjanek/monero 4 | ignore = dirty 5 | [submodule "monero-sys/monero-depends"] 6 | path = monero-sys/monero-depends 7 | url = https://github.com/eigenwallet/monero-depends.git 8 | -------------------------------------------------------------------------------- /src-tauri/gen/android/app/src/main/res/xml/file_paths.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /src-tauri/gen/apple/unstoppableswap-gui-rs_iOS/unstoppableswap-gui-rs_iOS.entitlements: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /CLAUDE.md: -------------------------------------------------------------------------------- 1 | - When asked about libp2p, check if a rust-libp2p folder exists which contains the cloned rust libp2p codebase. Read through to figure out what the best response it. If its a question about best practice when implementing protocols read @rust-libp2p/protocols/ specificially. 2 | -------------------------------------------------------------------------------- /src-gui/tsconfig.node.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "composite": true, 4 | "skipLibCheck": true, 5 | "module": "ESNext", 6 | "moduleResolution": "bundler", 7 | "allowSyntheticDefaultImports": true 8 | }, 9 | "include": ["vite.config.ts"] 10 | } 11 | -------------------------------------------------------------------------------- /monero-rpc-pool/migrations/20250813225842_cryptostorm_mainnet_node.sql: -------------------------------------------------------------------------------- 1 | DELETE FROM monero_nodes WHERE host = 'xmr.cryptostorm.is' AND port = 18081; 2 | INSERT INTO monero_nodes (scheme, host, port, network, first_seen_at) VALUES ('https', 'xmr.cryptostorm.is', 18081, 'mainnet', datetime('now')); -------------------------------------------------------------------------------- /swap-p2p/src/protocols.rs: -------------------------------------------------------------------------------- 1 | pub mod cooperative_xmr_redeem_after_punish; 2 | pub mod encrypted_signature; 3 | pub mod notice; 4 | pub mod quote; 5 | pub mod quotes; 6 | pub mod quotes_cached; 7 | pub mod redial; 8 | pub mod rendezvous; 9 | pub mod swap_setup; 10 | pub mod transfer_proof; 11 | -------------------------------------------------------------------------------- /dev-scripts/code2prompt_as_file_mac_os.sh: -------------------------------------------------------------------------------- 1 | # Install using: 2 | # 1. cargo install code2prompt 3 | # 2. brew install code2prompt 4 | code2prompt . --exclude "*.lock" --exclude ".sqlx/*" --exclude "target" --output-file "$TMPDIR/code.txt" && osascript -e 'set the clipboard to POSIX file "'"$TMPDIR"'/code.txt"' -------------------------------------------------------------------------------- /src-tauri/gen/apple/ExportOptions.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | method 6 | debugging 7 | 8 | 9 | -------------------------------------------------------------------------------- /swap-orchestrator/build.rs: -------------------------------------------------------------------------------- 1 | use anyhow::Result; 2 | use vergen::EmitBuilder; 3 | 4 | fn main() -> Result<()> { 5 | EmitBuilder::builder() 6 | .git_describe(true, true, None) 7 | .git_sha(false) // false = short hash, true = full hash 8 | .emit()?; 9 | Ok(()) 10 | } 11 | -------------------------------------------------------------------------------- /src-tauri/gen/android/.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig is awesome: https://EditorConfig.org 2 | 3 | # top-most EditorConfig file 4 | root = true 5 | 6 | [*] 7 | indent_style = space 8 | indent_size = 2 9 | end_of_line = lf 10 | charset = utf-8 11 | trim_trailing_whitespace = false 12 | insert_final_newline = false -------------------------------------------------------------------------------- /src-tauri/gen/android/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Tue May 10 19:22:52 CST 2022 2 | distributionBase=GRADLE_USER_HOME 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.14.3-bin.zip 4 | distributionPath=wrapper/dists 5 | zipStorePath=wrapper/dists 6 | zipStoreBase=GRADLE_USER_HOME 7 | -------------------------------------------------------------------------------- /swap-p2p/src/lib.rs: -------------------------------------------------------------------------------- 1 | pub mod behaviour_util; 2 | pub mod defaults; 3 | pub mod futures_util; 4 | pub mod impl_from_rr_event; 5 | pub mod libp2p_ext; 6 | pub mod observe; 7 | pub mod out_event; 8 | pub mod patches; 9 | pub mod protocols; 10 | 11 | #[cfg(any(test, feature = "test-support"))] 12 | pub mod test; 13 | -------------------------------------------------------------------------------- /swap/src/monero.rs: -------------------------------------------------------------------------------- 1 | pub use monero_wallet as wallet; 2 | pub mod wallet_rpc; 3 | 4 | pub use ::monero::network::Network; 5 | pub use ::monero::{Address, PrivateKey, PublicKey}; 6 | pub use curve25519_dalek::scalar::Scalar; 7 | pub use swap_core::monero::primitives::*; 8 | pub use wallet::{Daemon, Wallet, Wallets}; 9 | -------------------------------------------------------------------------------- /src-gui/src/renderer/components/pages/swap/swap/in_progress/CancelTimelockExpiredPage.tsx: -------------------------------------------------------------------------------- 1 | import CircularProgressWithSubtitle from "../components/CircularProgressWithSubtitle"; 2 | 3 | export default function CancelTimelockExpiredPage() { 4 | return ; 5 | } 6 | -------------------------------------------------------------------------------- /src-tauri/.gitignore: -------------------------------------------------------------------------------- 1 | # Generated by Cargo 2 | # will have compiled files and executables 3 | /target/ 4 | 5 | # Generated by Tauri 6 | # will have schema files for capabilities auto-completion 7 | /gen/schemas 8 | 9 | # Tauri windows .dll dependencies - build by `just prepare-windows-build` 10 | *.dll 11 | 12 | .yarn/ -------------------------------------------------------------------------------- /tracing-ext/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "tracing-ext" 3 | version = "0.1.0" 4 | authors = ["The COMIT guys "] 5 | edition = "2021" 6 | description = "Additional test utils for tracing" 7 | 8 | [dependencies] 9 | tracing = { workspace = true } 10 | tracing-subscriber = { workspace = true } 11 | -------------------------------------------------------------------------------- /docs/public/manifest.webmanifest: -------------------------------------------------------------------------------- 1 | { 2 | "icons": [ 3 | { 4 | "src": "/android-chrome-192x192.png", 5 | "sizes": "192x192", 6 | "type": "image/png" 7 | }, 8 | { 9 | "src": "/android-chrome-512x512.png", 10 | "sizes": "512x512", 11 | "type": "image/png" 12 | } 13 | ] 14 | } 15 | -------------------------------------------------------------------------------- /src-tauri/capabilities/desktop.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "../gen/schemas/desktop-schema.json", 3 | "identifier": "desktop-capability", 4 | "description": "Capabilities for desktop windows", 5 | "platforms": ["macOS", "windows", "linux"], 6 | "windows": ["main"], 7 | "permissions": ["cli:default", "cli:allow-cli-matches"] 8 | } 9 | -------------------------------------------------------------------------------- /.cursor/rules/dont-run-cargo.mdc: -------------------------------------------------------------------------------- 1 | --- 2 | description: Don't run cargo clean. Ask the user to confirm. 3 | globs: 4 | alwaysApply: true 5 | --- 6 | 7 | Only run cargo clean after asking the user. 8 | 9 | If the user says "run cargo clean" then use cargo clean. 10 | 11 | The codebase takes a long ass time to compile, that's why. 12 | -------------------------------------------------------------------------------- /flatpak/org.eigenwallet.app.flatpakref: -------------------------------------------------------------------------------- 1 | [Flatpak Ref] 2 | Url=%Url% 3 | Icon=%Url%/icon.png 4 | SuggestRemoteName=eigenwallet 5 | Homepage=%Homepage% 6 | GPGKey=%GPGKey% 7 | 8 | Title=eigenwallet GUI 9 | Name=org.eigenwallet.app 10 | Branch=stable 11 | RuntimeRepo=https://dl.flathub.org/repo/flathub.flatpakrepo 12 | IsRuntime=false 13 | -------------------------------------------------------------------------------- /src-gui/src/renderer/components/pages/swap/swap/in_progress/RedeemingMoneroPage.tsx: -------------------------------------------------------------------------------- 1 | import CircularProgressWithSubtitle from "../components/CircularProgressWithSubtitle"; 2 | 3 | export default function RedeemingMoneroPage() { 4 | return ( 5 | 6 | ); 7 | } 8 | -------------------------------------------------------------------------------- /src-gui/src/renderer/components/pages/swap/swap/in_progress/XmrLockedPage.tsx: -------------------------------------------------------------------------------- 1 | import CircularProgressWithSubtitle from "../components/CircularProgressWithSubtitle"; 2 | 3 | export default function XmrLockedPage() { 4 | return ( 5 | 6 | ); 7 | } 8 | -------------------------------------------------------------------------------- /src-tauri/gen/android/app/src/main/res/values/themes.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 7 | -------------------------------------------------------------------------------- /src-gui/src/renderer/components/alert/LoadingSpinnerAlert.tsx: -------------------------------------------------------------------------------- 1 | import { CircularProgress } from "@mui/material"; 2 | import { Alert } from "@mui/material"; 3 | import { AlertProps } from "@mui/material"; 4 | 5 | export function LoadingSpinnerAlert({ ...rest }: AlertProps) { 6 | return } {...rest} />; 7 | } 8 | -------------------------------------------------------------------------------- /src-gui/src/renderer/components/pages/swap/swap/in_progress/BitcoinCancelledPage.tsx: -------------------------------------------------------------------------------- 1 | import CircularProgressWithSubtitle from "renderer/components/pages/swap/swap/components/CircularProgressWithSubtitle"; 2 | 3 | export default function BitcoinCancelledPage() { 4 | return ; 5 | } 6 | -------------------------------------------------------------------------------- /src-tauri/gen/android/app/src/main/res/values-night/themes.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 7 | -------------------------------------------------------------------------------- /swap-controller-api/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "swap-controller-api" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | [dependencies] 7 | bitcoin = { workspace = true } 8 | jsonrpsee = { workspace = true, features = ["macros", "server", "client-core", "http-client"] } 9 | serde = { workspace = true } 10 | 11 | [lints] 12 | workspace = true 13 | -------------------------------------------------------------------------------- /monero-sys/migrations/20250710170522_create_recent_wallets.sql: -------------------------------------------------------------------------------- 1 | -- Add migration script here 2 | 3 | CREATE TABLE recent_wallets ( 4 | id INTEGER PRIMARY KEY AUTOINCREMENT, 5 | wallet_path TEXT UNIQUE NOT NULL, 6 | last_opened_at TEXT NOT NULL 7 | ); 8 | 9 | CREATE INDEX idx_recent_wallets_last_opened ON recent_wallets(last_opened_at DESC); 10 | -------------------------------------------------------------------------------- /flatpak/unstoppableswap-gui-rs.flatpak.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh -x 2 | 3 | # Work around https://github.com/eigenwallet/core/issues/665 4 | WEBKIT_DISABLE_DMABUF_RENDERER=1 5 | export WEBKIT_DISABLE_DMABUF_RENDERER 6 | 7 | # This executed in flatpak, with /app/bin in $PATH 8 | # flatpak runs execlp("${manifest.command}"), replicate this 9 | exec unstoppableswap-gui-rs "$@" 10 | -------------------------------------------------------------------------------- /docs/next.config.js: -------------------------------------------------------------------------------- 1 | const withNextra = require("nextra")({ 2 | theme: "nextra-theme-docs", 3 | themeConfig: "./theme.config.jsx", 4 | }); 5 | 6 | module.exports = withNextra({ 7 | output: "standalone", 8 | }); 9 | 10 | // If you have other Next.js configurations, you can pass them as the parameter: 11 | // module.exports = withNextra({ /* other next.js config */ }) 12 | -------------------------------------------------------------------------------- /flatpak/eigenwallet.flatpakrepo: -------------------------------------------------------------------------------- 1 | [Flatpak Repo] 2 | Url=%Url% 3 | Icon=%Url%/icon.png 4 | SuggestRemoteName=eigenwallet 5 | Homepage=%Homepage% 6 | GPGKey=%GPGKey% 7 | 8 | Title=eigenwallet 9 | Name=eigenwallet 10 | Comment=Unstoppable cross-chain atomic swaps 11 | Description=Repository for eigenwallet applications - providing secure and decentralized XMR-BTC atomic swaps 12 | -------------------------------------------------------------------------------- /src-tauri/gen/android/.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea/caches 5 | /.idea/libraries 6 | /.idea/modules.xml 7 | /.idea/workspace.xml 8 | /.idea/navEditor.xml 9 | /.idea/assetWizardSettings.xml 10 | .DS_Store 11 | build 12 | /captures 13 | .externalNativeBuild 14 | .cxx 15 | local.properties 16 | key.properties 17 | 18 | /.tauri 19 | /tauri.settings.gradle -------------------------------------------------------------------------------- /src-tauri/gen/android/app/src/main/java/net/unstoppableswap/gui/MainActivity.kt: -------------------------------------------------------------------------------- 1 | package net.unstoppableswap.gui 2 | 3 | import android.os.Bundle 4 | import androidx.activity.enableEdgeToEdge 5 | 6 | class MainActivity : TauriActivity() { 7 | override fun onCreate(savedInstanceState: Bundle?) { 8 | enableEdgeToEdge() 9 | super.onCreate(savedInstanceState) 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src-gui/src/utils/hash.ts: -------------------------------------------------------------------------------- 1 | const FNV_OFFSET_BASIS = 0x811c9dc5; 2 | const FNV_PRIME = 0x01000193; 3 | 4 | export function fnv1a(value: string): string { 5 | let hash = FNV_OFFSET_BASIS; 6 | 7 | for (let i = 0; i < value.length; i += 1) { 8 | hash ^= value.charCodeAt(i); 9 | hash = (hash * FNV_PRIME) >>> 0; 10 | } 11 | 12 | return hash.toString(16).padStart(8, "0"); 13 | } 14 | -------------------------------------------------------------------------------- /src-tauri/src/main.rs: -------------------------------------------------------------------------------- 1 | // Prevents additional console window on Windows in release, DO NOT REMOVE!! 2 | #![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] 3 | 4 | fn main() { 5 | rustls::crypto::ring::default_provider() 6 | .install_default() 7 | .expect("failed to install default rustls provider"); 8 | 9 | unstoppableswap_gui_rs_lib::run() 10 | } 11 | -------------------------------------------------------------------------------- /src-gui/src/renderer/components/pages/history/HistoryPage.tsx: -------------------------------------------------------------------------------- 1 | import { Typography } from "@mui/material"; 2 | import SwapTxLockAlertsBox from "../../alert/SwapTxLockAlertsBox"; 3 | import HistoryTable from "./table/HistoryTable"; 4 | 5 | export default function HistoryPage() { 6 | return ( 7 | <> 8 | 9 | 10 | > 11 | ); 12 | } 13 | -------------------------------------------------------------------------------- /dev-scripts/brew_dependencies_install.sh: -------------------------------------------------------------------------------- 1 | brew update 2 | 3 | # See action.yml 4 | brew install cmake boost openssl zmq libpgm miniupnpc expat libunwind-headers git 5 | 6 | # We need to build from source to be able to statically link the dependencies 7 | brew reinstall --build-from-source unbound expat 8 | 9 | # We need an older version of protobuf to be able to statically link it 10 | brew install protobuf@21 -------------------------------------------------------------------------------- /src-gui/src/renderer/components/pages/monero/components/index.ts: -------------------------------------------------------------------------------- 1 | export { default as WalletOverview } from "./WalletOverview"; 2 | export { default as TransactionHistory } from "./TransactionHistory"; 3 | export { default as WalletActionButtons } from "./WalletActionButtons"; 4 | export { default as SendTransactionContent } from "./SendTransactionContent"; 5 | export { default as SendApprovalContent } from "./SendApprovalContent"; 6 | -------------------------------------------------------------------------------- /src-gui/src/models/storeModel.ts: -------------------------------------------------------------------------------- 1 | import { CliLog, SwapSpawnType } from "./cliModel"; 2 | import { TauriSwapProgressEvent } from "./tauriModel"; 3 | 4 | export type SwapState = { 5 | curr: TauriSwapProgressEvent; 6 | prev: TauriSwapProgressEvent | null; 7 | swapId: string; 8 | }; 9 | 10 | export interface SwapSlice { 11 | state: SwapState | null; 12 | logs: CliLog[]; 13 | spawnType: SwapSpawnType | null; 14 | } 15 | -------------------------------------------------------------------------------- /swap/src/cli.rs: -------------------------------------------------------------------------------- 1 | pub mod api; 2 | pub mod cancel_and_refund; 3 | pub mod command; 4 | pub mod transport; 5 | pub mod watcher; 6 | 7 | mod behaviour; 8 | mod event_loop; 9 | mod list_sellers; 10 | 11 | pub use behaviour::{Behaviour, OutEvent}; 12 | pub use cancel_and_refund::{cancel, cancel_and_refund, refund}; 13 | pub use event_loop::{EventLoop, EventLoopHandle, SwapEventLoopHandle}; 14 | pub use list_sellers::QuoteWithAddress; 15 | -------------------------------------------------------------------------------- /docs/components/Logo.tsx: -------------------------------------------------------------------------------- 1 | import Image from "next/image"; 2 | 3 | export default function Logo() { 4 | return ( 5 | 6 | 13 | eigenwallet 14 | 15 | ); 16 | } 17 | -------------------------------------------------------------------------------- /src-gui/src/renderer/components/other/ExternalLink.tsx: -------------------------------------------------------------------------------- 1 | import Link from "@mui/material/Link"; 2 | import { openUrl } from "@tauri-apps/plugin-opener"; 3 | 4 | export default function ExternalLink({ 5 | children, 6 | href, 7 | }: { 8 | children: React.ReactNode; 9 | href: string; 10 | }) { 11 | return ( 12 | openUrl(href)}> 13 | {children} 14 | 15 | ); 16 | } 17 | -------------------------------------------------------------------------------- /src-tauri/gen/apple/unstoppableswap-gui-rs.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | BuildSystemType 6 | Original 7 | DisableBuildSystemDeprecationDiagnostic 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /.sqlx/query-2a356078a41b321234adf2aa385b501749f907f7c422945a8bdda2b6274f5225.json: -------------------------------------------------------------------------------- 1 | { 2 | "db_name": "SQLite", 3 | "query": "\n insert into peers (\n swap_id,\n peer_id\n ) values (?, ?);\n ", 4 | "describe": { 5 | "columns": [], 6 | "parameters": { 7 | "Right": 2 8 | }, 9 | "nullable": [] 10 | }, 11 | "hash": "2a356078a41b321234adf2aa385b501749f907f7c422945a8bdda2b6274f5225" 12 | } 13 | -------------------------------------------------------------------------------- /src-tauri/gen/android/app/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #FFBB86FC 4 | #FF6200EE 5 | #FF3700B3 6 | #FF03DAC5 7 | #FF018786 8 | #FF000000 9 | #FFFFFFFF 10 | -------------------------------------------------------------------------------- /electrum-pool/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "electrum-pool" 3 | version = "0.1.0" 4 | authors = ["eigenwallet Team "] 5 | edition = "2021" 6 | 7 | [dependencies] 8 | backoff = { workspace = true } 9 | bdk_electrum = { workspace = true, features = ["use-rustls-ring"] } 10 | bitcoin = { workspace = true } 11 | futures = { workspace = true } 12 | once_cell = { workspace = true } 13 | tokio = { workspace = true } 14 | tracing = { workspace = true } 15 | -------------------------------------------------------------------------------- /.sqlx/query-50ef34b4efabe650d40096a390d9240b9a7cd62878dfaa6805563cfc21284cd5.json: -------------------------------------------------------------------------------- 1 | { 2 | "db_name": "SQLite", 3 | "query": "\n insert or ignore into peer_addresses (\n peer_id,\n address\n ) values (?, ?);\n ", 4 | "describe": { 5 | "columns": [], 6 | "parameters": { 7 | "Right": 2 8 | }, 9 | "nullable": [] 10 | }, 11 | "hash": "50ef34b4efabe650d40096a390d9240b9a7cd62878dfaa6805563cfc21284cd5" 12 | } 13 | -------------------------------------------------------------------------------- /swap-db/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "swap-db" 3 | version = "0.1.0" 4 | edition = "2024" 5 | 6 | [dependencies] 7 | # Our crates 8 | swap-core = { path = "../swap-core" } 9 | swap-machine = { path = "../swap-machine" } 10 | swap-serde = { path = "../swap-serde" } 11 | 12 | # Crypto 13 | bitcoin = { workspace = true } 14 | 15 | # Serialization 16 | serde = { workspace = true } 17 | strum = { workspace = true, features = ["derive"] } 18 | 19 | [lints] 20 | workspace = true 21 | -------------------------------------------------------------------------------- /monero-rpc/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![warn( 2 | unused_extern_crates, 3 | missing_debug_implementations, 4 | missing_copy_implementations, 5 | rust_2018_idioms, 6 | clippy::cast_possible_truncation, 7 | clippy::cast_sign_loss, 8 | clippy::fallible_impl_from, 9 | clippy::cast_precision_loss, 10 | clippy::cast_possible_wrap, 11 | clippy::dbg_macro 12 | )] 13 | #![forbid(unsafe_code)] 14 | 15 | pub mod monerod; 16 | 17 | pub use jsonrpc_client as jsonrpc; 18 | -------------------------------------------------------------------------------- /src-gui/src/renderer/components/pages/swap/swap/in_progress/EncryptedSignatureSentPage.tsx: -------------------------------------------------------------------------------- 1 | import CircularProgressWithSubtitle from "../components/CircularProgressWithSubtitle"; 2 | import { useActiveSwapInfo, useSwapInfosSortedByDate } from "store/hooks"; 3 | import { Box } from "@mui/material"; 4 | 5 | export default function EncryptedSignatureSentPage() { 6 | return ( 7 | 8 | ); 9 | } 10 | -------------------------------------------------------------------------------- /swap-serde/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "swap-serde" 3 | version = "0.1.0" 4 | edition = "2024" 5 | 6 | [dependencies] 7 | anyhow = { workspace = true } 8 | bitcoin = { workspace = true } 9 | data-encoding = { workspace = true } 10 | libp2p = { workspace = true } 11 | monero = { workspace = true } 12 | serde = { workspace = true } 13 | serde_json = { workspace = true } 14 | thiserror = { workspace = true } 15 | url = { workspace = true } 16 | 17 | [lints] 18 | workspace = true 19 | -------------------------------------------------------------------------------- /src-tauri/gen/android/buildSrc/build.gradle.kts: -------------------------------------------------------------------------------- 1 | plugins { 2 | `kotlin-dsl` 3 | } 4 | 5 | gradlePlugin { 6 | plugins { 7 | create("pluginsForCoolKids") { 8 | id = "rust" 9 | implementationClass = "RustPlugin" 10 | } 11 | } 12 | } 13 | 14 | repositories { 15 | google() 16 | mavenCentral() 17 | } 18 | 19 | dependencies { 20 | compileOnly(gradleApi()) 21 | implementation("com.android.tools.build:gradle:8.11.0") 22 | } 23 | 24 | -------------------------------------------------------------------------------- /.sqlx/query-e36c287aa98ae80ad4b6bb6f7e4b59cced041406a9db71da827b09f0d3bacfd6.json: -------------------------------------------------------------------------------- 1 | { 2 | "db_name": "SQLite", 3 | "query": "\n INSERT INTO buffered_transfer_proofs (\n swap_id,\n proof\n ) VALUES (?, ?);\n ", 4 | "describe": { 5 | "columns": [], 6 | "parameters": { 7 | "Right": 2 8 | }, 9 | "nullable": [] 10 | }, 11 | "hash": "e36c287aa98ae80ad4b6bb6f7e4b59cced041406a9db71da827b09f0d3bacfd6" 12 | } 13 | -------------------------------------------------------------------------------- /monero-rpc-pool/migrations/20250624073558_default_nodes_remove_ssl_where_not_supported.sql: -------------------------------------------------------------------------------- 1 | -- Fix monerodevs.org nodes: change from https to http 2 | UPDATE monero_nodes 3 | SET scheme = 'http' 4 | WHERE host = 'node.monerodevs.org' AND network = 'stagenet'; 5 | 6 | UPDATE monero_nodes 7 | SET scheme = 'http' 8 | WHERE host = 'node2.monerodevs.org' AND network = 'stagenet'; 9 | 10 | UPDATE monero_nodes 11 | SET scheme = 'http' 12 | WHERE host = 'node3.monerodevs.org' AND network = 'stagenet'; -------------------------------------------------------------------------------- /src-gui/src/renderer/components/icons/LinkIconButton.tsx: -------------------------------------------------------------------------------- 1 | import { IconButton } from "@mui/material"; 2 | import { openUrl } from "@tauri-apps/plugin-opener"; 3 | import { ReactNode } from "react"; 4 | 5 | export default function LinkIconButton({ 6 | url, 7 | children, 8 | }: { 9 | url: string; 10 | children: ReactNode; 11 | }) { 12 | return ( 13 | openUrl(url)} size="large"> 14 | {children} 15 | 16 | ); 17 | } 18 | -------------------------------------------------------------------------------- /swap/migrations/20250625160448_scale_monero_pool_to_0_to_1_if_above_1.sql: -------------------------------------------------------------------------------- 1 | -- Fix percentage values that are stored as 0-100 instead of 0-1 2 | -- This migration converts percentage values for swap_ids where the sum > 1.0 3 | -- by scaling all percentages for that swap_id by dividing by 100 4 | UPDATE monero_addresses 5 | SET percentage = percentage / 100.0 6 | WHERE swap_id IN ( 7 | SELECT swap_id 8 | FROM monero_addresses 9 | GROUP BY swap_id 10 | HAVING SUM(percentage) > 1.0 11 | ); -------------------------------------------------------------------------------- /.sqlx/query-b703032b4ddc627a1124817477e7a8e5014bdc694c36a14053ef3bb2fc0c69b0.json: -------------------------------------------------------------------------------- 1 | { 2 | "db_name": "SQLite", 3 | "query": "\n insert into swap_states (\n swap_id,\n entered_at,\n state\n ) values (?, ?, ?);\n ", 4 | "describe": { 5 | "columns": [], 6 | "parameters": { 7 | "Right": 3 8 | }, 9 | "nullable": [] 10 | }, 11 | "hash": "b703032b4ddc627a1124817477e7a8e5014bdc694c36a14053ef3bb2fc0c69b0" 12 | } 13 | -------------------------------------------------------------------------------- /src-gui/.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | 10 | node_modules 11 | dist 12 | dist-ssr 13 | .vite 14 | *.local 15 | .yarn 16 | 17 | # Editor directories and files 18 | .vscode/* 19 | !.vscode/extensions.json 20 | .idea 21 | .DS_Store 22 | *.suo 23 | *.ntvs* 24 | *.njsproj 25 | *.sln 26 | *.sw? 27 | 28 | # Autogenerated bindings 29 | src/models/tauriModel.ts 30 | 31 | # Env files 32 | .env* 33 | .env.* 34 | -------------------------------------------------------------------------------- /src-tauri/gen/android/build.gradle.kts: -------------------------------------------------------------------------------- 1 | buildscript { 2 | repositories { 3 | google() 4 | mavenCentral() 5 | } 6 | dependencies { 7 | classpath("com.android.tools.build:gradle:8.11.0") 8 | classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:1.9.25") 9 | } 10 | } 11 | 12 | allprojects { 13 | repositories { 14 | google() 15 | mavenCentral() 16 | } 17 | } 18 | 19 | tasks.register("clean").configure { 20 | delete("build") 21 | } 22 | 23 | -------------------------------------------------------------------------------- /monero-tests/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "monero-tests" 3 | version = "0.1.0" 4 | edition = "2024" 5 | 6 | [dependencies] 7 | monero = { workspace = true } 8 | monero-harness = { path = "../monero-harness" } 9 | monero-sys = { path = "../monero-sys" } 10 | testcontainers = { workspace = true } 11 | 12 | anyhow = { workspace = true } 13 | tokio = { workspace = true, features = ["macros", "rt"] } 14 | tracing = { workspace = true } 15 | tracing-subscriber = { workspace = true } 16 | 17 | [lints] 18 | workspace = true 19 | -------------------------------------------------------------------------------- /monero-rpc/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "monero-rpc" 3 | version = "0.1.0" 4 | authors = ["CoBloX Team "] 5 | edition = "2021" 6 | 7 | [dependencies] 8 | anyhow = { workspace = true } 9 | data-encoding = { workspace = true } 10 | jsonrpc_client = { version = "0.7", features = ["reqwest"] } 11 | monero = { workspace = true } 12 | monero-epee-bin-serde = "1" 13 | reqwest = { workspace = true } 14 | rust_decimal = { workspace = true } 15 | serde = { workspace = true } 16 | serde_json = { workspace = true } 17 | -------------------------------------------------------------------------------- /src-gui/src/renderer/components/modal/DialogHeader.tsx: -------------------------------------------------------------------------------- 1 | import { DialogTitle, Typography } from "@mui/material"; 2 | import { ReactNode } from "react"; 3 | 4 | type DialogTitleProps = { 5 | title: ReactNode; 6 | }; 7 | 8 | export default function DialogHeader({ title }: DialogTitleProps) { 9 | return ( 10 | 16 | {title} 17 | 18 | ); 19 | } 20 | -------------------------------------------------------------------------------- /.sqlx/query-1f332be08a5426f3fbcadea4e755d82ff1cdc2690eb464ccc607d3a613fa76a1.json: -------------------------------------------------------------------------------- 1 | { 2 | "db_name": "SQLite", 3 | "query": "SELECT DISTINCT address FROM monero_addresses WHERE address IS NOT NULL", 4 | "describe": { 5 | "columns": [ 6 | { 7 | "name": "address", 8 | "ordinal": 0, 9 | "type_info": "Text" 10 | } 11 | ], 12 | "parameters": { 13 | "Right": 0 14 | }, 15 | "nullable": [true] 16 | }, 17 | "hash": "1f332be08a5426f3fbcadea4e755d82ff1cdc2690eb464ccc607d3a613fa76a1" 18 | } 19 | -------------------------------------------------------------------------------- /.sqlx/query-7c37de52b3bb2ccd0868ccb861127416848d85eaebe8245c58d5beac7d537087.json: -------------------------------------------------------------------------------- 1 | { 2 | "db_name": "SQLite", 3 | "query": "\n insert into monero_addresses (\n swap_id,\n address,\n percentage,\n label\n ) values (?, ?, ?, ?);\n ", 4 | "describe": { 5 | "columns": [], 6 | "parameters": { 7 | "Right": 4 8 | }, 9 | "nullable": [] 10 | }, 11 | "hash": "7c37de52b3bb2ccd0868ccb861127416848d85eaebe8245c58d5beac7d537087" 12 | } 13 | -------------------------------------------------------------------------------- /.sqlx/query-a679f789c90ede34cd840d23d90087520dcf1777fdf4cc3ed7aab0c9d70d060c.json: -------------------------------------------------------------------------------- 1 | { 2 | "db_name": "SQLite", 3 | "query": "\n INSERT INTO recent_wallets (wallet_path, last_opened_at)\n VALUES (?, ?)\n ON CONFLICT(wallet_path) DO UPDATE SET last_opened_at = excluded.last_opened_at\n ", 4 | "describe": { 5 | "columns": [], 6 | "parameters": { 7 | "Right": 2 8 | }, 9 | "nullable": [] 10 | }, 11 | "hash": "a679f789c90ede34cd840d23d90087520dcf1777fdf4cc3ed7aab0c9d70d060c" 12 | } 13 | -------------------------------------------------------------------------------- /src-tauri/capabilities/default.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "../gen/schemas/desktop-schema.json", 3 | "identifier": "default", 4 | "description": "Capability for the main window", 5 | "windows": ["main"], 6 | "permissions": [ 7 | "core:event:allow-emit", 8 | "core:event:default", 9 | "clipboard-manager:allow-write-text", 10 | "store:default", 11 | "process:default", 12 | "updater:default", 13 | "process:allow-restart", 14 | "opener:default", 15 | "dialog:allow-open", 16 | "dialog:default" 17 | ] 18 | } 19 | -------------------------------------------------------------------------------- /swap/src/network.rs: -------------------------------------------------------------------------------- 1 | pub use swap_p2p::protocols::cooperative_xmr_redeem_after_punish; 2 | pub use swap_p2p::protocols::encrypted_signature; 3 | pub use swap_p2p::protocols::quote; 4 | pub use swap_p2p::protocols::quotes; 5 | pub use swap_p2p::protocols::quotes_cached; 6 | pub use swap_p2p::protocols::redial; 7 | pub use swap_p2p::protocols::rendezvous; 8 | pub use swap_p2p::protocols::swap_setup; 9 | pub use swap_p2p::protocols::transfer_proof; 10 | 11 | pub mod swarm; 12 | pub mod transport; 13 | 14 | #[cfg(test)] 15 | pub use swap_p2p::test; 16 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/submit_rendezvous_point.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Submit rendezvous point 3 | about: If you know of a rendezvous point ran by community volunteer, submit it here. We'll add it to the default list. 4 | title: "Request to submit rendezvous point" 5 | labels: "" 6 | assignees: "" 7 | --- 8 | 9 | **Rendezvous Server Address** 10 | 11 | ``` 12 | /dns4/your.domain/tcp/8888/p2p/12D3KooWS5RaYJt4ANKMH4zczGVhNcw5W214e2DDYXnAb4dsj3 13 | ``` 14 | 15 | *_Who is running the server?_ 16 | Username? How is this individual known within the community? 17 | -------------------------------------------------------------------------------- /.sqlx/query-081c729a0f1ad6e4ff3e13d6702c946bc4d37d50f40670b4f51d2efcce595aa6.json: -------------------------------------------------------------------------------- 1 | { 2 | "db_name": "SQLite", 3 | "query": "\n SELECT peer_id\n FROM peers\n WHERE swap_id = ?\n ", 4 | "describe": { 5 | "columns": [ 6 | { 7 | "name": "peer_id", 8 | "ordinal": 0, 9 | "type_info": "Text" 10 | } 11 | ], 12 | "parameters": { 13 | "Right": 1 14 | }, 15 | "nullable": [false] 16 | }, 17 | "hash": "081c729a0f1ad6e4ff3e13d6702c946bc4d37d50f40670b4f51d2efcce595aa6" 18 | } 19 | -------------------------------------------------------------------------------- /docs/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "lib": ["dom", "dom.iterable", "esnext"], 4 | "allowJs": true, 5 | "skipLibCheck": true, 6 | "strict": false, 7 | "noEmit": true, 8 | "incremental": true, 9 | "module": "esnext", 10 | "esModuleInterop": true, 11 | "moduleResolution": "node", 12 | "resolveJsonModule": true, 13 | "isolatedModules": true, 14 | "jsx": "preserve", 15 | "target": "ES2017" 16 | }, 17 | "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"], 18 | "exclude": ["node_modules"] 19 | } 20 | -------------------------------------------------------------------------------- /src-gui/src/renderer/components/other/HumanizedBitcoinBlockDuration.tsx: -------------------------------------------------------------------------------- 1 | import humanizeDuration from "humanize-duration"; 2 | 3 | const AVG_BLOCK_TIME_MS = 10 * 60 * 1000; 4 | 5 | export default function HumanizedBitcoinBlockDuration({ 6 | blocks, 7 | displayBlocks = true, 8 | }: { 9 | blocks: number; 10 | displayBlocks?: boolean; 11 | }) { 12 | return ( 13 | <> 14 | {`≈ ${humanizeDuration(blocks * AVG_BLOCK_TIME_MS, { 15 | conjunction: " and ", 16 | })}${displayBlocks ? ` (${blocks} blocks)` : ""}`} 17 | > 18 | ); 19 | } 20 | -------------------------------------------------------------------------------- /src-gui/src/renderer/components/pages/swap/SwapPage.tsx: -------------------------------------------------------------------------------- 1 | import { Box } from "@mui/material"; 2 | import ApiAlertsBox from "./ApiAlertsBox"; 3 | import SwapWidget from "./swap/SwapWidget"; 4 | 5 | export default function SwapPage() { 6 | return ( 7 | 17 | 18 | 19 | 20 | ); 21 | } 22 | -------------------------------------------------------------------------------- /.sqlx/query-e05620f420f8c1022971eeb66a803323a8cf258cbebb2834e3f7cf8f812fa646.json: -------------------------------------------------------------------------------- 1 | { 2 | "db_name": "SQLite", 3 | "query": "\n SELECT state\n FROM swap_states\n WHERE swap_id = ?\n ", 4 | "describe": { 5 | "columns": [ 6 | { 7 | "name": "state", 8 | "ordinal": 0, 9 | "type_info": "Text" 10 | } 11 | ], 12 | "parameters": { 13 | "Right": 1 14 | }, 15 | "nullable": [false] 16 | }, 17 | "hash": "e05620f420f8c1022971eeb66a803323a8cf258cbebb2834e3f7cf8f812fa646" 18 | } 19 | -------------------------------------------------------------------------------- /src-gui/src/renderer/index.tsx: -------------------------------------------------------------------------------- 1 | import { createRoot } from "react-dom/client"; 2 | import { Provider } from "react-redux"; 3 | import { PersistGate } from "redux-persist/integration/react"; 4 | import App from "./components/App"; 5 | import { persistor, store } from "./store/storeRenderer"; 6 | 7 | const container = document.getElementById("root"); 8 | const root = createRoot(container!); 9 | 10 | root.render( 11 | 12 | 13 | 14 | 15 | , 16 | ); 17 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | target/ 2 | target-check/ 3 | 4 | .vscode 5 | .claude/settings.local.json 6 | .DS_Store 7 | 8 | build/ 9 | 10 | monero-rpc-pool/temp_db.sqlite 11 | monero-rpc-pool/temp.db 12 | 13 | # Shared temporary database for SQLx cache regeneration 14 | tempdb.sqlite 15 | 16 | # auto-generated files by swap-orchestrator 17 | swap-orchestrator/docker-compose.yml 18 | swap-orchestrator/config.toml 19 | 20 | # release build generator scripts 21 | release-build.sh 22 | cn_macos 23 | libp2p-rendezvous-node/rendezvous-data 24 | rust-electrum-client/ 25 | rust-libp2p/ 26 | bdk/ 27 | -------------------------------------------------------------------------------- /.sqlx/query-d78acba5eb8563826dd190e0886aa665aae3c6f1e312ee444e65df1c95afe8b2.json: -------------------------------------------------------------------------------- 1 | { 2 | "db_name": "SQLite", 3 | "query": "\n SELECT DISTINCT address\n FROM peer_addresses\n WHERE peer_id = ?\n ", 4 | "describe": { 5 | "columns": [ 6 | { 7 | "name": "address", 8 | "ordinal": 0, 9 | "type_info": "Text" 10 | } 11 | ], 12 | "parameters": { 13 | "Right": 1 14 | }, 15 | "nullable": [false] 16 | }, 17 | "hash": "d78acba5eb8563826dd190e0886aa665aae3c6f1e312ee444e65df1c95afe8b2" 18 | } 19 | -------------------------------------------------------------------------------- /src-gui/src/store/config.ts: -------------------------------------------------------------------------------- 1 | import { CliMatches, getMatches } from "@tauri-apps/plugin-cli"; 2 | import { Network } from "./types"; 3 | 4 | let matches: CliMatches; 5 | try { 6 | matches = await getMatches(); 7 | } catch { 8 | matches = { 9 | args: {}, 10 | subcommand: null, 11 | }; 12 | } 13 | 14 | export function getNetwork(): Network { 15 | if (isTestnet()) { 16 | return Network.Testnet; 17 | } else { 18 | return Network.Mainnet; 19 | } 20 | } 21 | 22 | export function isTestnet() { 23 | return matches.args.testnet?.value === true; 24 | } 25 | -------------------------------------------------------------------------------- /.sqlx/query-9047f0683f1cf956e9b367b4e85d61fe0ca4b4f7a6ae5986025601b2000565d9.json: -------------------------------------------------------------------------------- 1 | { 2 | "db_name": "SQLite", 3 | "query": "\n INSERT INTO health_checks (node_id, timestamp, was_successful, latency_ms)\n SELECT id, datetime('now'), ?, ?\n FROM monero_nodes \n WHERE scheme = ? AND host = ? AND port = ?\n ", 4 | "describe": { 5 | "columns": [], 6 | "parameters": { 7 | "Right": 5 8 | }, 9 | "nullable": [] 10 | }, 11 | "hash": "9047f0683f1cf956e9b367b4e85d61fe0ca4b4f7a6ae5986025601b2000565d9" 12 | } 13 | -------------------------------------------------------------------------------- /.sqlx/query-e9d422daf774d099fcbde6c4cda35821da948bd86cc57798b4d8375baf0b51ae.json: -------------------------------------------------------------------------------- 1 | { 2 | "db_name": "SQLite", 3 | "query": "\n SELECT proof\n FROM buffered_transfer_proofs\n WHERE swap_id = ?\n ", 4 | "describe": { 5 | "columns": [ 6 | { 7 | "name": "proof", 8 | "ordinal": 0, 9 | "type_info": "Text" 10 | } 11 | ], 12 | "parameters": { 13 | "Right": 1 14 | }, 15 | "nullable": [false] 16 | }, 17 | "hash": "e9d422daf774d099fcbde6c4cda35821da948bd86cc57798b4d8375baf0b51ae" 18 | } 19 | -------------------------------------------------------------------------------- /swap-controller/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "swap-controller" 3 | version = "3.5.2" 4 | edition = "2021" 5 | 6 | [[bin]] 7 | name = "asb-controller" 8 | path = "src/main.rs" 9 | 10 | [dependencies] 11 | anyhow = { workspace = true } 12 | clap = { version = "4", features = ["derive"] } 13 | jsonrpsee = { workspace = true, features = ["client-core", "http-client"] } 14 | monero = { workspace = true } 15 | rustyline = "17.0.0" 16 | shell-words = "1.1" 17 | swap-controller-api = { path = "../swap-controller-api" } 18 | tokio = { workspace = true } 19 | 20 | [lints] 21 | workspace = true 22 | -------------------------------------------------------------------------------- /.sqlx/query-60462ce4f45f174eb4603a2d94e67cf98eb7d6176515e6a28c4e8ce9fda6ef15.json: -------------------------------------------------------------------------------- 1 | { 2 | "db_name": "SQLite", 3 | "query": "\n SELECT 1 as found\n FROM swap_states\n WHERE swap_id = ?\n LIMIT 1\n ", 4 | "describe": { 5 | "columns": [ 6 | { 7 | "name": "found", 8 | "ordinal": 0, 9 | "type_info": "Integer" 10 | } 11 | ], 12 | "parameters": { 13 | "Right": 1 14 | }, 15 | "nullable": [false] 16 | }, 17 | "hash": "60462ce4f45f174eb4603a2d94e67cf98eb7d6176515e6a28c4e8ce9fda6ef15" 18 | } 19 | -------------------------------------------------------------------------------- /docs/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "unstoppableswap-docs", 3 | "version": "1.0.0", 4 | "description": "Documentation for the eigenwallet GUI", 5 | "main": "index.js", 6 | "license": "MIT", 7 | "scripts": { 8 | "dev": "next", 9 | "build": "next build", 10 | "start": "next start" 11 | }, 12 | "dependencies": { 13 | "next": "^15.0.3", 14 | "nextra": "^2.13.4", 15 | "nextra-theme-docs": "^2.13.4", 16 | "react": "^18.3.1", 17 | "react-dom": "^18.3.1" 18 | }, 19 | "devDependencies": { 20 | "@types/node": "20.14.5", 21 | "typescript": "5.4.5" 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /monero-harness/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "monero-harness" 3 | version = "0.1.0" 4 | authors = ["CoBloX Team "] 5 | edition = "2021" 6 | publish = false 7 | 8 | [dependencies] 9 | anyhow = { workspace = true } 10 | monero = { workspace = true } 11 | monero-rpc = { path = "../monero-rpc" } 12 | monero-sys = { path = "../monero-sys" } 13 | rand = { workspace = true } 14 | reqwest = { workspace = true } 15 | testcontainers = "0.15" 16 | tokio = { workspace = true, features = ["rt-multi-thread", "time", "macros"] } 17 | tracing = { workspace = true } 18 | tracing-subscriber = { workspace = true } 19 | -------------------------------------------------------------------------------- /.sqlx/query-0d465a17ebbb5761421def759c73cad023c30705d5b41a1399ef79d8d2571d7c.json: -------------------------------------------------------------------------------- 1 | { 2 | "db_name": "SQLite", 3 | "query": "\n SELECT min(entered_at) as start_date\n FROM swap_states\n WHERE swap_id = ?\n ", 4 | "describe": { 5 | "columns": [ 6 | { 7 | "name": "start_date", 8 | "ordinal": 0, 9 | "type_info": "Text" 10 | } 11 | ], 12 | "parameters": { 13 | "Right": 1 14 | }, 15 | "nullable": [true] 16 | }, 17 | "hash": "0d465a17ebbb5761421def759c73cad023c30705d5b41a1399ef79d8d2571d7c" 18 | } 19 | -------------------------------------------------------------------------------- /.sqlx/query-88f761a4f7a0429cad1df0b1bebb1c0a27b2a45656549b23076d7542cfa21ecf.json: -------------------------------------------------------------------------------- 1 | { 2 | "db_name": "SQLite", 3 | "query": "\n SELECT state\n FROM swap_states\n WHERE swap_id = ?\n ORDER BY id desc\n LIMIT 1;\n\n ", 4 | "describe": { 5 | "columns": [ 6 | { 7 | "name": "state", 8 | "ordinal": 0, 9 | "type_info": "Text" 10 | } 11 | ], 12 | "parameters": { 13 | "Right": 1 14 | }, 15 | "nullable": [false] 16 | }, 17 | "hash": "88f761a4f7a0429cad1df0b1bebb1c0a27b2a45656549b23076d7542cfa21ecf" 18 | } 19 | -------------------------------------------------------------------------------- /src-gui/src/renderer/components/pages/feedback/FeedbackPage.tsx: -------------------------------------------------------------------------------- 1 | import { Box } from "@mui/material"; 2 | import FeedbackInfoBox from "../help/FeedbackInfoBox"; 3 | import ConversationsBox from "../help/ConversationsBox"; 4 | import ContactInfoBox from "../help/ContactInfoBox"; 5 | 6 | export default function FeedbackPage() { 7 | return ( 8 | 16 | 17 | 18 | 19 | 20 | ); 21 | } 22 | -------------------------------------------------------------------------------- /.sqlx/query-6130b6cdd184181f890964eb460741f5cf23b5237fb676faed009106627a4ca6.json: -------------------------------------------------------------------------------- 1 | { 2 | "db_name": "SQLite", 3 | "query": "SELECT peer_id, address FROM peer_addresses", 4 | "describe": { 5 | "columns": [ 6 | { 7 | "name": "peer_id", 8 | "ordinal": 0, 9 | "type_info": "Text" 10 | }, 11 | { 12 | "name": "address", 13 | "ordinal": 1, 14 | "type_info": "Text" 15 | } 16 | ], 17 | "parameters": { 18 | "Right": 0 19 | }, 20 | "nullable": [false, false] 21 | }, 22 | "hash": "6130b6cdd184181f890964eb460741f5cf23b5237fb676faed009106627a4ca6" 23 | } 24 | -------------------------------------------------------------------------------- /.dockerignore: -------------------------------------------------------------------------------- 1 | # Rust build artifacts 2 | target/ 3 | target-check/ 4 | 5 | Dockerfile 6 | 7 | # IDE files 8 | .vscode/ 9 | .DS_Store 10 | 11 | # Cache directories 12 | .cargo/registry/ 13 | .cargo/git/ 14 | 15 | # Documentation build 16 | docs/_build/ 17 | 18 | # Node modules if any 19 | node_modules/ 20 | 21 | # Development scripts 22 | dev-scripts/ 23 | dev-docs/ 24 | 25 | # Tauri development files 26 | src-tauri/target/ 27 | 28 | # GUI development files 29 | src-gui/node_modules/ 30 | src-gui/dist/ 31 | src-gui/.next/ 32 | 33 | # Log files 34 | *.log 35 | 36 | # Temporary files 37 | *.tmp 38 | *.temp 39 | 40 | # OS files 41 | Thumbs.db 42 | -------------------------------------------------------------------------------- /swap-orchestrator/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "swap-orchestrator" 3 | version = "0.1.0" 4 | edition = "2024" 5 | 6 | [[bin]] 7 | name = "orchestrator" 8 | path = "src/main.rs" 9 | 10 | [dependencies] 11 | anyhow = { workspace = true } 12 | bitcoin = { workspace = true } 13 | chrono = "0.4.41" 14 | compose_spec = "0.3.0" 15 | dialoguer = { workspace = true } 16 | monero = { workspace = true } 17 | serde_yaml = "0.9.34" 18 | swap-env = { path = "../swap-env" } 19 | toml = { workspace = true } 20 | url = { workspace = true } 21 | 22 | [build-dependencies] 23 | anyhow = { workspace = true } 24 | vergen = { workspace = true } 25 | 26 | [lints] 27 | workspace = true 28 | -------------------------------------------------------------------------------- /swap/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![warn( 2 | unused_extern_crates, 3 | rust_2018_idioms, 4 | clippy::cast_possible_truncation, 5 | clippy::cast_sign_loss, 6 | clippy::fallible_impl_from, 7 | clippy::cast_precision_loss, 8 | clippy::cast_possible_wrap, 9 | clippy::dbg_macro 10 | )] 11 | #![cfg_attr(not(test), warn(clippy::unwrap_used))] 12 | #![forbid(unsafe_code)] 13 | #![allow( 14 | non_snake_case, 15 | missing_debug_implementations, 16 | missing_copy_implementations 17 | )] 18 | 19 | pub mod asb; 20 | pub mod cli; 21 | pub mod common; 22 | pub mod database; 23 | pub mod monero; 24 | pub mod network; 25 | pub mod protocol; 26 | pub mod seed; 27 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: "" 5 | labels: "" 6 | assignees: "" 7 | --- 8 | 9 | **Describe the bug** 10 | A clear and concise description of what the bug is. 11 | 12 | **Lost/trapped Funds** 13 | Yes or No 14 | 15 | **Debug logs** 16 | Please post your debug logs. You find them in: 17 | Linux: /home//.local/share/xmr-btc-swap/logs 18 | OSX: /Users//Library/ApplicationSupport/xmr-btc-swap/logs 19 | 20 | **Platform (please complete the following information):** 21 | 22 | - CLI or ASB [eg. CLI] 23 | - Software Version [e.g. 0.8.3] 24 | - Operating System: [e.g. Ubuntu] 25 | -------------------------------------------------------------------------------- /swap-feed/src/traits.rs: -------------------------------------------------------------------------------- 1 | use crate::rate::Rate; 2 | 3 | pub trait LatestRate { 4 | type Error: std::error::Error + Send + Sync + 'static; 5 | 6 | fn latest_rate(&mut self) -> Result; 7 | } 8 | 9 | // Future: Allow for different price feed sources 10 | pub trait PriceFeed: Sized { 11 | type Error: std::error::Error + Send + Sync + 'static; 12 | type Update; 13 | 14 | fn connect( 15 | url: url::Url, 16 | ) -> impl std::future::Future> + Send; 17 | fn next_update( 18 | &mut self, 19 | ) -> impl std::future::Future> + Send; 20 | } 21 | -------------------------------------------------------------------------------- /src-gui/src/renderer/components/navigation/NavigationFooter.tsx: -------------------------------------------------------------------------------- 1 | import { Box, Tooltip } from "@mui/material"; 2 | import { BackgroundProgressAlerts } from "../alert/DaemonStatusAlert"; 3 | import UnfinishedSwapsAlert from "../alert/UnfinishedSwapsAlert"; 4 | import ContactInfoBox from "../other/ContactInfoBox"; 5 | 6 | export default function NavigationFooter() { 7 | return ( 8 | 16 | 17 | 18 | 19 | 20 | ); 21 | } 22 | -------------------------------------------------------------------------------- /swap/migrations/20250122155820_add_unique_constraint_peer_addresses.sql: -------------------------------------------------------------------------------- 1 | -- SQLite doesn't support adding constraints via ALTER TABLE 2 | -- We need to recreate the table with the constraint 3 | CREATE TABLE peer_addresses_new ( 4 | peer_id TEXT NOT NULL, 5 | address TEXT NOT NULL, 6 | UNIQUE(peer_id, address) 7 | ); 8 | 9 | -- Copy existing data, ensuring only unique combinations are inserted 10 | INSERT INTO peer_addresses_new 11 | SELECT DISTINCT peer_id, address 12 | FROM peer_addresses; 13 | 14 | -- Drop the old table 15 | DROP TABLE peer_addresses; 16 | 17 | -- Rename the new table to the original name 18 | ALTER TABLE peer_addresses_new RENAME TO peer_addresses; -------------------------------------------------------------------------------- /swap-core/src/monero/ext.rs: -------------------------------------------------------------------------------- 1 | use crate::bitcoin::Scalar; 2 | use ecdsa_fun::fun::marker::{NonZero, Secret}; 3 | 4 | pub trait ScalarExt { 5 | fn to_secpfun_scalar(&self) -> ecdsa_fun::fun::Scalar; 6 | } 7 | 8 | impl ScalarExt for curve25519_dalek::scalar::Scalar { 9 | fn to_secpfun_scalar(&self) -> Scalar { 10 | let mut little_endian_bytes = self.to_bytes(); 11 | 12 | little_endian_bytes.reverse(); 13 | let big_endian_bytes = little_endian_bytes; 14 | 15 | ecdsa_fun::fun::Scalar::from_bytes(big_endian_bytes) 16 | .expect("valid scalar") 17 | .non_zero() 18 | .expect("non-zero scalar") 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /flatpak/org.eigenwallet.app.appdata.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | org.eigenwallet.app 4 | org.eigenwallet.app 5 | eigenwallet GUI 6 | GUI for XMR<>BTC Atomic Swaps written in Rust 7 | GUI for XMR<>BTC Atomic Swaps written in Rust 8 | CC0-1.0 9 | unstoppableswap-gui-rs 10 | 11 | Utility 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /swap/src/asb.rs: -------------------------------------------------------------------------------- 1 | mod event_loop; 2 | mod network; 3 | mod recovery; 4 | pub mod rpc; 5 | 6 | pub use crate::network::rendezvous::register; 7 | pub use event_loop::{EventLoop, EventLoopHandle}; 8 | pub use network::behaviour::Behaviour; 9 | pub use network::transport; 10 | pub use recovery::cancel::cancel; 11 | pub use recovery::punish::punish; 12 | pub use recovery::redeem::{redeem, Finality}; 13 | pub use recovery::refund::refund; 14 | pub use recovery::safely_abort::safely_abort; 15 | pub use recovery::{cancel, refund}; 16 | pub use swap_feed::{ExchangeRate, FixedRate, LatestRate, Rate}; 17 | pub use swap_p2p::out_event::alice::OutEvent; 18 | 19 | #[cfg(test)] 20 | pub use crate::network::rendezvous; 21 | -------------------------------------------------------------------------------- /utils/gpg_keys/einliterflasche.asc: -------------------------------------------------------------------------------- 1 | -----BEGIN PGP PUBLIC KEY BLOCK----- 2 | 3 | mDMEaQtSYRYJKwYBBAHaRw8BAQdAwb3Kby98GpsM6wt7m2Wxx/EGrs/FOuS2++48 4 | aHlqXMy0D2VpbmxpdGVyZmxhc2NoZYiTBBMWCgA7FiEEvEGkAG7bUe3mONS0AKvI 5 | CIZr8m8FAmkLUmECGwMFCwkIBwICIgIGFQoJCAsCBBYCAwECHgcCF4AACgkQAKvI 6 | CIZr8m9JWgD8CZZzeP1S4pktWMPjxVI2ZA3bWMJ5PwaldKQWwJMGGOIA/A6v+Mmn 7 | h+Uv4dR8mhrP8Y2+4ne0zpQx8zpz0dJFK8QJuDgEaQtSYRIKKwYBBAGXVQEFAQEH 8 | QH7Fe09RQuM194oEiMLdcKV/Zpo0vcrO1/e4O3uvh5pQAwEIB4h4BBgWCgAgFiEE 9 | vEGkAG7bUe3mONS0AKvICIZr8m8FAmkLUmECGwwACgkQAKvICIZr8m9h/wEAuKf6 10 | yvoYxzBufeZBExusC+BBpMSgN+BRMxb0mvfZitkBAOFzgzrVi3EyxFBUITniPI34 11 | hv8vURdB6gIhHbpcYA0D 12 | =aK60 13 | -----END PGP PUBLIC KEY BLOCK----- 14 | 15 | -------------------------------------------------------------------------------- /swap/tests/ensure_same_swap_id.rs: -------------------------------------------------------------------------------- 1 | pub mod harness; 2 | 3 | use harness::SlowCancelConfig; 4 | use swap::protocol::bob; 5 | 6 | #[tokio::test] 7 | async fn ensure_same_swap_id_for_alice_and_bob() { 8 | harness::setup_test(SlowCancelConfig, None, |mut ctx| async move { 9 | let (bob_swap, _) = ctx.bob_swap().await; 10 | let bob_swap_id = bob_swap.id; 11 | tokio::spawn(bob::run(bob_swap)); 12 | 13 | // once Bob's swap is spawned we can retrieve Alice's swap and assert on the 14 | // swap ID 15 | let alice_swap = ctx.alice_next_swap().await; 16 | assert_eq!(alice_swap.swap_id, bob_swap_id); 17 | 18 | Ok(()) 19 | }) 20 | .await; 21 | } 22 | -------------------------------------------------------------------------------- /swap-feed/src/bin/kraken_ticker.rs: -------------------------------------------------------------------------------- 1 | use anyhow::{Context, Result}; 2 | use url::Url; 3 | 4 | #[tokio::main] 5 | async fn main() -> Result<()> { 6 | tracing::subscriber::set_global_default( 7 | tracing_subscriber::fmt().with_env_filter("debug").finish(), 8 | )?; 9 | 10 | let price_ticker_ws_url_kraken = Url::parse("wss://ws.kraken.com")?; 11 | let mut ticker = swap_feed::kraken::connect(price_ticker_ws_url_kraken) 12 | .context("Failed to connect to kraken")?; 13 | 14 | loop { 15 | match ticker.wait_for_next_update().await? { 16 | Ok(update) => println!("Price update: {}", update.1.ask), 17 | Err(e) => println!("Error: {e:#?}"), 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /dev-docs/asb/diagrams/cli-asb-overview.puml: -------------------------------------------------------------------------------- 1 | @startuml 2 | 3 | package "Service Provider 1" { 4 | 5 | rectangle CLI as cli01 6 | rectangle CLI as cli02 7 | rectangle CLI as cli03 8 | 9 | 10 | rectangle ASB as asb01 11 | note right of asb01 12 | Service provider 13 | advertising to 14 | multiple users. 15 | end note 16 | 17 | cli01 -> asb01 18 | cli02 --> asb01 19 | asb01 <-- cli03 20 | 21 | } 22 | 23 | package "Service Provider 2" { 24 | rectangle CLI as cli04 25 | rectangle ASB as asb02 26 | note right of asb02 27 | Service provider 28 | advertising to 29 | one single users. 30 | end note 31 | 32 | cli04 -> asb02 33 | } 34 | @enduml 35 | -------------------------------------------------------------------------------- /utils/gpg_keys/binarybaron.asc: -------------------------------------------------------------------------------- 1 | -----BEGIN PGP PUBLIC KEY BLOCK----- 2 | 3 | mDMEZp+avRYJKwYBBAHaRw8BAQdAD99LhR+cHlXDsYPjRJr0Ag7BXsjGZKfdWCtx 4 | CPA0fwG0LWJpbmFyeWJhcm9uIDxiaW5hcnliYXJvbkB1bnN0b3BwYWJsZXN3YXAu 5 | bmV0PoiTBBMWCgA7FiEENahE1/S1W8ROGA/xmbddPhR2om4FAmafmr0CGwMFCwkI 6 | BwICIgIGFQoJCAsCBBYCAwECHgcCF4AACgkQmbddPhR2om5IQQD/d/EmD/yKMKRl 7 | Hw9RSP4bhcALmrZPri8sYkPteus8OhIA+wWTaIxXZJgydpXv95yECTfUXZ0UhuJq 8 | 6UH0FQL8mosJuDgEZp+avRIKKwYBBAGXVQEFAQEHQOd1tQ46YVKxyUKluPAvGJLY 9 | LQ+3UWFWQJavLblkrYE2AwEIB4h4BBgWCgAgFiEENahE1/S1W8ROGA/xmbddPhR2 10 | om4FAmafmr0CGwwACgkQmbddPhR2om6mmQEAn7vufrOp/HSYgn9l5tmJxMkyxJ3W 11 | 2WNo9u+JdnSik1IBAMsNcc4zm5ewfFr/qAnTHzHRId7dWR2+hs1oH7JOlf8L 12 | =Rxij 13 | -----END PGP PUBLIC KEY BLOCK----- 14 | -------------------------------------------------------------------------------- /src-gui/src/renderer/components/modal/introduction/slides/Slide03_PrepareSwap.tsx: -------------------------------------------------------------------------------- 1 | import { Typography } from "@mui/material"; 2 | import SlideTemplate from "./SlideTemplate"; 3 | import imagePath from "assets/mockConfigureSwap.svg"; 4 | import { IntroSlideProps } from "./SlideTypes"; 5 | 6 | export default function Slide02_ChooseAMaker(props: IntroSlideProps) { 7 | return ( 8 | 14 | 15 | To initiate a swap, provide a Monero address and optionally a Bitcoin 16 | refund address. 17 | 18 | 19 | ); 20 | } 21 | -------------------------------------------------------------------------------- /src-gui/src/store/features/poolSlice.ts: -------------------------------------------------------------------------------- 1 | import { createSlice, PayloadAction } from "@reduxjs/toolkit"; 2 | import { PoolStatus } from "models/tauriModel"; 3 | 4 | interface PoolSlice { 5 | status: PoolStatus | null; 6 | isLoading: boolean; 7 | } 8 | 9 | const initialState: PoolSlice = { 10 | status: null, 11 | isLoading: true, 12 | }; 13 | 14 | export const poolSlice = createSlice({ 15 | name: "pool", 16 | initialState, 17 | reducers: { 18 | poolStatusReceived(slice, action: PayloadAction) { 19 | slice.status = action.payload; 20 | slice.isLoading = false; 21 | }, 22 | }, 23 | }); 24 | 25 | export const { poolStatusReceived } = poolSlice.actions; 26 | 27 | export default poolSlice.reducer; 28 | -------------------------------------------------------------------------------- /docs/theme.config.jsx: -------------------------------------------------------------------------------- 1 | import Logo from "./components/Logo"; 2 | 3 | export default { 4 | logo: , 5 | project: { 6 | link: "https://github.com/eigenwallet/core", 7 | }, 8 | head: ( 9 | <> 10 | eigenwallet Docs 11 | 12 | 13 | 14 | 15 | 16 | 17 | > 18 | ), 19 | primaryHue: 14.3, 20 | primarySaturation: 90.68, 21 | }; 22 | -------------------------------------------------------------------------------- /src-gui/src/renderer/components/modal/introduction/slides/Slide02_ChooseAMaker.tsx: -------------------------------------------------------------------------------- 1 | import { Typography } from "@mui/material"; 2 | import SlideTemplate from "./SlideTemplate"; 3 | import imagePath from "assets/mockMakerSelection.svg"; 4 | import { IntroSlideProps } from "./SlideTypes"; 5 | 6 | export default function Slide02_ChooseAMaker(props: IntroSlideProps) { 7 | return ( 8 | 14 | 15 | To start a swap, choose a maker. Each maker offers different exchange 16 | rates and limits. 17 | 18 | 19 | ); 20 | } 21 | -------------------------------------------------------------------------------- /src-gui/src/renderer/components/pages/swap/swap/components/MoneroTransactionInfoBox.tsx: -------------------------------------------------------------------------------- 1 | import MoneroIcon from "renderer/components/icons/MoneroIcon"; 2 | import { isTestnet } from "store/config"; 3 | import { getMoneroTxExplorerUrl } from "utils/conversionUtils"; 4 | import TransactionInfoBox, { 5 | TransactionInfoBoxProps, 6 | } from "./TransactionInfoBox"; 7 | 8 | export default function MoneroTransactionInfoBox({ 9 | txId, 10 | ...props 11 | }: Omit) { 12 | return ( 13 | getMoneroTxExplorerUrl(txid, isTestnet())} 16 | icon={} 17 | {...props} 18 | /> 19 | ); 20 | } 21 | -------------------------------------------------------------------------------- /swap-feed/src/bin/bitfinex_ticker.rs: -------------------------------------------------------------------------------- 1 | use anyhow::{Context, Result}; 2 | use url::Url; 3 | 4 | #[tokio::main] 5 | async fn main() -> Result<()> { 6 | tracing::subscriber::set_global_default( 7 | tracing_subscriber::fmt().with_env_filter("debug").finish(), 8 | )?; 9 | 10 | let price_ticker_ws_url_bitfinex = Url::parse("wss://api-pub.bitfinex.com/ws/2")?; 11 | let mut ticker = swap_feed::bitfinex::connect(price_ticker_ws_url_bitfinex) 12 | .context("Failed to connect to bitfinex")?; 13 | 14 | loop { 15 | match ticker.wait_for_next_update().await? { 16 | Ok(update) => println!("Price update: {}", update.1.ask), 17 | Err(e) => println!("Error: {e:#}"), 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src-gui/src/renderer/components/other/TruncatedText.tsx: -------------------------------------------------------------------------------- 1 | export default function TruncatedText({ 2 | children, 3 | limit = 6, 4 | ellipsis = "...", 5 | truncateMiddle = false, 6 | }: { 7 | children: string; 8 | limit?: number; 9 | ellipsis?: string; 10 | truncateMiddle?: boolean; 11 | }) { 12 | const finalChildren = children ?? ""; 13 | 14 | const truncatedText = 15 | finalChildren.length > limit 16 | ? truncateMiddle 17 | ? finalChildren.slice(0, Math.floor(limit / 2)) + 18 | ellipsis + 19 | finalChildren.slice(finalChildren.length - Math.floor(limit / 2)) 20 | : finalChildren.slice(0, limit) + ellipsis 21 | : finalChildren; 22 | 23 | return {truncatedText}; 24 | } 25 | -------------------------------------------------------------------------------- /src-tauri/gen/apple/Podfile: -------------------------------------------------------------------------------- 1 | # Uncomment the next line to define a global platform for your project 2 | 3 | target 'unstoppableswap-gui-rs_iOS' do 4 | platform :ios, '13.0' 5 | # Pods for unstoppableswap-gui-rs_iOS 6 | end 7 | 8 | target 'unstoppableswap-gui-rs_macOS' do 9 | platform :osx, '11.0' 10 | # Pods for unstoppableswap-gui-rs_macOS 11 | end 12 | 13 | # Delete the deployment target for iOS and macOS, causing it to be inherited from the Podfile 14 | post_install do |installer| 15 | installer.pods_project.targets.each do |target| 16 | target.build_configurations.each do |config| 17 | config.build_settings.delete 'IPHONEOS_DEPLOYMENT_TARGET' 18 | config.build_settings.delete 'MACOSX_DEPLOYMENT_TARGET' 19 | end 20 | end 21 | end 22 | -------------------------------------------------------------------------------- /src-gui/src/renderer/components/pages/swap/swap/components/BitcoinTransactionInfoBox.tsx: -------------------------------------------------------------------------------- 1 | import BitcoinIcon from "renderer/components/icons/BitcoinIcon"; 2 | import { isTestnet } from "store/config"; 3 | import { getBitcoinTxExplorerUrl } from "utils/conversionUtils"; 4 | import TransactionInfoBox, { 5 | TransactionInfoBoxProps, 6 | } from "./TransactionInfoBox"; 7 | 8 | export default function BitcoinTransactionInfoBox({ 9 | txId, 10 | ...props 11 | }: Omit) { 12 | return ( 13 | getBitcoinTxExplorerUrl(txId, isTestnet())} 16 | icon={} 17 | {...props} 18 | /> 19 | ); 20 | } 21 | -------------------------------------------------------------------------------- /dev-scripts/homebrew/eigenwallet.rb.template: -------------------------------------------------------------------------------- 1 | cask "eigenwallet" do 2 | version "VERSION_PLACEHOLDER" 3 | 4 | on_arm do 5 | sha256 "AARCH64_SHA256_PLACEHOLDER" 6 | url "https://github.com/eigenwallet/core/releases/download/#{version}/eigenwallet_#{version}_aarch64.dmg" 7 | end 8 | 9 | on_intel do 10 | sha256 "X64_SHA256_PLACEHOLDER" 11 | url "https://github.com/eigenwallet/core/releases/download/#{version}/eigenwallet_#{version}_x64.dmg" 12 | end 13 | 14 | name "Eigenwallet" 15 | desc "GUI for XMR<>BTC Atomic Swaps" 16 | homepage "https://github.com/eigenwallet/core" 17 | 18 | livecheck do 19 | url :url 20 | strategy :github_latest 21 | end 22 | 23 | auto_updates true 24 | 25 | app "eigenwallet.app" 26 | end 27 | -------------------------------------------------------------------------------- /.sqlx/query-7e58428584d28a238ab37a83662b88afcef6fc5246f11c85a35869f79da61c34.json: -------------------------------------------------------------------------------- 1 | { 2 | "db_name": "SQLite", 3 | "query": "\n SELECT wallet_path, last_opened_at\n FROM recent_wallets \n ORDER BY last_opened_at DESC\n LIMIT ?\n ", 4 | "describe": { 5 | "columns": [ 6 | { 7 | "name": "wallet_path", 8 | "ordinal": 0, 9 | "type_info": "Text" 10 | }, 11 | { 12 | "name": "last_opened_at", 13 | "ordinal": 1, 14 | "type_info": "Text" 15 | } 16 | ], 17 | "parameters": { 18 | "Right": 1 19 | }, 20 | "nullable": [false, false] 21 | }, 22 | "hash": "7e58428584d28a238ab37a83662b88afcef6fc5246f11c85a35869f79da61c34" 23 | } 24 | -------------------------------------------------------------------------------- /swap-feed/src/lib.rs: -------------------------------------------------------------------------------- 1 | pub mod bitfinex; 2 | pub mod kraken; 3 | pub mod kucoin; 4 | pub mod rate; 5 | pub mod traits; 6 | 7 | // Re-exports for convenience 8 | pub use kraken::{connect, Error as KrakenError, PriceUpdates}; 9 | pub use rate::{ExchangeRate, FixedRate, Rate}; 10 | pub use traits::LatestRate; 11 | 12 | mod ticker; 13 | 14 | // Core functions 15 | pub fn connect_kraken(url: url::Url) -> anyhow::Result { 16 | kraken::connect(url) 17 | } 18 | 19 | pub fn connect_bitfinex(url: url::Url) -> anyhow::Result { 20 | bitfinex::connect(url) 21 | } 22 | 23 | pub fn connect_kucoin( 24 | url: url::Url, 25 | client: reqwest::Client, 26 | ) -> anyhow::Result { 27 | kucoin::connect(url, client) 28 | } 29 | -------------------------------------------------------------------------------- /.sqlx/query-5cc61dd0315571bc198401a354cd9431ee68360941f341386cbacf44ea598de8.json: -------------------------------------------------------------------------------- 1 | { 2 | "db_name": "SQLite", 3 | "query": "\n SELECT swap_id, state\n FROM (\n SELECT max(id), swap_id, state\n FROM swap_states\n GROUP BY swap_id\n )\n ", 4 | "describe": { 5 | "columns": [ 6 | { 7 | "name": "swap_id", 8 | "ordinal": 0, 9 | "type_info": "Text" 10 | }, 11 | { 12 | "name": "state", 13 | "ordinal": 1, 14 | "type_info": "Text" 15 | } 16 | ], 17 | "parameters": { 18 | "Right": 0 19 | }, 20 | "nullable": [true, true] 21 | }, 22 | "hash": "5cc61dd0315571bc198401a354cd9431ee68360941f341386cbacf44ea598de8" 23 | } 24 | -------------------------------------------------------------------------------- /swap-env/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "swap-env" 3 | version = "0.1.0" 4 | edition = "2024" 5 | 6 | [dependencies] 7 | anyhow = { workspace = true } 8 | bitcoin = { workspace = true } 9 | config = { version = "0.14", default-features = false, features = ["toml"] } 10 | console = "0.16" 11 | dialoguer = { workspace = true } 12 | libp2p = { workspace = true, features = ["serde"] } 13 | monero = { workspace = true } 14 | rust_decimal = { workspace = true } 15 | serde = { workspace = true } 16 | swap-fs = { path = "../swap-fs" } 17 | swap-serde = { path = "../swap-serde" } 18 | terminal_size = "0.4" 19 | thiserror = { workspace = true } 20 | time = "0.3" 21 | toml = { workspace = true } 22 | tracing = { workspace = true } 23 | url = { workspace = true } 24 | 25 | [lints] 26 | workspace = true 27 | -------------------------------------------------------------------------------- /docs/pages/donate.mdx: -------------------------------------------------------------------------------- 1 | # Donate 2 | 3 | We rely on generous donors like you to keep development moving forward. To bring Atomic Swaps to life, we need resources. If you have the possibility, please consider making a donation to the project. All funds will be used to support contributors and critical infrastructure. 4 | 5 | If you interested in a partnership or want to support the project in a way that requires coordination with the contributors, contact [`@binarybaron:matrix.org`](https://matrix.to/#/@binarybaron:matrix.org) on Matrix. 6 | 7 | ```raw filename="Monero" copy 8 | 49LEH26DJGuCyr8xzRAzWPUryzp7bpccC7Hie1DiwyfJEyUKvMFAethRLybDYrFdU1eHaMkKQpUPebY4WT3cSjEvThmpjPa 9 | ``` 10 | 11 | ```raw filename="Bitcoin Donation Address" copy 12 | bc1qz6lfs0r206396a9psunmkfpqh7sdf2zh3e7tnf 13 | ``` 14 | -------------------------------------------------------------------------------- /src-gui/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ES2020", 4 | "useDefineForClassFields": true, 5 | "lib": ["ES2022", "DOM", "DOM.Iterable"], 6 | "module": "ESNext", 7 | "skipLibCheck": true, 8 | 9 | /* Bundler mode */ 10 | "moduleResolution": "bundler", 11 | "allowImportingTsExtensions": true, 12 | "resolveJsonModule": true, 13 | "isolatedModules": true, 14 | "noEmit": true, 15 | "jsx": "react-jsx", 16 | 17 | /* Linting */ 18 | "strict": true, 19 | "noUnusedLocals": false, 20 | "noUnusedParameters": false, 21 | "noFallthroughCasesInSwitch": false, 22 | 23 | /* Path Resolving */ 24 | "baseUrl": "./src" 25 | }, 26 | "include": ["src"], 27 | "references": [{ "path": "./tsconfig.node.json" }] 28 | } 29 | -------------------------------------------------------------------------------- /swap-feed/src/bin/kucoin_ticker.rs: -------------------------------------------------------------------------------- 1 | use anyhow::{Context, Result}; 2 | use url::Url; 3 | 4 | #[tokio::main] 5 | async fn main() -> Result<()> { 6 | tracing::subscriber::set_global_default( 7 | tracing_subscriber::fmt().with_env_filter("debug").finish(), 8 | )?; 9 | 10 | let price_ticker_rest_url_kucoin = Url::parse("https://api.kucoin.com/api/v1/bullet-public")?; 11 | let mut ticker = 12 | swap_feed::kucoin::connect(price_ticker_rest_url_kucoin, reqwest::Client::new()) 13 | .context("Failed to connect to kucoin")?; 14 | 15 | loop { 16 | match ticker.wait_for_next_update().await? { 17 | Ok(update) => println!("Price update: {}", update.1.ask), 18 | Err(e) => println!("Error: {e:#}"), 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /swap/migrations/20210903050345_create_swaps_table.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE if NOT EXISTS swap_states 2 | ( 3 | id INTEGER PRIMARY KEY autoincrement NOT NULL, 4 | swap_id TEXT NOT NULL, 5 | entered_at TEXT NOT NULL, 6 | state TEXT NOT NULL 7 | ); 8 | 9 | CREATE TABLE if NOT EXISTS monero_addresses 10 | ( 11 | swap_id TEXT PRIMARY KEY NOT NULL, 12 | address TEXT NOT NULL 13 | ); 14 | 15 | CREATE TABLE if NOT EXISTS peers 16 | ( 17 | swap_id TEXT PRIMARY KEY NOT NULL, 18 | peer_id TEXT NOT NULL 19 | ); 20 | 21 | CREATE TABLE if NOT EXISTS peer_addresses 22 | ( 23 | peer_id TEXT NOT NULL, 24 | address TEXT NOT NULL 25 | ); -------------------------------------------------------------------------------- /libp2p-rendezvous-node/src/tracing_util.rs: -------------------------------------------------------------------------------- 1 | use tracing::level_filters::LevelFilter; 2 | use tracing_subscriber::FmtSubscriber; 3 | 4 | pub fn init_tracing(level: LevelFilter) { 5 | if level == LevelFilter::OFF { 6 | return; 7 | } 8 | 9 | let is_terminal = atty::is(atty::Stream::Stderr); 10 | 11 | FmtSubscriber::builder() 12 | .with_env_filter(format!( 13 | "rendezvous_server={},\ 14 | swap_p2p={},\ 15 | libp2p={}, 16 | libp2p_rendezvous={},\ 17 | libp2p_swarm={},\ 18 | libp2p_tor={}", 19 | level, level, level, level, level, level 20 | )) 21 | .with_writer(std::io::stderr) 22 | .with_ansi(is_terminal) 23 | .with_target(false) 24 | .init(); 25 | } 26 | -------------------------------------------------------------------------------- /src-gui/src/renderer/components/modal/wallet/pages/BitcoinWithdrawTxInMempoolPage.tsx: -------------------------------------------------------------------------------- 1 | import { DialogContentText } from "@mui/material"; 2 | import BitcoinTransactionInfoBox from "renderer/components/pages/swap/swap/components/BitcoinTransactionInfoBox"; 3 | 4 | export default function BtcTxInMempoolPageContent({ 5 | withdrawTxId, 6 | }: { 7 | withdrawTxId: string; 8 | }) { 9 | return ( 10 | <> 11 | 12 | All funds of the internal Bitcoin wallet have been transferred to your 13 | withdraw address. 14 | 15 | 21 | > 22 | ); 23 | } 24 | -------------------------------------------------------------------------------- /src-gui/src/renderer/components/alert/SwapTxLockAlertsBox.tsx: -------------------------------------------------------------------------------- 1 | import { Box } from "@mui/material"; 2 | import { useSwapInfosSortedByDate } from "store/hooks"; 3 | import SwapStatusAlert from "./SwapStatusAlert/SwapStatusAlert"; 4 | 5 | export default function SwapTxLockAlertsBox() { 6 | // We specifically choose ALL swaps here 7 | // If a swap is in a state where an Alert is not needed (becaue no Bitcoin have been locked or because the swap has been completed) 8 | // the SwapStatusAlert component will not render an Alert 9 | const swaps = useSwapInfosSortedByDate(); 10 | 11 | return ( 12 | 13 | {swaps.map((swap) => ( 14 | 15 | ))} 16 | 17 | ); 18 | } 19 | -------------------------------------------------------------------------------- /src-gui/src/renderer/components/modal/introduction/slides/Slide01_GettingStarted.tsx: -------------------------------------------------------------------------------- 1 | import { Typography } from "@mui/material"; 2 | import SlideTemplate from "./SlideTemplate"; 3 | import imagePath from "assets/walletWithBitcoinAndMonero.png"; 4 | import { IntroSlideProps } from "./SlideTypes"; 5 | 6 | export default function Slide01_GettingStarted(props: IntroSlideProps) { 7 | return ( 8 | 9 | 10 | To start swapping, you'll need: 11 | 12 | 13 | 14 | A Bitcoin wallet with funds to swap 15 | A Monero wallet to receive your Monero 16 | 17 | 18 | 19 | ); 20 | } 21 | -------------------------------------------------------------------------------- /src-gui/src/renderer/components/pages/wallet/WalletRefreshButton.tsx: -------------------------------------------------------------------------------- 1 | import RefreshIcon from "@mui/icons-material/Refresh"; 2 | import PromiseInvokeButton from "renderer/components/PromiseInvokeButton"; 3 | import { checkBitcoinBalance } from "renderer/rpc"; 4 | import { useIsSyncingBitcoin } from "store/hooks"; 5 | import { isContextWithBitcoinWallet } from "models/tauriModelExt"; 6 | 7 | export default function WalletRefreshButton() { 8 | const isSyncing = useIsSyncingBitcoin(); 9 | 10 | return ( 11 | } 13 | isIconButton 14 | isLoadingOverride={isSyncing} 15 | onInvoke={() => checkBitcoinBalance()} 16 | displayErrorSnackbar 17 | size="small" 18 | contextRequirement={isContextWithBitcoinWallet} 19 | /> 20 | ); 21 | } 22 | -------------------------------------------------------------------------------- /swap/tests/happy_path.rs: -------------------------------------------------------------------------------- 1 | pub mod harness; 2 | 3 | use harness::SlowCancelConfig; 4 | use swap::asb::FixedRate; 5 | use swap::protocol::{alice, bob}; 6 | use tokio::join; 7 | 8 | #[tokio::test] 9 | async fn happy_path() { 10 | harness::setup_test(SlowCancelConfig, None, |mut ctx| async move { 11 | let (bob_swap, _) = ctx.bob_swap().await; 12 | let bob_swap = tokio::spawn(bob::run(bob_swap)); 13 | 14 | let alice_swap = ctx.alice_next_swap().await; 15 | let alice_swap = tokio::spawn(alice::run(alice_swap, FixedRate::default())); 16 | 17 | let (bob_state, alice_state) = join!(bob_swap, alice_swap); 18 | 19 | ctx.assert_alice_redeemed(alice_state??).await; 20 | ctx.assert_bob_redeemed(bob_state??).await; 21 | 22 | Ok(()) 23 | }) 24 | .await; 25 | } 26 | -------------------------------------------------------------------------------- /src-gui/src/renderer/components/modal/swap/pages/DebugPageSwitchBadge.tsx: -------------------------------------------------------------------------------- 1 | import { Tooltip } from "@mui/material"; 2 | import IconButton from "@mui/material/IconButton"; 3 | import DeveloperBoardIcon from "@mui/icons-material/DeveloperBoard"; 4 | 5 | export default function DebugPageSwitchBadge({ 6 | enabled, 7 | setEnabled, 8 | }: { 9 | enabled: boolean; 10 | setEnabled: (enabled: boolean) => void; 11 | }) { 12 | const handleToggle = () => { 13 | setEnabled(!enabled); 14 | }; 15 | 16 | return ( 17 | 18 | 23 | 24 | 25 | 26 | ); 27 | } 28 | -------------------------------------------------------------------------------- /.sqlx/query-dff8b986c3dde27b8121775e48a58564fa346b038866699210a63f8a33b03f0b.json: -------------------------------------------------------------------------------- 1 | { 2 | "db_name": "SQLite", 3 | "query": "\n SELECT address, percentage, label\n FROM monero_addresses\n WHERE swap_id = ?\n ", 4 | "describe": { 5 | "columns": [ 6 | { 7 | "name": "address", 8 | "ordinal": 0, 9 | "type_info": "Text" 10 | }, 11 | { 12 | "name": "percentage", 13 | "ordinal": 1, 14 | "type_info": "Float" 15 | }, 16 | { 17 | "name": "label", 18 | "ordinal": 2, 19 | "type_info": "Text" 20 | } 21 | ], 22 | "parameters": { 23 | "Right": 1 24 | }, 25 | "nullable": [true, false, false] 26 | }, 27 | "hash": "dff8b986c3dde27b8121775e48a58564fa346b038866699210a63f8a33b03f0b" 28 | } 29 | -------------------------------------------------------------------------------- /src-gui/src/renderer/components/modal/wallet/WithdrawDialogContent.tsx: -------------------------------------------------------------------------------- 1 | import { Box, DialogContent } from "@mui/material"; 2 | import { ReactNode } from "react"; 3 | import WithdrawStepper from "./WithdrawStepper"; 4 | 5 | export default function WithdrawDialogContent({ 6 | children, 7 | isPending, 8 | withdrawTxId, 9 | }: { 10 | children: ReactNode; 11 | isPending: boolean; 12 | withdrawTxId: string | null; 13 | }) { 14 | return ( 15 | 25 | {children} 26 | 27 | 28 | ); 29 | } 30 | -------------------------------------------------------------------------------- /src-gui/src/renderer/components/modal/wallet/WithdrawStepper.tsx: -------------------------------------------------------------------------------- 1 | import { Step, StepLabel, Stepper } from "@mui/material"; 2 | 3 | function getActiveStep(isPending: boolean, withdrawTxId: string | null) { 4 | if (isPending) { 5 | return 1; 6 | } 7 | if (withdrawTxId !== null) { 8 | return 2; 9 | } 10 | return 0; 11 | } 12 | 13 | export default function WithdrawStepper({ 14 | isPending, 15 | withdrawTxId, 16 | }: { 17 | isPending: boolean; 18 | withdrawTxId: string | null; 19 | }) { 20 | return ( 21 | 22 | 23 | Enter withdraw address 24 | 25 | 26 | Transfer funds to wallet 27 | 28 | 29 | ); 30 | } 31 | -------------------------------------------------------------------------------- /src-gui/src/store/features/bitcoinWalletSlice.ts: -------------------------------------------------------------------------------- 1 | import { createSlice, PayloadAction } from "@reduxjs/toolkit"; 2 | 3 | interface BitcoinWalletState { 4 | address: string | null; 5 | balance: number | null; 6 | } 7 | 8 | const initialState: BitcoinWalletState = { 9 | address: null, 10 | balance: null, 11 | }; 12 | 13 | export const bitcoinWalletSlice = createSlice({ 14 | name: "bitcoinWallet", 15 | initialState, 16 | reducers: { 17 | setBitcoinAddress(state, action: PayloadAction) { 18 | state.address = action.payload; 19 | }, 20 | setBitcoinBalance(state, action: PayloadAction) { 21 | state.balance = action.payload; 22 | }, 23 | }, 24 | }); 25 | 26 | export const { setBitcoinAddress, setBitcoinBalance } = 27 | bitcoinWalletSlice.actions; 28 | 29 | export default bitcoinWalletSlice.reducer; 30 | -------------------------------------------------------------------------------- /dev-scripts/bump-version.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -eu 3 | 4 | if [ "$#" -ne 1 ]; then 5 | echo "Usage: $0 " 6 | exit 1 7 | fi 8 | 9 | VERSION=$1 10 | TODAY=$(date +%Y-%m-%d) 11 | echo "Bumping version to $VERSION" 12 | 13 | # Using sed and assuming GNU sed syntax as this is for the github workflow. 14 | 15 | # Update version in tauri.conf.json 16 | sed -i 's/"version": "[^"]*"/"version": "'"$VERSION"'"/' src-tauri/tauri.conf.json 17 | 18 | # Update version in Cargo.toml files 19 | sed -i -E 's/^version = "[0-9]+\.[0-9]+\.[0-9]+"/version = "'"$VERSION"'"/' swap/Cargo.toml src-tauri/Cargo.toml 20 | 21 | # Update changelog 22 | sed -i "s/^## \\[Unreleased\\]/## [$VERSION] - $TODAY/" CHANGELOG.md 23 | # Add a new [Unreleased] section at the top 24 | sed -i '3i## [Unreleased]\n' CHANGELOG.md 25 | 26 | echo "Updated all files to version $VERSION." -------------------------------------------------------------------------------- /src-gui/src/renderer/components/navigation/UnfinishedSwapsCountBadge.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { Badge } from "@mui/material"; 3 | import { 4 | useIsSwapRunning, 5 | useResumeableSwapsCountExcludingPunished, 6 | } from "store/hooks"; 7 | 8 | export default function UnfinishedSwapsBadge({ 9 | children, 10 | }: { 11 | children: React.ReactNode; 12 | }) { 13 | const isSwapRunning = useIsSwapRunning(); 14 | const resumableSwapsCount = useResumeableSwapsCountExcludingPunished(); 15 | 16 | const displayedResumableSwapsCount = isSwapRunning 17 | ? resumableSwapsCount - 1 18 | : resumableSwapsCount; 19 | 20 | if (displayedResumableSwapsCount > 0) { 21 | return ( 22 | 23 | {children} 24 | 25 | ); 26 | } 27 | return children; 28 | } 29 | -------------------------------------------------------------------------------- /src-gui/src/renderer/components/pages/help/DonateInfoBox.tsx: -------------------------------------------------------------------------------- 1 | import { Link, Typography } from "@mui/material"; 2 | import MoneroIcon from "renderer/components/icons/MoneroIcon"; 3 | import DepositAddressInfoBox from "renderer/components/pages/swap/swap/components/DepositAddressInfoBox"; 4 | 5 | const XMR_DONATE_ADDRESS = 6 | "87jS4C7ngk9EHdqFFuxGFgg8AyH63dRUoULshWDybFJaP75UA89qsutG5B1L1QTc4w228nsqsv8EjhL7bz8fB3611Mh98mg"; 7 | 8 | export default function DonateInfoBox() { 9 | return ( 10 | } 14 | additionalContent={ 15 | 16 | If you want to support our effort event further, you can do so at this 17 | address. 18 | 19 | } 20 | /> 21 | ); 22 | } 23 | -------------------------------------------------------------------------------- /src-tauri/gen/android/app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # You can control the set of applied configuration files using the 3 | # proguardFiles setting in build.gradle. 4 | # 5 | # For more details, see 6 | # http://developer.android.com/guide/developing/tools/proguard.html 7 | 8 | # If your project uses WebView with JS, uncomment the following 9 | # and specify the fully qualified class name to the JavaScript interface 10 | # class: 11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 12 | # public *; 13 | #} 14 | 15 | # Uncomment this to preserve the line number information for 16 | # debugging stack traces. 17 | #-keepattributes SourceFile,LineNumberTable 18 | 19 | # If you keep the line number information, uncomment this to 20 | # hide the original source file name. 21 | #-renamesourcefileattribute SourceFile -------------------------------------------------------------------------------- /src-gui/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /monero-wallet/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "monero-wallet" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | [dependencies] 7 | # Error handling 8 | anyhow = { workspace = true } 9 | 10 | # Other stuff 11 | monero = { workspace = true } 12 | monero-sys = { path = "../monero-sys" } 13 | swap-core = { path = "../swap-core" } 14 | throttle = { path = "../throttle" } 15 | time = "0.3" 16 | uuid = { workspace = true } 17 | 18 | # Tokio 19 | tokio = { workspace = true, features = ["process", "fs", "net", "parking_lot", "rt"] } 20 | 21 | # Tracing 22 | tracing = { workspace = true } 23 | tracing-appender = "0.2" 24 | tracing-subscriber = { workspace = true } 25 | 26 | # monero-oxide 27 | monero-oxide-rpc = { git = "https://github.com/monero-oxide/monero-oxide.git", package = "monero-rpc" } 28 | monero-simple-request-rpc = { git = "https://github.com/monero-oxide/monero-oxide.git" } 29 | -------------------------------------------------------------------------------- /monero-sys/README.md: -------------------------------------------------------------------------------- 1 | # monero-sys 2 | 3 | This crate is an idiomatic wrapper around [`wallet2_api.h`](./monero/src/wallet/api/wallet2_api.h) from the official Monero codebase. 4 | The C++ library is statically linked into the crate. 5 | 6 | Since we statically link the Monero codebase, we need to build it. 7 | That requires build dependencies, for a complete and up-to-date list see the Monero [README](./monero/README.md#dependencies). 8 | Missing dependencies will currently result in obscure CMake or linker errors. 9 | If you get obscure linker CMake or linker errors, check whether you correctly installed the dependencies. 10 | 11 | Since we build the Monero codebase from source, building this crate for the first time might take a while. 12 | 13 | ## Contributing 14 | 15 | Make sure to load the Monero submodule: 16 | 17 | ```bash 18 | git submodule update --init --recursive 19 | ``` 20 | -------------------------------------------------------------------------------- /src-gui/src/renderer/components/modal/swap/pages/DebugPage.tsx: -------------------------------------------------------------------------------- 1 | import { Box, DialogContentText } from "@mui/material"; 2 | import { useActiveSwapLogs } from "store/hooks"; 3 | import CliLogsBox from "../../../other/RenderedCliLog"; 4 | 5 | export default function DebugPage() { 6 | const logs = useActiveSwapLogs(); 7 | 8 | return ( 9 | 10 | 11 | 18 | 23 | 24 | 25 | 26 | ); 27 | } 28 | -------------------------------------------------------------------------------- /src-tauri/gen/android/app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 17 | 18 | -------------------------------------------------------------------------------- /src-gui/src/renderer/components/inputs/CardSelection/CardSelectionGroup.tsx: -------------------------------------------------------------------------------- 1 | import { Box } from "@mui/material"; 2 | import CheckIcon from "@mui/icons-material/Check"; 3 | import { CardSelectionProvider } from "./CardSelectionContext"; 4 | 5 | interface CardSelectionGroupProps { 6 | children: React.ReactElement<{ value: string }>[]; 7 | value: string; 8 | onChange: (value: string) => void; 9 | } 10 | 11 | export default function CardSelectionGroup({ 12 | children, 13 | value, 14 | onChange, 15 | }: CardSelectionGroupProps) { 16 | return ( 17 | 18 | 26 | {children} 27 | 28 | 29 | ); 30 | } 31 | -------------------------------------------------------------------------------- /src-gui/src/renderer/components/navigation/Navigation.tsx: -------------------------------------------------------------------------------- 1 | import { Box, Drawer } from "@mui/material"; 2 | import NavigationFooter from "./NavigationFooter"; 3 | import NavigationHeader from "./NavigationHeader"; 4 | 5 | export const drawerWidth = "240px"; 6 | 7 | export default function Navigation() { 8 | return ( 9 | 19 | 28 | 29 | 30 | 31 | 32 | ); 33 | } 34 | -------------------------------------------------------------------------------- /libp2p-rendezvous-node/Dockerfile: -------------------------------------------------------------------------------- 1 | # Latest Rust 1.87.0 image as of Tue, 05 Aug 2025 15:34:08 GMT 2 | FROM rust:1.87.0-bookworm@sha256:251cec8da4689d180f124ef00024c2f83f79d9bf984e43c180a598119e326b84 AS builder 3 | 4 | WORKDIR /build 5 | 6 | # Install some system dependencies 7 | # TODO: These might not be required? 8 | RUN apt-get update 9 | RUN apt-get install -y git clang cmake libsnappy-dev 10 | 11 | # Build the rendezvous server binary 12 | COPY . . 13 | RUN cargo build --release --package rendezvous-node --bin rendezvous-node 14 | 15 | # Latest Debian Bookworm image as of Tue, 05 Aug 2025 15:34:08 GMT 16 | FROM debian:bookworm@sha256:b6507e340c43553136f5078284c8c68d86ec8262b1724dde73c325e8d3dcdeba AS runner 17 | 18 | # Copy the compiled binary from the previous stage 19 | COPY --from=builder /build/target/release/rendezvous-node /bin/rendezvous-node 20 | 21 | EXPOSE 8888 22 | 23 | ENTRYPOINT ["rendezvous-node"] 24 | -------------------------------------------------------------------------------- /src-gui/src/renderer/components/modal/introduction/slides/Slide04_ExecuteSwap.tsx: -------------------------------------------------------------------------------- 1 | import { Typography } from "@mui/material"; 2 | import SlideTemplate from "./SlideTemplate"; 3 | import imagePath from "assets/simpleSwapFlowDiagram.svg"; 4 | import { IntroSlideProps } from "./SlideTypes"; 5 | 6 | export default function Slide02_ChooseAMaker(props: IntroSlideProps) { 7 | return ( 8 | 14 | After confirming: 15 | 16 | 17 | Your Bitcoin are locked 18 | Maker locks the Monero 19 | Maker reedems the Bitcoin 20 | Monero is sent to your address 21 | 22 | 23 | 24 | ); 25 | } 26 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | # To get started with Dependabot version updates, you'll need to specify which 2 | # package ecosystems to update and where the package manifests are located. 3 | # Please see the documentation for all configuration options: 4 | # https://help.github.com/github/administering-a-repository/configuration-options-for-dependency-updates 5 | 6 | version: 2 7 | updates: 8 | - package-ecosystem: "cargo" 9 | directory: "/" 10 | schedule: 11 | interval: "daily" 12 | rebase-strategy: "disabled" 13 | open-pull-requests-limit: 10 14 | ignore: 15 | - dependency-name: "bitcoin" # Needs to be updated together with bdk to be in sync. 16 | - dependency-name: "miniscript" # Needs to be updated together with bdk to be in sync. 17 | 18 | - package-ecosystem: "github-actions" 19 | directory: "/" 20 | schedule: 21 | interval: "daily" 22 | rebase-strategy: "disabled" 23 | -------------------------------------------------------------------------------- /swap-feed/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "swap-feed" 3 | version = "0.1.0" 4 | authors = ["The COMIT guys "] 5 | edition = "2021" 6 | description = "Price feed functionality for XMR/BTC atomic swaps" 7 | 8 | [lib] 9 | name = "swap_feed" 10 | 11 | [dependencies] 12 | anyhow = { workspace = true } 13 | backoff = { workspace = true } 14 | bitcoin = { workspace = true } 15 | futures = { workspace = true } 16 | monero = { workspace = true } 17 | reqwest = { workspace = true, features = ["http2", "rustls-tls-native-roots", "stream", "socks"] } 18 | rust_decimal = { workspace = true } 19 | serde = { workspace = true } 20 | serde_json = { workspace = true } 21 | thiserror = { workspace = true } 22 | tokio = { workspace = true } 23 | tokio-tungstenite = { version = "0.15", features = ["rustls-tls"] } 24 | tracing = { workspace = true } 25 | tracing-subscriber = { workspace = true } 26 | url = { workspace = true } 27 | -------------------------------------------------------------------------------- /monero-sys/patches/0004-fix-___isPlatformVersionAtLeast.patch: -------------------------------------------------------------------------------- 1 | From 1ac620cf1afd6515daa127039311ba9c9a2a1ea3 Mon Sep 17 00:00:00 2001 2 | From: Czarek Nakamoto 3 | Date: Tue, 15 Jul 2025 19:58:34 +0200 4 | Subject: [PATCH] fix: ___isPlatformVersionAtLeast 5 | 6 | --- 7 | src/virtual_memory.c | 2 +- 8 | 1 file changed, 1 insertion(+), 1 deletion(-) 9 | 10 | diff --git a/external/randomx/src/virtual_memory.c b/external/randomx/src/virtual_memory.c 11 | index d2cdcda..5158ea4 100644 12 | --- a/external/randomx/src/virtual_memory.c 13 | +++ b/external/randomx/src/virtual_memory.c 14 | @@ -35,7 +35,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 15 | #include 16 | #include 17 | # if TARGET_OS_OSX 18 | -# define USE_PTHREAD_JIT_WP 1 19 | +# define USE_PTHREAD_JIT_WP 0 20 | # include 21 | # include 22 | # include -------------------------------------------------------------------------------- /src-gui/src/renderer/components/other/Jdenticon.tsx: -------------------------------------------------------------------------------- 1 | import { useEffect, useRef } from "react"; 2 | import { update } from "jdenticon"; 3 | 4 | interface JdenticonProps { 5 | value: string; 6 | size: number; 7 | className?: string; 8 | style?: React.CSSProperties; 9 | } 10 | 11 | /** 12 | * React wrapper component for jdenticon 13 | * Generates a unique identicon based on the provided value 14 | */ 15 | export default function Jdenticon({ 16 | value, 17 | size, 18 | className, 19 | style, 20 | }: JdenticonProps) { 21 | const svgRef = useRef(null); 22 | 23 | useEffect(() => { 24 | if (svgRef.current) { 25 | update(svgRef.current, value); 26 | } 27 | }, [value]); 28 | 29 | return ( 30 | 38 | ); 39 | } 40 | -------------------------------------------------------------------------------- /src-gui/src/store/features/nodesSlice.ts: -------------------------------------------------------------------------------- 1 | import { createSlice, PayloadAction } from "@reduxjs/toolkit"; 2 | import { Blockchain } from "../types"; 3 | 4 | export interface NodesSlice { 5 | nodes: Record>; 6 | } 7 | 8 | function initialState(): NodesSlice { 9 | return { 10 | nodes: { 11 | [Blockchain.Bitcoin]: {}, 12 | [Blockchain.Monero]: {}, 13 | }, 14 | }; 15 | } 16 | 17 | const nodesSlice = createSlice({ 18 | name: "nodes", 19 | initialState: initialState(), 20 | reducers: { 21 | setStatus( 22 | slice, 23 | action: PayloadAction<{ 24 | node: string; 25 | status: boolean; 26 | blockchain: Blockchain; 27 | }>, 28 | ) { 29 | slice.nodes[action.payload.blockchain][action.payload.node] = 30 | action.payload.status; 31 | }, 32 | }, 33 | }); 34 | 35 | export const { setStatus } = nodesSlice.actions; 36 | export default nodesSlice.reducer; 37 | -------------------------------------------------------------------------------- /libp2p-rendezvous-node/src/behaviour.rs: -------------------------------------------------------------------------------- 1 | use anyhow::Result; 2 | use libp2p::swarm::NetworkBehaviour; 3 | use libp2p::{identity, PeerId}; 4 | use swap_p2p::protocols::rendezvous::{register, XmrBtcNamespace}; 5 | 6 | /// Acts as both a rendezvous server and registers at other rendezvous points 7 | #[derive(NetworkBehaviour)] 8 | pub struct Behaviour { 9 | pub server: libp2p::rendezvous::server::Behaviour, 10 | pub register: register::Behaviour, 11 | } 12 | 13 | impl Behaviour { 14 | pub fn new( 15 | identity: identity::Keypair, 16 | rendezvous_nodes: Vec, 17 | namespace: XmrBtcNamespace, 18 | ) -> Result { 19 | let server = libp2p::rendezvous::server::Behaviour::new( 20 | libp2p::rendezvous::server::Config::default(), 21 | ); 22 | 23 | let register = register::Behaviour::new(identity, rendezvous_nodes, namespace.into()); 24 | 25 | Ok(Self { server, register }) 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src-gui/src/renderer/components/modal/introduction/slides/Slide05_KeepAnEyeOnYourSwaps.tsx: -------------------------------------------------------------------------------- 1 | import { Link, SlideProps, Typography } from "@mui/material"; 2 | import SlideTemplate from "./SlideTemplate"; 3 | import imagePath from "assets/mockHistoryPage.svg"; 4 | import ExternalLink from "renderer/components/other/ExternalLink"; 5 | import { IntroSlideProps } from "./SlideTypes"; 6 | 7 | export default function Slide05_KeepAnEyeOnYourSwaps(props: IntroSlideProps) { 8 | return ( 9 | 15 | 16 | Monitor active swaps to ensure everything proceeds smoothly. 17 | 18 | 19 | 20 | Learn more about atomic swaps 21 | 22 | 23 | 24 | ); 25 | } 26 | -------------------------------------------------------------------------------- /swap-controller/src/repl/parse.rs: -------------------------------------------------------------------------------- 1 | use crate::cli::Cmd; 2 | use clap::Parser; 3 | 4 | /// A wrapper for parsing REPL commands using clap 5 | #[derive(Parser)] 6 | #[command(name = "")] 7 | #[command(about = "")] 8 | #[command(no_binary_name = true)] 9 | struct ReplCommand { 10 | #[command(subcommand)] 11 | cmd: Cmd, 12 | } 13 | 14 | /// Parse a line from the REPL into a command using clap's parser 15 | pub fn parse_line(line: &str) -> Option { 16 | let line = line.trim(); 17 | if line.is_empty() { 18 | return None; 19 | } 20 | 21 | // Split the line into arguments, preserving quoted strings 22 | let args = shell_words::split(line).ok()?; 23 | 24 | // Try to parse using clap 25 | match ReplCommand::try_parse_from(args) { 26 | Ok(repl_cmd) => Some(repl_cmd.cmd), 27 | Err(err) => { 28 | // Print clap's error message (it's quite good) 29 | eprintln!("{err}"); 30 | None 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /swap-machine/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "swap-machine" 3 | version = "0.1.0" 4 | edition = "2024" 5 | 6 | [dependencies] 7 | anyhow = { workspace = true } 8 | async-trait = { workspace = true } 9 | bitcoin = { workspace = true } 10 | bitcoin-wallet = { path = "../bitcoin-wallet" } 11 | curve25519-dalek = { workspace = true } 12 | ecdsa_fun = { workspace = true } 13 | libp2p = { workspace = true } 14 | monero = { workspace = true } 15 | rand = { workspace = true } 16 | rand_chacha = { workspace = true } 17 | serde = { workspace = true } 18 | sha2 = { workspace = true } 19 | sigma_fun = { workspace = true, default-features = false, features = ["ed25519", "serde", "secp256k1", "alloc"] } 20 | swap-core = { path = "../swap-core" } 21 | swap-env = { path = "../swap-env" } 22 | swap-serde = { path = "../swap-serde" } 23 | thiserror = { workspace = true } 24 | uuid = { workspace = true, features = ["serde"] } 25 | 26 | [dev-dependencies] 27 | tokio = { workspace = true } 28 | 29 | [lints] 30 | workspace = true 31 | -------------------------------------------------------------------------------- /swap-proptest/src/lib.rs: -------------------------------------------------------------------------------- 1 | use proptest::prelude::*; 2 | 3 | pub mod ecdsa_fun { 4 | use super::*; 5 | use ::ecdsa_fun::fun::{Point, Scalar, G}; 6 | 7 | pub fn point() -> impl Strategy { 8 | scalar().prop_map(|mut scalar| Point::even_y_from_scalar_mul(G, &mut scalar).normalize()) 9 | } 10 | 11 | pub fn scalar() -> impl Strategy { 12 | prop::array::uniform32(0..255u8).prop_filter_map("generated the 0 element", |bytes| { 13 | Scalar::from_bytes_mod_order(bytes).non_zero() 14 | }) 15 | } 16 | } 17 | 18 | pub mod bitcoin { 19 | use super::*; 20 | use ::bitcoin::bip32::Xpriv as ExtendedPrivKey; 21 | use ::bitcoin::Network; 22 | 23 | pub fn extended_priv_key() -> impl Strategy { 24 | prop::array::uniform8(0..255u8).prop_filter_map("invalid secret key generated", |bytes| { 25 | ExtendedPrivKey::new_master(Network::Regtest, &bytes).ok() 26 | }) 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src-gui/src/renderer/components/pages/swap/ApiAlertsBox.tsx: -------------------------------------------------------------------------------- 1 | import { Box } from "@mui/material"; 2 | import { Alert, AlertTitle } from "@mui/material"; 3 | import { acknowledgeAlert } from "store/features/alertsSlice"; 4 | import { useAlerts, useAppDispatch } from "store/hooks"; 5 | 6 | export default function ApiAlertsBox() { 7 | const alerts = useAlerts(); 8 | const dispatch = useAppDispatch(); 9 | 10 | function onAcknowledgeAlert(id: number) { 11 | dispatch(acknowledgeAlert(id)); 12 | } 13 | 14 | if (alerts.length === 0) return null; 15 | 16 | return ( 17 | 18 | {alerts.map((alert) => ( 19 | onAcknowledgeAlert(alert.id)} 24 | > 25 | {alert.title} 26 | {alert.body} 27 | 28 | ))} 29 | 30 | ); 31 | } 32 | -------------------------------------------------------------------------------- /src-tauri/build.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | #[cfg(target_os = "windows")] 3 | { 4 | #[cfg(not(host_os = "linux"))] 5 | { 6 | panic!("Compiling for Windows is currently only supported from Linux (x86_64)"); 7 | } 8 | 9 | // make sure the .dll's are exist -- else panic 10 | if !["libstdc++-6.dll", "libgcc_s_seh-1.dll"] 11 | .into_iter() 12 | .all(|dll| std::path::Path::new(dll).try_exists().unwrap_or(false)) 13 | { 14 | panic!("libstdc++-6.dll and libgcc_s_seh-1.dll don't exist in the src-tauri directory - run `just prepare-windows-build` to build them"); 15 | } 16 | 17 | let home_dir = std::env::var("HOME").expect("HOME environment variable not set"); 18 | let lib_path = format!("{}/opt/gcc-mingw-14.3/x86_64-w64-mingw32/lib", home_dir); 19 | println!("cargo:rustc-link-search=native={}", lib_path); 20 | println!("cargo:rustc-link-lib=stdc++"); 21 | } 22 | 23 | tauri_build::build(); 24 | } 25 | -------------------------------------------------------------------------------- /src-gui/src/utils/multiAddrUtils.ts: -------------------------------------------------------------------------------- 1 | import { ExtendedMakerStatus, Maker } from "models/apiModel"; 2 | import { Multiaddr } from "multiaddr"; 3 | import semver from "semver"; 4 | import { isTestnet } from "store/config"; 5 | 6 | // const MIN_ASB_VERSION = "1.0.0-alpha.1" // First version to support new libp2p protocol 7 | // const MIN_ASB_VERSION = "1.1.0-rc.3" // First version with support for bdk > 1.0 8 | // const MIN_ASB_VERSION = "2.0.0-beta.1"; // First version with support for tx_early_refund 9 | const MIN_ASB_VERSION = "3.2.0-rc.1"; 10 | 11 | export function isMakerOnCorrectNetwork( 12 | provider: ExtendedMakerStatus, 13 | ): boolean { 14 | return provider.testnet === isTestnet(); 15 | } 16 | 17 | export function isMakerVersionOutdated(version: string): boolean { 18 | // This checks if the version is less than the minimum version 19 | // we use .compare(...) instead of .satisfies(...) because satisfies(...) 20 | // does not work with pre-release versions 21 | return semver.compare(version, MIN_ASB_VERSION) === -1; 22 | } 23 | -------------------------------------------------------------------------------- /swap/src/cli/list_sellers.rs: -------------------------------------------------------------------------------- 1 | use crate::network::quote::BidQuote; 2 | use libp2p::{Multiaddr, PeerId}; 3 | use semver::Version; 4 | use serde::{Deserialize, Serialize}; 5 | use serde_with::{serde_as, DisplayFromStr}; 6 | use typeshare::typeshare; 7 | 8 | // TODO: Move these types into swap-p2p? 9 | #[serde_as] 10 | #[typeshare] 11 | #[derive(Debug, Serialize, Deserialize, PartialEq, Eq, Hash, Clone)] 12 | pub struct QuoteWithAddress { 13 | /// The multiaddr of the seller (at which we were able to connect to and get the quote from) 14 | #[serde_as(as = "DisplayFromStr")] 15 | #[typeshare(serialized_as = "string")] 16 | pub multiaddr: Multiaddr, 17 | 18 | /// The peer id of the seller 19 | #[typeshare(serialized_as = "string")] 20 | pub peer_id: PeerId, 21 | 22 | /// The quote of the seller 23 | pub quote: BidQuote, 24 | 25 | /// The version of the seller's agent 26 | #[serde_as(as = "Option")] 27 | #[typeshare(serialized_as = "string")] 28 | pub version: Option, 29 | } 30 | -------------------------------------------------------------------------------- /src-gui/src/renderer/components/alert/UnfinishedSwapsAlert.tsx: -------------------------------------------------------------------------------- 1 | import { Button } from "@mui/material"; 2 | import Alert from "@mui/material/Alert"; 3 | import { useNavigate } from "react-router-dom"; 4 | import { useResumeableSwapsCountExcludingPunished } from "store/hooks"; 5 | 6 | export default function UnfinishedSwapsAlert() { 7 | const resumableSwapsCount = useResumeableSwapsCountExcludingPunished(); 8 | const navigate = useNavigate(); 9 | 10 | if (resumableSwapsCount > 0) { 11 | return ( 12 | navigate("/history")} 20 | > 21 | VIEW 22 | 23 | } 24 | > 25 | You have{" "} 26 | {resumableSwapsCount > 1 27 | ? `${resumableSwapsCount} pending swaps` 28 | : "one pending swap"} 29 | 30 | ); 31 | } 32 | return null; 33 | } 34 | -------------------------------------------------------------------------------- /src-gui/src/renderer/components/pages/help/SettingsPage.tsx: -------------------------------------------------------------------------------- 1 | import { Box } from "@mui/material"; 2 | import DonateInfoBox from "./DonateInfoBox"; 3 | import DaemonControlBox from "./DaemonControlBox"; 4 | import SettingsBox from "./SettingsBox"; 5 | import MoneroPoolHealthBox from "./MoneroPoolHealthBox"; 6 | import { useLocation } from "react-router-dom"; 7 | import { useEffect } from "react"; 8 | 9 | export default function SettingsPage() { 10 | const location = useLocation(); 11 | 12 | useEffect(() => { 13 | if (location.hash) { 14 | const element = document.getElementById(location.hash.slice(1)); 15 | element?.scrollIntoView({ behavior: "smooth" }); 16 | } 17 | }, [location]); 18 | 19 | return ( 20 | 28 | 29 | 30 | 31 | 32 | 33 | ); 34 | } 35 | -------------------------------------------------------------------------------- /src-gui/src/renderer/components/pages/swap/swap/in_progress/ReceivedQuotePage.tsx: -------------------------------------------------------------------------------- 1 | import { 2 | useConservativeBitcoinSyncProgress, 3 | usePendingBackgroundProcesses, 4 | } from "store/hooks"; 5 | import CircularProgressWithSubtitle, { 6 | LinearProgressWithSubtitle, 7 | } from "../components/CircularProgressWithSubtitle"; 8 | 9 | export default function ReceivedQuotePage() { 10 | const syncProgress = useConservativeBitcoinSyncProgress(); 11 | 12 | if (syncProgress?.type === "Known") { 13 | const percentage = Math.round( 14 | (syncProgress.content.consumed / syncProgress.content.total) * 100, 15 | ); 16 | 17 | return ( 18 | 22 | ); 23 | } 24 | 25 | if (syncProgress?.type === "Unknown") { 26 | return ( 27 | 28 | ); 29 | } 30 | 31 | return ; 32 | } 33 | -------------------------------------------------------------------------------- /src-gui/src/store/combinedReducer.ts: -------------------------------------------------------------------------------- 1 | import alertsSlice from "./features/alertsSlice"; 2 | import ratesSlice from "./features/ratesSlice"; 3 | import rpcSlice from "./features/rpcSlice"; 4 | import swapReducer from "./features/swapSlice"; 5 | import settingsSlice from "./features/settingsSlice"; 6 | import nodesSlice from "./features/nodesSlice"; 7 | import conversationsSlice from "./features/conversationsSlice"; 8 | import poolSlice from "./features/poolSlice"; 9 | import walletSlice from "./features/walletSlice"; 10 | import bitcoinWalletSlice from "./features/bitcoinWalletSlice"; 11 | import logsSlice from "./features/logsSlice"; 12 | import p2pSlice from "./features/p2pSlice"; 13 | 14 | export const reducers = { 15 | swap: swapReducer, 16 | rpc: rpcSlice, 17 | p2p: p2pSlice, 18 | alerts: alertsSlice, 19 | rates: ratesSlice, 20 | settings: settingsSlice, 21 | nodes: nodesSlice, 22 | conversations: conversationsSlice, 23 | pool: poolSlice, 24 | wallet: walletSlice, 25 | bitcoinWallet: bitcoinWalletSlice, 26 | logs: logsSlice, 27 | }; 28 | -------------------------------------------------------------------------------- /src-gui/src/renderer/components/icons/MoneroIcon.tsx: -------------------------------------------------------------------------------- 1 | import SvgIcon, { SvgIconProps } from "@mui/material/SvgIcon"; 2 | 3 | export default function MoneroIcon(props: SvgIconProps) { 4 | return ( 5 | 6 | 15 | 19 | 23 | 24 | 25 | ); 26 | } 27 | -------------------------------------------------------------------------------- /src-gui/src/store/features/ratesSlice.ts: -------------------------------------------------------------------------------- 1 | import { createSlice, PayloadAction } from "@reduxjs/toolkit"; 2 | 3 | export interface RatesState { 4 | // USD price of 1 BTC 5 | btcPrice: number | null; 6 | // USD price of 1 XMR 7 | xmrPrice: number | null; 8 | // XMR/BTC exchange rate 9 | xmrBtcRate: number | null; 10 | } 11 | 12 | const initialState: RatesState = { 13 | btcPrice: null, 14 | xmrPrice: null, 15 | xmrBtcRate: null, 16 | }; 17 | 18 | const ratesSlice = createSlice({ 19 | name: "rates", 20 | initialState, 21 | reducers: { 22 | setBtcPrice: (state, action: PayloadAction) => { 23 | state.btcPrice = action.payload; 24 | }, 25 | setXmrPrice: (state, action: PayloadAction) => { 26 | state.xmrPrice = action.payload; 27 | }, 28 | setXmrBtcRate: (state, action: PayloadAction) => { 29 | state.xmrBtcRate = action.payload; 30 | }, 31 | }, 32 | }); 33 | 34 | export const { setBtcPrice, setXmrPrice, setXmrBtcRate } = ratesSlice.actions; 35 | 36 | export default ratesSlice.reducer; 37 | -------------------------------------------------------------------------------- /src-gui/src/renderer/components/other/ClickToCopy.tsx: -------------------------------------------------------------------------------- 1 | import { Box, Tooltip } from "@mui/material"; 2 | import { ReactNode, useState } from "react"; 3 | import { writeText } from "@tauri-apps/plugin-clipboard-manager"; 4 | 5 | type Props = { 6 | content: string; 7 | children: ReactNode; 8 | showTooltip?: boolean; 9 | }; 10 | 11 | export default function ClickToCopy({ 12 | content, 13 | children, 14 | showTooltip = true, 15 | }: Props) { 16 | const [copied, setCopied] = useState(false); 17 | 18 | const handleCopy = async () => { 19 | await writeText(content); 20 | setCopied(true); 21 | setTimeout(() => setCopied(false), 2000); 22 | }; 23 | 24 | const wrapper = ( 25 | 29 | {children} 30 | 31 | ); 32 | 33 | if (!showTooltip) { 34 | return wrapper; 35 | } 36 | 37 | return ( 38 | 39 | {wrapper} 40 | 41 | ); 42 | } 43 | -------------------------------------------------------------------------------- /swap-controller/Dockerfile: -------------------------------------------------------------------------------- 1 | # Latest Rust 1.87.0 image as of Tue, 05 Aug 2025 15:34:08 GMT 2 | # This needs to be built from the root of the Cargo workspace (root of git repo) 3 | FROM rust:1.87.0-bookworm@sha256:251cec8da4689d180f124ef00024c2f83f79d9bf984e43c180a598119e326b84 AS builder 4 | 5 | WORKDIR /build 6 | 7 | # Copy the entire Cargo workspace 8 | COPY . . 9 | 10 | RUN cargo build --locked --bin asb-controller --release 11 | 12 | # Latest Debian Bookworm image as of Tue, 05 Aug 2025 15:34:08 GMT 13 | FROM debian:bookworm@sha256:b6507e340c43553136f5078284c8c68d86ec8262b1724dde73c325e8d3dcdeba AS runner 14 | 15 | # Install native root certificates 16 | ENV DEBIAN_FRONTEND=noninteractive 17 | RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \ 18 | --mount=type=cache,target=/var/lib/apt,sharing=locked \ 19 | apt-get update && \ 20 | apt-get install -y ca-certificates && \ 21 | update-ca-certificates 22 | 23 | COPY --from=builder /build/target/release/asb-controller /usr/local/bin/asb-controller 24 | 25 | ENTRYPOINT ["/usr/local/bin/asb-controller"] -------------------------------------------------------------------------------- /dprint.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://dprint.dev/schemas/v0.json", 3 | "projectType": "openSource", 4 | "incremental": true, 5 | "markdown": {}, 6 | "exec": { 7 | "commands": [ 8 | { 9 | "command": "rustfmt --edition 2021", 10 | "exts": ["rs"] 11 | } 12 | ] 13 | }, 14 | "includes": [ 15 | "**/*.{md}", 16 | "**/*.{toml}", 17 | "**/*.{rs}", 18 | "**/*.{js,jsx,ts,tsx,json,css,scss,html}" 19 | ], 20 | "excludes": [ 21 | "target/", 22 | "src-tauri/Cargo.toml", 23 | "monero-sys/monero/", 24 | ".git/**", 25 | "**/node_modules/**", 26 | "**/dist/**", 27 | "monero-sys/monero_c", 28 | "monero-sys/monero" 29 | ], 30 | "plugins": [ 31 | "https://plugins.dprint.dev/markdown-0.18.0.wasm", 32 | "https://plugins.dprint.dev/toml-0.7.0.wasm", 33 | "https://plugins.dprint.dev/exec-0.5.1.json@492414e39dea4dccc07b4af796d2f4efdb89e84bae2bd4e1e924c0cc050855bf", 34 | "https://plugins.dprint.dev/prettier-0.58.2.json@2fd8cc9c9773364848dc93735b01a00d55fcfa78a56a9230b4b63c014964c82d" 35 | ] 36 | } 37 | -------------------------------------------------------------------------------- /swap/tests/happy_path_alice_developer_tip.rs: -------------------------------------------------------------------------------- 1 | pub mod harness; 2 | 3 | use harness::SlowCancelConfig; 4 | use rust_decimal::Decimal; 5 | use swap::asb::FixedRate; 6 | use swap::protocol::{alice, bob}; 7 | use tokio::join; 8 | 9 | #[tokio::test] 10 | async fn happy_path_alice_developer_tip() { 11 | harness::setup_test( 12 | SlowCancelConfig, 13 | Some((Decimal::from_f32_retain(0.1).unwrap(), false)), 14 | |mut ctx| async move { 15 | let (bob_swap, _) = ctx.bob_swap().await; 16 | let bob_swap = tokio::spawn(bob::run(bob_swap)); 17 | 18 | let alice_swap = ctx.alice_next_swap().await; 19 | let alice_swap = tokio::spawn(alice::run(alice_swap, FixedRate::default())); 20 | 21 | let (bob_state, alice_state) = join!(bob_swap, alice_swap); 22 | 23 | ctx.assert_alice_redeemed(alice_state??).await; 24 | ctx.assert_bob_redeemed(bob_state??).await; 25 | ctx.assert_alice_developer_tip_received().await; 26 | 27 | Ok(()) 28 | }, 29 | ) 30 | .await; 31 | } 32 | -------------------------------------------------------------------------------- /src-gui/src/renderer/components/pages/swap/swap/in_progress/WaitingForXmrConfirmationsBeforeRedeemPage.tsx: -------------------------------------------------------------------------------- 1 | import { Box, DialogContentText } from "@mui/material"; 2 | import { TauriSwapProgressEventContent } from "models/tauriModelExt"; 3 | import MoneroTransactionInfoBox from "../components/MoneroTransactionInfoBox"; 4 | 5 | export default function WaitingForXmrConfirmationsBeforeRedeemPage({ 6 | xmr_lock_txid, 7 | xmr_lock_tx_confirmations, 8 | xmr_lock_tx_target_confirmations, 9 | }: TauriSwapProgressEventContent<"WaitingForXmrConfirmationsBeforeRedeem">) { 10 | return ( 11 | 12 | 13 | We are waiting for the Monero lock transaction to receive enough 14 | confirmations before we can sweep them to your address. 15 | 16 | 17 | 23 | 24 | ); 25 | } 26 | -------------------------------------------------------------------------------- /swap/tests/happy_path_alice_developer_tip_subaddress.rs: -------------------------------------------------------------------------------- 1 | pub mod harness; 2 | 3 | use harness::SlowCancelConfig; 4 | use rust_decimal::Decimal; 5 | use swap::asb::FixedRate; 6 | use swap::protocol::{alice, bob}; 7 | use tokio::join; 8 | 9 | #[tokio::test] 10 | async fn happy_path_alice_developer_tip_subaddress() { 11 | harness::setup_test( 12 | SlowCancelConfig, 13 | Some((Decimal::from_f32_retain(0.1).unwrap(), true)), 14 | |mut ctx| async move { 15 | let (bob_swap, _) = ctx.bob_swap().await; 16 | let bob_swap = tokio::spawn(bob::run(bob_swap)); 17 | 18 | let alice_swap = ctx.alice_next_swap().await; 19 | let alice_swap = tokio::spawn(alice::run(alice_swap, FixedRate::default())); 20 | 21 | let (bob_state, alice_state) = join!(bob_swap, alice_swap); 22 | 23 | ctx.assert_alice_redeemed(alice_state??).await; 24 | ctx.assert_bob_redeemed(bob_state??).await; 25 | ctx.assert_alice_developer_tip_received().await; 26 | 27 | Ok(()) 28 | }, 29 | ) 30 | .await; 31 | } 32 | -------------------------------------------------------------------------------- /src-gui/src/renderer/components/pages/wallet/WalletPage.tsx: -------------------------------------------------------------------------------- 1 | import { Box } from "@mui/material"; 2 | import { useAppSelector } from "store/hooks"; 3 | import WalletOverview from "./components/WalletOverview"; 4 | import WalletActionButtons from "./components/WalletActionButtons"; 5 | import ActionableMonospaceTextBox from "renderer/components/other/ActionableMonospaceTextBox"; 6 | 7 | export default function WalletPage() { 8 | const walletBalance = useAppSelector((state) => state.bitcoinWallet.balance); 9 | const bitcoinAddress = useAppSelector((state) => state.bitcoinWallet.address); 10 | 11 | return ( 12 | 22 | 23 | {bitcoinAddress && ( 24 | 28 | )} 29 | 30 | 31 | ); 32 | } 33 | -------------------------------------------------------------------------------- /src-gui/src/renderer/components/modal/wallet/pages/AddressInputPage.tsx: -------------------------------------------------------------------------------- 1 | import { DialogContentText } from "@mui/material"; 2 | import BitcoinAddressTextField from "../../../inputs/BitcoinAddressTextField"; 3 | 4 | export default function AddressInputPage({ 5 | withdrawAddress, 6 | setWithdrawAddress, 7 | setWithdrawAddressValid, 8 | }: { 9 | withdrawAddress: string; 10 | setWithdrawAddress: (address: string) => void; 11 | setWithdrawAddressValid: (valid: boolean) => void; 12 | }) { 13 | return ( 14 | <> 15 | 16 | To withdraw the Bitcoin inside the internal wallet, please enter an 17 | address. All funds (the entire balance) will be sent to that address. 18 | 19 | 20 | 28 | > 29 | ); 30 | } 31 | -------------------------------------------------------------------------------- /.sqlx/query-d32d91ca2debc4212841282533482b2ff081234c7f9f848a7223ae04234995d9.json: -------------------------------------------------------------------------------- 1 | { 2 | "db_name": "SQLite", 3 | "query": "\n SELECT \n CAST(SUM(CASE WHEN hc.was_successful THEN 1 ELSE 0 END) AS INTEGER) as \"successful!: i64\",\n CAST(SUM(CASE WHEN NOT hc.was_successful THEN 1 ELSE 0 END) AS INTEGER) as \"unsuccessful!: i64\"\n FROM (\n SELECT hc.was_successful\n FROM health_checks hc\n JOIN monero_nodes n ON hc.node_id = n.id\n WHERE n.network = ?\n ORDER BY hc.timestamp DESC\n LIMIT 100\n ) hc\n ", 4 | "describe": { 5 | "columns": [ 6 | { 7 | "name": "successful!: i64", 8 | "ordinal": 0, 9 | "type_info": "Integer" 10 | }, 11 | { 12 | "name": "unsuccessful!: i64", 13 | "ordinal": 1, 14 | "type_info": "Integer" 15 | } 16 | ], 17 | "parameters": { 18 | "Right": 1 19 | }, 20 | "nullable": [true, true] 21 | }, 22 | "hash": "d32d91ca2debc4212841282533482b2ff081234c7f9f848a7223ae04234995d9" 23 | } 24 | -------------------------------------------------------------------------------- /libp2p-tor/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Hannes Furmans 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /src-gui/src/renderer/components/pages/swap/swap/in_progress/XmrLockInMempoolPage.tsx: -------------------------------------------------------------------------------- 1 | import { Box, DialogContentText } from "@mui/material"; 2 | import { TauriSwapProgressEventContent } from "models/tauriModelExt"; 3 | import { formatConfirmations } from "utils/formatUtils"; 4 | import MoneroTransactionInfoBox from "../components/MoneroTransactionInfoBox"; 5 | 6 | export default function XmrLockTxInMempoolPage({ 7 | xmr_lock_tx_confirmations, 8 | xmr_lock_txid, 9 | xmr_lock_tx_target_confirmations, 10 | }: TauriSwapProgressEventContent<"XmrLockTxInMempool">) { 11 | const additionalContent = `Confirmations: ${formatConfirmations(xmr_lock_tx_confirmations, xmr_lock_tx_target_confirmations)}`; 12 | 13 | return ( 14 | <> 15 | 16 | They have published their Monero lock transaction. The swap will proceed 17 | once the transaction has been confirmed. 18 | 19 | 20 | 26 | > 27 | ); 28 | } 29 | -------------------------------------------------------------------------------- /swap/migrations/20250704115958_receive_xmr_to_internal_wallet.sql: -------------------------------------------------------------------------------- 1 | -- Users don't have to specify a receive address for the swap anymore, if none is present 2 | -- we will use the internal wallet address instead. 3 | -- Now, the monero_addresses.address column can be NULL. 4 | 5 | -- SQLite doesn't support MODIFY COLUMN directly 6 | -- We need to recreate the table with the desired schema 7 | CREATE TABLE monero_addresses_temp 8 | ( 9 | swap_id TEXT NOT NULL, 10 | address TEXT NULL, 11 | percentage REAL NOT NULL DEFAULT 1.0, 12 | label TEXT NOT NULL DEFAULT 'user address' 13 | ); 14 | 15 | -- Copy data from the original table 16 | INSERT INTO monero_addresses_temp (swap_id, address, percentage, label) 17 | SELECT swap_id, address, percentage, label FROM monero_addresses; 18 | 19 | -- Drop the original table 20 | DROP TABLE monero_addresses; 21 | 22 | -- Rename the temporary table 23 | ALTER TABLE monero_addresses_temp RENAME TO monero_addresses; 24 | 25 | -- Create an index on swap_id for performance 26 | CREATE INDEX idx_monero_addresses_swap_id ON monero_addresses(swap_id); 27 | -------------------------------------------------------------------------------- /monero-sys/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "monero-sys" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | [dependencies] 7 | anyhow = { workspace = true } 8 | backoff = { workspace = true } 9 | chrono = { version = "0.4", features = ["serde"] } 10 | cxx = "1.0.137" 11 | monero = { workspace = true } 12 | serde = { workspace = true } 13 | sqlx = { version = "0.8", features = ["sqlite", "runtime-tokio-rustls", "macros", "chrono"] } 14 | thiserror = "2.0.17" 15 | tokio = { workspace = true, features = ["sync", "time", "rt"] } 16 | tracing = { workspace = true } 17 | typeshare = { workspace = true } 18 | url = { workspace = true } 19 | uuid = { workspace = true } 20 | 21 | # Our crates 22 | throttle = { path = "../throttle" } 23 | 24 | [build-dependencies] 25 | cmake = "0.1.54" 26 | num_cpus = "1.17" 27 | cxx-build = "1.0.137" 28 | diffy = "0.4.2" 29 | fs_extra = "1.3.0" 30 | 31 | [dev-dependencies] 32 | anyhow = { workspace = true } 33 | futures = { workspace = true } 34 | quickcheck = "1.0" 35 | quickcheck_macros = "1.0" 36 | tempfile = "3.19.1" 37 | tokio = { workspace = true, features = ["full"] } 38 | tracing-subscriber = { workspace = true } 39 | uuid = { workspace = true } 40 | -------------------------------------------------------------------------------- /src-gui/src/renderer/components/pages/swap/swap/components/InfoBox.tsx: -------------------------------------------------------------------------------- 1 | import { Box, LinearProgress, Paper, Typography } from "@mui/material"; 2 | import { ReactNode } from "react"; 3 | 4 | type Props = { 5 | id?: string | null; 6 | title: ReactNode | null; 7 | mainContent: ReactNode; 8 | additionalContent: ReactNode; 9 | loading: boolean; 10 | icon: ReactNode; 11 | }; 12 | 13 | export default function InfoBox({ 14 | id, 15 | title, 16 | mainContent, 17 | additionalContent, 18 | icon, 19 | loading, 20 | }: Props) { 21 | return ( 22 | 33 | {title ? {title} : null} 34 | 35 | {icon} 36 | {mainContent} 37 | 38 | {loading ? : null} 39 | {additionalContent} 40 | 41 | ); 42 | } 43 | -------------------------------------------------------------------------------- /docs/pages/getting_started/verify_tauri_signature.mdx: -------------------------------------------------------------------------------- 1 | # Verifying Release Binaries 2 | 3 | Each release includes `.asc` signature files alongside the binaries. 4 | 5 | ### 1. Import the signing key 6 | 7 | ```bash 8 | # Download the key from GitHub 9 | wget https://raw.githubusercontent.com/eigenwallet/core/master/utils/gpg_keys/binarybaron_and_einliterflasche.asc 10 | 11 | # Import it 12 | gpg --import binarybaron_and_einliterflasche.asc 13 | ``` 14 | 15 | ### 2. Download and verify the signature 16 | 17 | ```bash 18 | # Download both the binary and its signature 19 | wget https://github.com/eigenwallet/core/releases/download/3.1.3/eigenwallet_3.1.3_aarch64.dmg 20 | wget https://github.com/eigenwallet/core/releases/download/3.1.3/eigenwallet_3.1.3_aarch64.dmg.asc 21 | 22 | # Verify the signature 23 | gpg --verify eigenwallet_3.1.3_aarch64.dmg.asc eigenwallet_3.1.3_aarch64.dmg 24 | ``` 25 | 26 | Successful verification shows something like this: 27 | 28 | ``` 29 | gpg: Signature made Sat Oct 11 20:26:07 2025 CEST 30 | gpg: using RSA key 0518460FEBEC1DA14A155A7B44AE6F0B166AAD5A 31 | gpg: Good signature from "binarybaron-flatpak " [ultimate] 32 | ``` -------------------------------------------------------------------------------- /swap/src/protocol/alice.rs: -------------------------------------------------------------------------------- 1 | //! Run an XMR/BTC swap in the role of Alice. 2 | //! Alice holds XMR and wishes receive BTC. 3 | pub use crate::protocol::alice::swap::*; 4 | use crate::protocol::Database; 5 | use crate::{asb, monero}; 6 | use bitcoin_wallet::BitcoinWallet; 7 | use rust_decimal::Decimal; 8 | use std::sync::Arc; 9 | use swap_env::env::Config; 10 | pub use swap_machine::alice::*; 11 | use uuid::Uuid; 12 | 13 | pub mod swap; 14 | 15 | pub struct Swap { 16 | pub state: AliceState, 17 | pub event_loop_handle: asb::EventLoopHandle, 18 | pub bitcoin_wallet: Arc, 19 | pub monero_wallet: Arc, 20 | pub env_config: Config, 21 | pub developer_tip: TipConfig, 22 | pub swap_id: Uuid, 23 | pub db: Arc, 24 | } 25 | 26 | /// Configures how much the and where the user wants to send tips to 27 | /// 28 | /// The ratio is a number between 0 and 1 29 | /// 30 | /// ratio = 0 means that no tip will be sent 31 | /// ratio = 0.5 means that for a swap of 1 XMR, 0.5 XMR will be tipped 32 | #[derive(Clone)] 33 | pub struct TipConfig { 34 | pub ratio: Decimal, 35 | pub address: ::monero::Address, 36 | } 37 | -------------------------------------------------------------------------------- /swap-core/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "swap-core" 3 | version = "0.1.0" 4 | edition = "2024" 5 | 6 | [dependencies] 7 | anyhow = { workspace = true } 8 | 9 | # Bitcoin stuff 10 | bdk_wallet = { workspace = true, features = ["rusqlite"] } 11 | bitcoin = { workspace = true } 12 | bitcoin-wallet = { path = "../bitcoin-wallet" } 13 | curve25519-dalek = { workspace = true } 14 | ecdsa_fun = { workspace = true } 15 | monero = { workspace = true } 16 | sha2 = { workspace = true } 17 | 18 | # Serialization 19 | rust_decimal = { workspace = true } 20 | serde = { workspace = true } 21 | swap-serde = { path = "../swap-serde" } 22 | typeshare = { workspace = true } 23 | 24 | # Tracing 25 | tracing = { workspace = true } 26 | 27 | # Errors 28 | thiserror = { workspace = true } 29 | 30 | # Randomness 31 | rand = { workspace = true } 32 | rand_chacha = { workspace = true } 33 | 34 | [dev-dependencies] 35 | futures = { workspace = true } 36 | proptest = "1" 37 | serde_cbor = { workspace = true } 38 | serde_json = { workspace = true } 39 | swap-proptest = { path = "../swap-proptest" } 40 | tokio = { workspace = true } 41 | tracing-ext = { path = "../tracing-ext" } 42 | 43 | [lints] 44 | workspace = true 45 | -------------------------------------------------------------------------------- /monero-sys/patches/eigenwallet_0002_wallet2_increase_rpc_retries.patch: -------------------------------------------------------------------------------- 1 | diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp 2 | index d3e15a634..6edeebf35 100644 3 | --- a/src/wallet/wallet2.cpp 4 | +++ b/src/wallet/wallet2.cpp 5 | @@ -4229,7 +4229,7 @@ void wallet2::refresh(bool trusted_daemon, uint64_t start_height, uint64_t & blo 6 | { 7 | blocks_fetched += added_blocks; 8 | THROW_WALLET_EXCEPTION_IF(!waiter.wait(), error::wallet_internal_error, "Exception in thread pool"); 9 | - if(try_count < 3) 10 | + if(try_count < max_refresh_retries) 11 | { 12 | LOG_PRINT_L1("Another try pull_blocks (try_count=" << try_count << ")..."); 13 | first = true; 14 | diff --git a/src/wallet/wallet2.h b/src/wallet/wallet2.h 15 | index d3a799a48..12e67abee 100644 16 | --- a/src/wallet/wallet2.h 17 | +++ b/src/wallet/wallet2.h 18 | @@ -236,6 +236,7 @@ private: 19 | friend class wallet_device_callback; 20 | public: 21 | static constexpr const std::chrono::seconds rpc_timeout = std::chrono::minutes(3) + std::chrono::seconds(30); 22 | + static constexpr size_t max_refresh_retries = 10; 23 | 24 | enum RefreshType { 25 | RefreshFull, 26 | -------------------------------------------------------------------------------- /swap-controller/src/cli.rs: -------------------------------------------------------------------------------- 1 | use clap::{Parser, Subcommand}; 2 | 3 | #[derive(Parser)] 4 | #[command(name = "asb-controller")] 5 | #[command(about = "Control tool for ASB daemon")] 6 | pub struct Cli { 7 | /// RPC server URL 8 | #[arg(long, default_value = "http://127.0.0.1:9944")] 9 | pub url: String, 10 | 11 | /// Command to execute (defaults to interactive shell if omitted) 12 | #[command(subcommand)] 13 | pub cmd: Option, 14 | } 15 | 16 | #[derive(Subcommand, Clone)] 17 | pub enum Cmd { 18 | /// Check connection to ASB server 19 | CheckConnection, 20 | /// Get Bitcoin balance 21 | BitcoinBalance, 22 | /// Get Bitcoin descriptor containing private keys 23 | BitcoinSeed, 24 | /// Get Monero balance 25 | MoneroBalance, 26 | /// Get Monero wallet address 27 | MoneroAddress, 28 | /// Get Monero seed and restore height 29 | MoneroSeed, 30 | /// Get external multiaddresses 31 | Multiaddresses, 32 | /// Get peer ID 33 | PeerId, 34 | /// Get active connection count 35 | ActiveConnections, 36 | /// Get list of swaps 37 | GetSwaps, 38 | /// Show rendezvous registration status 39 | RegistrationStatus, 40 | } 41 | -------------------------------------------------------------------------------- /libp2p-rendezvous-node/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "rendezvous-node" 3 | version = "0.2.0" 4 | edition = "2018" 5 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 6 | 7 | [dependencies] 8 | # Tor 9 | arti-client = { workspace = true } 10 | tor-hsservice = { workspace = true } 11 | tor-rtcompat = { workspace = true } 12 | 13 | # Async 14 | futures = { workspace = true } 15 | tokio = { workspace = true, features = ["rt-multi-thread", "time", "macros", "sync", "process", "fs", "net", "io-util"] } 16 | 17 | # Libp2p 18 | libp2p = { workspace = true, features = ["rendezvous", "tcp", "yamux", "dns", "noise", "ping", "websocket", "tokio", "macros"] } 19 | libp2p-tor = { path = "../libp2p-tor", features = ["listen-onion-service"] } 20 | swap-p2p = { path = "../swap-p2p" } 21 | 22 | # Tracing 23 | tracing = { workspace = true, features = ["attributes"] } 24 | tracing-subscriber = { workspace = true, default-features = false, features = ["fmt", "ansi", "env-filter", "chrono", "tracing-log", "json"] } 25 | 26 | # Error 27 | anyhow = "1" 28 | 29 | # Other 30 | atty = "0.2" 31 | structopt = { version = "0.3", default-features = false } 32 | swap-env = { path = "../swap-env" } 33 | -------------------------------------------------------------------------------- /src-gui/src/renderer/components/pages/help/FeedbackInfoBox.tsx: -------------------------------------------------------------------------------- 1 | import { Button, Typography } from "@mui/material"; 2 | import { useState } from "react"; 3 | import FeedbackDialog from "renderer/components/modal/feedback/FeedbackDialog"; 4 | import InfoBox from "renderer/components/pages/swap/swap/components/InfoBox"; 5 | 6 | export default function FeedbackInfoBox() { 7 | const [showDialog, setShowDialog] = useState(false); 8 | 9 | return ( 10 | 14 | Your input is crucial to us! We'd love to hear your thoughts on Atomic 15 | Swaps. We personally read every response to improve the project. Got 16 | two minutes to share? 17 | 18 | } 19 | additionalContent={ 20 | <> 21 | setShowDialog(true)}> 22 | Give feedback 23 | 24 | setShowDialog(false)} 27 | /> 28 | > 29 | } 30 | icon={null} 31 | loading={false} 32 | /> 33 | ); 34 | } 35 | -------------------------------------------------------------------------------- /src-gui/src/renderer/components/pages/history/table/ExportLogsButton.tsx: -------------------------------------------------------------------------------- 1 | import { getLogsOfSwap, saveLogFiles } from "renderer/rpc"; 2 | import PromiseInvokeButton from "renderer/components/PromiseInvokeButton"; 3 | import { store } from "renderer/store/storeRenderer"; 4 | import { ButtonProps } from "@mui/material"; 5 | import { logsToRawString } from "utils/parseUtils"; 6 | 7 | interface ExportLogsButtonProps extends ButtonProps { 8 | swap_id: string; 9 | } 10 | 11 | export default function ExportLogsButton({ 12 | swap_id, 13 | ...buttonProps 14 | }: ExportLogsButtonProps) { 15 | async function handleExportLogs() { 16 | const swapLogs = await getLogsOfSwap(swap_id, false); 17 | const hashedDaemonLogs = store.getState().logs?.state.logs ?? []; 18 | const daemonLogs = hashedDaemonLogs.map((h) => h.log); 19 | 20 | const logContent = { 21 | swap_logs: logsToRawString(swapLogs.logs), 22 | daemon_logs: logsToRawString(daemonLogs), 23 | }; 24 | 25 | await saveLogFiles(`swap_${swap_id}_logs.zip`, logContent); 26 | } 27 | 28 | return ( 29 | 30 | Export Logs 31 | 32 | ); 33 | } 34 | -------------------------------------------------------------------------------- /bitcoin-wallet/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "bitcoin-wallet" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | [dependencies] 7 | anyhow = { workspace = true } 8 | async-trait = { workspace = true } 9 | backoff = { workspace = true } 10 | bdk = { workspace = true } 11 | bdk_chain = { workspace = true } 12 | bdk_core = { workspace = true } 13 | bdk_electrum = { workspace = true, features = ["use-rustls-ring"] } 14 | bdk_wallet = { workspace = true, features = ["rusqlite", "test-utils"] } 15 | bitcoin = { workspace = true } 16 | derive_builder = "0.20.2" 17 | electrum-pool = { path = "../electrum-pool" } 18 | futures = { workspace = true } 19 | moka = { version = "0.12", features = ["sync", "future"] } 20 | proptest = "1" 21 | reqwest = { workspace = true, features = ["http2", "rustls-tls-native-roots", "stream", "socks"] } 22 | rust_decimal = { version = "1", features = ["serde-float"] } 23 | rust_decimal_macros = "1" 24 | serde = { workspace = true } 25 | serde_json = { workspace = true } 26 | swap-env = { path = "../swap-env" } 27 | swap-proptest = { path = "../swap-proptest" } 28 | swap-serde = { path = "../swap-serde" } 29 | thiserror = { workspace = true } 30 | tokio = { workspace = true } 31 | tracing = { workspace = true } 32 | -------------------------------------------------------------------------------- /utils/gpg_keys/readme.md: -------------------------------------------------------------------------------- 1 | # GPG Signature Verification 2 | 3 | This directory contains public GPG keys for verifying release binary signatures. 4 | 5 | ## Verifying Release Binaries 6 | 7 | Each release includes `.asc` signature files alongside the binaries. 8 | 9 | ### 1. Import the signing key 10 | 11 | ```bash 12 | # Download the key from GitHub 13 | wget https://raw.githubusercontent.com/eigenwallet/core/master/utils/gpg_keys/binarybaron_and_einliterflasche.asc 14 | 15 | # Import it 16 | gpg --import binarybaron_and_einliterflasche.asc 17 | ``` 18 | 19 | ### 2. Download and verify the signature 20 | 21 | ```bash 22 | # Download both the binary archive and its signature 23 | wget https://github.com/eigenwallet/core/releases/download/3.0.7/asb_3.0.7_Linux_x86_64.tar 24 | wget https://github.com/eigenwallet/core/releases/download/3.0.7/asb_3.0.7_Linux_x86_64.tar.asc 25 | 26 | # Verify the signature 27 | gpg --verify asb_3.0.7_Linux_x86_64.tar.asc asb_3.0.7_Linux_x86_64.tar 28 | ``` 29 | 30 | Successful verification shows: 31 | 32 | ``` 33 | gpg: Signature made [date] 34 | gpg: Good signature from "..." 35 | ``` 36 | 37 | The warning `This key is not certified with a trusted signature` is expected unless you've explicitly trusted the key. 38 | -------------------------------------------------------------------------------- /libp2p-tor/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # 0.4.1 2 | 3 | - Remove double features: See [PR 21] 4 | - Correct typo in `src/lib.rs`: See [PR 21] 5 | - Update `CHANGELOG.md`: See [PR 21] 6 | 7 | [PR 21]: https://github.com/umgefahren/libp2p-tor/pull/21 8 | 9 | # 0.4.0 10 | 11 | ## Changes 12 | 13 | - Updated dependencies: See [PR 18] 14 | - [`arti-client` to `v0.24.0`] 15 | - [`libp2p` to `v0.53.0`] 16 | - [`tor-rtcompat` to `v0.24.0`] 17 | - Add tracing: See [PR 18] 18 | - Update CI: See [PR 20] 19 | - `actions/checkout` to `v4` 20 | - Remove `arduino/setup-protoc` 21 | 22 | ## First time contributor 23 | 24 | - @binarybaron 25 | 26 | Thanks! :rocket: 27 | 28 | [PR 18]: https://github.com/umgefahren/libp2p-tor/pull/18 29 | [PR 20]: https://github.com/umgefahren/libp2p-tor/pull/20 30 | 31 | # 0.3.0-alpha 32 | 33 | - Updated dependencies: See [PR 6]. 34 | - [`arti-client` to `v0.8` 35 | 36 | - Updated dependencies: See [PR 8]. 37 | - `libp2p-core` to `v0.39` 38 | - `libp2p` to `0.51` 39 | 40 | [PR 6]: https://github.com/umgefahren/libp2p-tor/pull/6 41 | [PR 8]: https://github.com/umgefahren/libp2p-tor/pull/8 42 | 43 | # 0.2.0-alpha 44 | 45 | - Updated dependencies: 46 | - [`libp2p` to `v0.50.0`](#2) 47 | - [`libp2p-core` to `v0.38.0`](#3) 48 | -------------------------------------------------------------------------------- /src-gui/src/renderer/components/pages/swap/swap/components/DepositAddressInfoBox.tsx: -------------------------------------------------------------------------------- 1 | import { Box } from "@mui/material"; 2 | import { ReactNode } from "react"; 3 | import ActionableMonospaceTextBox from "renderer/components/other/ActionableMonospaceTextBox"; 4 | import InfoBox from "./InfoBox"; 5 | import { Alert } from "@mui/material"; 6 | 7 | type Props = { 8 | title: string; 9 | address: string; 10 | additionalContent: ReactNode; 11 | icon: ReactNode; 12 | }; 13 | 14 | export default function DepositAddressInfoBox({ 15 | title, 16 | address, 17 | additionalContent, 18 | icon, 19 | }: Props) { 20 | return ( 21 | 29 | } 30 | additionalContent={ 31 | 39 | {additionalContent} 40 | 41 | } 42 | icon={icon} 43 | loading={false} 44 | /> 45 | ); 46 | } 47 | -------------------------------------------------------------------------------- /src-gui/src/renderer/components/other/MonospaceTextBox.tsx: -------------------------------------------------------------------------------- 1 | import { Box, Typography } from "@mui/material"; 2 | 3 | type Props = { 4 | children: React.ReactNode; 5 | light?: boolean; 6 | actions?: React.ReactNode; 7 | }; 8 | 9 | export default function MonospaceTextBox({ 10 | children, 11 | light = false, 12 | actions, 13 | }: Props) { 14 | return ( 15 | ({ 17 | display: "flex", 18 | alignItems: "center", 19 | justifyContent: "space-between", 20 | backgroundColor: light ? "transparent" : theme.palette.grey[900], 21 | borderRadius: 2, 22 | border: light ? `1px solid ${theme.palette.grey[800]}` : "none", 23 | padding: theme.spacing(1), 24 | gap: 1, 25 | })} 26 | > 27 | 38 | {children} 39 | 40 | {actions && ( 41 | {actions} 42 | )} 43 | 44 | ); 45 | } 46 | -------------------------------------------------------------------------------- /src-gui/src/renderer/components/pages/swap/swap/done/BitcoinPunishedPage.tsx: -------------------------------------------------------------------------------- 1 | import { Box, DialogContentText } from "@mui/material"; 2 | import FeedbackInfoBox from "renderer/components/pages/help/FeedbackInfoBox"; 3 | import { TauriSwapProgressEventExt } from "models/tauriModelExt"; 4 | 5 | export default function BitcoinPunishedPage({ 6 | state, 7 | }: { 8 | state: 9 | | TauriSwapProgressEventExt<"BtcPunished"> 10 | | TauriSwapProgressEventExt<"CooperativeRedeemRejected">; 11 | }) { 12 | return ( 13 | <> 14 | 15 | Unfortunately, the swap was unsuccessful. Since you did not refund in 16 | time, the Bitcoin has been lost. However, with the cooperation of the 17 | other party, you might still be able to redeem the Monero, although this 18 | is not guaranteed.{" "} 19 | {state.type === "CooperativeRedeemRejected" && ( 20 | <> 21 | 22 | We tried to redeem the Monero with the other party's help, but it 23 | was unsuccessful (reason: {state.content.reason}). Attempting again 24 | at a later time might yield success. 25 | > 26 | )} 27 | 28 | 29 | > 30 | ); 31 | } 32 | -------------------------------------------------------------------------------- /src-gui/src/renderer/components/navigation/RouteListItemIconButton.tsx: -------------------------------------------------------------------------------- 1 | import { ListItemIcon, ListItemText } from "@mui/material"; 2 | import { ReactNode } from "react"; 3 | import { useNavigate, useLocation } from "react-router-dom"; 4 | 5 | import ListItemButton from "@mui/material/ListItemButton"; 6 | 7 | export default function RouteListItemIconButton({ 8 | name, 9 | route, 10 | children, 11 | }: { 12 | name: string; 13 | route: string[] | string; 14 | children: ReactNode; 15 | }) { 16 | const navigate = useNavigate(); 17 | const location = useLocation(); 18 | 19 | const routeArray = Array.isArray(route) ? route : [route]; 20 | const firstRoute = routeArray[0]; 21 | const isSelected = routeArray.some((r) => location.pathname === r); 22 | 23 | return ( 24 | navigate(firstRoute)} 26 | key={name} 27 | sx={ 28 | isSelected 29 | ? { 30 | backgroundColor: "action.hover", 31 | "&:hover": { 32 | backgroundColor: "action.selected", 33 | }, 34 | } 35 | : undefined 36 | } 37 | > 38 | {children} 39 | 40 | 41 | ); 42 | } 43 | -------------------------------------------------------------------------------- /src-gui/src/renderer/components/icons/BitcoinIcon.tsx: -------------------------------------------------------------------------------- 1 | import SvgIcon, { SvgIconProps } from "@mui/material/SvgIcon"; 2 | 3 | export default function BitcoinIcon(props: SvgIconProps) { 4 | return ( 5 | 6 | 15 | 19 | 20 | 21 | ); 22 | } 23 | -------------------------------------------------------------------------------- /src-gui/src/renderer/components/inputs/CardSelection/CardSelectionContext.tsx: -------------------------------------------------------------------------------- 1 | import { createContext, useContext, useState, ReactNode } from "react"; 2 | 3 | interface CardSelectionContextType { 4 | selectedValue: string; 5 | setSelectedValue: (value: string) => void; 6 | } 7 | 8 | const CardSelectionContext = createContext< 9 | CardSelectionContextType | undefined 10 | >(undefined); 11 | 12 | export function CardSelectionProvider({ 13 | children, 14 | initialValue, 15 | onChange, 16 | }: { 17 | children: ReactNode; 18 | initialValue: string; 19 | onChange?: (value: string) => void; 20 | }) { 21 | const [selectedValue, setSelectedValue] = useState(initialValue); 22 | 23 | const handleValueChange = (value: string) => { 24 | setSelectedValue(value); 25 | onChange?.(value); 26 | }; 27 | 28 | return ( 29 | 32 | {children} 33 | 34 | ); 35 | } 36 | 37 | export function useCardSelection() { 38 | const context = useContext(CardSelectionContext); 39 | if (context === undefined) { 40 | throw new Error( 41 | "useCardSelection must be used within a CardSelectionProvider", 42 | ); 43 | } 44 | return context; 45 | } 46 | -------------------------------------------------------------------------------- /src-gui/src/renderer/components/modal/introduction/slides/Slide07_ReachOut.tsx: -------------------------------------------------------------------------------- 1 | import { Box, Typography } from "@mui/material"; 2 | import SlideTemplate from "./SlideTemplate"; 3 | import imagePath from "assets/groupWithChatbubbles.png"; 4 | import GitHubIcon from "@mui/icons-material/GitHub"; 5 | import MatrixIcon from "renderer/components/icons/MatrixIcon"; 6 | import LinkIconButton from "renderer/components/icons/LinkIconButton"; 7 | import { IntroSlideProps } from "./SlideTypes"; 8 | 9 | export default function Slide02_ChooseAMaker(props: IntroSlideProps) { 10 | return ( 11 | 17 | 18 | We would love to hear about your experience with Unstoppable Swap and 19 | invite you to join our community. 20 | 21 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | ); 35 | } 36 | -------------------------------------------------------------------------------- /src-tauri/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "unstoppableswap-gui-rs" 3 | version = "3.5.2" 4 | authors = ["binarybaron", "einliterflasche", "unstoppableswap"] 5 | edition = "2021" 6 | description = "GUI for XMR<>BTC Atomic Swaps written in Rust" 7 | 8 | [lib] 9 | name = "unstoppableswap_gui_rs_lib" 10 | crate-type = ["rlib", "staticlib", "cdylib"] 11 | 12 | [build-dependencies] 13 | tauri-build = { version = "2.*", features = ["config-json5"] } 14 | 15 | [dependencies] 16 | swap = { path = "../swap", features = [ "tauri" ] } 17 | swap-p2p = { path = "../swap-p2p" } 18 | dfx-swiss-sdk = { workspace = true } 19 | 20 | rustls = { version = "0.23.26", default-features = false, features = ["ring"] } 21 | serde = { version = "1", features = [ "derive" ] } 22 | serde_json = "1" 23 | 24 | tracing = "0.1" 25 | zip = "4.0.0" 26 | 27 | # Tauri 28 | tauri = { version = "2.8.0", features = [ "config-json5" ] } 29 | tauri-plugin-clipboard-manager = "2.*" 30 | tauri-plugin-dialog = "2.3.3" 31 | tauri-plugin-opener = "2.*" 32 | tauri-plugin-process = "2.*" 33 | tauri-plugin-store = "2.*" 34 | tauri-plugin-updater = "2.*" 35 | 36 | # Tokio 37 | tokio = { workspace = true } 38 | tokio-util = { workspace = true } 39 | 40 | [target."cfg(not(any(target_os = \"android\", target_os = \"ios\")))".dependencies] 41 | tauri-plugin-cli = "2.*" 42 | tauri-plugin-single-instance = "2.*" 43 | -------------------------------------------------------------------------------- /monero-sys/tests/special_paths.rs: -------------------------------------------------------------------------------- 1 | use monero::Network; 2 | use monero_sys::{Daemon, WalletHandle}; 3 | use tempfile::tempdir; 4 | 5 | #[tokio::test] 6 | async fn test_wallet_with_special_paths() { 7 | let tempdir = tempdir().unwrap(); 8 | 9 | let special_paths = vec![ 10 | "path_with_unicode_漢字", 11 | "path_with_emoji_😊", 12 | "path with space", 13 | "path-with-hyphen", 14 | ]; 15 | 16 | let daemon = Daemon::try_from("https://moneronode.org:18081").unwrap(); 17 | 18 | let futures = special_paths 19 | .into_iter() 20 | .map(|path| { 21 | let path = tempdir.path().join(path); 22 | let daemon = daemon.clone(); 23 | 24 | tokio::spawn(async move { 25 | let result = WalletHandle::open_or_create( 26 | path.display().to_string(), 27 | daemon, 28 | Network::Mainnet, 29 | true, 30 | ) 31 | .await; 32 | 33 | assert!( 34 | result.is_ok(), 35 | "Failed to create wallet in path: `{}`", 36 | path.display() 37 | ); 38 | }) 39 | }) 40 | .collect::>(); 41 | 42 | futures::future::try_join_all(futures).await.unwrap(); 43 | } 44 | -------------------------------------------------------------------------------- /src-gui/src/renderer/components/icons/MatrixIcon.tsx: -------------------------------------------------------------------------------- 1 | import SvgIcon, { SvgIconProps } from "@mui/material/SvgIcon"; 2 | 3 | export default function MatrixIcon(props: SvgIconProps) { 4 | return ( 5 | 6 | 7 | 8 | 9 | 10 | ); 11 | } 12 | -------------------------------------------------------------------------------- /src-gui/src/renderer/components/pages/wallet/components/WalletActionButtons.tsx: -------------------------------------------------------------------------------- 1 | import { Box, Chip } from "@mui/material"; 2 | import { Send as SendIcon } from "@mui/icons-material"; 3 | import { useState } from "react"; 4 | import { useAppSelector } from "store/hooks"; 5 | import WithdrawDialog from "../../../modal/wallet/WithdrawDialog"; 6 | import WalletDescriptorButton from "./WalletDescriptorButton"; 7 | 8 | export default function WalletActionButtons() { 9 | const [showDialog, setShowDialog] = useState(false); 10 | const balance = useAppSelector((state) => state.bitcoinWallet.balance); 11 | 12 | return ( 13 | <> 14 | setShowDialog(false)} /> 15 | 16 | 24 | } 26 | label="Sweep" 27 | variant="button" 28 | clickable 29 | onClick={() => setShowDialog(true)} 30 | disabled={balance === null || balance <= 0} 31 | /> 32 | 33 | 34 | 35 | > 36 | ); 37 | } 38 | -------------------------------------------------------------------------------- /monero-sys/patches/0003-include-locale-only-when-targeting-WIN32.patch: -------------------------------------------------------------------------------- 1 | From 6d9116c6d57d72f9bab5d28740209ffdefc9d197 Mon Sep 17 00:00:00 2001 2 | From: Czarek Nakamoto 3 | Date: Mon, 18 Nov 2024 10:57:37 -0500 4 | Subject: [PATCH] include locale only when targeting WIN32 5 | 6 | 7 | diff --git a/CMakeLists.txt b/CMakeLists.txt 8 | index 46bd5eb1b..d5cfecf39 100644 9 | --- a/CMakeLists.txt 10 | +++ b/CMakeLists.txt 11 | @@ -1085,7 +1085,11 @@ if(NOT Boost_FOUND) 12 | elseif(Boost_FOUND) 13 | message(STATUS "Found Boost Version: ${Boost_VERSION_STRING}") 14 | 15 | - set(BOOST_COMPONENTS filesystem thread date_time chrono serialization program_options locale) 16 | + set(BOOST_COMPONENTS filesystem thread date_time chrono serialization program_options) 17 | + 18 | + if(WIN32) 19 | + list(APPEND BOOST_COMPONENTS locale) 20 | + endif() 21 | 22 | # Boost System is header-only since 1.69 23 | if (Boost_VERSION_STRING VERSION_LESS 1.69.0) 24 | diff --git a/src/wallet/api/wallet.cpp b/src/wallet/api/wallet.cpp 25 | index 96393eaaa..b6f527ae5 100644 26 | --- a/src/wallet/api/wallet.cpp 27 | +++ b/src/wallet/api/wallet.cpp 28 | @@ -48,7 +48,10 @@ 29 | #include 30 | #include 31 | 32 | +#ifdef WIN32 33 | #include 34 | +#endif 35 | + 36 | #include 37 | 38 | using namespace std; -------------------------------------------------------------------------------- /swap/migrations/20250530215011_multiple_monero_receive_addresses.sql: -------------------------------------------------------------------------------- 1 | -- The user can now have multiple monero receive addresses 2 | -- for a single swap 3 | -- Each address has a percentage (0 to 1) of the amount they'll receive of the total of the swap amount 4 | -- The sum of the percentages must for a single swap MUST be 1 5 | -- Add percentage column with default value of 1.0 6 | ALTER TABLE monero_addresses ADD COLUMN percentage REAL NOT NULL DEFAULT 1.0; 7 | 8 | -- SQLite doesn't support dropping PRIMARY KEY constraint directly 9 | -- We need to recreate the table without the PRIMARY KEY on swap_id 10 | CREATE TABLE monero_addresses_temp 11 | ( 12 | swap_id TEXT NOT NULL, 13 | address TEXT NOT NULL, 14 | percentage REAL NOT NULL DEFAULT 1.0, 15 | label TEXT NOT NULL DEFAULT 'user address' 16 | ); 17 | 18 | -- Copy data from the original table 19 | INSERT INTO monero_addresses_temp (swap_id, address, percentage) 20 | SELECT swap_id, address, percentage FROM monero_addresses; 21 | 22 | -- Drop the original table 23 | DROP TABLE monero_addresses; 24 | 25 | -- Rename the temporary table 26 | ALTER TABLE monero_addresses_temp RENAME TO monero_addresses; 27 | 28 | -- Create an index on swap_id for performance 29 | CREATE INDEX idx_monero_addresses_swap_id ON monero_addresses(swap_id); -------------------------------------------------------------------------------- /monero-rpc-pool/migrations/20250618212026_initial_schema.sql: -------------------------------------------------------------------------------- 1 | -- Add migration script here 2 | 3 | -- Create monero_nodes table - stores node identity and current state 4 | CREATE TABLE IF NOT EXISTS monero_nodes ( 5 | id INTEGER PRIMARY KEY AUTOINCREMENT, 6 | scheme TEXT NOT NULL, 7 | host TEXT NOT NULL, 8 | port INTEGER NOT NULL, 9 | full_url TEXT NOT NULL UNIQUE, 10 | network TEXT NOT NULL, -- mainnet/stagenet/testnet - always known at insertion time 11 | first_seen_at TEXT NOT NULL, 12 | created_at TEXT NOT NULL DEFAULT (datetime('now')), 13 | updated_at TEXT NOT NULL DEFAULT (datetime('now')) 14 | ); 15 | 16 | -- Create health_checks table - stores raw event data 17 | CREATE TABLE IF NOT EXISTS health_checks ( 18 | id INTEGER PRIMARY KEY AUTOINCREMENT, 19 | node_id INTEGER NOT NULL, 20 | timestamp TEXT NOT NULL, 21 | was_successful BOOLEAN NOT NULL, 22 | latency_ms REAL, 23 | FOREIGN KEY (node_id) REFERENCES monero_nodes(id) ON DELETE CASCADE 24 | ); 25 | 26 | -- Create indexes for performance 27 | CREATE INDEX IF NOT EXISTS idx_nodes_full_url ON monero_nodes(full_url); 28 | CREATE INDEX IF NOT EXISTS idx_nodes_network ON monero_nodes(network); 29 | CREATE INDEX IF NOT EXISTS idx_health_checks_node_id ON health_checks(node_id); 30 | CREATE INDEX IF NOT EXISTS idx_health_checks_timestamp ON health_checks(timestamp); 31 | -------------------------------------------------------------------------------- /src-gui/src/renderer/components/snackbar/GlobalSnackbarProvider.tsx: -------------------------------------------------------------------------------- 1 | import { IconButton, styled } from "@mui/material"; 2 | import { Close } from "@mui/icons-material"; 3 | import { 4 | MaterialDesignContent, 5 | SnackbarKey, 6 | SnackbarProvider, 7 | useSnackbar, 8 | } from "notistack"; 9 | import { ReactNode } from "react"; 10 | 11 | const StyledMaterialDesignContent = styled(MaterialDesignContent)(() => ({ 12 | "&.notistack-MuiContent": { 13 | maxWidth: "50vw", 14 | }, 15 | })); 16 | 17 | function CloseSnackbarButton({ snackbarId }: { snackbarId: SnackbarKey }) { 18 | const { closeSnackbar } = useSnackbar(); 19 | 20 | return ( 21 | closeSnackbar(snackbarId)} size="large"> 22 | 23 | 24 | ); 25 | } 26 | 27 | export default function GlobalSnackbarManager({ 28 | children, 29 | }: { 30 | children: ReactNode; 31 | }) { 32 | return ( 33 | } 35 | Components={{ 36 | success: StyledMaterialDesignContent, 37 | error: StyledMaterialDesignContent, 38 | default: StyledMaterialDesignContent, 39 | info: StyledMaterialDesignContent, 40 | warning: StyledMaterialDesignContent, 41 | }} 42 | > 43 | {children} 44 | 45 | ); 46 | } 47 | -------------------------------------------------------------------------------- /src-gui/src/renderer/components/other/ExpandableSearchBox.tsx: -------------------------------------------------------------------------------- 1 | import { Box, IconButton, TextField } from "@mui/material"; 2 | import CloseIcon from "@mui/icons-material/Close"; 3 | import SearchIcon from "@mui/icons-material/Search"; 4 | import { useState } from "react"; 5 | 6 | export function ExpandableSearchBox({ 7 | query, 8 | setQuery, 9 | }: { 10 | query: string; 11 | setQuery: (query: string) => void; 12 | }) { 13 | const [expanded, setExpanded] = useState(false); 14 | 15 | return ( 16 | 17 | 18 | {expanded ? ( 19 | <> 20 | setQuery(e.target.value)} 23 | autoFocus 24 | size="small" 25 | /> 26 | { 28 | setExpanded(false); 29 | setQuery(""); 30 | }} 31 | size="small" 32 | > 33 | 34 | 35 | > 36 | ) : ( 37 | setExpanded(true)} size="small"> 38 | 39 | 40 | )} 41 | 42 | 43 | ); 44 | } 45 | -------------------------------------------------------------------------------- /swap/src/network/transport.rs: -------------------------------------------------------------------------------- 1 | use anyhow::Result; 2 | use futures::{AsyncRead, AsyncWrite}; 3 | use libp2p::core::muxing::StreamMuxerBox; 4 | use libp2p::core::transport::Boxed; 5 | use libp2p::core::upgrade::Version; 6 | use libp2p::noise; 7 | use libp2p::{identity, yamux, PeerId, Transport}; 8 | use std::time::Duration; 9 | 10 | const AUTH_AND_MULTIPLEX_TIMEOUT: Duration = Duration::from_secs(60); 11 | 12 | /// "Completes" a transport by applying the authentication and multiplexing 13 | /// upgrades. 14 | /// 15 | /// Even though the actual transport technology in use might be different, for 16 | /// two libp2p applications to be compatible, the authentication and 17 | /// multiplexing upgrades need to be compatible. 18 | pub fn authenticate_and_multiplex( 19 | transport: Boxed, 20 | identity: &identity::Keypair, 21 | ) -> Result> 22 | where 23 | T: AsyncRead + AsyncWrite + Unpin + Send + 'static, 24 | { 25 | let auth_upgrade = noise::Config::new(identity)?; 26 | let multiplex_upgrade = yamux::Config::default(); 27 | 28 | let transport = transport 29 | .upgrade(Version::V1) 30 | .authenticate(auth_upgrade) 31 | .multiplex(multiplex_upgrade) 32 | .timeout(AUTH_AND_MULTIPLEX_TIMEOUT) 33 | .map(|(peer, muxer), _| (peer, StreamMuxerBox::new(muxer))) 34 | .boxed(); 35 | 36 | Ok(transport) 37 | } 38 | --------------------------------------------------------------------------------
GUI for XMR<>BTC Atomic Swaps written in Rust