Skip to content

Commit

Permalink
feat: add redeem support
Browse files Browse the repository at this point in the history
  • Loading branch information
toniocodo committed Oct 3, 2023
1 parent 9968b98 commit 46e09d6
Show file tree
Hide file tree
Showing 4 changed files with 109 additions and 94 deletions.
22 changes: 17 additions & 5 deletions libs/oeth/redeem/src/hooks.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { useCallback } from 'react';

import { contracts } from '@origin/shared/contracts';
import { usePushActivity, useUpdateActivity } from '@origin/oeth/shared';
import { contracts, tokens } from '@origin/shared/contracts';
import {
BlockExplorerLink,
usePushNotification,
Expand Down Expand Up @@ -40,6 +41,8 @@ export const useHandleRedeem = () => {
const intl = useIntl();
const { value: slippage } = useSlippage();
const pushNotification = usePushNotification();
const pushActivity = usePushActivity();
const updateActivity = useUpdateActivity();
const { address } = useAccount();
const [{ amountIn, amountOut }, setRedeemState] = useRedeemState();
const wagmiClient = useQueryClient();
Expand All @@ -49,6 +52,15 @@ export const useHandleRedeem = () => {
return;
}

const activity = pushActivity({
type: 'redeem',
status: 'pending',
tokenIn: tokens.mainnet.OETH,
tokenOut: MIX_TOKEN,
amountIn,
amountOut,
});

setRedeemState(
produce((draft) => {
draft.isRedeemLoading = true;
Expand All @@ -75,6 +87,7 @@ export const useHandleRedeem = () => {

console.log('redeem vault done!');
wagmiClient.invalidateQueries({ queryKey: ['redeem_balance'] });
updateActivity({ ...activity, status: 'success', txReceipt });
pushNotification({
title: intl.formatMessage({ defaultMessage: 'Redeem complete' }),
severity: 'success',
Expand All @@ -88,10 +101,7 @@ export const useHandleRedeem = () => {
severity: 'info',
});
} else {
pushNotification({
title: intl.formatMessage({ defaultMessage: 'Redeem vault' }),
severity: 'error',
});
updateActivity({ ...activity, status: 'error', error: e.short });
}
}

Expand All @@ -105,9 +115,11 @@ export const useHandleRedeem = () => {
amountIn,
amountOut,
intl,
pushActivity,
pushNotification,
setRedeemState,
slippage,
updateActivity,
wagmiClient,
]);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
import { Box, Stack, Typography } from '@mui/material';
import { LinkIcon } from '@origin/shared/components';
import { isNilOrEmpty } from '@origin/shared/utils';
import { defineMessage, useIntl } from 'react-intl';
import { formatUnits } from 'viem';

import { ActivityIcon } from './ActivityIcon';

import type { StackProps } from '@mui/material';
import type { MessageDescriptor } from 'react-intl';

import type { Activity, ActivityType } from '../types';

type ActivityItemProps = {
activity: Activity;
} & StackProps;

const activityLabel: Record<ActivityType, MessageDescriptor> = {
swap: defineMessage({ defaultMessage: 'Swapped' }),
approval: defineMessage({ defaultMessage: 'Approved' }),
redeem: defineMessage({ defaultMessage: 'Redeemed' }),
};

export const ActivityItem = ({ activity, ...rest }: ActivityItemProps) => {
const intl = useIntl();

return (
<Stack {...rest} direction="row" justifyContent="space-between">
<Stack spacing={1}>
<Stack direction="row" alignItems="center" spacing={1}>
<ActivityIcon
status={activity.status}
sx={{ width: 20, height: 20 }}
/>
<Typography>
{intl.formatMessage(activityLabel[activity.type])}
</Typography>
{!isNilOrEmpty(activity?.txReceipt?.transactionHash) && (
<LinkIcon
size={10}
url={`https://etherscan.io/tx/${activity.txReceipt.transactionHash}`}
/>
)}
</Stack>
<Stack direction="row" alignItems="center">
<Typography color="text.tertiary">
{intl.formatMessage(
{
defaultMessage:
'{amountIn} {symbolIn} for {amountOut} {symbolOut}',
},
{
amountIn: intl.formatNumber(
+formatUnits(activity.amountIn, activity.tokenIn.decimals),
{ minimumFractionDigits: 4, maximumFractionDigits: 4 },
),
symbolIn: activity.tokenIn.symbol,
amountOut: intl.formatNumber(
+formatUnits(activity.amountOut, activity.tokenOut.decimals),
{ minimumFractionDigits: 4, maximumFractionDigits: 4 },
),
symbolOut: activity.tokenOut.symbol,
},
)}
</Typography>
</Stack>
</Stack>
<Stack direction="row" alignItems="center" spacing={1}>
<Box
component="img"
src={activity.tokenIn.icon}
sx={{ width: 24, height: 24 }}
/>
<Box
component="img"
src="images/arrow-right.svg"
sx={{ width: 12, height: 12 }}
/>
<Box
component="img"
src={activity.tokenOut.icon}
sx={{ width: 24, height: 24 }}
/>
</Stack>
</Stack>
);
};
Original file line number Diff line number Diff line change
@@ -1,24 +1,14 @@
import {
Box,
Divider,
Popover,
Stack,
Typography,
useTheme,
} from '@mui/material';
import { LinkIcon } from '@origin/shared/components';
import { Divider, Popover, Stack, Typography, useTheme } from '@mui/material';
import { isNilOrEmpty } from '@origin/shared/utils';
import { descend, pipe, prop, sort, take } from 'ramda';
import { defineMessage, useIntl } from 'react-intl';
import { formatUnits } from 'viem';
import { useIntl } from 'react-intl';

import { useActivityState } from '../state';
import { ActivityIcon } from './ActivityIcon';
import { ActivityItem } from './ActivityItem';

import type { StackProps } from '@mui/material';
import type { MessageDescriptor } from 'react-intl';

import type { Activity, ActivityType } from '../types';
import type { Activity } from '../types';

export type AcitivityPopoverProps = {
anchor: HTMLElement | null;
Expand Down Expand Up @@ -89,80 +79,6 @@ export const ActivityPopover = ({
);
};

type ActivityItemProps = {
activity: Activity;
} & StackProps;

const activityLabel: Record<ActivityType, MessageDescriptor> = {
swap: defineMessage({ defaultMessage: 'Swapped' }),
approval: defineMessage({ defaultMessage: 'Approved' }),
};

function ActivityItem({ activity, ...rest }: ActivityItemProps) {
const intl = useIntl();

return (
<Stack {...rest} direction="row" justifyContent="space-between">
<Stack spacing={1}>
<Stack direction="row" alignItems="center" spacing={1}>
<ActivityIcon
status={activity.status}
sx={{ width: 20, height: 20 }}
/>
<Typography>
{intl.formatMessage(activityLabel[activity.type])}
</Typography>
{!isNilOrEmpty(activity?.txReceipt?.transactionHash) && (
<LinkIcon
size={10}
url={`https://etherscan.io/tx/${activity.txReceipt.transactionHash}`}
/>
)}
</Stack>
<Stack direction="row" alignItems="center">
<Typography color="text.tertiary">
{intl.formatMessage(
{
defaultMessage:
'{amountIn} {symbolIn} for {amountOut} {symbolOut}',
},
{
amountIn: intl.formatNumber(
+formatUnits(activity.amountIn, activity.tokenIn.decimals),
{ minimumFractionDigits: 4, maximumFractionDigits: 4 },
),
symbolIn: activity.tokenIn.symbol,
amountOut: intl.formatNumber(
+formatUnits(activity.amountOut, activity.tokenOut.decimals),
{ minimumFractionDigits: 4, maximumFractionDigits: 4 },
),
symbolOut: activity.tokenOut.symbol,
},
)}
</Typography>
</Stack>
</Stack>
<Stack direction="row" alignItems="center" spacing={1}>
<Box
component="img"
src={activity.tokenIn.icon}
sx={{ width: 24, height: 24 }}
/>
<Box
component="img"
src="images/arrow-right.svg"
sx={{ width: 12, height: 12 }}
/>
<Box
component="img"
src={activity.tokenOut.icon}
sx={{ width: 24, height: 24 }}
/>
</Stack>
</Stack>
);
}

function EmptyActivity(props: StackProps) {
const intl = useIntl();

Expand Down
2 changes: 1 addition & 1 deletion libs/oeth/shared/src/components/ActivityProvider/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
import type { Token } from '@origin/shared/contracts';
import type { TransactionReceipt } from 'viem';

export type ActivityType = 'swap' | 'approval';
export type ActivityType = 'swap' | 'approval' | 'redeem';

export type ActivityStatus = 'pending' | 'success' | 'error';

Expand Down

0 comments on commit 46e09d6

Please sign in to comment.