Skip to content

Commit

Permalink
feat: add HighValueLoss emitter event (#86)
Browse files Browse the repository at this point in the history
* feat: add HighValueLoss emitter event

* fix: export HighValueLossUpdate props

* refactor: rename to RouteHighValueLoss

* feat: only trigger emit on continue

* refactor: remove unused emit + extract calc func

* refactor: adjust emit message

* refactor: move func to utils

* refactor: optimize token value loss threshold calculation

* refactor: optimize token value loss threshold calculation

---------

Co-authored-by: Eugene Chybisov <18644653+chybisov@users.noreply.github.com>
Co-authored-by: Eugene Chybisov <imchybisov@gmail.com>
  • Loading branch information
3 people authored May 16, 2023
1 parent 81c0773 commit 69d3918
Show file tree
Hide file tree
Showing 6 changed files with 67 additions and 26 deletions.
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

0 comments on commit 69d3918

Please sign in to comment.