feat(gui): Display provider spread to user (#124)

This commit is contained in:
binarybaron 2024-10-22 12:04:37 +02:00 committed by GitHub
parent 1acb597a34
commit 584cc41411
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 60 additions and 3 deletions

View file

@ -58,10 +58,30 @@ async function fetchCurrencyUsdPrice(currency: string): Promise<number> {
}
}
export async function fetchXmrBtcRate(): Promise<number> {
try {
const response = await fetch('https://api.kraken.com/0/public/Ticker?pair=XMRXBT');
const data = await response.json();
if (data.error && data.error.length > 0) {
throw new Error(`Kraken API error: ${data.error[0]}`);
}
const result = data.result.XXMRXXBT;
const lastTradePrice = parseFloat(result.c[0]);
return lastTradePrice;
} catch (error) {
console.error('Error fetching XMR/BTC rate from Kraken:', error);
throw error;
}
}
export async function fetchBtcPrice(): Promise<number> {
return fetchCurrencyUsdPrice("bitcoin");
}
export async function fetchXmrPrice(): Promise<number> {
return fetchCurrencyUsdPrice("monero");
}
}

View file

@ -9,6 +9,7 @@ import {
import { satsToBtc, secondsToDays } from "utils/conversionUtils";
import { isProviderOutdated } from 'utils/multiAddrUtils';
import WarningIcon from '@material-ui/icons/Warning';
import { useAppSelector } from "store/hooks";
const useStyles = makeStyles((theme) => ({
content: {
@ -25,6 +26,24 @@ const useStyles = makeStyles((theme) => ({
},
}));
function ProviderSpreadChip({ provider }: { provider: ExtendedProviderStatus }) {
const xmrBtcPrice = useAppSelector(s => s.rates?.xmrBtcRate);
if (xmrBtcPrice === null) {
return null;
}
const providerPrice = satsToBtc(provider.price);
const spread = ((providerPrice - xmrBtcPrice) / xmrBtcPrice) * 100;
return (
<Tooltip title="The spread is the difference between the provider's exchange rate and the market rate. A high spread indicates that the provider is charging more than the market rate.">
<Chip label={`Spread: ${spread.toFixed(2)} %`} />
</Tooltip>
);
}
export default function ProviderInfo({
provider,
}: {
@ -78,6 +97,7 @@ export default function ProviderInfo({
<Chip label="Outdated" icon={<WarningIcon />} color="primary" />
</Tooltip>
)}
<ProviderSpreadChip provider={provider} />
</Box>
</Box>
);

View file

@ -6,12 +6,13 @@ import {
registryConnectionFailed,
setRegistryProviders,
} from "store/features/providersSlice";
import { setBtcPrice, setXmrPrice } from "store/features/ratesSlice";
import { setBtcPrice, setXmrBtcRate, setXmrPrice } from "store/features/ratesSlice";
import logger from "../utils/logger";
import {
fetchAlertsViaHttp,
fetchBtcPrice,
fetchProvidersViaHttp,
fetchXmrBtcRate,
fetchXmrPrice,
} from "./api";
import App from "./components/App";
@ -64,6 +65,14 @@ async function fetchInitialData() {
} catch (e) {
logger.error(e, "Error retrieving fiat prices");
}
try {
const xmrBtcRate = await fetchXmrBtcRate();
store.dispatch(setXmrBtcRate(xmrBtcRate));
logger.info({ xmrBtcRate }, "Fetched XMR/BTC rate");
} catch (e) {
logger.error(e, "Error retrieving XMR/BTC rate");
}
}
fetchInitialData();

View file

@ -1,13 +1,18 @@
import { createSlice, PayloadAction } from "@reduxjs/toolkit";
export interface RatesState {
// USD price of 1 BTC
btcPrice: number | null;
// USD price of 1 XMR
xmrPrice: number | null;
// XMR/BTC exchange rate
xmrBtcRate: number | null;
}
const initialState: RatesState = {
btcPrice: null,
xmrPrice: null,
xmrBtcRate: null,
};
const ratesSlice = createSlice({
@ -20,9 +25,12 @@ const ratesSlice = createSlice({
setXmrPrice: (state, action: PayloadAction<number>) => {
state.xmrPrice = action.payload;
},
setXmrBtcRate: (state, action: PayloadAction<number>) => {
state.xmrBtcRate = action.payload;
},
},
});
export const { setBtcPrice, setXmrPrice } = ratesSlice.actions;
export const { setBtcPrice, setXmrPrice, setXmrBtcRate } = ratesSlice.actions;
export default ratesSlice.reducer;