mirror of
https://github.com/comit-network/xmr-btc-swap.git
synced 2025-08-22 21:15:21 -04:00
feat(gui): Allow discovery of sellers via connecting to rendezvous point (#83)
We, - add a new list_sellers Tauri IPC command - we rename the Seller struct to AliceAddress to name clash
This commit is contained in:
parent
beccd23280
commit
167e031172
13 changed files with 164 additions and 57 deletions
|
@ -1,3 +1,9 @@
|
|||
// This file is responsible for making HTTP requests to the Unstoppable API and to the CoinGecko API.
|
||||
// The APIs are used to:
|
||||
// - fetch provider status from the public registry
|
||||
// - fetch alerts to be displayed to the user
|
||||
// - and to submit feedback
|
||||
// - fetch currency rates from CoinGecko
|
||||
import { Alert, ExtendedProviderStatus } from "models/apiModel";
|
||||
|
||||
const API_BASE_URL = "https://api.unstoppableswap.net";
|
||||
|
|
|
@ -11,11 +11,15 @@ import {
|
|||
TextField,
|
||||
Theme,
|
||||
} from "@material-ui/core";
|
||||
import { Multiaddr } from "multiaddr";
|
||||
import { ListSellersResponse } from "models/tauriModel";
|
||||
import { useSnackbar } from "notistack";
|
||||
import { ChangeEvent, useState } from "react";
|
||||
import TruncatedText from "renderer/components/other/TruncatedText";
|
||||
import PromiseInvokeButton from "renderer/components/PromiseInvokeButton";
|
||||
import { listSellersAtRendezvousPoint } from "renderer/rpc";
|
||||
import { discoveredProvidersByRendezvous } from "store/features/providersSlice";
|
||||
import { useAppDispatch } from "store/hooks";
|
||||
import { isValidMultiAddressWithPeerId } from "utils/parseUtils";
|
||||
|
||||
const PRESET_RENDEZVOUS_POINTS = [
|
||||
"/dns4/discover.unstoppableswap.net/tcp/8888/p2p/12D3KooWA6cnqJpVnreBVnoro8midDL9Lpzmg8oJPoAGi7YYaamE",
|
||||
|
@ -42,27 +46,23 @@ export default function ListSellersDialog({
|
|||
const classes = useStyles();
|
||||
const [rendezvousAddress, setRendezvousAddress] = useState("");
|
||||
const { enqueueSnackbar } = useSnackbar();
|
||||
const dispatch = useAppDispatch();
|
||||
|
||||
function handleMultiAddrChange(event: ChangeEvent<HTMLInputElement>) {
|
||||
setRendezvousAddress(event.target.value);
|
||||
}
|
||||
|
||||
function getMultiAddressError(): string | null {
|
||||
try {
|
||||
const multiAddress = new Multiaddr(rendezvousAddress);
|
||||
if (!multiAddress.protoNames().includes("p2p")) {
|
||||
return "The multi address must contain the peer id (/p2p/)";
|
||||
}
|
||||
return null;
|
||||
} catch {
|
||||
return "Not a valid multi address";
|
||||
}
|
||||
return isValidMultiAddressWithPeerId(rendezvousAddress) ? null : "Address is invalid or missing peer ID";
|
||||
}
|
||||
|
||||
function handleSuccess(amountOfSellers: number) {
|
||||
function handleSuccess({ sellers }: ListSellersResponse) {
|
||||
dispatch(discoveredProvidersByRendezvous(sellers));
|
||||
|
||||
const discoveredSellersCount = sellers.length;
|
||||
let message: string;
|
||||
|
||||
switch (amountOfSellers) {
|
||||
switch (discoveredSellersCount) {
|
||||
case 0:
|
||||
message = `No providers were discovered at the rendezvous point`;
|
||||
break;
|
||||
|
@ -70,7 +70,7 @@ export default function ListSellersDialog({
|
|||
message = `Discovered one provider at the rendezvous point`;
|
||||
break;
|
||||
default:
|
||||
message = `Discovered ${amountOfSellers} providers at the rendezvous point`;
|
||||
message = `Discovered ${discoveredSellersCount} providers at the rendezvous point`;
|
||||
}
|
||||
|
||||
enqueueSnackbar(message, {
|
||||
|
@ -119,12 +119,13 @@ export default function ListSellersDialog({
|
|||
<Button onClick={onClose}>Cancel</Button>
|
||||
<PromiseInvokeButton
|
||||
variant="contained"
|
||||
disabled={!(rendezvousAddress && !getMultiAddressError())}
|
||||
disabled={
|
||||
// We disable the button if the multiaddress is invalid
|
||||
getMultiAddressError() !== null
|
||||
}
|
||||
color="primary"
|
||||
onSuccess={handleSuccess}
|
||||
onInvoke={() => {
|
||||
throw new Error("Not implemented");
|
||||
}}
|
||||
onInvoke={() => listSellersAtRendezvousPoint(rendezvousAddress)}
|
||||
>
|
||||
Connect
|
||||
</PromiseInvokeButton>
|
||||
|
|
|
@ -39,7 +39,7 @@ export default function ProviderInfo({
|
|||
{provider.multiAddr}
|
||||
</Typography>
|
||||
<Typography color="textSecondary" gutterBottom>
|
||||
<TruncatedText limit={12}>{provider.peerId}</TruncatedText>
|
||||
<TruncatedText>{provider.peerId}</TruncatedText>
|
||||
</Typography>
|
||||
<Typography variant="caption">
|
||||
Exchange rate:{" "}
|
||||
|
|
|
@ -177,7 +177,7 @@ function HasNoProvidersSwapWidget() {
|
|||
const forceShowDialog = useAppSelector((state) => state.swap.state !== null);
|
||||
const isPublicRegistryDown = useAppSelector((state) =>
|
||||
isRegistryDown(
|
||||
state.providers.registry.failedReconnectAttemptsSinceLastSuccess,
|
||||
state.providers.registry.connectionFailsCount,
|
||||
),
|
||||
);
|
||||
const classes = useStyles();
|
||||
|
@ -255,7 +255,7 @@ export default function SwapWidget() {
|
|||
(state) =>
|
||||
state.providers.registry.providers === null &&
|
||||
!isRegistryDown(
|
||||
state.providers.registry.failedReconnectAttemptsSinceLastSuccess,
|
||||
state.providers.registry.connectionFailsCount,
|
||||
),
|
||||
);
|
||||
|
||||
|
|
|
@ -2,7 +2,10 @@ import { createRoot } from "react-dom/client";
|
|||
import { Provider } from "react-redux";
|
||||
import { PersistGate } from "redux-persist/integration/react";
|
||||
import { setAlerts } from "store/features/alertsSlice";
|
||||
import { setRegistryProviders } from "store/features/providersSlice";
|
||||
import {
|
||||
registryConnectionFailed,
|
||||
setRegistryProviders,
|
||||
} from "store/features/providersSlice";
|
||||
import { setBtcPrice, setXmrPrice } from "store/features/ratesSlice";
|
||||
import logger from "../utils/logger";
|
||||
import {
|
||||
|
@ -12,18 +15,9 @@ import {
|
|||
fetchXmrPrice,
|
||||
} from "./api";
|
||||
import App from "./components/App";
|
||||
import {
|
||||
checkBitcoinBalance,
|
||||
getAllSwapInfos,
|
||||
initEventListeners,
|
||||
} from "./rpc";
|
||||
import { initEventListeners } from "./rpc";
|
||||
import { persistor, store } from "./store/storeRenderer";
|
||||
|
||||
setInterval(() => {
|
||||
checkBitcoinBalance();
|
||||
getAllSwapInfos();
|
||||
}, 30 * 1000);
|
||||
|
||||
const container = document.getElementById("root");
|
||||
const root = createRoot(container!);
|
||||
root.render(
|
||||
|
@ -44,6 +38,7 @@ async function fetchInitialData() {
|
|||
"Fetched providers via UnstoppableSwap HTTP API",
|
||||
);
|
||||
} catch (e) {
|
||||
store.dispatch(registryConnectionFailed());
|
||||
logger.error(e, "Failed to fetch providers via UnstoppableSwap HTTP API");
|
||||
}
|
||||
|
||||
|
|
|
@ -8,6 +8,7 @@ import {
|
|||
GetLogsArgs,
|
||||
GetLogsResponse,
|
||||
GetSwapInfoResponse,
|
||||
ListSellersArgs,
|
||||
MoneroRecoveryArgs,
|
||||
ResumeSwapArgs,
|
||||
ResumeSwapResponse,
|
||||
|
@ -27,6 +28,7 @@ import { store } from "./store/storeRenderer";
|
|||
import { Provider } from "models/apiModel";
|
||||
import { providerToConcatenatedMultiAddr } from "utils/multiAddrUtils";
|
||||
import { MoneroRecoveryResponse } from "models/rpcModel";
|
||||
import { ListSellersResponse } from "../models/tauriModel";
|
||||
|
||||
export async function initEventListeners() {
|
||||
// This operation is in-expensive
|
||||
|
@ -144,3 +146,11 @@ export async function getLogsOfSwap(
|
|||
redact,
|
||||
});
|
||||
}
|
||||
|
||||
export async function listSellersAtRendezvousPoint(
|
||||
rendezvousPointAddress: string,
|
||||
): Promise<ListSellersResponse> {
|
||||
return await invoke<ListSellersArgs, ListSellersResponse>("list_sellers", {
|
||||
rendezvous_point: rendezvousPointAddress,
|
||||
});
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue