diff --git a/apps/oeth/index.html b/apps/oeth/index.html
index 84b20c80b..c7ac055cd 100644
--- a/apps/oeth/index.html
+++ b/apps/oeth/index.html
@@ -2,7 +2,7 @@
- Oeth
+ OETH
{
return (
<>
-
+
({
+ xs: '112px',
+ md: `${theme.mixins.toolbar.height}px`,
+ }),
}}
maxWidth="sm"
>
-
-
-
+
>
diff --git a/apps/oeth/src/components/Topnav.tsx b/apps/oeth/src/components/Topnav.tsx
index ec85e1b58..035e03fae 100644
--- a/apps/oeth/src/components/Topnav.tsx
+++ b/apps/oeth/src/components/Topnav.tsx
@@ -33,20 +33,32 @@ export function Topnav(props: BoxProps) {
return (
({
+ position: 'fixed',
+ top: 0,
+ left: 0,
+ width: 1,
+ zIndex: theme.zIndex.appBar,
+ backgroundColor: alpha(theme.palette.background.default, 0.6),
+ backdropFilter: 'blur(15px)',
+ height: {
+ xs: '112px',
+ md: `${theme.mixins.toolbar.height}px`,
+ },
display: 'grid',
- borderBlockEnd: {
+ borderBottom: {
xs: 'none',
- md: '1px solid var(--mui-palette-background-paper)',
+ md: `1px solid ${theme.palette.background.paper}`,
},
- gap: { xs: 1, md: 10 },
+ columnGap: { xs: 1, md: 10 },
+ rowGap: { xs: 0, md: 10 },
alignItems: 'center',
- backgroundColor: 'divider',
- paddingInline: {
+ px: {
xs: 1.5,
md: 3,
},
- paddingBlockStart: {
+ pt: {
xs: 1.5,
md: 0,
},
@@ -54,8 +66,7 @@ export function Topnav(props: BoxProps) {
xs: '1fr 1fr',
md: 'auto 1fr auto',
},
- ...props?.sx,
- }}
+ })}
>
- `linear-gradient(90deg, ${alpha(
- theme.palette.primary.main,
- 0.4,
- )} 0%, ${alpha(theme.palette.primary.dark, 0.4)} 100%)`,
- position: 'absolute',
- left: 0,
- bottom: 0,
- zIndex: 2,
- },
- }}
/>
))}
-
a, & > *': {
- fontSize: {
- xs: '0.75rem',
- md: '1rem',
- },
- color: (theme) => theme.palette.primary.contrastText,
- lineHeight: (theme) => theme.spacing(3),
- },
}}
>
theme.palette.background.paper,
- backgroundImage: 'none',
},
- color: 'primary.contrastText',
- boxSizing: 'border-box',
- lineHeight: '1rem',
}}
>
{isMd
@@ -205,6 +169,21 @@ export function Topnav(props: BoxProps) {
setAccountModalAnchor(e.currentTarget);
}
}}
+ sx={{
+ borderRadius: 25,
+ paddingX: {
+ md: 3,
+ xs: 2,
+ },
+ paddingY: {
+ md: 1,
+ xs: 0.75,
+ },
+ minWidth: 36,
+ maxWidth: { xs: isConnected ? 36 : 160, sm: 160, lg: 220 },
+ fontWeight: 500,
+ minHeight: { xs: 36, md: 44 },
+ }}
/>
theme.palette.background.paper,
position: 'relative',
width: 'calc(100% + 1.5rem)',
- bottom: '-3.75rem',
+ bottom: '-3rem',
left: '-0.75rem',
}}
/>
diff --git a/apps/oeth/src/main.tsx b/apps/oeth/src/main.tsx
index 2076a176c..7a5c729ad 100644
--- a/apps/oeth/src/main.tsx
+++ b/apps/oeth/src/main.tsx
@@ -8,6 +8,7 @@ import { Experimental_CssVarsProvider as CssVarsProvider } from '@mui/material';
import { chains, queryClient, wagmiConfig } from '@origin/oeth/shared';
import {
CurveProvider,
+ GeoFenceProvider,
NotificationsProvider,
registerChart,
} from '@origin/shared/providers';
@@ -42,6 +43,7 @@ root.render(
[RainbowKitProvider, { chains: chains, theme: darkTheme() }],
[CurveProvider],
[NotificationsProvider],
+ [GeoFenceProvider],
],
,
),
diff --git a/libs/oeth/history/src/components/APYContainer.tsx b/libs/oeth/history/src/components/APYContainer.tsx
index 9e95389ac..3b5e28f5e 100644
--- a/libs/oeth/history/src/components/APYContainer.tsx
+++ b/libs/oeth/history/src/components/APYContainer.tsx
@@ -85,6 +85,7 @@ function ValueContainer({
paddingBlock: 2,
alignItems: 'center',
textAlign: 'center',
+ justifyContent: 'space-between',
flex: 1,
...rest?.sx,
}}
@@ -92,17 +93,7 @@ function ValueContainer({
{label}
- theme.typography.pxToRem(20),
- fontStyle: 'normal',
- fontWeight: 700,
- lineHeight: '2rem',
- textAlign: 'center',
- }}
- color="primary.contrastText"
- >
+
{isLoading ? : value}
diff --git a/libs/oeth/history/src/components/ChartCard.tsx b/libs/oeth/history/src/components/ChartCard.tsx
index 3e4519694..3cc200aaa 100644
--- a/libs/oeth/history/src/components/ChartCard.tsx
+++ b/libs/oeth/history/src/components/ChartCard.tsx
@@ -1,5 +1,11 @@
-import { Stack, Typography, useTheme } from '@mui/material';
-import { Card } from '@origin/shared/components';
+import {
+ Card,
+ CardContent,
+ CardHeader,
+ Stack,
+ Typography,
+ useTheme,
+} from '@mui/material';
import { Line } from 'react-chartjs-2';
import { useIntl } from 'react-intl';
@@ -13,82 +19,81 @@ export function ChartCard(props: Props) {
const intl = useIntl();
return (
- {intl.formatMessage({ defaultMessage: 'APY' })}>}
- >
-
-
- {intl.formatNumber(props.apyPercent / 100, {
- style: 'percent',
- maximumFractionDigits: 2,
- })}
-
-
- {intl.formatDate(new Date(), {
- month: 'long',
- day: 'numeric',
- year: 'numeric',
- })}
-
-
+
+
+
+
+
+ {intl.formatNumber(props.apyPercent / 100, {
+ style: 'percent',
+ maximumFractionDigits: 2,
+ })}
+
+
+ {intl.formatDate(new Date(), {
+ month: 'long',
+ day: 'numeric',
+ year: 'numeric',
+ })}
+
+
- ({
- x: intl.formatDate(new Date(item.timestamp), {
- month: 'short',
- day: 'numeric',
- }),
- y: item.value,
- })),
- pointRadius: 0,
- tension: 0.5,
- },
- ],
- }}
- />
+ }}
+ data={{
+ datasets: [
+ {
+ data: props.apy.map((item) => ({
+ x: intl.formatDate(new Date(item.timestamp), {
+ month: 'short',
+ day: 'numeric',
+ }),
+ y: item.value,
+ })),
+ pointRadius: 0,
+ tension: 0.5,
+ },
+ ],
+ }}
+ />
+
);
}
diff --git a/libs/oeth/history/src/components/HistoryButton.tsx b/libs/oeth/history/src/components/HistoryButton.tsx
index 2d4220121..c92c8388c 100644
--- a/libs/oeth/history/src/components/HistoryButton.tsx
+++ b/libs/oeth/history/src/components/HistoryButton.tsx
@@ -29,13 +29,12 @@ export function HistoryFilterButton({
borderRadius: 8,
paddingInline: 2,
paddingBlock: 0.5,
- fontSize: (theme) => theme.typography.pxToRem(12),
- color: 'primary.contrastText',
+ fontSize: 12,
fontWeight: 500,
fontStyle: 'normal',
- lineHeight: (theme) => theme.typography.pxToRem(20),
+ lineHeight: 1.6,
':hover': {
- background: (theme) => alpha(theme.palette.common.white, 0.1),
+ background: (theme) => alpha(theme.palette.common.white, 0.04),
},
...sx,
}}
diff --git a/libs/oeth/history/src/components/HistoryCard.tsx b/libs/oeth/history/src/components/HistoryCard.tsx
index 65678ec3d..81b8b189b 100644
--- a/libs/oeth/history/src/components/HistoryCard.tsx
+++ b/libs/oeth/history/src/components/HistoryCard.tsx
@@ -1,12 +1,13 @@
import { useState } from 'react';
-import { Box, Button, Divider, Stack, Typography } from '@mui/material';
+import { Box, Divider, Stack, Typography } from '@mui/material';
+import { ConnectedButton } from '@origin/shared/providers';
import { useIntl } from 'react-intl';
import { useAccount } from 'wagmi';
import { useHistoryTableWithFiltersQuery } from '../queries.generated';
import { ExportData } from './ExportData';
-import { HistoryFilters } from './Filters';
+import { HistoryFilters } from './HistoryFilters';
import { HistoryTable } from './HistoryTable';
const PAGE_SIZE = 20;
@@ -19,7 +20,7 @@ export function HistoryCard() {
const { data, isFetching } = useHistoryTableWithFiltersQuery(
{
- address: address.toLowerCase(),
+ address: address?.toLowerCase(),
filters: filters.length ? filters : undefined,
offset: page * PAGE_SIZE,
},
@@ -37,11 +38,14 @@ export function HistoryCard() {
alignItems="center"
justifyContent="space-between"
>
-
+
{intl.formatMessage({ defaultMessage: 'OETH transactions' })}
- setFilters(values)} />
+ setFilters(values)}
+ />
@@ -56,14 +60,21 @@ export function HistoryCard() {
setPage={(page) => setPage(page)}
/>
) : (
-
+
{intl.formatMessage({
defaultMessage: 'Connect your wallet to see your history',
})}
-
-
+
+
)}
);
diff --git a/libs/oeth/history/src/components/HistoryCell.tsx b/libs/oeth/history/src/components/HistoryCell.tsx
index 08fc49609..6524752f3 100644
--- a/libs/oeth/history/src/components/HistoryCell.tsx
+++ b/libs/oeth/history/src/components/HistoryCell.tsx
@@ -25,7 +25,7 @@ export function HistoryCell(props: Props) {
{/* @ts-expect-error whatever */}
- {props.type}
+ {props.type}
{intl.formatDate(new Date(props.timestamp))}
diff --git a/libs/oeth/history/src/components/Filters.tsx b/libs/oeth/history/src/components/HistoryFilters.tsx
similarity index 57%
rename from libs/oeth/history/src/components/Filters.tsx
rename to libs/oeth/history/src/components/HistoryFilters.tsx
index 420d8488c..a0efc550a 100644
--- a/libs/oeth/history/src/components/Filters.tsx
+++ b/libs/oeth/history/src/components/HistoryFilters.tsx
@@ -1,44 +1,49 @@
-import React, { useState } from 'react';
+import { useState } from 'react';
import {
- alpha,
Box,
Button,
Checkbox,
Divider,
- FormLabel,
+ FormControlLabel,
Popover,
Stack,
Typography,
useTheme,
} from '@mui/material';
-import {
- ActionButton,
- CheckboxIcon,
- EmptyCheckbox,
-} from '@origin/shared/components';
-import { useIntl } from 'react-intl';
+import { isNilOrEmpty } from '@origin/shared/utils';
+import { defineMessage, useIntl } from 'react-intl';
import { HistoryFilterButton } from './HistoryButton';
const styles = {
- fontSize: '0.75rem',
+ fontSize: 12,
fontWeight: 500,
- lineHeight: '1.25rem',
- color: 'primary.contrastText',
+ lineHeight: 1.6,
};
-interface Props {
+const filterOptions = [
+ { label: defineMessage({ defaultMessage: 'Yield' }), value: 'Yield' },
+ { label: defineMessage({ defaultMessage: 'Swap' }), value: 'Swap' },
+ { label: defineMessage({ defaultMessage: 'Sent' }), value: 'Sent' },
+ { label: defineMessage({ defaultMessage: 'Received' }), value: 'Received' },
+];
+
+export type HistoryFiltersProps = {
+ filters: string[];
onChange: (values: string[]) => void;
-}
+};
-export function HistoryFilters({ onChange }: Props) {
- const [selected, setSelectedTypes] = useState([]);
+export function HistoryFilters({ filters, onChange }: HistoryFiltersProps) {
+ const [selected, setSelectedTypes] = useState(filters);
const intl = useIntl();
const theme = useTheme();
const [anchorEl, setAnchorEl] = useState(null);
- function selection(e: React.ChangeEvent, label: string) {
+ const handleSelect = (
+ e: React.ChangeEvent,
+ label: string,
+ ) => {
setSelectedTypes((prev) => {
if (e.target.checked) {
return [...prev, label];
@@ -46,12 +51,17 @@ export function HistoryFilters({ onChange }: Props) {
return prev.filter((val) => val !== label);
}
});
- }
+ };
+
+ const applyDisabled =
+ filters.length === selected.length &&
+ filters.every((item) => selected.includes(item));
+ const clearDisabled = isNilOrEmpty(selected);
return (
<>
setAnchorEl(e.currentTarget)}>
- Filters
+ {intl.formatMessage({ defaultMessage: 'Filters' })}
theme.palette.primary.contrastText,
}}
>
- {selected.length}
+ {filters.length}
-
+
{intl.formatMessage({ defaultMessage: 'Filters' })}
-
- {['Yield', 'Swap', 'Sent', 'Received'].map((label) => (
+ {filterOptions.map((filter) => (
theme.palette.grey[700],
},
}}
>
-
- {label}
-
-
- }
- icon={}
- sx={{
- '& svg, input': {
- width: '1.25rem',
- height: '1.25rem',
- top: 'auto',
- left: 'auto',
- },
- '&:hover:has(input:checked) svg': {
- fill: (theme) => alpha(theme.palette.secondary.main, 0.4),
- strokeWidth: '1px',
- stroke: (theme) => theme.palette.primary.main,
- },
- '&:hover:has(input:not(:checked)) svg': {
- fill: (theme) => alpha(theme.palette.secondary.main, 0.4),
- },
- }}
- onChange={(e) => selection(e, label)}
+ handleSelect(e, filter.value)}
+ sx={{
+ ':hover': {
+ backgroundColor: 'transparent',
+ },
+ }}
+ />
+ }
+ sx={{ width: 1 }}
+ slotProps={{ typography: { width: 1 } }}
/>
))}
-
-
{intl.formatMessage({ defaultMessage: 'Apply' })}
-
+
>
diff --git a/libs/oeth/history/src/components/HistoryTable.tsx b/libs/oeth/history/src/components/HistoryTable.tsx
index c12d6ea70..53c8008ea 100644
--- a/libs/oeth/history/src/components/HistoryTable.tsx
+++ b/libs/oeth/history/src/components/HistoryTable.tsx
@@ -1,13 +1,13 @@
import { useMemo } from 'react';
import {
- Box,
Stack,
Table,
TableBody,
TableCell,
TableHead,
TableRow,
+ Typography,
} from '@mui/material';
import { LinkIcon } from '@origin/shared/components';
import { quantityFormat } from '@origin/shared/utils';
@@ -64,37 +64,37 @@ export function HistoryTable({
},
}),
columnHelper.accessor('value', {
- cell: (info) => intl.formatNumber(info.getValue(), quantityFormat),
- header: intl.formatMessage({ defaultMessage: 'Change' }),
+ cell: (info) => (
+
+ {intl.formatNumber(info.getValue(), quantityFormat)}
+
+ ),
+ header: () => (
+
+ {intl.formatMessage({ defaultMessage: 'Change' })}
+
+ ),
}),
columnHelper.accessor('balance', {
cell: (info) => (
-
-
- {intl.formatNumber(info.getValue(), quantityFormat)}
-
-
-
-
+
+ {intl.formatNumber(info.getValue(), quantityFormat)}
+
+ ),
+ header: () => (
+
+ {intl.formatMessage({ defaultMessage: 'Balance' })}
+
+ ),
+ }),
+ columnHelper.display({
+ id: 'link',
+ cell: (info) => (
+
),
- header: intl.formatMessage({ defaultMessage: 'Balance' }),
}),
],
[intl],
@@ -118,7 +118,7 @@ export function HistoryTable({
});
return (
-
+
@@ -155,12 +155,15 @@ export function HistoryTable({
'& > *:first-of-type': {
width: '50%',
},
+ '& > *:last-of-type': {
+ pl: 0,
+ textAlign: 'end',
+ },
}}
>
{row.getVisibleCells().map((cell) => (
{intl.formatMessage({ defaultMessage: 'Previous' })}
+
+ {intl.formatMessage(
+ { defaultMessage: 'Page {page}' },
+ { page: page + 1 },
+ )}
+
setPage(page + 1)}
diff --git a/libs/oeth/history/src/queries.generated.ts b/libs/oeth/history/src/queries.generated.ts
index 501572792..e6913fc17 100644
--- a/libs/oeth/history/src/queries.generated.ts
+++ b/libs/oeth/history/src/queries.generated.ts
@@ -16,6 +16,7 @@ export type HistoryTableQuery = {
earned: number;
isContract: boolean;
rebasingOption: string;
+ credits: any;
lastUpdated: any;
history: Array<{
__typename?: 'History';
@@ -44,7 +45,6 @@ export type HistoryTableWithFiltersQuery = {
earned: number;
isContract: boolean;
rebasingOption: string;
- credits: any;
lastUpdated: any;
history: Array<{
__typename?: 'History';
@@ -71,6 +71,7 @@ export const HistoryTableDocument = `
earned
isContract
rebasingOption
+ credits
lastUpdated
history(limit: 20, orderBy: timestamp_DESC, offset: $offset) {
type
@@ -118,7 +119,6 @@ export const HistoryTableWithFiltersDocument = `
earned
isContract
rebasingOption
- credits
lastUpdated
history(
limit: 20
diff --git a/libs/oeth/redeem/src/components/RedeemRoute.tsx b/libs/oeth/redeem/src/components/RedeemRoute.tsx
index 23c90b35e..155619451 100644
--- a/libs/oeth/redeem/src/components/RedeemRoute.tsx
+++ b/libs/oeth/redeem/src/components/RedeemRoute.tsx
@@ -24,12 +24,7 @@ export function RedeemRoute(props: Omit) {
}}
>
{isEstimateLoading ? (
- ({ color: theme.palette.primary.contrastText })}
- >
+
) {
component={Typography}
variant="body2"
alignItems="center"
- color="primary.contrastText"
>
{intl.formatMessage({ defaultMessage: 'Route' })}
) => {
const intl = useIntl();
+ const theme = useTheme();
+ const isXs = useMediaQuery(theme.breakpoints.down('sm'));
const { data: prices, isLoading: isPricesLoading } = usePrices();
const [{ amountOut, gas, rate, split, isEstimateLoading }] = useRedeemState();
const { data: gasPrice, isLoading: gasPriceLoading } = useGasPrice(gas);
@@ -36,59 +48,59 @@ export const RedeemSplitCard = (props: Omit) => {
`linear-gradient(${theme.palette.grey[800]}, ${theme.palette.grey[800]}) padding-box,
linear-gradient(90deg, var(--mui-palette-primary-main) 0%, var(--mui-palette-primary-dark) 100%) border-box;`,
...props?.sx,
+ overflow: 'hidden',
+ whiteSpace: 'nowrap',
}}
>
-
-
-
-
-
- {isEstimateLoading ? (
-
- ) : (
- formatAmount(amountOut, MIX_TOKEN.decimals)
- )}
-
-
- {isEstimateLoading ? (
-
- ) : (
- `(${intl.formatNumber(convertedAmount, currencyFormat)})`
- )}
-
+
+ {!isXs && (
+
+
+
+ )}
+
+
+
+
+ {isEstimateLoading ? (
+
+ ) : (
+ formatAmount(amountOut, MIX_TOKEN.decimals)
+ )}
+
+
+ {isEstimateLoading ? (
+
+ ) : (
+ `(${intl.formatNumber(convertedAmount, currencyFormat)})`
+ )}
+
+
+
+
+ {intl.formatMessage({ defaultMessage: 'Gas:' })}
+
+
+ {isEstimateLoading || gasPriceLoading ? (
+
+ ) : (
+ `~${intl.formatNumber(gasPrice?.gasCostUsd, currencyFormat)}`
+ )}
+
+
-
+
{intl.formatMessage({
defaultMessage: 'Redeem for mix via OETH vault',
})}
-
-
-
- {intl.formatMessage({ defaultMessage: 'Gas:' })}
-
-
- {isEstimateLoading || gasPriceLoading ? (
-
- ) : (
- `~${intl.formatNumber(gasPrice?.gasCostUsd, currencyFormat)}`
- )}
-
-
-
-
- {intl.formatMessage({ defaultMessage: 'Wait time:' })}
-
-
- {isEstimateLoading ? (
-
- ) : (
- intl.formatMessage({ defaultMessage: '~1 min' })
- )}
-
-
-
) => {
px={1.5}
py={1.5}
>
-
-
+
+
{intl.formatMessage({ defaultMessage: 'Rate:' })}
-
+
{isEstimateLoading ? (
) : (
@@ -124,46 +131,80 @@ export const RedeemSplitCard = (props: Omit) => {
- {split?.map((s) => {
- const converted =
- +formatUnits(s.amount, s.token.decimals) * prices?.[s.token.symbol];
-
- return (
-
-
-
- {s.token.symbol}
-
-
-
- {isEstimateLoading ? (
-
- ) : (
- formatAmount(s.amount, s.token.decimals)
- )}
-
- {isPricesLoading || isEstimateLoading ? (
-
- ) : (
-
- {intl.formatNumber(converted, currencyFormat)}
-
- )}
-
-
- );
- })}
+ {split?.map((s) => (
+
+ ))}
);
};
+
+type SplitRowProps = {
+ estimate: RedeemEstimate;
+ price: number;
+ isEstimateLoading: boolean;
+ isPricesLoading: boolean;
+} & StackProps;
+
+function SplitRow({
+ estimate,
+ price,
+ isEstimateLoading,
+ isPricesLoading,
+ ...rest
+}: SplitRowProps) {
+ const intl = useIntl();
+
+ const converted =
+ +formatUnits(estimate.amount, estimate.token.decimals) * price;
+
+ return (
+
+
+
+ {estimate.token.symbol}
+
+
+
+ {isEstimateLoading ? (
+
+ ) : (
+ formatAmount(estimate.amount, estimate.token.decimals)
+ )}
+
+ {isPricesLoading || isEstimateLoading ? (
+
+ ) : (
+
+ {intl.formatNumber(converted, currencyFormat)}
+
+ )}
+
+
+ );
+}
diff --git a/libs/oeth/redeem/src/state.ts b/libs/oeth/redeem/src/state.ts
index fb1bab443..9591b9f82 100644
--- a/libs/oeth/redeem/src/state.ts
+++ b/libs/oeth/redeem/src/state.ts
@@ -158,8 +158,8 @@ export const { Provider: RedeemProvider, useTracked: useRedeemState } =
draft.split.forEach((a, i) => (a.amount = splitEstimates[i]));
draft.gas = gasEstimate;
draft.rate =
- +formatUnits(state.amountIn, tokens.mainnet.OETH.decimals) /
- +formatUnits(total, MIX_TOKEN.decimals);
+ +formatUnits(total, MIX_TOKEN.decimals) /
+ +formatUnits(state.amountIn, tokens.mainnet.OETH.decimals);
draft.isEstimateLoading = false;
}),
);
diff --git a/libs/oeth/redeem/src/views/RedeemView.tsx b/libs/oeth/redeem/src/views/RedeemView.tsx
index bac846849..159d12084 100644
--- a/libs/oeth/redeem/src/views/RedeemView.tsx
+++ b/libs/oeth/redeem/src/views/RedeemView.tsx
@@ -1,6 +1,15 @@
-import { alpha, Box, CircularProgress, Stack, Typography } from '@mui/material';
+import {
+ alpha,
+ Box,
+ Card,
+ CardContent,
+ CardHeader,
+ CircularProgress,
+ Stack,
+ Typography,
+} from '@mui/material';
import { GasPopover } from '@origin/oeth/shared';
-import { Card, TokenInput } from '@origin/shared/components';
+import { TokenInput } from '@origin/shared/components';
import { tokens } from '@origin/shared/contracts';
import { ConnectedButton, usePrices } from '@origin/shared/providers';
import { composeContexts } from '@origin/shared/utils';
@@ -27,14 +36,13 @@ const tokenInputStyles = {
boxSizing: 'border-box',
'& .MuiInputBase-input': {
padding: 0,
- lineHeight: '1.875rem',
boxSizing: 'border-box',
fontStyle: 'normal',
- fontFamily: 'Sailec, Inter, Helvetica, Arial, sans-serif',
- fontSize: '1.5rem',
+ fontFamily: 'Sailec, sans-serif',
+ fontSize: 24,
+ lineHeight: 1.5,
fontWeight: 700,
- height: '1.5rem',
- color: 'primary.contrastText',
+ color: 'text.primary',
'&::placeholder': {
color: 'text.secondary',
opacity: 1,
@@ -61,52 +69,39 @@ function RedeemViewWrapped() {
const handleAmountInChange = useHandleAmountInChange();
const handleRedeem = useHandleRedeem();
- const amountInInputDisabled = isRedeemLoading;
-
const redeemButtonLabel =
amountIn === 0n
? intl.formatMessage({ defaultMessage: 'Enter an amount' })
: amountIn > balOeth?.value
? intl.formatMessage({ defaultMessage: 'Insufficient funds' })
: intl.formatMessage({ defaultMessage: 'Redeem for mix' });
- const redeemButtonLoading = isEstimateLoading || isRedeemLoading;
const redeemButtonDisabled =
isBalOethLoading ||
- redeemButtonLoading ||
+ isEstimateLoading ||
+ isRedeemLoading ||
amountIn > balOeth?.value ||
amountIn === 0n;
return (
-
-
- {intl.formatMessage({ defaultMessage: 'Redeem' })}
-
-
-
- }
- >
-
+
+
+
+ {intl.formatMessage({ defaultMessage: 'Redeem' })}
+
+
+
+ }
+ />
+
-
-
-
-
-
-
- {redeemButtonLoading ? (
-
- ) : (
- redeemButtonLabel
- )}
-
+
+
+
+
+
+ {isEstimateLoading ? (
+
+ ) : isRedeemLoading ? (
+ intl.formatMessage({ defaultMessage: 'Waiting for signature' })
+ ) : (
+ redeemButtonLabel
+ )}
+
+
);
}
@@ -189,10 +186,10 @@ function ArrowButton(props: BoxProps) {
display: 'flex',
justifyContent: 'center',
alignItems: 'center',
- top: { md: `calc(50% - ${48 / 2}px)`, xs: `calc(50% - ${32 / 2}px)` },
- left: { md: `calc(50% - ${48 / 2}px)`, xs: `calc(50% - ${32 / 2}px)` },
- width: { md: 48, xs: 32 },
- height: { md: 48, xs: 32 },
+ top: { md: `calc(50% - ${40 / 2}px)`, xs: `calc(50% - ${36 / 2}px)` },
+ left: { md: `calc(50% - ${40 / 2}px)`, xs: `calc(50% - ${36 / 2}px)` },
+ width: { md: 40, xs: 36 },
+ height: { md: 40, xs: 36 },
zIndex: 2,
fill: (theme) => theme.palette.background.paper,
strokeWidth: (theme) => theme.typography.pxToRem(2),
@@ -207,7 +204,7 @@ function ArrowButton(props: BoxProps) {
component="img"
src="/images/splitarrow.svg"
sx={{
- height: { md: 'auto', xs: '1.25rem' },
+ height: { md: 20, xs: 18 },
}}
/>
diff --git a/libs/oeth/shared/src/components/AccountPopover.tsx b/libs/oeth/shared/src/components/AccountPopover.tsx
index 8c0962399..3cac0c061 100644
--- a/libs/oeth/shared/src/components/AccountPopover.tsx
+++ b/libs/oeth/shared/src/components/AccountPopover.tsx
@@ -1,5 +1,4 @@
import {
- alpha,
Box,
Button,
Divider,
@@ -9,11 +8,12 @@ import {
Typography,
useTheme,
} from '@mui/material';
-import { Icon, LinkIcon, MiddleTruncated } from '@origin/shared/components';
+import { Icon, LinkIcon } from '@origin/shared/components';
import { tokens } from '@origin/shared/contracts';
-import { formatAmount } from '@origin/shared/utils';
+import { AddressLabel } from '@origin/shared/providers';
import { map, prop } from 'ramda';
import { useIntl } from 'react-intl';
+import { formatUnits } from 'viem';
import { useAccount, useBalance, useContractReads, useDisconnect } from 'wagmi';
import type { StackProps } from '@mui/material';
@@ -27,8 +27,6 @@ const balanceTokens = [
tokens.mainnet.stETH,
];
-const padding = { paddingInline: 2, paddingBlock: 3 };
-
interface Props {
anchor: HTMLElement | null;
setAnchor: (value: HTMLButtonElement | null) => void;
@@ -82,7 +80,7 @@ export function AccountPopover({ anchor, setAnchor }: Props) {
borderRadius: 1,
width: (theme) => ({
xs: '90vw',
- md: `min(${theme.typography.pxToRem(300)}, 90vw)`,
+ md: `min(${theme.typography.pxToRem(250)}, 90vw)`,
}),
[theme.breakpoints.down('md')]: {
left: '0 !important',
@@ -97,25 +95,12 @@ export function AccountPopover({ anchor, setAnchor }: Props) {
justifyContent="space-between"
alignItems="center"
direction="row"
- sx={padding}
+ sx={{ px: 2, py: 1.5 }}
>
-
+
{intl.formatMessage({ defaultMessage: 'Account' })}
{intl.formatMessage({ defaultMessage: 'Est gas' })}
-
+
~{intl.formatNumber(gas, currencyFormat)}
diff --git a/libs/oeth/swap/src/components/SwapRouteCard.tsx b/libs/oeth/swap/src/components/SwapRouteCard.tsx
index 38dc30b6b..04310e9df 100644
--- a/libs/oeth/swap/src/components/SwapRouteCard.tsx
+++ b/libs/oeth/swap/src/components/SwapRouteCard.tsx
@@ -8,6 +8,7 @@ import {
Typography,
} from '@mui/material';
import Grid2 from '@mui/material/Unstable_Grid2/Grid2';
+import { tokens } from '@origin/shared/contracts';
import { useGasPrice, usePrices } from '@origin/shared/providers';
import {
currencyFormat,
@@ -17,7 +18,7 @@ import {
import { useIntl } from 'react-intl';
import { formatUnits } from 'viem';
-import { routeActionLabel, routeActionLogos } from '../constants';
+import { routeActionLabel } from '../constants';
import { useSwapRouteAllowance } from '../hooks';
import { useSwapState } from '../state';
@@ -104,6 +105,7 @@ export function SwapRouteCard({
@@ -113,15 +115,17 @@ export function SwapRouteCard({
) : (
)}
-
+
{isLoading ? (
) : (
@@ -145,11 +149,11 @@ export function SwapRouteCard({
position: 'absolute',
borderBottomLeftRadius: (theme) => theme.shape.borderRadius,
background: (theme) => theme.palette.background.gradient1,
- color: 'primary.contrastText',
- fontSize: (theme) => theme.typography.pxToRem(12),
+ fontSize: 12,
top: (theme) => theme.spacing(-3),
- right: (theme) => theme.spacing(-2),
- paddingInline: 1,
+ right: (theme) => theme.spacing(-1.25),
+ px: 1,
+ pt: 0.25,
}}
>
{intl.formatMessage({ defaultMessage: 'Best' })}
@@ -159,11 +163,7 @@ export function SwapRouteCard({
}
>
-
+
{isLoading ? (
) : (
@@ -174,13 +174,13 @@ export function SwapRouteCard({
-
+
{intl.formatMessage({ defaultMessage: 'Rate:' })}
-
+
{isLoading ? (
) : (
@@ -191,13 +191,13 @@ export function SwapRouteCard({
-
+
{intl.formatMessage({ defaultMessage: 'Gas:' })}
-
+
{isGasLoading ? (
) : (
diff --git a/libs/oeth/swap/src/components/TokenSelectModal.tsx b/libs/oeth/swap/src/components/TokenSelectModal.tsx
index 45a8cdfe6..1148e6df5 100644
--- a/libs/oeth/swap/src/components/TokenSelectModal.tsx
+++ b/libs/oeth/swap/src/components/TokenSelectModal.tsx
@@ -1,7 +1,6 @@
import {
Box,
Dialog,
- Divider,
MenuItem,
MenuList,
Skeleton,
@@ -9,12 +8,8 @@ import {
Typography,
} from '@mui/material';
import { usePrices } from '@origin/shared/providers';
-import {
- currencyFormat,
- formatAmount,
- isNilOrEmpty,
-} from '@origin/shared/utils';
-import { partition, pipe, prop, reject } from 'ramda';
+import { currencyFormat, formatAmount } from '@origin/shared/utils';
+import { ascend, descend, prop, sortWith } from 'ramda';
import { useIntl } from 'react-intl';
import { useAccount, useBalance } from 'wagmi';
@@ -37,12 +32,10 @@ export const TokenSelectModal = ({
onClose,
...rest
}: TokenSelectModalProps) => {
- const intl = useIntl();
-
- const [swappable, unswappable] = pipe(
- reject(prop('isSelected')),
- partition(prop('isSwappable')),
- )(tokens);
+ const sortedTokens = sortWith([
+ ascend(prop('isSelected')),
+ descend(prop('isSwappable')),
+ ])(tokens);
return (
);
};
@@ -150,7 +108,6 @@ function TokenListItem({ token, ...rest }: TokenListItemProps) {
'&:hover': {
background: (theme) => theme.palette.grey[700],
},
- color: 'primary.contrastText',
...rest?.sx,
}}
>
@@ -161,15 +118,15 @@ function TokenListItem({ token, ...rest }: TokenListItemProps) {
sx={{ width: '2rem', height: '2rem' }}
/>
- {token?.name}
-
+ {token?.name}
+
{token.symbol}
-
+
{isBalanceLoading ? (
) : (
diff --git a/libs/oeth/swap/src/constants.ts b/libs/oeth/swap/src/constants.ts
index 8d7101d4f..5f630efdc 100644
--- a/libs/oeth/swap/src/constants.ts
+++ b/libs/oeth/swap/src/constants.ts
@@ -19,8 +19,10 @@ export const routeActionLabel: Record = {
'mint-vault': defineMessage({ defaultMessage: 'Mint with Vault' }),
'swap-curve': defineMessage({ defaultMessage: 'Swap with Curve' }),
'swap-curve-eth': defineMessage({ defaultMessage: 'Swap with CurvePool' }),
- 'swap-zapper-eth': defineMessage({ defaultMessage: 'Swap with Zapper' }),
- 'swap-zapper-sfrxeth': defineMessage({ defaultMessage: 'Swap with Zapper' }),
+ 'swap-zapper-eth': defineMessage({ defaultMessage: 'Zap + Mint with Vault' }),
+ 'swap-zapper-sfrxeth': defineMessage({
+ defaultMessage: 'Zap + Mint with Vault',
+ }),
'unwrap-woeth': defineMessage({ defaultMessage: 'Unwrap with Origin' }),
'wrap-oeth': defineMessage({ defaultMessage: 'Wrap with Origin' }),
};
diff --git a/libs/oeth/swap/src/queries.generated.ts b/libs/oeth/swap/src/queries.generated.ts
index 4c5ec1771..c94d68aeb 100644
--- a/libs/oeth/swap/src/queries.generated.ts
+++ b/libs/oeth/swap/src/queries.generated.ts
@@ -20,7 +20,11 @@ export type ApiesQuery = {
export const ApiesDocument = `
query Apies($limit: Int) {
- apies(limit: $limit, orderBy: timestamp_DESC) {
+ apies(
+ limit: $limit
+ orderBy: timestamp_DESC
+ where: {timestamp_gt: "2023-06-06T12:38:47.000000Z"}
+ ) {
id
timestamp
apy7DayAvg
diff --git a/libs/oeth/swap/src/queries.graphql b/libs/oeth/swap/src/queries.graphql
index 5e2258a0b..0fad24425 100644
--- a/libs/oeth/swap/src/queries.graphql
+++ b/libs/oeth/swap/src/queries.graphql
@@ -1,5 +1,5 @@
query Apies($limit: Int) {
- apies(limit: $limit, orderBy: timestamp_DESC) {
+ apies(limit: $limit, orderBy: timestamp_DESC, where: {timestamp_gt: "2023-06-06T12:38:47.000000Z"}) {
id
timestamp
apy7DayAvg
diff --git a/libs/oeth/swap/src/state.ts b/libs/oeth/swap/src/state.ts
index 5f200fc57..089de3d8d 100644
--- a/libs/oeth/swap/src/state.ts
+++ b/libs/oeth/swap/src/state.ts
@@ -21,7 +21,7 @@ export const { Provider: SwapProvider, useTracked: useSwapState } =
tokenOut: tokens.mainnet.OETH,
swapRoutes: [],
selectedSwapRoute: null,
- slippage: 0.01,
+ slippage: 0.001,
isSwapRoutesLoading: false,
isApproved: false,
isApprovalLoading: false,
diff --git a/libs/oeth/swap/src/views/SwapView.tsx b/libs/oeth/swap/src/views/SwapView.tsx
index a9490a550..a7417ccfa 100644
--- a/libs/oeth/swap/src/views/SwapView.tsx
+++ b/libs/oeth/swap/src/views/SwapView.tsx
@@ -4,6 +4,9 @@ import {
alpha,
Box,
Button,
+ Card,
+ CardContent,
+ CardHeader,
CircularProgress,
Collapse,
IconButton,
@@ -11,13 +14,13 @@ import {
Typography,
} from '@mui/material';
import { GasPopover } from '@origin/oeth/shared';
-import { Card, TokenInput } from '@origin/shared/components';
+import { TokenInput } from '@origin/shared/components';
import { ConnectedButton, usePrices } from '@origin/shared/providers';
import { composeContexts, isNilOrEmpty } from '@origin/shared/utils';
import { useIntl } from 'react-intl';
import { useAccount, useBalance } from 'wagmi';
-import { ApyChart } from '../components/ApyChart';
+import { ApyHeader } from '../components/ApyHeader';
import { SwapRoute } from '../components/SwapRoute';
import { TokenSelectModal } from '../components/TokenSelectModal';
import { routeActionLabel } from '../constants';
@@ -33,20 +36,11 @@ import {
} from '../hooks';
import { SwapProvider, useSwapState } from '../state';
-import type { IconButtonProps, Theme } from '@mui/material';
+import type { IconButtonProps } from '@mui/material';
import type { Token } from '@origin/shared/contracts';
import type { TokenSource } from '../types';
-const commonStyles = {
- paddingBlock: 2.5,
- paddingBlockStart: 2.625,
- paddingInline: 2,
- border: '1px solid',
- borderColor: 'divider',
- borderRadius: 1,
-};
-
const tokenInputStyles = {
border: 'none',
backgroundColor: 'transparent',
@@ -57,14 +51,12 @@ const tokenInputStyles = {
boxSizing: 'border-box',
'& .MuiInputBase-input': {
padding: 0,
- lineHeight: '1.875rem',
boxSizing: 'border-box',
fontStyle: 'normal',
- fontFamily: 'Sailec, Inter, Helvetica, Arial, sans-serif',
- fontSize: '1.5rem',
+ fontFamily: 'Sailec, sans-serif',
+ fontSize: 24,
+ lineHeight: 1.5,
fontWeight: 700,
- height: '1.5rem',
- color: 'primary.contrastText',
'&::placeholder': {
color: 'text.secondary',
opacity: 1,
@@ -138,159 +130,166 @@ function SwapViewWrapped() {
: !isNilOrEmpty(selectedSwapRoute)
? intl.formatMessage(routeActionLabel[selectedSwapRoute?.action])
: '';
- const approveButtonLoading = isSwapRoutesLoading || isApprovalLoading;
- const swapButtonLoading = isSwapRoutesLoading || isSwapLoading;
const amountInInputDisabled = isSwapLoading || isApprovalLoading;
const approveButtonDisabled =
isNilOrEmpty(selectedSwapRoute) ||
- approveButtonLoading ||
+ isSwapRoutesLoading ||
+ isApprovalLoading ||
amountIn > balTokenIn?.value;
const swapButtonDisabled =
needsApproval ||
isNilOrEmpty(selectedSwapRoute) ||
isBalTokenInLoading ||
- swapButtonLoading ||
+ isSwapRoutesLoading ||
+ isSwapLoading ||
amountIn > balTokenIn?.value ||
amountIn === 0n;
return (
<>
-
-
+
+
+
+ {intl.formatMessage({ defaultMessage: 'Swap' })}
+
+ theme.spacing(-0.75),
+ svg: { width: 16, height: 16 },
+ },
+ }}
+ />
+
+ }
+ />
+
+
-
- {intl.formatMessage({ defaultMessage: 'Swap' })}
-
- theme.spacing(-0.75),
+ {
+ setTokenSource('tokenIn');
+ }}
+ tokenPriceUsd={prices?.[tokenIn.symbol]}
+ isPriceLoading={isPriceLoading}
+ isConnected={isConnected}
+ isAmountDisabled={amountInInputDisabled}
+ inputProps={{ sx: tokenInputStyles }}
+ sx={{
+ paddingBlock: 2.5,
+ paddingBlockStart: 2.625,
+ paddingInline: 2,
+ border: '1px solid',
+ borderColor: 'divider',
+ borderTopLeftRadius: (theme) => theme.shape.borderRadius,
+ borderTopRightRadius: (theme) => theme.shape.borderRadius,
+ backgroundColor: 'grey.900',
+ borderBottomColor: 'transparent',
+ '&:hover, &:focus-within': {
+ borderColor: 'transparent',
+ },
+ '&:hover': {
+ background: (theme) =>
+ `linear-gradient(${theme.palette.grey[900]}, ${
+ theme.palette.grey[900]
+ }) padding-box, linear-gradient(90deg, ${alpha(
+ theme.palette.primary.main,
+ 0.4,
+ )} 0%, ${alpha(
+ theme.palette.primary.dark,
+ 0.4,
+ )} 100%) border-box;`,
+ },
+ '&:focus-within': {
+ background: (theme) =>
+ `linear-gradient(${theme.palette.grey[900]}, ${theme.palette.grey[900]}) padding-box, linear-gradient(90deg, ${theme.palette.primary.main} 0%, ${theme.palette.primary.dark} 100%) border-box;`,
},
}}
/>
-
- }
- >
-
- {
- setTokenSource('tokenIn');
- }}
- tokenPriceUsd={prices?.[tokenIn.symbol]}
- isPriceLoading={isPriceLoading}
- isConnected={isConnected}
- isAmountDisabled={amountInInputDisabled}
- inputProps={{ sx: tokenInputStyles }}
- sx={{
- ...commonStyles,
- backgroundColor: 'grey.900',
- borderBottomColor: 'transparent',
- '&:hover, &:focus-within': {
- borderColor: 'transparent',
- },
- '&:hover': {
- background: (theme) =>
- `linear-gradient(${theme.palette.grey[900]}, ${
- theme.palette.grey[900]
- }) padding-box,
- linear-gradient(90deg, ${alpha(
- theme.palette.primary.main,
- 0.4,
- )} 0%, ${alpha(
- theme.palette.primary.dark,
- 0.4,
- )} 100%) border-box;`,
- },
- '&:focus-within': {
- background: (theme) =>
- `linear-gradient(${theme.palette.grey[900]}, ${theme.palette.grey[900]}) padding-box,
- linear-gradient(90deg, var(--mui-palette-primary-main) 0%, var(--mui-palette-primary-dark) 100%) border-box;`,
- },
- }}
- />
- {
- setTokenSource('tokenOut');
- }}
- tokenPriceUsd={prices?.[tokenOut.symbol]}
- isPriceLoading={isSwapRoutesLoading || isPriceLoading}
- isConnected={isConnected}
- hideMaxButton
- inputProps={{ readOnly: true, sx: tokenInputStyles }}
+ {
+ setTokenSource('tokenOut');
+ }}
+ tokenPriceUsd={prices?.[tokenOut.symbol]}
+ isPriceLoading={isSwapRoutesLoading || isPriceLoading}
+ isConnected={isConnected}
+ hideMaxButton
+ inputProps={{ readOnly: true, sx: tokenInputStyles }}
+ sx={{
+ paddingBlock: 2.5,
+ paddingBlockStart: 2.625,
+ paddingInline: 2,
+ border: '1px solid',
+ borderColor: 'divider',
+ borderBottomLeftRadius: (theme) => theme.shape.borderRadius,
+ borderBottomRightRadius: (theme) => theme.shape.borderRadius,
+ backgroundColor: (theme) => alpha(theme.palette.grey[400], 0.2),
+ }}
+ />
+
+
+ alpha(theme.palette.grey[400], 0.2),
+ mt: 1.5,
+ borderRadius: 1,
+ border: (theme) => `1px solid ${theme.palette.divider}`,
}}
/>
-
-
-
-
-
+
+ {isSwapRoutesLoading ? (
+
+ ) : isApprovalLoading ? (
+ intl.formatMessage({ defaultMessage: 'Wait for signature' })
+ ) : (
+ intl.formatMessage({ defaultMessage: 'Approve' })
+ )}
+
+
+
- {approveButtonLoading ? (
+ {isSwapRoutesLoading ? (
+ ) : isSwapLoading ? (
+ intl.formatMessage({ defaultMessage: 'Waiting for signature' })
) : (
- intl.formatMessage({ defaultMessage: 'Approve' })
+ swapButtonLabel
)}
-
-
-
- {swapButtonLoading ? (
-
- ) : (
- swapButtonLabel
- )}
-
+
+
theme.palette.background.paper,
@@ -338,7 +337,7 @@ function ArrowButton(props: IconButtonProps) {
component="img"
src="/images/splitarrow.svg"
sx={{
- height: { md: 'auto', xs: '1.25rem' },
+ height: { md: 20, xs: 18 },
}}
/>
diff --git a/libs/shared/assets/files/settings-icon.svg b/libs/shared/assets/files/settings-icon.svg
index b6598f93b..022c07cda 100644
--- a/libs/shared/assets/files/settings-icon.svg
+++ b/libs/shared/assets/files/settings-icon.svg
@@ -1,11 +1,12 @@
-