Skip to content

Commit

Permalink
Merge pull request #52 from OriginProtocol/feat/apy-header
Browse files Browse the repository at this point in the history
[TAS-235] Feat/apy header
  • Loading branch information
toniocodo authored Sep 25, 2023
2 parents 1a2ea9e + 1fa3dc9 commit 6c60bb7
Show file tree
Hide file tree
Showing 21 changed files with 672 additions and 308 deletions.
3 changes: 0 additions & 3 deletions apps/oeth/src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,8 @@
import { Container, CssBaseline, Stack } from '@mui/material';
import { registerChart } from '@origin/shared/providers';
import { Outlet } from 'react-router-dom';

import { Topnav } from './components/Topnav';

registerChart();

export const App = () => {
return (
<>
Expand Down
8 changes: 7 additions & 1 deletion apps/oeth/src/main.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,11 @@ import * as ReactDOM from 'react-dom/client';

import { Experimental_CssVarsProvider as CssVarsProvider } from '@mui/material';
import { chains, queryClient, wagmiConfig } from '@origin/oeth/shared';
import { CurveProvider, NotificationsProvider } from '@origin/shared/providers';
import {
CurveProvider,
NotificationsProvider,
registerChart,
} from '@origin/shared/providers';
import { theme } from '@origin/shared/theme';
import { composeContexts } from '@origin/shared/utils';
import { darkTheme, RainbowKitProvider } from '@rainbow-me/rainbowkit';
Expand All @@ -22,6 +26,8 @@ import { routes } from './routes';
// https://github.com/dai-shi/proxy-compare/pull/8
setAutoFreeze(false);

registerChart();

const root = ReactDOM.createRoot(
document.getElementById('root') as HTMLElement,
);
Expand Down
70 changes: 53 additions & 17 deletions libs/oeth/history/src/components/APYContainer.tsx
Original file line number Diff line number Diff line change
@@ -1,19 +1,31 @@
import { Divider, Stack, Typography } from '@mui/material';
import { valueFormat } from '@origin/shared/utils';
import { Divider, Skeleton, Stack, Typography } from '@mui/material';
import { tokens } from '@origin/shared/contracts';
import { balanceFormat } from '@origin/shared/utils';
import { useIntl } from 'react-intl';
import { useAccount } from 'wagmi';
import { useAccount, useBalance } from 'wagmi';

import { usePendingYield } from '../hooks';
import { useHistoryTableQuery } from '../queries.generated';

import type { StackProps } from '@mui/material';

export function APYContainer() {
const intl = useIntl();
const { address, isConnected } = useAccount();
const { data } = useHistoryTableQuery(
{ addressId: address?.toLowerCase(), offset: 0 },
const { data: oethBalance, isLoading: oethLoading } = useBalance({
address,
token: tokens.mainnet.OETH.address,
watch: true,
});
const { data: earnings, isLoading: earningsLoading } = useHistoryTableQuery(
{ address: address?.toLowerCase(), offset: 0 },
{
enabled: isConnected,
},
);
const intl = useIntl();
const { data: pendingYield, isLoading: pendingYieldLoading } =
usePendingYield(tokens.mainnet.OETH);

return (
<Stack
sx={{
Expand All @@ -26,35 +38,59 @@ export function APYContainer() {
>
<ValueContainer
label={intl.formatMessage({ defaultMessage: 'OETH Balance' })}
value={data?.addressById?.balance ?? 0}
value={intl.formatNumber(
Number(oethBalance?.formatted ?? 0),
balanceFormat,
)}
isLoading={isConnected && oethLoading}
/>
<Divider orientation="vertical" flexItem />
<ValueContainer
label={intl.formatMessage({ defaultMessage: 'Pending Yield' })}
value={0.0023}
value={intl.formatNumber(pendingYield ?? 0, balanceFormat)}
isLoading={isConnected && pendingYieldLoading}
/>
<Divider orientation="vertical" flexItem />
<ValueContainer
label={intl.formatMessage({
defaultMessage: 'Lifetime earnings (OETH)',
})}
value={data?.addressById?.earned ?? 0}
value={intl.formatNumber(
earnings?.addressById?.earned ?? 0,
balanceFormat,
)}
isLoading={isConnected && earningsLoading}
/>
</Stack>
);
}

interface Props {
type ValueContainerProps = {
label: string;
value: number;
}
value: string;
isLoading?: boolean;
} & StackProps;

function ValueContainer(props: Props) {
const intl = useIntl();
function ValueContainer({
label,
value,
isLoading,
...rest
}: ValueContainerProps) {
return (
<Stack gap={0.5} sx={{ paddingBlock: 2, textAlign: 'center', flex: 1 }}>
<Stack
gap={0.5}
{...rest}
sx={{
paddingBlock: 2,
alignItems: 'center',
textAlign: 'center',
flex: 1,
...rest?.sx,
}}
>
<Typography variant="body2" color="text.secondary">
{props.label}
{label}
</Typography>
<Typography
sx={{
Expand All @@ -67,7 +103,7 @@ function ValueContainer(props: Props) {
}}
color="primary.contrastText"
>
{intl.formatNumber(props.value, valueFormat)}
{isLoading ? <Skeleton width={60} /> : value}
</Typography>
</Stack>
);
Expand Down
34 changes: 7 additions & 27 deletions libs/oeth/history/src/components/HistoryCard.tsx
Original file line number Diff line number Diff line change
@@ -1,51 +1,31 @@
import { useState } from 'react';

import { Box, Button, Divider, Stack, Typography } from '@mui/material';
import { graphqlClient } from '@origin/oeth/shared';
import { useQuery } from '@tanstack/react-query';
import { useIntl } from 'react-intl';
import { useAccount } from 'wagmi';

import {
HistoryTableDocument,
HistoryTableWithFiltersDocument,
} from '../queries.generated';
import { useHistoryTableWithFiltersQuery } from '../queries.generated';
import { ExportData } from './ExportData';
import { HistoryFilters } from './Filters';
import { HistoryTable } from './HistoryTable';

import type { HistoryTableQuery } from '../queries.generated';

const PAGE_SIZE = 20;

export function HistoryCard() {
const intl = useIntl();
const [page, setPage] = useState(0);
const [filters, setFilters] = useState<string[]>([]);
const { address, isConnected } = useAccount();

const { data, isFetching } = useQuery(
['history-table', address, filters, page],
() => {
return graphqlClient<
HistoryTableQuery,
{ addressId: string; filters?: string[]; offset: number }
>(
filters.length ? HistoryTableWithFiltersDocument : HistoryTableDocument,
{
addressId: address?.toLowerCase(),
filters: filters.length ? filters : undefined,
offset: page * PAGE_SIZE,
},
)();
},

const { data, isFetching } = useHistoryTableWithFiltersQuery(
{
enabled: isConnected,
address: address.toLowerCase(),
filters: filters.length ? filters : undefined,
offset: page * PAGE_SIZE,
},
{ enabled: isConnected },
);

const intl = useIntl();

return (
<Box sx={{ borderRadius: 1, backgroundColor: 'background.paper', mt: 3 }}>
<Stack
Expand Down
39 changes: 39 additions & 0 deletions libs/oeth/history/src/hooks.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import { queryClient } from '@origin/oeth/shared';
import { isNilOrEmpty } from '@origin/shared/utils';
import { useQuery } from '@tanstack/react-query';
import { fetchBalance, getAccount } from '@wagmi/core';

import { useHistoryTableQuery } from './queries.generated';

import type { Token } from '@origin/shared/contracts';
import type { QueryOptions } from '@tanstack/react-query';

import type { HistoryTableQuery } from './queries.generated';

export const usePendingYield = (token: Token, options?: QueryOptions) =>
useQuery({
queryKey: ['usePendingYield', token.symbol],
queryFn: async () => {
const { address, isConnected } = getAccount();

if (!isConnected) {
return 0;
}

// TODO endpoint for next userCredits is not yet available on subsquid
const [balance, data] = await Promise.all([
fetchBalance({ address, token: token.address }),
queryClient.fetchQuery<HistoryTableQuery>({
queryKey: useHistoryTableQuery.getKey({ address, offset: 0 }),
queryFn: useHistoryTableQuery.fetcher({
address: address.toLowerCase(),
offset: 0,
}),
}),
]);

if (isNilOrEmpty(data?.addressById) || balance?.value === 0n) return 0;

return 0;
},
});
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { useQuery } from '@tanstack/react-query';
import type * as Types from '@origin/oeth/shared';
import type { UseQueryOptions } from '@tanstack/react-query';
export type HistoryTableQueryVariables = Types.Exact<{
addressId: Types.Scalars['String']['input'];
address: Types.Scalars['String']['input'];
offset: Types.Scalars['Int']['input'];
}>;

Expand All @@ -29,7 +29,7 @@ export type HistoryTableQuery = {
};

export type HistoryTableWithFiltersQueryVariables = Types.Exact<{
addressId: Types.Scalars['String']['input'];
address: Types.Scalars['String']['input'];
offset: Types.Scalars['Int']['input'];
filters?: Types.InputMaybe<
Array<Types.Scalars['String']['input']> | Types.Scalars['String']['input']
Expand All @@ -44,6 +44,7 @@ export type HistoryTableWithFiltersQuery = {
earned: number;
isContract: boolean;
rebasingOption: string;
credits: any;
lastUpdated: any;
history: Array<{
__typename?: 'History';
Expand All @@ -56,9 +57,16 @@ export type HistoryTableWithFiltersQuery = {
} | null;
};

export type HistoryApyQueryVariables = Types.Exact<{ [key: string]: never }>;

export type HistoryApyQuery = {
__typename?: 'Query';
apies: Array<{ __typename?: 'APY'; apy7DayAvg: number; apy30DayAvg: number }>;
};

export const HistoryTableDocument = `
query HistoryTable($addressId: String!, $offset: Int!) {
addressById(id: $addressId) {
query HistoryTable($address: String!, $offset: Int!) {
addressById(id: $address) {
balance
earned
isContract
Expand Down Expand Up @@ -89,13 +97,28 @@ export const useHistoryTableQuery = <
),
options,
);

useHistoryTableQuery.getKey = (variables: HistoryTableQueryVariables) => [
'HistoryTable',
variables,
];
useHistoryTableQuery.fetcher = (
variables: HistoryTableQueryVariables,
options?: RequestInit['headers'],
) =>
graphqlClient<HistoryTableQuery, HistoryTableQueryVariables>(
HistoryTableDocument,
variables,
options,
);
export const HistoryTableWithFiltersDocument = `
query HistoryTableWithFilters($addressId: String!, $offset: Int!, $filters: [String!]) {
addressById(id: $addressId) {
query HistoryTableWithFilters($address: String!, $offset: Int!, $filters: [String!]) {
addressById(id: $address) {
balance
earned
isContract
rebasingOption
credits
lastUpdated
history(
limit: 20
Expand Down Expand Up @@ -127,3 +150,47 @@ export const useHistoryTableWithFiltersQuery = <
>(HistoryTableWithFiltersDocument, variables),
options,
);

useHistoryTableWithFiltersQuery.getKey = (
variables: HistoryTableWithFiltersQueryVariables,
) => ['HistoryTableWithFilters', variables];
useHistoryTableWithFiltersQuery.fetcher = (
variables: HistoryTableWithFiltersQueryVariables,
options?: RequestInit['headers'],
) =>
graphqlClient<
HistoryTableWithFiltersQuery,
HistoryTableWithFiltersQueryVariables
>(HistoryTableWithFiltersDocument, variables, options);
export const HistoryApyDocument = `
query HistoryApy {
apies(limit: 1, orderBy: timestamp_DESC) {
apy7DayAvg
apy30DayAvg
}
}
`;
export const useHistoryApyQuery = <TData = HistoryApyQuery, TError = unknown>(
variables?: HistoryApyQueryVariables,
options?: UseQueryOptions<HistoryApyQuery, TError, TData>,
) =>
useQuery<HistoryApyQuery, TError, TData>(
variables === undefined ? ['HistoryApy'] : ['HistoryApy', variables],
graphqlClient<HistoryApyQuery, HistoryApyQueryVariables>(
HistoryApyDocument,
variables,
),
options,
);

useHistoryApyQuery.getKey = (variables?: HistoryApyQueryVariables) =>
variables === undefined ? ['HistoryApy'] : ['HistoryApy', variables];
useHistoryApyQuery.fetcher = (
variables?: HistoryApyQueryVariables,
options?: RequestInit['headers'],
) =>
graphqlClient<HistoryApyQuery, HistoryApyQueryVariables>(
HistoryApyDocument,
variables,
options,
);
Loading

0 comments on commit 6c60bb7

Please sign in to comment.