Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add HighValueLoss emitter event #86

Merged
merged 10 commits into from
May 16, 2023
11 changes: 9 additions & 2 deletions examples/nextjs/components/WidgetEvents.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
import type { Route } from '@lifi/sdk';
import type { RouteExecutionUpdate } from '@lifi/widget';
import { useWidgetEvents, WidgetEvent } from '@lifi/widget';
import type {
RouteExecutionUpdate,
RouteHighValueLossUpdate,
} from '@lifi/widget';
import { WidgetEvent, useWidgetEvents } from '@lifi/widget';
import { useEffect } from 'react';

export const WidgetEvents = () => {
Expand All @@ -19,12 +22,16 @@ export const WidgetEvents = () => {
const onRouteExecutionFailed = (update: RouteExecutionUpdate) => {
console.log('onRouteExecutionFailed fired.');
};
const onRouteHighValueLoss = (update: RouteHighValueLossUpdate) => {
console.log('onRouteHighValueLoss continued.');
};
widgetEvents.on(WidgetEvent.RouteExecutionStarted, onRouteExecutionStarted);
widgetEvents.on(WidgetEvent.RouteExecutionUpdated, onRouteExecutionUpdated);
widgetEvents.on(
WidgetEvent.RouteExecutionCompleted,
onRouteExecutionCompleted,
);
widgetEvents.on(WidgetEvent.RouteHighValueLoss, onRouteHighValueLoss);
widgetEvents.on(WidgetEvent.RouteExecutionFailed, onRouteExecutionFailed);
return () => widgetEvents.all.clear();
}, [widgetEvents]);
Expand Down
11 changes: 9 additions & 2 deletions packages/widget-playground/src/components/WidgetEvents.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
import type { Route } from '@lifi/sdk';
import type { RouteExecutionUpdate } from '@lifi/widget';
import { useWidgetEvents, WidgetEvent } from '@lifi/widget';
import type {
RouteExecutionUpdate,
RouteHighValueLossUpdate,
} from '@lifi/widget';
import { WidgetEvent, useWidgetEvents } from '@lifi/widget';
import { useEffect } from 'react';

export const WidgetEvents = () => {
Expand All @@ -19,12 +22,16 @@ export const WidgetEvents = () => {
const onRouteExecutionFailed = (update: RouteExecutionUpdate) => {
// console.log('onRouteExecutionFailed fired.');
};
const onRouteHighValueLoss = (update: RouteHighValueLossUpdate) => {
// console.log('onRouteHighValueLoss continued.');
};
widgetEvents.on(WidgetEvent.RouteExecutionStarted, onRouteExecutionStarted);
widgetEvents.on(WidgetEvent.RouteExecutionUpdated, onRouteExecutionUpdated);
widgetEvents.on(
WidgetEvent.RouteExecutionCompleted,
onRouteExecutionCompleted,
);
widgetEvents.on(WidgetEvent.RouteHighValueLoss, onRouteHighValueLoss);
widgetEvents.on(WidgetEvent.RouteExecutionFailed, onRouteExecutionFailed);
// widgetEvents.on(WidgetEvent.InputValuesUpdated, onInputValuesUpdated);
return () => widgetEvents.all.clear();
Expand Down
30 changes: 23 additions & 7 deletions packages/widget/src/pages/SwapPage/SwapPage.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import type { ExchangeRateUpdateParams } from '@lifi/sdk';
import DeleteIcon from '@mui/icons-material/Delete';
import { Box, Button, Tooltip } from '@mui/material';
import { useCallback, useRef, useState } from 'react';
import { useRef, useState } from 'react';
import { useFormContext } from 'react-hook-form';
import { useTranslation } from 'react-i18next';
import { useLocation } from 'react-router-dom';
Expand All @@ -10,9 +10,14 @@ import { ContractComponent } from '../../components/ContractComponent';
import { GasMessage } from '../../components/GasMessage';
import { Insurance } from '../../components/Insurance';
import { getStepList } from '../../components/Step';
import { useNavigateBack, useRouteExecution } from '../../hooks';
import {
useNavigateBack,
useRouteExecution,
useWidgetEvents,
} from '../../hooks';
import { SwapFormKey, useWidgetConfig } from '../../providers';
import { RouteExecutionStatus } from '../../stores';
import { WidgetEvent } from '../../types/events';
import type { ExchangeRateBottomSheetBase } from './ExchangeRateBottomSheet';
import { ExchangeRateBottomSheet } from './ExchangeRateBottomSheet';
import { StartIdleSwapButton, StartSwapButton } from './StartSwapButton';
Expand All @@ -22,10 +27,12 @@ import {
TokenValueBottomSheet,
getTokenValueLossThreshold,
} from './TokenValueBottomSheet';
import { calcValueLoss } from './utils';

export const SwapPage: React.FC = () => {
const { t } = useTranslation();
const { setValue } = useFormContext();
const emitter = useWidgetEvents();
const { navigateBack } = useNavigateBack();
const { variant, insurance } = useWidgetConfig();
const { state }: any = useLocation();
Expand All @@ -48,18 +55,27 @@ export const SwapPage: React.FC = () => {
onAcceptExchangeRateUpdate,
});

const handleExecuteRoute = useCallback(() => {
const tokenValueLossThresholdExceeded = getTokenValueLossThreshold(route);

const handleExecuteRoute = () => {
if (tokenValueBottomSheetRef.current?.isOpen()) {
if (route) {
emitter.emit(WidgetEvent.RouteHighValueLoss, {
fromAmountUsd: route.fromAmountUSD,
gasCostUSD: route.gasCostUSD,
toAmountUSD: route.toAmountUSD,
valueLoss: calcValueLoss(route),
});
}
tokenValueBottomSheetRef.current?.close();
}
executeRoute();
setValue(SwapFormKey.FromAmount, '');
}, [executeRoute, setValue]);
};

const handleSwapClick = async () => {
if (status === RouteExecutionStatus.Idle) {
const thresholdExceeded = getTokenValueLossThreshold(route);
if (thresholdExceeded && variant !== 'nft') {
if (tokenValueLossThresholdExceeded && variant !== 'nft') {
tokenValueBottomSheetRef.current?.open();
} else {
handleExecuteRoute();
Expand Down Expand Up @@ -160,7 +176,7 @@ export const SwapPage: React.FC = () => {
{route && status ? (
<StatusBottomSheet status={status} route={route} />
) : null}
{route && variant !== 'nft' ? (
{route && tokenValueLossThresholdExceeded && variant !== 'nft' ? (
<TokenValueBottomSheet
route={route}
ref={tokenValueBottomSheetRef}
Expand Down
22 changes: 7 additions & 15 deletions packages/widget/src/pages/SwapPage/TokenValueBottomSheet.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
import type { Route } from '@lifi/sdk';
import WarningRoundedIcon from '@mui/icons-material/WarningRounded';
import { Box, Button, Typography } from '@mui/material';
import Big from 'big.js';
import type { MutableRefObject } from 'react';
import { forwardRef, useRef } from 'react';
import { useTranslation } from 'react-i18next';
import type { BottomSheetBase } from '../../components/BottomSheet';
import { BottomSheet } from '../../components/BottomSheet';
import { useSetContentHeight } from '../../hooks';
import { CenterContainer, IconCircle } from './StatusBottomSheet.style';
import { calcValueLoss } from './utils';

interface TokenValueBottomSheetProps {
route: Route;
Expand Down Expand Up @@ -75,15 +75,7 @@ const TokenValueBottomSheetContent: React.FC<TokenValueBottomSheetProps> = ({
</Box>
<Box display="flex" justifyContent="space-between" mt={0.25}>
<Typography>{t('swap.valueLoss')}</Typography>
<Typography fontWeight={600}>
{Big(route.toAmountUSD || 0)
.div(Big(route.fromAmountUSD || 0).plus(Big(route.gasCostUSD || 0)))
.minus(1)
.mul(100)
.round(2, Big.roundUp)
.toString()}
%
</Typography>
<Typography fontWeight={600}>{calcValueLoss(route)}</Typography>
</Box>
<Box display="flex" mt={3}>
<Button variant="text" onClick={onCancel} fullWidth>
Expand All @@ -102,11 +94,11 @@ export const getTokenValueLossThreshold = (route?: Route) => {
if (!route) {
return false;
}
const fromAmountUSD = Big(route?.fromAmountUSD || 0);
const toAmountUSD = Big(route?.toAmountUSD || 0);
const gasCostUSD = Big(route?.gasCostUSD || 0);
if (fromAmountUSD.eq(0) && toAmountUSD.eq(0)) {
const fromAmountUSD = Number(route.fromAmountUSD || 0);
const toAmountUSD = Number(route.toAmountUSD || 0);
const gasCostUSD = Number(route.gasCostUSD || 0);
if (!fromAmountUSD && !toAmountUSD) {
return false;
}
return toAmountUSD.div(fromAmountUSD.plus(gasCostUSD)).lt(0.9);
return toAmountUSD / (fromAmountUSD + gasCostUSD) < 0.9;
};
10 changes: 10 additions & 0 deletions packages/widget/src/pages/SwapPage/utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import type { Route } from '@lifi/sdk';

export const calcValueLoss = (route: Route) => {
return `${(
(Number(route.toAmountUSD || 0) /
(Number(route.fromAmountUSD || 0) + Number(route.gasCostUSD || 0)) -
1) *
100
).toFixed(2)}%`;
};
9 changes: 9 additions & 0 deletions packages/widget/src/types/events.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,22 @@ export enum WidgetEvent {
RouteExecutionUpdated = 'routeExecutionUpdated',
RouteExecutionCompleted = 'routeExecutionCompleted',
RouteExecutionFailed = 'routeExecutionFailed',
RouteHighValueLoss = 'routeHighValueLoss',
}

export interface RouteHighValueLossUpdate {
fromAmountUsd: string;
gasCostUSD: string | undefined;
toAmountUSD: string;
valueLoss: string;
}

export type WidgetEvents = {
routeExecutionStarted: Route;
routeExecutionUpdated: RouteExecutionUpdate;
routeExecutionCompleted: Route;
routeExecutionFailed: RouteExecutionUpdate;
routeHighValueLoss: RouteHighValueLossUpdate;
};

export interface RouteExecutionUpdate {
Expand Down