mirror of
https://github.com/RoboSats/robosats.git
synced 2024-09-11 14:05:51 +03:00
Fix bugs
This commit is contained in:
parent
166018d86f
commit
9008e98214
@ -21,13 +21,13 @@ const App = (): JSX.Element => {
|
||||
<Suspense fallback='loading'>
|
||||
<I18nextProvider i18n={i18n}>
|
||||
<AppContextProvider>
|
||||
<GarageContextProvider>
|
||||
<FederationContextProvider>
|
||||
<FederationContextProvider>
|
||||
<GarageContextProvider>
|
||||
<CssBaseline />
|
||||
{window.NativeRobosats === undefined ? <HostAlert /> : <TorConnectionBadge />}
|
||||
<Main />
|
||||
</FederationContextProvider>
|
||||
</GarageContextProvider>
|
||||
</GarageContextProvider>
|
||||
</FederationContextProvider>
|
||||
</AppContextProvider>
|
||||
</I18nextProvider>
|
||||
</Suspense>
|
||||
|
@ -12,12 +12,10 @@ import BookTable from '../../components/BookTable';
|
||||
import { BarChart, FormatListBulleted, Map } from '@mui/icons-material';
|
||||
import { AppContext, type UseAppStoreType } from '../../contexts/AppContext';
|
||||
import MapChart from '../../components/Charts/MapChart';
|
||||
import { FederationContext, type UseFederationStoreType } from '../../contexts/FederationContext';
|
||||
import { GarageContext, type UseGarageStoreType } from '../../contexts/GarageContext';
|
||||
|
||||
const BookPage = (): JSX.Element => {
|
||||
const { windowSize } = useContext<UseAppStoreType>(AppContext);
|
||||
const { setDelay } = useContext<UseFederationStoreType>(FederationContext);
|
||||
const { garage } = useContext<UseGarageStoreType>(GarageContext);
|
||||
const { t } = useTranslation();
|
||||
const navigate = useNavigate();
|
||||
@ -32,7 +30,6 @@ const BookPage = (): JSX.Element => {
|
||||
|
||||
const onOrderClicked = function (id: number, shortAlias: string): void {
|
||||
if (garage.getSlot()?.hashId) {
|
||||
setDelay(10000);
|
||||
navigate(`/order/${shortAlias}/${id}`);
|
||||
} else {
|
||||
setOpenNoRobot(true);
|
||||
|
@ -14,7 +14,7 @@ import { GarageContext, type UseGarageStoreType } from '../../contexts/GarageCon
|
||||
|
||||
const MakerPage = (): JSX.Element => {
|
||||
const { fav, windowSize, navbarHeight } = useContext<UseAppStoreType>(AppContext);
|
||||
const { federation, setDelay } = useContext<UseFederationStoreType>(FederationContext);
|
||||
const { federation } = useContext<UseFederationStoreType>(FederationContext);
|
||||
const { garage, maker } = useContext<UseGarageStoreType>(GarageContext);
|
||||
const { t } = useTranslation();
|
||||
const navigate = useNavigate();
|
||||
@ -53,7 +53,6 @@ const MakerPage = (): JSX.Element => {
|
||||
|
||||
const onOrderClicked = function (id: number, shortAlias: string): void {
|
||||
if (garage.getSlot()?.hashId) {
|
||||
setDelay(10000);
|
||||
navigate(`/order/${shortAlias}/${id}`);
|
||||
} else {
|
||||
setOpenNoRobot(true);
|
||||
|
@ -30,19 +30,13 @@ const OrderPage = (): JSX.Element => {
|
||||
useEffect(() => {
|
||||
const shortAlias = params.shortAlias;
|
||||
const orderId = Number(params.orderId);
|
||||
const robot = garage.getSlot()?.getRobot();
|
||||
if (
|
||||
robot &&
|
||||
orderId &&
|
||||
shortAlias &&
|
||||
currentOrder?.id !== orderId &&
|
||||
currentOrder?.shortAlias !== shortAlias
|
||||
) {
|
||||
const slot = garage.getSlot();
|
||||
if (slot?.token && currentOrder?.id !== orderId && currentOrder?.shortAlias !== shortAlias) {
|
||||
const order = new Order({ id: orderId, shortAlias });
|
||||
void order.fecth(federation, robot).then((updatedOrder) => {
|
||||
void order.fecth(federation, slot).then((updatedOrder) => {
|
||||
if (Number(params.orderId) === updatedOrder.id) {
|
||||
setCurrentOrder(order);
|
||||
garage.updateOrder(order);
|
||||
slot.updateSlotFromOrder(order);
|
||||
}
|
||||
});
|
||||
}
|
||||
@ -51,7 +45,7 @@ const OrderPage = (): JSX.Element => {
|
||||
return () => {
|
||||
setCurrentOrder(null);
|
||||
};
|
||||
}, []);
|
||||
}, [params.orderId]);
|
||||
|
||||
const onClickCoordinator = function (): void {
|
||||
if (currentOrder?.shortAlias != null) {
|
||||
|
@ -45,7 +45,6 @@ const RobotPage = (): JSX.Element => {
|
||||
if (token !== undefined && token !== null && page === 'robot') {
|
||||
setInputToken(token);
|
||||
if (window.NativeRobosats === undefined || torStatus === 'ON' || !settings.useProxy) {
|
||||
getGenerateRobot(token);
|
||||
setView('profile');
|
||||
}
|
||||
}
|
||||
@ -70,7 +69,7 @@ const RobotPage = (): JSX.Element => {
|
||||
pubKey: key.publicKeyArmored,
|
||||
encPrivKey: key.encryptedPrivateKeyArmored,
|
||||
});
|
||||
void federation.fetchRobot(garage, token);
|
||||
garage.fetchRobot(federation, token);
|
||||
garage.setCurrentSlot(token);
|
||||
})
|
||||
.catch((error) => {
|
||||
|
@ -5,10 +5,12 @@ import { AppContext, type UseAppStoreType } from '../../contexts/AppContext';
|
||||
import FederationTable from '../../components/FederationTable';
|
||||
import { t } from 'i18next';
|
||||
import { FederationContext, type UseFederationStoreType } from '../../contexts/FederationContext';
|
||||
import { GarageContext, UseGarageStoreType } from '../../contexts/GarageContext';
|
||||
|
||||
const SettingsPage = (): JSX.Element => {
|
||||
const { windowSize, navbarHeight } = useContext<UseAppStoreType>(AppContext);
|
||||
const { federation, addNewCoordinator } = useContext<UseFederationStoreType>(FederationContext);
|
||||
const { garage } = useContext<UseGarageStoreType>(GarageContext);
|
||||
const maxHeight = (windowSize.height - navbarHeight) * 0.85 - 3;
|
||||
const [newAlias, setNewAlias] = useState<string>('');
|
||||
const [newUrl, setNewUrl] = useState<string>('');
|
||||
@ -26,6 +28,7 @@ const SettingsPage = (): JSX.Element => {
|
||||
fullNewUrl = `http://${newUrl}`;
|
||||
}
|
||||
addNewCoordinator(newAlias, fullNewUrl);
|
||||
garage.syncCoordinator(federation, newAlias);
|
||||
setNewAlias('');
|
||||
setNewUrl('');
|
||||
} else {
|
||||
|
@ -301,12 +301,11 @@ const MakerForm = ({
|
||||
return;
|
||||
}
|
||||
|
||||
const robot = slot?.getRobot();
|
||||
const auth = robot?.getAuthHeaders();
|
||||
const auth = slot?.getAuthHeaders();
|
||||
|
||||
if (!disableRequest && maker.coordinator && auth && robot) {
|
||||
if (!disableRequest && maker.coordinator && auth && slot) {
|
||||
setSubmittingRequest(true);
|
||||
const order = new Order({
|
||||
const orderAttributes = {
|
||||
type: fav.type === 0 ? 1 : 0,
|
||||
currency: fav.currency === 0 ? 1 : fav.currency,
|
||||
amount: makerHasAmountRange ? null : maker.amount,
|
||||
@ -324,13 +323,12 @@ const MakerForm = ({
|
||||
latitude: maker.latitude,
|
||||
longitude: maker.longitude,
|
||||
shortAlias: maker.coordinator,
|
||||
});
|
||||
};
|
||||
|
||||
order
|
||||
.make(federation, robot)
|
||||
slot
|
||||
.makeOrder(federation, orderAttributes)
|
||||
.then((order: Order) => {
|
||||
if (order.id) {
|
||||
garage.updateOrder(order);
|
||||
navigate(`/order/${order.shortAlias}/${order.id}`);
|
||||
} else if (order?.bad_request) {
|
||||
setBadRequest(order?.bad_request);
|
||||
|
@ -313,31 +313,29 @@ const TakeButton = ({
|
||||
};
|
||||
|
||||
const takeOrder = function (): void {
|
||||
const robot = garage.getSlot()?.getRobot() ?? null;
|
||||
const slot = garage.getSlot();
|
||||
|
||||
if (currentOrder === null || robot === null) return;
|
||||
if (currentOrder === null || slot === null) return;
|
||||
|
||||
setLoadingTake(true);
|
||||
|
||||
if (robot && currentOrder) {
|
||||
currentOrder
|
||||
.submitAction(federation, robot, {
|
||||
action: 'take',
|
||||
amount:
|
||||
currentOrder?.currency === 1000 ? Number(takeAmount) / 100000000 : Number(takeAmount),
|
||||
})
|
||||
.then((order) => {
|
||||
if (order?.bad_request !== undefined) {
|
||||
setBadRequest(order.bad_request);
|
||||
} else {
|
||||
setBadRequest('');
|
||||
navigate(`/order/${order.shortAlias}/${order.id}`);
|
||||
}
|
||||
})
|
||||
.catch(() => {
|
||||
setBadRequest('Request error');
|
||||
});
|
||||
}
|
||||
currentOrder
|
||||
.submitAction(federation, slot, {
|
||||
action: 'take',
|
||||
amount:
|
||||
currentOrder?.currency === 1000 ? Number(takeAmount) / 100000000 : Number(takeAmount),
|
||||
})
|
||||
.then((order) => {
|
||||
if (order?.bad_request !== undefined) {
|
||||
setBadRequest(order.bad_request);
|
||||
} else {
|
||||
setBadRequest('');
|
||||
navigate(`/order/${order.shortAlias}/${order.id}`);
|
||||
}
|
||||
})
|
||||
.catch(() => {
|
||||
setBadRequest('Request error');
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
|
@ -31,6 +31,7 @@ import { UserNinjaIcon } from '../Icons';
|
||||
import { getWebln } from '../../utils';
|
||||
import { signCleartextMessage } from '../../pgp';
|
||||
import { GarageContext, type UseGarageStoreType } from '../../contexts/GarageContext';
|
||||
import { FederationContext, UseFederationStoreType } from '../../contexts/FederationContext';
|
||||
|
||||
interface Props {
|
||||
coordinator: Coordinator;
|
||||
@ -40,6 +41,7 @@ interface Props {
|
||||
|
||||
const RobotInfo: React.FC<Props> = ({ coordinator, onClose, disabled }: Props) => {
|
||||
const { garage } = useContext<UseGarageStoreType>(GarageContext);
|
||||
const { federation } = useContext<UseFederationStoreType>(FederationContext);
|
||||
const navigate = useNavigate();
|
||||
const { t } = useTranslation();
|
||||
|
||||
@ -72,7 +74,6 @@ const RobotInfo: React.FC<Props> = ({ coordinator, onClose, disabled }: Props) =
|
||||
|
||||
const handleWeblnInvoiceClicked = async (e: MouseEvent<HTMLButtonElement, MouseEvent>): void => {
|
||||
e.preventDefault();
|
||||
const robot = garage.getSlot()?.getRobot(coordinator.shortAlias);
|
||||
if (robot != null && robot.earnedRewards > 0) {
|
||||
const webln = await getWebln();
|
||||
const invoice = webln.makeInvoice(robot.earnedRewards).then(() => {
|
||||
@ -87,11 +88,11 @@ const RobotInfo: React.FC<Props> = ({ coordinator, onClose, disabled }: Props) =
|
||||
setBadInvoice('');
|
||||
setShowRewardsSpinner(true);
|
||||
|
||||
if (robot?.token && robot.encPrivKey != null) {
|
||||
if (robot && robot?.token && robot.encPrivKey != null) {
|
||||
void signCleartextMessage(rewardInvoice, robot.encPrivKey, robot?.token).then(
|
||||
(signedInvoice) => {
|
||||
console.log('Signed message:', signedInvoice);
|
||||
void coordinator.fetchReward(signedInvoice, garage, robot?.token).then((data) => {
|
||||
void robot.fetchReward(federation, signedInvoice).then((data) => {
|
||||
setBadInvoice(data.bad_invoice ?? '');
|
||||
setShowRewardsSpinner(false);
|
||||
setWithdrawn(data.successful_withdrawal);
|
||||
@ -104,9 +105,7 @@ const RobotInfo: React.FC<Props> = ({ coordinator, onClose, disabled }: Props) =
|
||||
};
|
||||
|
||||
const setStealthInvoice = (): void => {
|
||||
if (robot?.token) {
|
||||
void coordinator.fetchStealth(!robot?.stealthInvoices, garage, robot?.token);
|
||||
}
|
||||
if (robot?.token) void robot.fetchStealth(federation, !robot?.stealthInvoices);
|
||||
};
|
||||
|
||||
return (
|
||||
|
@ -98,7 +98,7 @@ const EncryptedTurtleChat: React.FC<Props> = ({
|
||||
.getEndpoint(settings.network, origin, settings.selfhostedClient, hostUrl);
|
||||
apiClient
|
||||
.get(url + basePath, `/api/chat/?order_id=${order.id}&offset=${lastIndex}`, {
|
||||
tokenSHA256: garage.getSlot()?.getRobot()?.tokenSHA256 ?? '',
|
||||
tokenSHA256: garage.getSlot()?.tokenSHA256 ?? '',
|
||||
})
|
||||
.then((results: any) => {
|
||||
if (results != null) {
|
||||
@ -207,7 +207,7 @@ const EncryptedTurtleChat: React.FC<Props> = ({
|
||||
order_id: order.id,
|
||||
offset: lastIndex,
|
||||
},
|
||||
{ tokenSHA256: robot?.tokenSHA256 ?? '' },
|
||||
{ tokenSHA256: slot?.tokenSHA256 ?? '' },
|
||||
)
|
||||
.then((response) => {
|
||||
if (response != null) {
|
||||
@ -240,7 +240,7 @@ const EncryptedTurtleChat: React.FC<Props> = ({
|
||||
order_id: order.id,
|
||||
offset: lastIndex,
|
||||
},
|
||||
{ tokenSHA256: robot?.tokenSHA256 },
|
||||
{ tokenSHA256: slot?.tokenSHA256 },
|
||||
)
|
||||
.then((response) => {
|
||||
if (response != null) {
|
||||
|
@ -154,10 +154,9 @@ const TradeBox = ({ currentOrder, onStartAgain }: TradeBoxProps): JSX.Element =>
|
||||
|
||||
const renewOrder = function (): void {
|
||||
const slot = garage.getSlot();
|
||||
const robot = slot?.getRobot();
|
||||
const newOrder = currentOrder;
|
||||
if (newOrder && robot) {
|
||||
const order = new Order({
|
||||
if (newOrder && slot) {
|
||||
const orderAttributes = {
|
||||
type: newOrder.type,
|
||||
currency: newOrder.currency,
|
||||
amount: newOrder.has_range ? null : newOrder.amount,
|
||||
@ -173,11 +172,10 @@ const TradeBox = ({ currentOrder, onStartAgain }: TradeBoxProps): JSX.Element =>
|
||||
bond_size: newOrder.bond_size,
|
||||
latitude: newOrder.latitude,
|
||||
longitude: newOrder.longitude,
|
||||
});
|
||||
void order.make(federation, robot).then((data: Order) => {
|
||||
if (data?.id) {
|
||||
navigate(`/order/${String(newOrder?.shortAlias)}/${String(data.id)}`);
|
||||
}
|
||||
shortAlias: newOrder.shortAlias,
|
||||
};
|
||||
void slot.makeOrder(federation, orderAttributes).then((order: Order) => {
|
||||
if (order?.id) navigate(`/order/${String(order?.shortAlias)}/${String(order.id)}`);
|
||||
});
|
||||
}
|
||||
};
|
||||
@ -191,11 +189,11 @@ const TradeBox = ({ currentOrder, onStartAgain }: TradeBoxProps): JSX.Element =>
|
||||
statement,
|
||||
rating,
|
||||
}: SubmitActionProps): void {
|
||||
const robot = garage.getSlot()?.getRobot();
|
||||
const slot = garage.getSlot();
|
||||
|
||||
if (robot && currentOrder) {
|
||||
if (slot && currentOrder) {
|
||||
currentOrder
|
||||
.submitAction(federation, robot, {
|
||||
.submitAction(federation, slot, {
|
||||
action,
|
||||
invoice,
|
||||
routing_budget_ppm,
|
||||
@ -214,7 +212,7 @@ const TradeBox = ({ currentOrder, onStartAgain }: TradeBoxProps): JSX.Element =>
|
||||
} else if (data.bad_statement !== undefined) {
|
||||
setDispute({ ...dispute, badStatement: data.bad_statement });
|
||||
}
|
||||
garage.updateOrder(data);
|
||||
slot.updateSlotFromOrder(data);
|
||||
})
|
||||
.catch(() => {
|
||||
setOpen(closeAll);
|
||||
|
@ -13,33 +13,8 @@ import { type Order, Federation, Settings } from '../models';
|
||||
import { federationLottery } from '../utils';
|
||||
|
||||
import { AppContext, type UseAppStoreType } from './AppContext';
|
||||
import { GarageContext, type UseGarageStoreType } from './GarageContext';
|
||||
import { type Origin, type Origins } from '../models/Coordinator.model';
|
||||
|
||||
// Refresh delays (ms) according to Order status
|
||||
const defaultDelay = 5000;
|
||||
const statusToDelay = [
|
||||
3000, // 'Waiting for maker bond'
|
||||
35000, // 'Public'
|
||||
180000, // 'Paused'
|
||||
3000, // 'Waiting for taker bond'
|
||||
999999, // 'Cancelled'
|
||||
999999, // 'Expired'
|
||||
8000, // 'Waiting for trade collateral and buyer invoice'
|
||||
8000, // 'Waiting only for seller trade collateral'
|
||||
8000, // 'Waiting only for buyer invoice'
|
||||
10000, // 'Sending fiat - In chatroom'
|
||||
10000, // 'Fiat sent - In chatroom'
|
||||
100000, // 'In dispute'
|
||||
999999, // 'Collaboratively cancelled'
|
||||
10000, // 'Sending satoshis to buyer'
|
||||
60000, // 'Sucessful trade'
|
||||
30000, // 'Failed lightning network routing'
|
||||
300000, // 'Wait for dispute resolution'
|
||||
300000, // 'Maker lost dispute'
|
||||
300000, // 'Taker lost dispute'
|
||||
];
|
||||
|
||||
export interface CurrentOrderIdProps {
|
||||
id: number | null;
|
||||
shortAlias: string | null;
|
||||
@ -52,7 +27,6 @@ export interface FederationContextProviderProps {
|
||||
export interface UseFederationStoreType {
|
||||
federation: Federation;
|
||||
sortedCoordinators: string[];
|
||||
setDelay: Dispatch<SetStateAction<number>>;
|
||||
coordinatorUpdatedAt: string;
|
||||
federationUpdatedAt: string;
|
||||
addNewCoordinator: (alias: string, url: string) => void;
|
||||
@ -61,7 +35,6 @@ export interface UseFederationStoreType {
|
||||
export const initialFederationContext: UseFederationStoreType = {
|
||||
federation: new Federation('onion', new Settings(), ''),
|
||||
sortedCoordinators: [],
|
||||
setDelay: () => {},
|
||||
coordinatorUpdatedAt: '',
|
||||
federationUpdatedAt: '',
|
||||
addNewCoordinator: () => {},
|
||||
@ -72,9 +45,7 @@ export const FederationContext = createContext<UseFederationStoreType>(initialFe
|
||||
export const FederationContextProvider = ({
|
||||
children,
|
||||
}: FederationContextProviderProps): JSX.Element => {
|
||||
const { settings, page, origin, hostUrl, open, torStatus } =
|
||||
useContext<UseAppStoreType>(AppContext);
|
||||
const { setMaker, garage } = useContext<UseGarageStoreType>(GarageContext);
|
||||
const { settings, page, origin, hostUrl, torStatus } = useContext<UseAppStoreType>(AppContext);
|
||||
const [federation] = useState(new Federation(origin, settings, hostUrl));
|
||||
const [sortedCoordinators, setSortedCoordinators] = useState(federationLottery(federation));
|
||||
const [coordinatorUpdatedAt, setCoordinatorUpdatedAt] = useState<string>(
|
||||
@ -82,15 +53,7 @@ export const FederationContextProvider = ({
|
||||
);
|
||||
const [federationUpdatedAt, setFederationUpdatedAt] = useState<string>(new Date().toISOString());
|
||||
|
||||
const [delay, setDelay] = useState<number>(defaultDelay);
|
||||
const [timer, setTimer] = useState<NodeJS.Timer | undefined>(() =>
|
||||
setInterval(() => null, delay),
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
setMaker((maker) => {
|
||||
return { ...maker, coordinator: sortedCoordinators[0] };
|
||||
}); // default MakerForm coordinator is decided via sorted lottery
|
||||
federation.registerHook('onFederationUpdate', () => {
|
||||
setFederationUpdatedAt(new Date().toISOString());
|
||||
});
|
||||
@ -99,59 +62,13 @@ export const FederationContextProvider = ({
|
||||
});
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
clearInterval(timer);
|
||||
fetchSlotOrder();
|
||||
|
||||
return () => {
|
||||
clearInterval(timer);
|
||||
};
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
if (window.NativeRobosats === undefined || torStatus === 'ON' || !settings.useProxy) {
|
||||
void federation.updateUrl(origin, settings, hostUrl);
|
||||
void federation.update();
|
||||
|
||||
const token = garage.getSlot()?.getRobot()?.token;
|
||||
if (token) void federation.fetchRobot(garage, token);
|
||||
}
|
||||
}, [settings.network, settings.useProxy, torStatus]);
|
||||
|
||||
const onOrderReceived = (order: Order): void => {
|
||||
let newDelay = defaultDelay;
|
||||
if (order?.bad_request) {
|
||||
newDelay = 99999999;
|
||||
garage.updateOrder(order);
|
||||
}
|
||||
if (order?.id) {
|
||||
newDelay =
|
||||
order.status >= 0 && order.status <= 18
|
||||
? page === 'order'
|
||||
? statusToDelay[order.status]
|
||||
: statusToDelay[order.status] * 5 // If user is not looking at "order" tab, refresh less often.
|
||||
: 99999999;
|
||||
}
|
||||
clearInterval(timer);
|
||||
console.log('New Delay:', newDelay);
|
||||
setDelay(newDelay);
|
||||
setTimer(setTimeout(fetchSlotOrder, newDelay));
|
||||
};
|
||||
|
||||
const fetchSlotOrder: () => void = () => {
|
||||
const slot = garage?.getSlot();
|
||||
const robot = slot?.getRobot();
|
||||
if (slot?.token && slot.activeOrder?.id && robot) {
|
||||
void slot.activeOrder.fecth(federation, robot).then((order) => {
|
||||
onOrderReceived(order);
|
||||
garage.updateOrder(order);
|
||||
});
|
||||
} else {
|
||||
clearInterval(timer);
|
||||
setTimer(setTimeout(fetchSlotOrder, defaultDelay));
|
||||
}
|
||||
};
|
||||
|
||||
const addNewCoordinator: (alias: string, url: string) => void = (alias, url) => {
|
||||
if (!federation.coordinators[alias]) {
|
||||
const attributes: Record<any, any> = {
|
||||
@ -175,7 +92,6 @@ export const FederationContextProvider = ({
|
||||
newCoordinator.update(() => {
|
||||
setCoordinatorUpdatedAt(new Date().toISOString());
|
||||
});
|
||||
garage.syncCoordinator(newCoordinator);
|
||||
setSortedCoordinators(federationLottery(federation));
|
||||
setFederationUpdatedAt(new Date().toISOString());
|
||||
}
|
||||
@ -185,21 +101,11 @@ export const FederationContextProvider = ({
|
||||
if (page === 'offers') void federation.updateBook();
|
||||
}, [page]);
|
||||
|
||||
// use effects to fetchRobots on Profile open
|
||||
useEffect(() => {
|
||||
const slot = garage.getSlot();
|
||||
|
||||
if (open.profile && slot?.hashId && slot?.token) {
|
||||
void federation.fetchRobot(garage, slot?.token); // refresh/update existing robot
|
||||
}
|
||||
}, [open.profile]);
|
||||
|
||||
return (
|
||||
<FederationContext.Provider
|
||||
value={{
|
||||
federation,
|
||||
sortedCoordinators,
|
||||
setDelay,
|
||||
coordinatorUpdatedAt,
|
||||
federationUpdatedAt,
|
||||
addNewCoordinator,
|
||||
|
@ -5,10 +5,13 @@ import React, {
|
||||
type SetStateAction,
|
||||
useEffect,
|
||||
type ReactNode,
|
||||
useContext,
|
||||
} from 'react';
|
||||
|
||||
import { defaultMaker, type Maker, Garage } from '../models';
|
||||
import { systemClient } from '../services/System';
|
||||
import { UseAppStoreType, AppContext } from './AppContext';
|
||||
import { UseFederationStoreType, FederationContext } from './FederationContext';
|
||||
|
||||
export interface GarageContextProviderProps {
|
||||
children: ReactNode;
|
||||
@ -18,6 +21,7 @@ export interface UseGarageStoreType {
|
||||
garage: Garage;
|
||||
maker: Maker;
|
||||
setMaker: Dispatch<SetStateAction<Maker>>;
|
||||
setDelay: Dispatch<SetStateAction<number>>;
|
||||
robotUpdatedAt: string;
|
||||
orderUpdatedAt: string;
|
||||
}
|
||||
@ -26,18 +30,49 @@ export const initialGarageContext: UseGarageStoreType = {
|
||||
garage: new Garage(),
|
||||
maker: defaultMaker,
|
||||
setMaker: () => {},
|
||||
setDelay: () => {},
|
||||
robotUpdatedAt: '',
|
||||
orderUpdatedAt: '',
|
||||
};
|
||||
|
||||
const defaultDelay = 5000;
|
||||
// Refresh delays (ms) according to Order status
|
||||
const statusToDelay = [
|
||||
3000, // 'Waiting for maker bond'
|
||||
35000, // 'Public'
|
||||
180000, // 'Paused'
|
||||
3000, // 'Waiting for taker bond'
|
||||
999999, // 'Cancelled'
|
||||
999999, // 'Expired'
|
||||
8000, // 'Waiting for trade collateral and buyer invoice'
|
||||
8000, // 'Waiting only for seller trade collateral'
|
||||
8000, // 'Waiting only for buyer invoice'
|
||||
10000, // 'Sending fiat - In chatroom'
|
||||
10000, // 'Fiat sent - In chatroom'
|
||||
100000, // 'In dispute'
|
||||
999999, // 'Collaboratively cancelled'
|
||||
10000, // 'Sending satoshis to buyer'
|
||||
60000, // 'Sucessful trade'
|
||||
30000, // 'Failed lightning network routing'
|
||||
300000, // 'Wait for dispute resolution'
|
||||
300000, // 'Maker lost dispute'
|
||||
300000, // 'Taker lost dispute'
|
||||
];
|
||||
|
||||
export const GarageContext = createContext<UseGarageStoreType>(initialGarageContext);
|
||||
|
||||
export const GarageContextProvider = ({ children }: GarageContextProviderProps): JSX.Element => {
|
||||
// All garage data structured
|
||||
const { settings, torStatus, open, page } = useContext<UseAppStoreType>(AppContext);
|
||||
const { federation, sortedCoordinators } = useContext<UseFederationStoreType>(FederationContext);
|
||||
const [garage] = useState<Garage>(initialGarageContext.garage);
|
||||
const [maker, setMaker] = useState<Maker>(initialGarageContext.maker);
|
||||
const [robotUpdatedAt, setRobotUpdatedAt] = useState<string>(new Date().toISOString());
|
||||
const [orderUpdatedAt, setOrderUpdatedAt] = useState<string>(new Date().toISOString());
|
||||
const [delay, setDelay] = useState<number>(defaultDelay);
|
||||
const [timer, setTimer] = useState<NodeJS.Timer | undefined>(() =>
|
||||
setInterval(() => null, delay),
|
||||
);
|
||||
|
||||
const onRobotUpdated = (): void => {
|
||||
setRobotUpdatedAt(new Date().toISOString());
|
||||
@ -48,22 +83,69 @@ export const GarageContextProvider = ({ children }: GarageContextProviderProps):
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
setMaker((maker) => {
|
||||
return { ...maker, coordinator: sortedCoordinators[0] };
|
||||
}); // default MakerForm coordinator is decided via sorted lottery
|
||||
garage.registerHook('onRobotUpdate', onRobotUpdated);
|
||||
garage.registerHook('onOrderUpdate', onOrderUpdate);
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
clearInterval(timer);
|
||||
void fetchSlotOrder();
|
||||
|
||||
return () => {
|
||||
clearInterval(timer);
|
||||
};
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
if (window.NativeRobosats === undefined || torStatus === 'ON' || !settings.useProxy) {
|
||||
const token = garage.getSlot()?.token;
|
||||
if (token) void garage.fetchRobot(federation, token);
|
||||
}
|
||||
}, [settings.network, settings.useProxy, torStatus]);
|
||||
|
||||
useEffect(() => {
|
||||
if (window.NativeRobosats !== undefined && !systemClient.loading) {
|
||||
garage.loadSlots();
|
||||
}
|
||||
}, [systemClient.loading]);
|
||||
|
||||
// use effects to fetchRobots on Profile open
|
||||
useEffect(() => {
|
||||
const slot = garage.getSlot();
|
||||
|
||||
if (open.profile && slot?.hashId && slot?.token) {
|
||||
void garage.fetchRobot(federation, slot?.token); // refresh/update existing robot
|
||||
}
|
||||
}, [open.profile]);
|
||||
|
||||
const fetchSlotOrder: () => Promise<void> = async () => {
|
||||
let newDelay = defaultDelay;
|
||||
const slot = garage?.getSlot();
|
||||
if (slot?.activeOrder?.id) {
|
||||
const order = await slot.fetchActiveOrder(federation);
|
||||
console.log(order);
|
||||
if (order?.bad_request) {
|
||||
newDelay = 99999999;
|
||||
} else if (order?.id) {
|
||||
newDelay = order.status >= 0 && order.status <= 18 ? statusToDelay[order.status] : 99999999;
|
||||
}
|
||||
console.log('New Delay:', newDelay);
|
||||
}
|
||||
clearInterval(timer);
|
||||
setDelay(newDelay);
|
||||
setTimer(setTimeout(fetchSlotOrder, newDelay));
|
||||
};
|
||||
|
||||
return (
|
||||
<GarageContext.Provider
|
||||
value={{
|
||||
garage,
|
||||
maker,
|
||||
setMaker,
|
||||
setDelay,
|
||||
robotUpdatedAt,
|
||||
orderUpdatedAt,
|
||||
}}
|
||||
|
@ -172,7 +172,6 @@ export class Coordinator {
|
||||
public loadingInfo: boolean = false;
|
||||
public limits: LimitList = {};
|
||||
public loadingLimits: boolean = false;
|
||||
public loadingRobot: string | null;
|
||||
|
||||
updateUrl = (origin: Origin, settings: Settings, hostUrl: string): void => {
|
||||
if (settings.selfhostedClient && this.shortAlias !== 'local') {
|
||||
@ -323,109 +322,6 @@ export class Coordinator {
|
||||
return { url: String(this[network][origin]), basePath: '' };
|
||||
}
|
||||
};
|
||||
|
||||
fetchRobot = async (garage: Garage, token: string): Promise<Robot | null> => {
|
||||
if (!this.enabled || !token || this.loadingRobot === token) return null;
|
||||
|
||||
const robot = garage?.getSlot(token)?.getRobot() ?? null;
|
||||
const authHeaders = robot?.getAuthHeaders();
|
||||
|
||||
if (!authHeaders) return null;
|
||||
|
||||
const { hasEnoughEntropy, bitsEntropy, shannonEntropy } = validateTokenEntropy(token);
|
||||
|
||||
if (!hasEnoughEntropy) return null;
|
||||
|
||||
this.loadingRobot = token;
|
||||
|
||||
garage.updateRobot(token, this.shortAlias, { loading: true });
|
||||
|
||||
const newAttributes = await apiClient
|
||||
.get(this.url, `${this.basePath}/api/robot/`, authHeaders)
|
||||
.then((data: any) => {
|
||||
return {
|
||||
nickname: data.nickname,
|
||||
activeOrderId: data.active_order_id ?? null,
|
||||
lastOrderId: data.last_order_id ?? null,
|
||||
earnedRewards: data.earned_rewards ?? 0,
|
||||
stealthInvoices: data.wants_stealth,
|
||||
tgEnabled: data.tg_enabled,
|
||||
tgBotName: data.tg_bot_name,
|
||||
tgToken: data.tg_token,
|
||||
found: data?.found,
|
||||
last_login: data.last_login,
|
||||
pubKey: data.public_key,
|
||||
encPrivKey: data.encrypted_private_key,
|
||||
};
|
||||
})
|
||||
.catch((e) => {
|
||||
console.log(e);
|
||||
})
|
||||
.finally(() => (this.loadingRobot = null));
|
||||
|
||||
garage.updateRobot(token, this.shortAlias, {
|
||||
...newAttributes,
|
||||
tokenSHA256: authHeaders.tokenSHA256,
|
||||
loading: false,
|
||||
bitsEntropy,
|
||||
shannonEntropy,
|
||||
shortAlias: this.shortAlias,
|
||||
});
|
||||
|
||||
return garage.getSlot(this.shortAlias)?.getRobot() ?? null;
|
||||
};
|
||||
|
||||
fetchReward = async (
|
||||
signedInvoice: string,
|
||||
garage: Garage,
|
||||
index: string,
|
||||
): Promise<null | {
|
||||
bad_invoice?: string;
|
||||
successful_withdrawal?: boolean;
|
||||
}> => {
|
||||
if (!this.enabled) return null;
|
||||
|
||||
const slot = garage.getSlot(index);
|
||||
const robot = slot?.getRobot();
|
||||
|
||||
if (!slot?.token || !robot?.encPrivKey) return null;
|
||||
|
||||
const data = await apiClient.post(
|
||||
this.url,
|
||||
`${this.basePath}/api/reward/`,
|
||||
{
|
||||
invoice: signedInvoice,
|
||||
},
|
||||
{ tokenSHA256: robot.tokenSHA256 },
|
||||
);
|
||||
garage.updateRobot(slot?.token, this.shortAlias, {
|
||||
earnedRewards: data?.successful_withdrawal === true ? 0 : robot.earnedRewards,
|
||||
});
|
||||
|
||||
return data ?? {};
|
||||
};
|
||||
|
||||
fetchStealth = async (wantsStealth: boolean, garage: Garage, index: string): Promise<null> => {
|
||||
if (!this.enabled) return null;
|
||||
|
||||
const slot = garage.getSlot(index);
|
||||
const robot = slot?.getRobot();
|
||||
|
||||
if (!(slot?.token != null) || !(robot?.encPrivKey != null)) return null;
|
||||
|
||||
await apiClient.post(
|
||||
this.url,
|
||||
`${this.basePath}/api/stealth/`,
|
||||
{ wantsStealth },
|
||||
{ tokenSHA256: robot.tokenSHA256 },
|
||||
);
|
||||
|
||||
garage.updateRobot(slot?.token, this.shortAlias, {
|
||||
stealthInvoices: wantsStealth,
|
||||
});
|
||||
|
||||
return null;
|
||||
};
|
||||
}
|
||||
|
||||
export default Coordinator;
|
||||
|
@ -135,13 +135,6 @@ export class Federation {
|
||||
this.triggerHook('onFederationUpdate');
|
||||
};
|
||||
|
||||
// Fetchs
|
||||
fetchRobot = async (garage: Garage, token: string): Promise<void> => {
|
||||
Object.values(this.coordinators).forEach((coor) => {
|
||||
void coor.fetchRobot(garage, token);
|
||||
});
|
||||
};
|
||||
|
||||
// Coordinators
|
||||
getCoordinator = (shortAlias: string): Coordinator => {
|
||||
return this.coordinators[shortAlias];
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { type Coordinator, type Order } from '.';
|
||||
import { Federation, Order, type Coordinator } from '.';
|
||||
import { systemClient } from '../services/System';
|
||||
import { saveAsJson } from '../utils';
|
||||
import Slot from './Slot.model';
|
||||
@ -67,11 +67,8 @@ class Garage {
|
||||
this.triggerHook('onRobotUpdate');
|
||||
},
|
||||
);
|
||||
Object.keys(rawSlot.robots).forEach((shortAlias) => {
|
||||
const rawRobot = rawSlot.robots[shortAlias];
|
||||
this.updateRobot(rawSlot.token, shortAlias, rawRobot);
|
||||
});
|
||||
this.updateOrder(rawSlot.token, rawSlot.activeOrder);
|
||||
this.slots[rawSlot.token].updateSlotFromOrder(new Order(rawSlot.lastOrder));
|
||||
this.slots[rawSlot.token].updateSlotFromOrder(new Order(rawSlot.activeOrder));
|
||||
this.currentSlot = rawSlot?.token;
|
||||
}
|
||||
});
|
||||
@ -131,36 +128,23 @@ class Garage {
|
||||
}
|
||||
};
|
||||
|
||||
updateRobot: (token: string, shortAlias: string, attributes: Record<any, any>) => void = (
|
||||
token,
|
||||
shortAlias,
|
||||
attributes,
|
||||
) => {
|
||||
if (!token || !shortAlias) return;
|
||||
|
||||
fetchRobot = async (federation: Federation, token: string): Promise<void> => {
|
||||
const slot = this.getSlot(token);
|
||||
|
||||
if (slot != null) {
|
||||
slot.updateRobot(shortAlias, { token, ...attributes });
|
||||
await slot.fetchRobot(federation);
|
||||
this.save();
|
||||
this.triggerHook('onRobotUpdate');
|
||||
}
|
||||
};
|
||||
|
||||
// Orders
|
||||
updateOrder: (order: Order | null, token?: string) => void = (order, token) => {
|
||||
const slot = this.getSlot(token);
|
||||
if (slot != null) {
|
||||
slot.updateOrder(order);
|
||||
this.save();
|
||||
this.triggerHook('onOrderUpdate');
|
||||
}
|
||||
};
|
||||
|
||||
// Coordinators
|
||||
syncCoordinator: (coordinator: Coordinator) => void = (coordinator) => {
|
||||
syncCoordinator: (federation: Federation, shortAlias: string) => void = (
|
||||
federation,
|
||||
shortAlias,
|
||||
) => {
|
||||
Object.values(this.slots).forEach((slot) => {
|
||||
slot.syncCoordinator(coordinator, this);
|
||||
slot.syncCoordinator(federation, shortAlias);
|
||||
});
|
||||
};
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
import { apiClient } from '../services/api';
|
||||
import type Federation from './Federation.model';
|
||||
import type Robot from './Robot.model';
|
||||
import Slot from './Slot.model';
|
||||
|
||||
export interface SubmitActionProps {
|
||||
action:
|
||||
@ -178,7 +179,7 @@ class Order {
|
||||
Object.assign(this, attributes);
|
||||
};
|
||||
|
||||
make: (federation: Federation, robot: Robot) => Promise<this> = async (federation, robot) => {
|
||||
make: (federation: Federation, slot: Slot) => Promise<this> = async (federation, slot) => {
|
||||
const body = {
|
||||
type: this.type,
|
||||
currency: this.currency,
|
||||
@ -197,42 +198,42 @@ class Order {
|
||||
longitude: this.longitude,
|
||||
};
|
||||
|
||||
if (robot) {
|
||||
if (slot) {
|
||||
const coordinator = federation.getCoordinator(this.shortAlias);
|
||||
const { basePath, url } = coordinator;
|
||||
const data = await apiClient.post(url + basePath, '/api/make/', body, {
|
||||
tokenSHA256: robot.tokenSHA256,
|
||||
tokenSHA256: slot.tokenSHA256,
|
||||
});
|
||||
Object.assign(this, data);
|
||||
if (data) this.update(data);
|
||||
}
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
submitAction: (federation: Federation, robot: Robot, action: SubmitActionProps) => Promise<this> =
|
||||
async (federation, robot, action) => {
|
||||
submitAction: (federation: Federation, slot: Slot, action: SubmitActionProps) => Promise<this> =
|
||||
async (federation, slot, action) => {
|
||||
if (this.id < 1) return this;
|
||||
|
||||
if (robot) {
|
||||
if (slot) {
|
||||
const coordinator = federation.getCoordinator(this.shortAlias);
|
||||
const { basePath, url } = coordinator;
|
||||
const data = await apiClient.post(
|
||||
url + basePath,
|
||||
`/api/order/?order_id=${Number(this.id)}`,
|
||||
action,
|
||||
{ tokenSHA256: robot?.tokenSHA256 },
|
||||
{ tokenSHA256: slot?.tokenSHA256 },
|
||||
);
|
||||
Object.assign(this, data);
|
||||
if (data) this.update(data);
|
||||
}
|
||||
return this;
|
||||
};
|
||||
|
||||
fecth: (federation: Federation, robot: Robot) => Promise<this> = async (federation, robot) => {
|
||||
fecth: (federation: Federation, slot: Slot) => Promise<this> = async (federation, slot) => {
|
||||
if (this.id < 1) return this;
|
||||
if (!robot) return this;
|
||||
if (!slot) return this;
|
||||
|
||||
const coordinator = federation.getCoordinator(this.shortAlias);
|
||||
const authHeaders = robot.getAuthHeaders();
|
||||
const authHeaders = slot.getAuthHeaders();
|
||||
if (!authHeaders) return this;
|
||||
const { basePath, url } = coordinator;
|
||||
const data = await apiClient.get(
|
||||
@ -241,7 +242,7 @@ class Order {
|
||||
authHeaders,
|
||||
);
|
||||
|
||||
Object.assign(this, data);
|
||||
if (data) this.update(data);
|
||||
|
||||
return this;
|
||||
};
|
||||
|
@ -1,29 +1,13 @@
|
||||
import { sha256 } from 'js-sha256';
|
||||
import { hexToBase91 } from '../utils';
|
||||
|
||||
interface AuthHeaders {
|
||||
tokenSHA256: string;
|
||||
keys: {
|
||||
pubKey: string;
|
||||
encPrivKey: string;
|
||||
};
|
||||
}
|
||||
import { apiClient } from '../services/api';
|
||||
import Federation from './Federation.model';
|
||||
import { AuthHeaders } from './Slot.model';
|
||||
|
||||
class Robot {
|
||||
constructor(attributes?: Record<any, any>) {
|
||||
if (attributes != null) {
|
||||
this.token = attributes?.token ?? undefined;
|
||||
this.tokenSHA256 =
|
||||
attributes?.tokenSHA256 ?? (this.token != null ? hexToBase91(sha256(this.token)) : '');
|
||||
this.pubKey = attributes?.pubKey ?? undefined;
|
||||
this.encPrivKey = attributes?.encPrivKey ?? undefined;
|
||||
}
|
||||
Object.assign(this, attributes);
|
||||
}
|
||||
|
||||
public token?: string;
|
||||
public bitsEntropy?: number;
|
||||
public shannonEntropy?: number;
|
||||
public tokenSHA256: string = '';
|
||||
public pubKey?: string;
|
||||
public encPrivKey?: string;
|
||||
public stealthInvoices: boolean = true;
|
||||
@ -37,6 +21,10 @@ class Robot {
|
||||
public found: boolean = false;
|
||||
public last_login: string = '';
|
||||
public shortAlias: string = '';
|
||||
public bitsEntropy?: number;
|
||||
public shannonEntropy?: number;
|
||||
public tokenSHA256: string = '';
|
||||
public hasEnoughEntropy: boolean = false;
|
||||
|
||||
update = (attributes: Record<string, any>): void => {
|
||||
Object.assign(this, attributes);
|
||||
@ -55,6 +43,77 @@ class Robot {
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
fetch = async (federation: Federation): Promise<Robot | null> => {
|
||||
const authHeaders = this.getAuthHeaders();
|
||||
const coordinator = federation.getCoordinator(this.shortAlias);
|
||||
|
||||
if (!authHeaders || !coordinator || !this.hasEnoughEntropy) return null;
|
||||
|
||||
this.loading = true;
|
||||
|
||||
await apiClient
|
||||
.get(coordinator.url, `${coordinator.basePath}/api/robot/`, authHeaders)
|
||||
.then((data: any) => {
|
||||
this.update({
|
||||
nickname: data.nickname,
|
||||
activeOrderId: data.active_order_id ?? null,
|
||||
lastOrderId: data.last_order_id ?? null,
|
||||
earnedRewards: data.earned_rewards ?? 0,
|
||||
stealthInvoices: data.wants_stealth,
|
||||
tgEnabled: data.tg_enabled,
|
||||
tgBotName: data.tg_bot_name,
|
||||
tgToken: data.tg_token,
|
||||
found: data?.found,
|
||||
last_login: data.last_login,
|
||||
pubKey: data.public_key,
|
||||
encPrivKey: data.encrypted_private_key,
|
||||
});
|
||||
})
|
||||
.catch((e) => {
|
||||
console.log(e);
|
||||
})
|
||||
.finally(() => (this.loading = false));
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
fetchReward = async (
|
||||
federation: Federation,
|
||||
signedInvoice: string,
|
||||
): Promise<null | {
|
||||
bad_invoice?: string;
|
||||
successful_withdrawal?: boolean;
|
||||
}> => {
|
||||
if (!federation) return null;
|
||||
|
||||
const coordinator = federation.getCoordinator(this.shortAlias);
|
||||
const data = await apiClient.post(
|
||||
coordinator.url,
|
||||
`${coordinator.basePath}/api/reward/`,
|
||||
{
|
||||
invoice: signedInvoice,
|
||||
},
|
||||
{ tokenSHA256: this.tokenSHA256 },
|
||||
);
|
||||
this.earnedRewards = data?.successful_withdrawal === true ? 0 : this.earnedRewards;
|
||||
|
||||
return data ?? {};
|
||||
};
|
||||
|
||||
fetchStealth = async (federation: Federation, wantsStealth: boolean): Promise<void> => {
|
||||
if (!federation) return;
|
||||
|
||||
const coordinator = federation.getCoordinator(this.shortAlias);
|
||||
await apiClient.post(
|
||||
coordinator.url,
|
||||
`${coordinator.basePath}/api/stealth/`,
|
||||
{ wantsStealth },
|
||||
{ tokenSHA256: this.tokenSHA256 },
|
||||
);
|
||||
|
||||
this.stealthInvoices = wantsStealth;
|
||||
};
|
||||
}
|
||||
|
||||
export default Robot;
|
||||
|
@ -1,6 +1,15 @@
|
||||
import { sha256 } from 'js-sha256';
|
||||
import { type Coordinator, type Garage, Robot, Order } from '.';
|
||||
import { type Coordinator, type Garage, Robot, Order, Federation } from '.';
|
||||
import { roboidentitiesClient } from '../services/Roboidentities/Web';
|
||||
import { hexToBase91, validateTokenEntropy } from '../utils';
|
||||
|
||||
export interface AuthHeaders {
|
||||
tokenSHA256: string;
|
||||
keys: {
|
||||
pubKey: string;
|
||||
encPrivKey: string;
|
||||
};
|
||||
}
|
||||
|
||||
class Slot {
|
||||
constructor(
|
||||
@ -11,6 +20,14 @@ class Slot {
|
||||
) {
|
||||
this.token = token;
|
||||
|
||||
const { hasEnoughEntropy, bitsEntropy, shannonEntropy } = validateTokenEntropy(token);
|
||||
const tokenSHA256 = hexToBase91(sha256(token));
|
||||
|
||||
this.hasEnoughEntropy = hasEnoughEntropy;
|
||||
this.bitsEntropy = bitsEntropy;
|
||||
this.shannonEntropy = shannonEntropy;
|
||||
this.tokenSHA256 = tokenSHA256;
|
||||
|
||||
this.hashId = sha256(sha256(this.token));
|
||||
this.nickname = null;
|
||||
void roboidentitiesClient.generateRoboname(this.hashId).then((nickname) => {
|
||||
@ -21,7 +38,15 @@ class Slot {
|
||||
void roboidentitiesClient.generateRobohash(this.hashId, 'large');
|
||||
|
||||
this.robots = shortAliases.reduce((acc: Record<string, Robot>, shortAlias: string) => {
|
||||
acc[shortAlias] = new Robot(robotAttributes);
|
||||
acc[shortAlias] = new Robot({
|
||||
...robotAttributes,
|
||||
shortAlias,
|
||||
hasEnoughEntropy,
|
||||
bitsEntropy,
|
||||
shannonEntropy,
|
||||
tokenSHA256,
|
||||
});
|
||||
this.updateSlotFromRobot(acc[shortAlias]);
|
||||
return acc;
|
||||
}, {});
|
||||
|
||||
@ -39,11 +64,31 @@ class Slot {
|
||||
activeOrder: Order | null;
|
||||
lastOrder: Order | null;
|
||||
copiedToken: boolean;
|
||||
hasEnoughEntropy: boolean;
|
||||
bitsEntropy: number;
|
||||
shannonEntropy: number;
|
||||
tokenSHA256: string = '';
|
||||
pubKey?: string;
|
||||
encPrivKey?: string;
|
||||
|
||||
setCopiedToken = (copied: boolean): void => {
|
||||
this.copiedToken = copied;
|
||||
};
|
||||
|
||||
getAuthHeaders = (): AuthHeaders | null => {
|
||||
const tokenSHA256 = this.tokenSHA256 ?? '';
|
||||
const encPrivKey = this.encPrivKey ?? '';
|
||||
const pubKey = this.pubKey ?? '';
|
||||
|
||||
return {
|
||||
tokenSHA256,
|
||||
keys: {
|
||||
pubKey: pubKey.split('\n').join('\\'),
|
||||
encPrivKey: encPrivKey.split('\n').join('\\'),
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
// Robots
|
||||
getRobot = (shortAlias?: string): Robot | null => {
|
||||
if (shortAlias) {
|
||||
@ -58,48 +103,73 @@ class Slot {
|
||||
return null;
|
||||
};
|
||||
|
||||
updateRobot = (shortAlias: string, attributes: Record<any, any>): Robot | null => {
|
||||
this.robots[shortAlias].update(attributes);
|
||||
fetchRobot = async (federation: Federation) => {
|
||||
Object.values(this.robots).forEach((robot) => {
|
||||
void robot.fetch(federation).then((robot) => this.updateSlotFromRobot(robot));
|
||||
});
|
||||
};
|
||||
|
||||
if (attributes.lastOrderId) {
|
||||
this.lastOrder = new Order({ id: attributes.lastOrderId, shortAlias: attributes.shortAlias });
|
||||
if (this.activeOrder?.id === attributes.lastOrderId) {
|
||||
updateSlotFromRobot = (robot: Robot | null): void => {
|
||||
if (robot?.lastOrderId) {
|
||||
this.lastOrder = new Order({ id: robot.lastOrderId, shortAlias: robot.shortAlias });
|
||||
if (this.activeOrder?.id === robot.lastOrderId) {
|
||||
this.activeOrder = null;
|
||||
}
|
||||
}
|
||||
if (attributes.activeOrderId && this.activeOrder?.id !== attributes.activeOrderId) {
|
||||
if (robot?.activeOrderId && this.activeOrder?.id !== robot.activeOrderId) {
|
||||
this.activeOrder = new Order({
|
||||
id: attributes.activeOrderId,
|
||||
shortAlias: attributes.shortAlias,
|
||||
id: robot.activeOrderId,
|
||||
shortAlias: robot.shortAlias,
|
||||
});
|
||||
}
|
||||
|
||||
return this.robots[shortAlias];
|
||||
};
|
||||
|
||||
// Orders
|
||||
updateOrder: (newOrder: Order | null) => void = (newOrder) => {
|
||||
fetchActiveOrder = async (federation: Federation) => {
|
||||
const order = await this.activeOrder?.fecth(federation, this);
|
||||
if (order) this.updateSlotFromOrder(order);
|
||||
return order;
|
||||
};
|
||||
|
||||
makeOrder = async (federation: Federation, attributes: object): Promise<Order> => {
|
||||
const order = new Order(attributes);
|
||||
await order.make(federation, this);
|
||||
this.activeOrder = order;
|
||||
return order;
|
||||
};
|
||||
|
||||
updateSlotFromOrder: (newOrder: Order | null) => void = (newOrder) => {
|
||||
if (newOrder) {
|
||||
if (
|
||||
newOrder.id === this.activeOrder?.id &&
|
||||
newOrder.shortAlias === this.activeOrder?.shortAlias
|
||||
) {
|
||||
this.activeOrder?.update(newOrder);
|
||||
if (newOrder?.bad_request) {
|
||||
this.activeOrder = null;
|
||||
this.lastOrder = newOrder;
|
||||
} else {
|
||||
this.activeOrder?.update(newOrder);
|
||||
}
|
||||
} else if (newOrder?.is_participant && this.lastOrder?.id !== newOrder.id) {
|
||||
this.activeOrder = newOrder;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
syncCoordinator: (coordinator: Coordinator, garage: Garage) => void = (coordinator, garage) => {
|
||||
syncCoordinator: (federation: Federation, shortAlias: string) => void = (
|
||||
federation,
|
||||
shortAlias,
|
||||
) => {
|
||||
const defaultRobot = this.getRobot();
|
||||
if (defaultRobot?.token) {
|
||||
this.robots[coordinator.shortAlias] = new Robot({
|
||||
this.robots[shortAlias] = new Robot({
|
||||
shortAlias,
|
||||
token: defaultRobot.token,
|
||||
pubKey: defaultRobot.pubKey,
|
||||
encPrivKey: defaultRobot.encPrivKey,
|
||||
});
|
||||
void coordinator.fetchRobot(garage, defaultRobot.token);
|
||||
this.robots[shortAlias].fetch(federation);
|
||||
this.updateSlotFromRobot(this.robots[shortAlias]);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user